Please 🖱️ here for Github Blogs

Claude Code Plugins

  • May 14, 2026
Table of Contents

What Are Claude Code Plugins?

Plugins are self-contained packages that extend Claude Code with custom functionality. A plugin can bundle any combination of:

  • Skills — reusable instructions Claude can invoke automatically or users can call manually
  • Agents — custom agent definitions with their own system prompts, tool restrictions, and models
  • Hooks — shell commands that fire automatically before or after Claude Code actions
  • MCP servers — connections to external tools and data sources via the Model Context Protocol
  • LSP servers — language server integrations for real-time code intelligence
  • Background monitors — processes that watch logs or files and notify Claude as events arrive
  • Output styles and themes — response style and UI colour customisations
  • Executables — binaries added to the Bash tool’s PATH while the plugin is active
  • Default settings — configuration applied automatically when the plugin is enabled

Plugins are designed for sharing. Once packaged, teammates or the wider community can install them with a single /plugin install command via a marketplace.


Plugins vs Standalone Configuration

Claude Code supports two ways to add custom skills, agents, and hooks. Choosing between them depends on whether you need to share the configuration.

ApproachSkill name formatBest for
Standalone (.claude/ directory)/helloPersonal workflows, project-specific customisation, quick experiments
Plugins (directory, usually with .claude-plugin/plugin.json)/plugin-name:helloSharing with teammates, distributing to the community, versioned releases, reuse across multiple projects

Use standalone configuration when:

  • You are customising Claude Code for a single project
  • The configuration is personal and does not need to be shared
  • You are experimenting with skills or hooks before packaging them
  • You want short, unnamespaced skill names like /hello or /deploy

Use plugins when:

  • You want to share functionality with your team or the broader community
  • You need the same skills or agents available across multiple projects
  • You want version control and easy updates for your extensions
  • You are distributing through a marketplace
  • You are comfortable with namespaced skill names like /my-plugin:hello (namespacing prevents conflicts between plugins)

Recommended workflow: Start with standalone configuration in .claude/ for fast iteration, then convert to a plugin when you are ready to share.


Plugin Directory Structure

A plugin lives in its own directory. The .claude-plugin/plugin.json manifest is recommended for distributable plugins because it defines the plugin name, metadata, version, and optional component paths. Claude Code can also auto-discover components in default locations when the manifest is omitted.

my-plugin/
├── .claude-plugin/
│   └── plugin.json          # Plugin manifest (recommended)
├── skills/                  # Skills as <name>/SKILL.md directories
├── commands/                # Legacy flat Markdown skills (use skills/ for new plugins)
├── agents/                  # Custom agent definitions
├── output-styles/           # Custom output styles
├── themes/                  # Colour themes
├── hooks/
│   └── hooks.json           # Event handlers
├── monitors/
│   └── monitors.json        # Background monitor configurations
├── bin/                     # Executables added to Bash tool PATH
├── scripts/                 # Helper scripts used by skills, hooks, or monitors
├── .mcp.json                # MCP server configurations
├── .lsp.json                # LSP server configurations
└── settings.json            # Default settings applied when plugin is enabled

Common mistake: Do not put commands/, agents/, skills/, output-styles/, themes/, monitors/, or hooks/ inside the .claude-plugin/ directory. Only plugin.json goes inside .claude-plugin/. All other directories must be at the plugin root level.

A CLAUDE.md file at the plugin root is not loaded as project context. Plugins contribute context through skills, agents, hooks, MCP servers, LSP servers, monitors, and settings. If you want instructions to enter Claude’s context, put them in a skill or agent.

ComponentDefault LocationPurpose
Manifest.claude-plugin/plugin.jsonPlugin metadata, versioning, and custom component paths
Skillsskills/Skills with <name>/SKILL.md structure
Commandscommands/Legacy flat Markdown skills; use skills/ for new plugins
Agentsagents/Custom subagent Markdown files
Output stylesoutput-styles/Response style definitions
Themesthemes/CLI colour theme definitions
Hookshooks/hooks.jsonHook configuration for lifecycle events
MCP servers.mcp.jsonModel Context Protocol server definitions
LSP servers.lsp.jsonLanguage server configurations
Monitorsmonitors/monitors.jsonBackground monitor definitions
Executablesbin/Commands added to the Bash tool’s PATH while the plugin is active
Settingssettings.jsonDefault plugin settings; currently agent and subagentStatusLine

