File Deleted
View Diff
1> ## Documentation Index
2> Fetch the complete documentation index at: https://code.claude.com/docs/llms.txt
3> Use this file to discover all available pages before exploring further.
4
5# Plugins reference
6
7> Complete technical reference for Claude Code plugin system, including schemas, CLI commands, and component specifications.
8
9<Tip>
10 Looking to install plugins? See [Discover and install plugins](/docs/en/discover-plugins). For creating plugins, see [Plugins](/docs/en/plugins). For distributing plugins, see [Plugin marketplaces](/docs/en/plugin-marketplaces).
11</Tip>
12
13A **plugin** is a self-contained directory of components that extends Claude Code with custom functionality. Plugin components include skills, agents, hooks, MCP servers, LSP servers, and monitors.
14
15## Plugin components reference
16
17### Skills
18
19Plugins add skills to Claude Code, creating `/name` shortcuts that you or Claude can invoke.
20
21**Location**: `skills/` or `commands/` directory in plugin root, or a single `SKILL.md` file at the plugin root
22
23**File format**: Skills are directories with `SKILL.md`; commands are simple markdown files
24
25**Skill structure**:
26
27```text theme={null}
28skills/
29├── pdf-processor/
30│ ├── SKILL.md
31│ ├── reference.md (optional)
32│ └── scripts/ (optional)
33└── code-reviewer/
34 └── SKILL.md
35```
36
37Skills and commands are automatically discovered when the plugin is installed.
38
39If a plugin has no `skills/` directory and no `skills` manifest field, a `SKILL.md` at the plugin root is loaded as a single skill. Set the frontmatter `name` field to control the skill's invocation name. Without it, Claude Code falls back to the install directory name. For a plugin [copied into the cache](#plugin-caching-and-file-resolution), that name is a version string that changes on every update. For plugins that ship more than one skill, use the `skills/` directory layout shown above.
40
41In plugin skills and commands, Boolean frontmatter fields such as `disable-model-invocation` accept `yes`, `no`, `on`, `off`, `1`, and `0` in any letter case, in addition to `true` and `false`. Before v2.1.218, Claude Code recognized only `true` and `false`.
42
43For complete details, see [Skills](/docs/en/skills).
44
45### Agents
46
47Plugins can provide specialized subagents for specific tasks that Claude can invoke automatically when appropriate.
48
49**Location**: `agents/` directory in plugin root
50
51**File format**: Markdown files describing agent capabilities
52
53**Agent structure**:
54
55```markdown theme={null}
56name: agent-name
57description: What this agent specializes in and when Claude should invoke it
58model: sonnet
59effort: medium
60maxTurns: 20
61disallowedTools: Write, Edit
62
63Detailed system prompt for the agent describing its role, expertise, and behavior.
64```
65
66#### Plugin agent frontmatter
67
68A plugin agent file uses the same [frontmatter fields as a subagent file](/docs/en/sub-agents#supported-frontmatter-fields), except that Claude Code honors only some of them when the agent comes from a plugin:
69
70* **Supported**: `name`, `description`, `model`, `effort`, `maxTurns`, `tools`, `disallowedTools`, `skills`, `memory`, `background`, `omitClaudeMd`, `isolation`, `color`, and `experimental`. The only valid `isolation` value is `"worktree"`.
71* **Not supported, for security reasons**: `hooks`, `mcpServers`, and `permissionMode`. Claude Code ignores these when loading an agent from a plugin. To use them, copy the agent file into `.claude/agents/` or `~/.claude/agents/`.
72* **Not supported**: `initialPrompt`.
73
74You can put plugin agent files in subfolders of `agents/`. Claude Code [loads them recursively](/docs/en/sub-agents#choose-the-subagent-scope) and joins the plugin name, each subfolder name, and the file name with colons to form the agent's scoped name. For example, `agents/review/security.md` in a plugin named `my-plugin` loads as `my-plugin:review:security`. Two settings change that name:
75
76* Frontmatter `name`: it replaces only the file name, so `name: audit` in `agents/review/security.md` loads as `my-plugin:review:audit`
77* Manifest [`agents`](#component-path-fields) field: a file you list there loads without subfolder names, so `"agents": "./custom/review/security.md"` loads as `my-plugin:security`
78
79Claude Code loads a plugin agent even when its frontmatter has no `name` or doesn't parse:
80
81* No `name`: Claude Code names the agent after the file, so `agents/reviewer.md` in a plugin named `my-plugin` loads as `my-plugin:reviewer`
82* Frontmatter that doesn't parse: Claude Code names the agent after the file, uses `Agent from my-plugin plugin` as its description, and ignores every field in the file
83
84By contrast, Claude Code skips a project, user, or managed agent file whose frontmatter has no `name` or doesn't parse.
85
86To find files in a plugin's default `agents/` directory whose frontmatter doesn't parse, run `claude plugin validate`. The path you pass depends on whether the plugin has a manifest, and both examples use `./my-plugin` as the plugin directory:
87
88* A plugin with a manifest: `claude plugin validate ./my-plugin`
89* A plugin without a manifest: `claude plugin validate ./my-plugin/agents`. Requires Claude Code v2.1.233 or later.
90
91Agents appear in the [@-mention typeahead](/docs/en/sub-agents#invoke-subagents-explicitly) under their scoped name, such as `my-plugin:code-reviewer`, once the plugin is enabled.
92
93For complete details, see [Subagents](/docs/en/sub-agents).
94
95### Hooks
96
97Plugins can provide event handlers that respond to Claude Code events automatically.
98
99**Location**: `hooks/hooks.json` in plugin root, or inline in plugin.json
100
101**Format**: JSON configuration with event matchers and actions
102
103`hooks/hooks.json` can carry a top-level `$schema` key that names a JSON Schema URL for editor autocomplete and validation. Claude Code ignores the key at load time.
104
105**Hook configuration**:
106
107```json theme={null}
108{
109 "hooks": {
110 "PostToolUse": [
111 {
112 "matcher": "Write|Edit",
113 "hooks": [
114 {
115 "type": "command",
116 "command": "\"${CLAUDE_PLUGIN_ROOT}\"/scripts/format-code.sh"
117 }
118 ]
119 }
120 ]
121 }
122}
123```
124
125Plugin hooks respond to the same lifecycle events as [user-defined hooks](/docs/en/hooks):
126
127| Event | When it fires |
128| :-------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
129| `SessionStart` | When a session begins or resumes |
130| `Setup` | When you start Claude Code with `--init-only`, or with `--init` or `--maintenance` in `-p` mode. For one-time preparation in CI or scripts |
131| `UserPromptSubmit` | When you submit a prompt, before Claude processes it |
132| `UserPromptExpansion` | When a user-typed command expands into a prompt, before it reaches Claude. Can block the expansion |
133| `PreToolUse` | Before a tool call executes. Can block it |
134| `PermissionRequest` | When a tool call needs a permission decision |
135| `PermissionDenied` | When auto mode denies a tool call, including denials without a classifier verdict. Use JSON `hookSpecificOutput.retry: true` to tell the model it may retry the denied tool call. Claude Code ignores `retry` when the classifier produced no verdict |
136| `PostToolUse` | After a tool call succeeds |
137| `PostToolUseFailure` | After a tool call fails |
138| `PostToolBatch` | After a full batch of parallel tool calls resolves, before the next model call |
139| `Notification` | When Claude Code sends a notification |
140| `MessageDisplay` | While assistant message text is displayed |
141| `SubagentStart` | When a subagent is spawned |
142| `SubagentStop` | When a subagent finishes |
143| `TaskCreated` | When a task is being created via `TaskCreate` |
144| `TaskCompleted` | When a task is being marked as completed |
145| `Stop` | When Claude finishes responding |
146| `StopFailure` | When the turn ends due to an API error |
147| `TeammateIdle` | When an [agent team](/docs/en/agent-teams) teammate is about to go idle |
148| `InstructionsLoaded` | When a CLAUDE.md or `.claude/rules/*.md` file is loaded into context. Fires at session start and when files are lazily loaded during a session |
149| `ConfigChange` | When a configuration file changes during a session |
150| `CwdChanged` | When the working directory changes, for example when Claude executes a `cd` command. Useful for reactive environment management with tools like direnv |
151| `DirectoryAdded` | When a working directory is added mid-session via `/add-dir` or the SDK `register_repo_root` control request |
152| `FileChanged` | When a watched file changes on disk. The `matcher` field specifies which filenames to watch |
153| `WorktreeCreate` | When a worktree is being created via `--worktree`, `isolation: "worktree"`, or for a background session. Replaces default git behavior |
154| `WorktreeRemove` | When a worktree is being removed at session exit, when a subagent finishes, or when you delete a background session |
155| `PreCompact` | Before context compaction |
156| `PostCompact` | After context compaction completes |
157| `PreModelSwitch` | Before Claude Code applies a model switch that you or a client requested. Can block the switch |
158| `PostModelSwitch` | After the session's model changes, including changes Claude Code makes on its own, such as restoring the model when you resume a session |
159| `Elicitation` | When an MCP server requests user input during a tool call |
160| `ElicitationResult` | After a user responds to an MCP elicitation, before the response is sent back to the server |
161| `SessionEnd` | When a session terminates |
162
163**Hook types**:
164
165* `command`: execute shell commands or scripts
166* `http`: send the event JSON as a POST request to a URL
167* `mcp_tool`: call a tool on a configured [MCP server](/docs/en/mcp)
168* `prompt`: evaluate a prompt with an LLM (uses `$ARGUMENTS` placeholder for context)
169* `agent`: run an agentic verifier with tools for complex verification tasks
170
171Hooks that target the plugin's own [bundled MCP server](#mcp-servers) must use its scoped names. Tool matchers and `if` fields take the scoped tool name `mcp__plugin_<plugin-name>_<server-name>__<tool>`, and an `mcp_tool` hook's `server` field takes `plugin:<plugin-name>:<server-name>`. A matcher written against the bare server key never fires. See [Match MCP tools](/docs/en/hooks#match-mcp-tools) and [Plugin-provided MCP servers](/docs/en/mcp#plugin-provided-mcp-servers).
172
173### MCP servers
174
175Plugins can bundle Model Context Protocol (MCP) servers to connect Claude Code with external tools and services.
176
177**Location**: `.mcp.json` in plugin root, or inline in plugin.json
178
179**Format**: Standard MCP server configuration
180
181**MCP server configuration**:
182
183```json theme={null}
184{
185 "mcpServers": {
186 "plugin-database": {
187 "command": "${CLAUDE_PLUGIN_ROOT}/servers/db-server",
188 "args": ["--config", "${CLAUDE_PLUGIN_ROOT}/config.json"],
189 "env": {
190 "DB_PATH": "${CLAUDE_PLUGIN_ROOT}/data"
191 }
192 },
193 "plugin-api-client": {
194 "command": "npx",
195 "args": ["@company/mcp-server", "--plugin-mode"]
196 }
197 }
198}
199```
200
201**Integration behavior**:
202
203* Plugin MCP servers start automatically when the plugin is enabled
204* Servers appear as standard MCP tools in Claude's toolkit
205* Plugin servers can be configured independently of user MCP servers
206* If you run [`/reload-plugins`](/docs/en/discover-plugins#apply-plugin-changes-without-restarting) mid-session, Claude Code keeps the live connections of servers whose configuration is unchanged
207
208### LSP servers
209
210<Tip>
211 Looking to use LSP plugins? Install them from the official marketplace: search for "lsp" in the `/plugin` Discover tab. This section documents how to create LSP plugins for languages not covered by the official marketplace.
212</Tip>
213
214Plugins can provide [Language Server Protocol](https://microsoft.github.io/language-server-protocol/) (LSP) servers to give Claude [real-time code intelligence](/docs/en/discover-plugins#code-intelligence) while working on your codebase.
215
216**Location**: `.lsp.json` in plugin root, or inline in `plugin.json`
217
218**Format**: JSON configuration mapping language server names to their configurations
219
220**`.lsp.json` file format**:
221
222```json theme={null}
223{
224 "go": {
225 "command": "gopls",
226 "args": ["serve"],
227 "extensionToLanguage": {
228 ".go": "go"
229 }
230 }
231}
232```
233
234**Inline in `plugin.json`**:
235
236```json theme={null}
237{
238 "name": "my-plugin",
239 "lspServers": {
240 "go": {
241 "command": "gopls",
242 "args": ["serve"],
243 "extensionToLanguage": {
244 ".go": "go"
245 }
246 }
247 }
248}
249```
250
251**Required fields:**
252
253| Field | Description |
254| :-------------------- | :------------------------------------------- |
255| `command` | The LSP binary to execute (must be in PATH) |
256| `extensionToLanguage` | Maps file extensions to language identifiers |
257
258**Optional fields:**
259
260| Field | Description |
261| :---------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
262| `args` | Command-line arguments for the LSP server |
263| `transport` | Communication transport: `stdio` (default) or `socket`. Claude Code accepts `socket` but runs every server over stdio, so the stdout protocol rules apply to all servers |
264| `env` | Environment variables to set when starting the server |
265| `initializationOptions` | Options passed to the server during initialization |
266| `settings` | Settings passed via `workspace/didChangeConfiguration` |
267| `workspaceFolder` | Workspace folder path for the server |
268| `startupTimeout` | Max time to wait for server startup (milliseconds) |
269| `shutdownTimeout` | Max time to wait for graceful shutdown (milliseconds). When the timeout elapses, Claude Code terminates the server process. When unset, no timeout applies |
270| `restartOnCrash` | Whether to restart the server after it crashes. Defaults to `true`. Set to `false` to leave a crashed server stopped instead of restarting it |
271| `maxRestarts` | Maximum number of restart attempts before giving up |
272| `diagnostics` | Whether to push diagnostics into Claude's context after edits (default `true`). Set to `false` to keep code navigation but suppress automatic diagnostic injection. |
273
274`restartOnCrash` and `shutdownTimeout` require Claude Code v2.1.205 or later. Before v2.1.205, the config schema accepted both options but setting either one caused Claude Code to skip that LSP server entirely at startup, with the reason visible only in `claude --debug` output.
275
276**Multiple servers for the same extension**: when more than one enabled LSP server declares the same file extension in `extensionToLanguage`, whether the servers come from one plugin or from different plugins, the first server registered handles files with that extension and the others never start. The `/plugin` interface shows a warning naming the plugin whose server is active.
277
278**Servers that fail to initialize**: Claude Code skips a server whose configuration is invalid, for example one missing `command` or `extensionToLanguage`, and the other configured servers still start. Run `claude --debug` to see why a server was skipped.
279
280A skipped server doesn't claim its file extensions, so another valid server that declares the same extension, from the same or a different plugin, still handles those files.
281
282**Send log output to stderr, not stdout**: Claude Code reads a server's stdout as protocol messages only, and accepts message headers up to 64 KiB and a message body up to 32 MiB. Claude Code disconnects a server that exceeds either limit or writes non-protocol output to stdout, and counts the disconnect as a crash for `restartOnCrash` and `maxRestarts`. When you run with `--debug`, Claude Code writes an error naming the cause to the debug log.
283
284<Warning>
285 **You must install the language server binary separately.** LSP plugins configure how Claude Code connects to a language server, but they don't include the server itself. If you see `Executable not found in $PATH` in the `/plugin` Errors tab, install the required binary for your language.
286</Warning>
287
288**Available LSP plugins:**
289
290| Plugin | Language server | Install command |
291| :------------------ | :------------------------- | :----------------------------------------------------------------------------------------- |
292| `pyright-lsp` | Pyright (Python) | `pip install pyright` or `npm install -g pyright` |
293| `typescript-lsp` | TypeScript Language Server | `npm install -g typescript-language-server typescript` |
294| `rust-analyzer-lsp` | rust-analyzer | [See rust-analyzer installation](https://rust-analyzer.github.io/manual.html#installation) |
295
296Install the language server first, then install the plugin from the marketplace.
297
298### Monitors
299
300Plugins can declare background monitors that Claude Code starts automatically when the plugin is active. Each monitor runs a shell command for the lifetime of the session and delivers every stdout line to Claude as a notification, so Claude can react to log entries, status changes, or polled events without being asked to start the watch itself.
301
302Plugin monitors use the same mechanism as the [Monitor tool](/docs/en/tools-reference#monitor-tool) and share its availability constraints. They run only in interactive CLI sessions, run unsandboxed at the same trust level as [hooks](#hooks), and are skipped on hosts where the Monitor tool is unavailable.
303
304**Location**: `monitors/monitors.json` in the plugin root, or inline in `plugin.json`
305
306**Format**: JSON array of monitor entries
307
308The following `monitors/monitors.json` watches a deployment status endpoint and a local error log:
309
310```json theme={null}
311[
312 {
313 "name": "deploy-status",
314 "command": "\"${CLAUDE_PLUGIN_ROOT}\"/scripts/poll-deploy.sh",
315 "description": "Deployment status changes"
316 },
317 {
318 "name": "error-log",
319 "command": "tail -F ./logs/error.log",
320 "description": "Application error log",
321 "when": "on-skill-invoke:debug"
322 }
323]
324```
325
326To declare monitors inline, set `experimental.monitors` in `plugin.json` to the same array. To load from a non-default path, set `experimental.monitors` to a relative path string such as `"./config/monitors.json"`. Monitors are an [experimental component](#experimental-components).
327
328**Required fields:**
329
330| Field | Description |
331| :------------ | :-------------------------------------------------------------------------------------------------------------------- |
332| `name` | Identifier unique within the plugin. Prevents duplicate processes when the plugin reloads or a skill is invoked again |
333| `command` | Shell command run as a persistent background process in the session working directory |
334| `description` | Short summary of what is being watched. Shown in the task panel and in notification summaries |
335
336**Optional fields:**
337
338| Field | Description |
339| :----- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
340| `when` | Controls when the monitor starts. `"always"` starts it at session start and on plugin reload, and is the default. `"on-skill-invoke:<skill-name>"` starts it the first time the named skill in this plugin is dispatched |
341
342The `command` value supports the [path substitutions](#environment-variables) `${CLAUDE_PLUGIN_ROOT}`, `${CLAUDE_PLUGIN_DATA}`, and `${CLAUDE_PROJECT_DIR}`, plus any `${ENV_VAR}` from the environment. Prefix the command with `cd "${CLAUDE_PLUGIN_ROOT}" && ` if the script needs to run from the plugin's own directory.
343
344A monitor `command` can't reference [`${user_config.*}`](#user-configuration) values. The command runs through a shell, so Claude Code rejects the monitor with an [error](/docs/en/errors#plugin-command-references-user-config) instead of substituting the value. Monitor processes don't receive `CLAUDE_PLUGIN_OPTION_<KEY>` environment variables, so have the monitor script read the value from a config file it owns.
345
346If you disable a plugin mid-session, Claude Code doesn't stop monitors that are already running; they stop when the session ends.
347
348### Themes
349
350Plugins can ship color themes that appear in `/theme` alongside the built-in presets and the user's local themes. A theme is a JSON file in `themes/` with a `base` preset and a sparse `overrides` map of color tokens. Themes are an [experimental component](#experimental-components).
351
352```json theme={null}
353{
354 "name": "Dracula",
355 "base": "dark",
356 "overrides": {
357 "claude": "#bd93f9",
358 "error": "#ff5555",
359 "success": "#50fa7b"
360 }
361}
362```
363
364When a user selects a plugin theme, Claude Code saves `custom:<plugin-name>:<slug>` in their config. Plugin themes are read-only: when a user presses `Ctrl+E` on one in `/theme`, Claude Code copies it into `~/.claude/themes/` so they can edit the copy.
365
366***
367
368## Plugin installation scopes
369
370When you install a plugin, you choose a **scope** that determines where the plugin is available and who else can use it:
371
372| Scope | Settings file | Use case |
373| :-------- | :--------------------------------------- | :-------------------------------------------------------------------------- |
374| `user` | `~/.claude/settings.json` | Personal plugins available across all projects (default) |
375| `project` | `.claude/settings.json` | Team plugins shared via version control |
376| `local` | `.claude/settings.local.json` | Project-specific plugins, gitignored when Claude Code saves a setting to it |
377| `managed` | [Managed settings](/docs/en/managed-settings) | Managed plugins (read-only, update only) |
378
379Plugins use the same scope system as other Claude Code configurations. For installation instructions and scope flags, see [Install plugins](/docs/en/discover-plugins#install-plugins). For a complete explanation of scopes, see [Configuration scopes](/docs/en/settings#where-settings-live).
380
381***
382
383## Skills-directory plugins
384
385Any folder under a skills directory that contains a `.claude-plugin/plugin.json` manifest is loaded as a plugin named `<name>@skills-dir` on the next session, with no marketplace and no install step. Scaffold one with [`plugin init`](#plugin-init). Unlike a copied marketplace install, the plugin is discovered in place rather than copied into the plugin cache.
386
387A skills directory tree supports three distinct things:
388
389| What you have | What it is |
390| :-------------------------------------------- | :---------------------------------------------------------------------------------- |
391| `<skills-dir>/foo/SKILL.md` with no manifest | A plain [skill](/docs/en/skills) named `foo` |
392| `<skills-dir>/foo/.claude-plugin/plugin.json` | A plugin `foo@skills-dir`, which can bundle its own skills, agents, hooks, and more |
393| `<plugin>/skills/bar/SKILL.md` | A skill `bar` packaged inside a plugin |
394
395### Choose where the plugin loads from
396
397| Skills directory | Scope | Loads |
398| :---------------------- | :------- | :---------------------------------------------------------------------------------------------------------------------- |
399| `~/.claude/skills/` | personal | In every project, since the location is yours alone |
400| `<cwd>/.claude/skills/` | project | Only after you accept the workspace [trust dialog](/docs/en/permissions#what-runs-before-you-trust-a-folder) for that folder |
401
402A project-scope plugin is checked into the repository and reaches every collaborator who clones it. Because that content comes from the repository rather than from you, it loads only after the same trust gate that governs project allow rules in `.claude/settings.json`, so trusting a parent folder or running with `-p` isn't enough, and components that run code are restricted further:
403
404* MCP servers it declares go through the [same per-server approval](/docs/en/mcp) as a project `.mcp.json`
405* LSP servers start only after you trust the workspace
406* [Background monitors](#monitors) do not load
407
408Personal-scope plugins have none of these restrictions.
409
410<Warning>
411 Project-scope `@skills-dir` plugins load only from the `.claude/skills/` of the session's [primary working directory](/docs/en/permissions#working-directories). They don't [walk up to the repository root](/docs/en/skills#discovery-from-parent-and-nested-directories) the way plain skills and commands do, so launching from a subdirectory misses a plugin that lives at the repo root. Launch from the repository root, or [move the session there with `/cd`](/docs/en/permissions#move-the-session-to-another-directory) on v2.1.246 or later.
412</Warning>
413
414### Edit, reload, and disable a skills-directory plugin
415
416Changes you make to a skill's `SKILL.md` take effect immediately in the current session. Changes to the plugin's other components, such as `hooks/`, `.mcp.json`, `agents/`, and `output-styles/`, do not. Run `/reload-plugins` or restart Claude Code to pick those up. See [Live change detection](/docs/en/skills#live-change-detection).
417
418To stop loading a skills-directory plugin, delete its folder or disable it by name. There is no `uninstall` step because nothing was installed from a marketplace.
419
420```bash theme={null}
421claude plugin disable my-tool@skills-dir
422```
423
424***
425
426<h2 id="synced-plugins">
427 Plugins synced from claude.ai
428</h2>
429
430Claude Code loads the plugins enabled for your claude.ai account, including plugins your organization turns on for its members, alongside the plugins you install from marketplaces. It downloads each one into `~/.claude/plugins/synced/` and loads it as `<name>@synced`, with no marketplace and no install record. A synced plugin runs with the same trust as a marketplace plugin you installed: its skills, agents, hooks, MCP servers, and LSP servers all load.
431
432Where Claude Code syncs these plugins depends on the session:
433
434* In [Cowork](https://claude.com/product/cowork) and [cloud sessions](/docs/en/cloud-environments#what-carries-over-from-your-setup), Claude Code downloads them into the session's own environment when the session starts. Before v2.1.239, Claude Code loaded these plugins as `<name>@inline`, the identity that `--plugin-dir` plugins use.
435* In terminal sessions where you sign in with your claude.ai account, Claude Code checks your account once each time it starts, then downloads new and updated plugins and removes the ones that you or your organization turned off, all in the background. Syncing in terminal sessions requires Claude Code v2.1.273 or later.
436
437The launch check runs in the background, so it can finish after your session has started. When it adds, updates, or removes a synced plugin in an interactive session, Claude Code shows `Plugins changed. Run /reload-plugins to activate.` Run [`/reload-plugins`](/docs/en/discover-plugins#apply-plugin-changes-without-restarting) to load the change in that session, or leave it for the next time you start Claude Code. If you enable a plugin on claude.ai while a session is running, Claude Code downloads it the next time it starts.
438
439Plugin sync in terminal sessions runs under the same sign-in conditions as [skills synced from claude.ai](/docs/en/skills#where-synced-skills-load). It also needs a sign-in that grants Claude Code access to your account's plugins.
440
441A sign-in from an earlier version of Claude Code picks up plugin access the next time Claude Code renews that sign-in in the background, within a few hours, or right away if you run `/login` again. Plugin sync starts the next time you start Claude Code after that.
442
443`claude plugin list` shows synced plugins under a `Synced from claude.ai` heading, and the `/plugin` **Installed** tab lists them with `synced` as their source. Manage a synced plugin by the `<name>@synced` ID that `claude plugin list` prints:
444
445* **Turn one off**: run `claude plugin disable <name>@synced`, or disable it from the `/plugin` **Installed** tab. Claude Code saves the choice as `"<name>@synced": false` in your user-level [`enabledPlugins`](/docs/en/settings-reference#enabledplugins). To turn the plugin back on, run `claude plugin enable <name>@synced`.
446* **Keep one out everywhere**: [turn the plugin off for your claude.ai account](/docs/en/desktop#extend-claude-code). To keep it out of one project in every environment, set `"<name>@synced": false` under `enabledPlugins` in that project's committed `.claude/settings.json`.
447* **Manage the plugin itself on claude.ai**: `claude plugin install`, `update`, and `uninstall` don't apply to a synced plugin. Claude Code downloads a plugin's updates at the next sync. To remove one, turn the plugin off for your claude.ai account, and Claude Code removes it at the next sync.
448* **Stop syncing on a machine**: set [`syncClaudeAiPlugins`](/docs/en/settings-reference#syncclaudeaiplugins) to `false` in your user settings. Claude Code stops downloading, and the next time it starts it moves the plugins it already synced to `~/.claude/plugins/.trash/` and no longer loads them. Your organization can set the same key in [managed settings](/docs/en/managed-settings), or turn off Skills on claude.ai, which stops plugins from syncing too.
449
450You can't turn off a plugin that your organization marks as required on claude.ai. Claude Code loads it even if you disabled it earlier, and `claude plugin disable` refuses with `Plugin "<name>@synced" is required by your organization and can't be disabled here. Contact your admin to change it.` In `claude plugin list`, these plugins are marked `required by your org`.
451
452When an enabled plugin from any other source matches a synced plugin's name, Claude Code loads that plugin and reports the synced copy as not loaded. Other sources include marketplace installs, [skills-directory plugins](#skills-directory-plugins), `--plugin-dir` plugins, and plugins built into Claude Code. To use the claude.ai copy instead, disable your own copy. Before v2.1.239, Claude Code loaded the synced copy instead of a same-named marketplace install.
453
454***
455
456## Plugin manifest schema
457
458The `.claude-plugin/plugin.json` file defines your plugin's metadata and configuration.
459
460The manifest is optional. If omitted, Claude Code auto-discovers components in [default locations](#file-locations-reference) and derives the plugin name from the directory name. Use a manifest when you need to provide metadata or custom component paths.
461
462### Complete schema
463
464```json theme={null}
465{
466 "name": "plugin-name",
467 "displayName": "Plugin Name",
468 "version": "1.2.0",
469 "description": "Brief plugin description",
470 "author": {
471 "name": "Author Name",
472 "email": "author@example.com",
473 "url": "https://github.com/author"
474 },
475 "homepage": "https://docs.example.com/plugin",
476 "repository": "https://github.com/author/plugin",
477 "license": "MIT",
478 "keywords": ["keyword1", "keyword2"],
479 "metadata": { "catalogId": "cat-123", "tier": "pro" },
480 "skills": "./custom/skills/",
481 "commands": ["./custom/commands/special.md"],
482 "agents": ["./custom/agents/reviewer.md"],
483 "hooks": "./config/hooks.json",
484 "mcpServers": "./mcp-config.json",
485 "outputStyles": "./styles/",
486 "lspServers": "./.lsp.json",
487 "experimental": {
488 "themes": "./themes/",
489 "monitors": "./monitors.json",
490 "evals": "quality/evals"
491 },
492 "dependencies": [
493 "helper-lib",
494 { "name": "secrets-vault", "version": "~2.1.0" }
495 ]
496}
497```
498
499### Required fields
500
501If you include a manifest, `name` is the only required field.
502
503| Field | Type | Description | Example |
504| :----- | :----- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------- |
505| `name` | string | Unique identifier in kebab-case, with no spaces, control characters, or bidirectional-formatting characters. When a [marketplace entry](/docs/en/plugin-marketplaces#plugin-entries) lists the plugin under a different name, the marketplace entry name is what `enabledPlugins` keys and `/plugin` use | `"deployment-tools"` |
506
507This name is used for namespacing components. For example, in the UI, the
508agent `agent-creator` for the plugin with name `plugin-dev` will appear as
509`plugin-dev:agent-creator`.
510
511### Unrecognized fields
512
513Claude Code ignores top-level fields it does not recognize. You can keep
514metadata from another ecosystem in `plugin.json` and the plugin still loads.
515This makes it practical to maintain one manifest that doubles as a VS Code or
516Cursor extension manifest, an npm `package.json`, or an MCPB/DXT bundle
517manifest.
518
519`claude plugin validate` reports unrecognized fields as warnings, not errors.
520If a field is one or two characters off from a recognized one, the warning
521suggests the likely intended name. A plugin with only unrecognized-field
522warnings still passes validation and loads at runtime.
523
524How Claude Code handles a recognized field whose value has the wrong type depends on the field:
525
526* **Most fields**: the plugin fails to load. For example, a `keywords` value that is a string instead of an array is a load error, and `claude plugin validate` reports it as one.
527* **`experimental` and `metadata`**: Claude Code ignores a non-object value, and `claude plugin validate` reports a warning.
528
529Pass `--strict` to treat warnings as errors. Use it in CI to catch a misspelled
530field name or a field left over from another tool's manifest before publishing,
531even though the plugin would load at runtime.
532
533```bash theme={null}
534claude plugin validate ./my-plugin --strict
535```
536
537### Metadata fields
538
539| Field | Type | Description | Example |
540| :--------------- | :------ | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------- |
541| `$schema` | string | JSON Schema URL for editor autocomplete and validation. Claude Code ignores this field at load time. | `"https://json.schemastore.org/claude-code-plugin-manifest.json"` |
542| `displayName` | string | Human-readable name shown in the `/plugin` picker and other UI surfaces. For a marketplace-installed plugin, a `displayName` on the [marketplace entry](/docs/en/plugin-marketplaces#optional-plugin-fields) takes precedence over this value. When no display name is set in either place, users see `name`. Unlike `name`, may contain spaces and any casing. Not used for namespacing or lookup. | `"Deployment Tools"` |
543| `version` | string | Optional. Semantic version. Setting this pins the plugin to that version string, so users only receive updates when you bump it, except for a [`command` source](/docs/en/plugin-marketplaces#command-sources) or a plugin [loaded in place](#plugin-caching-and-file-resolution); see [Version management](#version-management). If also set in the marketplace entry, `plugin.json` wins. If omitted, the version comes from the next source in [Version management](#version-management). | `"2.1.0"` |
544| `description` | string | Brief explanation of plugin purpose | `"Deployment automation tools"` |
545| `author` | object | Author information | `{"name": "Dev Team", "email": "dev@company.com"}` |
546| `homepage` | string | Documentation URL | `"https://docs.example.com"` |
547| `repository` | string | Source code URL | `"https://github.com/user/plugin"` |
548| `license` | string | License identifier | `"MIT"`, `"Apache-2.0"` |
549| `keywords` | array | Discovery tags | `["deployment", "ci-cd"]` |
550| `metadata` | object | Free-form object for your own data, such as entitlement or catalog fields. Claude Code doesn't read it, so the values never affect plugin behavior. Claude Code ignores a non-object value, and `claude plugin validate` reports it as a warning. Before v2.1.222, Claude Code treated the key as an [unrecognized field](#unrecognized-fields). | `{"catalogId": "cat-123"}` |
551| `defaultEnabled` | boolean | Whether the plugin starts in an enabled state when the user has not set one. Defaults to `true`. See [Default enablement](#default-enablement). | `false` |
552
553### Default enablement
554
555Set `defaultEnabled: false` in `plugin.json` to ship a plugin that installs disabled. The user turns it on with `claude plugin enable <plugin>` or the `/plugin` interface. Use this for plugins that add cost or scope a user should opt into, such as one that connects to an external service.
556
557`defaultEnabled` is the fallback when nothing else has decided the plugin's state. The user's setting and a dependency requirement take precedence over it:
558
559* **The user's setting**: an entry for the plugin in `enabledPlugins` at any settings scope. Once written, it persists across plugin updates and reinstalls, so changing `defaultEnabled` in a later release does not flip an existing user.
560* **A dependency requirement**: when a plugin is required by another one that is active, Claude Code writes `true` for it at install or enable time. That gives it an explicit setting, so its own default no longer applies. See [Enable or disable a plugin with dependencies](/docs/en/plugin-dependencies#enable-or-disable-a-plugin-with-dependencies).
561
562The same field can appear in a plugin's marketplace entry, where it takes precedence over the value in `plugin.json`. See [Optional plugin fields](/docs/en/plugin-marketplaces#optional-plugin-fields).
563
564### Component path fields
565
566| Field | Type | Description | Example |
567| :---------------------- | :-------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :--------------------------------------------------- |
568| `skills` | string\|array | Custom skill directories containing `<name>/SKILL.md`. Adds to the default `skills/` scan. See [Path behavior rules](#path-behavior-rules) for the marketplace-root exception | `"./custom/skills/"` |
569| `commands` | string\|array | Custom flat `.md` skill files or directories (replaces default `commands/`) | `"./custom/cmd.md"` or `["./cmd1.md"]` |
570| `agents` | string\|array | Custom agent files (replaces default `agents/`) | `"./custom/agents/reviewer.md"` |
571| `workflows` | string\|array | Custom [workflow](/docs/en/workflows) script files or directories (replaces default `workflows/`) | `"./custom/workflows/"` |
572| `hooks` | string\|array\|object | Hook config paths or inline config | `"./my-extra-hooks.json"` |
573| `mcpServers` | string\|array\|object | MCP config paths or inline config | `"./my-extra-mcp-config.json"` |
574| `outputStyles` | string\|array | Custom output style files/directories (replaces default `output-styles/`) | `"./styles/"` |
575| `lspServers` | string\|array\|object | [Language Server Protocol](https://microsoft.github.io/language-server-protocol/) configs for code intelligence (go to definition, find references, etc.) | `"./.lsp.json"` |
576| `experimental.themes` | string\|array | Color theme files/directories (replaces default `themes/`). See [Themes](#themes) | `"./themes/"` |
577| `experimental.monitors` | string\|array | Background [Monitor](/docs/en/tools-reference#monitor-tool) configurations that start automatically when the plugin is active. See [Monitors](#monitors) | `"./monitors.json"` |
578| `experimental.evals` | string\|array | Directory below the plugin root that holds the plugin's [eval cases](/docs/en/plugin-evals#use-a-different-eval-directory), when it isn't the default `evals/`. `claude plugin eval --eval-dir` overrides it | `"quality/evals"` |
579| `userConfig` | object | User-configurable values prompted at enable time. See [User configuration](#user-configuration) | |
580| `channels` | array | Channel declarations for message injection (Telegram, Slack, Discord style). See [Channels](#channels) | |
581| `dependencies` | array | Other plugins this plugin requires, optionally with semver version constraints. See [Constrain plugin dependency versions](/docs/en/plugin-dependencies) | `[{ "name": "secrets-vault", "version": "~2.1.0" }]` |
582
583### Experimental components
584
585Components under the `experimental` key, `themes` and `monitors`, have a manifest schema that may change between releases while they stabilize. Where you declare them is a separate migration: the top level still works, `claude plugin validate` warns, and a future release will require `experimental.*`.
586
587### User configuration
588
589The `userConfig` field declares values that Claude Code prompts the user for when the plugin is enabled. Use this instead of requiring users to hand-edit `settings.json`.
590
591```json theme={null}
592{
593 "userConfig": {
594 "api_endpoint": {
595 "type": "string",
596 "title": "API endpoint",
597 "description": "Your team's API endpoint"
598 },
599 "api_token": {
600 "type": "string",
601 "title": "API token",
602 "description": "API authentication token",
603 "sensitive": true
604 }
605 }
606}
607```
608
609Keys must be valid identifiers. Each option supports these fields:
610
611| Field | Required | Description |
612| :------------ | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
613| `type` | Yes | One of `string`, `number`, `boolean`, `directory`, or `file` |
614| `title` | Yes | Label shown in the configuration dialog |
615| `description` | Yes | Help text shown beneath the field |
616| `sensitive` | No | If `true`, masks input and stores the value in secure storage instead of `settings.json` |
617| `required` | No | If `true`, validation fails when the field is empty |
618| `default` | No | Value used when the user provides nothing |
619| `options` | No | For `string` type, the values the field accepts, shown in `/config` as a picker over them. See [Limit a field to fixed options](#limit-a-field-to-fixed-options). Requires Claude Code v2.1.271 or later |
620| `multiple` | No | For `string` type, allow an array of strings |
621| `min` / `max` | No | Bounds for `number` type |
622
623Except `sensitive` fields and `multiple` lists, each field of each enabled plugin also appears as a row in the `/config` panel. The rows require Claude Code v2.1.269 or later.
624
625Each value is available for substitution as `${user_config.KEY}` in MCP and LSP server configs and hook commands. Non-sensitive values can also be substituted in skill and agent content. All values are exported to hook processes as `CLAUDE_PLUGIN_OPTION_<KEY>` environment variables, where `<KEY>` is the option key uppercased.
626
627Fields that run in a shell reject `${user_config.*}`: substituting a configured value into a shell command would let the shell run whatever that value contains, so the component fails with an [error](/docs/en/errors#plugin-command-references-user-config) instead. Each rejected field has an alternative way to pass the value:
628
629| Rejected field | How to pass the value |
630| :--------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------- |
631| Shell-form hook commands | Use [exec form](/docs/en/hooks#exec-form-and-shell-form) with `args`, or read `CLAUDE_PLUGIN_OPTION_<KEY>` from the hook's environment |
632| [Monitor](#monitors) commands | Read the value from a config file in the script |
633| MCP [`headersHelper`](/docs/en/mcp#use-dynamic-headers-for-custom-authentication) | Read the value from a config file in the script |
634
635Before v2.1.207, these fields substituted `${user_config.KEY}` values; update plugins that relied on this.
636
637Non-sensitive values are stored under the [`pluginConfigs`](/docs/en/settings-reference#pluginconfigs) key in your user `settings.json` as `pluginConfigs[<plugin-id>].options`.
638
639On macOS, Claude Code stores sensitive values in the macOS Keychain, falling back to `~/.claude/.credentials.json` when the Keychain rejects the write. On platforms without a supported keychain, it stores them in `~/.claude/.credentials.json`. Keychain storage is shared with OAuth tokens and has an approximately 2 KB total limit, so keep sensitive values small.
640
641Claude Code reads all `pluginConfigs` values from only three settings sources:
642
643* **User settings**: `~/.claude/settings.json`, the file the enable-time prompt writes to
644* **`--settings`**: the CLI flag or SDK inline settings
645* **Managed settings**: [organization-controlled policy](/docs/en/permissions#managed-settings)
646
647When more than one source sets the same key, managed settings take precedence, then `--settings`, then user settings. The only source you can remove from this list is user settings: pass [`--setting-sources`](/docs/en/cli-reference#cli-flags) without `user` and Claude Code skips them. Managed settings and `--settings` stay whatever you pass. The SDK's [`settingSources`](/docs/en/agent-sdk/claude-code-features#what-settingsources-does-not-control) option sets the same list.
648
649Entries in a project's `.claude/settings.json` or `.claude/settings.local.json` are ignored. Both files live in the workspace, so a cloned repository could supply values there, and those values would flow into plugin hook commands, MCP server configs, LSP commands, and monitor commands. Before v2.1.207, these entries were read. The restriction is specific to `pluginConfigs`: [`enabledPlugins`](/docs/en/settings-reference#enabledplugins) still honors project and local settings.
650
651#### Limit a field to fixed options
652
653Set `options` on a `userConfig` field to make users pick its value from a fixed list.
654
655To limit a `tone` field to three options, list them in `options` and set `default` to one of them:
656
657```json theme={null}
658{
659 "userConfig": {
660 "tone": {
661 "type": "string",
662 "title": "Tone",
663 "description": "Voice for generated replies",
664 "options": ["neutral", "warm", "formal"],
665 "default": "neutral"
666 }
667 }
668}
669```
670
671If you declare `options` on any field, users on Claude Code versions before v2.1.271 can't load the plugin.
672
673When you set `options` on a field, follow these rules:
674
675* Set `type` to `string`
676* Don't set `multiple` or `sensitive` to `true`
677* Set `default` to one of the options
678* If you leave `default` unset, set `required` to `true`
679* List at least one option, each 1 to 64 characters long
680* Don't start or end an option with a space
681* Don't use control characters, invisible characters, characters that change text direction, or spaces other than a regular space in an option
682* Don't list the same option twice, even in a different letter case
683
684If you break any of these rules, the plugin fails to load. Run `claude plugin validate` to see which field breaks which rule.
685
686### Channels
687
688The `channels` field lets a plugin declare one or more message channels that inject content into the conversation. Each channel binds to an MCP server that the plugin provides.
689
690```json theme={null}
691{
692 "channels": [
693 {
694 "server": "telegram",
695 "userConfig": {
696 "bot_token": {
697 "type": "string",
698 "title": "Bot token",
699 "description": "Telegram bot token",
700 "sensitive": true
701 },
702 "owner_id": {
703 "type": "string",
704 "title": "Owner ID",
705 "description": "Your Telegram user ID"
706 }
707 }
708 }
709 ]
710}
711```
712
713The `server` field is required and must match a key in the plugin's `mcpServers`. The optional per-channel `userConfig` uses the same schema as the top-level field, letting the plugin prompt for bot tokens or owner IDs when the plugin is enabled.
714
715### Path behavior rules
716
717Whether a custom path replaces or extends the plugin's default directory depends on the field:
718
719* **Replaces the default**: `commands`, `agents`, `workflows`, `outputStyles`, `experimental.themes`, `experimental.monitors`. For example, when the manifest specifies `commands`, the default `commands/` directory is not scanned. To keep the default and add more, list it explicitly: `"commands": ["./commands/", "./extras/"]`
720* **Adds to the default**: `skills`. The default `skills/` directory is always scanned, and directories listed in `skills` are loaded alongside it. Exception: for a [marketplace entry whose `source` resolves to the marketplace root](/docs/en/plugin-marketplaces#advanced-plugin-entries), declaring specific subdirectories replaces the default `skills/` scan
721* **Own merge rules**: [hooks](#hooks), [MCP servers](#mcp-servers), and [LSP servers](#lsp-servers). See each section for how multiple sources combine
722
723When a plugin has both a default folder and the matching manifest key, Claude Code warns about the ignored folder in `claude plugin list` and the `/plugin` detail view. The plugin still loads using the manifest paths. Claude Code doesn't warn when the manifest key points into the default folder, for example `"commands": ["./commands/deploy.md"]`, because that path names the folder explicitly.
724
725For all path fields:
726
727* All paths must be relative to the plugin root and start with `./`, except that the `skills` field also accepts `"."`
728 * Both `"."` and `"./"` denote the plugin root itself
729 * Before v2.1.221, `"."` failed manifest validation and the plugin didn't load, so use `"./"` to support earlier versions
730* Components from custom paths use the same naming and namespacing rules, except agent files. See [Agents](#agents) for how agent names work
731* Multiple paths can be specified as arrays
732* A skill path can point to a directory that contains a `SKILL.md` directly, for example `"skills": ["."]` for the plugin root
733 * Claude Code takes the skill's invocation name from the frontmatter `name` field in `SKILL.md`, so the name stays stable whatever the install directory is named
734 * If `name` isn't set in the frontmatter, Claude Code falls back to the directory basename
735
736A plugin that has a `SKILL.md` at its root, no `skills/` subdirectory, and no `skills` manifest field is automatically loaded as a single-skill plugin. You do not need to set `"skills": ["./"]` in `plugin.json` for this layout.
737
738**Path examples**:
739
740```json theme={null}
741{
742 "commands": [
743 "./specialized/deploy.md",
744 "./utilities/batch-process.md"
745 ],
746 "agents": [
747 "./custom-agents/reviewer.md",
748 "./custom-agents/tester.md"
749 ]
750}
751```
752
753### Environment variables
754
755Claude Code provides three variables for referencing paths:
756
757| Variable | Resolves to | Use it for |
758| :---------------------- | :---------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------- |
759| `${CLAUDE_PLUGIN_ROOT}` | Absolute path to the plugin's installation directory | Scripts, binaries, and config files bundled with the plugin |
760| `${CLAUDE_PLUGIN_DATA}` | [Persistent directory](#persistent-data-directory) that survives plugin updates, created on first reference | Installed dependencies such as `node_modules` or Python virtual environments, generated code, and caches |
761| `${CLAUDE_PROJECT_DIR}` | The project root | Project-local scripts and config files |
762
763All three are exported as environment variables to hook processes and to MCP and LSP server subprocesses. They aren't present in the environment of commands Claude runs through the Bash tool, in the main session or in a subagent. In plugin content, write the placeholder instead, and Claude Code substitutes the path inline when it loads the content. Which fields substitute them inline depends on the plugin component:
764
765| Plugin component | Fields where placeholders resolve |
766| :------------------------------ | :------------------------------------------ |
767| Skill and agent content | Anywhere the placeholder appears |
768| Hook and monitor commands | Anywhere the placeholder appears |
769| MCP `stdio` servers | `command`, `args`, `env` |
770| MCP `http`, `sse`, `ws` servers | `url`, `headers`, `headersHelper` |
771| LSP servers | `command`, `args`, `env`, `workspaceFolder` |
772
773In hook commands, use [exec form](/docs/en/hooks#exec-form-and-shell-form) with `args` so each path is passed as one argument with no quoting. In shell-form hooks and monitor commands, wrap the variables in double quotes, as in `"${CLAUDE_PROJECT_DIR}/scripts/server.sh"`. This shell-form hook runs a script bundled with a plugin:
774
775```json theme={null}
776{
777 "hooks": {
778 "PostToolUse": [
779 {
780 "hooks": [
781 {
782 "type": "command",
783 "command": "\"${CLAUDE_PLUGIN_ROOT}\"/scripts/process.sh"
784 }
785 ]
786 }
787 ]
788 }
789}
790```
791
792For a copied plugin, `${CLAUDE_PLUGIN_ROOT}` changes when the plugin updates. The previous version's directory remains on disk for a grace period after an update, but treat it as ephemeral and don't write state there. For a plugin loaded in place from a local-directory marketplace, the variable points at the stable source directory. See [plugin caching](#plugin-caching-and-file-resolution) for which plugins are copied and for cleanup semantics.
793
794When a copied plugin updates mid-session, hook commands, monitors, MCP servers, and LSP servers keep using the previous version's path. Run `/reload-plugins` to switch hooks, MCP servers, and LSP servers to the new path; monitors require a session restart. In a session without an interactive terminal, the reload leaves plugin MCP servers on the old path until the next session.
795
796For a plugin with a `command` source, Claude Code [can reload the plugin itself](/docs/en/plugin-marketplaces#when-claude-code-re-runs-the-command).
797
798MCP servers can also call the `roots/list` request to read the session's working directories at runtime. See [what `roots/list` returns and when Claude Code notifies the server of changes](/docs/en/mcp#option-3-add-a-local-stdio-server).
799
800#### Persistent data directory
801
802The `${CLAUDE_PLUGIN_DATA}` directory resolves to `~/.claude/plugins/data/{id}/`, where `{id}` is the plugin identifier with characters outside `a-z`, `A-Z`, `0-9`, `_`, and `-` replaced by `-`. For a plugin installed as `formatter@my-marketplace`, the directory is `~/.claude/plugins/data/formatter-my-marketplace/`.
803
804A common use is installing language dependencies once and reusing them across sessions and plugin updates. Use it for Python dependencies, dependencies locked with Yarn or pnpm, and packages whose lifecycle scripts must run. For a marketplace-installed plugin, you may not need it at all: Claude Code installs eligible [Node.js package dependencies](#node-js-package-dependencies) automatically when it caches the plugin.
805
806Because the data directory outlives any single plugin version, a check for directory existence alone cannot detect when an update changes the plugin's dependency manifest. The recommended pattern compares the bundled manifest against a copy in the data directory and reinstalls when they differ.
807
808This `SessionStart` hook installs `node_modules` on the first run and again whenever a plugin update includes a changed `package.json`:
809
810```json theme={null}
811{
812 "hooks": {
813 "SessionStart": [
814 {
815 "hooks": [
816 {
817 "type": "command",
818 "command": "diff -q \"${CLAUDE_PLUGIN_ROOT}/package.json\" \"${CLAUDE_PLUGIN_DATA}/package.json\" >/dev/null 2>&1 || (cd \"${CLAUDE_PLUGIN_DATA}\" && cp \"${CLAUDE_PLUGIN_ROOT}/package.json\" . && npm install) || rm -f \"${CLAUDE_PLUGIN_DATA}/package.json\""
819 }
820 ]
821 }
822 ]
823 }
824}
825```
826
827The `diff` exits nonzero when the stored copy is missing or differs from the bundled one, covering both first run and dependency-changing updates. If `npm install` fails, the trailing `rm` removes the copied manifest so the next session retries.
828
829Scripts bundled in `${CLAUDE_PLUGIN_ROOT}` can then run against the persisted `node_modules`:
830
831```json theme={null}
832{
833 "mcpServers": {
834 "routines": {
835 "command": "node",
836 "args": ["${CLAUDE_PLUGIN_ROOT}/server.js"],
837 "env": {
838 "NODE_PATH": "${CLAUDE_PLUGIN_DATA}/node_modules"
839 }
840 }
841 }
842}
843```
844
845The data directory is deleted automatically when you uninstall the plugin from the last scope where it is installed. The `/plugin` interface shows the directory size and prompts before deleting. The CLI deletes by default; pass [`--keep-data`](#plugin-uninstall) to preserve it.
846
847***
848
849## Plugin caching and file resolution
850
851Plugins are specified in one of three ways:
852
853* Through `claude --plugin-dir` or `claude --plugin-url`, for the duration of a session.
854* Through a marketplace, installed for future sessions.
855* Through your claude.ai account, [synced](#synced-plugins) into `~/.claude/plugins/synced/`.
856
857For security and verification purposes, Claude Code copies *marketplace* plugins to the user's local **plugin cache** (`~/.claude/plugins/cache`), unless the plugin loads in place. A [`command` source in link mode](/docs/en/plugin-marketplaces#copy-mode-and-link-mode) loads in place through links in the cache entry. A [relative path source](/docs/en/plugin-marketplaces#relative-paths) in a marketplace added from a local directory loads in place from the marketplace folder.
858
859For a plugin loaded in place from a local-directory marketplace, your edits to the source directory take effect at the next session start or `/reload-plugins`. You don't need a version bump. The plugin's hook processes and MCP and LSP servers receive a `CLAUDE_PLUGIN_ROOT` that points at the source directory. Claude Code doesn't install the plugin's [Node.js package dependencies](#node-js-package-dependencies) into the source directory. Install them there yourself, or from a hook into the [persistent data directory](#persistent-data-directory).
860
861For copied plugins, each installed version is a separate directory in the cache, grouped by marketplace and plugin and named for the resolved version, with its own copy of the plugin's files and [Node.js package dependencies](#node-js-package-dependencies). A dependency resolved from a [release tag](/docs/en/plugin-dependencies#tag-plugin-releases-for-version-resolution) gets a directory name with a commit-SHA suffix.
862
863When you update or uninstall a plugin, Claude Code marks the previous version directory as orphaned and removes it in a background sweep roughly 14 days later. The grace period lets concurrent Claude Code sessions that already loaded the old version keep running without errors. Claude Code runs the sweep only while at least one plugin is installed; after you uninstall your last plugin, orphaned directories stay on disk until you install a plugin again.
864
865Claude Code removes a plugin or marketplace folder from the cache only when it no longer contains any directory or symlink. If you symlink a development checkout into the cache as a plugin's version entry, Claude Code never marks the link as orphaned and never removes it or the folders that hold it. Claude Code also never writes its version-tracking files inside the linked checkout.
866
867Claude's Glob and Grep tools skip orphaned version directories during searches, so file results don't include outdated plugin code.
868
869### Node.js package dependencies
870
871When Claude Code copies a plugin into the cache, it also installs the plugin's Node.js package dependencies there, so the plugin's hooks and MCP servers can load them. This section covers the npm and Bun packages a plugin declares in its own `package.json`. For plugins that depend on other plugins, see [plugin dependency versions](/docs/en/plugin-dependencies).
872
873Claude Code runs the install inside the copied version directory each time it creates one: when you install a plugin, when Claude Code updates a plugin to a new version, and at session start when an enabled plugin isn't cached yet, such as on a new machine. The install runs only when the plugin's root directory contains both a `package.json` and a supported lockfile:
874
875| Lockfile | Command |
876| :------------------------------------------- | :----------------------------------------------- |
877| `bun.lock` or `bun.lockb` | `bun install --frozen-lockfile --ignore-scripts` |
878| `npm-shrinkwrap.json` or `package-lock.json` | `npm ci --ignore-scripts` |
879
880If a plugin contains more than one of these lockfiles, Claude Code uses the first match, checking in order: `bun.lock`, `bun.lockb`, `npm-shrinkwrap.json`, `package-lock.json`.
881
882Claude Code skips the install in two cases, each with its own fix:
883
884* If your plugin ships only a `yarn.lock` or `pnpm-lock.yaml`, replace it with an npm lockfile.
885* If a `bunfig.toml` sits beside the bun lockfile, remove the `bunfig.toml`, or replace the bun lockfile with an npm lockfile.
886
887Ship an npm lockfile for the widest reach. Claude Code runs the matched lockfile's package manager from the user's PATH and doesn't fall back to the other lockfile if it's missing. For a plugin distributed through an npm source, use `npm-shrinkwrap.json`; npm excludes `package-lock.json` from published packages.
888
889Claude Code constrains this dependency install so that no code from the plugin or its packages executes during it, and bounds how long it can run:
890
891* **Frozen resolution:** Bun and npm install exactly what the lockfile pins, and fail rather than re-resolve versions when `package.json` and the lockfile disagree.
892* **No lifecycle scripts:** `--ignore-scripts` keeps `preinstall`, `install`, and `postinstall` scripts from running, so dependencies that build native modules in those scripts download but don't compile during this install.
893* **60-second timeout:** Claude Code stops an install that runs longer and treats it as failed.
894
895Claude Code fetches an npm-source plugin before this dependency install, and none of the package's own install scripts run during the fetch. See [npm packages](/docs/en/plugin-marketplaces#npm-packages).
896
897A failed or skipped install never blocks the plugin. When the install fails, or Claude Code skips it because of a yarn or pnpm lockfile or a `bunfig.toml`, it records the reason as a warning in [debug output](#debugging-commands). A plugin with a `package.json` and no lockfile is skipped without a log entry. A timed-out install can leave a partial `node_modules` tree in the cached copy.
898
899You can't turn the automatic install off; no setting or environment variable disables it. In restricted networks, see the [network access requirements](/docs/en/network-config#network-access-requirements) for the hosts to allow.
900
901For dependencies the automatic install can't provide, such as packages that need their lifecycle scripts to build, Python dependencies, or a plugin locked with Yarn or pnpm, install them from a hook into the [persistent data directory](#persistent-data-directory).
902
903### Path traversal limitations
904
905Claude Code doesn't let a plugin reference files outside its own directory. It rejects a component path that resolves outside the plugin root, whether the path is declared in `plugin.json` or in a [marketplace entry](/docs/en/plugin-marketplaces#plugin-entries). That covers a path that points outside the plugin as written, such as `../shared-utils`, and a symlink that leads outside the plugin, other than [links within one marketplace](#share-files-within-a-marketplace-with-symlinks).
906
907On macOS and Linux, Claude Code also rejects a component path that contains a backslash anywhere in it, even when the path stays inside the plugin. Components declared with backslash paths therefore load on Windows only. Write component paths with forward slashes, such as `./commands/deploy.md`.
908
909When Claude Code rejects a path, it reports a [`path escapes plugin directory`](/docs/en/errors#path-escapes-plugin-directory) error and loads the plugin without that component.
910
911Claude Code also doesn't copy files outside the plugin directory into the cache when it installs the plugin, so when a script inside a copied plugin reads a path above the plugin root, it doesn't find those files either.
912
913### Share files within a marketplace with symlinks
914
915If your plugin needs to share files with other parts of the same marketplace, you can create symbolic links inside your plugin directory. How a symlink is handled when the plugin is copied into the cache depends on where its target resolves:
916
917* **Within the plugin's own directory:** the symlink is preserved as a relative symlink in the cache, so it keeps resolving to the copied target at runtime.
918* **Elsewhere within the same marketplace:** the symlink is dereferenced. The target's content is copied into the cache in its place. This lets a meta-plugin's `skills/` directory link to skills defined by other plugins in the marketplace.
919* **Outside the marketplace:** the symlink is skipped for security. This prevents plugins from pulling arbitrary host files such as system paths into the cache.
920
921For plugins installed with `--plugin-dir`, from a local path, or from a [`command` source](/docs/en/plugin-marketplaces#copy-mode-and-link-mode) in copy mode, only symlinks that resolve within the plugin's own directory are preserved. All others are skipped.
922
923The following command creates a link from inside a marketplace plugin to a shared skill defined by a sibling plugin. On Windows, use `mklink /D` from an elevated Command Prompt or enable Developer Mode:
924
925```bash theme={null}
926ln -s ../../shared-plugin/skills/foo ./skills/foo
927```
928
929***
930
931## Plugin directory structure
932
933### Standard plugin layout
934
935A complete plugin follows this structure:
936
937```text theme={null}
938enterprise-plugin/
939├── .claude-plugin/ # Metadata directory (optional)
940│ └── plugin.json # plugin manifest
941├── skills/ # Skills
942│ ├── code-reviewer/
943│ │ └── SKILL.md
944│ └── pdf-processor/
945│ ├── SKILL.md
946│ └── scripts/
947├── commands/ # Skills as flat .md files
948│ ├── status.md
949│ └── logs.md
950├── agents/ # Subagent definitions
951│ ├── security-reviewer.md
952│ ├── performance-tester.md
953│ ├── compliance-checker.md
954│ └── review/ # Agents here load as enterprise-plugin:review:<name>
955│ └── accessibility.md
956├── workflows/ # Workflow scripts
957│ └── release-audit.js
958├── output-styles/ # Output style definitions
959│ └── terse.md
960├── themes/ # Color theme definitions
961│ └── dracula.json
962├── monitors/ # Background monitor configurations
963│ └── monitors.json
964├── hooks/ # Hook configurations
965│ ├── hooks.json # Main hook config
966│ └── security-hooks.json # Additional hooks
967├── bin/ # Plugin executables added to PATH
968│ └── my-tool # Invokable as bare command in Bash tool
969├── settings.json # Default settings for the plugin
970├── .mcp.json # MCP server definitions
971├── .lsp.json # LSP server configurations
972├── scripts/ # Hook and utility scripts
973│ ├── security-scan.sh
974│ ├── format-code.py
975│ └── deploy.js
976├── LICENSE # License file
977└── CHANGELOG.md # Version history
978```
979
980<Warning>
981 The `.claude-plugin/` directory contains the `plugin.json` file. All other directories (commands/, agents/, skills/, workflows/, output-styles/, themes/, monitors/, hooks/) must be at the plugin root, not inside `.claude-plugin/`.
982</Warning>
983
984A `CLAUDE.md` file at the plugin root is not loaded as project context. Plugins contribute context through skills, agents, and hooks rather than CLAUDE.md. To ship instructions that load into Claude's context, put them in a [skill](#skills).
985
986### File locations reference
987
988| Component | Default Location | Purpose |
989| :---------------- | :--------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
990| **Manifest** | `.claude-plugin/plugin.json` | Plugin metadata and configuration (optional) |
991| **Skills** | `skills/` | Skills with `<name>/SKILL.md` structure |
992| **Commands** | `commands/` | Skills as flat Markdown files. Use `skills/` for new plugins |
993| **Agents** | `agents/` | Subagent Markdown files. Subfolders are part of the [agent name](#agents) |
994| **Workflows** | `workflows/` | [Workflow](/docs/en/workflows) script files |
995| **Output styles** | `output-styles/` | Output style definitions |
996| **Themes** | `themes/` | Color theme definitions |
997| **Hooks** | `hooks/hooks.json` | Hook configuration |
998| **MCP servers** | `.mcp.json` | MCP server definitions |
999| **LSP servers** | `.lsp.json` | Language server configurations |
1000| **Monitors** | `monitors/monitors.json` | Background monitor configurations |
1001| **Executables** | `bin/` | Executables added to the Bash tool's `PATH` and invokable as bare commands while the plugin is enabled. You can't include this directory in a plugin you [distribute through claude.ai organization settings](/docs/en/plugin-marketplaces#keep-executables-out-of-the-top-level-bin-directory) |
1002| **Settings** | `settings.json` | Default configuration applied when the plugin is enabled. Only the [`agent`](/docs/en/sub-agents) and [`subagentStatusLine`](/docs/en/statusline#subagent-status-lines) keys are supported |
1003
1004***
1005
1006## CLI commands reference
1007
1008Claude Code provides CLI commands for non-interactive plugin management, useful for scripting and automation.
1009
1010### plugin init
1011
1012Scaffold a new plugin at `~/.claude/skills/<name>/`. On the next Claude Code session it loads automatically as `<name>@skills-dir` and appears in `/plugin` and `claude plugin list` with no install step.
1013
1014See [Skills-directory plugins](#skills-directory-plugins) for scope and trust requirements.
1015
1016```bash theme={null}
1017claude plugin init <name> [options]
1018```
1019
1020The command takes these arguments:
1021
1022* `<name>`: Plugin name. Becomes the skill namespace and the directory name under `~/.claude/skills/`, so it cannot contain spaces or path separators.
1023
1024The command accepts these options:
1025
1026| Option | Description | Default |
1027| :----------------------- | :------------------------------------------------------------------------------------------------------------------ | :---------------------- |
1028| `--description <text>` | Manifest description | |
1029| `--author <name>` | Author name | `git config user.name` |
1030| `--author-email <email>` | Author email | `git config user.email` |
1031| `--with <components...>` | Also scaffold component folders. Valid values: `skills`, `agents`, `hooks`, `mcp`, `lsp`, `output-style`, `channel` | |
1032| `-f, --force` | Overwrite an existing `.claude-plugin/` at the target | |
1033| `-h, --help` | Display help for command | |
1034
1035`claude plugin new` is an alias for this command.
1036
1037Each `--with` value adds a starter file for that component, ready to edit:
1038
1039| Component | What it scaffolds |
1040| :------------- | :-------------------------------------------------------------------------------------------------------- |
1041| `skills` | An extra namespaced `<name>:example` skill alongside the default one |
1042| `agents` | An `agents/` subagent definition |
1043| `hooks` | A `hooks/hooks.json` with a sample event handler |
1044| `mcp` | A `.mcp.json` with HTTP and stdio server examples |
1045| `lsp` | A `.lsp.json` language-server example |
1046| `output-style` | An `output-styles/<name>.md` that applies automatically while the plugin is enabled |
1047| `channel` | An MCP-based [channel](/docs/en/channels): a stdio server (`server.ts`), its `.mcp.json`, and a `package.json` |
1048
1049The scaffolded plugin uses the `@skills-dir` source rather than a marketplace. Admins can block this source with `strictKnownMarketplaces` or by adding `{"source": "skills-dir"}` to `blockedMarketplaces` in [managed settings](/docs/en/plugin-marketplaces#managed-marketplace-restrictions). When blocked, `plugin init` fails before writing.
1050
1051These examples show common invocations:
1052
1053```bash theme={null}
1054# Scaffold a minimal plugin
1055claude plugin init my-helper
1056
1057# Scaffold with skill and hook folders
1058claude plugin init my-helper --with skills hooks
1059
1060# Overwrite an existing scaffold
1061claude plugin init my-helper --force
1062```
1063
1064### plugin install
1065
1066Install a plugin from available marketplaces.
1067
1068```bash theme={null}
1069claude plugin install <plugin> [options]
1070```
1071
1072The command takes these arguments:
1073
1074* `<plugin>`: Plugin name or `plugin-name@marketplace-name` for a specific marketplace
1075
1076The command accepts these options:
1077
1078| Option | Description | Default |
1079| :-------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------ |
1080| `-s, --scope <scope>` | Installation scope: `user`, `project`, or `local` | `user` |
1081| `--config <key=value>` | Set a [`userConfig`](#user-configuration) option declared in the plugin's manifest. Repeat the flag to set multiple options | |
1082| `-y, --yes` | Accept a command the plugin's marketplace declares, without the confirmation prompt: the command that produces a plugin with a [`command` source](/docs/en/plugin-marketplaces#command-sources), or the [`headersHelper`](/docs/en/plugin-marketplaces#authenticate-archive-downloads) that authenticates an archive download. Accepting a `headersHelper` requires Claude Code v2.1.238 or later. Claude Code still prints the command first. Required when stdin or stdout isn't a TTY, unless you pass `--accept-command`. Has no effect inside a Claude Code session, so run the command from your own terminal | |
1083| `--accept-command <sha256>` | Accept the marketplace-declared command whose `sha256` a previous [`--json` run](#plugin-json-result) reported in `shownCommand`, in place of `-y`. The acceptance counts for exactly that command, plugin, and marketplace catalog. If any of them changed since the command was displayed, including through the run's own marketplace refresh, Claude Code doesn't accept the digest and shows the command again. Can't be combined with `-y`. Has no effect inside a Claude Code session, so run the command from your own terminal. Requires Claude Code v2.1.271 or later | |
1084| `--json` | Print the result as one JSON object on the last line of stdout instead of the human-readable message, for use in scripts. See [JSON result format](#plugin-json-result). Requires Claude Code v2.1.268 or later | |
1085| `-h, --help` | Display help for command | |
1086
1087Scope determines which settings file the installed plugin is added to. For example, `--scope project` writes to `enabledPlugins` in .claude/settings.json, making the plugin available to everyone who clones the project repository.
1088
1089<span id="plugin-json-result" />With `--json`, the last line of stdout is one JSON object. Parse only that line, because Claude Code prints any command the marketplace declares ahead of it. Three fields are always present:
1090
1091* `command`: the subcommand that ran, such as `install`
1092* `outcome`: `ok` or `failed`
1093* `message`: a human-readable description of the result
1094
1095Other fields, such as `pluginId`, `scope`, and `failureCode`, appear only when they apply. The `--json` option on `plugin uninstall`, `plugin update`, `plugin enable`, and `plugin disable` prints the same object with that subcommand's own fields. A usage error, such as an invalid `--scope`, prints no result line and exits 1 with the reason on stderr.
1096
1097When a run displays a marketplace-declared command and doesn't run it, the `failed` result also carries a `shownCommand` object whose fields include the command as displayed, the plugin it belongs to, and the command's `sha256`. To accept exactly that command, re-run with that `sha256` as `--accept-command`. Requires Claude Code v2.1.271 or later.
1098
1099If `shownCommand.acceptCommandMatched` is `false`, the digest you passed doesn't match the command now displayed. Show that command to a person before passing its `sha256`.
1100
1101These examples show common invocations:
1102
1103```bash theme={null}
1104# Install to user scope (default)
1105claude plugin install formatter@my-marketplace
1106
1107# Install to project scope (shared with team)
1108claude plugin install formatter@my-marketplace --scope project
1109
1110# Install to local scope (not shared with team)
1111claude plugin install formatter@my-marketplace --scope local
1112```
1113
1114### plugin uninstall
1115
1116Remove an installed plugin.
1117
1118```bash theme={null}
1119claude plugin uninstall <plugin> [options]
1120```
1121
1122The command takes these arguments:
1123
1124* `<plugin>`: Plugin name or `plugin-name@marketplace-name`
1125
1126The command accepts these options:
1127
1128| Option | Description | Default |
1129| :-------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------ |
1130| `-s, --scope <scope>` | Uninstall from scope: `user`, `project`, or `local` | `user` |
1131| `--keep-data` | Preserve the plugin's [persistent data directory](#persistent-data-directory) | |
1132| `--prune` | Also remove auto-installed dependencies that no other plugin requires. See [plugin prune](#plugin-prune) | |
1133| `-y, --yes` | Skip the `--prune` confirmation prompt. Required when stdin or stdout is not a TTY | |
1134| `--json` | Print the result as one JSON object on the last line of stdout, in the [same format as `plugin install --json`](#plugin-json-result). Can't be combined with `--prune`. Requires Claude Code v2.1.268 or later | |
1135| `-h, --help` | Display help for command | |
1136
1137`claude plugin remove` and `claude plugin rm` are aliases for this command.
1138
1139By default, uninstalling from the last remaining scope also deletes the plugin's `${CLAUDE_PLUGIN_DATA}` directory. Use `--keep-data` to preserve it, for example when reinstalling after testing a new version.
1140
1141<Note>
1142 When installed plugins from different marketplaces share a name, the `plugin-name@marketplace-name` form uninstalls only the plugin from the named marketplace. Before v2.1.212, the qualified form could match and uninstall the same-named plugin from a different marketplace.
1143</Note>
1144
1145### plugin prune
1146
1147Remove auto-installed plugin dependencies that are no longer required by any installed plugin. Dependencies that Claude Code pulled in to satisfy another plugin's [`dependencies`](/docs/en/plugin-dependencies) field are removed; plugins you installed directly are never touched.
1148
1149```bash theme={null}
1150claude plugin prune [options]
1151```
1152
1153The command accepts these options:
1154
1155| Option | Description | Default |
1156| :-------------------- | :----------------------------------------------------------------------- | :------ |
1157| `-s, --scope <scope>` | Prune at scope: `user`, `project`, or `local` | `user` |
1158| `--dry-run` | List what would be removed without removing anything | |
1159| `-y, --yes` | Skip the confirmation prompt. Required when stdin or stdout is not a TTY | |
1160| `-h, --help` | Display help for command | |
1161
1162`claude plugin autoremove` is an alias for this command.
1163
1164The command lists orphaned dependencies and asks for confirmation before removing them. To remove a plugin and clean up its dependencies in one step, run `claude plugin uninstall <plugin> --prune`.
1165
1166### plugin enable
1167
1168Enable a disabled plugin. When the target is installed from a marketplace and declares [dependencies](/docs/en/plugin-dependencies), Claude Code enables them transitively at the same scope. The command fails under the conditions that [Enable or disable a plugin with dependencies](/docs/en/plugin-dependencies#enable-or-disable-a-plugin-with-dependencies) lists.
1169
1170```bash theme={null}
1171claude plugin enable <plugin> [options]
1172```
1173
1174The command takes these arguments:
1175
1176* `<plugin>`: Plugin name, `plugin-name@marketplace-name`, or `plugin-name@synced` for a [plugin synced from claude.ai](#synced-plugins)
1177
1178The command accepts these options:
1179
1180| Option | Description | Default |
1181| :-------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :---------- |
1182| `-s, --scope <scope>` | Scope to enable: `user`, `project`, or `local`. When omitted, Claude Code detects the scope where the plugin is installed | Auto-detect |
1183| `--json` | Print the result as one JSON object on the last line of stdout, in the [same format as `plugin install --json`](#plugin-json-result). Requires Claude Code v2.1.268 or later | |
1184| `-h, --help` | Display help for command | |
1185
1186### plugin disable
1187
1188Disable a plugin without uninstalling it.
1189
1190When the target is installed from a marketplace, the command fails if another enabled plugin [depends on](/docs/en/plugin-dependencies#enable-or-disable-a-plugin-with-dependencies) it. The error message includes a chained command that disables every dependent first.
1191
1192For a [synced plugin](#synced-plugins) that your organization requires, the command fails and saves nothing.
1193
1194```bash theme={null}
1195claude plugin disable [plugin] [options]
1196```
1197
1198The command takes these arguments:
1199
1200* `[plugin]`: Plugin name, `plugin-name@marketplace-name`, or `plugin-name@synced` for a [plugin synced from claude.ai](#synced-plugins). Optional when using `--all`
1201
1202The command accepts these options:
1203
1204| Option | Description | Default |
1205| :-------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :---------- |
1206| `-a, --all` | Disable all enabled plugins. Can't be combined with `--scope` | |
1207| `-s, --scope <scope>` | Scope to disable: `user`, `project`, or `local`. When omitted, Claude Code detects the scope where the plugin is installed | Auto-detect |
1208| `--json` | Print the result as one JSON object on the last line of stdout, in the [same format as `plugin install --json`](#plugin-json-result). Requires Claude Code v2.1.268 or later | |
1209| `-h, --help` | Display help for command | |
1210
1211### plugin update
1212
1213Update a plugin to the latest version.
1214
1215```bash theme={null}
1216claude plugin update <plugin> [options]
1217```
1218
1219The command takes these arguments:
1220
1221* `<plugin>`: Plugin name or `plugin-name@marketplace-name`
1222
1223The command accepts these options:
1224
1225| Option | Description | Default |
1226| :-------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------ |
1227| `-s, --scope <scope>` | Scope to update: `user`, `project`, `local`, or `managed` | `user` |
1228| `-y, --yes` | Accept a command the plugin's marketplace declares, without the confirmation prompt: the command that produces a plugin with a [`command` source](/docs/en/plugin-marketplaces#command-sources), or the [`headersHelper`](/docs/en/plugin-marketplaces#authenticate-archive-downloads) that authenticates an archive download. Accepting a `headersHelper` requires Claude Code v2.1.238 or later. Claude Code still prints the command first. Required when stdin or stdout isn't a TTY, unless you pass `--accept-command`. Has no effect inside a Claude Code session, so run the command from your own terminal | |
1229| `--accept-command <sha256>` | Accept the marketplace-declared command whose `sha256` a previous [`--json` run](#plugin-json-result) reported in `shownCommand`, in place of `-y`. The acceptance counts for exactly that command, plugin, and marketplace catalog. If any of them changed since the command was displayed, including through the run's own marketplace refresh, Claude Code doesn't accept the digest and shows the command again. Can't be combined with `-y`. Has no effect inside a Claude Code session, so run the command from your own terminal. Requires Claude Code v2.1.271 or later | |
1230| `--json` | Print the result as one JSON object on the last line of stdout, in the [same format as `plugin install --json`](#plugin-json-result). Requires Claude Code v2.1.268 or later | |
1231| `-h, --help` | Display help for command | |
1232
1233<Note>
1234 Claude Code resolves a bare plugin name against your installed plugins. When installed plugins from different marketplaces share the name, Claude Code refuses the update and lists the qualified `plugin-name@marketplace-name` commands to run instead. Before v2.1.246, Claude Code accepted only the qualified form and rejected a bare name as not found.
1235</Note>
1236
1237***
1238
1239### plugin list
1240
1241List installed plugins with their version, source marketplace, and enable status.
1242
1243```bash theme={null}
1244claude plugin list [options]
1245```
1246
1247The command accepts these options:
1248
1249| Option | Description | Default |
1250| :------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------ |
1251| `--json` | Output as JSON. A plugin row with load problems or authoring warnings carries `errors` or `notes` string arrays. On Claude Code v2.1.268 or later, parallel `errorDetails` and `noteDetails` arrays give each entry's diagnostic `type` and the names it refers to, such as the plugin, marketplace, server, or file | |
1252| `--available` | Include available plugins from marketplaces. Requires `--json` | |
1253| `-h, --help` | Display help for command | |
1254
1255Within an interactive session, `/plugin list` prints a similar listing inline, but it covers marketplace-installed plugins only:
1256
1257* Plugins loaded from skills directories appear in the `/plugin` interface and in `claude plugin list`, but not in the inline `/plugin list` output.
1258* [Plugins synced from claude.ai](#synced-plugins) appear in `claude plugin list` on Claude Code v2.1.239 or later and in the `/plugin` interface, but not in the inline `/plugin list` output.
1259* Plugins loaded for the session with `--plugin-dir` or `--plugin-url` appear in the `/plugin` interface, and in `claude plugin list` only when the same flag precedes the subcommand, as in `claude --plugin-dir <dir> plugin list`. Only the flag names their location, so a bare `claude plugin list` can't find them, unlike synced plugins and skills-directory plugins, whose fixed directories Claude Code scans.
1260
1261The interactive form accepts `--enabled` or `--disabled` to show only plugins in that state, and `ls` as a shorthand for `list`.
1262
1263### plugin details
1264
1265Show a plugin's component inventory and projected token cost. The output lists all components the plugin contributes, grouped as Skills, Agents, Hooks, MCP servers, and LSP servers, along with an estimate of how many tokens it adds to each session. The Skills group includes both `skills/` and `commands/` entries.
1266
1267```bash theme={null}
1268claude plugin details <name>
1269```
1270
1271The command takes these arguments:
1272
1273* `<name>`: Plugin name or `plugin-name@marketplace-name`
1274
1275The command accepts these options:
1276
1277| Option | Description | Default |
1278| :----------- | :----------------------- | :------ |
1279| `-h, --help` | Display help for command | |
1280
1281The output shows two cost figures for each component:
1282
1283* **Always-on:** tokens added to every session by the plugin's listing text, such as skill descriptions, agent descriptions, and command names, regardless of whether any component fires.
1284* **On-invoke:** tokens a component costs when it fires. Shown per component, not as a plugin total, because a typical session invokes only a subset of components.
1285
1286This example shows what the output looks like for a plugin with two skills:
1287
1288```
1289dependency-guard 1.2.0
1290 Dependency analysis for Claude Code sessions
1291 Source: dependency-guard@example-marketplace
1292
1293Component inventory
1294 Skills (2) scan-dependencies, review-changes
1295 Agents (0)
1296 Hooks (1) SessionStart (harness-only — no model context cost)
1297 MCP servers (0)
1298 LSP servers (0)
1299
1300Projected token cost
1301 Always-on: ~180 tok added to every session
1302
1303Per-component (rounded)
1304 component always-on on-invoke
1305 scan-dependencies ~100 ~2400
1306 review-changes ~80 ~1800
1307
1308 On-invoke cost is paid each time a skill or agent fires.
1309 Token counts are estimates and may differ from actual usage.
1310```
1311
1312The always-on total is computed via the `count_tokens` API for your active model. Per-component numbers are proportionally scaled from that total. If the API is unreachable, the command falls back to a character-based estimate.
1313
1314### plugin validate
1315
1316Check a plugin or a marketplace for syntax and schema errors before publishing.
1317
1318The command exits 0 when validation passes, 1 when it fails, and 2 when the validation run itself fails, such as when the path you pass is unreadable.
1319
1320```bash theme={null}
1321claude plugin validate <path> [options]
1322```
1323
1324The command takes these arguments:
1325
1326* `<path>`: Path to a plugin directory or a marketplace directory. See [Validate a plugin or a directory without a manifest](/docs/en/plugin-marketplaces#validate-a-plugin-or-a-directory-without-a-manifest) for which files a plugin run covers.
1327
1328The command accepts these options:
1329
1330| Option | Description | Default |
1331| :----------- | :------------------------------------------------------------------------------------------------------------------------------------------------ | :------ |
1332| `--strict` | Treat warnings as errors and exit 1 on them. Use in CI to catch issues the runtime tolerates, such as [unrecognized fields](#unrecognized-fields) | |
1333| `--json` | Output the validation report as one JSON object with the same exit codes. Requires Claude Code v2.1.259 or later | |
1334| `-h, --help` | Display help for command | |
1335
1336With `--json`, Claude Code writes the report to stdout as one JSON object with these top-level fields:
1337
1338* `success`: the same verdict the exit code gives
1339* `strict`: whether the run treated warnings as errors
1340* `target`: the resolved path Claude Code validated
1341* `manifest`: the manifest's own result, or `null` for a [run without a manifest](/docs/en/plugin-marketplaces#validate-a-plugin-or-a-directory-without-a-manifest)
1342* `contents`: per-file results, each naming its `file` and carrying `errors`, `warnings`, and `notes` arrays
1343
1344On exit 2, the command writes nothing to stdout; the error message goes to stderr.
1345
1346Within an interactive session, `/plugin validate <path>` runs the same checks inline.
1347
1348### plugin eval
1349
1350Run a plugin's [eval cases](/docs/en/plugin-evals) and report scored results. Requires Claude Code v2.1.269 or later. Each case is a prompt plus graders; Claude Code runs it several times in an isolated session with only the target plugin loaded, and by default also without the plugin so the report shows the difference. See [Test plugins with evals](/docs/en/plugin-evals) for the case format, graders, results, and CI usage.
1351
1352```bash theme={null}
1353claude plugin eval [target] [options]
1354```
1355
1356The optional `target` is a plugin directory, a single `prompt.md` or `case.yaml` file, an installed plugin as `name` or `name@marketplace`, or `name@skills-dir`, and defaults to the current directory. Put it before `--tag`, `--allow-tools`, and `--json`.
1357
1358This table lists the options most runs use. Run `claude plugin eval --help` for the complete set, including `--case`, `--tag`, `--output-dir`, `--report`, `--allow-real-servers`, `--keep-temp`, and `--verbose`.
1359
1360| Option | Description | Default |
1361| :------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------------- |
1362| `--runs <n>` | Runs per case per arm | Each case's `runs`, else 3 |
1363| `-j, --concurrency <n>` | Agent sessions to run at once, 1 to 8. They share your rate limit | `1` |
1364| `--model <model>` | Model for the agent under test | Each case's `model`, else `ANTHROPIC_MODEL` if set, else Claude Code's default |
1365| `--judge-model <model>` | Model for `llm` and `baseline` graders | A small fast model |
1366| `--ablation <mode>` | `none` or `with-without`. See [Compare against a no-plugin baseline](/docs/en/plugin-evals#compare-against-a-no-plugin-baseline) | `with-without` when a plugin resolves, else `none` |
1367| `--threshold <0..1>` | Exit 1 if any case scores below this | `1.0` |
1368| `--max-cost-usd <usd>` | Stop before the next run once spend reaches this, exit 2, and report partial results | No ceiling |
1369| `--allow-tools <tools...>` | Grant tools beyond the read-only set, such as `Bash`, `Write`, `Edit`, or `"mcp__plugin_<plugin>_<server>__*"`. See [Grant tools](/docs/en/plugin-evals#grant-tools) | |
1370| `--scaffold` | Run each case's [`scaffold_script`](/docs/en/plugin-evals#add-setup-or-history-with-case-yaml) | Off |
1371| `--trust-plugin` | Skip the first-run trust prompt, for CI. See [What a run can access](/docs/en/plugin-evals#security) | Off |
1372| `--mocks <mode>` | `record` or `off`. See [Mock MCP servers](/docs/en/plugin-evals#mock-mcp-servers) | `record` |
1373| `--eval-dir <dir>` | Directory below the plugin that holds the cases | The manifest's `experimental.evals`, else `evals` |
1374| `--json [path]` | Print the [result document](/docs/en/plugin-evals#json-result) to stdout, or write it to a `.json` path | |
1375| `--no-publish` | Keep the HTML report local | |
1376| `-h, --help` | Display help for command | |
1377
1378The command exits 0 when every case meets the threshold, 1 on a failing case, a load error, or an untrusted plugin directory, 2 on a partial run, 130 when interrupted, and 143 when terminated. See [Run evals in CI](/docs/en/plugin-evals#run-evals-in-ci).
1379
1380### plugin eval init
1381
1382Create an eval suite for the plugin in the current directory. Requires Claude Code v2.1.269 or later. In a terminal this starts an authoring interview that reads the plugin, proposes cases and graders, pilots them, and writes the files. With `--bare`, or without a terminal, it writes a blank single-case template instead. Run from inside an interactive Claude Code session, it prints the interview instructions for that session to follow rather than writing a template. See [Create your first eval suite](/docs/en/plugin-evals#create-your-first-eval-suite).
1383
1384```bash theme={null}
1385claude plugin eval init [name] [options]
1386```
1387
1388The optional `name` is a case name: the interview doesn't need one, while `--bare` and the no-terminal template path require it. It accepts these options:
1389
1390| Option | Description | Default |
1391| :------------------ | :------------------------------------------------------------------------------------------------ | :------------------------------------------------ |
1392| `--bare` | Write a blank `prompt.md` and `graders/criteria.md` for `<name>` instead of running the interview | |
1393| `-i, --interactive` | Require the interview. Fails without a terminal instead of writing a template | |
1394| `--eval-dir <dir>` | Directory below the current directory to write cases into | The manifest's `experimental.evals`, else `evals` |
1395| `-h, --help` | Display help for command | |
1396
1397### plugin tag
1398
1399Create a release git tag for a plugin. By default the command tags the plugin in the current directory; pass a path to tag a plugin elsewhere. See [Tag plugin releases](/docs/en/plugin-dependencies#tag-plugin-releases-for-version-resolution).
1400
1401```bash theme={null}
1402claude plugin tag [path] [options]
1403```
1404
1405The command takes these arguments:
1406
1407* `[path]`: Path to the plugin directory. Defaults to the current directory.
1408
1409The command accepts these options:
1410
1411| Option | Description | Default |
1412| :-------------------- | :------------------------------------------------------------------------- | :------- |
1413| `--push` | Push the tag to the remote after creating it | |
1414| `--dry-run` | Print what would be tagged without creating the tag | |
1415| `-f, --force` | Create the tag even if the working tree is dirty or the tag already exists | |
1416| `-m, --message <msg>` | Tag annotation message. Use `%s` as a placeholder for the version | |
1417| `--remote <name>` | Remote to push to with `--push` | `origin` |
1418| `-h, --help` | Display help for command | |
1419
1420***
1421
1422## Debugging and development tools
1423
1424### Debugging commands
1425
1426Use `claude --debug` to see plugin loading details:
1427
1428This shows:
1429
1430* Which plugins are being loaded
1431* Any errors in plugin manifests
1432* Skill, agent, and hook registration
1433* MCP server initialization
1434
1435### Common issues
1436
1437| Issue | Cause | Solution |
1438| :---------------------------------- | :------------------------------ | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1439| Plugin not loading | Invalid `plugin.json` | Run `claude plugin validate ./my-plugin` or `/plugin validate ./my-plugin`, where `./my-plugin` is your plugin directory, to check `plugin.json`, `hooks/hooks.json`, and the frontmatter of the skills, agents, and commands in the plugin's default directories for syntax and schema errors. See [Validate a plugin or a directory without a manifest](/docs/en/plugin-marketplaces#validate-a-plugin-or-a-directory-without-a-manifest) for what a run covers |
1440| Skills not appearing | Wrong directory structure | Ensure `skills/` or `commands/` is at the plugin root, not inside `.claude-plugin/` |
1441| Hooks not firing | Script not executable | Run `chmod +x script.sh` |
1442| MCP server fails | Missing `${CLAUDE_PLUGIN_ROOT}` | Use variable for all plugin paths |
1443| Path errors | Absolute paths used | Make paths relative, starting with `./`; see [Path behavior rules](#path-behavior-rules), which cover the `skills` field's `"."` exception |
1444| LSP `Executable not found in $PATH` | Language server not installed | Install the binary (for example, `npm install -g typescript-language-server typescript`) |
1445
1446### Example error messages
1447
1448**Manifest validation errors**:
1449
1450* `Invalid JSON syntax: Unexpected token } in JSON at position 142`: check for missing commas, extra commas, or unquoted strings
1451* `Plugin <name> has an invalid manifest file at .claude-plugin/plugin.json. Validation errors: name: Invalid input: expected string, received undefined`: a required field is missing
1452* `Plugin <name> has a corrupt manifest file at .claude-plugin/plugin.json. JSON parse error: ...`: JSON syntax error. Before v2.1.246, Claude Code also produced this error for a `plugin.json` saved as UTF-8 with a leading byte-order mark (BOM), even when the JSON was otherwise valid.
1453
1454**Plugin loading errors**:
1455
1456* `Warning: No commands found in plugin my-plugin custom directory: ./cmds. Expected .md files or SKILL.md in subdirectories.`: command path exists but contains no valid command files
1457* `Plugin directory not found at path: ./plugins/my-plugin. Check that the marketplace entry has the correct path.`: the `source` path in marketplace.json points to a non-existent directory
1458* `Plugin my-plugin has conflicting manifests: both plugin.json and marketplace entry specify components.`: remove duplicate component definitions or remove `strict: false` in marketplace entry
1459
1460### Hook troubleshooting
1461
1462**Hook script not executing**:
1463
14641. Check the script is executable: `chmod +x ./scripts/your-script.sh`
14652. Verify the shebang line: First line should be `#!/bin/bash` or `#!/usr/bin/env bash`
14663. Check the path uses `${CLAUDE_PLUGIN_ROOT}`: `"command": "\"${CLAUDE_PLUGIN_ROOT}\"/scripts/your-script.sh"`
14674. Test the script manually: `./scripts/your-script.sh`
1468
1469**Hook not triggering on expected events**:
1470
14711. Verify the event name is correct (case-sensitive): `PostToolUse`, not `postToolUse`
14722. Check the matcher pattern matches your tools: `"matcher": "Write|Edit"` for file operations
14733. Confirm the hook type is valid: `command`, `http`, `mcp_tool`, `prompt`, or `agent`
1474
1475### MCP server troubleshooting
1476
1477**Server not starting**:
1478
14791. Check the command exists and is executable
14802. Verify all paths use `${CLAUDE_PLUGIN_ROOT}` variable
14813. Check the MCP server logs: `claude --debug` shows initialization errors
14824. Test the server manually outside of Claude Code
1483
1484**Server tools not appearing**:
1485
14861. Ensure the server is properly configured in `.mcp.json` or `plugin.json`
14872. Verify the server implements the MCP protocol correctly
14883. Check for connection timeouts in debug output
1489
1490### Directory structure mistakes
1491
1492**Symptoms**: Plugin loads but components (skills, agents, hooks) are missing.
1493
1494**Correct structure**: Components must be at the plugin root, not inside `.claude-plugin/`. Only `plugin.json` belongs in `.claude-plugin/`.
1495
1496**Debug checklist**:
1497
14981. Run `claude --debug` and look for "loading plugin" messages
14992. Check that each component directory is listed in the debug output
15003. Verify file permissions allow reading the plugin files
1501
1502***
1503
1504## Distribution and versioning reference
1505
1506### Version management
1507
1508Claude Code uses the plugin's version as the cache key that determines whether an update is available. When you run `/plugin update` or auto-update fires, Claude Code computes the current version and skips the update if it matches what's already installed. A plugin [loaded in place](#plugin-caching-and-file-resolution) from a local-directory marketplace loads its current source files at every session start, whatever its version string says.
1509
1510For every source type except `command`, Claude Code resolves the version from the first of these that is set:
1511
15121. The `version` field in the plugin's `plugin.json`
15132. The `version` field in the plugin's marketplace entry in `marketplace.json`
15143. The git commit SHA of the plugin's source, for `github`, `url`, `git-subdir`, and relative-path sources in a git-hosted marketplace
15154. The SHA-256 digest, for [`archive` sources](/docs/en/plugin-marketplaces#zip-archives): the `sha256` pin in the marketplace entry, or the digest of the downloaded file when you set no pin. Claude Code shortens it to the first 12 characters
15165. `unknown`, for `npm` sources, or for local directories when neither the plugin directory nor its marketplace is a git repository. Claude Code doesn't take the version from a repository that encloses the install path, such as a git-managed `~/.claude`
1517
1518For a [`command` source](/docs/en/plugin-marketplaces#command-sources), Claude Code always derives the version from what the command produced: a 12-character content hash on its own, or appended to the `plugin.json` version as `<version>-<hash>` when one is set. Claude Code ignores the marketplace entry's `version` field for command sources. A command whose hashed output changes therefore produces a new version, even when the authored version string stays the same. In [link mode](/docs/en/plugin-marketplaces#copy-mode-and-link-mode), the hash covers the printed directory's real path and its top-level entries rather than the file contents.
1519
1520For those source types, this gives you three ways to version a plugin:
1521
1522| Approach | How | Update behavior | Best for |
1523| :--------------------- | :----------------------------------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------- |
1524| **Explicit version** | Set `"version": "2.1.0"` in `plugin.json` | Users get updates only when you bump this field. Pushing new commits without bumping it has no effect, and `/plugin update` reports "already at the latest version". For a plugin [loaded in place](#plugin-caching-and-file-resolution), the new content loads anyway. | Published plugins with stable release cycles |
1525| **Commit-SHA version** | Omit `version` from both `plugin.json` and the marketplace entry | Users get updates whenever the source's resolved commit changes | Internal or team plugins under active development |
1526| **Digest version** | Use an [`archive` source](/docs/en/plugin-marketplaces#zip-archives) and omit `version` from both `plugin.json` and the marketplace entry | With a `sha256` pin, users get updates when you change the pin. Without one, users get updates whenever the hosted zip file's bytes change | Plugins published as zip files to a static server or artifact repository |
1527
1528If you use explicit versions, follow [semantic versioning](https://semver.org) (`MAJOR.MINOR.PATCH`): bump MAJOR for breaking changes, MINOR for new features, PATCH for bug fixes. Document changes in a `CHANGELOG.md`.
1529
1530***
1531
1532## See also
1533
1534* [Plugins](/docs/en/plugins) - Tutorials and practical usage
1535* [Plugin marketplaces](/docs/en/plugin-marketplaces) - Creating and managing marketplaces
1536* [Skills](/docs/en/skills) - Skill development details
1537* [Subagents](/docs/en/sub-agents) - Agent configuration and capabilities
1538* [Hooks](/docs/en/hooks) - Event handling and automation
1539* [MCP](/docs/en/mcp) - External tool integration
1540* [Settings](/docs/en/settings) - Configuration options for plugins