Quickstart: Creating Your First Plugin

Step 1 — Create the plugin directory

mkdir my-first-plugin

Step 2 — Create the plugin manifest

The manifest at .claude-plugin/plugin.json defines your plugin’s identity. Claude Code uses this metadata in the plugin manager. If you include a manifest, name is the only required field, but description and version are strongly recommended for shared plugins.

mkdir my-first-plugin/.claude-plugin

my-first-plugin/.claude-plugin/plugin.json:

{
  "name": "my-first-plugin",
  "description": "A greeting plugin to learn the basics",
  "version": "1.0.0",
  "author": {
    "name": "Your Name"
  }
}

Manifest metadata fields:

FieldTypeDescription
namestringRequired if a manifest is present. Unique kebab-case identifier and component namespace. Skills are prefixed with this, for example /my-first-plugin:hello.
$schemastringJSON Schema URL for editor autocomplete and validation. Ignored at plugin load time.
versionstringOptional version string. If set, users only receive updates when you bump it. If omitted and distributed via git, the commit SHA is used.
descriptionstringShort explanation shown in plugin listings and details views.
authorobjectAuthor metadata, usually name, and optionally email and url.
homepagestringDocumentation or product page URL.
repositorystringSource repository URL.
licensestringSPDX-style license identifier such as MIT or Apache-2.0.
keywordsarrayDiscovery tags for search and marketplace browsing.

Manifest component path fields:

FieldTypeDescription
skillsstring or arrayExtra skill directories. These are added alongside the default skills/ directory.
commandsstring or arrayCustom flat Markdown command files or directories. Replaces the default commands/ scan unless you list ./commands/ explicitly.
agentsstring or arrayCustom agent files or directories. Replaces the default agents/ scan unless you list it explicitly.
hooksstring, array, or objectHook config path(s), or inline hook configuration.
mcpServersstring, array, or objectMCP config path(s), or inline MCP server configuration.
outputStylesstring or arrayOutput style files or directories. Replaces the default output-styles/ scan unless listed explicitly.
lspServersstring, array, or objectLSP config path(s), or inline LSP server configuration.
experimental.themesstring or arrayTheme files or directories. Replaces the default themes/ scan unless listed explicitly.
experimental.monitorsstring or arrayMonitor config path(s). Monitors are still treated as experimental.
userConfigobjectUser-configurable values prompted when the plugin is enabled.
channelsarrayMessage channel declarations bound to plugin MCP servers.
dependenciesarrayOther plugins this plugin requires, optionally with version constraints.

Path rules are easy to trip over:

  • All custom paths in plugin.json should be relative to the plugin root and start with ./.
  • skills extends the default skills/ directory.
  • commands, agents, outputStyles, experimental.themes, and experimental.monitors replace their default directories unless you list the default path explicitly.
  • Hooks, MCP servers, and LSP servers have their own merge behaviour because they can be declared as paths or inline objects.

Use userConfig when a plugin needs per-user settings such as API endpoints, tokens, directories, or feature flags:

{
  "userConfig": {
    "api_endpoint": {
      "type": "string",
      "title": "API endpoint",
      "description": "Your team's API endpoint",
      "required": true
    },
    "api_token": {
      "type": "string",
      "title": "API token",
      "description": "API authentication token",
      "sensitive": true
    }
  }
}
userConfig FieldRequiredDescription
typeYesOne of string, number, boolean, directory, or file.
titleYesLabel shown in the configuration dialog.
descriptionYesHelp text shown beneath the field.
sensitiveNoMasks input and stores the value in secure storage instead of plain settings.
requiredNoFails validation when the value is empty.
defaultNoValue used when the user provides nothing.
multipleNoAllows an array of strings for string fields.
min / maxNoBounds for number fields.

Configured values can be referenced as ${user_config.KEY} in MCP and LSP server configs, hook commands, and monitor commands. Non-sensitive values can also be substituted into skill and agent content.

Channels let a plugin declare message sources that inject content into the conversation, usually backed by a plugin-provided MCP server:

{
  "channels": [
    {
      "server": "telegram",
      "userConfig": {
        "bot_token": {
          "type": "string",
          "title": "Bot token",
          "description": "Telegram bot token",
          "sensitive": true
        },
        "owner_id": {
          "type": "string",
          "title": "Owner ID",
          "description": "Your Telegram user ID"
        }
      }
    }
  ]
}

The server value must match a key in the plugin’s mcpServers. Channel-level userConfig uses the same schema as top-level userConfig.

Dependencies let one plugin require another:

{
  "name": "deploy-kit",
  "version": "3.1.0",
  "dependencies": [
    "audit-logger",
    { "name": "secrets-vault", "version": "~2.1.0" }
  ]
}
Dependency FieldRequiredDescription
nameYesPlugin name. By default, resolved within the same marketplace.
versionNoSemver range such as ~2.1.0, ^2.0, >=1.4, or =2.1.0.
marketplaceNoMarketplace to resolve the dependency from. Cross-marketplace dependencies must be allowed by the root marketplace.

Use claude plugin tag --push when publishing versioned releases. For git-backed marketplaces, dependency constraints resolve against tags named {plugin-name}--v{version}.

Step 3 — Add a skill

Skills live in the skills/ directory. Each skill is a folder whose name becomes the skill name, prefixed by the plugin namespace.

mkdir -p my-first-plugin/skills/hello

my-first-plugin/skills/hello/SKILL.md:

---
description: Greet the user with a friendly message
disable-model-invocation: true
---

Greet the user warmly and ask how you can help them today.

Step 4 — Test your plugin locally

Use the --plugin-dir flag to load your plugin for a session without installing it:

claude --plugin-dir ./my-first-plugin

Then invoke your skill:

/my-first-plugin:hello

Run /help to see your skill listed under the plugin namespace. Run /reload-plugins after any changes to pick them up without restarting.

Step 5 — Add skill arguments

The $ARGUMENTS placeholder captures any text the user provides after the skill name, making skills dynamic:

---
description: Greet the user with a personalized message
---

Greet the user named "$ARGUMENTS" warmly and ask how you can help them today.

Usage:

/my-first-plugin:hello Alex

Plugin Components in Depth

Skills

By default, skills can be model-invoked: Claude can select and use them based on task context, without the user needing to invoke them manually. Each skill is a folder inside skills/ containing a SKILL.md file.

my-plugin/
└── skills/
    └── code-review/
        └── SKILL.md

A typical SKILL.md:

---
description: Reviews code for best practices and potential issues. Use when reviewing code, checking PRs, or analyzing code quality.
---

When reviewing code, check for:

1. Code organisation and structure
2. Error handling
3. Security concerns
4. Test coverage

The description frontmatter field is what Claude reads to decide when to invoke the skill. Use disable-model-invocation: true for manual-only skills, especially workflows with side effects such as deploys or commits. Use user-invocable: false for background knowledge that Claude may use but users should not call from the slash menu.

Skill frontmatter fields:

FieldRequiredDescription
nameNoDisplay name for the skill. If omitted, Claude uses the directory name. Use lowercase letters, numbers and hyphens.
descriptionRecommendedWhat the skill does and when Claude should use it. If omitted, Claude falls back to the first paragraph of the Markdown body.
when_to_useNoExtra invocation guidance, such as trigger phrases or example requests. Appended to description in the skill listing.
argument-hintNoAutocomplete hint for expected arguments, such as [issue-number] or [filename] [format].
argumentsNoNamed positional arguments for $name substitution in the skill body. Accepts a space-separated string or YAML list.
disable-model-invocationNoSet to true to prevent Claude from loading or invoking the skill automatically. Useful for manual commands such as deploys.
user-invocableNoSet to false to hide the skill from the slash menu while still allowing Claude to invoke it automatically.
allowed-toolsNoTools Claude may use without asking while this skill is active. Accepts a space-separated string or YAML list.
modelNoModel override while the skill is active. Accepts the same values as /model, or inherit.
effortNoReasoning effort override while the skill is active. Common values are low, medium, high, xhigh, and max, depending on model support.
contextNoSet to fork to run the skill in a forked subagent context instead of the main conversation.
agentNoSubagent type to use when context: fork is set. Can reference built-in or custom agents.
hooksNoHooks scoped to this skill’s lifecycle. Uses the same hook configuration format as Claude Code hooks.
pathsNoGlob patterns that limit when Claude activates the skill automatically. Accepts a comma-separated string or YAML list.
shellNoShell for inline ! commands and code blocks. Supports bash by default and powershell when enabled.

After installing or reloading a plugin, run /reload-plugins to activate the skills.

For full skill authoring details including progressive disclosure and tool restrictions, see Extend Claude with skills.


Agents

Plugins can define custom subagents in the agents/ directory. Agents have their own system prompts, tool restrictions, and model selections. Claude can invoke them automatically when appropriate, and users can also select them from /agents.

Example agents/security-reviewer.md:

---
name: security-reviewer
description: Reviews code for security risks and unsafe patterns
model: sonnet
effort: medium
maxTurns: 20
disallowedTools: Write, Edit
---

Review code for security issues, risky dependencies, exposed secrets, and unsafe defaults.
Return findings with file references and concrete remediation steps.

Agent frontmatter fields:

FieldRequiredDescription
nameYesUnique agent identifier. Use lowercase letters and hyphens. In plugins, nested folders become part of the scoped agent identifier.
descriptionYesWhen Claude should delegate to this agent. Write this as routing guidance, not marketing copy.
toolsNoAllowlist of tools the agent can use. If omitted, the agent inherits the available tools from the main conversation.
disallowedToolsNoDenylist of tools to remove from the inherited or specified tool list. If both tools and disallowedTools are set, denied tools are removed.
modelNoModel for the agent, such as sonnet, opus, haiku, a full model ID, or inherit. Defaults to inherit.
effortNoReasoning effort while this agent is active. Common values are low, medium, high, xhigh, and max, depending on model support.
maxTurnsNoMaximum number of agentic turns before the agent stops.
skillsNoSkills to preload into the agent’s context at startup. The full skill content is injected, not just the description.
memoryNoPersistent memory scope for cross-session learning. Supported scopes are user, project, and local.
backgroundNoSet to true to always run this agent as a background task. Defaults to false.
isolationNoSet to worktree to run the agent in an isolated temporary git worktree.
colorNoDisplay colour in task lists and transcripts. Supported values include red, blue, green, yellow, purple, orange, pink, and cyan.
initialPromptNoFirst user turn automatically submitted when the agent runs as the main session agent through --agent or plugin settings.json.
permissionModeNoPermission mode for non-plugin agents. Ignored for plugin agents.
mcpServersNoMCP servers scoped to non-plugin agents. Ignored for plugin agents.
hooksNoLifecycle hooks scoped to non-plugin agents. Ignored for plugin agents.

For security reasons, plugin-shipped agents ignore hooks, mcpServers, and permissionMode. If you need those fields, copy the agent into .claude/agents/ or ~/.claude/agents/ instead of shipping it from a plugin.

You can set a default agent in the plugin’s settings.json:

{
  "agent": "security-reviewer"
}

This activates the security-reviewer agent as the main thread when the plugin is enabled. Settings in settings.json take priority over settings declared in plugin.json. Unknown keys are silently ignored.

Currently, only the agent and subagentStatusLine keys are supported in plugin settings.json.


Hooks

Hooks let you run shell commands automatically before or after Claude Code actions. Define them in hooks/hooks.json:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '.tool_input.file_path' | xargs npm run lint:fix"
          }
        ]
      }
    ]
  }
}

The hook command receives hook input as JSON on stdin. Use jq to extract fields like the file path. The format is the same as standalone hooks in settings.json, so existing hooks migrate directly.

Common hook events:

EventWhen It Fires
SessionStartWhen a session begins or resumes
SetupWhen Claude Code starts with setup-only modes such as --init-only, --init, or --maintenance in print mode
UserPromptSubmitAfter the user submits a prompt, before Claude processes it
UserPromptExpansionWhen a user-typed command expands into a prompt before it reaches Claude
PreToolUseBefore a tool call executes; can block or shape behaviour
PermissionRequestWhen a permission dialog appears
PermissionDeniedWhen a tool call is denied by auto mode
PostToolUseAfter a tool call succeeds
PostToolUseFailureAfter a tool call fails
PostToolBatchAfter a batch of parallel tool calls finishes
NotificationWhen Claude Code sends a notification
SubagentStartWhen a subagent starts
SubagentStopWhen a subagent finishes
TaskCreatedWhen a task is created through TaskCreate
TaskCompletedWhen a task is marked complete
StopWhen Claude finishes responding
StopFailureWhen a turn ends due to an API error
TeammateIdleWhen an agent-team teammate is about to go idle
InstructionsLoadedWhen a CLAUDE.md or .claude/rules/*.md file is loaded into context
ConfigChangeWhen configuration changes during a session
CwdChangedWhen the working directory changes
FileChangedWhen a watched file changes on disk
WorktreeCreateWhen a worktree is being created
WorktreeRemoveWhen a worktree is being removed
PreCompactBefore context compaction
PostCompactAfter context compaction
ElicitationWhen an MCP server requests user input during a tool call
ElicitationResultAfter the user responds to an MCP elicitation
SessionEndWhen the session terminates

Hook handler types:

TypeDescription
commandRuns a shell command or script. The event JSON is passed on stdin.
httpSends the event JSON to an HTTP endpoint as a POST request.
mcp_toolCalls a tool on an already-connected MCP server.
promptRuns a single-turn model evaluation and expects a structured decision.
agentSpawns an agentic verifier with tools for more complex checks.

Hook handler fields:

FieldRequiredDescription
typeYesOne of command, http, mcp_tool, prompt, or agent.
ifNoPermission-rule filter such as Bash(git *) or Edit(*.ts). Evaluated on tool events.
timeoutNoSeconds before cancellation. Defaults vary by handler type.
statusMessageNoSpinner text displayed while the hook runs.
onceNoRuns once per session when declared in skill frontmatter. Ignored in plugin-level hook files.
commandFor commandShell command or executable to run.
argsNoArgument vector for exec form. Prefer this when passing ${CLAUDE_PLUGIN_ROOT} paths.
asyncNoRuns a command hook in the background.
asyncRewakeNoRuns in the background and wakes Claude on exit code 2.
shellNoShell for command hooks, usually bash or powershell.

Use hooks sparingly. They run with the user’s local privileges, so a shared plugin should make side effects clear and keep commands auditable.


MCP Servers

MCP (Model Context Protocol) server configurations go in .mcp.json at the plugin root, or inline in plugin.json under mcpServers. This connects Claude Code to external tools, APIs, and data sources — databases, GitHub, Slack, Jira, internal services and more — bundled as part of the plugin.

{
  "mcpServers": {
    "plugin-database": {
      "command": "${CLAUDE_PLUGIN_ROOT}/servers/db-server",
      "args": ["--config", "${CLAUDE_PLUGIN_ROOT}/config.json"],
      "env": {
        "DB_PATH": "${CLAUDE_PLUGIN_DATA}/db"
      }
    },
    "plugin-api-client": {
      "command": "npx",
      "args": ["@company/mcp-server", "--plugin-mode"],
      "cwd": "${CLAUDE_PLUGIN_ROOT}"
    }
  }
}

Plugin MCP servers start when the plugin is enabled and expose tools through Claude’s normal MCP tool system. They can use ${CLAUDE_PLUGIN_ROOT} for bundled files, ${CLAUDE_PLUGIN_DATA} for persistent state, ${CLAUDE_PROJECT_DIR} for project paths, and ${user_config.KEY} for values collected from the user.

Use MCP when the plugin needs a durable integration surface: API calls, database queries, browser automation, ticketing systems, internal tools, or reusable tool contracts. Use hooks when you only need to react to Claude Code lifecycle events.


LSP Servers

LSP (Language Server Protocol) plugins give Claude real-time code intelligence for a given language. Define them in .lsp.json:

{
  "go": {
    "command": "gopls",
    "args": ["serve"],
    "extensionToLanguage": {
      ".go": "go"
    }
  }
}

LSP server fields:

FieldRequiredDescription
commandYesLSP binary to execute. It must be installed and available on the user’s PATH.
extensionToLanguageYesMaps file extensions such as .go or .rs to LSP language identifiers.
argsNoArguments passed to the language server.
transportNoCommunication transport. stdio is the default; socket is also supported.
envNoEnvironment variables set when starting the server.
initializationOptionsNoOptions passed during LSP initialization.
settingsNoSettings sent through workspace/didChangeConfiguration.
workspaceFolderNoWorkspace folder path for the server.
startupTimeoutNoMaximum startup wait in milliseconds.
shutdownTimeoutNoMaximum graceful shutdown wait in milliseconds.
restartOnCrashNoWhether Claude Code should restart the server after a crash.
maxRestartsNoMaximum restart attempts before giving up.

For common languages (TypeScript, Python, Rust, and others), install the pre-built LSP plugins from the official marketplace instead of writing your own. Only create a custom LSP plugin when you need support for a language with no existing plugin. Users installing your LSP plugin must have the language server binary installed on their own machine.

Official PluginLanguage ServerInstall the Server
pyright-lspPyright for Pythonpip install pyright or npm install -g pyright
typescript-lspTypeScript Language Servernpm install -g typescript-language-server typescript
rust-analyzer-lsprust-analyzerInstall rust-analyzer for your platform

Background Monitors

Background monitors watch logs, files, or external status in the background and notify Claude as events arrive. Claude Code starts each monitor automatically when the plugin is active — you do not need to instruct Claude to start watching.

Monitors require Claude Code v2.1.105 or later. They run only in interactive CLI sessions, run unsandboxed at the same trust level as hooks, and are skipped when the Monitor tool is unavailable.

Define monitors in monitors/monitors.json:

[
  {
    "name": "error-log",
    "command": "tail -F ./logs/error.log",
    "description": "Application error log"
  }
]

Each line written to stdout by command is delivered to Claude as a notification during the session. The full schema also supports a when trigger and variable substitution — see the plugins reference.

Monitor fields:

FieldRequiredDescription
nameYesIdentifier unique within the plugin. Prevents duplicate monitor processes on reload.
commandYesLong-running shell command executed from the session working directory.
descriptionYesShort summary shown in task panels and notification summaries.
whenNoStart condition. Defaults to always; use on-skill-invoke:<skill-name> to start after a skill first runs.

Monitor commands support ${CLAUDE_PLUGIN_ROOT}, ${CLAUDE_PLUGIN_DATA}, ${CLAUDE_PROJECT_DIR}, ${user_config.KEY} and environment variable substitutions. If a monitor script must run from the plugin directory, start the command with cd "${CLAUDE_PLUGIN_ROOT}" && ....


Output Styles and Themes

Plugins can include output-styles/ and themes/ directories. Output styles customise how Claude responds, while themes customise the CLI appearance. These are useful when a team wants consistent review formats, concise operational responses, or a shared visual theme.

When declaring custom paths in plugin.json, note that commands, agents, outputStyles, themes, and monitors replace their default directories unless you list the default path explicitly. skills are different: custom skill paths are added alongside the default skills/ directory.

Example themes/dracula.json:

{
  "name": "Dracula",
  "base": "dark",
  "overrides": {
    "claude": "#bd93f9",
    "error": "#ff5555",
    "success": "#50fa7b"
  }
}

Plugin themes appear in /theme alongside built-in themes. They are read-only while installed from the plugin; users can copy them into their own theme directory if they want to customise them.

Output styles are best for response conventions, not capability. Use a skill or agent when the plugin needs task-specific instructions, tools, or routing logic.


Executables (bin/)

Any executables you place in the bin/ directory are added to the Bash tool’s PATH while the plugin is enabled. This lets you ship helper scripts or binaries that your hooks or skills depend on.

For example, a plugin can ship bin/check-release, then a skill or hook can call check-release directly. Keep executables self-contained, document required system dependencies, and prefer ${CLAUDE_PLUGIN_DATA} for caches or installed dependencies that should survive plugin updates.


Plugin Environment Variables

Claude Code provides useful variables for plugin components:

VariableUse
${CLAUDE_PLUGIN_ROOT}Absolute path to the installed plugin version. Use this to reference bundled scripts and config files.
${CLAUDE_PLUGIN_DATA}Persistent data directory that survives plugin updates. Use for caches, dependencies, generated files, or state.
${CLAUDE_PROJECT_DIR}Project root where Claude Code is running. Use this to reference project-local scripts or config.

Quote these paths in shell commands because project and plugin paths may contain spaces.

When a plugin updates during a session, hooks, MCP servers and LSP servers keep using the previous plugin version until /reload-plugins runs. Monitors usually require a fresh session to switch to the new version. Treat ${CLAUDE_PLUGIN_ROOT} as read-only and versioned; write persistent state to ${CLAUDE_PLUGIN_DATA} instead.


Testing Plugins Locally

Load a local directory

claude --plugin-dir ./my-plugin

Load a zip archive (requires v2.1.128+)

claude --plugin-dir ./my-plugin.zip

Load from a URL

claude --plugin-url https://example.com/my-plugin.zip

Multiple plugins can be loaded at once:

claude --plugin-dir ./plugin-one --plugin-dir ./plugin-two
claude --plugin-url "https://example.com/a.zip https://example.com/b.zip"

Precedence: When a --plugin-dir plugin has the same name as an installed marketplace plugin, the local copy takes precedence for that session. This lets you iterate on a plugin you already have installed without uninstalling it first.

Reloading: Run /reload-plugins after making changes to reload skills, agents, hooks, MCP servers, and LSP servers without restarting Claude Code.

Debugging

If a plugin is not working:

  1. Check the structure — make sure commands/, agents/, skills/, and hooks/ are at the plugin root, not inside .claude-plugin/
  2. Test components individually — check each skill, agent, and hook separately
  3. Validate the plugin — run claude plugin validate ./my-plugin or use /plugin validate
  4. Inspect what loaded — run claude plugin list and claude plugin details <name>
  5. Use the CLI debugging tools — see Debugging and development tools

Useful plugin CLI commands:

CommandPurpose
claude plugin install <plugin>Install a plugin from a known marketplace.
claude plugin uninstall <plugin>Remove an installed plugin. Use --keep-data to preserve ${CLAUDE_PLUGIN_DATA}.
claude plugin pruneRemove auto-installed plugin dependencies no longer required by installed plugins.
claude plugin enable <plugin>Re-enable a disabled plugin.
claude plugin disable <plugin>Disable a plugin without uninstalling it.
claude plugin update <plugin>Update a plugin to the latest available version.
claude plugin listList installed plugins, versions, marketplace sources, and enabled status.
claude plugin details <name>Show component inventory and projected token cost.
claude plugin tagCreate a release git tag from inside a plugin folder.
claude plugin validate ./my-pluginValidate the manifest, frontmatter, and hook configuration.

Common failure modes:

SymptomLikely CauseFix
Plugin does not loadInvalid plugin.jsonRun claude plugin validate ./my-plugin.
Skill does not appearskills/ or commands/ is inside .claude-plugin/Move it to the plugin root.
Hook does not fireEvent or matcher is wrong, or script is not executableCheck the event name and run chmod +x for scripts.
MCP server failsPlugin path is hard-coded or binary is missingUse ${CLAUDE_PLUGIN_ROOT} and document required binaries.
LSP error says executable not foundLanguage server is not installedInstall the language server binary on the user’s machine.
Custom path ignoredManifest path replaces the default directoryAdd the default path explicitly or remove the custom path.

Installation Scopes

When installing a plugin, choose a scope based on who should receive it:

ScopeSettings fileBest for
user~/.claude/settings.jsonPersonal plugins available across projects
project.claude/settings.jsonTeam plugins shared through version control
local.claude/settings.local.jsonProject-specific plugins that should stay local
managedManaged settingsOrganisation-managed plugins

Examples:

claude plugin install formatter@team-marketplace
claude plugin install formatter@team-marketplace --scope project
claude plugin update formatter
claude plugin uninstall formatter --keep-data

Converting Standalone Configuration to a Plugin

If you already have commands, skills, agents, or hooks in your project’s .claude/ directory, you can migrate them into a plugin.

Step 1 — Create the plugin structure

mkdir -p my-plugin/.claude-plugin

my-plugin/.claude-plugin/plugin.json:

{
  "name": "my-plugin",
  "description": "Migrated from standalone configuration",
  "version": "1.0.0"
}

Step 2 — Copy your existing files

cp -r .claude/commands my-plugin/
cp -r .claude/agents my-plugin/   # if any
cp -r .claude/skills my-plugin/   # if any

Step 3 — Migrate hooks

mkdir my-plugin/hooks

Copy the hooks object from your .claude/settings.json or settings.local.json into my-plugin/hooks/hooks.json. The format is identical.

Step 4 — Test the migrated plugin

claude --plugin-dir ./my-plugin

Test each component: run your skills, check agents appear in /agents, and verify hooks trigger correctly. After confirming everything works, remove the originals from .claude/ to avoid duplicates. The plugin version takes precedence when loaded.

What changes after migration

Standalone (.claude/)Plugin
Only available in one projectShareable via marketplaces
Files in .claude/commands/Files in plugin-name/commands/
Hooks in settings.jsonHooks in hooks/hooks.json
Must be copied manually to shareInstalled with /plugin install

Sharing and Distribution

Prepare your plugin for release

  1. Add a README.md with installation and usage instructions
  2. Choose a versioning strategy:
    • Set an explicit version in plugin.json — users only receive updates when you bump the version
    • Omit version — if distributed via git, the commit SHA is used and every commit is treated as a new version
  3. Create or use a marketplace for distribution
  4. Have teammates test before a wider release

Marketplace file

A marketplace is a catalog of plugins. Put its manifest at .claude-plugin/marketplace.json in the marketplace repository:

{
  "name": "company-tools",
  "owner": {
    "name": "DevTools Team",
    "email": "devtools@example.com"
  },
  "plugins": [
    {
      "name": "code-formatter",
      "source": "./plugins/formatter",
      "description": "Automatic code formatting on save",
      "version": "2.1.0"
    },
    {
      "name": "deployment-tools",
      "source": {
        "source": "github",
        "repo": "company/deploy-plugin"
      },
      "description": "Deployment automation tools"
    }
  ]
}

Marketplace fields:

FieldRequiredDescription
nameYesMarketplace identifier used in install commands such as /plugin install tool@company-tools.
ownerYesMaintainer information. owner.name is required; owner.email is optional.
pluginsYesArray of plugin entries.
$schemaNoJSON Schema URL for editor support.
descriptionNoMarketplace description.
versionNoMarketplace manifest version.
metadata.pluginRootNoBase directory prepended to relative plugin source paths.
allowCrossMarketplaceDependenciesOnNoOther marketplaces that dependencies may come from.

Plugin entry fields:

FieldRequiredDescription
nameYesPlugin identifier.
sourceYesWhere Claude Code fetches the plugin from.
descriptionNoShort plugin description.
versionNoPlugin version. If set here or in plugin.json, users update only when the version changes.
categoryNoMarketplace grouping for browsing.
tagsNoSearch tags.
strictNoControls how marketplace metadata interacts with the plugin’s own manifest.

Plugin source types:

SourceExampleNotes
Relative path"./plugins/formatter"Resolved relative to the marketplace root. Must start with ./.
GitHub{ "source": "github", "repo": "company/deploy-plugin" }Supports optional ref or exact sha.
Git URL{ "source": "url", "url": "https://git.example.com/plugin.git" }Useful for non-GitHub git hosts.
Git subdirectory{ "source": "git-subdir", "url": "...", "path": "plugins/foo" }Useful for monorepos.
npm{ "source": "npm", "package": "@company/claude-plugin" }Installed through npm.

Users add a marketplace first, then install individual plugins:

claude plugin marketplace add acme-corp/claude-plugins
claude plugin marketplace list
claude plugin marketplace update
claude plugin install formatter@company-tools

Project teams can add known marketplaces and default plugins to .claude/settings.json so collaborators are prompted after trusting the repository:

{
  "extraKnownMarketplaces": {
    "company-tools": {
      "source": {
        "source": "github",
        "repo": "your-org/claude-plugins"
      }
    }
  },
  "enabledPlugins": {
    "code-formatter@company-tools": true,
    "deployment-tools@company-tools": true
  }
}

Submit to the official Anthropic marketplace

Once listed, you can prompt Claude Code users to install your plugin directly from your CLI. See Recommend your plugin from your CLI.

For internal team plugins, host a private marketplace in a private repository. See Plugin marketplaces.


Further Reading

TopicLink
Discover and install prebuilt pluginscode.claude.com/docs/en/discover-plugins
Full plugin technical referencecode.claude.com/docs/en/plugins-reference
Agent skills guidecode.claude.com/docs/en/skills
Custom subagentscode.claude.com/docs/en/sub-agents
Hooks guidecode.claude.com/docs/en/hooks
MCP integrationcode.claude.com/docs/en/mcp
Plugin marketplacescode.claude.com/docs/en/plugin-marketplaces
Share :
comments powered by Disqus

Related Posts

Claude Notes

Claude is a family of large language models developed by Anthropic, designed to be helpful, harmless, and honest. This document provides an overview of Claude’s capabilities, architecture, and applications — with all examples using LangChain (Python).

Read More

Testing LLM Outputs: Evals for Models, Agents, and Skills

LLM outputs are non-deterministic, which breaks the assumptions most of our testing tooling is built on. This document covers how to actually test model outputs, agent trajectories, and Claude Code-style skills — the layers of evaluation, the current 2026 tool landscape, and a working CI harness you can copy.

Read More