Follow Discord
Sweep 22 Oct 2026 · 21:04Z Build v2.1.309 528 read Stable v2.1.308 Latest v2.1.309 Next v2.1.309 Feeds RSS JSON llms.txt llms-full.txt Unofficial
One capture · claude-code

One read of Claude Code CLIclaude-code-20261022T180701Z

220 pages moved out of 228 read.

Pages moved 220 significant first
Pages read 228 in this capture
Captured 18:07 UTC
Corpus hash 237d0503e095 corpus-hash

What this read moved

126-150 of 220, page 6 of 9

This capture is too large to show at once. Changes 126-150 of 220 are below, significant first; the rest are on the following screens.

plugins/anthropic-marketplaces Changed · +15 / -15 lines

from line 10
1010>
1111> These cases are covered on other pages:
1212>
13> * **How to install a plugin**: see [Install plugins](/docs/en/plugins/install)
14> * **A failed install**: see [Troubleshoot plugins](/docs/en/plugins/troubleshooting)
13> * **How to install a plugin**: see [Install plugins](/docs/en/plugins/install.md)
14> * **A failed install**: see [Troubleshoot plugins](/docs/en/plugins/troubleshooting.md)
1515 
1616Go to the part of the page you need:
1717 
from line 29
2929| Repository | [`anthropics/claude-plugins-official`](https://github.com/anthropics/claude-plugins-official) | [`anthropics/claude-plugins-community`](https://github.com/anthropics/claude-plugins-community) | [`anthropics/claude-code`](https://github.com/anthropics/claude-code/tree/main/plugins) |
3030| Marketplace name | `claude-plugins-official` | `claude-community` | `claude-code-plugins` |
3131| What's in it | Plugins Anthropic maintains, plus plugins from partners and other authors | Third-party plugins that their authors submitted to Anthropic | A small set of example plugins that show what a plugin can contain |
32| How you get it | Claude Code adds it the first time you start an interactive terminal session, unless a [managed policy](/docs/en/plugins/org#allow-the-official-marketplace-and-your-own) or `CLAUDE_CODE_DISABLE_OFFICIAL_MARKETPLACE_AUTOINSTALL` blocks it. See [Marketplace `claude-plugins-official` not found](/docs/en/plugins/troubleshooting#marketplace-claude-plugins-official-not-found) if it's missing | You add it in a Claude Code session with `/plugin marketplace add anthropics/claude-plugins-community` | You add it in a Claude Code session with `/plugin marketplace add anthropics/claude-code` |
32| How you get it | Claude Code adds it the first time you start an interactive terminal session, unless a [managed policy](/docs/en/plugins/org.md#allow-the-official-marketplace-and-your-own) or `CLAUDE_CODE_DISABLE_OFFICIAL_MARKETPLACE_AUTOINSTALL` blocks it. See [Marketplace `claude-plugins-official` not found](/docs/en/plugins/troubleshooting#marketplace-claude-plugins-official-not-found) if it's missing | You add it in a Claude Code session with `/plugin marketplace add anthropics/claude-plugins-community` | You add it in a Claude Code session with `/plugin marketplace add anthropics/claude-code` |
3333 
34If you wrote a plugin and want other people to install it, see [Publish a plugin](/docs/en/plugins/publish), which covers your own marketplace and submitting to Anthropic's directory.
34If you wrote a plugin and want other people to install it, see [Publish a plugin](/docs/en/plugins/publish.md), which covers your own marketplace and submitting to Anthropic's directory.
3535 
3636### The demo marketplace in `anthropics/claude-code`
3737 
from line 41
4141 
4242## Find plugins in the official marketplace
4343 
44By default, Claude Code adds the official marketplace, `claude-plugins-official`, for you. Most of what it lists comes from partners and other authors rather than from Anthropic: tool vendors publish plugins that connect Claude Code to their services, and Anthropic maintains a smaller set of its own, such as `commit-commands`, `code-review`, `feature-dev`, and the [language server plugins](/docs/en/plugins/code-intelligence). The catalog changes often, so this page doesn't list it.
44By default, Claude Code adds the official marketplace, `claude-plugins-official`, for you. Most of what it lists comes from partners and other authors rather than from Anthropic: tool vendors publish plugins that connect Claude Code to their services, and Anthropic maintains a smaller set of its own, such as `commit-commands`, `code-review`, `feature-dev`, and the [language server plugins](/docs/en/plugins/code-intelligence.md). The catalog changes often, so this page doesn't list it.
4545 
4646To see what's in it, use the **Discover** tab of `/plugin` in a Claude Code session, which you can search, or browse [Claude Marketplace](https://claude.com/marketplace/plugins) on the web.
4747 
from line 50
5050You can search Anthropic's marketplaces for a plugin in Claude Code, on the web, or on GitHub:
5151 
5252* **In Claude Code, by browsing**: run `/plugin` in an interactive session. Its **Discover** tab lists the plugins from your marketplaces.
53* **In Claude Code, by name**: run `/plugin install <name>` in a session, which looks the name up in your marketplaces. If the plugin is in one of them, its details open in the `/plugin` panel, and nothing installs until you choose an [installation scope](/docs/en/plugins/install#install-a-plugin) and confirm there. If it isn't, you see `Plugin "<name>" not found in any marketplace`.
53* **In Claude Code, by name**: run `/plugin install <name>` in a session, which looks the name up in your marketplaces. If the plugin is in one of them, its details open in the `/plugin` panel, and nothing installs until you choose an [installation scope](/docs/en/plugins/install.md#install-a-plugin) and confirm there. If it isn't, you see `Plugin "<name>" not found in any marketplace`.
5454* **On the web**: search the full catalog on [Claude Marketplace](https://claude.com/marketplace/plugins), which shows install counts and marks some plugins **Anthropic verified**.
5555* **On GitHub**: open `.claude-plugin/marketplace.json` in the marketplace's repository, such as [`anthropics/claude-plugins-official`](https://github.com/anthropics/claude-plugins-official). That file is the catalog itself.
5656 
57Anthropic's directory is separate from these marketplaces. The directory is the catalog on claude.ai. A plugin you add from the directory on claude.ai reaches Claude Code through [account sync](/docs/en/plugins/loading#synced-plugins). To list your own plugin there, see [Submit to Anthropic's directory](/docs/en/plugins/publish#submit-to-anthropics-directory).
57Anthropic's directory is separate from these marketplaces. The directory is the catalog on claude.ai. A plugin you add from the directory on claude.ai reaches Claude Code through [account sync](/docs/en/plugins/loading.md#synced-plugins). To list your own plugin there, see [Submit to Anthropic's directory](/docs/en/plugins/publish.md#submit-to-anthropics-directory).
5858 
59To install from the desktop app or from a script, or to see what a cloud session loads, see [Install plugins](/docs/en/plugins/install).
59To install from the desktop app or from a script, or to see what a cloud session loads, see [Install plugins](/docs/en/plugins/install.md).
6060 
6161### Add the community or demo marketplace
6262 
from line 67
6767 
6868If `claude-plugins-official` isn't on the **Marketplaces** tab of `/plugin`, add it the same way with `/plugin marketplace add anthropics/claude-plugins-official`.
6969 
70For `not found` errors and marketplaces that won't add, see [Troubleshoot plugins](/docs/en/plugins/troubleshooting#install-a-plugin).
70For `not found` errors and marketplaces that won't add, see [Troubleshoot plugins](/docs/en/plugins/troubleshooting.md#install-a-plugin).
7171 
7272## Third-party marketplaces
7373 
7474Many popular plugins aren't in any Anthropic marketplace. They're in their authors' own marketplaces, usually a GitHub repository with a `.claude-plugin/marketplace.json` at its root.
7575 
76Anthropic doesn't review third-party marketplaces, so read [Plugin security and trust](/docs/en/plugins/security) before you add one.
76Anthropic doesn't review third-party marketplaces, so read [Plugin security and trust](/docs/en/plugins/security.md) before you add one.
7777 
7878To use a third-party marketplace, add its repository in a Claude Code session with `/plugin marketplace add <owner>/<repo>`, then install with `/plugin install <plugin>@<marketplace-name>`. The marketplace name is the `name` field of that `marketplace.json`, and Claude Code prints it once it has added the marketplace.
7979 
80For other ways to add a marketplace, see [Add a marketplace](/docs/en/plugins/install#add-a-marketplace).
80For other ways to add a marketplace, see [Add a marketplace](/docs/en/plugins/install.md#add-a-marketplace).
8181 
8282## Next steps
8383 
84* [Install and manage plugins](/docs/en/plugins/install): install a plugin from one of these marketplaces and choose a scope
85* [Plugin security and trust](/docs/en/plugins/security): what a plugin can do on your machine and how to review one before you install it
86* [Code intelligence plugins](/docs/en/plugins/code-intelligence): install one of the official marketplace's language-server plugins
87* [Create a marketplace](/docs/en/plugins/create-marketplace): run your own marketplace alongside Anthropic's
84* [Install and manage plugins](/docs/en/plugins/install.md): install a plugin from one of these marketplaces and choose a scope
85* [Plugin security and trust](/docs/en/plugins/security.md): what a plugin can do on your machine and how to review one before you install it
86* [Code intelligence plugins](/docs/en/plugins/code-intelligence.md): install one of the official marketplace's language-server plugins
87* [Create a marketplace](/docs/en/plugins/create-marketplace.md): run your own marketplace alongside Anthropic's
8888 

plugins/cli-hints Changed · +7 / -7 lines

from line 4
44 
55If you maintain a CLI or SDK, your tool can prompt Claude Code users to install your plugin. When your CLI detects that it's running inside Claude Code, have it write a one-line `<claude-code-hint />` tag to stderr. Claude Code removes the line from Bash and PowerShell tool output before the model sees the output, then shows the user a one-time install prompt.
66 
7This page applies only if your plugin is listed in `claude-plugins-official` or another marketplace with one of Anthropic's [official marketplace names](/docs/en/plugins/security#official-marketplace-names). The community marketplace, `claude-community`, isn't one of them.
7This page applies only if your plugin is listed in `claude-plugins-official` or another marketplace with one of Anthropic's [official marketplace names](/docs/en/plugins/security.md#official-marketplace-names). The community marketplace, `claude-community`, isn't one of them.
88 
99> [!NOTE]
1010>
11> To publish a plugin, see [Publish and distribute a plugin](/docs/en/plugins/publish).
11> To publish a plugin, see [Publish and distribute a plugin](/docs/en/plugins/publish.md).
1212 
1313## Emit the hint
1414 
from line 19
1919* **`CLAUDECODE`**: set by every Claude Code version. IDE extensions also set it in their integrated terminals, so a gate on `CLAUDECODE` alone also emits the tag when a person runs your CLI themselves in one of those terminals
2020* **`CLAUDE_CODE_CHILD_SESSION`**: set only in subprocesses Claude Code itself starts. Use it when you can require v2.1.172 or later
2121 
22The [environment variables reference](/docs/en/env-vars) has the details.
22The [environment variables reference](/docs/en/env-vars.md) has the details.
2323 
2424The following examples gate on `CLAUDECODE` for the widest reach and emit a hint for a plugin named `example-cli` in the official marketplace:
2525 
from line 81
8181The prompt appears only in interactive terminal sessions. In `claude -p` runs, in subagent runs, and in hook command output, the tag is stripped and no prompt is shown. All of these checks must also pass:
8282 
8383* **Official and installable**: `value` names a plugin that Claude Code finds in its local copy of an official marketplace, that isn't already installed, and that no policy blocks
84* **Analytics on**: a session where Claude Code's analytics are off never prompts, for example one with `DISABLE_TELEMETRY`, `DO_NOT_TRACK`, or `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC` set, or one on a third-party provider such as Amazon Bedrock, where the [automatic telemetry opt-out](/docs/en/data-usage#default-behaviors-by-api-provider) applies
84* **Analytics on**: a session where Claude Code's analytics are off never prompts, for example one with `DISABLE_TELEMETRY`, `DO_NOT_TRACK`, or `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC` set, or one on a third-party provider such as Amazon Bedrock, where the [automatic telemetry opt-out](/docs/en/data-usage.md#default-behaviors-by-api-provider) applies
8585* **Frequency limits**: one prompt per session, one prompt ever per plugin regardless of the user's answer, and none once 100 plugins have been prompted for on that machine
8686* **Not turned off**: the user hasn't chosen **No, and don't show plugin installation hints again**
8787* **Local, attended session**: the session's workspace is local rather than on a cloud or remote machine, and the session isn't running unattended. For example, a session started with `--cloud`, one serving Remote Control, or an agent-team teammate never prompts
from line 110
110110 
111111The dialog names the first word of the shell command Claude ran, so users can spot a mismatch. Each answer has one effect:
112112 
113* **Yes, install**: installs the plugin at [user scope](/docs/en/plugins/install)
113* **Yes, install**: installs the plugin at [user scope](/docs/en/plugins/install.md)
114114* **No, and don't show plugin installation hints again**: turns off future hint prompts for that user
115115* **No answer for 30 seconds**: counts as **No**
116116 
117117## Next steps
118118 
119* [Publish and distribute a plugin](/docs/en/plugins/publish): the routes for distributing a plugin, including the official marketplace, which the hint requires
120* [Plugin commands reference](/docs/en/plugins/cli-reference#plugin-install): the shell command that installs the same plugin outside a session
119* [Publish and distribute a plugin](/docs/en/plugins/publish.md): the routes for distributing a plugin, including the official marketplace, which the hint requires
120* [Plugin commands reference](/docs/en/plugins/cli-reference.md#plugin-install): the shell command that installs the same plugin outside a session
121121 

plugins/cli-reference Changed · +70 / -70 lines

from line 10
1010>
1111> These cases are covered on other pages:
1212>
13> * **Install and manage steps, and where `/plugin` runs**: see [Install and manage plugins](/docs/en/plugins/install)
14> * **What a command changes on disk and which scope takes precedence**: see [Plugin loading reference](/docs/en/plugins/loading)
15> * **What an error message means**: see [Troubleshoot plugins](/docs/en/plugins/troubleshooting)
13> * **Install and manage steps, and where `/plugin` runs**: see [Install and manage plugins](/docs/en/plugins/install.md)
14> * **What a command changes on disk and which scope takes precedence**: see [Plugin loading reference](/docs/en/plugins/loading.md)
15> * **What an error message means**: see [Troubleshoot plugins](/docs/en/plugins/troubleshooting.md)
1616 
1717## claude plugin commands
1818 
from line 28
2828 
2929### plugin init
3030 
31Scaffold a new plugin at `~/.claude/skills/<name>/`. Unless your administrator has [blocked skills-directory plugins](/docs/en/plugins/loading#skills-directory-plugins-blocked-by-managed-settings), it loads in your next session as `<name>@skills-dir` with no install step.
31Scaffold a new plugin at `~/.claude/skills/<name>/`. Unless your administrator has [blocked skills-directory plugins](/docs/en/plugins/loading.md#skills-directory-plugins-blocked-by-managed-settings), it loads in your next session as `<name>@skills-dir` with no install step.
3232 
3333`new` is an alias for `init`.
3434 
35For the create, test, and edit workflow that begins with this command, see [Create a plugin](/docs/en/plugins/create).
35For the create, test, and edit workflow that begins with this command, see [Create a plugin](/docs/en/plugins/create.md).
3636 
3737```bash theme={null}
3838claude plugin init <name> [options]
from line 40
4040 
4141`<name>` becomes the directory name under `~/.claude/skills/` and the plugin's `name` in its manifest.
4242 
43The command has no flag for another location. To scaffold inside a project instead, see [Create a plugin](/docs/en/plugins/create).
43The command has no flag for another location. To scaffold inside a project instead, see [Create a plugin](/docs/en/plugins/create.md).
4444 
4545| Flag | Description |
4646| :- | :- |
from line 72
7272claude plugin install <plugin> [options]
7373```
7474 
75Most plugins install without a prompt. For a plugin whose marketplace entry [runs a command to install it](/docs/en/plugins/host-marketplace) or [sets a `headersHelper` for its download](/docs/en/plugins/host-marketplace#how-users-accept-a-headershelper-command), Claude Code first prints the command and asks `Run this command now? [y/N]`.
75Most plugins install without a prompt. For a plugin whose marketplace entry [runs a command to install it](/docs/en/plugins/host-marketplace.md) or [sets a `headersHelper` for its download](/docs/en/plugins/host-marketplace#how-users-accept-a-headershelper-command), Claude Code first prints the command and asks `Run this command now? [y/N]`.
7676 
7777| Flag | Description |
7878| :- | :- |
7979| `-s, --scope <scope>` | Installation scope: `user`, `project`, or `local`. Defaults to `user` |
80| `--config <key=value>` | Set a [`userConfig`](/docs/en/plugins/manifest-reference) option the plugin's manifest declares. Repeat the flag for each option. A key written `<server>.<key>` sets a setting that a [bundled MCP server](/docs/en/plugins/components#include-a-packaged-mcpb-server) declares in its own `user_config` instead, for a bundle file shipped inside the plugin. The `<server>.<key>` form requires Claude Code v2.1.285 or later |
80| `--config <key=value>` | Set a [`userConfig`](/docs/en/plugins/manifest-reference) option the plugin's manifest declares. Repeat the flag for each option. A key written `<server>.<key>` sets a setting that a [bundled MCP server](/docs/en/plugins/components.md#include-a-packaged-mcpb-server) declares in its own `user_config` instead, for a bundle file shipped inside the plugin. The `<server>.<key>` form requires Claude Code v2.1.285 or later |
8181| `-y, --yes` | Accept the displayed install command without the `Run this command now?` prompt. Ignored when the command runs inside a Claude Code session, such as from the Bash tool or a hook. Requires Claude Code v2.1.229 or later |
8282| `--accept-command <sha256>` | Accept the displayed install command whose `sha256` a previous [`--json` run](#plugin-json-result) reported in `shownCommand`, in place of `-y`. Can't be combined with `-y`. See [Accept a displayed install command](#accept-a-displayed-install-command). Requires Claude Code v2.1.271 or later |
8383| `--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 |
84| `--marketplace <source>` | Install `<plugin>`, given by its bare name, from the marketplace at `<source>`, adding the marketplace first if you haven't added it yet. See [Add a marketplace and install in one command](/docs/en/plugins/install#add-a-marketplace-and-install-in-one-command). Requires Claude Code v2.1.292 or later |
84| `--marketplace <source>` | Install `<plugin>`, given by its bare name, from the marketplace at `<source>`, adding the marketplace first if you haven't added it yet. See [Add a marketplace and install in one command](/docs/en/plugins/install.md#add-a-marketplace-and-install-in-one-command). Requires Claude Code v2.1.292 or later |
8585 
8686Run `claude plugin install --help` in your shell to see every option your version supports.
8787 
from line 131
131131* `marketplace`: the name of the marketplace the command acted on
132132* `failureCode`: a code for why the command failed, such as `invalid_source`
133133 
134`plugin marketplace add` and `plugin marketplace remove` can print no result line when the argument is the [reserved name](/docs/en/plugins/marketplace-reference#reserved-names) `anthropic-plugin-directory`, so check the exit code for that name.
134`plugin marketplace add` and `plugin marketplace remove` can print no result line when the argument is the [reserved name](/docs/en/plugins/marketplace-reference.md#reserved-names) `anthropic-plugin-directory`, so check the exit code for that name.
135135 
136136#### Accept a displayed install command
137137 
from line 155
155155| :- | :- |
156156| `-s, --scope <scope>` | Uninstall from scope: `user`, `project`, or `local`. Defaults to `user` |
157157| `--keep-data` | Preserve the plugin's persistent data directory, `~/.claude/plugins/data/<id>/` |
158| `--prune` | Also remove auto-installed [dependencies](/docs/en/plugins/dependencies) that no remaining plugin needs |
158| `--prune` | Also remove auto-installed [dependencies](/docs/en/plugins/dependencies.md) that no remaining plugin needs |
159159| `-y, --yes` | Skip the `--prune` confirmation prompt. Required with `--prune` when stdin or stdout isn't a TTY |
160160| `--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 |
161161 
from line 171
171171 
172172#### What an uninstall deletes and keeps
173173 
174When you uninstall a plugin from the last scope it's installed at, Claude Code also deletes the plugin's stored [options and secrets](/docs/en/plugins/manifest-reference#user-configuration) and its data directory, `~/.claude/plugins/data/<id>/`. There are three exceptions:
174When you uninstall a plugin from the last scope it's installed at, Claude Code also deletes the plugin's stored [options and secrets](/docs/en/plugins/manifest-reference.md#user-configuration) and its data directory, `~/.claude/plugins/data/<id>/`. There are three exceptions:
175175 
176176* With `--keep-data`, the data directory stays
177177* When another installed plugin uses the same folder, such as one whose ID differs from this one only in letter case, the data directory stays
from line 181
181181 
182182### plugin enable
183183 
184Enable a disabled plugin. For a [plugin synced from claude.ai](/docs/en/plugins/loading#synced-plugins), pass `<name>@synced` as the plugin.
184Enable a disabled plugin. For a [plugin synced from claude.ai](/docs/en/plugins/loading.md#synced-plugins), pass `<name>@synced` as the plugin.
185185 
186186```bash theme={null}
187187claude plugin enable <plugin> [options]
from line 196
196196 
197197If you pass a `--scope` where the plugin isn't declared, the command either writes an override or fails:
198198 
199* **A scope that [takes precedence](/docs/en/plugins/loading) over the declaring one**: Claude Code writes an override at the scope you passed. For example, `claude plugin disable formatter --scope local` turns off a project-enabled plugin for you alone
199* **A scope that [takes precedence](/docs/en/plugins/loading.md) over the declaring one**: Claude Code writes an override at the scope you passed. For example, `claude plugin disable formatter --scope local` turns off a project-enabled plugin for you alone
200200* **Any other scope**: the command fails with `Plugin "formatter" is installed at project scope, not user. Use --scope project or omit --scope to auto-detect.`
201201 
202202If the plugin is already enabled at the resolved scope, the command prints `Plugin "formatter" is already enabled` and exits `1`. With `--json`, the result has `"failureCode": "already_in_goal_state"` and `"alreadyInGoalState": true`, so a script can treat that case as success.
203203 
204When the plugin declares [dependencies](/docs/en/plugins/dependencies), Claude Code enables them too. The command fails in these cases:
204When the plugin declares [dependencies](/docs/en/plugins/dependencies.md), Claude Code enables them too. The command fails in these cases:
205205 
206206* **A dependency is not installed**: enable fails and prints the `claude plugin install` command for each missing dependency
207207* **A dependency is blocked by your organization's plugin policy**: enable fails and names the blocked dependency
from line 217
217217 
218218### plugin disable
219219 
220Disable a plugin without uninstalling it. For a [plugin synced from claude.ai](/docs/en/plugins/loading#synced-plugins), pass `<name>@synced` as the plugin.
220Disable a plugin without uninstalling it. For a [plugin synced from claude.ai](/docs/en/plugins/loading.md#synced-plugins), pass `<name>@synced` as the plugin.
221221 
222222```bash theme={null}
223223claude plugin disable [plugin] [options]
from line 235
235235 
236236The command fails for a plugin that is still required:
237237 
238* **Another enabled plugin [depends on](/docs/en/plugins/dependencies) it**: the command fails and names the dependents to disable first
238* **Another enabled plugin [depends on](/docs/en/plugins/dependencies.md) it**: the command fails and names the dependents to disable first
239239* **Your organization requires it as a synced plugin**: the command fails and saves nothing
240240 
241241Disable one plugin:
from line 257
257257| Flag | Description |
258258| :- | :- |
259259| `-s, --scope <scope>` | Scope to update: `user`, `project`, `local`, or `managed`. Auto-detected when omitted |
260| `-y, --yes` | Accept a changed install command from a [command-source](/docs/en/plugins/host-marketplace) plugin, without the prompt. Required when stdin or stdout isn't a TTY, unless you pass `--accept-command`. Requires Claude Code v2.1.229 or later |
260| `-y, --yes` | Accept a changed install command from a [command-source](/docs/en/plugins/host-marketplace.md) plugin, without the prompt. Required when stdin or stdout isn't a TTY, unless you pass `--accept-command`. Requires Claude Code v2.1.229 or later |
261261| `--accept-command <sha256>` | Accept the marketplace-declared command whose `sha256` a previous [`--json` run](#plugin-json-result) reported in `shownCommand`, in place of `-y`. Can't be combined with `-y`. Requires Claude Code v2.1.271 or later |
262262| `--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 |
263263 
from line 275
275275 
276276Before v2.1.281, the command used `user` when you omitted `--scope`, so updating a plugin installed only at project or local scope failed with `Plugin "<name>" is not installed at scope user`. On those versions, pass `--scope`.
277277 
278`managed` is the one scope you can update but not install to. For admin-installed plugins, see [Manage plugins for your organization](/docs/en/plugins/org).
278`managed` is the one scope you can update but not install to. For admin-installed plugins, see [Manage plugins for your organization](/docs/en/plugins/org.md).
279279 
280280#### Update by bare name
281281 
from line 283
283283 
284284#### Retry an unfinished dependency install
285285 
286When the plugin is already at its latest version, the command can also retry an unfinished dependency install in its cached copy. For the cases where that retry runs or is skipped, see [The packages it lists are not installed](/docs/en/plugins/troubleshooting#the-packages-it-lists-are-not-installed). If the retry fails, the output is `Failed to update plugin "formatter@my-marketplace"` with the reason and the exit code is `1`. Before v2.1.287, the command reported the plugin at its latest version without retrying the install.
286When the plugin is already at its latest version, the command can also retry an unfinished dependency install in its cached copy. For the cases where that retry runs or is skipped, see [The packages it lists are not installed](/docs/en/plugins/troubleshooting.md#the-packages-it-lists-are-not-installed). If the retry fails, the output is `Failed to update plugin "formatter@my-marketplace"` with the reason and the exit code is `1`. Before v2.1.287, the command reported the plugin at its latest version without retrying the install.
287287 
288288### plugin list
289289 
from line 304
304304* **`Installed plugins:`**: plugins you installed from a marketplace
305305* **`Session-only plugins (--plugin-dir / --plugin-url):`**: plugins loaded by those flags in the same command, as in `claude --plugin-dir ./my-plugin plugin list`
306306* **`Skills-directory plugins (.claude/skills/*):`**: plugins Claude Code found in a skills directory
307* **`Synced from claude.ai`**: [plugins synced from your claude.ai account](/docs/en/plugins/loading#synced-plugins)
307* **`Synced from claude.ai`**: [plugins synced from your claude.ai account](/docs/en/plugins/loading.md#synced-plugins)
308308 
309309With nothing in any group, Claude Code prints ``No plugins installed. Use `claude plugin install` to install a plugin.``
310310 
from line 315
315315| Field | Type | Description |
316316| :- | :- | :- |
317317| `id` | string | `name@marketplace` for installs, `name@inline` for session-only plugins, `name@skills-dir` for skills-directory plugins, `name@synced` for plugins synced from claude.ai |
318| `version` | string | For a marketplace install, the [version Claude Code computed](/docs/en/plugins/loading#versions-and-updates) at install. For a session-only, skills-directory, or synced plugin, the manifest's `version`, or `unknown` when it declares none |
318| `version` | string | For a marketplace install, the [version Claude Code computed](/docs/en/plugins/loading.md#versions-and-updates) at install. For a session-only, skills-directory, or synced plugin, the manifest's `version`, or `unknown` when it declares none |
319319| `scope` | string | `user`, `project`, `local`, or `managed` for installs; `user` or `project` for skills-directory plugins; `session` for session-only plugins; `synced` for plugins synced from claude.ai |
320320| `enabled` | boolean | Whether the plugin is enabled in your merged settings |
321| `installPath` | string | Directory the plugin loads from, except for a plugin that sessions [load in place](/docs/en/plugins/loading#in-place-and-copied-plugins) from its marketplace's folder |
322| `readFromFolder` | string | For a plugin that sessions [load in place](/docs/en/plugins/loading#in-place-and-copied-plugins) from its marketplace's folder, the plugin's source directory inside that folder. Requires Claude Code v2.1.289 or later |
321| `installPath` | string | Directory the plugin loads from, except for a plugin that sessions [load in place](/docs/en/plugins/loading.md#in-place-and-copied-plugins) from its marketplace's folder |
322| `readFromFolder` | string | For a plugin that sessions [load in place](/docs/en/plugins/loading.md#in-place-and-copied-plugins) from its marketplace's folder, the plugin's source directory inside that folder. Requires Claude Code v2.1.289 or later |
323323| `folderVersion` | string | With `readFromFolder`, the plugin's `version` as Claude Code loaded it from that folder, which can differ from the `version` field above. Absent when the plugin didn't load or declares no version. Requires Claude Code v2.1.289 or later |
324324| `installedAt` | string | ISO timestamp of the install. Marketplace installs only |
325325| `lastUpdated` | string | ISO timestamp of the last update. Marketplace installs only |
from line 326
326326| `projectPath` | string | Project the install belongs to. `project` and `local` scope only |
327327| `mcpServers` | object | The plugin's MCP server definitions, when a marketplace-installed plugin has any |
328328| `errors` | array of strings | Load errors, when the plugin failed to load |
329| `notes` | array of strings | Warnings that aren't load errors, such as authoring issues or [packages that aren't installed](/docs/en/plugins/loading#when-the-dependency-install-fails-or-is-skipped) |
329| `notes` | array of strings | Warnings that aren't load errors, such as authoring issues or [packages that aren't installed](/docs/en/plugins/loading.md#when-the-dependency-install-fails-or-is-skipped) |
330330| `errorDetails` | array of objects | One object per `errors` entry, giving its diagnostic `type` and the names it refers to, such as the plugin, marketplace, server, or file. Requires Claude Code v2.1.268 or later |
331331| `noteDetails` | array of objects | The same detail objects for each `notes` entry. Requires Claude Code v2.1.268 or later |
332332| `hasUserConfig` | boolean | Present and `true` when the plugin loaded and its manifest declares [`userConfig` options](/docs/en/plugins/manifest-reference#user-configuration). Absent for a plugin that failed to load, whatever its manifest declares. Saved values are never included. Requires Claude Code v2.1.285 or later |
from line 341
341341| `pluginId` | string | `name@marketplace` |
342342| `name` | string | The plugin's name in the marketplace |
343343| `marketplaceName` | string | The marketplace that offers it |
344| `source` | string or object | The marketplace entry's [source](/docs/en/plugins/marketplace-reference): a string for a relative path, an object otherwise |
344| `source` | string or object | The marketplace entry's [source](/docs/en/plugins/marketplace-reference.md): a string for a relative path, an object otherwise |
345345| `description` | string | The entry's description, when it has one |
346346| `version` | string | The entry's version, when it declares one |
347347| `installCount` | number | Install count, when Claude Code has one for the plugin |
from line 370
370370* **`Projected token cost`**: the always-on tokens the plugin adds to every session
371371* **`Per-component (rounded)`**: always-on and on-invoke estimates for each skill, agent, and command. Omitted when the plugin has none
372372 
373For what the two cost figures mean, see [Measure plugin cost and usage](/docs/en/plugins/measure).
373For what the two cost figures mean, see [Measure plugin cost and usage](/docs/en/plugins/measure.md).
374374 
375375For a plugin that isn't loaded, Claude Code prints this message and exits `1`:
376376 
from line 378
378378Plugin "formatter" not found. Run `claude plugin list` to see installed plugins, or pass --plugin-dir <path> to load one from disk.
379379```
380380 
381An ID that ends in `@builtin` names one of the [plugins built into Claude Code](/docs/en/plugins/mods/overview#mods-built-into-claude-code). If you pass such an ID and Claude Code doesn't find that plugin, the message reads instead:
381An ID that ends in `@builtin` names one of the [plugins built into Claude Code](/docs/en/plugins/mods/overview.md#mods-built-into-claude-code). If you pass such an ID and Claude Code doesn't find that plugin, the message reads instead:
382382 
383383```text theme={null}
384384Plugin "<name>@builtin" not found. Built-in plugins don't appear in `claude plugin list`. To see the ones available in a session, run /plugin in Claude Code and open the Installed tab.
from line 413
413413 
414414### plugin prune
415415 
416Remove auto-installed [dependencies](/docs/en/plugins/dependencies) that no installed plugin needs anymore. The command never removes a plugin you installed yourself. `autoremove` is an alias for `prune`.
416Remove auto-installed [dependencies](/docs/en/plugins/dependencies.md) that no installed plugin needs anymore. The command never removes a plugin you installed yourself. `autoremove` is an alias for `prune`.
417417 
418418```bash theme={null}
419419claude plugin prune [options]
from line 447
447447 
448448### plugin eval
449449 
450Run a plugin's [eval cases](/docs/en/plugin-evals) and report scored results. Requires Claude Code v2.1.269 or later.
450Run a plugin's [eval cases](/docs/en/plugin-evals.md) and report scored results. Requires Claude Code v2.1.269 or later.
451451 
452452Each 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.
453453 
454See [Test plugins with evals](/docs/en/plugin-evals) for the case format, graders, results, and CI usage.
454See [Test plugins with evals](/docs/en/plugin-evals.md) for the case format, graders, results, and CI usage.
455455 
456456```bash theme={null}
457457claude plugin eval [target] [options]
from line 470
470470 
471471| Option | Description | Default |
472472| :- | :- | :- |
473| `--runs <n>` | Runs per case in each [arm](/docs/en/plugin-evals#compare-against-a-no-plugin-baseline) | Each case's `runs`, else 3 |
473| `--runs <n>` | Runs per case in each [arm](/docs/en/plugin-evals.md#compare-against-a-no-plugin-baseline) | Each case's `runs`, else 3 |
474474| `-j, --concurrency <n>` | Agent sessions to run at once, 1 to 8. They share your rate limit | `1` |
475475| `--model <model>` | Model for the agent under test | Each case's `model`, else `ANTHROPIC_MODEL` if set, else Claude Code's default |
476| `--judge-model <model>` | Model for `llm` and `baseline` graders | The model for [background tasks](/docs/en/plugin-evals#grade-the-result) |
477| `--ablation <mode>` | `none` or `with-without`. See [Score against the no-plugin baseline](/docs/en/plugin-evals#compare-against-a-no-plugin-baseline) | Decided per case, as that section describes |
476| `--judge-model <model>` | Model for `llm` and `baseline` graders | The model for [background tasks](/docs/en/plugin-evals.md#grade-the-result) |
477| `--ablation <mode>` | `none` or `with-without`. See [Score against the no-plugin baseline](/docs/en/plugin-evals.md#compare-against-a-no-plugin-baseline) | Decided per case, as that section describes |
478478| `--threshold <0..1>` | Exit 1 if any case scores below this | `1.0` |
479479| `--max-cost-usd <usd>` | Stop before the next run once spend reaches this, exit 2, and report partial results | No limit |
480| `--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) | |
480| `--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.md#grant-tools) | |
481481| `--scaffold` | Run each case's [`scaffold_script`](/docs/en/plugin-evals#add-setup-or-history-with-case-yaml) | Off |
482| `--trust-plugin` | Skip the first-run trust prompt, for CI. See [What a run can access](/docs/en/plugin-evals#security) | Off |
483| `--mocks <mode>` | `record` or `off`. See [Mock MCP servers](/docs/en/plugin-evals#mock-mcp-servers) | `record` |
482| `--trust-plugin` | Skip the first-run trust prompt, for CI. See [What a run can access](/docs/en/plugin-evals.md#security) | Off |
483| `--mocks <mode>` | `record` or `off`. See [Mock MCP servers](/docs/en/plugin-evals.md#mock-mcp-servers) | `record` |
484484| `--eval-dir <dir>` | Directory below the plugin that holds the cases | The manifest's `experimental.evals`, else `evals` |
485| `--json [path]` | Print the [result document](/docs/en/plugin-evals#json-result) to stdout, or write it to a `.json` path | |
485| `--json [path]` | Print the [result document](/docs/en/plugin-evals.md#json-result) to stdout, or write it to a `.json` path | |
486486| `--no-publish` | Keep the HTML report local | |
487487 
488The exit code reports how the run ended. To act on it in a pipeline, see [Run evals in CI](/docs/en/plugin-evals#run-evals-in-ci).
488The exit code reports how the run ended. To act on it in a pipeline, see [Run evals in CI](/docs/en/plugin-evals.md#run-evals-in-ci).
489489 
490490| Exit code | Meaning |
491491| :- | :- |
492492| `0` | The suite passed: every case meets the threshold and nothing else failed the run |
493| `1` | A failing case, a load error, an untrusted plugin directory, a run that [ended on an API error](/docs/en/plugin-evals#runs-ended-on-an-api-error), or another cause listed under [Run evals in CI](/docs/en/plugin-evals#run-evals-in-ci) |
493| `1` | A failing case, a load error, an untrusted plugin directory, a run that [ended on an API error](/docs/en/plugin-evals.md#runs-ended-on-an-api-error), or another cause listed under [Run evals in CI](/docs/en/plugin-evals.md#run-evals-in-ci) |
494494| `2` | A partial run |
495495| `130` | Interrupted |
496496| `143` | Terminated |
from line 497
497497 
498498### plugin eval init
499499 
500Create an eval suite for the plugin in the current directory. Requires Claude Code v2.1.269 or later. See [Create your first eval suite](/docs/en/plugin-evals#create-your-first-eval-suite).
500Create an eval suite for the plugin in the current directory. Requires Claude Code v2.1.269 or later. See [Create your first eval suite](/docs/en/plugin-evals.md#create-your-first-eval-suite).
501501 
502502```bash theme={null}
503503claude plugin eval init [name] [options]
from line 529
529529 
530530Create an annotated git tag named `<name>--v<version>` for a plugin release. Before tagging, the command checks that the plugin's `plugin.json` and any marketplace entry that lists it agree on the version.
531531 
532For when to tag a release, see [Publish a plugin](/docs/en/plugins/publish).
532For when to tag a release, see [Publish a plugin](/docs/en/plugins/publish.md).
533533 
534534```bash theme={null}
535535claude plugin tag [path] [options]
from line 569
569569 
570570### plugin test
571571 
572Run the tests for a [mod](/docs/en/plugins/mods/overview), a plugin whose code registers event handlers. The command needs no session, sign-in, or network. For how to write a test, see [Test a mod](/docs/en/plugins/mods/test).
572Run the tests for a [mod](/docs/en/plugins/mods/overview.md), a plugin whose code registers event handlers. The command needs no session, sign-in, or network. For how to write a test, see [Test a mod](/docs/en/plugins/mods/test.md).
573573 
574574```bash theme={null}
575575claude plugin test [directory]
from line 585
585585 
586586### plugin validate
587587 
588Validate a plugin manifest, a marketplace manifest, or the skills, agents, and commands in a directory, and exit with a code a CI job can act on. For the create, test, and edit workflow, see [Create a plugin](/docs/en/plugins/create). For what the validator checks in each manifest, see the [plugin manifest reference](/docs/en/plugins/manifest-reference) and the [marketplace reference](/docs/en/plugins/marketplace-reference).
588Validate a plugin manifest, a marketplace manifest, or the skills, agents, and commands in a directory, and exit with a code a CI job can act on. For the create, test, and edit workflow, see [Create a plugin](/docs/en/plugins/create.md). For what the validator checks in each manifest, see the [plugin manifest reference](/docs/en/plugins/manifest-reference.md) and the [marketplace reference](/docs/en/plugins/marketplace-reference.md).
589589 
590590```bash theme={null}
591591claude plugin validate <path> [options]
from line 644
644644* `target`: the resolved path Claude Code validated
645645* `manifest`: the manifest's own result, or `null` for a run without a manifest
646646* `contents`: per-file results, each naming its `file` and carrying `errors`, `warnings`, and `notes` arrays
647 * `gatingHooks`: whether each [mod](/docs/en/plugins/mods/overview) hook that can refuse an action, such as a `tool.call` hook, has a [`.catch` handler](/docs/en/plugins/mods/events#handle-a-hook-that-fails). Each item gives `module`, `pattern`, `hook`, and `hasCatch`. Requires Claude Code v2.1.290 or later
647 * `gatingHooks`: whether each [mod](/docs/en/plugins/mods/overview.md) hook that can refuse an action, such as a `tool.call` hook, has a [`.catch` handler](/docs/en/plugins/mods/events#handle-a-hook-that-fails). Each item gives `module`, `pattern`, `hook`, and `hasCatch`. Requires Claude Code v2.1.290 or later
648648 
649649On exit `2`, the command writes nothing to stdout. The error message goes to stderr.
650650 
from line 655
655655* **Exit codes**: these subcommands follow the [exit-code convention](#claude-plugin-commands) of the plugin commands
656656* **Scopes**: their `--scope` flag has no `-s` short form
657657 
658For what a marketplace is and how Claude Code caches it, see [Plugin loading reference](/docs/en/plugins/loading).
658For what a marketplace is and how Claude Code caches it, see [Plugin loading reference](/docs/en/plugins/loading.md).
659659 
660660### plugin marketplace add
661661 
662662Add a marketplace from a GitHub repository, a git URL, a hosted `marketplace.json`, or a local path, and declare it in a settings file.
663663 
664After you add it, Claude Code installs any [dependencies](/docs/en/plugins/dependencies) that your installed plugins were missing.
664After you add it, Claude Code installs any [dependencies](/docs/en/plugins/dependencies.md) that your installed plugins were missing.
665665 
666666```bash theme={null}
667667claude plugin marketplace add <source> [options]
from line 671
671671| :- | :- |
672672| `--scope <scope>` | Settings file to declare the marketplace in: `user`, `project`, or `local`. Defaults to `user` |
673673| `--sparse <paths...>` | Limit the git checkout to these directories, for monorepos. `github` and `git` sources only |
674| `--claudeai` | Read the argument as the name of a [marketplace hosted on claude.ai](/docs/en/plugins/install#add-from-claude-ai) instead of a source. Requires Claude Code v2.1.273 or later |
674| `--claudeai` | Read the argument as the name of a [marketplace hosted on claude.ai](/docs/en/plugins/install.md#add-from-claude-ai) instead of a source. Requires Claude Code v2.1.273 or later |
675675| `--json` | Print whether the command succeeded, and its message, as one JSON object on the last line of stdout, in the [JSON result format](#plugin-json-result). Has no effect with `--claudeai`. Requires Claude Code v2.1.287 or later |
676676 
677`<source>` takes any of the forms in the table below, and its form decides the source type and how Claude Code fetches the marketplace. For the resulting source object, see the [marketplace reference](/docs/en/plugins/marketplace-reference).
677`<source>` takes any of the forms in the table below, and its form decides the source type and how Claude Code fetches the marketplace. For the resulting source object, see the [marketplace reference](/docs/en/plugins/marketplace-reference.md).
678678 
679679| You type | Source type | How Claude Code fetches it |
680680| :- | :- | :- |
from line 702
702702* **Unrecognized source**: the output is `Invalid marketplace source format. Try: owner/repo, https://..., or ./path` and the exit code is `1`
703703* **Bare host such as `gitlab.example.com/team/plugins`**: the add fails as an invalid `owner/repo` shorthand, and the message tells you to add `https://` or use a local path
704704 
705Add a [marketplace hosted on claude.ai](/docs/en/plugins/install#add-from-claude-ai) by the name printed in the `From claude.ai:` section of `claude plugin marketplace list`:
705Add a [marketplace hosted on claude.ai](/docs/en/plugins/install.md#add-from-claude-ai) by the name printed in the `From claude.ai:` section of `claude plugin marketplace list`:
706706 
707707```bash theme={null}
708708claude plugin marketplace add --claudeai claudeai-organization-library
from line 736
736736| `ref` | The pinned branch or tag. `github` and `git` sources, only when pinned |
737737| `installLocation` | Where Claude Code cached the marketplace |
738738 
739An added [claude.ai marketplace](/docs/en/plugins/install#add-from-claude-ai) has no local clone, so its entry carries its claude.ai identifiers, `marketplaceId` and `organizationUuid`, in place of `installLocation`. It also carries `scope` when one is recorded, and `status`.
739An added [claude.ai marketplace](/docs/en/plugins/install.md#add-from-claude-ai) has no local clone, so its entry carries its claude.ai identifiers, `marketplaceId` and `organizationUuid`, in place of `installLocation`. It also carries `scope` when one is recorded, and `status`.
740740 
741If your terminal sessions [sync plugins from your claude.ai account](/docs/en/plugins/loading#synced-plugins), the text listing ends with a `From claude.ai:` section. That section names the marketplaces claude.ai lists for your account that you haven't added, both git-based and hosted. It requires Claude Code v2.1.273 or later.
741If your terminal sessions [sync plugins from your claude.ai account](/docs/en/plugins/loading.md#synced-plugins), the text listing ends with a `From claude.ai:` section. That section names the marketplaces claude.ai lists for your account that you haven't added, both git-based and hosted. It requires Claude Code v2.1.273 or later.
742742 
743To add a marketplace from that section, see [Add a marketplace from claude.ai](/docs/en/plugins/install#add-from-claude-ai).
743To add a marketplace from that section, see [Add a marketplace from claude.ai](/docs/en/plugins/install.md#add-from-claude-ai).
744744 
745745The `--json` output covers configured marketplaces only and leaves the section out.
746746 
from line 750
750750 
751751> [!WARNING]
752752>
753> When you remove a marketplace from the last scope that declares it, Claude Code also deletes its cache and uninstalls every plugin you installed from it. It also deletes their saved [options and secrets](/docs/en/plugins/manifest-reference#user-configuration) and [data](/docs/en/plugins/components#path-variables-and-persistent-data) where it can.
753> When you remove a marketplace from the last scope that declares it, Claude Code also deletes its cache and uninstalls every plugin you installed from it. It also deletes their saved [options and secrets](/docs/en/plugins/manifest-reference.md#user-configuration) and [data](/docs/en/plugins/components.md#path-variables-and-persistent-data) where it can.
754754>
755755> To refresh a marketplace without losing its plugins, run `plugin marketplace update` instead.
756756 
from line 801
801801 
802802You can run these commands only in an interactive terminal session. In a non-interactive run such as `claude -p`, Claude Code replies that `/plugin` isn't available in this environment.
803803 
804For which surfaces have `/plugin`, how to install without it, and what each panel tab shows, see [Install and manage plugins](/docs/en/plugins/install).
804For which surfaces have `/plugin`, how to install without it, and what each panel tab shows, see [Install and manage plugins](/docs/en/plugins/install.md).
805805 
806806A `<plugin>` is a plugin `name` or `name@marketplace`.
807807 
from line 814
814814| `/plugin list [--enabled\|--disabled]` | `ls` | Prints your marketplace-installed plugins inline, with version, scope, and status. A filter flag shows only that state. A plugin whose enable state hasn't been applied yet is marked `— run /reload-plugins to apply` |
815815| `/plugin install` | `i` | Opens the **Discover** tab |
816816| `/plugin install <plugin>` | `i` | Opens the plugin's details in the **Discover** tab. With `name@marketplace`, opens them in that marketplace's list |
817| `/plugin install <source>` | `i` | Reports a [marketplace not found](/docs/en/plugins/troubleshooting#marketplace-not-found) error and installs nothing when the target is a path, URL, or `owner/repo`, even a source you've already added. To install from a source, see [Add a marketplace and install in one command](/docs/en/plugins/install#add-a-marketplace-and-install-in-one-command) |
818| `/plugin install <plugin> --marketplace <source>` | `i` | Adds the marketplace at `<source>` when you haven't added it yet, asking you to confirm first, then opens the plugin's details. See [Add a marketplace and install in one command](/docs/en/plugins/install#add-a-marketplace-and-install-in-one-command). Requires Claude Code v2.1.275 or later |
817| `/plugin install <source>` | `i` | Reports a [marketplace not found](/docs/en/plugins/troubleshooting.md#marketplace-not-found) error and installs nothing when the target is a path, URL, or `owner/repo`, even a source you've already added. To install from a source, see [Add a marketplace and install in one command](/docs/en/plugins/install.md#add-a-marketplace-and-install-in-one-command) |
818| `/plugin install <plugin> --marketplace <source>` | `i` | Adds the marketplace at `<source>` when you haven't added it yet, asking you to confirm first, then opens the plugin's details. See [Add a marketplace and install in one command](/docs/en/plugins/install.md#add-a-marketplace-and-install-in-one-command). Requires Claude Code v2.1.275 or later |
819819| `/plugin manage` | | Opens the **Installed** tab |
820820| `/plugin stats` | | Opens the **Stats** tab, in sessions where [`/skill-doctor`](/docs/en/skills#find-unused-skills) is available. Anywhere else it opens the panel on the **Discover** tab |
821821| `/plugin enable <plugin>` | | Opens the **Installed** tab at the plugin and enables it |
from line 852
852852 
853853The skills count covers every skill a plugin provides, both its `commands/` entries and its `SKILL.md` skills. The agents count is the number of agents loaded in the session, including ones that don't come from plugins.
854854 
855When a reloaded plugin's [dependencies](/docs/en/plugins/dependencies) are missing, Claude Code installs them, reloads again, and appends `(+ N dependencies: <names>) resolved` to the summary.
855When a reloaded plugin's [dependencies](/docs/en/plugins/dependencies.md) are missing, Claude Code installs them, reloads again, and appends `(+ N dependencies: <names>) resolved` to the summary.
856856 
857857### Reloads that change MCP tools
858858 
859When the reload would add or remove a plugin MCP server or the `LSP` tool, and that change would invalidate the [prompt cache](/docs/en/prompt-caching#enabling-or-disabling-a-plugin), Claude Code doesn't apply the reload. It prints a line such as `This reload changes MCP tools (<server>) — your next message will re-read the whole conversation instead of using the cache. Run /reload-plugins --force to apply.` Pass `--force` to apply it anyway.
859When the reload would add or remove a plugin MCP server or the `LSP` tool, and that change would invalidate the [prompt cache](/docs/en/prompt-caching.md#enabling-or-disabling-a-plugin), Claude Code doesn't apply the reload. It prints a line such as `This reload changes MCP tools (<server>) — your next message will re-read the whole conversation instead of using the cache. Run /reload-plugins --force to apply.` Pass `--force` to apply it anyway.
860860 
861861### Sessions without an interactive terminal
862862 
863`/reload-plugins` also runs in sessions without an interactive terminal, such as the desktop app, the Agent SDK, and [non-interactive mode](/docs/en/headless) with `-p`. Requires Claude Code v2.1.260 or later.
863`/reload-plugins` also runs in sessions without an interactive terminal, such as the desktop app, the Agent SDK, and [non-interactive mode](/docs/en/headless.md) with `-p`. Requires Claude Code v2.1.260 or later.
864864 
865In those sessions, the command runs only when you type it into the session yourself, such as in the `-p` prompt or the desktop app's prompt box. When it arrives another way, such as through [Remote Control](/docs/en/remote-control) or a message relayed from Slack, the command replies `/reload-plugins isn't available over a remote connection in this session.` and reloads nothing.
865In those sessions, the command runs only when you type it into the session yourself, such as in the `-p` prompt or the desktop app's prompt box. When it arrives another way, such as through [Remote Control](/docs/en/remote-control.md) or a message relayed from Slack, the command replies `/reload-plugins isn't available over a remote connection in this session.` and reloads nothing.
866866 
867867The reload in those sessions doesn't connect or disconnect plugin MCP servers. Those changes take effect in your next session.
868868 
from line 870
870870 
871871Two `claude` flags load a plugin for one session only, without installing it. Both are repeatable.
872872 
873Plugin authors use them to test a plugin before publishing. For the load-edit-reload workflow, see [Develop without a marketplace](/docs/en/plugins/create#develop-without-a-marketplace).
873Plugin authors use them to test a plugin before publishing. For the load-edit-reload workflow, see [Develop without a marketplace](/docs/en/plugins/create.md#develop-without-a-marketplace).
874874 
875875| Flag | Description | Example |
876876| :- | :- | :- |
from line 879
879879 
880880A plugin that either flag loads is a session-only plugin. [`claude plugin list`](#plugin-list) shows it only when the same flag precedes the subcommand, as in `claude --plugin-dir ./my-plugin plugin list`. The plugin appears as `<name>@inline` under a heading that begins `Session-only plugins`, and `--json` reports its `scope` as `session`.
881881 
882When a session-only plugin shares a name with an installed plugin, Claude Code loads the session-only copy for that session and skips the installed one. The installed copy loads instead if you disabled the session-only copy with `claude plugin disable <name>@inline`, or if managed settings lock that plugin name. For the precedence, see [Plugin loading reference](/docs/en/plugins/loading).
882When a session-only plugin shares a name with an installed plugin, Claude Code loads the session-only copy for that session and skips the installed one. The installed copy loads instead if you disabled the session-only copy with `claude plugin disable <name>@inline`, or if managed settings lock that plugin name. For the precedence, see [Plugin loading reference](/docs/en/plugins/loading.md).
883883 
884884An administrator can reject both flags, and folders named in the [`CLAUDE_CODE_PLUGIN_DIRS`](/docs/en/env-vars#variables) variable, with the managed [`disableSideloadFlags`](/docs/en/settings-reference#disablesideloadflags) setting. Claude Code then prints that the flag is disabled by your organization's managed settings and exits `1` without starting.
885885 
from line 887
887887 
888888## Next steps
889889 
890* [Install and manage plugins](/docs/en/plugins/install): the same operations as steps, with what you see at each one
891* [Plugin loading reference](/docs/en/plugins/loading): what each command changes on disk and which scope takes effect
892* [Troubleshoot plugins](/docs/en/plugins/troubleshooting): install, marketplace, load, and validation error messages with their fixes
893* [Plugin manifest reference](/docs/en/plugins/manifest-reference): the fields `claude plugin validate` checks
890* [Install and manage plugins](/docs/en/plugins/install.md): the same operations as steps, with what you see at each one
891* [Plugin loading reference](/docs/en/plugins/loading.md): what each command changes on disk and which scope takes effect
892* [Troubleshoot plugins](/docs/en/plugins/troubleshooting.md): install, marketplace, load, and validation error messages with their fixes
893* [Plugin manifest reference](/docs/en/plugins/manifest-reference.md): the fields `claude plugin validate` checks
894894 

plugins/code-intelligence Changed · +11 / -11 lines

from line 8
88 
99> [!NOTE]
1010>
11> Code intelligence plugins work in terminal sessions. In [cloud sessions](/docs/en/claude-code-on-the-web), Claude Code doesn't start plugin language servers, so Claude gets no diagnostics or code navigation there. To write your own language server plugin, or to connect a language server that has no plugin, see [LSP servers in plugin components](/docs/en/plugins/components#lsp-servers).
11> Code intelligence plugins work in terminal sessions. In [cloud sessions](/docs/en/claude-code-on-the-web.md), Claude Code doesn't start plugin language servers, so Claude gets no diagnostics or code navigation there. To write your own language server plugin, or to connect a language server that has no plugin, see [LSP servers in plugin components](/docs/en/plugins/components.md#lsp-servers).
1212 
13To get started, find your language in the table under [Install a code intelligence plugin](#install-a-code-intelligence-plugin). The plugins in that table come from Anthropic's [official plugin marketplace](/docs/en/plugins/anthropic-marketplaces).
13To get started, find your language in the table under [Install a code intelligence plugin](#install-a-code-intelligence-plugin). The plugins in that table come from Anthropic's [official plugin marketplace](/docs/en/plugins/anthropic-marketplaces.md).
1414 
1515If you already saw an **LSP plugin recommendation** dialog, see [Accept or dismiss the recommendation dialog](#accept-or-dismiss-the-recommendation-dialog) for what each choice does.
1616 
from line 46
4646 
4747**2. Install the plugin**
4848 
49In the VS Code extension or the desktop app, follow [Install a plugin](/docs/en/plugins/install#install-a-plugin) instead of this step. In a terminal, start Claude Code by running `claude`, then enter this at its prompt, replacing `typescript-lsp` with the plugin the step 1 table lists for your language:
49In the VS Code extension or the desktop app, follow [Install a plugin](/docs/en/plugins/install.md#install-a-plugin) instead of this step. In a terminal, start Claude Code by running `claude`, then enter this at its prompt, replacing `typescript-lsp` with the plugin the step 1 table lists for your language:
5050 
5151```
5252/plugin install typescript-lsp@claude-plugins-official
5353```
5454 
55A confirmation message says whether the plugin is active now or needs `/reload-plugins`. If the install fails with `Marketplace "claude-plugins-official" not found`, see the [troubleshooting entry for that error](/docs/en/plugins/troubleshooting#marketplace-claude-plugins-official-not-found). To control where the plugin is installed, or to run the install from your shell instead of inside Claude Code, see [Install plugins](/docs/en/plugins/install).
55A confirmation message says whether the plugin is active now or needs `/reload-plugins`. If the install fails with `Marketplace "claude-plugins-official" not found`, see the [troubleshooting entry for that error](/docs/en/plugins/troubleshooting.md#marketplace-claude-plugins-official-not-found). To control where the plugin is installed, or to run the install from your shell instead of inside Claude Code, see [Install plugins](/docs/en/plugins/install.md).
5656 
5757**3. Confirm the server starts**
5858 
from line 68
6868With a language server running, Claude gains diagnostics and code navigation:
6969 
7070* **Diagnostics after edits**: each time Claude edits or writes a file the server handles, Claude gets the errors and warnings the server reports. It sees a type error, missing import, or syntax error it introduced without running a compiler.
71* **Code navigation**: Claude gets an `LSP` tool that looks up symbols through the server instead of searching text for them. The tool is read-only. For what Claude can look up with the tool and how permissions apply to it, see [LSP tool behavior](/docs/en/tools-reference#lsp-tool-behavior).
71* **Code navigation**: Claude gets an `LSP` tool that looks up symbols through the server instead of searching text for them. The tool is read-only. For what Claude can look up with the tool and how permissions apply to it, see [LSP tool behavior](/docs/en/tools-reference.md#lsp-tool-behavior).
7272 
7373### Read the diagnostics yourself
7474 
from line 107
107107 
108108## Troubleshoot code intelligence
109109 
110The plugins troubleshooting page covers the symptoms specific to code intelligence plugins under [Language server doesn't start, uses too much memory, or reports wrong diagnostics](/docs/en/plugins/troubleshooting#language-server-doesnt-start):
110The plugins troubleshooting page covers the symptoms specific to code intelligence plugins under [Language server doesn't start, uses too much memory, or reports wrong diagnostics](/docs/en/plugins/troubleshooting.md#language-server-doesnt-start):
111111 
112112* **The language server doesn't start**: you see `Executable not found in $PATH` in the **Errors** tab of `/plugin`, or Claude never reports diagnostics for the language.
113113* **High memory use**: memory use increases while the server indexes the project.
from line 120
1201201. Write a plugin with an `.lsp.json` file that names the server command and the file extensions it handles.
1211212. Then load the plugin with [`--plugin-dir`](/docs/en/plugins/cli-reference#flags-that-load-a-plugin-for-one-session) or publish it to a marketplace.
122122 
123For the file's fields and a worked example, see [LSP servers in plugin components](/docs/en/plugins/components#lsp-servers).
123For the file's fields and a worked example, see [LSP servers in plugin components](/docs/en/plugins/components.md#lsp-servers).
124124 
125125## Next steps
126126 
127* [LSP servers in plugin components](/docs/en/plugins/components#lsp-servers): write the `.lsp.json` for a language server that has no official plugin
128* [Install and manage plugins](/docs/en/plugins/install): scopes, updates, and uninstalling
129* [Troubleshoot plugins](/docs/en/plugins/troubleshooting): load errors beyond the language-server ones on this page
130* [Find plugins in the official marketplace](/docs/en/plugins/anthropic-marketplaces#find-plugins-in-the-official-marketplace): where to browse the rest of the official marketplace
127* [LSP servers in plugin components](/docs/en/plugins/components.md#lsp-servers): write the `.lsp.json` for a language server that has no official plugin
128* [Install and manage plugins](/docs/en/plugins/install.md): scopes, updates, and uninstalling
129* [Troubleshoot plugins](/docs/en/plugins/troubleshooting.md): load errors beyond the language-server ones on this page
130* [Find plugins in the official marketplace](/docs/en/plugins/anthropic-marketplaces.md#find-plugins-in-the-official-marketplace): where to browse the rest of the official marketplace
131131 

plugins/components Changed · +58 / -58 lines

from line 2
22 
33> Add skills, hooks, MCP servers, and every other component type to a Claude Code plugin, with an example that validates for each.
44 
5A Claude Code plugin is built from components, such as skills, agents, hooks, and MCP servers. Each component has a default folder in the plugin, an optional manifest key in `.claude-plugin/plugin.json` that replaces or adds to that folder, and a name the user sees. For each key's full field table, see the [manifest reference](/docs/en/plugins/manifest-reference#fields).
5A Claude Code plugin is built from components, such as skills, agents, hooks, and MCP servers. Each component has a default folder in the plugin, an optional manifest key in `.claude-plugin/plugin.json` that replaces or adds to that folder, and a name the user sees. For each key's full field table, see the [manifest reference](/docs/en/plugins/manifest-reference.md#fields).
66 
77Use this page to add a component to a plugin that already loads.
88 
from line 12
1212>
1313> These cases are covered on other pages:
1414>
15> * **Building your first plugin**: start with [Create a plugin](/docs/en/plugins/create)
16> * **Installing someone else's plugin**: see [Install plugins](/docs/en/plugins/install)
15> * **Building your first plugin**: start with [Create a plugin](/docs/en/plugins/create.md)
16> * **Installing someone else's plugin**: see [Install plugins](/docs/en/plugins/install.md)
1717> * **Your plugin's users are on claude.ai or in Cowork**: a different set of components loads there. See [Plugin structure and testing](https://claude.com/docs/plugins/build) and the [component support table](https://claude.com/docs/plugins/platform-support#compare-component-support-by-app)
1818 
1919## Explore the plugin directory
from line 42
4242 
4343Selected piece
4444 
45The [manifest](/docs/en/plugins/manifest-reference) is the `plugin.json` file in a plugin's `.claude-plugin/` directory. It contains the plugin's metadata and the `userConfig` values that Claude Code prompts the user for. Claude Code loads a plugin without one. Inside the file, only `name` is required. In this one, `description` is the text users see for the plugin in `/plugin`, and `version` keeps users on that version until you change it:
45The [manifest](/docs/en/plugins/manifest-reference.md) is the `plugin.json` file in a plugin's `.claude-plugin/` directory. It contains the plugin's metadata and the `userConfig` values that Claude Code prompts the user for. Claude Code loads a plugin without one. Inside the file, only `name` is required. In this one, `description` is the text users see for the plugin in `/plugin`, and `version` keeps users on that version until you change it:
4646 
4747```json theme={null}
4848{
from line 52
5252}
5353```
5454 
55A [skill](/docs/en/skills) is a `SKILL.md` file. Save each skill in its own directory under `skills/`. Claude reads every skill's `description`, and when what the user asks for matches it, such as asking Claude to review a pull request here, Claude loads the skill's instructions and follows them. The user can also run it directly as `/my-plugin:review`:
55A [skill](/docs/en/skills.md) is a `SKILL.md` file. Save each skill in its own directory under `skills/`. Claude reads every skill's `description`, and when what the user asks for matches it, such as asking Claude to review a pull request here, Claude loads the skill's instructions and follows them. The user can also run it directly as `/my-plugin:review`:
5656 
5757```markdown theme={null}
5858---
from line 72
7272Summarize what this repository does in three sentences.
7373```
7474 
75A [subagent](/docs/en/sub-agents) is a separate assistant, with its own instructions and its own context window, that Claude can delegate a task to and get a result back from. Each Markdown file under `agents/` defines one: the frontmatter names it and says when to use it, and the body is its system prompt. This one is named `my-plugin:security-reviewer`, and the user can invoke it with `@agent-my-plugin:security-reviewer`:
75A [subagent](/docs/en/sub-agents.md) is a separate assistant, with its own instructions and its own context window, that Claude can delegate a task to and get a result back from. Each Markdown file under `agents/` defines one: the frontmatter names it and says when to use it, and the body is its system prompt. This one is named `my-plugin:security-reviewer`, and the user can invoke it with `@agent-my-plugin:security-reviewer`:
7676 
7777```markdown theme={null}
7878---
from line 84
8484You are a security reviewer. Read the changed files and report injection, authentication, and secrets-handling risks.
8585```
8686 
87A [hook](/docs/en/hooks-guide) runs something automatically at a point in Claude Code's lifecycle, such as after every file edit: a shell command, an HTTP request, an MCP tool call, a prompt to a model, or a subagent. Save the plugin's hooks in `hooks/hooks.json` at the plugin root. This one runs the plugin's `scripts/format.sh` after Claude writes or edits a file:
87A [hook](/docs/en/hooks-guide.md) runs something automatically at a point in Claude Code's lifecycle, such as after every file edit: a shell command, an HTTP request, an MCP tool call, a prompt to a model, or a subagent. Save the plugin's hooks in `hooks/hooks.json` at the plugin root. This one runs the plugin's `scripts/format.sh` after Claude writes or edits a file:
8888 
8989```json theme={null}
9090{
from line 116
116116]
117117```
118118 
119A plugin can include [output styles](/docs/en/output-styles), which change how Claude formats and phrases its replies. Save each output style as `output-styles/<name>.md`. This one appears in `/output-style` as `my-plugin:terse`:
119A plugin can include [output styles](/docs/en/output-styles.md), which change how Claude formats and phrases its replies. Save each output style as `output-styles/<name>.md`. This one appears in `/output-style` as `my-plugin:terse`:
120120 
121121```markdown theme={null}
122122---
from line 128
128128Keep every reply short. Skip preambles and summaries.
129129```
130130 
131A plugin can include [color themes](/docs/en/terminal-config#create-a-custom-theme) for the Claude Code interface. Save each theme as `themes/<slug>.json`. This one appears in `/theme` as `Dracula`, marked as from `my-plugin`:
131A plugin can include [color themes](/docs/en/terminal-config.md#create-a-custom-theme) for the Claude Code interface. Save each theme as `themes/<slug>.json`. This one appears in `/theme` as `Dracula`, marked as from `my-plugin`:
132132 
133133```json theme={null}
134134{
from line 141
141141}
142142```
143143 
144The `workflows/` folder holds [workflow](/docs/en/workflows) `.js` files: a `meta` block, then a script body that orchestrates several subagents. This one runs as `/my-plugin:audit-routes`:
144The `workflows/` folder holds [workflow](/docs/en/workflows.md) `.js` files: a `meta` block, then a script body that orchestrates several subagents. This one runs as `/my-plugin:audit-routes`:
145145 
146146```javascript theme={null}
147147export const meta = {
from line 174
174174npx prettier --write .
175175```
176176 
177A `settings.json` at the plugin root holds [settings](/docs/en/settings-reference) that apply while the plugin is enabled, so a plugin can change how the session behaves and not only add components. Only two keys take effect from a plugin, [`agent`](/docs/en/settings-reference#agent) and [`subagentStatusLine`](/docs/en/settings-reference#subagentstatusline); every other key is dropped. See [Default settings](#default-settings).
177A `settings.json` at the plugin root holds [settings](/docs/en/settings-reference.md) that apply while the plugin is enabled, so a plugin can change how the session behaves and not only add components. Only two keys take effect from a plugin, [`agent`](/docs/en/settings-reference#agent) and [`subagentStatusLine`](/docs/en/settings-reference#subagentstatusline); every other key is dropped. See [Default settings](#default-settings).
178178 
179179This one sets `agent`, which runs the session's main thread as the plugin's own `security-reviewer` agent, so that agent's system prompt, tool restrictions, and model apply to the whole session:
180180 
from line 184
184184}
185185```
186186 
187An [MCP server](/docs/en/mcp) gives Claude tools from an external system. Declare it in `.mcp.json` at the plugin root. This one starts a local server from a script inside the plugin, and appears in `/mcp` as `plugin:my-plugin:db`:
187An [MCP server](/docs/en/mcp.md) gives Claude tools from an external system. Declare it in `.mcp.json` at the plugin root. This one starts a local server from a script inside the plugin, and appears in `/mcp` as `plugin:my-plugin:db`:
188188 
189189```json theme={null}
190190{
from line 197
197197}
198198```
199199 
200An LSP server gives Claude [diagnostics and code navigation](/docs/en/plugins/code-intelligence) for a language. Declare the server in `.lsp.json` at the plugin root. This one connects the Go language server for `.go` files:
200An LSP server gives Claude [diagnostics and code navigation](/docs/en/plugins/code-intelligence.md) for a language. Declare the server in `.lsp.json` at the plugin root. This one connects the Go language server for `.go` files:
201201 
202202```json theme={null}
203203{
from line 217
217217 
218218### Skills
219219 
220A [skill](/docs/en/skills) is a `SKILL.md` file that Claude can load when its description matches the task. The user can also run it as a command. Save each skill in its own directory under `skills/`:
220A [skill](/docs/en/skills.md) is a `SKILL.md` file that Claude can load when its description matches the task. The user can also run it as a command. Save each skill in its own directory under `skills/`:
221221 
222222```text theme={null}
223223my-plugin/
from line 240
240240 
241241After you load the plugin, `/my-plugin:review` runs the skill. The command name and who can invoke it follow these rules:
242242 
243* **Command name**: `/<plugin>:<directory>`, so `skills/review/SKILL.md` in `my-plugin` is `/my-plugin:review`. If you set `name` in the frontmatter, it replaces the last segment and the plugin prefix stays. See [how a skill gets its command name](/docs/en/skills#how-a-skill-gets-its-command-name)
244* **Who invokes it**: Claude, the user, or both, controlled by frontmatter. See [Control who invokes a skill](/docs/en/skills#control-who-invokes-a-skill)
243* **Command name**: `/<plugin>:<directory>`, so `skills/review/SKILL.md` in `my-plugin` is `/my-plugin:review`. If you set `name` in the frontmatter, it replaces the last segment and the plugin prefix stays. See [how a skill gets its command name](/docs/en/skills.md#how-a-skill-gets-its-command-name)
244* **Who invokes it**: Claude, the user, or both, controlled by frontmatter. See [Control who invokes a skill](/docs/en/skills.md#control-who-invokes-a-skill)
245245 
246246You can also place skills outside the default `skills/` directory:
247247 
248248* **Additional directories**: list them in the `skills` manifest key. They add to the default `skills/` scan rather than replacing it, unlike `commands` and `agents`
249* **A single skill at the plugin root**: with no `skills/` directory and no `skills` manifest key, a `SKILL.md` at the plugin root loads as one skill. Set `name` in its frontmatter, because otherwise a marketplace install names the skill after its [cache directory](/docs/en/plugins/loading#find-plugins-on-disk) rather than your plugin
249* **A single skill at the plugin root**: with no `skills/` directory and no `skills` manifest key, a `SKILL.md` at the plugin root loads as one skill. Set `name` in its frontmatter, because otherwise a marketplace install names the skill after its [cache directory](/docs/en/plugins/loading.md#find-plugins-on-disk) rather than your plugin
250250 
251251To include instructions in a plugin, write them as a skill. Claude Code doesn't load a `CLAUDE.md` at the plugin root, and `claude plugin validate` warns `CLAUDE.md at the plugin root is not loaded as project context`.
252252 
253If a rule must hold every time, such as [blocking edits to protected files](/docs/en/hooks-guide#block-edits-to-protected-files), add it to the plugin as a [hook](#hooks) rather than a skill. To choose between the two, see the Hook vs Skill tab under [Compare similar features](/docs/en/features-overview#compare-similar-features).
253If a rule must hold every time, such as [blocking edits to protected files](/docs/en/hooks-guide.md#block-edits-to-protected-files), add it to the plugin as a [hook](#hooks) rather than a skill. To choose between the two, see the Hook vs Skill tab under [Compare similar features](/docs/en/features-overview.md#compare-similar-features).
254254 
255For frontmatter fields and supporting files, see [Skills](/docs/en/skills).
255For frontmatter fields and supporting files, see [Skills](/docs/en/skills.md).
256256 
257257### Commands
258258 
from line 290
290290 
291291### Agents
292292 
293A [subagent](/docs/en/sub-agents) is a separate assistant, with its own instructions and context window, that Claude can delegate a task to. Each Markdown file under `agents/` defines one:
293A [subagent](/docs/en/sub-agents.md) is a separate assistant, with its own instructions and context window, that Claude can delegate a task to. Each Markdown file under `agents/` defines one:
294294 
295295```markdown agents/security-reviewer.md theme={null}
296296---
from line 302
302302You are a security reviewer. Read the changed files and report injection, authentication, and secrets-handling risks.
303303```
304304 
305This agent is named `my-plugin:security-reviewer`, and the user can [invoke it explicitly](/docs/en/sub-agents#invoke-subagents-explicitly) with `@agent-my-plugin:security-reviewer`. The name form is `<plugin>:<name>`, where `<name>` comes from the frontmatter `name` field, or from the file name when that field is missing.
305This agent is named `my-plugin:security-reviewer`, and the user can [invoke it explicitly](/docs/en/sub-agents.md#invoke-subagents-explicitly) with `@agent-my-plugin:security-reviewer`. The name form is `<plugin>:<name>`, where `<name>` comes from the frontmatter `name` field, or from the file name when that field is missing.
306306 
307307The `agents` manifest key replaces the `agents/` scan.
308308 
309309#### Organize agents in subfolders
310310 
311You 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:
311You can put plugin agent files in subfolders of `agents/`. Claude Code [loads them recursively](/docs/en/sub-agents.md#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:
312312 
313313* Frontmatter `name`: it replaces only the file name, so `name: audit` in `agents/review/security.md` loads as `my-plugin:review:audit`
314314* Manifest [`agents`](/docs/en/plugins/manifest-reference#fields) field: a file you list there loads without subfolder names, so `"agents": "./custom/review/security.md"` loads as `my-plugin:security`
from line 317
317317 
318318A plugin agent's frontmatter follows these rules:
319319 
320* **Supported fields**: `name`, `description`, `model`, `effort`, `maxTurns`, `autoCompactWindow`, `tools`, `disallowedTools`, `skills`, `memory`, `background`, `omitClaudeMd`, `isolation`, `color`, and the `cacheTtl` key of `experimental`. The only valid `isolation` value is `"worktree"`. See [supported frontmatter fields](/docs/en/sub-agents#supported-frontmatter-fields) for what each one does
320* **Supported fields**: `name`, `description`, `model`, `effort`, `maxTurns`, `autoCompactWindow`, `tools`, `disallowedTools`, `skills`, `memory`, `background`, `omitClaudeMd`, `isolation`, `color`, and the `cacheTtl` key of `experimental`. The only valid `isolation` value is `"worktree"`. See [supported frontmatter fields](/docs/en/sub-agents.md#supported-frontmatter-fields) for what each one does
321321* **Ignored fields**: `permissionMode`, `hooks`, `mcpServers`, and `initialPrompt`. An agent file can't add hooks or MCP servers on its own, so add those as plugin [hooks](#hooks) and [MCP servers](#mcp-servers) instead
322322* **A `name` longer than 256 characters**: Claude Code ignores it and names the agent after its file, as it does when the field is missing
323323* **Frontmatter that doesn't parse**: the agent still loads with every field ignored. It's named after the file, and its description reads `Agent from my-plugin plugin`. Run [`claude plugin validate`](/docs/en/plugins/cli-reference#plugin-validate) in your shell to find these files
324324 
325For what each field does and the precedence rules, see [Subagents](/docs/en/sub-agents#supported-frontmatter-fields).
325For what each field does and the precedence rules, see [Subagents](/docs/en/sub-agents.md#supported-frontmatter-fields).
326326 
327327### Hooks
328328 
329A [hook](/docs/en/hooks-guide) runs something automatically at a point in Claude Code's lifecycle, such as after every file edit: a shell command, an HTTP request, an MCP tool call, a prompt to a model, or a subagent. Save the plugin's hooks in `hooks/hooks.json` at the plugin root, under a top-level `"hooks"` key, in the same shape as the `hooks` object in `settings.json`. That lets you copy an existing settings hook in unchanged.
329A [hook](/docs/en/hooks-guide.md) runs something automatically at a point in Claude Code's lifecycle, such as after every file edit: a shell command, an HTTP request, an MCP tool call, a prompt to a model, or a subagent. Save the plugin's hooks in `hooks/hooks.json` at the plugin root, under a top-level `"hooks"` key, in the same shape as the `hooks` object in `settings.json`. That lets you copy an existing settings hook in unchanged.
330330 
331331This hook runs a bundled script after every `Write` or `Edit`:
332332 
from line 350
350350 
351351Save the script at `scripts/format.sh` and make it executable.
352352 
353Load the plugin and ask Claude to edit a file. A `PostToolUse` hook that exits 0 shows nothing in the transcript, so confirm it ran with [debug logging](/docs/en/hooks#debug-hooks) or by what the script itself changes.
353Load the plugin and ask Claude to edit a file. A `PostToolUse` hook that exits 0 shows nothing in the transcript, so confirm it ran with [debug logging](/docs/en/hooks.md#debug-hooks) or by what the script itself changes.
354354 
355Hooks in `hooks/hooks.json` and in the `hooks` manifest key both load. For every event and its payload, see [Hook events](/docs/en/hooks#hook-events).
355Hooks in `hooks/hooks.json` and in the `hooks` manifest key both load. For every event and its payload, see [Hook events](/docs/en/hooks.md#hook-events).
356356 
357When another enabled plugin has the same name, one of the two registers its `hooks/hooks.json` hooks and the other's are left out. See [Hooks when two enabled plugins share a name](/docs/en/plugins/loading#hooks-when-two-enabled-plugins-share-a-name) for which one, and for the note in `/plugin` that tells you.
357When another enabled plugin has the same name, one of the two registers its `hooks/hooks.json` hooks and the other's are left out. See [Hooks when two enabled plugins share a name](/docs/en/plugins/loading.md#hooks-when-two-enabled-plugins-share-a-name) for which one, and for the note in `/plugin` that tells you.
358358 
359To write hooks as JavaScript functions that run inside Claude Code and can draw in its interface, list a module file under a `modules` key in the same `hooks/hooks.json`. A plugin with one is a mod. See [Create a mod](/docs/en/plugins/mods/create).
359To write hooks as JavaScript functions that run inside Claude Code and can draw in its interface, list a module file under a `modules` key in the same `hooks/hooks.json`. A plugin with one is a mod. See [Create a mod](/docs/en/plugins/mods/create.md).
360360 
361361#### When plugin hooks fire
362362 
363363A plugin's hooks don't wait for one of the plugin's skills or commands to be used. Claude Code registers them when a session loads the plugin, and they fire on their events from then on. To limit when a hook runs, narrow its `matcher`.
364364 
365If a hook never fires, see [hooks that don't fire](/docs/en/plugins/troubleshooting#failed-to-load-hooks-from-and-hooks-that-dont-fire).
365If a hook never fires, see [hooks that don't fire](/docs/en/plugins/troubleshooting.md#failed-to-load-hooks-from-and-hooks-that-dont-fire).
366366 
367367#### Environment, quoting, and matching MCP tools
368368 
from line 369
369369The hook's environment, the quoting of `${CLAUDE_PLUGIN_ROOT}`, and matchers for the plugin's own MCP tools work as follows:
370370 
371371* **Environment**: every hook process receives `CLAUDE_PLUGIN_ROOT` and `CLAUDE_PLUGIN_DATA` in its environment, plus `CLAUDE_PLUGIN_OPTION_<KEY>` for each [user configuration](#user-configuration) value, so your script can read them from there
372* **Quoting**: when `command` has no `args`, it runs through a shell, so wrap the `${CLAUDE_PLUGIN_ROOT}` path in double quotes, as the `hooks/hooks.json` example under [Hooks](#hooks) does, to keep the expanded path one shell word. When you pass `args` instead, each element is passed as one argument with no shell and needs no quoting. See [exec form and shell form](/docs/en/hooks#exec-form-and-shell-form)
373* **Matching the plugin's own MCP tools**: a tool from an [MCP server this plugin declares](#mcp-servers) is named `mcp__plugin_<plugin>_<server>__<tool>`, so write that full name in the matcher. A matcher on the server name alone never fires. See [Match MCP tools](/docs/en/hooks#match-mcp-tools)
372* **Quoting**: when `command` has no `args`, it runs through a shell, so wrap the `${CLAUDE_PLUGIN_ROOT}` path in double quotes, as the `hooks/hooks.json` example under [Hooks](#hooks) does, to keep the expanded path one shell word. When you pass `args` instead, each element is passed as one argument with no shell and needs no quoting. See [exec form and shell form](/docs/en/hooks.md#exec-form-and-shell-form)
373* **Matching the plugin's own MCP tools**: a tool from an [MCP server this plugin declares](#mcp-servers) is named `mcp__plugin_<plugin>_<server>__<tool>`, so write that full name in the matcher. A matcher on the server name alone never fires. See [Match MCP tools](/docs/en/hooks.md#match-mcp-tools)
374374 
375375### MCP servers
376376 
from line 393
393393 
394394`claude plugin validate` checks `.mcp.json` and reports a server entry that Claude Code would drop at load time as an error. Requires Claude Code v2.1.281 or later.
395395 
396For where a bad entry shows up at load time, see [MCP servers that don't start](/docs/en/plugins/troubleshooting#invalid-mcp-server-config-for-and-mcp-servers-that-dont-start).
396For where a bad entry shows up at load time, see [MCP servers that don't start](/docs/en/plugins/troubleshooting.md#invalid-mcp-server-config-for-and-mcp-servers-that-dont-start).
397397 
398398The `mcpServers` manifest key takes an inline server map, a path to a JSON file, or an array of those. When a manifest server has the same name as one in `.mcp.json`, the manifest server replaces it.
399399 
from line 406
406406The server's names, variable substitution, and reload behavior follow these rules:
407407 
408408* **Server name**: `plugin:<plugin>:<server>`, so the `db` server in `my-plugin` is `plugin:my-plugin:db` in `/mcp`. Use the same form to name the server in an [`mcp_tool` hook](/docs/en/hooks#mcp-tool-hook-fields)
409* **Tool names**: `mcp__plugin_<plugin>_<server>__<tool>`, so a `query` tool on that `db` server is `mcp__plugin_my-plugin_db__query`. That is the name to use in [permission rules](/docs/en/permissions) and [hook matchers](#hooks)
409* **Tool names**: `mcp__plugin_<plugin>_<server>__<tool>`, so a `query` tool on that `db` server is `mcp__plugin_my-plugin_db__query`. That is the name to use in [permission rules](/docs/en/permissions.md) and [hook matchers](#hooks)
410410* **Substitution**: `${CLAUDE_PLUGIN_ROOT}` and the other [path variables](#path-variables-and-persistent-data) are substituted in `command`, `args`, and `env`. No quoting is needed in `args`, because each element is passed as one argument
411* **Reload**: when the user runs `/reload-plugins` and [the reload applies](/docs/en/plugins/cli-reference#reloads-that-change-mcp-tools), a server whose configuration is unchanged keeps its connection. A server whose configuration changed reconnects, and one you removed disconnects
411* **Reload**: when the user runs `/reload-plugins` and [the reload applies](/docs/en/plugins/cli-reference.md#reloads-that-change-mcp-tools), a server whose configuration is unchanged keeps its connection. A server whose configuration changed reconnects, and one you removed disconnects
412412 
413413#### Include a packaged MCPB server
414414 
from line 430
430430* **In `/plugin`**: select the plugin on the **Installed** tab and choose **Configure**
431431* **At install, from the shell**: pass [`--config <server>.<key>=<value>`](/docs/en/plugins/cli-reference#plugin-install) to `claude plugin install`. Requires Claude Code v2.1.285 or later, and works only for a bundle packaged inside the plugin.
432432 
433For transports and authentication, see [MCP](/docs/en/mcp#plugin-provided-mcp-servers).
433For transports and authentication, see [MCP](/docs/en/mcp.md#plugin-provided-mcp-servers).
434434 
435435### LSP servers
436436 
437An LSP server gives Claude diagnostics and code navigation for a language. If an [official code intelligence plugin](/docs/en/plugins/code-intelligence) already covers your language, install that instead of writing one. Otherwise declare the server in `.lsp.json` at the plugin root:
437An LSP server gives Claude diagnostics and code navigation for a language. If an [official code intelligence plugin](/docs/en/plugins/code-intelligence.md) already covers your language, install that instead of writing one. Otherwise declare the server in `.lsp.json` at the plugin root:
438438 
439439```json .lsp.json theme={null}
440440{
from line 467
467467 
468468### Executables
469469 
470Files in `bin/` at the plugin root are on the `PATH` of the Bash tool's shell while the plugin is enabled, so Claude can run them as bare commands. A command that Claude runs with the [PowerShell tool](/docs/en/tools-reference#powershell-tool) outside the [sandbox](/docs/en/sandboxing) finds them on its `PATH` too, and a sandboxed PowerShell command doesn't. Add an executable script:
470Files in `bin/` at the plugin root are on the `PATH` of the Bash tool's shell while the plugin is enabled, so Claude can run them as bare commands. A command that Claude runs with the [PowerShell tool](/docs/en/tools-reference.md#powershell-tool) outside the [sandbox](/docs/en/sandboxing.md) finds them on its `PATH` too, and a sandboxed PowerShell command doesn't. Add an executable script:
471471 
472472```bash bin/hello-plugin theme={null}
473473#!/bin/bash
from line 502
502502* **User settings over plugin defaults**: across settings sources, plugin defaults are the lowest layer, so a user's own `agent` in `~/.claude/settings.json` overrides yours
503503* **Two plugins set the same key**: the value from the plugin loaded last applies, and `claude --debug` logs `overrides setting`
504504 
505For the `subagentStatusLine` shape, see [subagent status lines](/docs/en/statusline#subagent-status-lines).
505For the `subagentStatusLine` shape, see [subagent status lines](/docs/en/statusline.md#subagent-status-lines).
506506 
507507### Themes and output styles
508508 
from line 510
510510 
511511| Component | Save as | Format | Appears in | Manifest key |
512512| :- | :- | :- | :- | :- |
513| Theme | `themes/<slug>.json` | The [custom theme file](/docs/en/terminal-config#create-a-custom-theme) format users write in `~/.claude/themes/` | `/theme`, under the file's `name` | `experimental.themes` |
514| Output style | `output-styles/<name>.md` | The [custom output style](/docs/en/output-styles#create-a-custom-output-style) format, with `name` and `description` frontmatter | `/output-style`, as `<plugin>:<name>` | `outputStyles` |
513| Theme | `themes/<slug>.json` | The [custom theme file](/docs/en/terminal-config.md#create-a-custom-theme) format users write in `~/.claude/themes/` | `/theme`, under the file's `name` | `experimental.themes` |
514| Output style | `output-styles/<name>.md` | The [custom output style](/docs/en/output-styles.md#create-a-custom-output-style) format, with `name` and `description` frontmatter | `/output-style`, as `<plugin>:<name>` | `outputStyles` |
515515 
516516Plugin themes are read-only, so when a user edits one in `/theme`, the edit is saved as a copy in their own themes directory.
517517 
from line 530
530530 
531531### Channels
532532 
533A [channel](/docs/en/channels) lets an outside system such as a chat app send messages into a session. In a plugin, a channel is one of the MCP servers plus a `channels` entry that binds to it and can prompt for its own configuration. This manifest binds a channel to a `telegram` server and asks for a bot token:
533A [channel](/docs/en/channels.md) lets an outside system such as a chat app send messages into a session. In a plugin, a channel is one of the MCP servers plus a `channels` entry that binds to it and can prompt for its own configuration. This manifest binds a channel to a `telegram` server and asks for a bot token:
534534 
535535```json .claude-plugin/plugin.json theme={null}
536536{
from line 560
560560 
561561`server` must match a key in `mcpServers`. The per-channel `userConfig` takes the same shape as the [top-level `userConfig` key](#user-configuration).
562562 
563For what the server must implement and how users enable a channel plugin, see [Package as a plugin](/docs/en/channels-reference#package-as-a-plugin) in the channels reference. For the field table, see [`channels`](/docs/en/plugins/manifest-reference#channels).
563For what the server must implement and how users enable a channel plugin, see [Package as a plugin](/docs/en/channels-reference.md#package-as-a-plugin) in the channels reference. For the field table, see [`channels`](/docs/en/plugins/manifest-reference#channels).
564564 
565565### Monitors
566566 
from line 576
576576]
577577```
578578 
579The command runs in a shell, in the session's current working directory. It runs with your full user permissions and outside the [sandbox](/docs/en/sandboxing).
579The command runs in a shell, in the session's current working directory. It runs with your full user permissions and outside the [sandbox](/docs/en/sandboxing.md).
580580 
581581A monitor's command is limited in where it starts and what it can reference:
582582 
583* **Interactive sessions only**: plugin monitors start in an interactive session and never in non-interactive mode with the `-p` flag. They also don't start in sessions where the API provider or telemetry settings make the [Monitor tool](/docs/en/tools-reference#monitor-tool) unavailable
583* **Interactive sessions only**: plugin monitors start in an interactive session and never in non-interactive mode with the `-p` flag. They also don't start in sessions where the API provider or telemetry settings make the [Monitor tool](/docs/en/tools-reference.md#monitor-tool) unavailable
584584* **No user configuration**: `command` gets the [path variables](#path-variables-and-persistent-data) and `${ENV_VAR}` from the environment, but never `${user_config.*}`. A monitor that references one doesn't start, and monitor processes don't receive `CLAUDE_PLUGIN_OPTION_<KEY>` either
585585* **Disabling mid-session**: if you disable a plugin mid-session, Claude Code doesn't stop monitors that are already running. They stop when the session ends
586586 
from line 625
625625 
626626To open the same dialog at any time, the user runs `/plugin configure <plugin>@<marketplace>`.
627627 
628The VS Code extension's [Manage plugins dialog](/docs/en/vs-code#install-plugins) asks for unset options as a form after an install, and a gear icon on the plugin's row opens the form again with every option.
628The VS Code extension's [Manage plugins dialog](/docs/en/vs-code.md#install-plugins) asks for unset options as a form after an install, and a gear icon on the plugin's row opens the form again with every option.
629629 
630630The `claude plugin install` shell command never prompts for `userConfig` values. To set values from the shell, pass each one as `--config KEY=VALUE` when you install, or pipe a JSON object to [`claude plugin configure --values-stdin`](/docs/en/plugins/cli-reference#plugin-configure) afterward.
631631 
632632When options remain unset, `claude plugin install` prints a `userConfig options not yet set` line. For the line's exact text, see [The `userConfig` dialog never appears](/docs/en/plugins/troubleshooting#the-userconfig-dialog-never-appears).
633633 
634For the option fields, where each value is stored, how a component references a saved value, and which fields reject `${user_config.*}`, see [User configuration](/docs/en/plugins/manifest-reference#user-configuration).
634For the option fields, where each value is stored, how a component references a saved value, and which fields reject `${user_config.*}`, see [User configuration](/docs/en/plugins/manifest-reference.md#user-configuration).
635635 
636636## Reference plugin paths and store data
637637 
638638You don't know where your plugin will be installed, so refer to its files and data through these variables rather than fixed paths. They're substituted in skill, command, and agent content, in hook and monitor commands, and in MCP and LSP server configurations. They're also exported to hook, MCP, and LSP processes:
639639 
640* **`${CLAUDE_PLUGIN_ROOT}`**: the plugin's install directory. Each version has its own [cache directory](/docs/en/plugins/loading#find-plugins-on-disk), so the path changes when the plugin updates. Don't write state there
640* **`${CLAUDE_PLUGIN_ROOT}`**: the plugin's install directory. Each version has its own [cache directory](/docs/en/plugins/loading.md#find-plugins-on-disk), so the path changes when the plugin updates. Don't write state there
641641* **`${CLAUDE_PLUGIN_DATA}`**: a directory that survives updates, for `node_modules`, virtual environments, and caches. It resolves to `~/.claude/plugins/data/<id>/` and is created when first referenced
642642* **`${CLAUDE_PROJECT_DIR}`**: the project root, the same value hooks receive
643643 
from line 647
647647 
648648### Install dependencies into the data directory
649649 
650For a marketplace-installed plugin, Claude Code installs eligible [Node.js package dependencies](/docs/en/plugins/loading#node-js-package-dependencies) automatically when it caches the plugin, so you may not need to install them yourself. When you do, this `SessionStart` hook installs `node_modules` into `${CLAUDE_PLUGIN_DATA}` on first run and again after an update changes `package.json`:
650For a marketplace-installed plugin, Claude Code installs eligible [Node.js package dependencies](/docs/en/plugins/loading.md#node-js-package-dependencies) automatically when it caches the plugin, so you may not need to install them yourself. When you do, this `SessionStart` hook installs `node_modules` into `${CLAUDE_PLUGIN_DATA}` on first run and again after an update changes `package.json`:
651651 
652652```json hooks/hooks.json theme={null}
653653{
from line 666
666666}
667667```
668668 
669After the first session, `~/.claude/plugins/data/<id>/node_modules` exists. An MCP server can then set `NODE_PATH` to `${CLAUDE_PLUGIN_DATA}/node_modules` in its `env`. For which fields substitute which variable, see [Environment variables](/docs/en/plugins/manifest-reference#environment-variables).
669After the first session, `~/.claude/plugins/data/<id>/node_modules` exists. An MCP server can then set `NODE_PATH` to `${CLAUDE_PLUGIN_DATA}/node_modules` in its `env`. For which fields substitute which variable, see [Environment variables](/docs/en/plugins/manifest-reference.md#environment-variables).
670670 
671671## Next steps
672672 
673* [Plugin manifest reference](/docs/en/plugins/manifest-reference): `plugin.json` fields, path rules, and the standard layout
674* [Test plugins with evals](/docs/en/plugin-evals): check that the components you added change Claude's behavior the way you intend
675* [Publish and distribute a plugin](/docs/en/plugins/publish): version the plugin and put it in a marketplace
676* [Troubleshoot plugins](/docs/en/plugins/troubleshooting): what to do when a component doesn't load or a hook doesn't fire
673* [Plugin manifest reference](/docs/en/plugins/manifest-reference.md): `plugin.json` fields, path rules, and the standard layout
674* [Test plugins with evals](/docs/en/plugin-evals.md): check that the components you added change Claude's behavior the way you intend
675* [Publish and distribute a plugin](/docs/en/plugins/publish.md): version the plugin and put it in a marketplace
676* [Troubleshoot plugins](/docs/en/plugins/troubleshooting.md): what to do when a component doesn't load or a hook doesn't fire
677677 

plugins/create Changed · +41 / -41 lines

from line 10
1010>
1111> These cases are covered on other pages:
1212>
13> * **Installing someone else's plugin**: see [Install plugins](/docs/en/plugins/install)
14> * **Not sure you need a plugin**: see [Decide whether you need a plugin](/docs/en/plugins/overview#decide-whether-you-need-a-plugin) on the overview
13> * **Installing someone else's plugin**: see [Install plugins](/docs/en/plugins/install.md)
14> * **Not sure you need a plugin**: see [Decide whether you need a plugin](/docs/en/plugins/overview.md#decide-whether-you-need-a-plugin) on the overview
1515> * **Your plugin's users are on claude.ai or in Cowork**: the same folder installs there with a different subset of components. See [Plugin structure and testing](https://claude.com/docs/plugins/build) and the [component support table](https://claude.com/docs/plugins/platform-support#compare-component-support-by-app)
1616 
1717Start from the section that matches what you already have:
from line 32
3232 
3333## Create your first plugin
3434 
35In this walkthrough, you create a plugin whose only component is one skill, a greeting, and run it with `--plugin-dir`, which loads a plugin for one session without installing it. A plugin can hold any mix of [components](/docs/en/plugins/components), such as skills, agents, hooks, and MCP servers, and none is required; one skill is the smallest example that shows the layout.
35In this walkthrough, you create a plugin whose only component is one skill, a greeting, and run it with `--plugin-dir`, which loads a plugin for one session without installing it. A plugin can hold any mix of [components](/docs/en/plugins/components.md), such as skills, agents, hooks, and MCP servers, and none is required; one skill is the smallest example that shows the layout.
3636 
37You need Claude Code [installed and signed in](/docs/en/quickstart#step-1-install-claude-code).
37You need Claude Code [installed and signed in](/docs/en/quickstart.md#step-1-install-claude-code).
3838 
3939Open a terminal in the directory where you want to keep the plugin, such as `~/projects`, and run the commands in these steps from it. You can keep a plugin anywhere, because you pass its path to Claude Code when you start a session.
4040 
from line 48
4848 
4949**2. Write the manifest**
5050 
51The [manifest](/docs/en/plugins/manifest-reference) is a JSON file named `plugin.json` that tells Claude Code the plugin's name and describes it. Save this one as `my-first-plugin/.claude-plugin/plugin.json`:
51The [manifest](/docs/en/plugins/manifest-reference.md) is a JSON file named `plugin.json` that tells Claude Code the plugin's name and describes it. Save this one as `my-first-plugin/.claude-plugin/plugin.json`:
5252 
5353```json my-first-plugin/.claude-plugin/plugin.json theme={null}
5454{
from line 65
6565 
6666* **`name`**: required. It identifies the plugin and becomes the prefix on every skill and agent the plugin provides. Don't put spaces in it.
6767* **`description`**: the text users see for the plugin in `/plugin`.
68* **`version`**: optional. Setting it keeps users on that version until you change it; [Release a new version](/docs/en/plugins/host-marketplace#release-a-new-version) says when to set or omit it.
68* **`version`**: optional. Setting it keeps users on that version until you change it; [Release a new version](/docs/en/plugins/host-marketplace.md#release-a-new-version) says when to set or omit it.
6969* **`author`**: who to credit. `name` is required inside it; `email` and `url` are optional.
7070 
71Every other field is on the [manifest reference](/docs/en/plugins/manifest-reference#fields).
71Every other field is on the [manifest reference](/docs/en/plugins/manifest-reference.md#fields).
7272 
7373Only `plugin.json` goes inside `.claude-plugin/`. The skill you add next goes directly under `my-first-plugin/`, next to that folder.
7474 
from line 92
9292Greet the user warmly and ask how you can help them today.
9393```
9494 
95The `disable-model-invocation: true` line means Claude doesn't run the skill on its own. Remove that line from a skill you want Claude to run on its own. The skill's command combines the plugin name and the skill's name, so you run this one as `/my-first-plugin:hello`. For the other frontmatter fields, see the [skill frontmatter reference](/docs/en/skills#frontmatter-reference).
95The `disable-model-invocation: true` line means Claude doesn't run the skill on its own. Remove that line from a skill you want Claude to run on its own. The skill's command combines the plugin name and the skill's name, so you run this one as `/my-first-plugin:hello`. For the other frontmatter fields, see the [skill frontmatter reference](/docs/en/skills.md#frontmatter-reference).
9696 
9797**4. Validate the plugin**
9898 
from line 122
122122 
123123The plugin loads only in sessions you start with `--plugin-dir`. To keep working on it without the flag, or to test a `.zip` build, see [Develop without a marketplace](#develop-without-a-marketplace).
124124 
125To have Claude scaffold and check a larger plugin with you, [install](/docs/en/plugins/install#install-a-plugin) Anthropic's `plugin-dev` plugin from the `claude-plugins-official` marketplace, which adds skills and agents for writing components such as skills, hooks, and MCP servers and for validating the finished plugin. Once it's installed, run `/plugin-dev:create-plugin` followed by a description of the plugin you want, and Claude walks you through designing, creating, and validating it.
125To have Claude scaffold and check a larger plugin with you, [install](/docs/en/plugins/install.md#install-a-plugin) Anthropic's `plugin-dev` plugin from the `claude-plugins-official` marketplace, which adds skills and agents for writing components such as skills, hooks, and MCP servers and for validating the finished plugin. Once it's installed, run `/plugin-dev:create-plugin` followed by a description of the plugin you want, and Claude walks you through designing, creating, and validating it.
126126 
127127### Share your plugin
128128 
129129A plugin you built with [Create your first plugin](#create-your-first-plugin) exists only on your machine. When it's ready for other people, there are three ways to get it to them:
130130 
131* **Send it to a few people directly**: give them the plugin's directory or a `.zip` of it, and nothing needs to be published. See [Share a plugin without a marketplace](/docs/en/plugins/publish#share-a-plugin-without-a-marketplace).
132* **List it in your own marketplace**: teammates add your marketplace once and install the plugin by name, and they receive your updates. See [Publish through your own marketplace](/docs/en/plugins/publish#publish-through-your-own-marketplace).
133* **Submit it to Anthropic's directory**: after it passes review, people can add it on claude.ai and in Cowork, and it reaches Claude Code through their account. See [Submit to Anthropic's directory](/docs/en/plugins/publish#submit-to-anthropics-directory).
131* **Send it to a few people directly**: give them the plugin's directory or a `.zip` of it, and nothing needs to be published. See [Share a plugin without a marketplace](/docs/en/plugins/publish.md#share-a-plugin-without-a-marketplace).
132* **List it in your own marketplace**: teammates add your marketplace once and install the plugin by name, and they receive your updates. See [Publish through your own marketplace](/docs/en/plugins/publish.md#publish-through-your-own-marketplace).
133* **Submit it to Anthropic's directory**: after it passes review, people can add it on claude.ai and in Cowork, and it reaches Claude Code through their account. See [Submit to Anthropic's directory](/docs/en/plugins/publish.md#submit-to-anthropics-directory).
134134 
135135### Plugin layout
136136 
137Each kind of [component](/docs/en/plugins/components), such as skills, agents, hooks, and MCP servers, goes in a fixed directory under the plugin root, which is the directory you pass to `--plugin-dir`. Add only the directories you use. To click through a complete plugin directory and read what each file does, open the [plugin explorer](/docs/en/plugins/components#explore-the-plugin-directory).
137Each kind of [component](/docs/en/plugins/components.md), such as skills, agents, hooks, and MCP servers, goes in a fixed directory under the plugin root, which is the directory you pass to `--plugin-dir`. Add only the directories you use. To click through a complete plugin directory and read what each file does, open the [plugin explorer](/docs/en/plugins/components.md#explore-the-plugin-directory).
138138 
139The table lists the directories most plugins start with, and the [full layout](/docs/en/plugins/manifest-reference#standard-layout) lists the rest.
139The table lists the directories most plugins start with, and the [full layout](/docs/en/plugins/manifest-reference.md#standard-layout) lists the rest.
140140 
141141| Location | Contents |
142142| :- | :- |
from line 155
155155 
156156## Develop without a marketplace
157157 
158You don't need a [marketplace](/docs/en/plugins/overview#get-plugins-from-a-marketplace) to run a plugin you're writing. Load it directly from disk or a URL instead:
158You don't need a [marketplace](/docs/en/plugins/overview.md#get-plugins-from-a-marketplace) to run a plugin you're writing. Load it directly from disk or a URL instead:
159159 
160160* [`--plugin-dir`](#load-a-directory-or-archive-for-one-session): loads a directory or `.zip` archive for one session.
161161* [`--plugin-url`](#fetch-an-archive-from-a-url-for-one-session): fetches a `.zip` archive from a URL for one session.
162162* [`claude plugin init`](#scaffold-a-plugin-that-loads-every-session): scaffolds a plugin under `~/.claude/skills/` that loads across sessions.
163163 
164If two plugins loaded in different ways share a name, see [Name conflicts](/docs/en/plugins/loading#name-conflicts) for which one Claude Code keeps.
164If two plugins loaded in different ways share a name, see [Name conflicts](/docs/en/plugins/loading.md#name-conflicts) for which one Claude Code keeps.
165165 
166166### Load a plugin for one session
167167 
from line 188
188188* A subfolder you add loads as a new plugin once its manifest exists.
189189* When you remove a subfolder, its plugin unloads.
190190 
191A message appears in the session for each of these changes. If loading or unloading a plugin mid-conversation would [invalidate the prompt cache](/docs/en/prompt-caching#enabling-or-disabling-a-plugin), the change is held instead, and the message tells you to run `/reload-plugins` to apply it.
191A message appears in the session for each of these changes. If loading or unloading a plugin mid-conversation would [invalidate the prompt cache](/docs/en/prompt-caching.md#enabling-or-disabling-a-plugin), the change is held instead, and the message tells you to run `/reload-plugins` to apply it.
192192 
193193#### Load a plugin from a URL
194194 
from line 206
206206 
207207#### Load plugins from an environment variable
208208 
209To load plugins in a session where you can't add the `--plugin-dir` flag, list their absolute paths in the [`CLAUDE_CODE_PLUGIN_DIRS`](/docs/en/env-vars#variables) environment variable instead. Claude Code loads each path as it loads a `--plugin-dir` path. These plugins load in addition to any you pass with `--plugin-dir`. [Project and local settings can't set this variable](/docs/en/settings-reference#variables-claude-code-ignores-in-env). `CLAUDE_CODE_PLUGIN_DIRS` requires Claude Code v2.1.280 or later.
209To load plugins in a session where you can't add the `--plugin-dir` flag, list their absolute paths in the [`CLAUDE_CODE_PLUGIN_DIRS`](/docs/en/env-vars#variables) environment variable instead. Claude Code loads each path as it loads a `--plugin-dir` path. These plugins load in addition to any you pass with `--plugin-dir`. [Project and local settings can't set this variable](/docs/en/settings-reference.md#variables-claude-code-ignores-in-env). `CLAUDE_CODE_PLUGIN_DIRS` requires Claude Code v2.1.280 or later.
210210 
211Managed settings can turn off `--plugin-dir` and `CLAUDE_CODE_PLUGIN_DIRS`. See [Flags that load a plugin for one session](/docs/en/plugins/cli-reference#flags-that-load-a-plugin-for-one-session). To test a plugin together with a plugin it depends on, see [Test a plugin and its dependency locally](/docs/en/plugins/dependencies#test-a-plugin-and-its-dependency-locally).
211Managed settings can turn off `--plugin-dir` and `CLAUDE_CODE_PLUGIN_DIRS`. See [Flags that load a plugin for one session](/docs/en/plugins/cli-reference.md#flags-that-load-a-plugin-for-one-session). To test a plugin together with a plugin it depends on, see [Test a plugin and its dependency locally](/docs/en/plugins/dependencies.md#test-a-plugin-and-its-dependency-locally).
212212 
213213### Make a plugin load in every session
214214 
215Your personal skills directory is `~/.claude/skills/`, and a folder there that contains a `.claude-plugin/plugin.json` is a skills-directory plugin. Unless your administrator has [blocked skills-directory plugins](/docs/en/plugins/loading#skills-directory-plugins-blocked-by-managed-settings), Claude Code loads each one when a session starts, with no flag and no install step. `claude plugin init` scaffolds one for you.
215Your personal skills directory is `~/.claude/skills/`, and a folder there that contains a `.claude-plugin/plugin.json` is a skills-directory plugin. Unless your administrator has [blocked skills-directory plugins](/docs/en/plugins/loading.md#skills-directory-plugins-blocked-by-managed-settings), Claude Code loads each one when a session starts, with no flag and no install step. `claude plugin init` scaffolds one for you.
216216 
217217#### Scaffold the plugin with `claude plugin init`
218218 
from line 224
224224 
225225The command creates `~/.claude/skills/my-tool/` with a `.claude-plugin/plugin.json` and a root `SKILL.md`. It prints `✔ Created plugin "my-tool" at ~/.claude/skills/my-tool` followed by `It will auto-load next session as my-tool@skills-dir. Run /reload-plugins to load it now.`
226226 
227Pass `--with skills` to have `claude plugin init` scaffold a skill under `skills/` for you. The other `--with` values are on the [plugin commands reference](/docs/en/plugins/cli-reference#plugin-init).
227Pass `--with skills` to have `claude plugin init` scaffold a skill under `skills/` for you. The other `--with` values are on the [plugin commands reference](/docs/en/plugins/cli-reference.md#plugin-init).
228228 
229229#### Name the plugin's skills
230230 
from line 236
236236 
237237#### Share the plugin through a repository
238238 
239`claude plugin init` writes the plugin to your personal skills directory at `~/.claude/skills/`, which all your projects on this machine share. To make a plugin load for everyone in one repository, create the same layout yourself at `<project>/.claude/skills/<name>/`, including its `.claude-plugin/plugin.json`. See [Plugins shared through a repository](/docs/en/plugins/loading#plugins-shared-through-a-repository) for the conditions under which Claude Code loads it.
239`claude plugin init` writes the plugin to your personal skills directory at `~/.claude/skills/`, which all your projects on this machine share. To make a plugin load for everyone in one repository, create the same layout yourself at `<project>/.claude/skills/<name>/`, including its `.claude-plugin/plugin.json`. See [Plugins shared through a repository](/docs/en/plugins/loading.md#plugins-shared-through-a-repository) for the conditions under which Claude Code loads it.
240240 
241241## Test and debug
242242 
243243When a change to your plugin doesn't show up, work through these checks in order. Each one tells you what Claude Code did with the plugin:
244244 
2451. In your shell, run `claude plugin validate <path>`. It checks the manifest and the frontmatter of every skill, agent, and command file, and exits `0` on `Validation passed`. Add `--strict` to fail on warnings too. Exit codes and directory handling are on the [plugin commands reference](/docs/en/plugins/cli-reference#plugin-validate).
2451. In your shell, run `claude plugin validate <path>`. It checks the manifest and the frontmatter of every skill, agent, and command file, and exits `0` on `Validation passed`. Add `--strict` to fail on warnings too. Exit codes and directory handling are on the [plugin commands reference](/docs/en/plugins/cli-reference.md#plugin-validate).
2462462. In the running session, run `/reload-plugins` to apply edits you made on disk. It prints one `Reloaded:` line with counts. Then confirm a skill loaded by typing its `/plugin-name:skill` command, or by finding the plugin in the `/plugin` **Installed** tab.
2472473. In the same session, run `/plugin`. The **Installed** tab lists your plugin and, in the plugin's details, the components Claude Code found. The **Errors** tab lists what failed to load and why, such as a path in your manifest that doesn't exist.
2482484. Back in your shell, run `claude plugin list`. It prints session-only and skills-directory plugins in their own sections with `Status: ✔ loaded` or the load error. To include the plugin you're developing, pass `--plugin-dir` with its path before `plugin list`.
2495. If your plugin is in a skills directory and `claude plugin list` doesn't print it, with no error there or in `/plugin`, see [Skills-directory plugins blocked by managed settings](/docs/en/plugins/loading#skills-directory-plugins-blocked-by-managed-settings).
2495. If your plugin is in a skills directory and `claude plugin list` doesn't print it, with no error there or in `/plugin`, see [Skills-directory plugins blocked by managed settings](/docs/en/plugins/loading.md#skills-directory-plugins-blocked-by-managed-settings).
250250 
251To check an MCP server, run `/mcp` in the session to see the server's status. When the server is healthy, `/mcp` lists it as connected. If it isn't, see [MCP servers that don't start](/docs/en/plugins/troubleshooting#invalid-mcp-server-config-for-and-mcp-servers-that-dont-start).
251To check an MCP server, run `/mcp` in the session to see the server's status. When the server is healthy, `/mcp` lists it as connected. If it isn't, see [MCP servers that don't start](/docs/en/plugins/troubleshooting.md#invalid-mcp-server-config-for-and-mcp-servers-that-dont-start).
252252 
253To check a hook, trigger the event it matches. For example, ask Claude to edit a file to trigger a `PostToolUse` hook. Then read the [debug log](/docs/en/hooks#debug-hooks), which shows which hooks matched, their exit codes, and their output.
253To check a hook, trigger the event it matches. For example, ask Claude to edit a file to trigger a `PostToolUse` hook. Then read the [debug log](/docs/en/hooks.md#debug-hooks), which shows which hooks matched, their exit codes, and their output.
254254 
255The next sections cover the failures you're most likely to hit while developing, and the [troubleshooting page](/docs/en/plugins/troubleshooting#build-a-plugin) has the full entry for each.
255The next sections cover the failures you're most likely to hit while developing, and the [troubleshooting page](/docs/en/plugins/troubleshooting.md#build-a-plugin) has the full entry for each.
256256 
257257### A component path isn't found
258258 
from line 260
260260 
261261### `--plugin-dir` at a marketplace root doesn't load the plugins under `plugins/`
262262 
263`--plugin-dir` takes the plugin's root directory, the one that contains `.claude-plugin/plugin.json` and the component directories such as `skills/`. If you point it at a marketplace root instead, Claude Code doesn't read `marketplace.json`, so a plugin under `plugins/` doesn't load, and you see no error. Point the flag at one plugin's folder, or add the marketplace. See [the troubleshooting entry](/docs/en/plugins/troubleshooting#plugin-dir-loads-a-plugin-with-no-components).
263`--plugin-dir` takes the plugin's root directory, the one that contains `.claude-plugin/plugin.json` and the component directories such as `skills/`. If you point it at a marketplace root instead, Claude Code doesn't read `marketplace.json`, so a plugin under `plugins/` doesn't load, and you see no error. Point the flag at one plugin's folder, or add the marketplace. See [the troubleshooting entry](/docs/en/plugins/troubleshooting.md#plugin-dir-loads-a-plugin-with-no-components).
264264 
265265### The plugin loads but its skills are missing
266266 
267The `skills/` directory is inside `.claude-plugin/`, or a `skills` entry in the manifest points at a file. Move `skills/` to the plugin root, point each `skills` entry at a directory that contains `SKILL.md`, and run `/reload-plugins` in the session. See [Plugin loads but its skills are missing](/docs/en/plugins/troubleshooting#plugin-loads-but-its-skills-are-missing).
267The `skills/` directory is inside `.claude-plugin/`, or a `skills` entry in the manifest points at a file. Move `skills/` to the plugin root, point each `skills` entry at a directory that contains `SKILL.md`, and run `/reload-plugins` in the session. See [Plugin loads but its skills are missing](/docs/en/plugins/troubleshooting.md#plugin-loads-but-its-skills-are-missing).
268268 
269269### The `userConfig` dialog never appears
270270 
from line 272
272272 
273273### Check that the plugin changes Claude's behavior
274274 
275A plugin that loads without errors can still fail to steer Claude the way you intend. `claude plugin eval`, which you run in your shell, runs your test cases with and without the plugin and scores the difference. See [Test plugins with evals](/docs/en/plugin-evals), starting with [Create your first eval suite](/docs/en/plugin-evals#create-your-first-eval-suite).
275A plugin that loads without errors can still fail to steer Claude the way you intend. `claude plugin eval`, which you run in your shell, runs your test cases with and without the plugin and scores the difference. See [Test plugins with evals](/docs/en/plugin-evals.md), starting with [Create your first eval suite](/docs/en/plugin-evals.md#create-your-first-eval-suite).
276276 
277277## Convert an existing `.claude/` setup
278278 
from line 366
366366 
367367## Next steps
368368 
369* [Plugin components](/docs/en/plugins/components): add agents, hooks, MCP servers, LSP servers, and user configuration to your plugin
370* [Test plugins with evals](/docs/en/plugin-evals): write eval cases and run them with `claude plugin eval` to check how reliably the plugin guides Claude's behavior
371* [Publish a plugin](/docs/en/plugins/publish): version it, put it in a marketplace, and submit it for review
369* [Plugin components](/docs/en/plugins/components.md): add agents, hooks, MCP servers, LSP servers, and user configuration to your plugin
370* [Test plugins with evals](/docs/en/plugin-evals.md): write eval cases and run them with `claude plugin eval` to check how reliably the plugin guides Claude's behavior
371* [Publish a plugin](/docs/en/plugins/publish.md): version it, put it in a marketplace, and submit it for review
372372* [Plugin structure and testing](https://claude.com/docs/plugins/build): the same plugin folder installs on claude.ai and in Cowork. Some components are Claude Code-only, and the [component support table](https://claude.com/docs/plugins/platform-support#compare-component-support-by-app) lists which load on each surface
373* [Plugin manifest reference](/docs/en/plugins/manifest-reference): every `plugin.json` field, path rule, and directory
374* [Skills](/docs/en/skills): write the skills your plugin provides
373* [Plugin manifest reference](/docs/en/plugins/manifest-reference.md): every `plugin.json` field, path rule, and directory
374* [Skills](/docs/en/skills.md): write the skills your plugin provides
375375* [Anthropic's plugins in the claude-code repository](https://github.com/anthropics/claude-code/tree/main/plugins): complete worked examples of the layout on this page, such as `feature-dev` and `code-review`
376376 

plugins/create-marketplace Changed · +19 / -19 lines

from line 4
44 
55A plugin marketplace is a directory or repository with a `.claude-plugin/marketplace.json` file that lists your plugins and where to fetch each one. You push the directory to a git host, and anyone with access registers it in Claude Code with one command and installs your plugins from it.
66 
7Create your own marketplace when you want a group you choose, such as your team or your organization, to install your plugins and keep receiving your updates from a catalog you control. The repository can be private, it can list as many plugins as you like, and an administrator can [require it on every machine](/docs/en/plugins/org).
7Create your own marketplace when you want a group you choose, such as your team or your organization, to install your plugins and keep receiving your updates from a catalog you control. The repository can be private, it can list as many plugins as you like, and an administrator can [require it on every machine](/docs/en/plugins/org.md).
88 
99> [!NOTE]
1010>
1111> These cases are covered on other pages:
1212>
13> * **Sharing one plugin with a few people**: send them the plugin's directory or a `.zip` of it. See [Share a plugin without a marketplace](/docs/en/plugins/publish#share-a-plugin-without-a-marketplace).
14> * **Offering a plugin to everyone**: submit it to Anthropic's directory. See [Submit to Anthropic's directory](/docs/en/plugins/publish#submit-to-anthropics-directory).
15> * **Using a plugin yourself**: load it with `--plugin-dir` or save it in your skills directory. See [Develop without a marketplace](/docs/en/plugins/create#develop-without-a-marketplace).
13> * **Sharing one plugin with a few people**: send them the plugin's directory or a `.zip` of it. See [Share a plugin without a marketplace](/docs/en/plugins/publish.md#share-a-plugin-without-a-marketplace).
14> * **Offering a plugin to everyone**: submit it to Anthropic's directory. See [Submit to Anthropic's directory](/docs/en/plugins/publish.md#submit-to-anthropics-directory).
15> * **Using a plugin yourself**: load it with `--plugin-dir` or save it in your skills directory. See [Develop without a marketplace](/docs/en/plugins/create.md#develop-without-a-marketplace).
1616 
1717Start with [Create a marketplace](#create-a-marketplace) to build one on your own machine and install a plugin from it, then [add more plugin entries](#add-plugin-entries).
1818 
from line 20
2020 
2121The following steps create a marketplace on your machine, add a plugin to it, register it in Claude Code, and install the plugin from it. That is the whole loop, and it's the same loop your users go through once you host the marketplace somewhere they can reach. Run every command in your shell, from the directory where you want `my-marketplace/` created.
2222 
23You need a plugin to list. The example uses `my-first-plugin` from [Create your first plugin](/docs/en/plugins/create#create-your-first-plugin), a plugin with one skill that you run as `/my-first-plugin:hello`; build it first if you don't have a plugin yet. To use a plugin of your own instead, substitute its directory and its `name` wherever the steps say `my-first-plugin`. For what a plugin directory can contain, see the [plugin directory explorer](/docs/en/plugins/components#explore-the-plugin-directory).
23You need a plugin to list. The example uses `my-first-plugin` from [Create your first plugin](/docs/en/plugins/create.md#create-your-first-plugin), a plugin with one skill that you run as `/my-first-plugin:hello`; build it first if you don't have a plugin yet. To use a plugin of your own instead, substitute its directory and its `name` wherever the steps say `my-first-plugin`. For what a plugin directory can contain, see the [plugin directory explorer](/docs/en/plugins/components.md#explore-the-plugin-directory).
2424 
2525**1. Set up the marketplace directory**
2626 
from line 90
9090 
9191The command prints `✔ Successfully installed plugin: my-first-plugin@my-marketplace (scope: user)`.
9292 
93Inside a session, `/plugin marketplace add ./my-marketplace` registers the marketplace the same way. `/plugin install my-first-plugin@my-marketplace` opens the plugin's details in the `/plugin` panel, where you install it. For that flow, see [Install and manage plugins](/docs/en/plugins/install).
93Inside a session, `/plugin marketplace add ./my-marketplace` registers the marketplace the same way. `/plugin install my-first-plugin@my-marketplace` opens the plugin's details in the `/plugin` panel, where you install it. For that flow, see [Install and manage plugins](/docs/en/plugins/install.md).
9494 
9595**5. Confirm the plugin loaded**
9696 
from line 116
116116 
117117Every plugin you distribute is one object in the `plugins` array of `marketplace.json`. To add a second plugin, add a second object. These fields cover most entries:
118118 
119* `name`: the identifier people type before `@` when they install. [Plugin entries](/docs/en/plugins/marketplace-reference#plugin-entries) gives the characters a name can use.
119* `name`: the identifier people type before `@` when they install. [Plugin entries](/docs/en/plugins/marketplace-reference.md#plugin-entries) gives the characters a name can use.
120120* `source`: where Claude Code fetches the plugin from. Write a relative path string for a plugin inside the marketplace directory, as in [the walkthrough](#create-a-marketplace), or a source object for a plugin outside it. See [Choose a plugin source](#choose-a-plugin-source).
121121* `description`: the line people see next to the plugin when they browse your marketplace in `/plugin`.
122122 
123For the full field list, see [Plugin entries](/docs/en/plugins/marketplace-reference#plugin-entries), which also covers the [`plugin.json`](/docs/en/plugins/manifest-reference) fields an entry can set and when they apply.
123For the full field list, see [Plugin entries](/docs/en/plugins/marketplace-reference.md#plugin-entries), which also covers the [`plugin.json`](/docs/en/plugins/manifest-reference) fields an entry can set and when they apply.
124124 
125125## Rules for plugin entries
126126 
from line 142
142142* **Entry name**: the install id, `<entry-name>@<marketplace>`. It's what people type to install, what `claude plugin list` shows, and the key Claude Code writes under [`enabledPlugins`](/docs/en/settings-reference#enabledplugins) in their settings file.
143143* **Manifest name**: the prefix on the plugin's skills, and the name `claude plugin details` takes.
144144 
145When the two names differ and someone installs by the manifest name, Claude Code reports `Plugin "<manifest-name>" not found in marketplace "<marketplace>"`. Keep the two names the same. For more on how Claude Code uses the two names, see [Plugin loading reference](/docs/en/plugins/loading#find-where-a-plugin-came-from).
145When the two names differ and someone installs by the manifest name, Claude Code reports `Plugin "<manifest-name>" not found in marketplace "<marketplace>"`. Keep the two names the same. For more on how Claude Code uses the two names, see [Plugin loading reference](/docs/en/plugins/loading.md#find-where-a-plugin-came-from).
146146 
147147## Choose a plugin source
148148 
from line 163
163163* `npm`: an npm package
164164* `command`: a directory produced by running a command on the machine where the plugin is installed
165165 
166For the fields of every source type, and for pinning a git-based source to a `ref` or `sha`, see [Plugin sources](/docs/en/plugins/marketplace-reference#plugin-sources).
166For the fields of every source type, and for pinning a git-based source to a `ref` or `sha`, see [Plugin sources](/docs/en/plugins/marketplace-reference.md#plugin-sources).
167167 
168168## Validate and test
169169 
from line 175
175175 
176176* JSON syntax errors, as `json: Invalid JSON syntax: <reason>`
177177* Missing required fields, such as `owner: Invalid input`
178* A marketplace or plugin name that breaks the naming rules in the [marketplace reference](/docs/en/plugins/marketplace-reference#top-level-fields)
178* A marketplace or plugin name that breaks the naming rules in the [marketplace reference](/docs/en/plugins/marketplace-reference.md#top-level-fields)
179179* A relative `source` that contains `..`
180180* Unknown fields at the top level or in a plugin entry, as warnings
181181* Problems in the `plugin.json` of each relative-path plugin, as `plugins[N] plugin.json → <field>: <message>`
182182 
183For every message `validate` can print, see [Validation messages](/docs/en/plugins/marketplace-reference#validation-messages). For its flags and exit codes, see [`plugin validate`](/docs/en/plugins/cli-reference#plugin-validate).
183For every message `validate` can print, see [Validation messages](/docs/en/plugins/marketplace-reference.md#validation-messages). For its flags and exit codes, see [`plugin validate`](/docs/en/plugins/cli-reference#plugin-validate).
184184 
185185### Problems that surface when you add or install
186186 
187187Problems that `claude plugin validate` doesn't report appear when you add the marketplace or install from it:
188188 
189* **When you add the marketplace**: the exact [official marketplace names](/docs/en/plugins/marketplace-reference#reserved-names), such as `claude-plugins-official`, pass validation. When you add a marketplace with one of those names, Claude Code refuses it with a message that starts `The name '<name>' is reserved for official Anthropic marketplaces`.
189* **When you add the marketplace**: the exact [official marketplace names](/docs/en/plugins/marketplace-reference.md#reserved-names), such as `claude-plugins-official`, pass validation. When you add a marketplace with one of those names, Claude Code refuses it with a message that starts `The name '<name>' is reserved for official Anthropic marketplaces`.
190190* **When you install a plugin**:
191191 * Claude Code first fetches a `github`, `git-subdir`, or other remote source when you install the plugin, so a wrong `repo` or `path` appears then.
192192 * A relative `source` whose directory doesn't exist also fails at install, with `Source path does not exist: <path>`.
from line 195
195195 
196196In [the walkthrough](#create-a-marketplace), you added `my-marketplace` from a local directory with a relative-path `source`. With that setup, Claude Code reads the plugin's files directly from `my-marketplace/plugins/`. Your edits take effect at the next session start or when you run `/reload-plugins` in a session, with no change to the plugin's `version`.
197197 
198People who install from your hosted marketplace get a copy in the plugin cache instead. For how they receive a new version, see [Keep users up to date](/docs/en/plugins/host-marketplace#keep-users-up-to-date).
198People who install from your hosted marketplace get a copy in the plugin cache instead. For how they receive a new version, see [Keep users up to date](/docs/en/plugins/host-marketplace.md#keep-users-up-to-date).
199199 
200200### Remove the marketplace to start over
201201 
from line 207
207207 
208208Your teammates then run `claude plugin marketplace add <owner>/<repo>` in their shell for a GitHub repository, or the same command with the repository URL. They then install a plugin by name as in [the walkthrough](#create-a-marketplace).
209209 
210For private-repository access, updates, versioning, and renaming or removing entries, see [Host and maintain a marketplace](/docs/en/plugins/host-marketplace).
210For private-repository access, updates, versioning, and renaming or removing entries, see [Host and maintain a marketplace](/docs/en/plugins/host-marketplace.md).
211211 
212212## Next steps
213213 
214* [Host and maintain a marketplace](/docs/en/plugins/host-marketplace): pick a host, keep users up to date, and rename or remove plugins safely
215* [Marketplace reference](/docs/en/plugins/marketplace-reference): `marketplace.json` fields and source types
216* [Manage plugins for your organization](/docs/en/plugins/org): require your marketplace and its plugins on every machine
217* [Suggest plugins by relevance](/docs/en/plugins/relevance): have Claude Code suggest a plugin from your marketplace when a session matches
214* [Host and maintain a marketplace](/docs/en/plugins/host-marketplace.md): pick a host, keep users up to date, and rename or remove plugins safely
215* [Marketplace reference](/docs/en/plugins/marketplace-reference.md): `marketplace.json` fields and source types
216* [Manage plugins for your organization](/docs/en/plugins/org.md): require your marketplace and its plugins on every machine
217* [Suggest plugins by relevance](/docs/en/plugins/relevance.md): have Claude Code suggest a plugin from your marketplace when a session matches
218218 

plugins/dependencies Changed · +13 / -13 lines

from line 10
1010>
1111> These cases are covered on other pages:
1212>
13> * **Installing a plugin that has dependencies**: see [Manage installed plugins](/docs/en/plugins/install#manage-installed-plugins)
14> * **Reading a dependency error**: see [Dependency errors](/docs/en/plugins/troubleshooting#dependency-errors)
15> * **Declaring the npm and Bun packages that your plugin's own code needs**: see [Node.js package dependencies](/docs/en/plugins/loading#node-js-package-dependencies)
13> * **Installing a plugin that has dependencies**: see [Manage installed plugins](/docs/en/plugins/install.md#manage-installed-plugins)
14> * **Reading a dependency error**: see [Dependency errors](/docs/en/plugins/troubleshooting.md#dependency-errors)
15> * **Declaring the npm and Bun packages that your plugin's own code needs**: see [Node.js package dependencies](/docs/en/plugins/loading.md#node-js-package-dependencies)
1616 
1717To add a constraint, start at [Declare a dependency with a version constraint](#declare-a-dependency-with-a-version-constraint). If you maintain a plugin that others depend on, [tag your releases](#tag-plugin-releases-for-version-resolution) so their constraints can resolve.
1818 
from line 69
6969}
7070```
7171 
72To add a plugin to the standard set later, publish a new `backend-standard` version with the extra dependency. When the marketplace doesn't [auto-update by default](/docs/en/plugins/loading#which-marketplaces-and-plugins-auto-update), engineers either turn on auto-update for the marketplace or update manually:
72To add a plugin to the standard set later, publish a new `backend-standard` version with the extra dependency. When the marketplace doesn't [auto-update by default](/docs/en/plugins/loading.md#which-marketplaces-and-plugins-auto-update), engineers either turn on auto-update for the marketplace or update manually:
7373 
7474* **Turn on auto-update for the marketplace**: the next auto-update moves the bundle to the new version and installs any dependencies it adds.
7575* **Update manually**: run `claude plugin update backend-standard` in a shell, then `/reload-plugins` in an open session to install the newly added dependencies.
7676 
77For the engineer-side steps, see [Keep plugins updated](/docs/en/plugins/install#keep-plugins-updated).
77For the engineer-side steps, see [Keep plugins updated](/docs/en/plugins/install.md#keep-plugins-updated).
7878 
79To deploy a bundle to everyone in an organization, an administrator adds it to `enabledPlugins` in managed settings. See [Pre-install and require plugins](/docs/en/plugins/org#pre-install-and-require-plugins).
79To deploy a bundle to everyone in an organization, an administrator adds it to `enabledPlugins` in managed settings. See [Pre-install and require plugins](/docs/en/plugins/org.md#pre-install-and-require-plugins).
8080 
8181### Depend on a plugin from another marketplace
8282 
from line 129
129129 
130130## Release a plugin that others depend on
131131 
132If you maintain a plugin that other plugins depend on with a version constraint, tag its releases so those constraints can resolve. A constraint resolves against git tags on the repository that hosts the plugin. Tag the repository that the plugin's [plugin source](/docs/en/plugins/marketplace-reference#plugin-sources) in `marketplace.json` points at:
132If you maintain a plugin that other plugins depend on with a version constraint, tag its releases so those constraints can resolve. A constraint resolves against git tags on the repository that hosts the plugin. Tag the repository that the plugin's [plugin source](/docs/en/plugins/marketplace-reference.md#plugin-sources) in `marketplace.json` points at:
133133 
134134* **`github`, `url`, or `git-subdir` source**: the plugin's own repository, so the plugin's author creates the tags
135135* **Relative path such as `./plugins/secrets-vault`**: the marketplace repository, so the marketplace maintainer creates the tags
from line 161
161161 
162162### Constrain a dependency that has a non-git source
163163 
164Tag-based resolution applies only to git-backed sources. For a dependency with an `npm`, `archive`, or `command` [plugin source](/docs/en/plugins/marketplace-reference#plugin-sources), the constraint doesn't control which version is fetched. It's still checked when the plugin loads, and the dependent plugin is disabled if the installed version doesn't satisfy it.
164Tag-based resolution applies only to git-backed sources. For a dependency with an `npm`, `archive`, or `command` [plugin source](/docs/en/plugins/marketplace-reference.md#plugin-sources), the constraint doesn't control which version is fetched. It's still checked when the plugin loads, and the dependent plugin is disabled if the installed version doesn't satisfy it.
165165 
166166For `npm`, `archive`, and `command` sources, the version checked is the `version` in the dependency's `plugin.json`. Set one there before you constrain that dependency, because a `plugin.json` that sets no version satisfies no constraint.
167167 
168Claude Code never installs a dependency with a `command` source itself, so users [install it first](/docs/en/plugins/marketplace-reference#command-plugin-source). It also never runs a dependency's [`headersHelper`](/docs/en/plugins/host-marketplace#authenticate-archive-downloads), so users also install a dependency whose marketplace entry sets one before they install your plugin.
168Claude Code never installs a dependency with a `command` source itself, so users [install it first](/docs/en/plugins/marketplace-reference.md#command-plugin-source). It also never runs a dependency's [`headersHelper`](/docs/en/plugins/host-marketplace#authenticate-archive-downloads), so users also install a dependency whose marketplace entry sets one before they install your plugin.
169169 
170170Besides `claude plugin install`, these operations also install any missing declared dependency, and the `command` and `headersHelper` limits apply to them too:
171171 
from line 193
193193 
194194Constraint checks use the tag's version rather than the `version` in `plugin.json`, even if `plugin.json` at that commit lags behind.
195195 
196If you force-move a tag to a different commit, the next install fetches that commit's content instead of reusing a stale cached copy. See [Versions and updates](/docs/en/plugins/loading#versions-and-updates) for how a plugin's version becomes its cache key.
196If you force-move a tag to a different commit, the next install fetches that commit's content instead of reusing a stale cached copy. See [Versions and updates](/docs/en/plugins/loading.md#versions-and-updates) for how a plugin's version becomes its cache key.
197197 
198198### Combine constraints from several plugins
199199 
from line 211
211211 
212212### Dependencies when your plugin loads from claude.ai
213213 
214When a user turns your plugin on for their claude.ai account, Claude Code loads it as `<name>@synced`, [with no marketplace](/docs/en/plugins/loading#synced-plugins). For that copy of your plugin, Claude Code counts a dependency entry that names a marketplace as met when the user has either of these:
214When a user turns your plugin on for their claude.ai account, Claude Code loads it as `<name>@synced`, [with no marketplace](/docs/en/plugins/loading.md#synced-plugins). For that copy of your plugin, Claude Code counts a dependency entry that names a marketplace as met when the user has either of these:
215215 
216216* **The dependency from its marketplace**: installed from the marketplace your entry names, and enabled. Claude Code checks a `version` range in your entry against the installed copy's version.
217217* **A claude.ai plugin of the same name**: enabled from their claude.ai account. Claude Code checks a `version` range in your entry against that plugin's `version`, and a plugin that states no `version` passes the check.
from line 223
223223## See also
224224 
225225* [`claude plugin prune`](/docs/en/plugins/cli-reference#plugin-prune): remove auto-installed dependencies no plugin needs anymore
226* [Host a marketplace](/docs/en/plugins/host-marketplace): release channels and recommending other plugins
226* [Host a marketplace](/docs/en/plugins/host-marketplace.md): release channels and recommending other plugins
227227 

plugins/host-marketplace Changed · +35 / -35 lines

from line 10
1010>
1111> These cases are covered on other pages:
1212>
13> * **You haven't written the catalog file yet**: start with [Create a marketplace](/docs/en/plugins/create-marketplace)
14> * **You're an admin requiring, restricting, or pre-installing marketplaces across your organization's machines**: read [Manage plugins for your organization](/docs/en/plugins/org)
13> * **You haven't written the catalog file yet**: start with [Create a marketplace](/docs/en/plugins/create-marketplace.md)
14> * **You're an admin requiring, restricting, or pre-installing marketplaces across your organization's machines**: read [Manage plugins for your organization](/docs/en/plugins/org.md)
1515 
1616Start with [Host your marketplace](#host-your-marketplace) to pick a host and the command your users run. Read [Keep users up to date](#keep-users-up-to-date) before your first release. Read [Rename or remove a plugin](#rename-or-remove-a-plugin) before you change a plugin's `name`.
1717 
from line 26
2626| A hosted `marketplace.json` URL | `/plugin marketplace add https://plugins.example.com/marketplace.json` | HTTPS access to the URL. Users don't need `git` for the catalog itself |
2727| A directory on a shared filesystem | `/plugin marketplace add /Volumes/shared/claude-plugins` | Read access to the path |
2828 
29To pin a branch or tag of a GitHub or git-URL marketplace, tell users to append `#<ref>`, as in `your-org/your-marketplace#stable`. The [plugin commands reference](/docs/en/plugins/cli-reference#plugin-marketplace-add) lists every form the command accepts.
29To pin a branch or tag of a GitHub or git-URL marketplace, tell users to append `#<ref>`, as in `your-org/your-marketplace#stable`. The [plugin commands reference](/docs/en/plugins/cli-reference.md#plugin-marketplace-add) lists every form the command accepts.
3030 
3131A successful add prints `Successfully added marketplace: your-marketplace`. Claude Code takes that name from the `name` field in your `marketplace.json`, not from the repository name.
3232 
from line 34
3434 
3535### Register the marketplace for everyone in a repository
3636 
37To share the marketplace with everyone who works in one repository, run `claude plugin marketplace add your-org/your-marketplace --scope project` there once from your shell and commit the `.claude/settings.json` it writes. Claude Code then registers the marketplace for each teammate who [trusts the folder](/docs/en/plugins/org#require-plugins-per-repository).
37To share the marketplace with everyone who works in one repository, run `claude plugin marketplace add your-org/your-marketplace --scope project` there once from your shell and commit the `.claude/settings.json` it writes. Claude Code then registers the marketplace for each teammate who [trusts the folder](/docs/en/plugins/org.md#require-plugins-per-repository).
3838 
3939### Avoid relative-path entries in a URL-hosted marketplace
4040 
from line 89
8989Organization sync is stricter about the repository than `/plugin marketplace add` is:
9090 
9191* **Marketplace repository**: on github.com and gitlab.com, it must be private or internal
92* **Plugin sources**: organization sync accepts only some [source types](/docs/en/plugins/marketplace-reference#plugin-sources)
92* **Plugin sources**: organization sync accepts only some [source types](/docs/en/plugins/marketplace-reference.md#plugin-sources)
9393* **Top-level `bin/` directory**: claude.ai rejects a plugin that has one and syncs the rest of the marketplace. The error message starts with `Plugin contains a top-level bin/ directory`. Keep executables in another directory, such as `scripts/`, and reference them as `${CLAUDE_PLUGIN_ROOT}/scripts/<name>` from your hooks or MCP server configs
9494 
9595[Sync your organization's plugins from a repository](https://claude.com/docs/plugins/org-sync) on claude.com lists the accepted sources, the GitLab setup, and the `bin/` error, and [Manage plugins for your organization](https://claude.com/docs/plugins/admin) covers the admin workflow.
from line 109
109109* **SSH**: the key must work without a passphrase prompt, for example because it's loaded in `ssh-agent`. The host must already be in `known_hosts`.
110110* **HTTPS**: Claude Code leaves the user's git credential helper enabled but forbids it from prompting. A credential the helper already stores works; one it would have to ask for fails. On GitHub, `gh auth login` followed by `gh auth setup-git` stores one.
111111 
112For a GitHub Enterprise Server host, users need git access to that host from their machine. See [Plugin marketplaces on GHES](/docs/en/github-enterprise-server#plugin-marketplaces-on-ghes) for what each Claude Code surface needs to reach a GHES-hosted marketplace.
112For a GitHub Enterprise Server host, users need git access to that host from their machine. See [Plugin marketplaces on GHES](/docs/en/github-enterprise-server.md#plugin-marketplaces-on-ghes) for what each Claude Code surface needs to reach a GHES-hosted marketplace.
113113 
114114If you distribute through **Organization settings > Plugins & skills** on claude.ai instead, your users' git credentials aren't involved. See [Distribute through organization settings](#distribute-through-organization-settings).
115115 
from line 139
139139After the check, Claude Code does one of the following:
140140 
141141* **The checkout is up to date**: Claude Code leaves it as it is.
142* **The check finds new commits, or fails because it can't reach or authenticate to the remote**: Claude Code clones the marketplace again and replaces the existing checkout with the new clone. If that clone fails, the existing checkout stays in place. The re-clone can [time out on large repositories](/docs/en/plugins/troubleshooting#git-clone-timed-out-after-120s).
142* **The check finds new commits, or fails because it can't reach or authenticate to the remote**: Claude Code clones the marketplace again and replaces the existing checkout with the new clone. If that clone fails, the existing checkout stays in place. The re-clone can [time out on large repositories](/docs/en/plugins/troubleshooting.md#git-clone-timed-out-after-120s).
143143 
144144To keep a private marketplace current, a user can do either of the following:
145145 
from line 155
155155| Who | What they do | Where it's covered |
156156| :- | :- | :- |
157157| You, the marketplace owner | Keep the catalog in a repository only the company can read, send the add command for your host, and say what each person needs on their machine | [Host your marketplace](#host-your-marketplace) and [Grant access to a private marketplace](#grant-access-to-a-private-marketplace) |
158| An administrator | Registers the marketplace and turns its plugins on for everyone with `extraKnownMarketplaces` and `enabledPlugins` in managed settings, and sets `autoUpdate` there | [Require a marketplace and its plugins](/docs/en/plugins/org#require-a-marketplace-and-its-plugins) and [Set update policy](/docs/en/plugins/org#set-update-policy) |
159| Each person | Needs read access to a private git repository, with credentials already stored on their machine. Without an administrator, they also run the add and install commands | [Add a private marketplace](/docs/en/plugins/install#add-a-private-marketplace) |
158| An administrator | Registers the marketplace and turns its plugins on for everyone with `extraKnownMarketplaces` and `enabledPlugins` in managed settings, and sets `autoUpdate` there | [Require a marketplace and its plugins](/docs/en/plugins/org.md#require-a-marketplace-and-its-plugins) and [Set update policy](/docs/en/plugins/org.md#set-update-policy) |
159| Each person | Needs read access to a private git repository, with credentials already stored on their machine. Without an administrator, they also run the add and install commands | [Add a private marketplace](/docs/en/plugins/install.md#add-a-private-marketplace) |
160160 
161161For people who have no git-host account, these sections each cover one way to reach them:
162162 
163163* **Entry sources that need no git account**: [Serve users who have no git-host account](#serve-users-who-have-no-git-host-account)
164* **A pre-populated plugins directory**: [Seed containers and CI](/docs/en/plugins/org#seed-containers-and-ci), which also serves users who have no git-host account
164* **A pre-populated plugins directory**: [Seed containers and CI](/docs/en/plugins/org.md#seed-containers-and-ci), which also serves users who have no git-host account
165165* **claude.ai organization settings**: [Distribute through organization settings](#distribute-through-organization-settings), where your users' git credentials aren't involved
166166 
167167## Keep users up to date
from line 173
173173Background auto-update is off for your marketplace by default, and `marketplace.json` has no field to turn it on. A user or an admin turns it on:
174174 
175175* **Tell users to turn it on**: each user goes to **Marketplaces** in `/plugin`, selects your marketplace, and selects **Enable auto-update**.
176* **Ask an admin to set it**: if an admin sets `"autoUpdate": true` on your marketplace's `extraKnownMarketplaces` entry in managed settings, it's on for everyone who receives those settings. See [Set update policy](/docs/en/plugins/org#set-update-policy).
176* **Ask an admin to set it**: if an admin sets `"autoUpdate": true` on your marketplace's `extraKnownMarketplaces` entry in managed settings, it's on for everyone who receives those settings. See [Set update policy](/docs/en/plugins/org.md#set-update-policy).
177177 
178178Without auto-update, users receive your changes when they run `/plugin marketplace update <name>` in a session or `claude plugin update <plugin>@<name>` in the shell.
179179 
180For what users see when an update reaches them, see [When auto-update runs](/docs/en/plugins/loading#when-auto-update-runs).
180For what users see when an update reaches them, see [When auto-update runs](/docs/en/plugins/loading.md#when-auto-update-runs).
181181 
182182### Release a new version
183183 
184To release a new version to users, change the plugin's `version`. Users get a new copy only when the plugin's computed version differs from the one they have. That version comes from `plugin.json` first, then from the marketplace entry, per [Versions and updates](/docs/en/plugins/loading#versions-and-updates).
184To release a new version to users, change the plugin's `version`. Users get a new copy only when the plugin's computed version differs from the one they have. That version comes from `plugin.json` first, then from the marketplace entry, per [Versions and updates](/docs/en/plugins/loading.md#versions-and-updates).
185185 
186A plugin that users [load in place](/docs/en/plugins/loading#find-plugins-on-disk) from a marketplace they added from a local path isn't controlled by `version`. It loads your current files at every session start, whatever its version string says.
186A plugin that users [load in place](/docs/en/plugins/loading.md#find-plugins-on-disk) from a marketplace they added from a local path isn't controlled by `version`. It loads your current files at every session start, whatever its version string says.
187187 
188188For every install other than an in-place load or one from a `command` source, either increase `version` on each release or omit it:
189189 
from line 196
196196 
197197One marketplace serves one version of each plugin at a time, so you hold users on a version by choosing what each entry points at:
198198 
199* **`ref` and `sha` on the plugin entry**: `ref` names a branch or tag and `sha` names a commit for a `github`, `url`, or `git-subdir` source. See [Plugin sources](/docs/en/plugins/marketplace-reference#plugin-sources).
199* **`ref` and `sha` on the plugin entry**: `ref` names a branch or tag and `sha` names a commit for a `github`, `url`, or `git-subdir` source. See [Plugin sources](/docs/en/plugins/marketplace-reference.md#plugin-sources).
200200* **`#<ref>` on the add command**: users who add `your-org/your-marketplace#stable` get that branch or tag of the catalog. For two release lines at once, see [Run release channels](#run-release-channels).
201* **`<plugin>--v<version>` tags**: a dependency's version range resolves against these tags. See [Release a plugin that others depend on](/docs/en/plugins/dependencies#tag-plugin-releases-for-version-resolution).
201* **`<plugin>--v<version>` tags**: a dependency's version range resolves against these tags. See [Release a plugin that others depend on](/docs/en/plugins/dependencies.md#tag-plugin-releases-for-version-resolution).
202202 
203203[Release a new version](#release-a-new-version) says when a changed entry reaches users.
204204 
from line 208
208208 
209209After a user's copy of your marketplace picks up the change, that user sees the following:
210210 
211* **No more background runs**: the [once-per-session run](/docs/en/plugins/loading#when-a-command-source-re-runs) of the command stops for that user, so the tool's new output doesn't reach them.
211* **No more background runs**: the [once-per-session run](/docs/en/plugins/loading.md#when-a-command-source-re-runs) of the command stops for that user, so the tool's new output doesn't reach them.
212212* **An entry in the `/plugin` Errors tab**: the entry shows the new command and the `claude plugin update` command to run.
213213 
214214Tell users to run the `claude plugin update` command that entry shows, in a terminal. Claude Code shows them the new command and asks them to accept it.
from line 243
243243 
244244Give the two refs different `plugin.json` versions, or omit `version` so the commit SHA distinguishes them. Updates are detected by comparing versions, so a ref that moves without a version change leaves users on the cached copy.
245245 
246To assign the channels to user groups instead of letting users choose, an admin gives each group the matching `extraKnownMarketplaces` entry, as described under [Set update policy](/docs/en/plugins/org#set-update-policy).
246To assign the channels to user groups instead of letting users choose, an admin gives each group the matching `extraKnownMarketplaces` entry, as described under [Set update policy](/docs/en/plugins/org.md#set-update-policy).
247247 
248248## Rename or remove a plugin
249249 
from line 300
300300 
301301In either place, set a `headersHelper` command instead of `headers` when the value is short-lived, such as a token your registry generates on request. Claude Code runs the command and sends the JSON object it prints as that place's headers. Requires Claude Code v2.1.238 or later.
302302 
303The [marketplace reference](/docs/en/plugins/marketplace-reference#plugin-entries) lists the `headers` and `headersHelper` entry fields.
303The [marketplace reference](/docs/en/plugins/marketplace-reference.md#plugin-entries) lists the `headers` and `headersHelper` entry fields.
304304 
305305The place you choose decides which downloads get the headers and when Claude Code runs the command:
306306 
from line 354
354354* **Marketplace URL doesn't start with `https://`**: that `url` source's command doesn't run, and requests carry only the headers listed in its `headers` field.
355355* **Redirect leaves the origin**: when a download is redirected off the archive URL's origin, the redirected request carries no `headers` values or command output from either the marketplace `url` source or the plugin entry.
356356* **Entry sets a routing or identity header**: Claude Code drops request-routing and client-identity names such as `Host`, `Cookie`, and `X-Forwarded-*` from an entry's `headers` and command output, and keeps authentication names such as `Authorization`. Every `marketplace.json` entry is filtered this way. For an inline plugin entry in settings, see [`extraKnownMarketplaces`](/docs/en/settings-reference#extraknownmarketplaces).
357* **Command set in an `--add-dir` directory's settings**: the command is ignored, on a `url` source and on an [inline plugin entry](/docs/en/settings-reference#extraknownmarketplaces) alike, and only that file's `headers` are sent.
357* **Command set in an `--add-dir` directory's settings**: the command is ignored, on a `url` source and on an [inline plugin entry](/docs/en/settings-reference.md#extraknownmarketplaces) alike, and only that file's `headers` are sent.
358358* **Managed settings block the command**: setting [`disableCommandPluginSources`](/docs/en/settings-reference#disablecommandpluginsources) to `true` blocks `headersHelper` commands, and [`allowManagedHooksOnly`](/docs/en/settings-reference#allowmanagedhooksonly) blocks them too unless `disableCommandPluginSources` is explicitly `false`. Under either block, Claude Code still runs the command for a marketplace that managed settings themselves declare.
359359 
360360### How users accept a headersHelper command
from line 365
365365 
366366* **Terminal session**: from the plugin's own view in `/plugin`.
367367* **Shell**: with `claude plugin install` or `claude plugin update`.
368* **VS Code extension**: from the [**Manage plugins** dialog](/docs/en/vs-code#manage-plugins), with version 2.1.290 or later of the extension.
368* **VS Code extension**: from the [**Manage plugins** dialog](/docs/en/vs-code.md#manage-plugins), with version 2.1.290 or later of the extension.
369369 
370370In a non-interactive shell, pass [`--yes`](/docs/en/plugins/cli-reference#plugin-install) to accept the command. To accept only the command that a previous `--json` run displayed, pass [`--accept-command`](/docs/en/plugins/cli-reference#plugin-install) with the `sha256` the run reported.
371371 
from line 385
385385| Settings file | When Claude Code runs the command |
386386| :- | :- |
387387| User settings, a `--settings` file, or a managed settings file on the machine | Without asking, including during a background marketplace refresh |
388| A project's `.claude/settings.json` or `.claude/settings.local.json` | Only after the user accepts the [workspace trust dialog](/docs/en/permissions#what-runs-before-you-trust-a-folder) for that folder itself. A `-p` or SDK session doesn't count as accepting it, and neither does trust granted to a parent folder |
389| Server-managed settings | In an interactive session, only after the user approves the delivered settings in the [security approval dialog](/docs/en/server-managed-settings#security-approval-dialogs) |
388| A project's `.claude/settings.json` or `.claude/settings.local.json` | Only after the user accepts the [workspace trust dialog](/docs/en/permissions.md#what-runs-before-you-trust-a-folder) for that folder itself. A `-p` or SDK session doesn't count as accepting it, and neither does trust granted to a parent folder |
389| Server-managed settings | In an interactive session, only after the user approves the delivered settings in the [security approval dialog](/docs/en/server-managed-settings.md#security-approval-dialogs) |
390390 
391For an [inline plugin entry](/docs/en/settings-reference#extraknownmarketplaces) in one of these files, Claude Code requires the same folder trust or settings approval as for a marketplace-level command in that file, and the user also accepts the entry's command on each install or update.
391For an [inline plugin entry](/docs/en/settings-reference.md#extraknownmarketplaces) in one of these files, Claude Code requires the same folder trust or settings approval as for a marketplace-level command in that file, and the user also accepts the entry's command on each install or update.
392392 
393393## Depend on and recommend other plugins
394394 
from line 397
397397* **Version ranges**: a dependency can carry a semver range.
398398* **Cross-marketplace dependencies**: a dependency from another marketplace installs only when your marketplace lists that marketplace in `allowCrossMarketplaceDependenciesOn`.
399399 
400For version ranges, the `<plugin>--v<version>` git-tag convention they resolve against, and cross-marketplace trust, see [Plugin dependencies](/docs/en/plugins/dependencies).
400For version ranges, the `<plugin>--v<version>` git-tag convention they resolve against, and cross-marketplace trust, see [Plugin dependencies](/docs/en/plugins/dependencies.md).
401401 
402To have Claude Code suggest a plugin when a project matches it, add a `relevance` block to the entry with the signals that identify the project. Users see suggestions from your marketplace only when an admin lists it in `pluginSuggestionMarketplaces`. For the signals and the enablement step, see [Plugin relevance](/docs/en/plugins/relevance).
402To have Claude Code suggest a plugin when a project matches it, add a `relevance` block to the entry with the signals that identify the project. Users see suggestions from your marketplace only when an admin lists it in `pluginSuggestionMarketplaces`. For the signals and the enablement step, see [Plugin relevance](/docs/en/plugins/relevance.md).
403403 
404404## Work around what a marketplace can't do
405405 
406406Some things owners ask for have no field in `marketplace.json`. Here is the nearest option for each:
407407 
408* **Restrict what else users install**: the marketplace allowlist is a managed setting, `strictKnownMarketplaces`. See [Restrict what users can install](/docs/en/plugins/org#restrict-what-users-can-install).
409* **Install or enable a plugin without the user asking**: no entry field installs a plugin. Managed `enabledPlugins` does that for a fleet; see [Pre-install and require plugins](/docs/en/plugins/org#pre-install-and-require-plugins).
408* **Restrict what else users install**: the marketplace allowlist is a managed setting, `strictKnownMarketplaces`. See [Restrict what users can install](/docs/en/plugins/org.md#restrict-what-users-can-install).
409* **Install or enable a plugin without the user asking**: no entry field installs a plugin. Managed `enabledPlugins` does that for a fleet; see [Pre-install and require plugins](/docs/en/plugins/org.md#pre-install-and-require-plugins).
410410* **Show different entries to different users**: entries carry no audience field, and every user who adds the marketplace sees the whole catalog. Host separate marketplaces for separate audiences.
411411* **Mark a plugin deprecated**: there is no deprecation state. The option is to remove the entry, map its name to `null` in `renames`, and optionally set `forceRemoveDeletedPlugins`.
412412* **Turn on auto-update for your users**: each user turns it on under **Marketplaces** in `/plugin`, or an admin sets `autoUpdate` in managed settings. See [Turn on auto-update](#turn-on-auto-update).
from line 414
414414 
415415## Next steps
416416 
417* [Marketplace reference](/docs/en/plugins/marketplace-reference): `marketplace.json` fields, source types, and validation messages
418* [Manage plugins for your organization](/docs/en/plugins/org): require, restrict, or seed your marketplace across your organization's machines
419* [Plugin dependencies](/docs/en/plugins/dependencies): tag releases so plugins that depend on yours can resolve versions
420* [Troubleshoot plugins](/docs/en/plugins/troubleshooting): the errors your users see when adding or updating from your marketplace
417* [Marketplace reference](/docs/en/plugins/marketplace-reference.md): `marketplace.json` fields, source types, and validation messages
418* [Manage plugins for your organization](/docs/en/plugins/org.md): require, restrict, or seed your marketplace across your organization's machines
419* [Plugin dependencies](/docs/en/plugins/dependencies.md): tag releases so plugins that depend on yours can resolve versions
420* [Troubleshoot plugins](/docs/en/plugins/troubleshooting.md): the errors your users see when adding or updating from your marketplace
421421 

plugins/install Changed · +43 / -43 lines

from line 11
1111> These cases are covered on other pages:
1212>
1313> * **You use claude.ai chat or Cowork, not Claude Code**: see [Plugins on claude.ai and in Cowork](https://claude.com/docs/plugins/overview)
14> * **Claude Code printed an error**: find it in [Troubleshoot plugins](/docs/en/plugins/troubleshooting)
14> * **Claude Code printed an error**: find it in [Troubleshoot plugins](/docs/en/plugins/troubleshooting.md)
1515 
1616Start with [Install a plugin](#install-a-plugin). If someone sent you an install command whose `@` name isn't `claude-plugins-official`, [add that marketplace](#add-a-marketplace) first.
1717 
1818## Install a plugin
1919 
20As an example, this section installs [`commit-commands`](https://github.com/anthropics/claude-plugins-official/tree/main/plugins/commit-commands) from [Anthropic's official marketplace](/docs/en/plugins/anthropic-marketplaces), which adds commands for committing, pushing, and opening pull requests.
20As an example, this section installs [`commit-commands`](https://github.com/anthropics/claude-plugins-official/tree/main/plugins/commit-commands) from [Anthropic's official marketplace](/docs/en/plugins/anthropic-marketplaces.md), which adds commands for committing, pushing, and opening pull requests.
2121 
2222The same steps install any other plugin: substitute its name and its marketplace's name wherever `commit-commands` and `claude-plugins-official` appear. If that plugin comes from a different marketplace, [add the marketplace](#add-a-marketplace) first.
2323 
from line 47
4747 
4848Plugins from a local or custom marketplace can show `Components will be discovered at installation` instead.
4949 
50A plugin can run hooks and MCP servers, so read the pane before you install. See [Plugin security and trust](/docs/en/plugins/security).
50A plugin can run hooks and MCP servers, so read the pane before you install. See [Plugin security and trust](/docs/en/plugins/security.md).
5151 
5252**3. Choose a scope**
5353 
from line 66
6666The last sentence of the summary tells you whether the plugin is usable in this session yet:
6767 
6868* **Active now**: `Plugin is now active.` No reload is needed.
69* **Active, but a server needs setup**: `Plugin is now active.` is followed by `Its bundled MCP server needs configuration before it can start`. The plugin's [bundled MCP server](/docs/en/plugins/components#include-a-packaged-mcpb-server) can't start until you set its options. Select the plugin on the **Installed** tab in `/plugin` and choose **Configure** to set the server's options.
70* **Reload needed**: `Run /reload-plugins to apply.` The panel closes and Claude Code runs that reload for you. If the reload would [invalidate the prompt cache](/docs/en/prompt-caching#enabling-or-disabling-a-plugin), it warns and leaves the plugin pending instead. Run `/reload-plugins --force` to activate it anyway, which costs one uncached request.
71* **Load failed**: `The plugin couldn't be loaded`. Open the **Errors** tab in `/plugin` for the reason, then see [After install: plugin not working](/docs/en/plugins/troubleshooting#plugin-installed-but-not-working).
69* **Active, but a server needs setup**: `Plugin is now active.` is followed by `Its bundled MCP server needs configuration before it can start`. The plugin's [bundled MCP server](/docs/en/plugins/components.md#include-a-packaged-mcpb-server) can't start until you set its options. Select the plugin on the **Installed** tab in `/plugin` and choose **Configure** to set the server's options.
70* **Reload needed**: `Run /reload-plugins to apply.` The panel closes and Claude Code runs that reload for you. If the reload would [invalidate the prompt cache](/docs/en/prompt-caching.md#enabling-or-disabling-a-plugin), it warns and leaves the plugin pending instead. Run `/reload-plugins --force` to activate it anyway, which costs one uncached request.
71* **Load failed**: `The plugin couldn't be loaded`. Open the **Errors** tab in `/plugin` for the reason, then see [After install: plugin not working](/docs/en/plugins/troubleshooting.md#plugin-installed-but-not-working).
7272 
7373**5. Confirm the plugin works**
7474 
from line 77
7777* Open the **Installed** tab in `/plugin`, which lists the plugin with its scope.
7878* In your shell, run `claude plugin list`, which prints the same list with `Version`, `Scope`, and `Status` lines.
7979 
80If `/commit-commands:commit` doesn't appear, see [After install: plugin not working](/docs/en/plugins/troubleshooting#plugin-installed-but-not-working).
80If `/commit-commands:commit` doesn't appear, see [After install: plugin not working](/docs/en/plugins/troubleshooting.md#plugin-installed-but-not-working).
8181 
8282Installing from any other marketplace requires one extra step first: [add the marketplace](#add-a-marketplace). Claude Code adds Anthropic's official marketplace for you the first time you start an interactive terminal session, which is why the example skips that step. If you found a plugin on [claude.com/marketplace](https://claude.com/marketplace), its **Claude Code** button copies the install command in its [shell form](#install-from-your-shell), `claude plugin install <name>@claude-plugins-official`.
8383 
from line 97
9797 
9898Choose a [scope](#choose-an-install-scope): your user account, this project, or local-only.
9999 
100To enable, disable, or uninstall a plugin later, see [Install plugins in the desktop app](/docs/en/desktop#install-plugins).
100To enable, disable, or uninstall a plugin later, see [Install plugins in the desktop app](/docs/en/desktop.md#install-plugins).
101101 
102102**VS Code**
103103 
from line 115
115115 
116116Choose a [scope](#choose-an-install-scope): **Install for you**, **Install for this project**, or **Install locally**.
117117 
118Your changes apply to open sessions without a restart. See [Manage plugins in VS Code](/docs/en/vs-code#manage-plugins).
118Your changes apply to open sessions without a restart. See [Manage plugins in VS Code](/docs/en/vs-code.md#manage-plugins).
119119 
120120**Cloud session**
121121 
122A [cloud session](/docs/en/cloud-environments), including [the browser at claude.ai/code](/docs/en/claude-code-on-the-web), has no plugin browser and doesn't load the plugins you installed on your own machine or the ones your repository's `.claude/settings.json` turns on. For plugins your organization distributes through managed settings, see [Manage plugins for your organization](/docs/en/plugins/org).
122A [cloud session](/docs/en/cloud-environments.md), including [the browser at claude.ai/code](/docs/en/claude-code-on-the-web.md), has no plugin browser and doesn't load the plugins you installed on your own machine or the ones your repository's `.claude/settings.json` turns on. For plugins your organization distributes through managed settings, see [Manage plugins for your organization](/docs/en/plugins/org.md).
123123 
124See [which parts of your setup are also available in a cloud session](/docs/en/cloud-environments#what-carries-over-from-your-setup) for the rest of your setup.
124See [which parts of your setup are also available in a cloud session](/docs/en/cloud-environments.md#what-carries-over-from-your-setup) for the rest of your setup.
125125 
126126### Choose an install scope
127127 
from line 128
128128A plugin's install scope decides who gets the plugin and which settings file records it as enabled:
129129 
130130* **User scope**: the plugin is enabled for you in every project on this machine. The entry goes in `enabledPlugins` in `~/.claude/settings.json`.
131* **Project scope**: the plugin is enabled for everyone who works in this repository. The entry goes in `.claude/settings.json`, which you commit. Committing that entry turns the plugin on for your collaborators but doesn't download it to their machines, so each collaborator also runs `claude plugin install <name>@<marketplace> --scope project` once; see [Enabled in project settings but not installed](/docs/en/plugins/loading#enabled-in-project-settings-but-not-installed).
131* **Project scope**: the plugin is enabled for everyone who works in this repository. The entry goes in `.claude/settings.json`, which you commit. Committing that entry turns the plugin on for your collaborators but doesn't download it to their machines, so each collaborator also runs `claude plugin install <name>@<marketplace> --scope project` once; see [Enabled in project settings but not installed](/docs/en/plugins/loading.md#enabled-in-project-settings-but-not-installed).
132132* **Local scope**: the plugin is enabled for you in this repository only. The entry goes in `.claude/settings.local.json`.
133133 
134134Some plugins are set by their author to start turned off, through the [`defaultEnabled`](/docs/en/plugins/manifest-reference#defaultenabled) field. Such a plugin is installed but stays off until you turn it on with `claude plugin enable <name>` in your shell, or from the **Installed** tab of `/plugin` in a session.
135135 
136When the same plugin is set at several scopes, the local setting overrides the project setting, and the project setting overrides the user setting. See [Find where a plugin is enabled](/docs/en/plugins/loading#find-where-a-plugin-is-enabled) for the full rule.
136When the same plugin is set at several scopes, the local setting overrides the project setting, and the project setting overrides the user setting. See [Find where a plugin is enabled](/docs/en/plugins/loading.md#find-where-a-plugin-is-enabled) for the full rule.
137137 
138138The terminal, the desktop app's local sessions, and the VS Code extension on one computer read the same settings files, so a plugin you install at user scope in any of them is available in the other two.
139139 
from line 143
143143 
144144* **JetBrains IDEs**: the JetBrains plugin runs Claude Code in the IDE's terminal, so use the **Terminal** tab's steps there.
145145* **`claude -p` and other non-interactive runs**: `/plugin` doesn't run, and Claude replies `/plugin isn't available in this environment.` Plugins you already installed do load. Install and manage them from your shell with [`claude plugin` commands](#install-from-your-shell).
146* **Agent SDK**: load plugins through the SDK's plugin option. See [Load plugins in the Agent SDK](/docs/en/agent-sdk/plugins).
146* **Agent SDK**: load plugins through the SDK's plugin option. See [Load plugins in the Agent SDK](/docs/en/agent-sdk/plugins.md).
147147 
148If Claude Code reports that a plugin enabled in the repository's `.claude/settings.json` isn't installed, see [Enabled in project settings but not installed](/docs/en/plugins/loading#enabled-in-project-settings-but-not-installed).
148If Claude Code reports that a plugin enabled in the repository's `.claude/settings.json` isn't installed, see [Enabled in project settings but not installed](/docs/en/plugins/loading.md#enabled-in-project-settings-but-not-installed).
149149 
150150> [!TIP]
151151>
152> If you're a plugin author testing a copy of your plugin on disk, start Claude Code from your shell with `--plugin-dir` to load it for one session instead of installing it. See [Flags that load a plugin for one session](/docs/en/plugins/cli-reference#flags-that-load-a-plugin-for-one-session).
152> If you're a plugin author testing a copy of your plugin on disk, start Claude Code from your shell with `--plugin-dir` to load it for one session instead of installing it. See [Flags that load a plugin for one session](/docs/en/plugins/cli-reference.md#flags-that-load-a-plugin-for-one-session).
153153 
154154### Plugins from your claude.ai account
155155 
from line 159
159159* **Where you see them**: in `/plugin` and `claude plugin list` under the ID `<name>@synced`. You can turn one off at your own scope unless your organization requires it.
160160* **What doesn't go the other way**: plugins you install with `/plugin` or `claude plugin install` stay on this machine and aren't added to your claude.ai account.
161161 
162For sync timing, sign-in requirements, and turning sync off, see [Plugins synced from claude.ai](/docs/en/plugins/loading#synced-plugins).
162For sync timing, sign-in requirements, and turning sync off, see [Plugins synced from claude.ai](/docs/en/plugins/loading.md#synced-plugins).
163163 
164164### Install from your shell
165165 
from line 177
177177 
178178Some plugins install by running a command that their marketplace names, called a [`command` source](/docs/en/plugins/marketplace-reference#command-plugin-source). Claude Code shows you that command and asks you to accept it before it runs. A script has no one to answer that prompt, so pass `--yes` there to accept it.
179179 
180For the other `claude plugin install` flags, see [plugin install](/docs/en/plugins/cli-reference#plugin-install).
180For the other `claude plugin install` flags, see [plugin install](/docs/en/plugins/cli-reference.md#plugin-install).
181181 
182182## Add a marketplace
183183 
from line 202
202202 
203203Include the `https://` prefix on every URL, or use the `git@host:path` form for SSH. If you type a bare `gitlab.example.com/your-group/your-marketplace.git`, Claude Code reads it as GitHub `owner/repo` shorthand and rejects it.
204204 
205When the command succeeds, it prints `Successfully added marketplace: <name>`, and the marketplace's plugins appear on the **Discover** tab the next time you open `/plugin`, with no reload needed. If it fails, match the error message in [Troubleshoot plugins](/docs/en/plugins/troubleshooting#add-a-marketplace).
205When the command succeeds, it prints `Successfully added marketplace: <name>`, and the marketplace's plugins appear on the **Discover** tab the next time you open `/plugin`, with no reload needed. If it fails, match the error message in [Troubleshoot plugins](/docs/en/plugins/troubleshooting.md#add-a-marketplace).
206206 
207207### Add a marketplace and install in one command
208208 
from line 226
226226claude plugin install deploy-helper --marketplace your-org/plugins
227227```
228228 
229The shell command adds the marketplace without a confirmation step. A marketplace you've already added from that source is reused. A new one is added under the same [organization policy checks](/docs/en/plugins/org#restrict-what-users-can-install) as `claude plugin marketplace add`, and is declared in your user settings even when you pass `--scope project`.
229The shell command adds the marketplace without a confirmation step. A marketplace you've already added from that source is reused. A new one is added under the same [organization policy checks](/docs/en/plugins/org.md#restrict-what-users-can-install) as `claude plugin marketplace add`, and is declared in your user settings even when you pass `--scope project`.
230230 
231231If you haven't added that marketplace yet, the command prints `Successfully added marketplace: <name> (declared in user settings)` and then [installs the plugin](#install-from-your-shell).
232232 
from line 240
240240 
241241The same credentials apply when you run `/plugin install`, `/plugin marketplace update`, and `claude plugin update`.
242242 
243On a GitHub Enterprise Server host, see [Plugin marketplaces on GHES](/docs/en/github-enterprise-server#plugin-marketplaces-on-ghes) for the credentials each operation needs.
243On a GitHub Enterprise Server host, see [Plugin marketplaces on GHES](/docs/en/github-enterprise-server.md#plugin-marketplaces-on-ghes) for the credentials each operation needs.
244244 
245If your organization registers the marketplace for you through managed settings, you don't add it yourself. See [Pre-install and require plugins](/docs/en/plugins/org#pre-install-and-require-plugins).
245If your organization registers the marketplace for you through managed settings, you don't add it yourself. See [Pre-install and require plugins](/docs/en/plugins/org.md#pre-install-and-require-plugins).
246246 
247247### Add a marketplace from claude.ai
248248 
249In terminal sessions where [plugins sync from your claude.ai account](/docs/en/plugins/loading#synced-plugins), claude.ai can also list plugin marketplaces for you, such as your organization's plugin library and your own claude.ai uploads. You add one of these by its name rather than by a source. Adding a marketplace from claude.ai requires Claude Code v2.1.273 or later.
249In terminal sessions where [plugins sync from your claude.ai account](/docs/en/plugins/loading.md#synced-plugins), claude.ai can also list plugin marketplaces for you, such as your organization's plugin library and your own claude.ai uploads. You add one of these by its name rather than by a source. Adding a marketplace from claude.ai requires Claude Code v2.1.273 or later.
250250 
251251Add a claude.ai marketplace from the `/plugin` panel or from your shell:
252252 
from line 276
276276A plugin's details menu offers **Disable plugin** or **Enable plugin**, **Update now**, and **Uninstall**. Two more items appear for plugins that take settings, and a plugin can show both:
277277 
278278* **Configure options**: shown when the plugin's manifest declares [`userConfig` options](/docs/en/plugins/manifest-reference#user-configuration). Opens the dialog for those options
279* **Configure**: shown when the plugin includes a [bundled MCP server](/docs/en/plugins/components#include-a-packaged-mcpb-server). Sets that server's own `user_config` settings
279* **Configure**: shown when the plugin includes a [bundled MCP server](/docs/en/plugins/components.md#include-a-packaged-mcpb-server). Sets that server's own `user_config` settings
280280 
281The tab can also show plugins at **Managed** scope. Your organization installed those through [managed settings](/docs/en/settings#settings-files), and you can't enable, disable, or uninstall them here.
281The tab can also show plugins at **Managed** scope. Your organization installed those through [managed settings](/docs/en/settings.md#settings-files), and you can't enable, disable, or uninstall them here.
282282 
283283For a synced plugin that your organization requires on claude.ai, see [Manage plugins synced from claude.ai](#manage-plugins-synced-from-claude-ai).
284284 
285When you close the `/plugin` panel with pending changes you made in it, Claude Code runs `/reload-plugins` for you to apply them. If the reload would [invalidate the prompt cache](/docs/en/prompt-caching#enabling-or-disabling-a-plugin), it warns and leaves the changes pending instead. Run `/reload-plugins --force` to apply them anyway.
285When you close the `/plugin` panel with pending changes you made in it, Claude Code runs `/reload-plugins` for you to apply them. If the reload would [invalidate the prompt cache](/docs/en/prompt-caching.md#enabling-or-disabling-a-plugin), it warns and leaves the changes pending instead. Run `/reload-plugins --force` to apply them anyway.
286286 
287287### Manage plugins synced from claude.ai
288288 
289The **Installed** tab in `/plugin` also lists the [plugins synced from your claude.ai account](/docs/en/plugins/loading#synced-plugins), with `synced` as their source. Synced plugins appear in terminal sessions on Claude Code v2.1.273 or later.
289The **Installed** tab in `/plugin` also lists the [plugins synced from your claude.ai account](/docs/en/plugins/loading.md#synced-plugins), with `synced` as their source. Synced plugins appear in terminal sessions on Claude Code v2.1.273 or later.
290290 
291291* **Enable or disable**: use the **Installed** tab, unless your organization marked the plugin as required.
292292* **Remove**: turn the plugin off on claude.ai.
from line 302
302302 
303303### See what an installed plugin adds to your sessions
304304 
305In your shell, run `claude plugin details <name>` for an installed plugin. The `Always-on` line is the number of tokens the plugin adds to every session where it's enabled, and the per-component rows show which skill or agent contributes most. For the full output and what each figure means, see [Measure what a plugin costs](/docs/en/plugins/measure#measure-what-a-plugin-costs).
305In your shell, run `claude plugin details <name>` for an installed plugin. The `Always-on` line is the number of tokens the plugin adds to every session where it's enabled, and the per-component rows show which skill or agent contributes most. For the full output and what each figure means, see [Measure what a plugin costs](/docs/en/plugins/measure.md#measure-what-a-plugin-costs).
306306 
307307### Find plugins you no longer use
308308 
from line 315
315315* **Install**: Claude Code also installs and enables the plugin's declared dependencies at the same scope. The success message lists them.
316316* **Enable**: Claude Code also enables the plugin's dependencies that are installed but disabled. If a declared dependency isn't installed, the enable fails and the message tells you to install it first.
317317* **Disable**: when another enabled plugin still needs the one you named, Claude Code refuses and prints a chained command that disables both in the right order.
318* **Uninstall**: auto-installed dependencies stay until you run `claude plugin prune` in your shell; see [plugin prune](/docs/en/plugins/cli-reference#plugin-prune).
318* **Uninstall**: auto-installed dependencies stay until you run `claude plugin prune` in your shell; see [plugin prune](/docs/en/plugins/cli-reference.md#plugin-prune).
319319 
320If you loaded the plugin with `--plugin-dir` instead, see [Test a plugin and its dependency locally](/docs/en/plugins/dependencies#test-a-plugin-and-its-dependency-locally).
320If you loaded the plugin with `--plugin-dir` instead, see [Test a plugin and its dependency locally](/docs/en/plugins/dependencies.md#test-a-plugin-and-its-dependency-locally).
321321 
322322### Manage plugins from your shell
323323 
from line 342
342342 
343343These are the auto-update defaults for each kind of marketplace:
344344 
345* **On by default**: `claude-plugins-official` and the other [official marketplace names](/docs/en/plugins/security#official-marketplace-names) except `knowledge-work-plugins` and `first-party-plugins`, plus [marketplaces added from claude.ai](#add-from-claude-ai).
345* **On by default**: `claude-plugins-official` and the other [official marketplace names](/docs/en/plugins/security.md#official-marketplace-names) except `knowledge-work-plugins` and `first-party-plugins`, plus [marketplaces added from claude.ai](#add-from-claude-ai).
346346* **Off by default**: every other marketplace, including the community marketplace, third-party marketplaces, and local development marketplaces.
347347 
348For when auto-update runs, which plugins it skips, and the environment variables that turn it off, see [When auto-update runs](/docs/en/plugins/loading#when-auto-update-runs).
348For when auto-update runs, which plugins it skips, and the environment variables that turn it off, see [When auto-update runs](/docs/en/plugins/loading.md#when-auto-update-runs).
349349 
350350### Turn auto-update on or off for a marketplace
351351 
from line 361
361361 
362362### Auto-update from a private marketplace
363363 
364For a private marketplace, see [What background auto-update does with credentials](/docs/en/plugins/host-marketplace#what-background-auto-update-does-with-credentials) for how background auto-updates authenticate over SSH and HTTPS, and [Troubleshoot plugins](/docs/en/plugins/troubleshooting#add-a-marketplace) for the messages you see when they fail.
364For a private marketplace, see [What background auto-update does with credentials](/docs/en/plugins/host-marketplace.md#what-background-auto-update-does-with-credentials) for how background auto-updates authenticate over SSH and HTTPS, and [Troubleshoot plugins](/docs/en/plugins/troubleshooting.md#add-a-marketplace) for the messages you see when they fail.
365365 
366366## Manage marketplaces
367367 
from line 379
379379 
380380## Next steps
381381 
382* [Anthropic's marketplaces](/docs/en/plugins/anthropic-marketplaces): how the official, community, and demo marketplaces differ and where to browse each one
383* [Plugin loading reference](/docs/en/plugins/loading): why a plugin loaded, didn't load, or didn't change after an update
384* [Plugin security and trust](/docs/en/plugins/security): what to review before you install a plugin from a marketplace you don't know
385* [Troubleshoot plugins](/docs/en/plugins/troubleshooting): install and marketplace error messages with their fixes
386* [Create a plugin](/docs/en/plugins/create): build your own
382* [Anthropic's marketplaces](/docs/en/plugins/anthropic-marketplaces.md): how the official, community, and demo marketplaces differ and where to browse each one
383* [Plugin loading reference](/docs/en/plugins/loading.md): why a plugin loaded, didn't load, or didn't change after an update
384* [Plugin security and trust](/docs/en/plugins/security.md): what to review before you install a plugin from a marketplace you don't know
385* [Troubleshoot plugins](/docs/en/plugins/troubleshooting.md): install and marketplace error messages with their fixes
386* [Create a plugin](/docs/en/plugins/create.md): build your own
387387 

plugins/loading Changed · +49 / -49 lines

from line 8
88>
99> These cases are covered on other pages:
1010>
11> * **Install, enable, disable, and update steps**: see [Install and manage plugins](/docs/en/plugins/install)
12> * **You have a specific error message**: see [Troubleshoot plugins](/docs/en/plugins/troubleshooting)
11> * **Install, enable, disable, and update steps**: see [Install and manage plugins](/docs/en/plugins/install.md)
12> * **You have a specific error message**: see [Troubleshoot plugins](/docs/en/plugins/troubleshooting.md)
1313 
1414Start with [Check which stage a plugin reached](#check-which-stage-a-plugin-reached) for the three stages an installed plugin passes through, or go to the section that matches what you're seeing:
1515 
from line 71
7171 
7272A 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 check that applies to project allow rules in `.claude/settings.json`. Trusting a parent folder or running with `-p` isn't enough. Components that run code are restricted further:
7373 
74* MCP servers it declares go through the [same per-server approval](/docs/en/mcp) as a project `.mcp.json`
75* MCP servers it declares as an [MCP bundle](/docs/en/plugins/manifest-reference#mcpservers), a `.mcpb` or `.dxt` file, or from a file outside the plugin directory are skipped. Declare them inline or in a `.mcp.json` inside the plugin directory
76* [Background monitors](/docs/en/plugins/components#monitors) do not load
74* MCP servers it declares go through the [same per-server approval](/docs/en/mcp.md) as a project `.mcp.json`
75* MCP servers it declares as an [MCP bundle](/docs/en/plugins/manifest-reference.md#mcpservers), a `.mcpb` or `.dxt` file, or from a file outside the plugin directory are skipped. Declare them inline or in a `.mcp.json` inside the plugin directory
76* [Background monitors](/docs/en/plugins/components.md#monitors) do not load
7777 
7878Neither the trust check nor these component limits apply to a plugin under your own `~/.claude/skills/`.
7979 
80For how to write `--plugin-dir` and skills-directory plugins, see [Create plugins](/docs/en/plugins/create).
80For how to write `--plugin-dir` and skills-directory plugins, see [Create plugins](/docs/en/plugins/create.md).
8181 
8282#### Check why a repository plugin didn't load
8383 
8484If a plugin in your repository's `.claude/skills/` doesn't load, check for these causes:
8585 
86* **In a subdirectory**: a plugin at the repository root doesn't load. Claude Code reads the `.claude/skills/` of the session's [primary working directory](/docs/en/permissions#working-directories) and, unlike plain skills and commands, doesn't [search parent directories](/docs/en/skills#discovery-from-parent-and-nested-directories) for plugins. Launch from the repository root instead, or [move the session there with `/cd`](/docs/en/permissions#move-the-session-to-another-directory) on v2.1.246 or later
87* **From the desktop app, in a worktree**: the plugin loads from the main checkout's `.claude/skills/` rather than the worktree's. See [What worktrees share with the main checkout](/docs/en/worktrees#what-worktrees-share-with-the-main-checkout)
88* **In a folder you haven't trusted**: the plugin loads only after you accept the [workspace trust dialog](/docs/en/permissions#what-runs-before-you-trust-a-folder) for that folder
86* **In a subdirectory**: a plugin at the repository root doesn't load. Claude Code reads the `.claude/skills/` of the session's [primary working directory](/docs/en/permissions.md#working-directories) and, unlike plain skills and commands, doesn't [search parent directories](/docs/en/skills.md#discovery-from-parent-and-nested-directories) for plugins. Launch from the repository root instead, or [move the session there with `/cd`](/docs/en/permissions#move-the-session-to-another-directory) on v2.1.246 or later
87* **From the desktop app, in a worktree**: the plugin loads from the main checkout's `.claude/skills/` rather than the worktree's. See [What worktrees share with the main checkout](/docs/en/worktrees.md#what-worktrees-share-with-the-main-checkout)
88* **In a folder you haven't trusted**: the plugin loads only after you accept the [workspace trust dialog](/docs/en/permissions.md#what-runs-before-you-trust-a-folder) for that folder
8989* **In an organization that manages Claude Code**: see [Skills-directory plugins blocked by managed settings](#skills-directory-plugins-blocked-by-managed-settings)
9090 
9191### Skills-directory plugins blocked by managed settings
9292 
93If a plugin folder in `~/.claude/skills/` or a project's `.claude/skills/` didn't load and you see no error, your administrator may have blocked it through [managed settings](/docs/en/managed-settings). These folders come from you or your repository rather than from a marketplace, so Claude Code skips them when your administrator sets one of these restrictions:
93If a plugin folder in `~/.claude/skills/` or a project's `.claude/skills/` didn't load and you see no error, your administrator may have blocked it through [managed settings](/docs/en/managed-settings.md). These folders come from you or your repository rather than from a marketplace, so Claude Code skips them when your administrator sets one of these restrictions:
9494 
9595* **Customization locked to plugins**: [`strictPluginOnlyCustomization`](/docs/en/settings-reference#strictpluginonlycustomization) set to `true` or to an array naming one or more kinds of customization to lock. The whole plugin is skipped when any one kind is locked, such as `mcp`, whichever components it has.
9696* **Marketplace sources restricted**: a [`strictKnownMarketplaces`](/docs/en/settings-reference#strictknownmarketplaces) allowlist without a `{ "source": "skills-dir" }` entry, or a [`blockedMarketplaces`](/docs/en/settings-reference#blockedmarketplaces) list with one.
from line 100
100100Unless skills are among the locked kinds, a `SKILL.md` at the folder's root still loads as a plain skill. In that case `/<name>` keeps working, and the `/plugin` **Installed** tab lists that skill under **Skills**.
101101 
102102* **Confirm the cause**: run `/status` in a Claude Code session. If the `Setting sources` line lists `Enterprise managed settings`, ask your administrator whether one of these settings applies to you. If it doesn't, see [Check why a repository plugin didn't load](#check-why-a-repository-plugin-didnt-load) for other causes.
103* **Load the whole plugin**: add it to a [marketplace](/docs/en/plugins/create-marketplace#create-a-marketplace) your organization allows and install it from there. To load it for one session instead, start `claude` from your shell with [`--plugin-dir`](/docs/en/plugins/cli-reference#flags-that-load-a-plugin-for-one-session) and the folder's path, which works unless your administrator has also turned off that flag.
103* **Load the whole plugin**: add it to a [marketplace](/docs/en/plugins/create-marketplace.md#create-a-marketplace) your organization allows and install it from there. To load it for one session instead, start `claude` from your shell with [`--plugin-dir`](/docs/en/plugins/cli-reference#flags-that-load-a-plugin-for-one-session) and the folder's path, which works unless your administrator has also turned off that flag.
104104 
105105### Plugins synced from claude.ai
106106 
from line 132
132132Claude Code neither downloads nor loads synced plugins in these terminal sessions, even after you sign in with `/login`:
133133 
134134* A session where `ANTHROPIC_AUTH_TOKEN`, `CLAUDE_CODE_OAUTH_TOKEN`, or an `apiKeyHelper` script supplies the credential in place of that sign-in
135* A session that doesn't [fetch feature flags from Anthropic](/docs/en/env-vars#features-that-need-feature-flag-fetching), such as one where you set `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC`
136* A session in [bare mode](/docs/en/headless#start-faster-with-bare-mode) or one you start with `--safe-mode`
135* A session that doesn't [fetch feature flags from Anthropic](/docs/en/env-vars.md#features-that-need-feature-flag-fetching), such as one where you set `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC`
136* A session in [bare mode](/docs/en/headless.md#start-faster-with-bare-mode) or one you start with `--safe-mode`
137137* A session you start with a [`--setting-sources`](/docs/en/cli-reference#cli-flags) list that leaves out `user`
138138 
139139If you signed in on an earlier version of Claude Code, that sign-in doesn't cover plugins until Claude Code renews it in the background. To get access sooner, run `/login` again. Plugin sync then starts the next time you start Claude Code.
from line 143
143143You can turn synced plugins off one at a time, except a plugin your organization requires, or turn off every synced plugin on the machine:
144144 
145145* **One plugin**: `claude plugin disable <name>@synced` in your shell and the `/plugin` **Installed** tab in a session both save `"<name>@synced": false` in your user-level [`enabledPlugins`](/docs/en/settings-reference#enabledplugins). To keep the plugin out of a project in every environment, set the same key in the project's committed `.claude/settings.json`
146* **Every synced plugin on a machine**: set [`syncClaudeAiPlugins`](/docs/en/settings-reference#syncclaudeaiplugins) to `false` in your user settings, or your organization sets it in [managed settings](/docs/en/managed-settings). Claude Code stops downloading, and the next time you start it, it moves the plugins it already synced to `~/.claude/plugins/.trash/` and no longer loads them. If your organization turns off Skills on claude.ai, plugins stop syncing too
146* **Every synced plugin on a machine**: set [`syncClaudeAiPlugins`](/docs/en/settings-reference#syncclaudeaiplugins) to `false` in your user settings, or your organization sets it in [managed settings](/docs/en/managed-settings.md). Claude Code stops downloading, and the next time you start it, it moves the plugins it already synced to `~/.claude/plugins/.trash/` and no longer loads them. If your organization turns off Skills on claude.ai, plugins stop syncing too
147147* **A plugin your organization requires**: a plugin that your organization marks as required on claude.ai loads even if you disabled it earlier. `claude plugin disable` refuses it with `Plugin "<name>@synced" is required by your organization and can't be disabled here. Contact your admin to change it.`, and `claude plugin list` marks it `required by your org`
148148 
149For removing a plugin on claude.ai, see [Manage installed plugins](/docs/en/plugins/install#manage-installed-plugins).
149For removing a plugin on claude.ai, see [Manage installed plugins](/docs/en/plugins/install.md#manage-installed-plugins).
150150 
151151## Find where a plugin is enabled
152152 
153You can set an `enabledPlugins` entry in any of six sources. The table lists them from lowest precedence to highest, and who each one applies to. For the settings files themselves, see [Settings files and who they affect](/docs/en/settings#where-settings-live).
153You can set an `enabledPlugins` entry in any of six sources. The table lists them from lowest precedence to highest, and who each one applies to. For the settings files themselves, see [Settings files and who they affect](/docs/en/settings.md#where-settings-live).
154154 
155155| Source | Where you set it | Reaches |
156156| :- | :- | :- |
from line 159
159159| `project` | `.claude/settings.json` | Everyone who clones the repository |
160160| `local` | `.claude/settings.local.json` | You, in this repository only |
161161| `flag` | The `--settings` value you pass at launch | This session only |
162| `managed` | [Managed settings](/docs/en/managed-settings) | Every user the policy covers. `true` force-enables and `false` blocks, and no other source overrides them |
162| `managed` | [Managed settings](/docs/en/managed-settings.md) | Every user the policy covers. `true` force-enables and `false` blocks, and no other source overrides them |
163163 
164164These sources merge key by key. For each plugin id, the value that applies is the one from the highest-precedence source that mentions the id. A source that doesn't mention the id leaves the value from the lower-precedence source in effect.
165165 
from line 171
171171 
172172### Enabled in project settings but not installed
173173 
174When a plugin's only `true` is in the project's `.claude/settings.json`, Claude Code doesn't fetch it onto a machine where it isn't installed, unless its marketplace entry has a [relative-path source](/docs/en/plugins/marketplace-reference#plugin-sources) or a [seed directory](/docs/en/plugins/org#seed-containers-and-ci) already holds it. Instead, the `/plugin` **Errors** tab shows `Plugin "<name>" is enabled in project settings but isn't installed here`.
174When a plugin's only `true` is in the project's `.claude/settings.json`, Claude Code doesn't fetch it onto a machine where it isn't installed, unless its marketplace entry has a [relative-path source](/docs/en/plugins/marketplace-reference.md#plugin-sources) or a [seed directory](/docs/en/plugins/org.md#seed-containers-and-ci) already holds it. Instead, the `/plugin` **Errors** tab shows `Plugin "<name>" is enabled in project settings but isn't installed here`.
175175 
176176A relative-path plugin needs no install record because it loads from the marketplace itself.
177177 
from line 189
189189| Path | What it holds |
190190| :- | :- |
191191| `cache/<marketplace>/<plugin>/<version>/` | One directory per installed version of a marketplace plugin. `<plugin>` is the marketplace entry name and `<version>` is the [resolved version](#versions-and-updates). `${CLAUDE_PLUGIN_ROOT}` points at this directory |
192| `data/<plugin-id>/` | The plugin's persistent directory, exposed as `${CLAUDE_PLUGIN_DATA}`. For how `<plugin-id>` is formed, see [Path variables and persistent data](/docs/en/plugins/components#path-variables-and-persistent-data). Claude Code creates it when a plugin component first uses it and keeps it across updates. By default, Claude Code deletes it when you uninstall the plugin from its last scope. For `--keep-data` and the other cases where it stays, see [plugin uninstall](/docs/en/plugins/cli-reference#plugin-uninstall) |
192| `data/<plugin-id>/` | The plugin's persistent directory, exposed as `${CLAUDE_PLUGIN_DATA}`. For how `<plugin-id>` is formed, see [Path variables and persistent data](/docs/en/plugins/components.md#path-variables-and-persistent-data). Claude Code creates it when a plugin component first uses it and keeps it across updates. By default, Claude Code deletes it when you uninstall the plugin from its last scope. For `--keep-data` and the other cases where it stays, see [plugin uninstall](/docs/en/plugins/cli-reference.md#plugin-uninstall) |
193193| `marketplaces/<name>/` | The clone or download of a marketplace added from GitHub, another Git host, or a URL. A marketplace added from a local `file` or `directory` source has no copy here, and its `installLocation` in `known_marketplaces.json` is the path you gave |
194194| `synced/` | The plugins Claude Code [synced from your claude.ai account](#synced-plugins) |
195195| `.trash/` | Plugins that the claude.ai sync removed, such as after you turn one off on claude.ai or stop syncing |
196| `installed_plugins.json` and `known_marketplaces.json` | The records of what Claude Code has installed and which marketplaces it has fetched, described under [Check which stage a plugin reached](#check-which-stage-a-plugin-reached). A [marketplace hosted on claude.ai](/docs/en/plugins/install#add-from-claude-ai) is recorded in `known_marketplaces_claudeai.json` instead |
197| `flagged-plugins.json` | Plugins Claude Code uninstalled because their marketplace delisted them. They appear in the **Flagged** section of `/plugin`; see [Host a marketplace](/docs/en/plugins/host-marketplace) |
198| `installed_plugins.set-aside.<date>.<hash>.json` and `installed_plugins.unreadable.<date>.<hash>.kept` | Dated copies Claude Code keeps before it drops install records that no version of Claude Code can use or rebuilds an unreadable `installed_plugins.json`. See [the recovery notes](/docs/en/plugins/troubleshooting#installed-plugins-json-could-not-be-read-and-was-rebuilt). They age out on the [`cleanupPeriodDays`](/docs/en/settings-reference#cleanupperioddays) schedule |
196| `installed_plugins.json` and `known_marketplaces.json` | The records of what Claude Code has installed and which marketplaces it has fetched, described under [Check which stage a plugin reached](#check-which-stage-a-plugin-reached). A [marketplace hosted on claude.ai](/docs/en/plugins/install.md#add-from-claude-ai) is recorded in `known_marketplaces_claudeai.json` instead |
197| `flagged-plugins.json` | Plugins Claude Code uninstalled because their marketplace delisted them. They appear in the **Flagged** section of `/plugin`; see [Host a marketplace](/docs/en/plugins/host-marketplace.md) |
198| `installed_plugins.set-aside.<date>.<hash>.json` and `installed_plugins.unreadable.<date>.<hash>.kept` | Dated copies Claude Code keeps before it drops install records that no version of Claude Code can use or rebuilds an unreadable `installed_plugins.json`. See [the recovery notes](/docs/en/plugins/troubleshooting.md#installed-plugins-json-could-not-be-read-and-was-rebuilt). They age out on the [`cleanupPeriodDays`](/docs/en/settings-reference#cleanupperioddays) schedule |
199199 
200200Because `${CLAUDE_PLUGIN_ROOT}` points at a version directory, a plugin's root path changes with every version. Keep a plugin's durable files in `${CLAUDE_PLUGIN_DATA}` instead.
201201 
from line 205
205205 
206206* **`--plugin-dir` and skills-directory plugins**: the directory loads in place and is never copied. A `--plugin-url` archive or a `--plugin-dir` `.zip` is extracted into a session temp directory first
207207* **Relative-path plugins in a marketplace you added from a local path**: the plugin loads in place from its path inside the marketplace folder. Your edits to the source directory take effect at the next session start or `/reload-plugins`, and you don't need to increase the version. The plugin's hook processes and MCP and LSP servers receive a `CLAUDE_PLUGIN_ROOT` that points at the source directory. For its Node.js package dependencies, see [When the dependency install runs](#when-the-dependency-install-runs)
208* **`command`-source plugins in [link mode](/docs/en/plugins/marketplace-reference#command-plugin-source)**: the directory the command printed loads in place, through links in the cache entry
208* **`command`-source plugins in [link mode](/docs/en/plugins/marketplace-reference.md#command-plugin-source)**: the directory the command printed loads in place, through links in the cache entry
209209* **Every other marketplace plugin**: Claude Code copies the plugin into `cache/<marketplace>/<plugin>/<version>/` at install and loads that copy. Files outside the plugin directory aren't copied, so when a script inside a copied plugin reads a path above the plugin root, such as `../shared`, it doesn't find them
210210 
211211### Paths that escape the plugin directory
from line 213
213213Whether a plugin loads in place or from a cached copy, Claude Code doesn't let it declare components 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:
214214 
215215* **A path that points outside the plugin as written**, such as `../shared-utils`
216* **A symlink that leads outside the plugin**, other than [links between plugins within one marketplace](/docs/en/plugins/host-marketplace#share-files-within-a-marketplace-with-symlinks)
216* **A symlink that leads outside the plugin**, other than [links between plugins within one marketplace](/docs/en/plugins/host-marketplace.md#share-files-within-a-marketplace-with-symlinks)
217217* **On macOS and Linux, a 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, so write component paths with forward slashes, such as `./commands/deploy.md`
218218 
219219A rejected path appears as a [`path escapes plugin directory`](/docs/en/errors#path-escapes-plugin-directory) error, and the plugin loads without that component.
from line 228
228228 
229229When 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.
230230 
231This 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/plugins/dependencies).
231This 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/plugins/dependencies.md).
232232 
233233#### When the dependency install runs
234234 
from line 273
273273* **No overrides or patches**: a plugin whose `package.json` sets npm `overrides` gets no install from an npm lockfile, and a plugin that sets Bun `patchedDependencies` gets no install from `bun.lock`
274274* **60-second timeout**: Claude Code stops an install that runs longer and treats it as failed
275275 
276Claude 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 plugin source](/docs/en/plugins/marketplace-reference#npm-plugin-source).
276Claude 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 plugin source](/docs/en/plugins/marketplace-reference.md#npm-plugin-source).
277277 
278278You can't turn the automatic install off. No setting or environment variable disables it.
279279 
280In restricted networks, see the [network access requirements](/docs/en/network-config#network-access-requirements) for the hosts to allow.
280In restricted networks, see the [network access requirements](/docs/en/network-config.md#network-access-requirements) for the hosts to allow.
281281 
282282#### When the dependency install fails or is skipped
283283 
284284If the install fails or is skipped, the plugin still loads, but the parts of it that need the missing packages may not work.
285285 
286`/plugin` and `claude plugin list` show a note on an enabled plugin whose cached copy has a lockfile and a `package.json` that lists runtime dependencies, but no `node_modules` directory. The note says whether the install didn't finish or can't run for this plugin. See [the troubleshooting entry](/docs/en/plugins/troubleshooting#the-packages-it-lists-are-not-installed) for what to do about each.
286`/plugin` and `claude plugin list` show a note on an enabled plugin whose cached copy has a lockfile and a `package.json` that lists runtime dependencies, but no `node_modules` directory. The note says whether the install didn't finish or can't run for this plugin. See [the troubleshooting entry](/docs/en/plugins/troubleshooting.md#the-packages-it-lists-are-not-installed) for what to do about each.
287287 
288When the automatic install can't provide a dependency, install it from a hook into the [persistent data directory](/docs/en/plugins/components#path-variables-and-persistent-data). That includes packages that need their lifecycle scripts to build, Python dependencies, plugins locked with Yarn or pnpm, and dependencies that aren't registry packages, such as git dependencies.
288When the automatic install can't provide a dependency, install it from a hook into the [persistent data directory](/docs/en/plugins/components.md#path-variables-and-persistent-data). That includes packages that need their lifecycle scripts to build, Python dependencies, plugins locked with Yarn or pnpm, and dependencies that aren't registry packages, such as git dependencies.
289289 
290290## Versions and updates
291291 
292292If a plugin's author pushed new commits and `claude plugin update` prints `<name> is already at the latest version (<version>).`, the version Claude Code computes for the plugin is unchanged, so the plugin's files on disk don't change.
293293 
294Claude Code computes a version for every plugin it installs, and that version is how it detects an update. `claude plugin update` and background auto-update compute the version again and don't replace the cached copy when it matches what `installed_plugins.json` records. An update that you start can still [retry an unfinished dependency install](/docs/en/plugins/troubleshooting#the-packages-it-lists-are-not-installed) in that copy.
294Claude Code computes a version for every plugin it installs, and that version is how it detects an update. `claude plugin update` and background auto-update compute the version again and don't replace the cached copy when it matches what `installed_plugins.json` records. An update that you start can still [retry an unfinished dependency install](/docs/en/plugins/troubleshooting.md#the-packages-it-lists-are-not-installed) in that copy.
295295 
296296The version also names the plugin's cache directory.
297297 
298298A manifest that pins `"version"` is one way the computed version stays the same across commits. See [How Claude Code computes the version](#how-claude-code-computes-the-version) for the resolution order.
299299 
300A plugin [loaded in place](#in-place-and-copied-plugins) from a marketplace you added from a local path loads its current source files at every session start, whatever its version string says. For a plugin from a [marketplace hosted on claude.ai](/docs/en/plugins/install#add-from-claude-ai), the version claude.ai records for the plugin is its version, and the manifest's `version` isn't read.
300A plugin [loaded in place](#in-place-and-copied-plugins) from a marketplace you added from a local path loads its current source files at every session start, whatever its version string says. For a plugin from a [marketplace hosted on claude.ai](/docs/en/plugins/install.md#add-from-claude-ai), the version claude.ai records for the plugin is its version, and the manifest's `version` isn't read.
301301 
302302### How Claude Code computes the version
303303 
304For a marketplace you added by source, Claude Code picks the rule by the `source` type of the plugin's marketplace entry. The [marketplace reference](/docs/en/plugins/marketplace-reference#plugin-sources) lists the source types. For every source type in that list except `command`:
304For a marketplace you added by source, Claude Code picks the rule by the `source` type of the plugin's marketplace entry. The [marketplace reference](/docs/en/plugins/marketplace-reference.md#plugin-sources) lists the source types. For every source type in that list except `command`:
305305 
3063061. The `version` field in the plugin's manifest comes first
3073072. Then the `version` field in the plugin's marketplace entry
from line 317
317317 
318318Claude Code doesn't take the version from a repository that encloses the install path, such as a git-managed `~/.claude`.
319319 
320For a `command` source, Claude Code always derives the version from what the command produced: a 12-character hash on its own, or `<manifest version>-<hash>` when the manifest sets one. The marketplace entry's `version` is ignored for command sources. For what the hash covers, see [Copy mode and link mode](/docs/en/plugins/marketplace-reference#copy-mode-and-link-mode).
320For a `command` source, Claude Code always derives the version from what the command produced: a 12-character hash on its own, or `<manifest version>-<hash>` when the manifest sets one. The marketplace entry's `version` is ignored for command sources. For what the hash covers, see [Copy mode and link mode](/docs/en/plugins/marketplace-reference.md#copy-mode-and-link-mode).
321321 
322Because the manifest comes first, a manifest that pins `"version": "1.0.0"` keeps every user on the cached copy until its author changes the string, however many commits they push. To let users track commits instead, leave `version` out of both the manifest and the entry. [Host a marketplace](/docs/en/plugins/host-marketplace) covers which choice fits which release setup.
322Because the manifest comes first, a manifest that pins `"version": "1.0.0"` keeps every user on the cached copy until its author changes the string, however many commits they push. To let users track commits instead, leave `version` out of both the manifest and the entry. [Host a marketplace](/docs/en/plugins/host-marketplace.md) covers which choice fits which release setup.
323323 
324324### When Claude Code refreshes a marketplace before an install
325325 
from line 338
338338Claude Code skips the refresh before a `name@marketplace` install when:
339339 
340340* The marketplace was added from a local `file` or `directory` source, or is defined inline in settings with a [`settings` source](/docs/en/settings-reference#extraknownmarketplaces)
341* A [seed directory](/docs/en/env-vars) supplies the marketplace
341* A [seed directory](/docs/en/env-vars.md) supplies the marketplace
342342* Claude Code refreshed the marketplace within the last 30 seconds
343343* You set `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC`
344* [Managed settings](/docs/en/plugins/org#restrict-what-users-can-install) block the marketplace, in which case Claude Code also refuses the install
344* [Managed settings](/docs/en/plugins/org.md#restrict-what-users-can-install) block the marketplace, in which case Claude Code also refuses the install
345345 
346346### When auto-update runs
347347 
from line 355
355355 
3563561. **`autoUpdate` on its `extraKnownMarketplaces` entry** in a settings file
3573572. **`autoUpdate` on its `known_marketplaces.json` entry**, which the **Enable auto-update** toggle under `/plugin` **Marketplaces** writes. When a settings file also declares the marketplace under `extraKnownMarketplaces`, the toggle writes `autoUpdate` to that settings entry as well
3583. **The default**: on for Anthropic's official marketplaces such as `claude-plugins-official`, off for `knowledge-work-plugins` and `first-party-plugins`, on for [marketplaces added from claude.ai](/docs/en/plugins/install#add-from-claude-ai), and off for every other marketplace
3583. **The default**: on for Anthropic's official marketplaces such as `claude-plugins-official`, off for `knowledge-work-plugins` and `first-party-plugins`, on for [marketplaces added from claude.ai](/docs/en/plugins/install.md#add-from-claude-ai), and off for every other marketplace
359359 
360If you set `DISABLE_UPDATES=1`, `DISABLE_AUTOUPDATER=1`, or `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1`, the whole pass is off and the **Enable auto-update** toggle is hidden, unless you also set `FORCE_AUTOUPDATE_PLUGINS=1`. The [environment variables reference](/docs/en/env-vars) covers each variable's wider effect.
360If you set `DISABLE_UPDATES=1`, `DISABLE_AUTOUPDATER=1`, or `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1`, the whole pass is off and the **Enable auto-update** toggle is hidden, unless you also set `FORCE_AUTOUPDATE_PLUGINS=1`. The [environment variables reference](/docs/en/env-vars.md) covers each variable's wider effect.
361361 
362Auto-update also skips a plugin whose marketplace entry declares a `headersHelper`. [Installs and updates that refuse a command instead of asking](/docs/en/plugins/host-marketplace#installs-and-updates-that-refuse-the-command-instead-of-asking) explains when such a plugin appears in the `/plugin` **Errors** tab and how you update it from there.
362Auto-update also skips a plugin whose marketplace entry declares a `headersHelper`. [Installs and updates that refuse a command instead of asking](/docs/en/plugins/host-marketplace.md#installs-and-updates-that-refuse-the-command-instead-of-asking) explains when such a plugin appears in the `/plugin` **Errors** tab and how you update it from there.
363363 
364364When 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.
365365 
366366### When a command source re-runs
367367 
368Plugins with a `command` source don't wait for the [auto-update pass](#when-auto-update-runs). The printed directory reflects the tool's state at the time the command ran, so Claude Code runs the [command you accepted](/docs/en/plugins/host-marketplace#change-the-command-of-a-command-source) again at these times:
368Plugins with a `command` source don't wait for the [auto-update pass](#when-auto-update-runs). The printed directory reflects the tool's state at the time the command ran, so Claude Code runs the [command you accepted](/docs/en/plugins/host-marketplace.md#change-the-command-of-a-command-source) again at these times:
369369 
370370* Every time you install or update the plugin
371371* Once per session for each enabled command-sourced plugin, in the background, shortly after the session starts. This run doesn't depend on the marketplace's auto-update setting or on `DISABLE_AUTOUPDATER`
from line 393
393393 
394394### Hooks when two enabled plugins share a name
395395 
396When you install and enable two plugins with the same manifest name from different marketplaces, both appear as enabled in `/plugin`, but the hooks of one of them are left out. One plugin per name registers the hooks in its `hooks/hooks.json`, and one plugin per name loads a [hooks module](/docs/en/plugins/mods/overview). When your organization's managed settings turn on one of the copies, that copy holds the name. Otherwise the copy Claude Code loads first holds it.
396When you install and enable two plugins with the same manifest name from different marketplaces, both appear as enabled in `/plugin`, but the hooks of one of them are left out. One plugin per name registers the hooks in its `hooks/hooks.json`, and one plugin per name loads a [hooks module](/docs/en/plugins/mods/overview.md). When your organization's managed settings turn on one of the copies, that copy holds the name. Otherwise the copy Claude Code loads first holds it.
397397 
398398To see which copy holds the name, run `/plugin` in your session and open the **Errors** tab. A note there for the copy whose hooks were left out names the copy that holds the name, and the left-out copy's details show the same note. For `hooks/hooks.json` hooks the note begins `Its hooks.json hooks do not run`, and for a hooks module it begins `Its hooks module does not load`. The note requires Claude Code v2.1.296 or later.
399399 
from line 405
405405 
406406## Next steps
407407 
408* [Install and manage plugins](/docs/en/plugins/install): the install, enable, disable, and update steps themselves
409* [Troubleshoot plugins](/docs/en/plugins/troubleshooting): error messages by the stage that produces them
410* [Plugin commands reference](/docs/en/plugins/cli-reference): the flags and commands named on this page
411* [Manage plugins for your organization](/docs/en/plugins/org): the managed settings that force-enable or block plugins
408* [Install and manage plugins](/docs/en/plugins/install.md): the install, enable, disable, and update steps themselves
409* [Troubleshoot plugins](/docs/en/plugins/troubleshooting.md): error messages by the stage that produces them
410* [Plugin commands reference](/docs/en/plugins/cli-reference.md): the flags and commands named on this page
411* [Manage plugins for your organization](/docs/en/plugins/org.md): the managed settings that force-enable or block plugins
412412 

plugins/manifest-reference Changed · +37 / -35 lines

from line 10
1010>
1111> These cases are covered on other pages:
1212>
13> * **Learning to build a plugin**: start with [Create a plugin](/docs/en/plugins/create)
14> * **What each component does at runtime**: see [Plugin components](/docs/en/plugins/components)
13> * **Learning to build a plugin**: start with [Create a plugin](/docs/en/plugins/create.md)
14> * **What each component does at runtime**: see [Plugin components](/docs/en/plugins/components.md)
1515 
1616Start at the section that matches what you're looking up:
1717 
from line 19
1919* A `userConfig` option or a `channels` entry: the [User configuration](#user-configuration) and [Channels](#channels) schemas
2020* `${CLAUDE_PLUGIN_ROOT}` or another variable a plugin can reference: [Environment variables](#environment-variables)
2121* Where each component's files go: [Standard layout](#standard-layout)
22* A message from `claude plugin validate`: the [troubleshooting page](/docs/en/plugins/troubleshooting) lists each message with its fix and links to the relevant sections on this page
22* A message from `claude plugin validate`: the [troubleshooting page](/docs/en/plugins/troubleshooting.md) lists each message with its fix and links to the relevant sections on this page
2323 
2424## Manifest file
2525 
from line 139
139139| [`dependencies`](#dependencies) | Array of strings or objects | Plugins that must be enabled for this one to work |
140140| [`settings`](#settings) | Object | Settings Claude Code applies while the plugin is enabled. Only `agent` and `subagentStatusLine` take effect |
141141| [`userConfig`](#user-configuration) | Object | Values Claude Code prompts the user for when the plugin is enabled |
142| `types` | Path | A `.d.ts` file that declares the `$.state` values and `$` nouns of a [mod](/docs/en/plugins/mods/reference#files) |
142| `types` | Path | A `.d.ts` file that declares the `$.state` values and `$` nouns of a [mod](/docs/en/plugins/mods/reference.md#files) |
143143| [`channels`](#channels) | Array of objects | Message channels the plugin provides, each bound to one of its MCP servers |
144144| `skills` | Path, or array of paths | Directories to scan for skills, each a directory of `<name>/SKILL.md` folders or one folder holding `SKILL.md` directly. `"."` names the plugin root. Adds to the default `skills/` scan |
145145| [`commands`](#commands) | Path, array of paths, or object | Flat `.md` command files, directories of them, or an object map of command name to `source` or `content`. Replaces the default `commands/` scan |
from line 148
148148| [`mcpServers`](#mcpservers) | Path, object, or array of either | `.json` MCP config files, `.mcpb` or `.dxt` bundles, or inline server configs keyed by name. Loaded together with `.mcp.json`; a server name declared later replaces an earlier one |
149149| [`lspServers`](#lspservers) | Path, object, or array of either | `.json` LSP config files or inline server configs keyed by name. Loaded together with `.lsp.json` |
150150| `outputStyles` | Path, or array of paths | Output style files or directories. Replaces the default `output-styles/` scan |
151| `workflows` | Path, or array of paths | [Workflow](/docs/en/workflows#distribute-a-workflow-in-a-plugin) `.js` files or directories. Replaces the default `workflows/` scan |
151| `workflows` | Path, or array of paths | [Workflow](/docs/en/workflows.md#distribute-a-workflow-in-a-plugin) `.js` files or directories. Replaces the default `workflows/` scan |
152152| `experimental` | Object | Container for `themes`, `monitors`, and `evals`, whose manifest shape may still change |
153153| `experimental.themes` | Path, or array of paths | Theme files or directories. Replaces the default `themes/` scan. A top-level `themes` key still loads, with a `claude plugin validate` warning |
154154| [`experimental.monitors`](#monitors) | Path, or inline array | A `.json` file holding the monitors array, or the array itself. Defaults to `monitors/monitors.json`. A top-level `monitors` key still loads, with a `claude plugin validate` warning. Monitors run only in interactive sessions, and not on Amazon Bedrock, Google Cloud's Agent Platform, or Microsoft Foundry |
155| `experimental.evals` | Path, or array of paths | Directory 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 |
155| `experimental.evals` | Path, or array of paths | Directory that holds the plugin's [eval cases](/docs/en/plugin-evals.md#use-a-different-eval-directory) when it isn't the default `evals/`. `claude plugin eval --eval-dir` overrides it |
156156 
157157In the Type column, a path is a string relative to the plugin root, such as `"./custom/commands"`.
158158 
from line 177
177177 
178178The name shown in UI in place of `name`. It may contain spaces and any casing, and it isn't used for namespacing or lookup.
179179 
180For a marketplace-installed plugin, a `displayName` on the [marketplace entry](/docs/en/plugins/marketplace-reference#plugin-entries) takes precedence over this value.
180For a marketplace-installed plugin, a `displayName` on the [marketplace entry](/docs/en/plugins/marketplace-reference.md#plugin-entries) takes precedence over this value.
181181 
182182### `version`
183183 
184A version string, not checked against semver. Setting it pins the plugin to that version until you change it; see [Versions and updates](/docs/en/plugins/loading#versions-and-updates). A plugin with a [`command` source](/docs/en/plugins/marketplace-reference), a plugin from a [marketplace hosted on claude.ai](/docs/en/plugins/install#add-from-claude-ai), and a plugin [loaded in place](/docs/en/plugins/loading#find-plugins-on-disk) from a marketplace added from a local path aren't pinned by this field.
184A version string, not checked against semver. Setting it pins the plugin to that version until you change it; see [Versions and updates](/docs/en/plugins/loading.md#versions-and-updates). A plugin with a [`command` source](/docs/en/plugins/marketplace-reference), a plugin from a [marketplace hosted on claude.ai](/docs/en/plugins/install.md#add-from-claude-ai), and a plugin [loaded in place](/docs/en/plugins/loading.md#find-plugins-on-disk) from a marketplace added from a local path aren't pinned by this field.
185185 
186186### `metadata`
187187 
from line 189
189189 
190190### Directory listing fields
191191 
192Anthropic's directory reads the `icon`, `documentationUrl`, `supportUrl`, `privacyPolicyUrl`, and `termsOfServiceUrl` fields from `plugin.json` for your plugin's listing when you [submit the plugin](/docs/en/plugins/publish#submit-to-anthropics-directory). Claude Code ignores them at load time. Set them only in `plugin.json`. In a [marketplace entry](#marketplace-entries-and-the-manifest), `claude plugin validate` reports each one as an unknown field.
192Anthropic's directory reads the `icon`, `documentationUrl`, `supportUrl`, `privacyPolicyUrl`, and `termsOfServiceUrl` fields from `plugin.json` for your plugin's listing when you [submit the plugin](/docs/en/plugins/publish.md#submit-to-anthropics-directory). Claude Code ignores them at load time. Set them only in `plugin.json`. In a [marketplace entry](#marketplace-entries-and-the-manifest), `claude plugin validate` reports each one as an unknown field.
193193 
194194Set `icon` to the path of an image file inside the plugin, such as `./logo.png`, and each of the four URL fields to an `https://` URL.
195195 
196`claude plugin validate` accepts these fields without a warning on Claude Code v2.1.281 or later. Earlier versions print an `Unknown field` warning for each one, so a `--strict` run fails on those versions.
196> [!NOTE]
197>
198> `claude plugin validate` doesn't report these fields in `plugin.json` as unknown on Claude Code v2.1.281 or later. Earlier versions print an `Unknown field` warning for each one, so a `--strict` run fails on those versions.
197199 
198200### `defaultEnabled`
199201 
from line 205
203205 
204206### `dependencies`
205207 
206Plugins that must be enabled for this one to work. Each entry is `"name"`, `"name@marketplace"`, or `{ "name": "...", "marketplace": "...", "version": "..." }`. Bare names resolve against this plugin's own marketplace. See [dependency constraints](/docs/en/plugins/dependencies).
208Plugins that must be enabled for this one to work. Each entry is `"name"`, `"name@marketplace"`, or `{ "name": "...", "marketplace": "...", "version": "..." }`. Bare names resolve against this plugin's own marketplace. See [dependency constraints](/docs/en/plugins/dependencies.md).
207209 
208210### `settings`
209211 
210Settings Claude Code applies while the plugin is enabled. Only `agent` and `subagentStatusLine` take effect; other keys are dropped at load. A `settings.json` at the plugin root takes precedence over this key. See [Default settings](/docs/en/plugins/components#default-settings).
212Settings Claude Code applies while the plugin is enabled. Only `agent` and `subagentStatusLine` take effect; other keys are dropped at load. A `settings.json` at the plugin root takes precedence over this key. See [Default settings](/docs/en/plugins/components.md#default-settings).
211213 
212214## Component path forms
213215 
214Every component key accepts a path relative to the plugin root. `hooks`, `mcpServers`, `lspServers`, and `experimental.monitors` also accept inline configuration, `commands` also accepts an object map, and `mcpServers` also accepts MCP bundle paths and URLs. The examples that follow show each accepted shape once. For what each component does at runtime, see [Plugin components](/docs/en/plugins/components).
216Every component key accepts a path relative to the plugin root. `hooks`, `mcpServers`, `lspServers`, and `experimental.monitors` also accept inline configuration, `commands` also accepts an object map, and `mcpServers` also accepts MCP bundle paths and URLs. The examples that follow show each accepted shape once. For what each component does at runtime, see [Plugin components](/docs/en/plugins/components.md).
215217 
216218### Path-only fields
217219 
from line 255
253255 
254256### `hooks`
255257 
256`hooks` takes a `.json` file path, an inline hooks object in the same shape as [`hooks` in `settings.json`](/docs/en/hooks#configuration), or an array mixing both. For hook events and handler fields, see the [hooks reference](/docs/en/hooks#hook-events).
258`hooks` takes a `.json` file path, an inline hooks object in the same shape as [`hooks` in `settings.json`](/docs/en/hooks#configuration), or an array mixing both. For hook events and handler fields, see the [hooks reference](/docs/en/hooks.md#hook-events).
257259 
258260A hooks file wraps the event map in a top-level `"hooks"` key, the shape [`hooks/hooks.json`](/docs/en/plugins/components#hooks) uses. A file that contains only the event map, without that wrapper, fails to load. An inline object is the event map itself, with no wrapper.
259261 
from line 298
296298 
297299### `mcpServers`
298300 
299`mcpServers` takes a `.json` file path, an MCP bundle path or URL, an inline map, or an array mixing them. For server config fields, see [plugin-provided MCP servers](/docs/en/mcp#plugin-provided-mcp-servers).
301`mcpServers` takes a `.json` file path, an MCP bundle path or URL, an inline map, or an array mixing them. For server config fields, see [plugin-provided MCP servers](/docs/en/mcp.md#plugin-provided-mcp-servers).
300302 
301303Claude Code loads `.mcp.json` at the plugin root first, then each declared shape in order. A server name declared later replaces an earlier one.
302304 
from line 352
350352}
351353```
352354 
353For the language servers Anthropic publishes as plugins and how the servers behave at runtime, see [Code intelligence](/docs/en/plugins/code-intelligence).
355For the language servers Anthropic publishes as plugins and how the servers behave at runtime, see [Code intelligence](/docs/en/plugins/code-intelligence.md).
354356 
355357### `monitors`
356358 
from line 393
391393* **`skills`**: also accepts `"."`. Both `"."` and `"./"` denote the plugin root. Before v2.1.221, `"."` failed manifest validation, so use `"./"` when the plugin must load on earlier versions
392394* **`mcpServers`**: also accepts an `https://` bundle URL
393395 
394`experimental.evals` isn't a component path, so the rules in this section don't cover it, and `claude plugin eval` checks the value when it runs instead. It names a directory below the plugin root, such as `"quality/evals"`, with or without the `./` prefix. With an array, only the first entry is used. For what the value accepts and what happens with an unusable one, see [Use a different eval directory](/docs/en/plugin-evals#use-a-different-eval-directory).
396`experimental.evals` isn't a component path, so the rules in this section don't cover it, and `claude plugin eval` checks the value when it runs instead. It names a directory below the plugin root, such as `"quality/evals"`, with or without the `./` prefix. With an array, only the first entry is used. For what the value accepts and what happens with an unusable one, see [Use a different eval directory](/docs/en/plugin-evals.md#use-a-different-eval-directory).
395397 
396398### Containment and existence
397399 
from line 484
482484 
483485### Where values are stored
484486 
485Non-sensitive values are saved under [`pluginConfigs`](/docs/en/settings-reference#pluginconfigs) in the user's `settings.json`. Sensitive values go to the platform's secure credential store instead. The [settings page](/docs/en/settings-reference#pluginconfigs) lists which settings files `pluginConfigs` is read from.
487Non-sensitive values are saved under [`pluginConfigs`](/docs/en/settings-reference#pluginconfigs) in the user's `settings.json`. Sensitive values go to the platform's secure credential store instead. The [settings page](/docs/en/settings-reference.md#pluginconfigs) lists which settings files `pluginConfigs` is read from.
486488 
487489### Reference a saved value
488490 
489491Reference a saved value where the plugin needs it, in one of two forms:
490492 
491* **`${user_config.KEY}`**: substituted in MCP server config, LSP server config, [exec-form](/docs/en/hooks#exec-form-and-shell-form) hook `args`, and skill and agent content. In skill and agent content, only non-sensitive values are substituted, and a sensitive value there becomes a placeholder
493* **`${user_config.KEY}`**: substituted in MCP server config, LSP server config, [exec-form](/docs/en/hooks.md#exec-form-and-shell-form) hook `args`, and skill and agent content. In skill and agent content, only non-sensitive values are substituted, and a sensitive value there becomes a placeholder
492494* **`CLAUDE_PLUGIN_OPTION_<KEY>`**: exported to hook processes for every option, with `<KEY>` uppercased. A shell-form hook reads `$CLAUDE_PLUGIN_OPTION_API_TOKEN` for `api_token`
493495 
494496### Fields that run through a shell
495497 
496Shell-form hook commands, monitor commands, and MCP [`headersHelper`](/docs/en/mcp#use-dynamic-headers-for-custom-authentication) reject `${user_config.*}`. A component that references it in one of these fields fails with an [error](/docs/en/errors#plugin-command-references-user-config) instead of running, because the field's value is passed to a shell that would re-parse the substituted value.
498Shell-form hook commands, monitor commands, and MCP [`headersHelper`](/docs/en/mcp#use-dynamic-headers-for-custom-authentication) reject `${user_config.*}`. A component that references it in one of these fields fails with an [error](/docs/en/errors.md#plugin-command-references-user-config) instead of running, because the field's value is passed to a shell that would re-parse the substituted value.
497499 
498500The table shows how the value can reach each of these fields instead.
499501 
500502| Field | How the value can reach it |
501503| :- | :- |
502| 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 |
504| Shell-form hook commands | Use [exec form](/docs/en/hooks.md#exec-form-and-shell-form) with `args`, or read `CLAUDE_PLUGIN_OPTION_<KEY>` from the hook's environment |
503505| Monitor commands | Not through Claude Code. Monitor processes don't receive `CLAUDE_PLUGIN_OPTION_<KEY>`, so the monitor script has to obtain the value on its own |
504506| MCP `headersHelper` | Not through Claude Code. The helper's environment carries `CLAUDE_PLUGIN_ROOT`, `CLAUDE_CODE_MCP_SERVER_NAME`, and `CLAUDE_CODE_MCP_SERVER_URL` but no option values, so the helper script has to obtain the value on its own |
505507 
506508## Channels
507509 
508`channels` declares the message channels a plugin provides, such as a bridge to a chat app. When you declare one, Claude Code can prompt for the channel's configuration when the plugin is enabled. For how the server injects messages, see the [channels reference](/docs/en/channels-reference#package-as-a-plugin).
510`channels` declares the message channels a plugin provides, such as a bridge to a chat app. When you declare one, Claude Code can prompt for the channel's configuration when the plugin is enabled. For how the server injects messages, see the [channels reference](/docs/en/channels-reference.md#package-as-a-plugin).
509511 
510512Each entry is a strict object bound to one of the plugin's MCP servers, with these fields:
511513 
from line 555
553555| `${CLAUDE_PLUGIN_DATA}` | `~/.claude/plugins/data/<id>/`, created on first reference and kept across plugin updates. `<id>` is the plugin identifier with every character other than a letter, digit, `_`, or `-` replaced by `-` | Installed dependencies such as `node_modules`, generated code, and caches |
554556| `${CLAUDE_PROJECT_DIR}` | The project root | Project-local scripts and config files |
555557 
556`${CLAUDE_PLUGIN_ROOT}` changes when the plugin updates, so don't write state there. For where the root moves and when the old directory is cleaned up, see the [loading page](/docs/en/plugins/loading).
558`${CLAUDE_PLUGIN_ROOT}` changes when the plugin updates, so don't write state there. For where the root moves and when the old directory is cleaned up, see the [loading page](/docs/en/plugins/loading.md).
557559 
558By default, Claude Code deletes the `${CLAUDE_PLUGIN_DATA}` directory when you uninstall the plugin from the last place it's installed. For `--keep-data` and the other cases where it stays, see [plugin uninstall](/docs/en/plugins/cli-reference#plugin-uninstall).
560By default, Claude Code deletes the `${CLAUDE_PLUGIN_DATA}` directory when you uninstall the plugin from the last place it's installed. For `--keep-data` and the other cases where it stays, see [plugin uninstall](/docs/en/plugins/cli-reference.md#plugin-uninstall).
559561 
560562### Where each variable resolves
561563 
from line 578
576578 
577579Keep each substituted path a single argument:
578580 
579* **Hook commands**: use [exec form](/docs/en/hooks#exec-form-and-shell-form) with `args` so each path is one argument with no quoting
581* **Hook commands**: use [exec form](/docs/en/hooks.md#exec-form-and-shell-form) with `args` so each path is one argument with no quoting
580582* **Shell-form hooks and monitor commands**: wrap the variable in double quotes so a path with spaces stays one word
581583 
582584If you leave one of these variables outside quotes in a shell-form command in a hooks file, `claude plugin validate` warns about it unless the hook sets [`shell`](/docs/en/hooks#command-hook-fields) to `"powershell"`.
from line 613
611613| Manifest | `.claude-plugin/plugin.json` | Plugin metadata and configuration. Optional |
612614| Skills | `skills/` | One `<name>/SKILL.md` per skill. A plugin with `SKILL.md` at its root, no `skills/`, and no `skills` key loads as a single skill |
613615| Commands | `commands/` | Flat Markdown command files. Prefer `skills/` for new plugins |
614| Agents | `agents/` | Agent Markdown files. Subfolders are part of the [agent name](/docs/en/plugins/components#agents) |
616| Agents | `agents/` | Agent Markdown files. Subfolders are part of the [agent name](/docs/en/plugins/components.md#agents) |
615617| Hooks | `hooks/hooks.json` | Hook configuration |
616618| MCP servers | `.mcp.json` | MCP server definitions |
617619| LSP servers | `.lsp.json` | LSP server configurations |
from line 656
654656└── .lsp.json
655657```
656658 
657To click through this layout and read what each file does, open the [plugin explorer](/docs/en/plugins/components#explore-the-plugin-directory).
659To click through this layout and read what each file does, open the [plugin explorer](/docs/en/plugins/components.md#explore-the-plugin-directory).
658660 
659661A `CLAUDE.md` at the plugin root isn't loaded as context, and `claude plugin validate` warns when it finds one. To include instructions that load into Claude's context, put them in a skill.
660662 
661663## Marketplace entries and the manifest
662664 
663A [marketplace entry](/docs/en/plugins/marketplace-reference) accepts [its own fields](/docs/en/plugins/marketplace-reference#plugin-entries), including `strict`, and every field on this page except the [directory listing fields](#directory-listing-fields).
665A [marketplace entry](/docs/en/plugins/marketplace-reference.md) accepts [its own fields](/docs/en/plugins/marketplace-reference.md#plugin-entries), including `strict`, and every field on this page except the [directory listing fields](#directory-listing-fields).
664666 
665667The `strict` field decides whether the entry may add components to a plugin that has its own `plugin.json`. It defaults to `true`.
666668 
from line 680
678680 
679681Some metadata fields have a fixed precedence regardless of `strict`:
680682 
681* **`defaultEnabled` and display fields**: the entry's `defaultEnabled` and its [display fields](/docs/en/plugins/marketplace-reference#entry-and-plugin-json) such as `displayName` override the manifest's
683* **`defaultEnabled` and display fields**: the entry's `defaultEnabled` and its [display fields](/docs/en/plugins/marketplace-reference.md#entry-and-plugin-json) such as `displayName` override the manifest's
682684* **`version`**: the manifest's `version` overrides the entry's
683685* **`name`**: when the entry lists the plugin under a different `name` than the manifest, `enabledPlugins` uses the entry name, and components are namespaced under the manifest name
684686 
685For the full precedence table, see [Strict mode](/docs/en/plugins/marketplace-reference).
687For the full precedence table, see [Strict mode](/docs/en/plugins/marketplace-reference.md).
686688 
687689## Next steps
688690 
689* [Add components to a plugin](/docs/en/plugins/components): what each component does at runtime, with an example that validates
690* [Marketplace reference](/docs/en/plugins/marketplace-reference): the entry fields a marketplace can set for your plugin
691* [Plugin commands reference](/docs/en/plugins/cli-reference#plugin-validate): `claude plugin validate` flags and output
692* [Troubleshoot plugins](/docs/en/plugins/troubleshooting#claude-plugin-validate-reports-errors): each validation message with its fix
691* [Add components to a plugin](/docs/en/plugins/components.md): what each component does at runtime, with an example that validates
692* [Marketplace reference](/docs/en/plugins/marketplace-reference.md): the entry fields a marketplace can set for your plugin
693* [Plugin commands reference](/docs/en/plugins/cli-reference.md#plugin-validate): `claude plugin validate` flags and output
694* [Troubleshoot plugins](/docs/en/plugins/troubleshooting.md#claude-plugin-validate-reports-errors): each validation message with its fix
693695 

plugins/marketplace-reference Changed · +32 / -32 lines

from line 12
1212>
1313> These cases are covered on other pages:
1414>
15> * **Building or hosting a marketplace**: see [Create a marketplace](/docs/en/plugins/create-marketplace) and [Host and maintain a marketplace](/docs/en/plugins/host-marketplace)
16> * **Allowlist and blocklist recipes**: see [Manage plugins for your organization](/docs/en/plugins/org)
15> * **Building or hosting a marketplace**: see [Create a marketplace](/docs/en/plugins/create-marketplace.md) and [Host and maintain a marketplace](/docs/en/plugins/host-marketplace.md)
16> * **Allowlist and blocklist recipes**: see [Manage plugins for your organization](/docs/en/plugins/org.md)
1717 
1818Find the section for what you're writing or reading:
1919 
from line 49
4949 
5050When a registered marketplace stops loading because its name imitates an official one, `claude plugin list` and `/plugin` report `Claude Code refuses the marketplace name "<name>"`. The message tells you to remove the marketplace. Removing it also uninstalls its plugins and deletes their data, options, and secrets. This named refusal message requires Claude Code v2.1.282 or later.
5151 
52If a settings file declares the marketplace inline, the message tells you to rename its entry before you remove the old name. For the steps, see [Claude Code refuses the marketplace name](/docs/en/errors#claude-code-refuses-the-marketplace-name). The message lists them in Claude Code v2.1.292 or later.
52If a settings file declares the marketplace inline, the message tells you to rename its entry before you remove the old name. For the steps, see [Claude Code refuses the marketplace name](/docs/en/errors.md#claude-code-refuses-the-marketplace-name). The message lists them in Claude Code v2.1.292 or later.
5353 
5454## Top-level fields
5555 
from line 57
5757 
5858| Field | Type | Description |
5959| :- | :- | :- |
60| `name` | string | Marketplace identifier: letters, digits, `.`, `_`, and `-`, starting with a letter or digit, and no `..`. `claude plugin validate` fails any other name, because Claude Code [can't install plugins from a marketplace that uses one](/docs/en/plugins/troubleshooting#cannot-install-plugins-from-a-marketplace-with-this-name). Users type the name after `@` in a [plugin id](/docs/en/plugins/loading#find-where-a-plugin-came-from) such as `my-plugin@my-marketplace` when they install a plugin. See [Reserved names](#reserved-names) |
60| `name` | string | Marketplace identifier: letters, digits, `.`, `_`, and `-`, starting with a letter or digit, and no `..`. `claude plugin validate` fails any other name, because Claude Code [can't install plugins from a marketplace that uses one](/docs/en/plugins/troubleshooting.md#cannot-install-plugins-from-a-marketplace-with-this-name). Users type the name after `@` in a [plugin id](/docs/en/plugins/loading.md#find-where-a-plugin-came-from) such as `my-plugin@my-marketplace` when they install a plugin. See [Reserved names](#reserved-names) |
6161| `owner` | object | Maintainer information. `name` is required; `email` and `url` are optional |
6262| `plugins` | array | [Plugin entries](#plugin-entries). Each entry is validated on its own, so one invalid entry doesn't fail the marketplace |
6363| `$schema` | string | JSON Schema URL for editor autocomplete. Ignored at load time |
from line 65
6565| `version` | string | Marketplace manifest version |
6666| `metadata.description`, `metadata.version` | string | Alternate location for `description` and `version` |
6767| `metadata.pluginRoot` | string | Directory that bare plugin source names resolve under. See [Relative path plugin source](#relative-path-plugin-source). Requires Claude Code v2.1.239 or later |
68| `forceRemoveDeletedPlugins` | boolean | When `true`, a plugin you remove from `plugins` is uninstalled on users' machines. See [Host and maintain a marketplace](/docs/en/plugins/host-marketplace) |
69| `allowCrossMarketplaceDependenciesOn` | array of strings | Marketplace names whose plugins may be installed as dependencies of this marketplace's plugins. When you install a plugin, only the list in that plugin's own marketplace applies, for its whole dependency chain. See [Plugin dependencies](/docs/en/plugins/dependencies) |
70| `renames` | object | Map from a former plugin `name` to its current name, or to `null` for a plugin you removed. See [Host and maintain a marketplace](/docs/en/plugins/host-marketplace) |
68| `forceRemoveDeletedPlugins` | boolean | When `true`, a plugin you remove from `plugins` is uninstalled on users' machines. See [Host and maintain a marketplace](/docs/en/plugins/host-marketplace.md) |
69| `allowCrossMarketplaceDependenciesOn` | array of strings | Marketplace names whose plugins may be installed as dependencies of this marketplace's plugins. When you install a plugin, only the list in that plugin's own marketplace applies, for its whole dependency chain. See [Plugin dependencies](/docs/en/plugins/dependencies.md) |
70| `renames` | object | Map from a former plugin `name` to its current name, or to `null` for a plugin you removed. See [Host and maintain a marketplace](/docs/en/plugins/host-marketplace.md) |
7171 
7272## Plugin entries
7373 
7474Each object in the top-level `plugins` array of `marketplace.json` names a plugin and says where to fetch it. `name` and `source` are required.
7575 
76Apart from the [directory listing fields](/docs/en/plugins/manifest-reference#directory-listing-fields), an entry also accepts every [`plugin.json` field](/docs/en/plugins/manifest-reference), such as `description`, `version`, `author`, `commands`, and `hooks`. For when those fields apply, see [How an entry combines with plugin.json](#entry-and-plugin-json).
76Apart from the [directory listing fields](/docs/en/plugins/manifest-reference.md#directory-listing-fields), an entry also accepts every [`plugin.json` field](/docs/en/plugins/manifest-reference), such as `description`, `version`, `author`, `commands`, and `hooks`. For when those fields apply, see [How an entry combines with plugin.json](#entry-and-plugin-json).
7777 
7878The table lists the entry's own fields and the manifest fields whose meaning changes in an entry.
7979 
from line 82
8282| `name` | string | Plugin identifier: letters, digits, `.`, `_`, and `-`, starting with a letter or digit. `claude plugin validate` fails other names, which Claude Code can't install. Users type it before `@` when they install, even when the plugin's own `plugin.json` sets a different `name` |
8383| `source` | string or object | Where to fetch the plugin. See [Plugin sources](#plugin-sources) |
8484| `description` | string | Shown in [`/plugin`](/docs/en/plugins/install) listings and details |
85| `version` | string | Version string for the plugin. When `plugin.json` also sets `version`, `plugin.json` takes precedence and `claude plugin validate` warns. See [Plugin loading reference](/docs/en/plugins/loading) |
85| `version` | string | Version string for the plugin. When `plugin.json` also sets `version`, `plugin.json` takes precedence and `claude plugin validate` warns. See [Plugin loading reference](/docs/en/plugins/loading.md) |
8686| `category` | string | Free-form category for organizing the catalog |
8787| `tags` | array of strings | Free-form tags for search |
8888| `strict` | boolean | Default `true`. Whether `plugin.json` is the definitive source for the plugin's components. See [Strict mode](#strict-mode) |
89| `relevance` | object | Signals that tell Claude Code when to suggest the plugin. See [Recommend plugins for your org](/docs/en/plugins/relevance) |
90| `dependencies` | array | Plugins that must be enabled for this one to work. Each item is `"name"`, `"name@marketplace"`, or an object. See [Plugin dependencies](/docs/en/plugins/dependencies) |
89| `relevance` | object | Signals that tell Claude Code when to suggest the plugin. See [Recommend plugins for your org](/docs/en/plugins/relevance.md) |
90| `dependencies` | array | Plugins that must be enabled for this one to work. Each item is `"name"`, `"name@marketplace"`, or an object. See [Plugin dependencies](/docs/en/plugins/dependencies.md) |
9191| `defaultEnabled` | boolean | Default `true`. Whether the plugin starts enabled when the user hasn't set it in [`enabledPlugins`](/docs/en/settings-reference#enabledplugins). The entry value takes precedence over `plugin.json` |
9292| `displayName` | string | Human-readable name shown in the UI. When neither the entry nor the plugin's `plugin.json` sets one, users see the plugin's `name` |
9393| `metadata` | object | Free-form object for your own fields. Claude Code doesn't read it. Requires Claude Code v2.1.222 or later |
9494| `headers` | object | HTTP headers Claude Code sends when it downloads this entry's [archive](#archive-plugin-source). A header set here replaces a header of the same name from the marketplace source's [`headers`](#fields-by-type). Requires Claude Code v2.1.238 or later |
95| `headersHelper` | string | Command that prints this entry's archive-download headers as one JSON object, for a credential that expires. The entry must also set [`"strict": false`](#strict-mode). Requires Claude Code v2.1.238 or later. See [Authenticate archive downloads](/docs/en/plugins/host-marketplace#authenticate-archive-downloads) |
95| `headersHelper` | string | Command that prints this entry's archive-download headers as one JSON object, for a credential that expires. The entry must also set [`"strict": false`](#strict-mode). Requires Claude Code v2.1.238 or later. See [Authenticate archive downloads](/docs/en/plugins/host-marketplace.md#authenticate-archive-downloads) |
9696 
9797### How an entry combines with plugin.json
9898 
from line 121
121121| `strict` | `plugin.json` | Entry component fields | Result |
122122| :- | :- | :- | :- |
123123| any | absent | any | The entry is the manifest |
124| `true`, the default | present | any | `plugin.json` is the authority. Claude Code appends the entry's component fields to it, except `hooks`, whose matchers [replace the manifest's per event](/docs/en/plugins/manifest-reference#how-entry-fields-combine-with-plugin-json) |
124| `true`, the default | present | any | `plugin.json` is the authority. Claude Code appends the entry's component fields to it, except `hooks`, whose matchers [replace the manifest's per event](/docs/en/plugins/manifest-reference.md#how-entry-fields-combine-with-plugin-json) |
125125| `false` | present | none | `plugin.json` is the manifest, as with `true` |
126126| `false` | present | one or more | Conflict. The plugin fails to load with `Plugin <name> has conflicting manifests: both plugin.json and marketplace entry specify components` |
127127 
from line 150
150150* **`ref`**: a branch or tag. Defaults to the repository's default branch.
151151* **`sha`**: a full 40-character lowercase commit SHA. When you set both `ref` and `sha`, Claude Code checks out `sha`. On most git hosts, including GitHub, GitLab, and Bitbucket, this means installation succeeds even if the branch or tag named by `ref` has since been deleted upstream, as long as the commit is still reachable from the repository. Some servers, such as AWS CodeCommit, don't support fetching commits by SHA. On those servers the `ref` must still exist and the pinned commit must be reachable from it.
152152 
153For how each type is fetched, cached, and versioned, see [Plugin loading reference](/docs/en/plugins/loading).
153For how each type is fetched, cached, and versioned, see [Plugin loading reference](/docs/en/plugins/loading.md).
154154 
155155### Relative path plugin source
156156 
from line 232
232232* `version`: a version, a semver range, or a dist-tag, used when `package` is a package name with no version appended. Omit it to fetch `latest`
233233* `registry`: a registry URL for a package that isn't on the default registry
234234 
235Claude Code fetches the package with your npm client. The package's install scripts, such as `preinstall` or `postinstall`, never run, and its dependencies aren't installed during the fetch. If the package has a supported lockfile beside its `package.json`, Claude Code installs those [Node.js package dependencies](/docs/en/plugins/loading#node-js-package-dependencies) in a separate step, also with scripts disabled.
235Claude Code fetches the package with your npm client. The package's install scripts, such as `preinstall` or `postinstall`, never run, and its dependencies aren't installed during the fetch. If the package has a supported lockfile beside its `package.json`, Claude Code installs those [Node.js package dependencies](/docs/en/plugins/loading.md#node-js-package-dependencies) in a separate step, also with scripts disabled.
236236 
237237Claude Code checks the `package` value before fetching anything. A refused value fails the install with a message that names the value and the reason. The refused values include:
238238 
from line 256
256256 
257257### archive plugin source
258258 
259`url` must use `https://` and can't point at a loopback, link-local, or cloud-metadata host. For the size, timeout, redirect, and extraction limits on the download, see [Stay within the download limits for hosted files](/docs/en/plugins/host-marketplace#stay-within-the-download-limits-for-hosted-files).
259`url` must use `https://` and can't point at a loopback, link-local, or cloud-metadata host. For the size, timeout, redirect, and extraction limits on the download, see [Stay within the download limits for hosted files](/docs/en/plugins/host-marketplace.md#stay-within-the-download-limits-for-hosted-files).
260260 
261261The plugin root may be at the top of the zip or one directory down.
262262 
from line 275
275275 
276276### command plugin source
277277 
278Use a `command` source when a tool installed on the user's machine produces the plugin directory, such as an IDE that renders its plugin for the toolchain the user has selected. Claude Code runs the command when the user installs or updates the plugin, and [again once per session](/docs/en/plugins/loading#when-a-command-source-re-runs), so users get the tool's changed output without reinstalling.
278Use a `command` source when a tool installed on the user's machine produces the plugin directory, such as an IDE that renders its plugin for the toolchain the user has selected. Claude Code runs the command when the user installs or updates the plugin, and [again once per session](/docs/en/plugins/loading.md#when-a-command-source-re-runs), so users get the tool's changed output without reinstalling.
279279 
280280A `command` source takes these fields:
281281 
from line 294
294294}
295295```
296296 
297For how users accept the command, see [Install from your shell](/docs/en/plugins/install#install-from-your-shell). For what users see after you change it, see [Change the command of a command source](/docs/en/plugins/host-marketplace#change-the-command-of-a-command-source). Administrators turn command sources off with [`disableCommandPluginSources`](/docs/en/settings-reference#disablecommandpluginsources).
297For how users accept the command, see [Install from your shell](/docs/en/plugins/install.md#install-from-your-shell). For what users see after you change it, see [Change the command of a command source](/docs/en/plugins/host-marketplace.md#change-the-command-of-a-command-source). Administrators turn command sources off with [`disableCommandPluginSources`](/docs/en/settings-reference#disablecommandpluginsources).
298298 
299299#### What the command must do
300300 
from line 317
317317 
318318`mode` decides whether Claude Code copies the printed directory or uses it in place:
319319 
320* **`copy`**: Claude Code copies the directory into the plugin cache and derives the [plugin version](/docs/en/plugins/loading#how-claude-code-computes-the-version) from a hash of the copied files. Your tool can delete or rewrite the directory after the command exits. A re-run that produces identical files counts as up to date.
320* **`copy`**: Claude Code copies the directory into the plugin cache and derives the [plugin version](/docs/en/plugins/loading.md#how-claude-code-computes-the-version) from a hash of the copied files. Your tool can delete or rewrite the directory after the command exits. A re-run that produces identical files counts as up to date.
321321* **`link`**: Claude Code fills the plugin's cache entry with a link to each top-level entry of the printed directory and loads the files in place. Nothing is copied, file contents aren't hashed, and the size limits don't apply. Use it for a directory too large to copy, such as a rendered SDK export.
322322 
323323A link-mode plugin has these requirements:
from line 325
325325* **Keep the directory in place**: Claude Code loads the plugin through the links at every startup, so the printed directory must stay where it is for as long as the plugin stays installed.
326326* **Print a different path to signal new content**: the version comes from the printed directory's real path and its top-level entries, not from the files inside them.
327327* **Keep top-level symlinks inside the directory**: the install fails if a top-level entry is a symlink that points outside the printed directory.
328* **Include `node_modules`**: Claude Code skips the [Node.js package dependency install](/docs/en/plugins/loading#node-js-package-dependencies) for a link-mode plugin, so print a directory that already contains the packages the plugin needs.
328* **Include `node_modules`**: Claude Code skips the [Node.js package dependency install](/docs/en/plugins/loading.md#node-js-package-dependencies) for a link-mode plugin, so print a directory that already contains the packages the plugin needs.
329329* **Sessions started inside the directory**: a session started in the printed directory or anywhere below it doesn't load the plugin.
330330* **Not on Windows**: Claude Code refuses to install a link-mode plugin on Windows. Declare `"mode": "copy"` there.
331331 
from line 356
356356| `file` | `path` | A path to a `.json` file | Loads | Allows the same path | Blocks the same path |
357357| `directory` | `path` | A path to a directory | Loads | Allows the same path | Blocks the same path |
358358| `settings` | `name`, `plugins`, `owner` | Not produced | Loads | Allows an entry with the same `name` and identical `plugins` | Blocks the same `name` |
359| `skills-dir` | none | Not produced | Fails to load: `Unsupported marketplace source type` | Allows [skills-directory plugins](/docs/en/plugins/org#keep-skills-directory-plugins-loading). See [Source values valid only in policy lists](#source-values-valid-only-in-policy-lists) | Stops skills-directory plugins from loading |
359| `skills-dir` | none | Not produced | Fails to load: `Unsupported marketplace source type` | Allows [skills-directory plugins](/docs/en/plugins/org.md#keep-skills-directory-plugins-loading). See [Source values valid only in policy lists](#source-values-valid-only-in-policy-lists) | Stops skills-directory plugins from loading |
360360| `hostPattern` | `hostPattern` | Not produced | Fails to load: `Unsupported marketplace source type` | Allows `github`, `git`, and `url` sources whose host matches | Blocks those sources |
361361| `pathPattern` | `pathPattern` | Not produced | Fails to load: `Unsupported marketplace source type` | Allows `file` and `directory` sources whose `path` matches | Blocks those sources |
362362 
from line 366
366366 
367367| Field | Types | Description |
368368| :- | :- | :- |
369| `url` | `url` | Link to the `marketplace.json` file. Claude Code downloads only that file, so the marketplace's plugins can't use [relative-path sources](#relative-path-plugin-source). See [Stay within the download limits for hosted files](/docs/en/plugins/host-marketplace#stay-within-the-download-limits-for-hosted-files) for the size, timeout, and redirect limits |
369| `url` | `url` | Link to the `marketplace.json` file. Claude Code downloads only that file, so the marketplace's plugins can't use [relative-path sources](#relative-path-plugin-source). See [Stay within the download limits for hosted files](/docs/en/plugins/host-marketplace.md#stay-within-the-download-limits-for-hosted-files) for the size, timeout, and redirect limits |
370370| `url` | `git` | The git repository to clone |
371371| `headers` | `url` | Map of HTTP headers Claude Code sends with the fetch, for authenticated hosts |
372| `headersHelper` | `url` | Command that prints headers whose values are too short-lived to list in `headers`. Requires Claude Code v2.1.238 or later. See [Authenticate archive downloads](/docs/en/plugins/host-marketplace#authenticate-archive-downloads) |
372| `headersHelper` | `url` | Command that prints headers whose values are too short-lived to list in `headers`. Requires Claude Code v2.1.238 or later. See [Authenticate archive downloads](/docs/en/plugins/host-marketplace.md#authenticate-archive-downloads) |
373373| `repo` | `github` | In `marketplace add` and `extraKnownMarketplaces`, `repo` must name one repository. `marketplace add` rejects `owner/*` as not a valid `owner/repo` shorthand; in `extraKnownMarketplaces` Claude Code takes it literally and the clone fails |
374374| `ref` | `github`, `git` | Branch or tag. Defaults to the repository's default branch |
375375| `path` | `github`, `git` | The marketplace file's path inside the repository. Defaults to `.claude-plugin/marketplace.json` |
from line 376
376376| `path` | `file` | The marketplace file itself. Claude Code reads it in place and takes the directory two levels up as the marketplace root, so keep the file at `<root>/.claude-plugin/marketplace.json` |
377377| `path` | `directory` | The marketplace root, the directory that contains `.claude-plugin/marketplace.json` |
378378| `sparsePaths` | `github`, `git` | Array of directories for a sparse checkout, such as `[".claude-plugin", "plugins"]`. `claude plugin marketplace add --sparse` sets it |
379| `skipLfs` | `github`, `git` | Accepted and has no effect. See [Keep plugin files out of Git LFS](/docs/en/plugins/host-marketplace#keep-plugin-files-out-of-git-lfs) |
379| `skipLfs` | `github`, `git` | Accepted and has no effect. See [Keep plugin files out of Git LFS](/docs/en/plugins/host-marketplace.md#keep-plugin-files-out-of-git-lfs) |
380380| `name` | `settings` | Must equal the `extraKnownMarketplaces` key and can't be a [reserved name](#reserved-names) |
381381| `plugins` | `settings` | The inline catalog, with no hosted file. Each item takes `name`, `source`, `description`, `version`, `strict`, `headers`, and `headersHelper`. Write each item's `source` as an object type, because a relative path has no repository to resolve against |
382382 
from line 385
385385`hostPattern`, `pathPattern`, `skills-dir`, and the `owner/*` form of `repo` are valid only in the two policy lists, `strictKnownMarketplaces` and `blockedMarketplaces`:
386386 
387387* **`hostPattern` and `pathPattern`**: regular expressions Claude Code tests against a source before it fetches from it.
388* **`skills-dir`**: not a source. If you set `strictKnownMarketplaces` without a `{"source": "skills-dir"}` entry, [skills-directory plugins](/docs/en/plugins/org#keep-skills-directory-plugins-loading) stop loading. If you lock any customization type with [`strictPluginOnlyCustomization`](/docs/en/settings-reference#strictpluginonlycustomization), they stop loading whether or not the entry is present.
388* **`skills-dir`**: not a source. If you set `strictKnownMarketplaces` without a `{"source": "skills-dir"}` entry, [skills-directory plugins](/docs/en/plugins/org.md#keep-skills-directory-plugins-loading) stop loading. If you lock any customization type with [`strictPluginOnlyCustomization`](/docs/en/settings-reference#strictpluginonlycustomization), they stop loading whether or not the entry is present.
389389* **`owner/*`**: as a `github` `repo` value, matches every repository under exactly that GitHub owner. Requires Claude Code v2.1.223 or later.
390390 
391For match order, exact-`ref` semantics, and recipes, see [Manage plugins for your organization](/docs/en/plugins/org).
391For match order, exact-`ref` semantics, and recipes, see [Manage plugins for your organization](/docs/en/plugins/org.md).
392392 
393393### Source objects in settings
394394 
from line 421
421421 
422422## Validation messages
423423 
424`claude plugin validate <path>` takes the marketplace root or the marketplace file itself. It prints errors and warnings. For exit codes and `--strict`, see [plugin validate](/docs/en/plugins/cli-reference#plugin-validate).
424`claude plugin validate <path>` takes the marketplace root or the marketplace file itself. It prints errors and warnings. For exit codes and `--strict`, see [plugin validate](/docs/en/plugins/cli-reference.md#plugin-validate).
425425 
426426A message names a plugin entry by its index, written as `plugins.1.source` or `plugins[1].source`.
427427 
from line 483
483483 
484484`claude plugin validate` doesn't report every failure. An entry `hooks` written as a file path or array passes validation, and the error appears only when the plugin loads, as [Hooks in an entry](#hooks-in-an-entry) describes. Errors fetching a `source` also appear only after install, not in validation.
485485 
486[`claude plugin list`](/docs/en/plugins/cli-reference) shows a plugin that failed to load with its error, and [Troubleshoot plugins](/docs/en/plugins/troubleshooting) covers the load-time strings.
486[`claude plugin list`](/docs/en/plugins/cli-reference) shows a plugin that failed to load with its error, and [Troubleshoot plugins](/docs/en/plugins/troubleshooting.md) covers the load-time strings.
487487 
488488## Next steps
489489 
490* [Create a marketplace](/docs/en/plugins/create-marketplace): build a marketplace from these fields and install from it locally
491* [Host and maintain a marketplace](/docs/en/plugins/host-marketplace): where to put the file and how users receive changes
492* [Plugin manifest reference](/docs/en/plugins/manifest-reference): the `plugin.json` fields an entry can override
493* [Manage plugins for your organization](/docs/en/plugins/org): allowlist and blocklist recipes that use these source values
490* [Create a marketplace](/docs/en/plugins/create-marketplace.md): build a marketplace from these fields and install from it locally
491* [Host and maintain a marketplace](/docs/en/plugins/host-marketplace.md): where to put the file and how users receive changes
492* [Plugin manifest reference](/docs/en/plugins/manifest-reference.md): the `plugin.json` fields an entry can override
493* [Manage plugins for your organization](/docs/en/plugins/org.md): allowlist and blocklist recipes that use these source values
494494 

plugins/measure Changed · +17 / -17 lines

from line 10
1010>
1111> These cases are covered on other pages:
1212>
13> * **Testing how reliably the plugin changes Claude's behavior**: see [Test plugins with evals](/docs/en/plugin-evals)
14> * **Trimming your own session's context**: see [Manage installed plugins](/docs/en/plugins/install#manage-installed-plugins) and the [context window](/docs/en/context-window) page
13> * **Testing how reliably the plugin changes Claude's behavior**: see [Test plugins with evals](/docs/en/plugin-evals.md)
14> * **Trimming your own session's context**: see [Manage installed plugins](/docs/en/plugins/install.md#manage-installed-plugins) and the [context window](/docs/en/context-window.md) page
1515 
1616Start with [Measure what a plugin costs](#measure-what-a-plugin-costs).
1717 
from line 59
5959 
6060### Lower the always-on figure
6161 
62If you maintain the plugin, these changes reduce what it adds to every session. If you only use it, your options are to disable or uninstall it; see [Manage installed plugins](/docs/en/plugins/install#manage-installed-plugins).
62If you maintain the plugin, these changes reduce what it adds to every session. If you only use it, your options are to disable or uninstall it; see [Manage installed plugins](/docs/en/plugins/install.md#manage-installed-plugins).
6363 
6464The always-on figure counts each component's name plus its `description` and `when_to_use` frontmatter. To lower it:
6565 
from line 68
6868 
6969A skill's description is also what Claude matches a request against, so a shorter one can stop the skill triggering. After you trim descriptions, check triggering with a [`tool_used: Skill` grader](/docs/en/plugin-evals#create-your-first-eval-suite) in your eval suite.
7070 
71For what each component type contributes, see [plugin components](/docs/en/plugins/components).
71For what each component type contributes, see [plugin components](/docs/en/plugins/components.md).
7272 
7373### Cost shown to users before install
7474 
from line 88
8888 
8989### Not used recently in `/plugin`
9090 
91On the **Installed** tab of `/plugin`, a plugin the user installed from a marketplace moves under a **Not used recently** header once it has gone unused for at least 14 days and 10 sessions. The plugin's details also show a `Last used:` line. For what users do with that header and line, see [Find plugins you no longer use](/docs/en/plugins/install#find-plugins-you-no-longer-use).
91On the **Installed** tab of `/plugin`, a plugin the user installed from a marketplace moves under a **Not used recently** header once it has gone unused for at least 14 days and 10 sessions. The plugin's details also show a `Last used:` line. For what users do with that header and line, see [Find plugins you no longer use](/docs/en/plugins/install.md#find-plugins-you-no-longer-use).
9292 
9393The **Not used recently** header never appears for:
9494 
9595* Plugins loaded with `--plugin-dir` or from a skills directory
96* Plugins enabled through managed settings, or mounted from a [seed directory](/docs/en/plugins/org#seed-containers-and-ci)
96* Plugins enabled through managed settings, or mounted from a [seed directory](/docs/en/plugins/org.md#seed-containers-and-ci)
9797* Plugins that include a theme, output style, monitor, or workflow, because those are in use without a tracked invocation
9898 
99A plugin's [language server](/docs/en/plugins/components#lsp-servers) counts as used when it delivers diagnostics or answers a code navigation request, so an LSP plugin whose server is active in your sessions isn't listed as unused.
99A plugin's [language server](/docs/en/plugins/components.md#lsp-servers) counts as used when it delivers diagnostics or answers a code navigation request, so an LSP plugin whose server is active in your sessions isn't listed as unused.
100100 
101101When the user's organization sets [`strictKnownMarketplaces`](/docs/en/plugins/org#restrict-what-users-can-install), neither the header nor the `Last used:` line appears.
102102 
from line 104
104104 
105105Run `/skill-doctor` to see what each of your skills costs and how often it gets used. It flags skills that are in Claude's skill listing but have never been invoked, including skills from plugins.
106106 
107In an interactive session, the report opens in the `/plugin` manager's **Stats** tab. See [Find unused skills](/docs/en/skills#find-unused-skills) for what the report covers and where it's available.
107In an interactive session, the report opens in the `/plugin` manager's **Stats** tab. See [Find unused skills](/docs/en/skills.md#find-unused-skills) for what the report covers and where it's available.
108108 
109109### Unused plugins in `/doctor`
110110 
from line 118
118118 
119119If you administer Claude Code for an organization, you can measure plugin cost and usage across every machine from either of these sources:
120120 
121* **OpenTelemetry events**: Claude Code exports these to your own backend once you [configure an exporter](/docs/en/monitoring-usage). See [OpenTelemetry events for plugin installs and use](#pick-the-opentelemetry-event-for-each-question).
121* **OpenTelemetry events**: Claude Code exports these to your own backend once you [configure an exporter](/docs/en/monitoring-usage.md). See [OpenTelemetry events for plugin installs and use](#pick-the-opentelemetry-event-for-each-question).
122122* **Analytics API**: served from Anthropic's records, with no exporter needed. See [Query the Analytics API](#query-the-analytics-api).
123123 
124124### OpenTelemetry events for plugin installs and use
from line 131
131131| Which plugins are active in how many sessions | [`claude_code.plugin_loaded`](/docs/en/monitoring-usage#plugin-loaded-event), one per enabled plugin at session start |
132132| Which skills activate, and which plugin owns them | [`claude_code.skill_activated`](/docs/en/monitoring-usage#skill-activated-event), with `plugin.name` and `marketplace.name` for plugin skills |
133133| What a plugin's hooks report | [`claude_code.hook_plugin_metrics`](/docs/en/monitoring-usage#hook-plugin-metrics-event), emitted only for hooks in official-marketplace plugins |
134| What a plugin costs in API spend | `plugin.name` and `marketplace.name` on the [cost counter](/docs/en/monitoring-usage#cost-counter), set when the active skill or subagent belongs to a plugin |
134| What a plugin costs in API spend | `plugin.name` and `marketplace.name` on the [cost counter](/docs/en/monitoring-usage.md#cost-counter), set when the active skill or subagent belongs to a plugin |
135135 
136136### Redacted plugin names in your backend
137137 
138Plugins from the official marketplace report their plugin name and marketplace name to your backend verbatim. Every other plugin's name is redacted or omitted by default, including a plugin from your organization's own marketplace. The plugin's [trust tier](/docs/en/plugins/security#find-plugins-in-telemetry) decides which.
138Plugins from the official marketplace report their plugin name and marketplace name to your backend verbatim. Every other plugin's name is redacted or omitted by default, including a plugin from your organization's own marketplace. The plugin's [trust tier](/docs/en/plugins/security.md#find-plugins-in-telemetry) decides which.
139139 
140To get real names on some events, set the [`OTEL_LOG_TOOL_DETAILS`](/docs/en/monitoring-usage#common-configuration-variables) environment variable to `1` on the machines that export telemetry, for example in the `env` block of the same [managed settings](/docs/en/monitoring-usage#administrator-configuration) that configure the exporter:
140To get real names on some events, set the [`OTEL_LOG_TOOL_DETAILS`](/docs/en/monitoring-usage#common-configuration-variables) environment variable to `1` on the machines that export telemetry, for example in the `env` block of the same [managed settings](/docs/en/monitoring-usage.md#administrator-configuration) that configure the exporter:
141141 
142142| Event | Default | With `OTEL_LOG_TOOL_DETAILS=1` |
143143| :- | :- | :- |
from line 151
151151 
152152On the Enterprise plan, the Analytics API answers "which plugins does my organization install and invoke" from Anthropic's records, with no exporter needed. [`GET /v1/organizations/analytics/plugins`](https://platform.claude.com/docs/en/api/admin/analytics/plugins/list) returns per-plugin, per-day install and invocation counts across Claude Code and Cowork, which you can group by user, RBAC group, or product.
153153 
154Plugin activity that reaches Anthropic without a plugin name appears in one aggregate `third-party` row. [Find plugins in telemetry](/docs/en/plugins/security#find-plugins-in-telemetry) says which plugins Claude Code reports by name.
154Plugin activity that reaches Anthropic without a plugin name appears in one aggregate `third-party` row. [Find plugins in telemetry](/docs/en/plugins/security.md#find-plugins-in-telemetry) says which plugins Claude Code reports by name.
155155 
156Authenticate the request with an API key that has the `read:analytics` scope, which a Primary Owner creates as described under [Access data programmatically](/docs/en/analytics#access-data-programmatically).
156Authenticate the request with an API key that has the `read:analytics` scope, which a Primary Owner creates as described under [Access data programmatically](/docs/en/analytics.md#access-data-programmatically).
157157 
158158See the [endpoint reference](https://platform.claude.com/docs/en/api/admin/analytics/plugins/list) for the parameters and response fields.
159159 
160160## Next steps
161161 
162* [Test plugins with evals](/docs/en/plugin-evals): measure how reliably the plugin steers Claude, not only what it costs
162* [Test plugins with evals](/docs/en/plugin-evals.md): measure how reliably the plugin steers Claude, not only what it costs
163163* [Lower the always-on figure](#lower-the-always-on-figure): what to change in the plugin to reduce its per-turn cost
164* [Plugin security and trust](/docs/en/plugins/security#find-plugins-in-telemetry): which telemetry fields carry plugin names and when they're redacted
165* [Monitoring usage](/docs/en/monitoring-usage): the full OpenTelemetry event reference
164* [Plugin security and trust](/docs/en/plugins/security.md#find-plugins-in-telemetry): which telemetry fields carry plugin names and when they're redacted
165* [Monitoring usage](/docs/en/monitoring-usage.md): the full OpenTelemetry event reference
166166 

plugins/mods/admin Changed · +51 / -51 lines

from line 2
22 
33> Control Claude Code mods with managed settings: stop user-installed mods, allow only your own, review what a mod can do, and enforce policy with your own mod.
44 
5A [mod](/docs/en/plugins/mods/overview) is a plugin that runs code inside Claude Code with the permissions of the user who installed it. Mods aren't sandboxed. Through [managed settings](/docs/en/managed-settings), you decide whether mods run on your users' machines, which ones, and in what order. You can also install a mod of your own that watches or refuses what other mods do.
5A [mod](/docs/en/plugins/mods/overview.md) is a plugin that runs code inside Claude Code with the permissions of the user who installed it. Mods aren't sandboxed. Through [managed settings](/docs/en/managed-settings.md), you decide whether mods run on your users' machines, which ones, and in what order. You can also install a mod of your own that watches or refuses what other mods do.
66 
77This page is for the person who deploys managed settings for Claude Code, whether as a file, through MDM, or from the claude.ai admin console. Mods are on by default in Claude Code v2.1.286 and later. Start with the section that matches what you came to do:
88 
from line 14
1414>
1515> These cases are covered on other pages:
1616>
17> * **You haven't deployed managed settings before**: start with [Deploy managed settings](/docs/en/managed-settings)
18> * **You want to control which plugins users can install**: see [Manage plugins for your organization](/docs/en/plugins/org)
17> * **You haven't deployed managed settings before**: start with [Deploy managed settings](/docs/en/managed-settings.md)
18> * **You want to control which plugins users can install**: see [Manage plugins for your organization](/docs/en/plugins/org.md)
1919 
2020## Stop user-installed mods from loading
2121 
from line 35
3535 
3636With the option set in managed settings:
3737 
38* **No mod a user brings runs its hooks**: that covers a mod in a plugin the user installed, a mod loaded with `--plugin-dir`, and a mod [Claude wrote during a session](/docs/en/plugins/mods/create#ask-claude-for-a-mod)
38* **No mod a user brings runs its hooks**: that covers a mod in a plugin the user installed, a mod loaded with `--plugin-dir`, and a mod [Claude wrote during a session](/docs/en/plugins/mods/create.md#ask-claude-for-a-mod)
3939* **Your organization's mods still run**: a mod that [counts as your organization's](#install-your-organizations-mods) isn't checked. Every other mod counts as a user's and is refused. That includes a mod in a plugin you enable from a GitHub or other remote marketplace, and one your organization turns on for its members on claude.ai. If none counts as yours, no installed mod runs its hooks.
4040* **Users can't undo it**: the guard reads the option from managed settings only, so the same entry in a user, project, or local settings file, or in a file passed with `--settings`, changes nothing
41* **A file or MDM policy covers every provider**: when you deliver the option as a file or through MDM, it works the same way on Amazon Bedrock, Google Cloud's Agent Platform, and Microsoft Foundry. For delivery from the claude.ai admin console, see [Platform availability](/docs/en/server-managed-settings#platform-availability)
42* **Users' other customizations keep working**: their [hooks in settings files](/docs/en/hooks) and in plugins' `hooks/hooks.json`, status lines, and `/goal` aren't affected
43* **Built-in mods keep running**: mods built into Claude Code, such as `AGENTS.md` support, each have [their own switch](/docs/en/plugins/mods/overview#mods-built-into-claude-code)
41* **A file or MDM policy covers every provider**: when you deliver the option as a file or through MDM, it works the same way on Amazon Bedrock, Google Cloud's Agent Platform, and Microsoft Foundry. For delivery from the claude.ai admin console, see [Platform availability](/docs/en/server-managed-settings.md#platform-availability)
42* **Users' other customizations keep working**: their [hooks in settings files](/docs/en/hooks.md) and in plugins' `hooks/hooks.json`, status lines, and `/goal` aren't affected
43* **Built-in mods keep running**: mods built into Claude Code, such as `AGENTS.md` support, each have [their own switch](/docs/en/plugins/mods/overview.md#mods-built-into-claude-code)
4444 
45To confirm the option on a user's machine, start Claude Code there with `--plugin-dir` and the path of a directory that holds a mod, such as `claude --plugin-dir ./first-mod`. The mod's hooks don't run, and the transcript and the debug log have the [guard's message](/docs/en/plugins/mods/troubleshoot#messages-from-the-built-in-guard), which names the mod and `allowManagedModsOnly`. If the message isn't there, see [Check that a policy is in force](/docs/en/managed-settings#check-that-a-policy-is-in-force) and the [rules that decide whether an option takes effect](#set-options-on-the-built-in-guard).
45To confirm the option on a user's machine, start Claude Code there with `--plugin-dir` and the path of a directory that holds a mod, such as `claude --plugin-dir ./first-mod`. The mod's hooks don't run, and the transcript and the debug log have the [guard's message](/docs/en/plugins/mods/troubleshoot.md#messages-from-the-built-in-guard), which names the mod and `allowManagedModsOnly`. If the message isn't there, see [Check that a policy is in force](/docs/en/managed-settings.md#check-that-a-policy-is-in-force) and the [rules that decide whether an option takes effect](#set-options-on-the-built-in-guard).
4646 
4747If you set `CLAUDE_CODE_ENABLE_FUNCTION_HOOKS` to `0` during early access, replace it with this option. Claude Code v2.1.287 and later ignores the variable at any value, so a `0` there leaves mods on.
4848 
from line 62
6262* **Permission rules and `PreToolUse` hooks take precedence over a user's mod.** With the guard loaded, by default a user's mod can't approve a call that a `deny` rule refuses or an `ask` rule prompts for, whichever settings file holds the rule. The mod can't approve a call that any `PreToolUse` hook blocked, either.
6363 
6464 Permission rules and `PreToolUse` hooks apply to Claude's tool calls, not to a mod's [`$.fs` and `$.process` calls](/docs/en/plugins/mods/api#reach-files-processes-and-the-network). With `Read(.env)` denied, a mod can still read that file with `$.fs.read` or start a program that does. To limit a mod's own `$.fs` and `$.process` calls, [keep the mod from loading](#stop-user-installed-mods-from-loading) or handle them in a [policy mod](#enforce-a-policy-with-a-mod-of-your-own).
65* **A user's mod can still skip some prompts.** In [auto mode](/docs/en/permission-modes#eliminate-prompts-with-auto-mode), a call the mod approves runs without a classifier check, unless the guard is loaded and the session runs with [`--permission-prompt-tool`](/docs/en/cli-reference#cli-flags) or an Agent SDK [`canUseTool` callback](/docs/en/agent-sdk/user-input#handle-tool-approval-requests). There the classifier checks the call first. For the prompts a mod's approval doesn't skip, see [Extend permissions with hooks](/docs/en/permissions#precedence-among-rules-hooks-and-mods).
65* **A user's mod can still skip some prompts.** In [auto mode](/docs/en/permission-modes.md#eliminate-prompts-with-auto-mode), a call the mod approves runs without a classifier check, unless the guard is loaded and the session runs with [`--permission-prompt-tool`](/docs/en/cli-reference#cli-flags) or an Agent SDK [`canUseTool` callback](/docs/en/agent-sdk/user-input#handle-tool-approval-requests). There the classifier checks the call first. For the prompts a mod's approval doesn't skip, see [Extend permissions with hooks](/docs/en/permissions.md#precedence-among-rules-hooks-and-mods).
6666 
6767The guard's source is public in the [`mods/sec-default` directory of the Claude Code repository](https://github.com/anthropics/claude-code/tree/main/mods/sec-default).
6868 
from line 74
7474* **Deny rules take precedence where the guard loads.** A user's mod can't approve a call that a `deny` rule refuses, unless you set [`allowModsToOverrideDenyRules`](#set-options-on-the-built-in-guard).
7575* **Managed hooks run first.** A `PreToolUse` hook in managed settings runs before any mod's [`tool.call`](/docs/en/plugins/mods/reference#tools) hook, and when that managed hook blocks a tool call, no mod's `tool.call` hook runs for that call. If the call goes ahead and a mod rewrites it, your managed hooks run again on the rewritten call, so they can still block it.
7676 
77 `PreToolUse` hooks from other settings files and from plugins run after the last mod. If a mod answers the tool call itself, the tool never runs and neither do those hooks. See [The order mods run in](/docs/en/plugins/mods/events#the-order-mods-run-in).
77 `PreToolUse` hooks from other settings files and from plugins run after the last mod. If a mod answers the tool call itself, the tool never runs and neither do those hooks. See [The order mods run in](/docs/en/plugins/mods/events.md#the-order-mods-run-in).
7878* **Network policy covers `$.http.fetch`.**
7979 
80 * **Your organization's policy doesn't allow WebFetch**: Claude Code also refuses every mod's `$.http.fetch` request. See [WebFetch availability](/docs/en/tools-reference#webfetch-availability).
81 * **You turn off the WebFetch tool with [`CLAUDE_CODE_DISABLE_WEB_FETCH`](/docs/en/env-vars#variables) or a `WebFetch` [deny rule](/docs/en/permissions#tool-specific-permission-rules), in managed settings or any other settings file**: mods can still make `$.http.fetch` requests.
80 * **Your organization's policy doesn't allow WebFetch**: Claude Code also refuses every mod's `$.http.fetch` request. See [WebFetch availability](/docs/en/tools-reference.md#webfetch-availability).
81 * **You turn off the WebFetch tool with [`CLAUDE_CODE_DISABLE_WEB_FETCH`](/docs/en/env-vars#variables) or a `WebFetch` [deny rule](/docs/en/permissions.md#tool-specific-permission-rules), in managed settings or any other settings file**: mods can still make `$.http.fetch` requests.
8282 
83 To stop them for every mod your users install, [keep user-installed mods from loading](#stop-user-installed-mods-from-loading), or hook `http.fetch` in a [policy mod](#enforce-a-policy-with-a-mod-of-your-own) and refuse requests from users' mods. Give that hook a [`.catch` handler](/docs/en/plugins/mods/events#handle-a-hook-that-fails) that refuses too, because Claude Code skips a hook that fails and the request then goes ahead. If you only [restrict which plugins users can install](/docs/en/plugins/org#restrict-what-users-can-install), fewer mods load, but those you allow still make these requests.
84 * **You set [`CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC`](/docs/en/env-vars)**: a mod that you or your users install can still make these requests. The variable stops only the [mods built into Claude Code](/docs/en/plugins/mods/overview#mods-built-into-claude-code), plus any `$.http.fetch` request that carries the session's Anthropic credentials. Before v2.1.288, the variable stopped every mod's `$.http.fetch` request.
83 To stop them for every mod your users install, [keep user-installed mods from loading](#stop-user-installed-mods-from-loading), or hook `http.fetch` in a [policy mod](#enforce-a-policy-with-a-mod-of-your-own) and refuse requests from users' mods. Give that hook a [`.catch` handler](/docs/en/plugins/mods/events#handle-a-hook-that-fails) that refuses too, because Claude Code skips a hook that fails and the request then goes ahead. If you only [restrict which plugins users can install](/docs/en/plugins/org.md#restrict-what-users-can-install), fewer mods load, but those you allow still make these requests.
84 * **You set [`CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC`](/docs/en/env-vars)**: a mod that you or your users install can still make these requests. The variable stops only the [mods built into Claude Code](/docs/en/plugins/mods/overview.md#mods-built-into-claude-code), plus any `$.http.fetch` request that carries the session's Anthropic credentials. Before v2.1.288, the variable stopped every mod's `$.http.fetch` request.
8585 
8686 None of these covers a program the mod starts with `$.process.run`, which reaches the network with the user's own access.
87* **Plugin controls cover mods.** A mod is a plugin, so the [settings that restrict what users can install](/docs/en/plugins/org#restrict-what-users-can-install), such as `strictKnownMarketplaces`, decide whether it can be installed at all.
87* **Plugin controls cover mods.** A mod is a plugin, so the [settings that restrict what users can install](/docs/en/plugins/org.md#restrict-what-users-can-install), such as `strictKnownMarketplaces`, decide whether it can be installed at all.
8888* **Mods can't change the permission prompt.** A mod can restyle much of Claude Code's interface, but not the permission prompt, so it can't change what a prompt shows. A mod can still approve or deny a tool call before the prompt appears, as [Know what happens by default](#know-what-happens-by-default) describes.
8989* **Trust prompts come first.** In an interactive session in a directory the user hasn't trusted yet, no mod loads until they answer the trust prompt.
9090* **`--safe-mode` turns installed mods off, yours included.** Start a session with `claude --safe-mode` to check whether a mod caused a problem.
from line 103
103103| A marketplace allowlist | A mod from the marketplaces you allow, or from any directory with `--plugin-dir`. A mod Claude writes during a session loads only when the allowlist [includes `skills-dir`](/docs/en/plugins/org#keep-skills-directory-plugins-loading). |
104104| A marketplace allowlist and `disableSideloadFlags` | A mod from the marketplaces you allow |
105105 
106[Manage plugins for your organization](/docs/en/plugins/org) lists the ways a plugin loads and the setting that controls each.
106[Manage plugins for your organization](/docs/en/plugins/org.md) lists the ways a plugin loads and the setting that controls each.
107107 
108108To check the mods in a marketplace before your users install them, see [Review what a mod can do](#review-what-a-mod-can-do). To keep users' mods out until you've done that, see [Stop user-installed mods from loading](#stop-user-installed-mods-from-loading).
109109 
from line 122
122122 ❯ ./register.js calls: $.fs.read, $.http.fetch, $.store.set, $.ui.open
123123```
124124 
125The `hooks:` line lists the events the mod receives. The `calls:` line lists the mods API methods its code calls. The [mods API](/docs/en/plugins/mods/api), written `$` in a mod's code, is how a mod reaches files, processes, and the network. Claude Code refuses to load a mod that uses the mods API in a way this command can't read.
125The `hooks:` line lists the events the mod receives. The `calls:` line lists the mods API methods its code calls. The [mods API](/docs/en/plugins/mods/api.md), written `$` in a mod's code, is how a mod reaches files, processes, and the network. Claude Code refuses to load a mod that uses the mods API in a way this command can't read.
126126 
127127Look at the `calls:` line for these:
128128 
from line 136
136136| `$.mcp.call` | Calls a tool on a connected MCP server, under the session's permission rules |
137137| `$.model.complete` | Uses the user's plan or API key for model calls |
138138| `$.prompt.submit` | Submits a prompt, and can send it as the user's own words |
139| `$.session.send` | Sends a message that another session's, subagent's, or [teammate's](/docs/en/agent-teams) Claude reads |
139| `$.session.send` | Sends a message that another session's, subagent's, or [teammate's](/docs/en/agent-teams.md) Claude reads |
140140 
141141In the `hooks:` line, [`tool.call`](/docs/en/plugins/mods/reference#tools) and [`prompt.submit`](/docs/en/plugins/mods/reference#prompts-and-what-claude-reads) mean the mod sees every tool call and every prompt, and can change them. [`session.append`](/docs/en/plugins/mods/reference#session) means the mod can rewrite each row of the conversation before it's stored. [`ui.render{component=AskUserQuestion}`](/docs/en/plugins/mods/interface#change-what-claude-code-already-draws) means the mod can redraw the dialog Claude uses to ask the user a question. `tool.check` means the mod can approve or deny a tool call before a permission prompt appears. [Know what happens by default](#know-what-happens-by-default) lists which of your rules and hooks take precedence over its answer.
142142 
143143## Choose how much to allow
144144 
145Mod policies range from no installed mods at all to any mod a user chooses, with your own mod checking the others, and each one is a few managed settings. Find the policy you want in the first column and set what the second column names. [Deploy managed settings](/docs/en/managed-settings) covers where managed settings live.
145Mod policies range from no installed mods at all to any mod a user chooses, with your own mod checking the others, and each one is a few managed settings. Find the policy you want in the first column and set what the second column names. [Deploy managed settings](/docs/en/managed-settings.md) covers where managed settings live.
146146 
147147| What you want | Settings |
148148| :- | :- |
from line 149
149149| No installed mod runs, with settings hooks untouched | Set [`allowManagedModsOnly`](#set-options-on-the-built-in-guard) and deploy no mods of your own |
150150| No installed mods and no hooks at all, your managed hooks included | Set `disableAllHooks` to `true` |
151151| Only your organization's mods | Set the guard's [`allowManagedModsOnly` option](#stop-user-installed-mods-from-loading), and [install your mods](#install-your-organizations-mods) so that they count as yours |
152| Any mod from marketplaces you approve | Keep your [marketplace restrictions](/docs/en/plugins/org#restrict-what-users-can-install), and set `disableSideloadFlags` to `true` |
152| Any mod from marketplaces you approve | Keep your [marketplace restrictions](/docs/en/plugins/org.md#restrict-what-users-can-install), and set `disableSideloadFlags` to `true` |
153153| Any mod, with your own mod checking the others | [Install your mod](#install-your-organizations-mods), and list it with `sec-default@builtin` in `prependPlugins` |
154154 
155155What each setting does:
from line 159
159159* **`disableAllHooks`**: the widest setting. In managed settings, it stops the mods in every installed plugin, yours included, and turns off every hook in settings files, so a `PreToolUse` hook in your managed settings no longer blocks anything. Custom status lines and `/goal` stop working too. Read [`disableAllHooks`](/docs/en/settings-reference#disableallhooks) before you set it.
160160* **`disableSideloadFlags`**: rejects `--plugin-dir` and `--plugin-url` at startup, and keeps mods Claude writes during a session from loading. The setting also rejects `--agents` and `--mcp-config`. Read [`disableSideloadFlags`](/docs/en/settings-reference#disablesideloadflags) before you set it.
161161 
162Mods built into Claude Code, such as `AGENTS.md` support, aren't affected by these settings. Each has [its own switch](/docs/en/plugins/mods/overview#mods-built-into-claude-code).
162Mods built into Claude Code, such as `AGENTS.md` support, aren't affected by these settings. Each has [its own switch](/docs/en/plugins/mods/overview.md#mods-built-into-claude-code).
163163 
164A user whose mod was refused or didn't load finds the reason in their debug log. [Refusal messages](/docs/en/plugins/mods/troubleshoot#refusal-messages) lists the lines for `allowManagedHooksOnly` and `disableAllHooks`, and [Messages from the built-in guard](/docs/en/plugins/mods/troubleshoot#messages-from-the-built-in-guard) has the line for `allowManagedModsOnly`.
164A user whose mod was refused or didn't load finds the reason in their debug log. [Refusal messages](/docs/en/plugins/mods/troubleshoot.md#refusal-messages) lists the lines for `allowManagedHooksOnly` and `disableAllHooks`, and [Messages from the built-in guard](/docs/en/plugins/mods/troubleshoot.md#messages-from-the-built-in-guard) has the line for `allowManagedModsOnly`.
165165 
166166### Allow only your organization's mods
167167 
from line 197
197197* **A mod the user installed**: a line reads `refused by cc-plugin-sec-default: mods are limited to your organization's by policy (allowManagedModsOnly)`. An earlier line says that mod's hooks module `loaded`, so look for the refusal.
198198* **A plugin directory**: `claude --plugin-dir ./any-mod` exits with a message that starts `--plugin-dir is disabled by your organization's managed settings (disableSideloadFlags)`
199199 
200To also limit which marketplaces users can add, combine this file with your [marketplace restrictions](/docs/en/plugins/org#restrict-what-users-can-install).
200To also limit which marketplaces users can add, combine this file with your [marketplace restrictions](/docs/en/plugins/org.md#restrict-what-users-can-install).
201201 
202202### Apply your plugin controls to mods
203203 
204A mod is a plugin, so the ways you [manage plugins for your organization](/docs/en/plugins/org) also apply to a plugin that holds a mod:
204A mod is a plugin, so the ways you [manage plugins for your organization](/docs/en/plugins/org.md) also apply to a plugin that holds a mod:
205205 
206* **See which plugins load across your fleet**: [Audit and review](/docs/en/plugins/org#audit-and-review)
207* **Decide when a plugin you reviewed can update**: [Set update policy](/docs/en/plugins/org#set-update-policy)
208* **Give one group a different policy, such as a pilot**: [Plan for what managed settings can't enforce](/docs/en/plugins/org#plan-for-what-managed-settings-can’t-enforce)
209* **Check which apps and session kinds apply the plugin keys**: [When each surface applies the plugin keys](/docs/en/plugins/org#when-each-surface-applies-the-plugin-keys)
210* **Set up CI and containers**: [Seed containers and CI](/docs/en/plugins/org#seed-containers-and-ci)
211* **Offer mods your users may install**: [Host a marketplace](/docs/en/plugins/host-marketplace). A mod that Claude Code copies from a GitHub, git, URL, or npm source counts as a user's, not as [your organization's](#install-your-organizations-mods).
206* **See which plugins load across your fleet**: [Audit and review](/docs/en/plugins/org.md#audit-and-review)
207* **Decide when a plugin you reviewed can update**: [Set update policy](/docs/en/plugins/org.md#set-update-policy)
208* **Give one group a different policy, such as a pilot**: [Plan for what managed settings can't enforce](/docs/en/plugins/org.md#plan-for-what-managed-settings-can’t-enforce)
209* **Check which apps and session kinds apply the plugin keys**: [When each surface applies the plugin keys](/docs/en/plugins/org.md#when-each-surface-applies-the-plugin-keys)
210* **Set up CI and containers**: [Seed containers and CI](/docs/en/plugins/org.md#seed-containers-and-ci)
211* **Offer mods your users may install**: [Host a marketplace](/docs/en/plugins/host-marketplace.md). A mod that Claude Code copies from a GitHub, git, URL, or npm source counts as a user's, not as [your organization's](#install-your-organizations-mods).
212212 
213213### Set options on the built-in guard
214214 
from line 228
228228* **The guard has to load**: if you set `prependPlugins`, [name the guard in the list](#install-your-organizations-mods). Where the guard doesn't load, neither option applies.
229229* **The guard fails closed**: if the guard can't read managed settings, it refuses every user's mod at load. If it can't check the deny rules for a call that a user's mod approved, it refuses the call.
230230 
231The [messages from the built-in guard](/docs/en/plugins/mods/troubleshoot#messages-from-the-built-in-guard) are what your users see when either option applies.
231The [messages from the built-in guard](/docs/en/plugins/mods/troubleshoot.md#messages-from-the-built-in-guard) are what your users see when either option applies.
232232 
233233## Run your organization's own mods
234234 
from line 239
239239Your organization's mods load where users' mods don't and can run ahead of them, so Claude Code has to be able to tell that a mod came from you. It treats a mod as your organization's only when all of these are true:
240240 
241241* Managed `enabledPlugins` sets the mod's plugin to `true`
242* Managed settings name the plugin's [marketplace](/docs/en/plugins/create-marketplace) as a directory on the user's machine, by absolute path. An `extraKnownMarketplaces` entry does that and registers the marketplace for the user too.
243* The marketplace lists the plugin by a relative path, so Claude Code [loads it in place](/docs/en/plugins/loading#in-place-and-copied-plugins) from that directory
242* Managed settings name the plugin's [marketplace](/docs/en/plugins/create-marketplace.md) as a directory on the user's machine, by absolute path. An `extraKnownMarketplaces` entry does that and registers the marketplace for the user too.
243* The marketplace lists the plugin by a relative path, so Claude Code [loads it in place](/docs/en/plugins/loading.md#in-place-and-copied-plugins) from that directory
244244 
245245To meet them, have your device management copy the marketplace directory to the same path on every machine. Make the directory and every directory above it writable only by an administrator, as the managed settings file is. Anyone who can write there can rewrite your mod. Managed settings you deliver from the claude.ai admin console can carry the keys, but they can't put the directory on a machine.
246246 
from line 273
273273 
274274A plugin that Claude Code copies into its cache counts as a user's, even when managed `enabledPlugins` enables it. That covers every plugin from a GitHub, git, URL, or npm source. Its mod runs among users' mods, `prependPlugins` and `appendPlugins` skip it, `allowManagedModsOnly` refuses it, and `allowManagedHooksOnly` keeps it from loading. The user's debug log has a line that starts with the plugin's id and `is enabled by managed settings, but`.
275275 
276Claude Code fires an event each time it's about to act, such as run a tool, and passes it to each mod in turn. A mod that counts as yours [runs before users' mods](/docs/en/plugins/mods/events#the-order-mods-run-in) even when you list it nowhere. To set its place, list its id in one of two settings. The id is the plugin's name, `@`, and the marketplace's name, such as `acme-guard@acme-tools`.
276Claude Code fires an event each time it's about to act, such as run a tool, and passes it to each mod in turn. A mod that counts as yours [runs before users' mods](/docs/en/plugins/mods/events.md#the-order-mods-run-in) even when you list it nowhere. To set its place, list its id in one of two settings. The id is the plugin's name, `@`, and the marketplace's name, such as `acme-guard@acme-tools`.
277277 
278278* **`prependPlugins`**: your mod sees every event before any user's mod and every result after. It can change the event, refuse it, or skip the users' mods.
279279* **`appendPlugins`**: your mod runs after every user's mod, so it sees only the events those mods pass on, in the form they pass them
from line 298
298298* **`enabledPlugins`**: turns `acme-guard` on for every user who receives these managed settings
299299* **`prependPlugins`**: puts `acme-guard` first and the built-in guard second, both ahead of any mod a user installs. Claude Code follows the order you list.
300300 
301To confirm that a user's machine received the settings, see [Check that a policy is in force](/docs/en/managed-settings#check-that-a-policy-is-in-force).
301To confirm that a user's machine received the settings, see [Check that a policy is in force](/docs/en/managed-settings.md#check-that-a-policy-is-in-force).
302302 
303To confirm where the mod runs, start a session on that machine with `claude --debug` and search the [debug log](/docs/en/plugins/mods/troubleshoot#read-the-debug-log) for the mod's id:
303To confirm where the mod runs, start a session on that machine with `claude --debug` and search the [debug log](/docs/en/plugins/mods/troubleshoot.md#read-the-debug-log) for the mod's id:
304304 
305305* **`hooks module acme-guard@acme-tools loaded`, with `tier prepend`**: the mod counts as your organization's and runs first
306306* **The same line with `tier user`**: Claude Code treats it as a user's mod. A second line, `prependPlugins names acme-guard@acme-tools, which is not an enabled managed plugin with a hooks module; skipped`, says the list skipped it.
from line 315
315315 
316316To keep every user's mod out, you don't need a mod of your own. Set [`allowManagedModsOnly`](#stop-user-installed-mods-from-loading). Write a policy mod when you want to allow some users' mods and refuse others, or to record what mods do.
317317 
318Each time another mod is about to load, your mod receives the list that `claude plugin validate` prints, in an event named [`plugin.register`](/docs/en/plugins/mods/reference#other-mods). A mod in `prependPlugins` can read that list and refuse the mod. It can also [handle any mods API call by name](/docs/en/plugins/mods/api#reach-files-processes-and-the-network) to record or refuse that call for every other mod. The name is the method without the `$.`, so a hook on `fs.write` sees every `$.fs.write` call.
318Each time another mod is about to load, your mod receives the list that `claude plugin validate` prints, in an event named [`plugin.register`](/docs/en/plugins/mods/reference#other-mods). A mod in `prependPlugins` can read that list and refuse the mod. It can also [handle any mods API call by name](/docs/en/plugins/mods/api.md#reach-files-processes-and-the-network) to record or refuse that call for every other mod. The name is the method without the `$.`, so a hook on `fs.write` sees every `$.fs.write` call.
319319 
320320This policy mod refuses any user's mod whose own code calls `$.process.run` or `$.process.spawn`. It also keeps an audit log, writing each tool call and each file a mod writes to the debug log. Because it runs first, the log records what was requested, before any user's mod changes it. Save it as `acme-guard/hooks/register.js`:
321321 
from line 361
361361* **`e.tier`**: where the mod would run, one of `prepend`, `user`, `append`, or `builtin`. Every mod a person installs is `user`.
362362* **`e.uses.calls`**: the mods API methods the mod calls, each written `namespace.method` such as `process.run`, without the `$.` that `claude plugin validate` prints
363363 
364When a user installs a mod that calls `$.process.run`, the mod doesn't load, and their debug log has a line that ends with `refused by acme-guard:` and your reason. The refusal also reaches the transcript in a [session that hot-reloads a plugin directory](/docs/en/plugins/mods/troubleshoot#find-out-why-a-mod-does-nothing). To block a call without refusing the whole mod, return `{ deny: 'your reason' }` from a hook on that call's name.
364When a user installs a mod that calls `$.process.run`, the mod doesn't load, and their debug log has a line that ends with `refused by acme-guard:` and your reason. The refusal also reaches the transcript in a [session that hot-reloads a plugin directory](/docs/en/plugins/mods/troubleshoot.md#find-out-why-a-mod-does-nothing). To block a call without refusing the whole mod, return `{ deny: 'your reason' }` from a hook on that call's name.
365365 
366366To send the audit lines somewhere other than the debug log, call `$.http.fetch` from the same hooks.
367367 
368A session can run without your mod. If the worker thread that runs installed mods [crashes three times](/docs/en/plugins/mods/troubleshoot#mods-that-run-in-the-hooks-worker-are-off-for-this-session), Claude Code unloads every mod that isn't built in, including yours, until the user runs `/reload-plugins` or starts a new session. And a user who starts Claude Code with `--safe-mode` runs without installed mods, yours included.
368A session can run without your mod. If the worker thread that runs installed mods [crashes three times](/docs/en/plugins/mods/troubleshoot.md#mods-that-run-in-the-hooks-worker-are-off-for-this-session), Claude Code unloads every mod that isn't built in, including yours, until the user runs `/reload-plugins` or starts a new session. And a user who starts Claude Code with `--safe-mode` runs without installed mods, yours included.
369369 
370[Create a mod](/docs/en/plugins/mods/create) covers the files a mod needs. [Test a policy mod](/docs/en/plugins/mods/test#test-a-mod-that-judges-other-mods) has a test file for this policy mod.
370[Create a mod](/docs/en/plugins/mods/create.md) covers the files a mod needs. [Test a policy mod](/docs/en/plugins/mods/test.md#test-a-mod-that-judges-other-mods) has a test file for this policy mod.
371371 
372372#### Refuse mods when your check fails
373373 
from line 396
396396}
397397```
398398 
399With the handler in place, a mod that was being checked when the check threw or timed out doesn't load, and the refusal line carries the second reason, as in `refused by acme-guard: Acme policy check failed, so this mod was not loaded`. The handler passes every mod outside the `user` tier to `next(e)`, so a failed check doesn't stop the mods your organization lists. [Handle a hook that fails](/docs/en/plugins/mods/events#handle-a-hook-that-fails) covers `.catch` for other events.
399With the handler in place, a mod that was being checked when the check threw or timed out doesn't load, and the refusal line carries the second reason, as in `refused by acme-guard: Acme policy check failed, so this mod was not loaded`. The handler passes every mod outside the `user` tier to `next(e)`, so a failed check doesn't stop the mods your organization lists. [Handle a hook that fails](/docs/en/plugins/mods/events.md#handle-a-hook-that-fails) covers `.catch` for other events.
400400 
401401## Next steps
402402 
403* [Plugin security](/docs/en/plugins/security): what any plugin can do on a user's machine, and how to review one before it's installed
404* [Mods overview](/docs/en/plugins/mods/overview): what a mod is and how it compares to hooks, skills, and MCP servers
405* [The order mods run in](/docs/en/plugins/mods/events#the-order-mods-run-in): how `prependPlugins` and `appendPlugins` fit with users' mods
406* [Settings and environment variables](/docs/en/plugins/mods/reference#settings-and-environment-variables): every setting named on this page in one table
403* [Plugin security](/docs/en/plugins/security.md): what any plugin can do on a user's machine, and how to review one before it's installed
404* [Mods overview](/docs/en/plugins/mods/overview.md): what a mod is and how it compares to hooks, skills, and MCP servers
405* [The order mods run in](/docs/en/plugins/mods/events.md#the-order-mods-run-in): how `prependPlugins` and `appendPlugins` fit with users' mods
406* [Settings and environment variables](/docs/en/plugins/mods/reference.md#settings-and-environment-variables): every setting named on this page in one table
407407 

plugins/mods/api Changed · +27 / -27 lines

from line 2
22 
33> Call the mods API from a Claude Code mod to add commands and tools, call a model, run work on a timer, message other sessions, and reach files and the network.
44 
5The mods API is the set of methods a mod calls to act: add commands and tools, call a model, run work between events, and reach the file system, processes, and the network. Every hook receives it as its first argument, `$`, with the methods grouped in namespaces such as `$.ui` and `$.fs`. [Events](/docs/en/plugins/mods/events) decide when a hook runs, and the mods API is what the hook calls once it does.
5The mods API is the set of methods a mod calls to act: add commands and tools, call a model, run work between events, and reach the file system, processes, and the network. Every hook receives it as its first argument, `$`, with the methods grouped in namespaces such as `$.ui` and `$.fs`. [Events](/docs/en/plugins/mods/events.md) decide when a hook runs, and the mods API is what the hook calls once it does.
66 
7Build your [first mod](/docs/en/plugins/mods/create) before you start here. For every method, see [mods API methods](/docs/en/plugins/mods/reference#mods-api-methods) or read [the types for your build](/docs/en/plugins/mods/create#get-the-types-for-your-build).
7Build your [first mod](/docs/en/plugins/mods/create.md) before you start here. For every method, see [mods API methods](/docs/en/plugins/mods/reference.md#mods-api-methods) or read [the types for your build](/docs/en/plugins/mods/create.md#get-the-types-for-your-build).
88 
99## Add a command or a tool
1010 
from line 30
3030 
3131After the session starts, `/standup` appears with its description in the list you see when you type `/`. The `argumentHint` shows in the prompt after you type the command and a space, as in `/standup [days]`. When you run `/standup 3`, the second hook returns `Summary for the last 3 day(s): ...`, and the transcript shows that text after the plugin's name. The hook never calls `next`, because the command has no behavior other than yours.
3232 
33The `text` you return prints in the transcript and Claude reads it. To print nothing, as a command that only opens a [pane](/docs/en/plugins/mods/interface#pick-where-to-draw) does, return `{}`. To let the command run while Claude is working, add `immediate: true` to the registration.
33The `text` you return prints in the transcript and Claude reads it. To print nothing, as a command that only opens a [pane](/docs/en/plugins/mods/interface.md#pick-where-to-draw) does, return `{}`. To let the command run while Claude is working, add `immediate: true` to the registration.
3434 
3535Pick a name that no built-in command uses. Type `/` in a session to see them. `$.command.register` throws for a taken name, with a message such as `"/focus" refused: it is the built-in /focus`. A hook that throws is skipped, so the rest of your `session.start` hook doesn't run either. Register commands last in that hook, or wrap the call in `try` and `catch`.
3636 
from line 63
6363 
6464> [!TIP]
6565>
66> When [MCP tool search](/docs/en/mcp#scale-with-mcp-tool-search) defers a registered tool, Claude sees its name but not its description until it searches for it. If Claude should consider the tool on every turn, add [`isDeferred: false`](/docs/en/plugins/mods/reference#tools) to the registration to [load the full tool upfront](/docs/en/mcp#exempt-a-server-from-deferral). The field requires Claude Code v2.1.293 or later, and earlier versions ignore it.
66> When [MCP tool search](/docs/en/mcp.md#scale-with-mcp-tool-search) defers a registered tool, Claude sees its name but not its description until it searches for it. If Claude should consider the tool on every turn, add [`isDeferred: false`](/docs/en/plugins/mods/reference#tools) to the registration to [load the full tool upfront](/docs/en/mcp.md#exempt-a-server-from-deferral). The field requires Claude Code v2.1.293 or later, and earlier versions ignore it.
6767 
6868## Call a model
6969 
from line 74
7474| In the request | `$.model.complete` | `$.model.fork` |
7575| :- | :- | :- |
7676| Model | The `model` you pass | The session's model |
77| System prompt | A short [attribution block](/docs/en/llm-gateway-protocol#system-prompt-attribution-block), then your `system` if you pass one | The session's system prompt |
77| System prompt | A short [attribution block](/docs/en/llm-gateway-protocol.md#system-prompt-attribution-block), then your `system` if you pass one | The session's system prompt |
7878| Messages | One user message, your `prompt` | The conversation so far, then your `prompt` as a user message |
7979| CLAUDE.md and other project context | Not included | Included, as in the conversation's last request |
8080| Tools | None | Claude's tools, which the model can't call |
8181 
82A fork repeats the conversation's last request, so the Claude API serves most of it from the [prompt cache](/docs/en/prompt-caching) while the conversation is still cached.
82A fork repeats the conversation's last request, so the Claude API serves most of it from the [prompt cache](/docs/en/prompt-caching.md) while the conversation is still cached.
8383 
84Both calls use the session's credentials, so they bill to the user's plan, API key, or cloud provider. [The types for your build](/docs/en/plugins/mods/create#get-the-types-for-your-build) document every `$.model` method.
84Both calls use the session's credentials, so they bill to the user's plan, API key, or cloud provider. [The types for your build](/docs/en/plugins/mods/create.md#get-the-types-for-your-build) document every `$.model` method.
8585 
8686### Send one prompt
8787 
from line 110
110110 
111111A Claude API failure doesn't reject the call, so check `r.isAnswered`, and read `r.reason` when it's `false`. The call rejects for a request Claude Code won't send, such as a model your organization blocks.
112112 
113[The types for your build](/docs/en/plugins/mods/create#get-the-types-for-your-build) list the other options, such as `effort`, and the [limits](/docs/en/plugins/mods/reference#limits) give the `maxTokens` default.
113[The types for your build](/docs/en/plugins/mods/create.md#get-the-types-for-your-build) list the other options, such as `effort`, and the [limits](/docs/en/plugins/mods/reference.md#limits) give the `maxTokens` default.
114114 
115115### Use prompt caching
116116 
from line 149
149149Put the static content that your calls share at the start of `prompt` unless you know that your requests go directly to the Claude API:
150150 
151151* **Directly to the Claude API, with an API key or a Claude subscription**: either field works
152* **Through [Amazon Bedrock](/docs/en/amazon-bedrock), [Claude Platform on AWS](/docs/en/claude-platform-on-aws), [Google Cloud's Agent Platform](/docs/en/google-vertex-ai), [Microsoft Foundry](/docs/en/microsoft-foundry), or an [LLM gateway](/docs/en/llm-gateway)**: use `prompt`. Claude Code begins the system prompt with an [attribution block](/docs/en/llm-gateway-protocol#system-prompt-attribution-block) whose fingerprint comes from the start of the user message. The `api.anthropic.com` endpoint strips that block before caching. Other endpoints receive it as part of the prompt, so a breakpoint in `system` can miss when `prompt` starts differently.
152* **Through [Amazon Bedrock](/docs/en/amazon-bedrock.md), [Claude Platform on AWS](/docs/en/claude-platform-on-aws.md), [Google Cloud's Agent Platform](/docs/en/google-vertex-ai.md), [Microsoft Foundry](/docs/en/microsoft-foundry.md), or an [LLM gateway](/docs/en/llm-gateway)**: use `prompt`. Claude Code begins the system prompt with an [attribution block](/docs/en/llm-gateway-protocol.md#system-prompt-attribution-block) whose fingerprint comes from the start of the user message. The `api.anthropic.com` endpoint strips that block before caching. Other endpoints receive it as part of the prompt, so a breakpoint in `system` can miss when `prompt` starts differently.
153153* **In a mod that other people run**: use `prompt`, because you don't choose their provider
154154 
155155`system` comes before `prompt` in the prefix, so a breakpoint in `prompt` covers `system` too, and a call with a different `system` misses the cache.
from line 164
164164 
165165* **The prefix is too short**: the API doesn't cache a prefix under the model's [minimum length](https://platform.claude.com/docs/en/build-with-claude/prompt-caching#cache-limitations), and it returns no error
166166* **Prompt caching is disabled**: when a [`DISABLE_PROMPT_CACHING` variable](/docs/en/prompt-caching#disable-prompt-caching) applies to the model, Claude Code removes the breakpoints and sends the text uncached
167* **Your gateway strips `cache_control`**: a gateway can [remove the field and still return success](/docs/en/prompt-caching#where-the-cache-lives)
167* **Your gateway strips `cache_control`**: a gateway can [remove the field and still return success](/docs/en/prompt-caching.md#where-the-cache-lives)
168168* **Another mod rewrites the start of the text**: Claude Code then [sends it without breakpoints](#what-a-model-complete-hook-receives)
169169 
170170### What a `model.complete` hook receives
from line 179
179179 
180180## Run work in the background
181181 
182Work that outlives one event, such as checking on something once a minute, runs on a timer you start from `session.start`. A hook itself runs for one event and has a [time limit](/docs/en/plugins/mods/reference#limits) on its own execution time. Time spent waiting on `next` or on a mods API call doesn't count, except a `$.clock.sleep`. `$.clock.every` and `$.clock.after` take the place of `setInterval` and `setTimeout`, with the delay in milliseconds first: `$.clock.after(5000, fn)` calls `fn` once, five seconds from now. Each returns a timer with a `cancel()` method, and `await $.clock.now()` gives the time in milliseconds.
182Work that outlives one event, such as checking on something once a minute, runs on a timer you start from `session.start`. A hook itself runs for one event and has a [time limit](/docs/en/plugins/mods/reference.md#limits) on its own execution time. Time spent waiting on `next` or on a mods API call doesn't count, except a `$.clock.sleep`. `$.clock.every` and `$.clock.after` take the place of `setInterval` and `setTimeout`, with the delay in milliseconds first: `$.clock.after(5000, fn)` calls `fn` once, five seconds from now. Each returns a timer with a `cancel()` method, and `await $.clock.now()` gives the time in milliseconds.
183183 
184184This hook looks up a pull request's checks once a minute and shows the result under the prompt. `summarize` is a function of your own that turns the command's JSON output into a few words:
185185 
from line 196
196196})
197197```
198198 
199The session starts as usual. A minute later, a line appears under the prompt with a `⚠`, the mod's name, and then `checks:` and your summary. It's replaced once a minute after that. The timer's callback runs outside any event, so it keeps running between turns and doesn't start one. If the callback throws, the error goes to the [debug log](/docs/en/plugins/mods/troubleshoot#read-the-debug-log) and the timer runs again at the next interval.
199The session starts as usual. A minute later, a line appears under the prompt with a `⚠`, the mod's name, and then `checks:` and your summary. It's replaced once a minute after that. The timer's callback runs outside any event, so it keeps running between turns and doesn't start one. If the callback throws, the error goes to the [debug log](/docs/en/plugins/mods/troubleshoot.md#read-the-debug-log) and the timer runs again at the next interval.
200200 
201201### Show something without starting a turn
202202 
from line 205
205205| Call | What the user sees |
206206| :- | :- |
207207| `$.ui.status(text)` | One line under the prompt that stays until you change it. It starts with `⚠` and the mod's name, as in `⚠ my-mod: checks: 3 passing`. |
208| `$.ui.toast(text)` | A toast notification with the mod's name that disappears after a few seconds. It's a box at the top right in [fullscreen rendering](/docs/en/fullscreen), and one line at the right under the prompt in the classic renderer. |
208| `$.ui.toast(text)` | A toast notification with the mod's name that disappears after a few seconds. It's a box at the top right in [fullscreen rendering](/docs/en/fullscreen.md), and one line at the right under the prompt in the classic renderer. |
209209| `$.ui.log(text)` | A dim line in the transcript that Claude doesn't read. It starts with `●` and the mod's name, as in `● my-mod: build finished`. |
210210| `$.ui.notify(text)` | A notification from their terminal, outside Claude Code, sent the way their [`preferredNotifChannel`](/docs/en/settings-reference#preferrednotifchannel) setting says. The mod's name is its title unless you pass a non-empty `{ title }`, which is shown as you give it. |
211211 
from line 244
244244})
245245```
246246 
247In the [VS Code extension](/docs/en/plugins/mods/interface#draw-in-the-vs-code-extension), status lines and toasts show above the prompt box instead, and log lines in the conversation.
247In the [VS Code extension](/docs/en/plugins/mods/interface.md#draw-in-the-vs-code-extension), status lines and toasts show above the prompt box instead, and log lines in the conversation.
248248 
249249### Start a turn from a background job
250250 
from line 269
269269* **`the session was stopped and nobody has sent input since`**: the call was refused
270270* **`was removed from the queue before it ran`**: the prompt or command left the queue without running and was dropped, for example when the user stopped the turn
271271 
272In this example, call `submitPrompt` from your background job in place of [`$.prompt.submit`](#start-a-turn-from-a-background-job). Put the `pendingText` variable and the `submitPrompt` function above [`register`](/docs/en/plugins/mods/reference#files), and the `turn.complete` hook inside it, because [validation](/docs/en/plugins/mods/create#check-what-claude-code-reads-from-your-mod) refuses `$` passed to a function declared inside `register`. When the result or the error carries one of those strings, `submitPrompt` keeps the text in `pendingText` for the `turn.complete` hook to submit again:
272In this example, call `submitPrompt` from your background job in place of [`$.prompt.submit`](#start-a-turn-from-a-background-job). Put the `pendingText` variable and the `submitPrompt` function above [`register`](/docs/en/plugins/mods/reference#files), and the `turn.complete` hook inside it, because [validation](/docs/en/plugins/mods/create.md#check-what-claude-code-reads-from-your-mod) refuses `$` passed to a function declared inside `register`. When the result or the error carries one of those strings, `submitPrompt` keeps the text in `pendingText` for the `turn.complete` hook to submit again:
273273 
274274```javascript theme={null}
275275// The text of the last refused or dropped prompt, or null
from line 317
317317| `$.command.run` | Rejects with an error whose message ends with `<reason>` |
318318| [`$.agent.spawn`](/docs/en/plugins/mods/reference#mods-api-methods) | Resolves with `{ deny: '<reason>' }` and starts no subagent |
319319| `$.session.send` to a subagent that finished | Resolves with `{ isDelivered: false, reason: 'Agent "<id>" was not resumed: <reason>.' }`, where `<id>` is the subagent's id. A subagent that's still running receives the message. |
320| `$.session.send` to an [agent team](/docs/en/agent-teams) teammate | Resolves with `{ isDelivered: false, reason: 'Teammate "<name>" was not messaged: <reason>.' }`, where `<name>` is the teammate's name |
320| `$.session.send` to an [agent team](/docs/en/agent-teams.md) teammate | Resolves with `{ isDelivered: false, reason: 'Teammate "<name>" was not messaged: <reason>.' }`, where `<name>` is the teammate's name |
321321| [`$.tool.call`](/docs/en/plugins/mods/reference#mods-api-methods) of Bash with `run_in_background: true`, Monitor, or CronCreate | Resolves with `{ deny: '<tool> was not run: it starts background work, a schedule or a goal, and <reason>' }`, where `<tool>` is the tool's name |
322322 
323323Along with these `$.session.send` and `$.tool.call` results, the user can see the [`Stopped:` toast](/docs/en/plugins/mods/troubleshoot#stopped-type-a-message-to-continue).
from line 339
339339 
340340## Send and receive messages between sessions
341341 
342A mod can send a plain-text message to another of your sessions, to one of this session's subagents, or to a teammate in its [agent team](/docs/en/agent-teams). It can also observe the messages that arrive and leave.
342A mod can send a plain-text message to another of your sessions, to one of this session's subagents, or to a teammate in its [agent team](/docs/en/agent-teams.md). It can also observe the messages that arrive and leave.
343343 
344344To send one, call `$.session.send({ to, text })`, which makes the same delivery the SendMessage tool makes. Set `to` by who receives the message:
345345 
from line 371
371371| `session.receive` | A message arrives for this session, before Claude reads it | `e.text`, and `e.origin.kind`, such as `peer` or `peer-send-message` for another session or agent, `task-notification`, or `scheduled-trigger`. Return `{ consumed: reason }` to keep it from Claude. |
372372| `session.send` | A message is about to leave, from the SendMessage tool or a mod | `e.to`, `e.text`, and `e.origin.kind`, which is `model` or `plugin` |
373373 
374A session set to [refuse inbound messages](/docs/en/cross-session-messaging#control-inbound-messages) refuses a message before `session.receive` fires, so a hook never sees it. A message that's held for your approval reaches the hook first, so a mod can read a message you haven't approved yet. The hook's `next(e)` rejects when the message isn't delivered.
374A session set to [refuse inbound messages](/docs/en/cross-session-messaging.md#control-inbound-messages) refuses a message before `session.receive` fires, so a hook never sees it. A message that's held for your approval reaches the hook first, so a mod can read a message you haven't approved yet. The hook's `next(e)` rejects when the message isn't delivered.
375375 
376376The sender's name on a received message is whatever the sender wrote, so don't base a decision on it.
377377 
from line 395
395395* **Paths**: a relative path resolves against the working directory of the session, or of the subagent whose event the hook is handling
396396* **`$.fs.list`**: returns one directory's entries as `{ name, kind, size, isLink }` and isn't recursive
397397* **`$.process.run`**: takes an argument list and uses no shell. It resolves to `{ exitCode, stdout, stderr }` whatever the exit code. It rejects if the program can't start or is still running at the timeout, which is 30 seconds by default, so wrap it in `try` and `catch`.
398* **`$.http.fetch`**: follows up to five redirects. On a redirect to a different origin, it keeps only the `accept`, `accept-language`, `content-type`, and `user-agent` request headers you set and drops the rest, so a request that depends on another header, such as `Authorization`, can fail after that redirect. The [limits](/docs/en/plugins/mods/reference#limits) give its timeout and body sizes.
398* **`$.http.fetch`**: follows up to five redirects. On a redirect to a different origin, it keeps only the `accept`, `accept-language`, `content-type`, and `user-agent` request headers you set and drops the rest, so a request that depends on another header, such as `Authorization`, can fail after that redirect. The [limits](/docs/en/plugins/mods/reference.md#limits) give its timeout and body sizes.
399399 
400Every one of these calls is itself an event, named for its namespace and method without the `$.`, such as `fs.read` for `$.fs.read`. A mod [earlier in the chain](/docs/en/plugins/mods/events#the-order-mods-run-in) can observe, rewrite, or refuse your call, which is how an organization restricts what mods reach.
400Every one of these calls is itself an event, named for its namespace and method without the `$.`, such as `fs.read` for `$.fs.read`. A mod [earlier in the chain](/docs/en/plugins/mods/events.md#the-order-mods-run-in) can observe, rewrite, or refuse your call, which is how an organization restricts what mods reach.
401401 
402402A mod can refuse your `$.process.spawn` call after the command has produced output or exited, and nothing the command did is undone. The call then rejects with a message that ends with one of these strings and the refusing mod's reason:
403403 
from line 406
406406 
407407## Next steps
408408 
409* [React to events](/docs/en/plugins/mods/events): hook tool calls, prompts, and turns
410* [Draw in the interface](/docs/en/plugins/mods/interface): show what your mod collects in a pane or above the prompt
411* [Test a mod](/docs/en/plugins/mods/test): stub any of these calls in a test
412* [Mods reference](/docs/en/plugins/mods/reference): events, mods API methods, and limits
409* [React to events](/docs/en/plugins/mods/events.md): hook tool calls, prompts, and turns
410* [Draw in the interface](/docs/en/plugins/mods/interface.md): show what your mod collects in a pane or above the prompt
411* [Test a mod](/docs/en/plugins/mods/test.md): stub any of these calls in a test
412* [Mods reference](/docs/en/plugins/mods/reference.md): events, mods API methods, and limits
413413 

plugins/mods/create Changed · +29 / -29 lines

from line 2
22 
33> Have Claude write a Claude Code mod from a description, or write one yourself that counts tool calls and adds a command. Learn the reload and validate loop.
44 
5A mod is a Claude Code [plugin](/docs/en/plugins/overview) with an entry file, called the hooks module: a JavaScript or TypeScript file whose functions Claude Code calls when events happen. To make one:
5A mod is a Claude Code [plugin](/docs/en/plugins/overview.md) with an entry file, called the hooks module: a JavaScript or TypeScript file whose functions Claude Code calls when events happen. To make one:
66 
77* **Ask Claude to write it**: [describe what you want](#ask-claude-for-a-mod) in a Claude Code session
88* **Write it yourself**: [follow the tutorial](#write-a-mod-yourself) to learn how a mod's code works. You don't need Node.js, a bundler, or a build step, because Claude Code loads `.js` and `.ts` files directly.
99 
10If you haven't decided whether a mod is the right tool, read the [comparison on the overview](/docs/en/plugins/mods/overview#compare-mods-settings-hooks-skills-and-mcp-servers) first.
10If you haven't decided whether a mod is the right tool, read the [comparison on the overview](/docs/en/plugins/mods/overview.md#compare-mods-settings-hooks-skills-and-mcp-servers) first.
1111 
1212> [!NOTE]
1313>
14> Use Claude Code v2.1.287 or later. In your shell, run `claude --version` to check. To see whether mods can load for you, see [Check whether mods can load](/docs/en/plugins/mods/troubleshoot#check-whether-mods-can-load).
14> Use Claude Code v2.1.287 or later. In your shell, run `claude --version` to check. To see whether mods can load for you, see [Check whether mods can load](/docs/en/plugins/mods/troubleshoot.md#check-whether-mods-can-load).
1515 
1616## Ask Claude for a mod
1717 
18Describe the mod you want in an interactive Claude Code session, and Claude writes it. Claude works from a built-in [skill](/docs/en/skills) named `plugin-authoring`, which tells it where to write the mod, which events and methods your version has, and how the mod gets loaded. Claude can load the skill when you ask for a mod, or you can load it yourself by running `/plugin-authoring` at the Claude Code prompt.
18Describe the mod you want in an interactive Claude Code session, and Claude writes it. Claude works from a built-in [skill](/docs/en/skills.md) named `plugin-authoring`, which tells it where to write the mod, which events and methods your version has, and how the mod gets loaded. Claude can load the skill when you ask for a mod, or you can load it yourself by running `/plugin-authoring` at the Claude Code prompt.
1919 
2020The mod runs once you approve it, except in [sessions where a mod Claude writes can't load](#sessions-that-skip-the-approval).
2121 
from line 25
2525 
2626> [!NOTE]
2727>
28> In the `default` and `acceptEdits` [permission modes](/docs/en/permission-modes), Claude Code asks you to approve each of the mod's files before Claude creates it, because the mods folder is a [protected path](/docs/en/permission-modes#protected-paths). Approve each file as it comes up.
28> In the `default` and `acceptEdits` [permission modes](/docs/en/permission-modes.md), Claude Code asks you to approve each of the mod's files before Claude creates it, because the mods folder is a [protected path](/docs/en/permission-modes.md#protected-paths). Approve each file as it comes up.
2929 
3030**2. Approve the mod**
3131 
from line 57
5757 
5858* **Nobody is there to approve**: the session can't show you a prompt, as in a `claude -p` run or [`dontAsk` mode](/docs/en/permission-modes)
5959* **The workspace isn't trusted**: you haven't accepted the trust prompt for the directory
60* **Mods are disabled**: you started with `--safe-mode` or `--bare`, you set `disableAllHooks`, or your organization's [managed settings block it](/docs/en/plugins/mods/admin#choose-how-much-to-allow)
60* **Mods are disabled**: you started with `--safe-mode` or `--bare`, you set `disableAllHooks`, or your organization's [managed settings block it](/docs/en/plugins/mods/admin.md#choose-how-much-to-allow)
6161 
6262## Write a mod yourself
6363 
from line 78
7878 └── register.js
7979```
8080 
81* **`plugin.json`**: the plugin's [manifest](/docs/en/plugins/manifest-reference)
82* **`hooks.json`**: [points to your code file](/docs/en/plugins/mods/reference#files)
81* **`plugin.json`**: the plugin's [manifest](/docs/en/plugins/manifest-reference.md)
82* **`hooks.json`**: [points to your code file](/docs/en/plugins/mods/reference.md#files)
8383* **`register.js`**: your code, called the hooks module
8484 
8585**1. Create the plugin directory**
from line 100
100100 
101101**2. Write the manifest**
102102 
103A mod is a plugin, and a mod needs a [manifest](/docs/en/plugins/manifest-reference). This mod's manifest has no special fields. Save this as `first-mod/.claude-plugin/plugin.json`:
103A mod is a plugin, and a mod needs a [manifest](/docs/en/plugins/manifest-reference.md). This mod's manifest has no special fields. Save this as `first-mod/.claude-plugin/plugin.json`:
104104 
105105```json first-mod/.claude-plugin/plugin.json theme={null}
106106{
from line 201
201201first-mod: Claude has made 0 tool calls since this mod loaded
202202```
203203 
204If `/tally` isn't in the command list, the module didn't load. See [Find out why a mod does nothing](/docs/en/plugins/mods/troubleshoot#find-out-why-a-mod-does-nothing).
204If `/tally` isn't in the command list, the module didn't load. See [Find out why a mod does nothing](/docs/en/plugins/mods/troubleshoot.md#find-out-why-a-mod-does-nothing).
205205 
206206**7. Change the code while the session runs**
207207 
from line 221
221221 
222222Each function you pass to `on` is a hook, which is an event handler. Claude Code passes every hook the same three arguments:
223223 
224* **The mods API**, named `$`: every method a mod can call to reach outside itself, in [namespaces](/docs/en/plugins/mods/reference#mods-api-methods) such as `$.ui` and `$.command`
225* **The event**, named `e`: the [event's input](/docs/en/plugins/mods/reference#events) as plain data, such as a tool call's name and arguments
224* **The mods API**, named `$`: every method a mod can call to reach outside itself, in [namespaces](/docs/en/plugins/mods/reference.md#mods-api-methods) such as `$.ui` and `$.command`
225* **The event**, named `e`: the [event's input](/docs/en/plugins/mods/reference.md#events) as plain data, such as a tool call's name and arguments
226226* **The next handler**, named [`next`](/docs/en/plugins/mods/events#how-a-hook-handles-an-event): a function that passes the event on to the other mods and then to Claude Code's own behavior, and returns the result
227227 
228228The hooks in `first-mod` handle their events in these ways:
229229 
230230* **Observe**: the `session.start` hook registers the command, and the `tool.call` hook counts the call and asks for a redraw. Both return `next(e)`, so the session starts and the tool runs as usual.
231* **Answer**: the `command.run` hook returns its own result and never calls `next`. The second argument to `on`, `{ command: 'tally' }`, is a filter, called a [matcher](/docs/en/plugins/mods/events#filter-which-events-a-hook-handles), so the hook runs only for `/tally`.
231* **Answer**: the `command.run` hook returns its own result and never calls `next`. The second argument to `on`, `{ command: 'tally' }`, is a filter, called a [matcher](/docs/en/plugins/mods/events.md#filter-which-events-a-hook-handles), so the hook runs only for `/tally`.
232232* **Rewrite**: the `ui.render` hook calls `next` with a copy of `e` whose `suffix` holds the count, so Claude Code draws its usual spinner with your text after the word
233233 
234Claude Code watches a directory loaded with `--plugin-dir` and hot-reloads the hooks module when a file in it changes. Each reload runs `register` again, so `calls` resets to `0` and `/tally` starts counting again. To keep a value across reloads, see [Keep state](/docs/en/plugins/mods/interface#keep-state).
234Claude Code watches a directory loaded with `--plugin-dir` and hot-reloads the hooks module when a file in it changes. Each reload runs `register` again, so `calls` resets to `0` and `/tally` starts counting again. To keep a value across reloads, see [Keep state](/docs/en/plugins/mods/interface.md#keep-state).
235235 
236236## Keep working on a mod
237237 
from line 245
245245claude --plugin-dir ./first-mod
246246```
247247 
248Then ask for the change, for example `add a /tally-reset command to this mod that sets the tally back to zero`. Claude edits the hooks module, runs `claude plugin validate`, and fixes what it reports. A directory you load with `--plugin-dir` is a [protected path](/docs/en/permission-modes#protected-paths), so in `default` and `acceptEdits` modes you're asked to approve each of Claude's edits to the mod. The protected paths table gives the result for the other permission modes.
248Then ask for the change, for example `add a /tally-reset command to this mod that sets the tally back to zero`. Claude edits the hooks module, runs `claude plugin validate`, and fixes what it reports. A directory you load with `--plugin-dir` is a [protected path](/docs/en/permission-modes.md#protected-paths), so in `default` and `acceptEdits` modes you're asked to approve each of Claude's edits to the mod. The protected paths table gives the result for the other permission modes.
249249 
250250Files Claude saves during its turn reload when the turn ends, so you can try `/tally-reset` as soon as Claude finishes.
251251 
from line 295
295295* Inside `register`, don't declare a second variable or parameter named `on`. Validation fails with `"on" is declared again (shadowed)`.
296296* Import only from files inside the plugin directory, by relative path. The one bare import allowed is `claude-code`, for types and a few helpers.
297297* Use `import` declarations at the top of the file, as in `import { name } from './file.js'`. A dynamic `import()` fails with `a dynamic import(); a hooks module imports its own files with an import declaration`.
298* Write every file as an ES module, with `import` and not `require`. The [reference](/docs/en/plugins/mods/reference#files) lists the file extensions Claude Code loads.
298* Write every file as an ES module, with `import` and not `require`. The [reference](/docs/en/plugins/mods/reference.md#files) lists the file extensions Claude Code loads.
299299 
300300### Test the mod
301301 
from line 337
337337Ran 1 test across 1 file. [0.19s]
338338```
339339 
340[Test a mod](/docs/en/plugins/mods/test) covers stubbing a model call or the store, and testing timers and drawings.
340[Test a mod](/docs/en/plugins/mods/test.md) covers stubbing a model call or the store, and testing timers and drawings.
341341 
342342## Share your mod
343343 
344344A mod is a plugin, so you version it in the manifest and people install and update it with the `/plugin` commands. How you share it depends on who it's for:
345345 
346* **A few people**: send them the plugin's directory or a `.zip` of it. See [Share a plugin without a marketplace](/docs/en/plugins/publish#share-a-plugin-without-a-marketplace)
347* **Your team**: list it in [your own marketplace](/docs/en/plugins/publish#publish-through-your-own-marketplace), such as a private repository with one directory for each plugin. To add that marketplace for everyone who works in a repository, [register it in the repository's settings](/docs/en/plugins/host-marketplace#register-the-marketplace-for-everyone-in-a-repository)
348* **Your whole organization**: an administrator can [install your organization's mods](/docs/en/plugins/mods/admin#install-your-organizations-mods) through managed settings
349* **Anyone**: make your marketplace's repository public, or [submit the plugin to Anthropic's directory](/docs/en/plugins/publish#submit-to-anthropics-directory)
346* **A few people**: send them the plugin's directory or a `.zip` of it. See [Share a plugin without a marketplace](/docs/en/plugins/publish.md#share-a-plugin-without-a-marketplace)
347* **Your team**: list it in [your own marketplace](/docs/en/plugins/publish.md#publish-through-your-own-marketplace), such as a private repository with one directory for each plugin. To add that marketplace for everyone who works in a repository, [register it in the repository's settings](/docs/en/plugins/host-marketplace.md#register-the-marketplace-for-everyone-in-a-repository)
348* **Your whole organization**: an administrator can [install your organization's mods](/docs/en/plugins/mods/admin.md#install-your-organizations-mods) through managed settings
349* **Anyone**: make your marketplace's repository public, or [submit the plugin to Anthropic's directory](/docs/en/plugins/publish.md#submit-to-anthropics-directory)
350350 
351Before you do, check the plugin's `name`: `claude plugin validate` fails a name that [looks like one of Anthropic's own](/docs/en/plugins/manifest-reference#name), such as one that starts with `claude-`. The events and methods can change between releases, so your README is the place to say which Claude Code version you tested with.
351Before you do, check the plugin's `name`: `claude plugin validate` fails a name that [looks like one of Anthropic's own](/docs/en/plugins/manifest-reference.md#name), such as one that starts with `claude-`. The events and methods can change between releases, so your README is the place to say which Claude Code version you tested with.
352352 
353353Keep developing against the directory with `--plugin-dir`, not against an installed copy. Claude Code caches an installed plugin by version, so your edits don't reach the installed copy until you increment the version and install again.
354354 
355355## Next steps
356356 
357* [Draw in the interface](/docs/en/plugins/mods/interface): open a pane, draw above the prompt, and add buttons and text fields
358* [React to events](/docs/en/plugins/mods/events): hook tool calls, prompts, and turns
359* [Use the mods API](/docs/en/plugins/mods/api): add commands and tools, call a model, and run work on a timer
360* [Test a mod](/docs/en/plugins/mods/test): stub what Claude Code would answer, and test timers and drawings
361* [Troubleshoot a mod](/docs/en/plugins/mods/troubleshoot): the reasons a mod does nothing, and the debug log
362* [Read the source of built-in mods](/docs/en/plugins/mods/overview#read-the-source-of-built-in-mods): complete plugins, each with its hooks module and tests
357* [Draw in the interface](/docs/en/plugins/mods/interface.md): open a pane, draw above the prompt, and add buttons and text fields
358* [React to events](/docs/en/plugins/mods/events.md): hook tool calls, prompts, and turns
359* [Use the mods API](/docs/en/plugins/mods/api.md): add commands and tools, call a model, and run work on a timer
360* [Test a mod](/docs/en/plugins/mods/test.md): stub what Claude Code would answer, and test timers and drawings
361* [Troubleshoot a mod](/docs/en/plugins/mods/troubleshoot.md): the reasons a mod does nothing, and the debug log
362* [Read the source of built-in mods](/docs/en/plugins/mods/overview.md#read-the-source-of-built-in-mods): complete plugins, each with its hooks module and tests
363363 

plugins/mods/events Changed · +29 / -29 lines

from line 4
44 
55A hook is an event handler: a function that Claude Code runs when a named event happens. Claude Code fires an event at each point where it's about to act, such as when it runs a tool, submits a prompt, sends a request to the model, or starts or ends a session. Your hook runs before Claude Code acts, so it can observe the event, rewrite it, or answer it in Claude Code's place. You register a hook with [`on(eventName, handler)`](/docs/en/plugins/mods/reference#the-hook-function).
66 
7Build your [first mod](/docs/en/plugins/mods/create) before you start here. For every event and its exact fields, see the [reference](/docs/en/plugins/mods/reference#events) or read [the types for your build](/docs/en/plugins/mods/create#get-the-types-for-your-build).
7Build your [first mod](/docs/en/plugins/mods/create.md) before you start here. For every event and its exact fields, see the [reference](/docs/en/plugins/mods/reference.md#events) or read [the types for your build](/docs/en/plugins/mods/create.md#get-the-types-for-your-build).
88 
99## How a hook handles an event
1010 
11A hook sits between an event and what Claude Code would do about it, so it can observe the event, rewrite it, or answer it itself. It receives three arguments: the [mods API](/docs/en/plugins/mods/api) as `$`, the event as `e`, and the next handler as `next`. The handlers for an event form a middleware chain. `next(e)` calls the next handler, which is another mod's hook or, at the end of the chain, Claude Code's own behavior, and it resolves to the result. What your hook does with `next` decides which of the three it does.
11A hook sits between an event and what Claude Code would do about it, so it can observe the event, rewrite it, or answer it itself. It receives three arguments: the [mods API](/docs/en/plugins/mods/api.md) as `$`, the event as `e`, and the next handler as `next`. The handlers for an event form a middleware chain. `next(e)` calls the next handler, which is another mod's hook or, at the end of the chain, Claude Code's own behavior, and it resolves to the result. What your hook does with `next` decides which of the three it does.
1212 
1313### Observe an event
1414 
from line 64
6464})
6565```
6666 
67When Claude tries a Bash command, the command doesn't run, and Claude reads the `deny` text as the tool's result. Each event has its own result shape, which the [events reference](/docs/en/plugins/mods/reference#events) lists.
67When Claude tries a Bash command, the command doesn't run, and Claude reads the `deny` text as the tool's result. Each event has its own result shape, which the [events reference](/docs/en/plugins/mods/reference.md#events) lists.
6868 
6969### Filter which events a hook handles
7070 
from line 83
8383 
8484`hook` runs once for a Bash, Edit, or Write call, and once for a call to a tool whose name starts with `mcp__github__`. A call to any other tool, such as Read, matches none of the three, so `hook` doesn't run for it.
8585 
86The event name can be a wildcard. `'classic.*'` matches every [settings hook event](#hook-the-settings-hook-events). `'*'` matches every event except the [telemetry events](/docs/en/plugins/mods/reference#telemetry), which take their own name and a `{ to: 'collector' }` filter.
86The event name can be a wildcard. `'classic.*'` matches every [settings hook event](#hook-the-settings-hook-events). `'*'` matches every event except the [telemetry events](/docs/en/plugins/mods/reference.md#telemetry), which take their own name and a `{ to: 'collector' }` filter.
8787 
8888Register each event once per matcher. If you call `on` twice for `session.start` with no matcher, the module fails to load with `on("session.start") is registered twice without a matcher`. Put everything your mod does at session start in one hook.
8989 
9090## Hook what Claude is doing
9191 
92Handle these events to see or change a tool call, a prompt, or a turn as it happens. For every event and what a hook can return, see the [events reference](/docs/en/plugins/mods/reference#events).
92Handle these events to see or change a tool call, a prompt, or a turn as it happens. For every event and what a hook can return, see the [events reference](/docs/en/plugins/mods/reference.md#events).
9393 
9494### Guard or change a tool call
9595 
from line 131
131131 
132132* **Change the call**: pass changed arguments to `next`.
133133* **Retry the call**: call `next(e)` again. A hook that sees `isError` on the first result can run the tool a second time and return that result.
134* **Answer the call yourself**: return an object with a `result` field, without calling `next`, and for a built-in tool, give `result` the shape that tool's own result has in [the types for your build](/docs/en/plugins/mods/create#get-the-types-for-your-build). No permission prompt appears and the tool doesn't run, so the result you return is all Claude learns about what happened.
134* **Answer the call yourself**: return an object with a `result` field, without calling `next`, and for a built-in tool, give `result` the shape that tool's own result has in [the types for your build](/docs/en/plugins/mods/create.md#get-the-types-for-your-build). No permission prompt appears and the tool doesn't run, so the result you return is all Claude learns about what happened.
135135* **Withhold the result from Claude**: return `{ deny: reason }` after `await next(e)`. Claude reads your reason in place of what `next` returned. When the tool ran, the deny keeps its result from Claude and undoes nothing the tool did. When the tool ran and succeeded, the reason follows a note such as `Bash ran, and a plugin withheld its result:`.
136136 
137Hooks in your organization's [managed settings](/docs/en/server-managed-settings) run before any mod's `tool.call` hook. When a managed hook blocks the call, no mod's `tool.call` hook runs for that call.
137Hooks in your organization's [managed settings](/docs/en/server-managed-settings.md) run before any mod's `tool.call` hook. When a managed hook blocks the call, no mod's `tool.call` hook runs for that call.
138138 
139139#### Hold a tool call until the user decides
140140 
from line 173
173173* **The user types an answer**: `$.ui.ask` resolves to the typed text. The hook compares it with `Run it`, so any other text refuses the command.
174174* **Nobody answers**: `$.ui.ask` rejects when the user dismisses the question or picks **Chat about this**, and in a `claude -p` run, so the `catch` block leaves the answer at `Refuse`
175175 
176Keep the wait inside a mods API call such as `$.ui.ask`, because that time doesn't count against the hook's [time limit](/docs/en/plugins/mods/reference#limits). Time spent awaiting a promise of your own does count. Claude Code skips a hook that times out, so the held command would run.
176Keep the wait inside a mods API call such as `$.ui.ask`, because that time doesn't count against the hook's [time limit](/docs/en/plugins/mods/reference.md#limits). Time spent awaiting a promise of your own does count. Claude Code skips a hook that times out, so the held command would run.
177177 
178178#### Approve or refuse a tool call before the user is asked
179179 
180180To decide whether a tool call may run, handle [`tool.check`](/docs/en/plugins/mods/reference#tools), the event where Claude Code makes that decision.
181181 
182For a fixed command or path, use a [permission rule](/docs/en/permissions#permission-rule-syntax) such as `Bash(npm test)`, which takes no code. Handle `tool.check` when the decision depends on what's true at that moment, such as the current Git branch or a value another hook recorded.
182For a fixed command or path, use a [permission rule](/docs/en/permissions.md#permission-rule-syntax) such as `Bash(npm test)`, which takes no code. Handle `tool.check` when the decision depends on what's true at that moment, such as the current Git branch or a value another hook recorded.
183183 
184184* **What to return**: to decide the call yourself, return an object of your own, such as `{ decision: 'allow' }` or `{ decision: 'deny', reason }`. To leave the decision alone, return what `await next(e)` gives you.
185185* **What `await next(e)` gives you**: Claude Code's own decision, as an object whose `decision` is `allow`, `ask`, or `deny`. No permission prompt appears while `next(e)` runs.
186186* **Arguments**: `e.input` holds the tool's arguments, such as `command` for Bash
187* **When `tool.check` fires**: after the [`PreToolUse` hooks](/docs/en/hooks#pretooluse) run, and before the permission prompt, [auto mode](/docs/en/permission-modes#eliminate-prompts-with-auto-mode)'s classifier, or a [`PermissionRequest`](/docs/en/hooks#permissionrequest) hook
187* **When `tool.check` fires**: after the [`PreToolUse` hooks](/docs/en/hooks#pretooluse) run, and before the permission prompt, [auto mode](/docs/en/permission-modes.md#eliminate-prompts-with-auto-mode)'s classifier, or a [`PermissionRequest`](/docs/en/hooks#permissionrequest) hook
188188 
189189This hook refuses `git push` while the current branch is `main`:
190190 
from line 208
208208 
209209> [!NOTE]
210210>
211> A `tool.check` hook can also return `allow` or `ask`. In [plan mode](/docs/en/permissions#hook-approvals-in-plan-mode), for a call that isn't read-only, such as a file edit, your hook can tighten the decision `next(e)` returns but can't loosen it. For the permission rules and `PreToolUse` hook decisions your hook's `allow` can't replace, see [Extend permissions with hooks](/docs/en/permissions#precedence-among-rules-hooks-and-mods).
211> A `tool.check` hook can also return `allow` or `ask`. In [plan mode](/docs/en/permissions.md#hook-approvals-in-plan-mode), for a call that isn't read-only, such as a file edit, your hook can tighten the decision `next(e)` returns but can't loosen it. For the permission rules and `PreToolUse` hook decisions your hook's `allow` can't replace, see [Extend permissions with hooks](/docs/en/permissions.md#precedence-among-rules-hooks-and-mods).
212212 
213213#### Check whether a tool call is read-only
214214 
from line 216
216216 
217217Some tools, such as Read, Grep, Glob, and WebSearch, report every call as read-only. Bash and MCP tools report a call as read-only in these cases:
218218 
219* **Bash**: the command passes Claude Code's built-in [read-only command check](/docs/en/permissions#read-only-commands)
219* **Bash**: the command passes Claude Code's built-in [read-only command check](/docs/en/permissions.md#read-only-commands)
220220* **An MCP tool**: the server sets the tool's `readOnlyHint` annotation to `true`
221221 
222The value is the tool's own report, so don't approve a call on this field alone. For example, WebFetch and Agent calls report as read-only, though [WebFetch](/docs/en/tools-reference#webfetch-tool-behavior) requests a URL and [Agent](/docs/en/tools-reference#agent-tool-behavior) starts a subagent that runs tools of its own.
222The value is the tool's own report, so don't approve a call on this field alone. For example, WebFetch and Agent calls report as read-only, though [WebFetch](/docs/en/tools-reference.md#webfetch-tool-behavior) requests a URL and [Agent](/docs/en/tools-reference.md#agent-tool-behavior) starts a subagent that runs tools of its own.
223223 
224224This hook returns an `ask` for every `mcp__github__` call that isn't read-only and wasn't already denied:
225225 
from line 245
245245 
246246| To do this | Return this |
247247| :- | :- |
248| Rewrite the prompt. The transcript and your [prompt history](/docs/en/interactive-mode#command-history) show the new text. | `next({ ...e, text: newText })` |
248| Rewrite the prompt. The transcript and your [prompt history](/docs/en/interactive-mode.md#command-history) show the new text. | `next({ ...e, text: newText })` |
249249| Add text only Claude reads, after the prompt | `next({ ...e, context: [...(e.context ?? []), extraText] })` |
250250| Stop the prompt from being sent | `{ drop: 'the reason' }` |
251251 
from line 267
267267 
268268To stop a prompt, return `{ drop: 'the reason' }` without calling `next`. The text goes back into the user's prompt input, and they see `Prompt dropped by a hook:` followed by your reason, so address the reason to them. If your hook returns a `drop` after its `next(e)` call let the prompt through, the turn still runs, and the hook [fails](#handle-a-hook-that-fails) with a message that includes `a drop after its next() was answered`.
269269 
270[Other events](/docs/en/plugins/mods/reference#prompts-and-what-claude-reads) cover the rest of what Claude reads: `prompt.section` for each section of the system prompt, `prompt.context` for the context sent with the first message, and `skill.prompt` for a skill's text. Text from these hooks that changes between requests [invalidates the prompt cache](/docs/en/prompt-caching). In a `skill.prompt` hook, you can also read [which plugin or file the skill came from](/docs/en/plugins/mods/reference#skill-prompt-fields).
270[Other events](/docs/en/plugins/mods/reference.md#prompts-and-what-claude-reads) cover the rest of what Claude reads: `prompt.section` for each section of the system prompt, `prompt.context` for the context sent with the first message, and `skill.prompt` for a skill's text. Text from these hooks that changes between requests [invalidates the prompt cache](/docs/en/prompt-caching.md). In a `skill.prompt` hook, you can also read [which plugin or file the skill came from](/docs/en/plugins/mods/reference.md#skill-prompt-fields).
271271 
272272### Follow a turn
273273 
from line 279
279279| `turn.step` | Claude Code is about to send one request to the model. A turn with tool calls has several. `e.agentId` is set for a subagent's request. | Read each request's token usage, send it to a different model with `next({ ...e, model })`, or answer without calling the model |
280280| `turn.complete` | The turn ended, including a turn the user interrupted, where `e.isAborted` is `true`. `e.answer` is Claude's final text, `e.durationMs` how long it took, and `e.usage` the turn's token totals. A subagent's turn fires it with `e.agentId` set. | Observe, or return an object with a `text` field, such as `{ text: 'Done in 12 seconds' }`, to show a line under the answer |
281281 
282Write a `turn.step` hook as an async generator, because the event streams. `yield* next(e)` forwards the response as it streams and evaluates to the finished result. This hook logs how much of each request the Claude API served from the [prompt cache](/docs/en/prompt-caching):
282Write a `turn.step` hook as an async generator, because the event streams. `yield* next(e)` forwards the response as it streams and evaluates to the finished result. This hook logs how much of each request the Claude API served from the [prompt cache](/docs/en/prompt-caching.md):
283283 
284284```javascript theme={null}
285285// function* makes the hook a generator, which can pass the response on piece by piece
from line 299
299299 
300300`result.usage` holds the token counts the Claude API reports for a request, plus the `model` that answered: `input_tokens`, `output_tokens`, `cache_read_input_tokens`, and `cache_creation_input_tokens`. The hook runs for subagents' requests too, so check `e.agentId` when you want only the main conversation.
301301 
302To see the tool calls that the API ran itself during the request, such as calls to the [advisor tool](/docs/en/advisor), read `result.serverToolUses`. Claude Code doesn't run these calls, so no `tool.call` or `tool.check` hook fires for them. The field is absent when the response has no such calls, and it requires Claude Code v2.1.290 or later.
302To see the tool calls that the API ran itself during the request, such as calls to the [advisor tool](/docs/en/advisor.md), read `result.serverToolUses`. Claude Code doesn't run these calls, so no `tool.call` or `tool.check` hook fires for them. The field is absent when the response has no such calls, and it requires Claude Code v2.1.290 or later.
303303 
304304### Handle the settings hook events
305305 
306Settings hooks are the command, HTTP, prompt, and agent hooks you configure in settings files. Each [settings hook event](/docs/en/hooks#hook-events), such as `Stop`, `SessionEnd`, or `PostToolUse`, is also an event named `classic.` followed by the settings hook event's name, such as `classic.Stop`. `e` is the JSON a settings hook receives on stdin, including `transcript_path`.
306Settings hooks are the command, HTTP, prompt, and agent hooks you configure in settings files. Each [settings hook event](/docs/en/hooks.md#hook-events), such as `Stop`, `SessionEnd`, or `PostToolUse`, is also an event named `classic.` followed by the settings hook event's name, such as `classic.Stop`. `e` is the JSON a settings hook receives on stdin, including `transcript_path`.
307307 
308308This hook uses `Stop`, which fires when Claude finishes responding, to log where the session's transcript is saved:
309309 
from line 328
328328 
329329Claude Code orders the chain by where each mod comes from:
330330 
3311. The built-in guard `sec-default@builtin`, a mod built into Claude Code that `/plugin` lists as `cc-plugin-sec-default`, where [it loads](/docs/en/plugins/mods/admin#know-what-happens-by-default), mods your organization lists in [`prependPlugins`](/docs/en/plugins/mods/admin#install-your-organizations-mods), and then any other mod that counts as your organization's and isn't in `appendPlugins`
3311. The built-in guard `sec-default@builtin`, a mod built into Claude Code that `/plugin` lists as `cc-plugin-sec-default`, where [it loads](/docs/en/plugins/mods/admin.md#know-what-happens-by-default), mods your organization lists in [`prependPlugins`](/docs/en/plugins/mods/admin#install-your-organizations-mods), and then any other mod that counts as your organization's and isn't in `appendPlugins`
3323322. Mods you install
3333333. Mods your organization lists in `appendPlugins`
3343344. Other mods built into Claude Code
from line 342
342342* **`PreToolUse` hooks from managed settings**: run before the first mod's `tool.call` hook. When a managed hook blocks the call, no mod's `tool.call` hook runs for that call.
343343* **`PreToolUse` hooks from every other settings file and from plugins' `hooks/hooks.json`**: run after the last mod calls `next`, as part of Claude Code's own behavior. A mod that answers `tool.call` without calling `next` keeps them from running, and a mod that calls `next` sees their decision in the result it returns.
344344 
345[`tool.check`](#approve-or-refuse-a-tool-call-before-the-user-is-asked) fires after the `PreToolUse` hooks have run. For the permission rules and `PreToolUse` hook decisions a `tool.check` hook's `allow` can't replace, see [Extend permissions with hooks](/docs/en/permissions#precedence-among-rules-hooks-and-mods).
345[`tool.check`](#approve-or-refuse-a-tool-call-before-the-user-is-asked) fires after the `PreToolUse` hooks have run. For the permission rules and `PreToolUse` hook decisions a `tool.check` hook's `allow` can't replace, see [Extend permissions with hooks](/docs/en/permissions.md#precedence-among-rules-hooks-and-mods).
346346 
347347### Handle a hook that fails
348348 
from line 351
351351* **It failed before calling `next`**: Claude Code skips it, and the next handler runs in its place
352352* **It failed after `next` resolved**: that result stands, and nothing runs a second time
353353 
354One line names the mod, the event, and the reason, such as `my-mod: tool.call hook skipped: threw Error: boom`. Where you read it depends on the session, as [Find out why a mod does nothing](/docs/en/plugins/mods/troubleshoot#find-out-why-a-mod-does-nothing) lists. A `ui.render` hook whose drawing doesn't validate is reported differently, as [Build a tree from elements](/docs/en/plugins/mods/interface#build-a-tree-from-elements) describes.
354One line names the mod, the event, and the reason, such as `my-mod: tool.call hook skipped: threw Error: boom`. Where you read it depends on the session, as [Find out why a mod does nothing](/docs/en/plugins/mods/troubleshoot.md#find-out-why-a-mod-does-nothing) lists. A `ui.render` hook whose drawing doesn't validate is reported differently, as [Build a tree from elements](/docs/en/plugins/mods/interface.md#build-a-tree-from-elements) describes.
355355 
356356To make a hook that blocks calls fail closed, add a `.catch` error handler that answers in its place. Here, `guard` is your hook function, and the handler tests [`next.called`](/docs/en/plugins/mods/reference#the-hook-function) to tell whether `guard` had already called `next` when it failed:
357357 
from line 370
370370* **`guard` failed before it called `next`**: the command doesn't run, and Claude reads the `deny` text with the kind at the end
371371* **`guard` failed after it called `next`**: the handler's `next(e)` resolves to the result that `guard`'s call produced without running the command again, and Claude reads that result
372372 
373The handler has a shorter [time limit](/docs/en/plugins/mods/reference#limits) of its own. If the handler itself throws or times out, Claude Code skips the hook as if it had no handler. When `guard` hadn't called `next`, the command then goes on as it would without the mod.
373The handler has a shorter [time limit](/docs/en/plugins/mods/reference.md#limits) of its own. If the handler itself throws or times out, Claude Code skips the hook as if it had no handler. When `guard` hadn't called `next`, the command then goes on as it would without the mod.
374374 
375The same handler shape fits a guard on `prompt.submit` or `config.set`. When `next.called` is false, return the refusal that the [events reference](/docs/en/plugins/mods/reference#events) lists for that event: `{ drop: 'the reason' }` for `prompt.submit`, `{ deny: 'the reason' }` for `config.set`.
375The same handler shape fits a guard on `prompt.submit` or `config.set`. When `next.called` is false, return the refusal that the [events reference](/docs/en/plugins/mods/reference.md#events) lists for that event: `{ drop: 'the reason' }` for `prompt.submit`, `{ deny: 'the reason' }` for `config.set`.
376376 
377377At `tool.check` and `plugin.register`, a refusal returned after `next` resolved still holds, so return it without testing `next.called`:
378378 
379379* **`tool.check`**: return `{ decision: 'deny', reason: 'the reason' }`
380* **`plugin.register`**: return `{ refuse: 'the reason' }`, as [Refuse mods when your check fails](/docs/en/plugins/mods/admin#refuse-mods-when-your-check-fails) shows
380* **`plugin.register`**: return `{ refuse: 'the reason' }`, as [Refuse mods when your check fails](/docs/en/plugins/mods/admin.md#refuse-mods-when-your-check-fails) shows
381381 
382382At `tool.call`, a `deny` returned after `next` resolved [withholds the result from Claude](#guard-or-change-a-tool-call).
383383 
384384## Next steps
385385 
386* [Use the mods API](/docs/en/plugins/mods/api): add commands and tools, call a model, and run work on a timer
387* [Draw in the interface](/docs/en/plugins/mods/interface): show what your hooks collect in a pane or above the prompt
388* [Test a mod](/docs/en/plugins/mods/test): fire any of these events from a test
389* [Mods reference](/docs/en/plugins/mods/reference): every event, every mods API method, and the limits
386* [Use the mods API](/docs/en/plugins/mods/api.md): add commands and tools, call a model, and run work on a timer
387* [Draw in the interface](/docs/en/plugins/mods/interface.md): show what your hooks collect in a pane or above the prompt
388* [Test a mod](/docs/en/plugins/mods/test.md): fire any of these events from a test
389* [Mods reference](/docs/en/plugins/mods/reference.md): every event, every mods API method, and the limits
390390 

plugins/mods/gallery Changed · +17 / -17 lines

from line 4
44 
55A mod draws its interface from elements: text, boxes, buttons, fields, and a few that format content for you. The samples here show the code that draws an element, and most come with a screenshot of the result in a terminal pane, so you can pick an element by how it looks.
66 
7To learn how drawing works, start with [Draw in the interface](/docs/en/plugins/mods/interface). For the main props and which apps draw each element, see the [elements reference](/docs/en/plugins/mods/reference#elements). The [type declarations](/docs/en/plugins/mods/create#get-the-types-for-your-build) list every prop.
7To learn how drawing works, start with [Draw in the interface](/docs/en/plugins/mods/interface.md). For the main props and which apps draw each element, see the [elements reference](/docs/en/plugins/mods/reference.md#elements). The [type declarations](/docs/en/plugins/mods/create.md#get-the-types-for-your-build) list every prop.
88 
99## Try a sample
1010 
1111The samples on this page are snippets, not whole mods. Each one is the code for one element and anything nested inside it.
1212 
13To see a sample in your own terminal, create the small mod in these steps and paste the sample into it. The mod adds a `/gallery` command that opens a pane and draws the sample there. A [pane](/docs/en/plugins/mods/interface#pick-where-to-draw) is a sidebar beside the transcript in a wide fullscreen terminal, or a framed region above the prompt otherwise.
13To see a sample in your own terminal, create the small mod in these steps and paste the sample into it. The mod adds a `/gallery` command that opens a pane and draws the sample there. A [pane](/docs/en/plugins/mods/interface.md#pick-where-to-draw) is a sidebar beside the transcript in a wide fullscreen terminal, or a framed region above the prompt otherwise.
1414 
1515**1. Create the mod**
1616 
17Create a directory named `gallery` with `.claude-plugin` and `hooks` directories inside it. [Create a mod](/docs/en/plugins/mods/create#write-a-mod-yourself) explains the files.
17Create a directory named `gallery` with `.claude-plugin` and `hooks` directories inside it. [Create a mod](/docs/en/plugins/mods/create.md#write-a-mod-yourself) explains the files.
1818 
1919Save the manifest as `gallery/.claude-plugin/plugin.json`:
2020 
from line 215
215215 
216216## Take input
217217 
218`Button`, `Input`, and `Select` are controls: the user moves between them with Tab and uses the one that has the focus. [Keyboard focus and hotkeys](/docs/en/plugins/mods/interface#know-which-keys-your-mod-can-receive) covers which keys reach them.
218`Button`, `Input`, and `Select` are controls: the user moves between them with Tab and uses the one that has the focus. [Keyboard focus and hotkeys](/docs/en/plugins/mods/interface.md#know-which-keys-your-mod-can-receive) covers which keys reach them.
219219 
220Open a pane with `focus: true` to request keyboard focus for it. Typed letters reach an `Input` once it has the focus. To choose which field has the focus when the pane opens, see [Set a hotkey and the first focus](/docs/en/plugins/mods/interface#set-a-hotkey-and-the-first-focus).
220Open a pane with `focus: true` to request keyboard focus for it. Typed letters reach an `Input` once it has the focus. To choose which field has the focus when the pane opens, see [Set a hotkey and the first focus](/docs/en/plugins/mods/interface.md#set-a-hotkey-and-the-first-focus).
221221 
222222### `Button`
223223 
from line 303
303303 
304304### `Raster`
305305 
306A `Raster` is a grid of colored character cells, for a heat map, a sparkline, or a game board. The terminal draws it. This sample uses the `cellsOf` function in the starter module, which packs the cells into the string a `Raster` takes. [Draw a grid of colored cells](/docs/en/plugins/mods/interface#draw-a-grid-of-colored-cells) explains it:
306A `Raster` is a grid of colored character cells, for a heat map, a sparkline, or a game board. The terminal draws it. This sample uses the `cellsOf` function in the starter module, which packs the cells into the string a `Raster` takes. [Draw a grid of colored cells](/docs/en/plugins/mods/interface.md#draw-a-grid-of-colored-cells) explains it:
307307 
308308```javascript theme={null}
309309Raster({
from line 339
339339 
340340### `Image` and `Client`
341341 
342Two more elements have no sample here. `Image` draws a PNG or raw pixels in the terminal. `Client` is a region that a second file of yours draws, for animation and pointer input. The [elements reference](/docs/en/plugins/mods/reference#elements) lists their props.
342Two more elements have no sample here. `Image` draws a PNG or raw pixels in the terminal. `Client` is a region that a second file of yours draws, for animation and pointer input. The [elements reference](/docs/en/plugins/mods/reference.md#elements) lists their props.
343343 
344344An `Image` draws as a picture in these terminals:
345345 
from line 350
350350In any other terminal, the user sees the `Image`'s `alt` text, dimmed, in place of the picture. Write `alt` text that stands on its own, because it also shows in these cases, among others:
351351 
352352* **tmux and screen**: a session running inside tmux or screen, in any terminal.
353* **Background sessions**: every [background session](/docs/en/agent-view), whatever terminal it's attached from.
354* **iTerm2 outside fullscreen rendering**: in iTerm2 the picture draws only under [fullscreen rendering](/docs/en/fullscreen), and not while [`CLAUDE_CODE_ALT_SCREEN_FULL_REPAINT`](/docs/en/env-vars) is set to `1`. To see the picture, run `/tui fullscreen` at the Claude Code prompt and leave that variable unset.
353* **Background sessions**: every [background session](/docs/en/agent-view.md), whatever terminal it's attached from.
354* **iTerm2 outside fullscreen rendering**: in iTerm2 the picture draws only under [fullscreen rendering](/docs/en/fullscreen.md), and not while [`CLAUDE_CODE_ALT_SCREEN_FULL_REPAINT`](/docs/en/env-vars) is set to `1`. To see the picture, run `/tui fullscreen` at the Claude Code prompt and leave that variable unset.
355355* **A file path source in iTerm2**: iTerm2 draws an `Image` whose `source` prop holds `png` or `rgba` bytes, and shows the `alt` text for one whose `source` names a `file`. If your mod has iTerm2 users, pass the picture as base64 in `source.png` or `source.rgba` rather than as a path in `source.file`.
356356 
357357If your mod's users see the dimmed text in a terminal that draws kitty graphics protocol images with Unicode placeholders, they can set [`CLAUDE_CODE_FORCE_TERMINAL_IMAGES`](/docs/en/env-vars) to `1`. Inside tmux or screen that doesn't help: the `alt` text goes away, and Claude Code sends the picture without wrapping it for tmux or screen passthrough.
from line 360
360360 
361361The samples all draw in a pane. A mod can also draw in other places, and call Claude Code to show something for it:
362362 
363* **Pane and band**: [Pick where to draw](/docs/en/plugins/mods/interface#pick-where-to-draw)
364* **Claude Code's own rows, such as the spinner**: [Change what Claude Code already draws](/docs/en/plugins/mods/interface#change-what-claude-code-already-draws)
365* **Toast, status line, and log line**: [Show something without starting a turn](/docs/en/plugins/mods/api#show-something-without-starting-a-turn)
366* **Question dialog**: [Hold a tool call until the user decides](/docs/en/plugins/mods/events#hold-a-tool-call-until-the-user-decides)
363* **Pane and band**: [Pick where to draw](/docs/en/plugins/mods/interface.md#pick-where-to-draw)
364* **Claude Code's own rows, such as the spinner**: [Change what Claude Code already draws](/docs/en/plugins/mods/interface.md#change-what-claude-code-already-draws)
365* **Toast, status line, and log line**: [Show something without starting a turn](/docs/en/plugins/mods/api.md#show-something-without-starting-a-turn)
366* **Question dialog**: [Hold a tool call until the user decides](/docs/en/plugins/mods/events.md#hold-a-tool-call-until-the-user-decides)
367367 
368368## Next steps
369369 
370* [Draw in the interface](/docs/en/plugins/mods/interface): build a pane with tabs, step by step
371* [Test a drawing](/docs/en/plugins/mods/test#test-a-drawing): press your buttons from a test
372* [Elements reference](/docs/en/plugins/mods/reference#elements): each element's main props and the apps that draw it
370* [Draw in the interface](/docs/en/plugins/mods/interface.md): build a pane with tabs, step by step
371* [Test a drawing](/docs/en/plugins/mods/test.md#test-a-drawing): press your buttons from a test
372* [Elements reference](/docs/en/plugins/mods/reference.md#elements): each element's main props and the apps that draw it
373373 

plugins/mods/interface Changed · +21 / -21 lines

from line 2
22 
33> Draw panes, a band above the prompt, buttons, and text fields from a Claude Code mod, handle presses and input, and keep state between redraws and sessions.
44 
5A mod can draw its own interface in Claude Code and change parts of the interface Claude Code already draws. Each place a mod can draw is called a [render site](/docs/en/plugins/mods/reference#render-sites), such as a pane, the band above the prompt, or the spinner. Claude Code fires the [`ui.render`](/docs/en/plugins/mods/reference#interface) event each time it's about to draw a render site, and your hook for that event returns what to draw there.
5A mod can draw its own interface in Claude Code and change parts of the interface Claude Code already draws. Each place a mod can draw is called a [render site](/docs/en/plugins/mods/reference.md#render-sites), such as a pane, the band above the prompt, or the spinner. Claude Code fires the [`ui.render`](/docs/en/plugins/mods/reference#interface) event each time it's about to draw a render site, and your hook for that event returns what to draw there.
66 
77This map shows where a mod can draw in a terminal session:
88 
from line 10
1010 
1111In a narrower terminal, the pane sits above the prompt instead of beside the transcript.
1212 
13Build your [first mod](/docs/en/plugins/mods/create) before you start here. Begin with the worked example, which builds a pane with two tabs and a counter, then read the section for each piece you want to change.
13Build your [first mod](/docs/en/plugins/mods/create.md) before you start here. Begin with the worked example, which builds a pane with two tabs and a counter, then read the section for each piece you want to change.
1414 
1515> [!NOTE]
1616>
17> To look up one prop or limit, see the [reference](/docs/en/plugins/mods/reference#render-sites).
17> To look up one prop or limit, see the [reference](/docs/en/plugins/mods/reference.md#render-sites).
1818 
1919## Build a pane with tabs
2020 
from line 28
2828 
2929**1. Create the plugin**
3030 
31A mod is a plugin with a manifest, a `hooks.json` that points to your code, and the code file. [Create a mod](/docs/en/plugins/mods/create#write-a-mod-yourself) explains each one. Create a directory named `hello-tabs` with `.claude-plugin` and `hooks` directories inside it, then save the first two files.
31A mod is a plugin with a manifest, a `hooks.json` that points to your code, and the code file. [Create a mod](/docs/en/plugins/mods/create.md#write-a-mod-yourself) explains each one. Create a directory named `hello-tabs` with `.claude-plugin` and `hooks` directories inside it, then save the first two files.
3232 
3333Save the manifest as `hello-tabs/.claude-plugin/plugin.json`:
3434 
from line 173
173173 
174174## Pick where to draw
175175 
176A `ui.render` hook runs for every render site unless you narrow it to the one you want to draw in. To choose the render site, pass a filter, called a [matcher](/docs/en/plugins/mods/events#filter-which-events-a-hook-handles), as the second argument to `on`. `{ component: 'Pane' }` runs the hook only for panes. In the hook, `e.component` names the site, `e.surface` says which app is drawing, and `e.props` holds the site's own data. For a pane, `e.requestId` is the `id` you opened it with.
176A `ui.render` hook runs for every render site unless you narrow it to the one you want to draw in. To choose the render site, pass a filter, called a [matcher](/docs/en/plugins/mods/events.md#filter-which-events-a-hook-handles), as the second argument to `on`. `{ component: 'Pane' }` runs the hook only for panes. In the hook, `e.component` names the site, `e.surface` says which app is drawing, and `e.props` holds the site's own data. For a pane, `e.requestId` is the `id` you opened it with.
177177 
178178The pane and the band are empty until a mod fills them. Select a tab to see what each one is and how to draw in it:
179179 
from line 189
189189 
190190The band is a strip directly above the prompt input. It's always there, and every mod shares it.
191191 
192Your hook returns a tree to show something in the band, or `next(e)` to show nothing. A tree replaces what the mods [after yours](/docs/en/plugins/mods/events#the-order-mods-run-in) draw there. To keep theirs, put the result of `await next(e)` among the children of a [`Box`](#build-a-tree-from-elements) in your tree.
192Your hook returns a tree to show something in the band, or `next(e)` to show nothing. A tree replaces what the mods [after yours](/docs/en/plugins/mods/events.md#the-order-mods-run-in) draw there. To keep theirs, put the result of `await next(e)` among the children of a [`Box`](#build-a-tree-from-elements) in your tree.
193193 
194194To draw in the band, filter on `{ component: 'AbovePrompt' }`.
195195 
from line 206
206206| `Spinner`, `ToolProgress`, `TurnDuration` | Status lines for a turn: the line that animates while Claude works, a running tool's live progress line, and the line that closes a turn |
207207| `InfoNotice`, `SessionMode`, `PromptHint` | Status lines under the logo, the mode labels in the footer, and the hint line under the prompt |
208208 
209`Pane`, `AskUserQuestion`, `Spinner`, `UserMessage`, `AssistantMessage`, and the tool call sites work in the terminal, the Desktop app, and the VS Code extension. The [render sites table](/docs/en/plugins/mods/reference#render-sites) lists where each of the others is raised.
209`Pane`, `AskUserQuestion`, `Spinner`, `UserMessage`, `AssistantMessage`, and the tool call sites work in the terminal, the Desktop app, and the VS Code extension. The [render sites table](/docs/en/plugins/mods/reference.md#render-sites) lists where each of the others is raised.
210210 
211At a site Claude Code already draws, your hook can change a detail, replace the drawing, or leave it alone. Select a tab to see each one applied to the spinner. The examples read a `calls` variable that another hook counts, as in the [tutorial mod](/docs/en/plugins/mods/create#write-a-mod-yourself).
211At a site Claude Code already draws, your hook can change a detail, replace the drawing, or leave it alone. Select a tab to see each one applied to the spinner. The examples read a `calls` variable that another hook counts, as in the [tutorial mod](/docs/en/plugins/mods/create.md#write-a-mod-yourself).
212212 
213213**Change a detail**
214214 
from line 313
313313await $.ui.open(items.length > 0 ? { ...pane, focus: true } : pane)
314314```
315315 
316To let a command open the pane while Claude is working, add `immediate: true` when you [register the command](/docs/en/plugins/mods/api#add-a-command). Without it, a command typed during a turn waits for the turn to end.
316To let a command open the pane while Claude is working, add `immediate: true` when you [register the command](/docs/en/plugins/mods/api.md#add-a-command). Without it, a command typed during a turn waits for the turn to end.
317317 
318318#### Hold toasts behind a dialog
319319 
from line 332
332332 
333333### Draw in the VS Code extension
334334 
335In the VS Code extension, what a mod draws appears in the chat panel with extension version 2.1.299 or later. A session that [doesn't fetch feature flags](/docs/en/env-vars#features-that-need-feature-flag-fetching), such as one on Amazon Bedrock, needs 2.1.304 or later. In a `ui.render` hook for the panel, `e.surface` is `vscode`. To check which sites and elements the panel draws, and which props it ignores, see the [render sites](/docs/en/plugins/mods/reference#render-sites) and [elements](/docs/en/plugins/mods/reference#elements) tables.
335In the VS Code extension, what a mod draws appears in the chat panel with extension version 2.1.299 or later. A session that [doesn't fetch feature flags](/docs/en/env-vars.md#features-that-need-feature-flag-fetching), such as one on Amazon Bedrock, needs 2.1.304 or later. In a `ui.render` hook for the panel, `e.surface` is `vscode`. To check which sites and elements the panel draws, and which props it ignores, see the [render sites](/docs/en/plugins/mods/reference.md#render-sites) and [elements](/docs/en/plugins/mods/reference.md#elements) tables.
336336 
337337To make a mod work in the panel as well as the terminal, account for these differences:
338338 
from line 417
417417Note: Type a note and press Enter
418418```
419419 
420The [interface gallery](/docs/en/plugins/mods/gallery) has samples and screenshots of most elements. This table lists every element:
420The [interface gallery](/docs/en/plugins/mods/gallery.md) has samples and screenshots of most elements. This table lists every element:
421421 
422422| Element | What it draws | Where |
423423| :- | :- | :- |
424| `Box` | A flex container that takes layout props such as `flexDirection`, [`borderStyle`](/docs/en/plugins/mods/reference#box-border-styles), and `width`. Spacing props such as `columnGap` and `padding` take a number or a [step name](/docs/en/plugins/mods/reference#box-spacing-steps) from `'xs'` to `'xl'`. | Everywhere |
424| `Box` | A flex container that takes layout props such as `flexDirection`, [`borderStyle`](/docs/en/plugins/mods/reference#box-border-styles), and `width`. Spacing props such as `columnGap` and `padding` take a number or a [step name](/docs/en/plugins/mods/reference.md#box-spacing-steps) from `'xs'` to `'xl'`. | Everywhere |
425425| `Text` | Styled text. Takes `color`, `bold`, `dimColor`, `italic`, `wrap`, and others such as [`weight`](/docs/en/plugins/mods/reference#text-typography). A `color` is a theme key or a color such as `'red'`. A `wrap` is `'wrap'`, `'truncate'`, `'truncate-start'`, `'truncate-middle'`, or `'truncate-end'`. | Everywhere |
426426| `Button` | A control that calls `onPress` | Everywhere |
427427| `Link`, `Code`, `Markdown` | A link with `href` and an optional `label`, a code block, and text formatted the way Claude's replies are. `Markdown` takes its content in a `text` prop, not in `children`, and needs a `key` when you pass `onLinkPress`. | Everywhere |
from line 434
434434 
435435If a tree uses an element the app doesn't have, a prop an element doesn't take, or a child where none goes, Claude Code draws its own version of the site.
436436 
437In a session started with `--plugin-dir`, a transcript line says so, such as `ui.render (Pane) refused: Text prop "bogusProp" is not allowed; the engine drew its own`. The [debug log](/docs/en/plugins/mods/troubleshoot#read-the-debug-log) records it as `ui.render (Pane): a hook returned a tree that does not validate` with the same reason. Nothing else appears in the session, so when a drawing doesn't show up, check that line or the log.
437In a session started with `--plugin-dir`, a transcript line says so, such as `ui.render (Pane) refused: Text prop "bogusProp" is not allowed; the engine drew its own`. The [debug log](/docs/en/plugins/mods/troubleshoot.md#read-the-debug-log) records it as `ui.render (Pane): a hook returned a tree that does not validate` with the same reason. Nothing else appears in the session, so when a drawing doesn't show up, check that line or the log.
438438 
439439### `Link` in the Desktop app and VS Code
440440 
from line 508
508508 
509509### Keyboard focus and hotkeys
510510 
511Your mod never reads the keyboard itself. The user presses a key, Claude Code decides which of your controls it's for, and that control's callback runs. Apart from a [digit hotkey on the band](/docs/en/plugins/mods/reference#elements), that happens only while your pane or band has keyboard focus. The rest of the time, keys go to the prompt.
511Your mod never reads the keyboard itself. The user presses a key, Claude Code decides which of your controls it's for, and that control's callback runs. Apart from a [digit hotkey on the band](/docs/en/plugins/mods/reference.md#elements), that happens only while your pane or band has keyboard focus. The rest of the time, keys go to the prompt.
512512 
513513In the [VS Code extension](#draw-in-the-vs-code-extension), buttons have no hotkeys: the user clicks a button or presses Enter on it, and types into fields.
514514 
from line 551
551551| With brackets, the default | `[ Add one ]`, with no hotkey shown | The label with a small key beside it | The label, and the hotkey does nothing |
552552| With `plain: true` | `1: One` | The label with a small key beside it | The label, and the hotkey does nothing |
553553 
554In the terminal, name the key in a bracketed button's label, or use `plain: true`, so the user can see what to press. The [elements reference](/docs/en/plugins/mods/reference#elements) has the other `Button` rules: `action`, digit hotkeys on the band, and two buttons on one hotkey.
554In the terminal, name the key in a bracketed button's label, or use `plain: true`, so the user can see what to press. The [elements reference](/docs/en/plugins/mods/reference.md#elements) has the other `Button` rules: `action`, digit hotkeys on the band, and two buttons on one hotkey.
555555 
556556### Take typed input and draw a row for each item
557557 
from line 707
707707 
708708### How often a site can redraw
709709 
710Claude Code throttles redraws of a site, so your mod can call `$.ui.invalidate` as often as its data changes. For how often each site can redraw, see the [limits table](/docs/en/plugins/mods/reference#limits).
710Claude Code throttles redraws of a site, so your mod can call `$.ui.invalidate` as often as its data changes. For how often each site can redraw, see the [limits table](/docs/en/plugins/mods/reference.md#limits).
711711 
712712Calls that come faster than the limit are coalesced into one redraw. That redraw runs your hook once, and the hook reads your data as it is at that moment, so the latest value shows and the values in between don't. An animation can't run faster than the limit.
713713 
from line 852
852852 
853853## Next steps
854854 
855* [React to events](/docs/en/plugins/mods/events): feed your drawing from tool calls and turns
856* [Use the mods API](/docs/en/plugins/mods/api): feed your drawing from timers and model calls
857* [Test a drawing](/docs/en/plugins/mods/test#test-a-drawing): press your buttons from a test, on more than one surface
858* [Render sites](/docs/en/plugins/mods/reference#render-sites) and [elements](/docs/en/plugins/mods/reference#elements): each site's props and each element's props
855* [React to events](/docs/en/plugins/mods/events.md): feed your drawing from tool calls and turns
856* [Use the mods API](/docs/en/plugins/mods/api.md): feed your drawing from timers and model calls
857* [Test a drawing](/docs/en/plugins/mods/test.md#test-a-drawing): press your buttons from a test, on more than one surface
858* [Render sites](/docs/en/plugins/mods/reference.md#render-sites) and [elements](/docs/en/plugins/mods/reference.md#elements): each site's props and each element's props
859859 

plugins/mods/overview Changed · +47 / -47 lines

from line 2
22 
33> Add panes, commands, and tool call rules to Claude Code with a mod. See what a mod can do, how to make or install one, and where mods run.
44 
5A mod is a [plugin](/docs/en/plugins/overview) that changes how Claude Code looks and behaves. It's made of JavaScript or TypeScript event handlers: Claude Code calls one when an event happens, such as a tool call, a submitted prompt, or a part of the interface being drawn, and the handler can watch the event, change it, or take it over. Use a mod to add a feature of your own to Claude Code, such as a pane that charts how full your context is after each request. For the files in a mod and a complete example, see [How a mod works](#how-a-mod-works).
5A mod is a [plugin](/docs/en/plugins/overview.md) that changes how Claude Code looks and behaves. It's made of JavaScript or TypeScript event handlers: Claude Code calls one when an event happens, such as a tool call, a submitted prompt, or a part of the interface being drawn, and the handler can watch the event, change it, or take it over. Use a mod to add a feature of your own to Claude Code, such as a pane that charts how full your context is after each request. For the files in a mod and a complete example, see [How a mod works](#how-a-mod-works).
66 
77> [!NOTE]
88>
9> Claude Code's existing [hooks](/docs/en/hooks) also run on events, as a shell command, HTTP request, or prompt you configure in a settings file. A mod's handlers are functions that run inside Claude Code instead. Claude Code calls both kinds hooks: on these pages, "hook" means a mod's handler, and the settings-file kind is a "settings hook".
9> Claude Code's existing [hooks](/docs/en/hooks.md) also run on events, as a shell command, HTTP request, or prompt you configure in a settings file. A mod's handlers are functions that run inside Claude Code instead. Claude Code calls both kinds hooks: on these pages, "hook" means a mod's handler, and the settings-file kind is a "settings hook".
1010 
1111## What a mod can do
1212 
1313Settings hooks, skills, status lines, and MCP servers work from outside Claude Code: each one runs a script, or gives Claude text or tools. A mod runs inside Claude Code, so it can do things they can't:
1414 
15* **Draw an interface you can use**: a pane beside the transcript or a band above the prompt, with tabs, buttons, and text fields. See [Draw in the interface](/docs/en/plugins/mods/interface).
16* **Redraw Claude Code's own interface**: replace or restyle parts Claude Code draws itself, such as a tool call's row, the spinner, or the dialog Claude asks questions in. See [Change what Claude Code already draws](/docs/en/plugins/mods/interface#change-what-claude-code-already-draws).
17* **Step into a tool call or a request**: for example, hold a tool call while you ask the user a question, answer it without running the tool, or send one request to a different model. See [Guard or change a tool call](/docs/en/plugins/mods/events#guard-or-change-a-tool-call) and [Follow a turn](/docs/en/plugins/mods/events#follow-a-turn).
18* **Run your own code on a command**: a `/command` that runs your function at once, with no Claude turn, even while Claude is working. See [Add a command or a tool](/docs/en/plugins/mods/api#add-a-command-or-a-tool).
19* **Share data between hooks**: a mod's hooks share the variables in its file, so what one hook records, another can show. For example, one hook can count tool calls while another shows the count beside the spinner, or one can read each request's token usage while another charts it in a pane. See [React to events](/docs/en/plugins/mods/events).
15* **Draw an interface you can use**: a pane beside the transcript or a band above the prompt, with tabs, buttons, and text fields. See [Draw in the interface](/docs/en/plugins/mods/interface.md).
16* **Redraw Claude Code's own interface**: replace or restyle parts Claude Code draws itself, such as a tool call's row, the spinner, or the dialog Claude asks questions in. See [Change what Claude Code already draws](/docs/en/plugins/mods/interface.md#change-what-claude-code-already-draws).
17* **Step into a tool call or a request**: for example, hold a tool call while you ask the user a question, answer it without running the tool, or send one request to a different model. See [Guard or change a tool call](/docs/en/plugins/mods/events.md#guard-or-change-a-tool-call) and [Follow a turn](/docs/en/plugins/mods/events.md#follow-a-turn).
18* **Run your own code on a command**: a `/command` that runs your function at once, with no Claude turn, even while Claude is working. See [Add a command or a tool](/docs/en/plugins/mods/api.md#add-a-command-or-a-tool).
19* **Share data between hooks**: a mod's hooks share the variables in its file, so what one hook records, another can show. For example, one hook can count tool calls while another shows the count beside the spinner, or one can read each request's token usage while another charts it in a pane. See [React to events](/docs/en/plugins/mods/events.md).
2020 
21Mods work in the Claude Code CLI, the Code tab of the Claude Desktop app, and the VS Code extension. See [Where mods run](#where-mods-run) for how they behave elsewhere, such as in `claude -p` and cloud sessions. If a settings hook, a skill, or an MCP server already does what you need, [compare them](#compare-mods-settings-hooks-skills-and-mcp-servers) before you write a mod. To manage mods for an organization, see [Manage mods for your organization](/docs/en/plugins/mods/admin).
21Mods work in the Claude Code CLI, the Code tab of the Claude Desktop app, and the VS Code extension. See [Where mods run](#where-mods-run) for how they behave elsewhere, such as in `claude -p` and cloud sessions. If a settings hook, a skill, or an MCP server already does what you need, [compare them](#compare-mods-settings-hooks-skills-and-mcp-servers) before you write a mod. To manage mods for an organization, see [Manage mods for your organization](/docs/en/plugins/mods/admin.md).
2222 
2323## Get a mod
2424 
from line 25
2525To start with a mod:
2626 
2727* **Use one you already have**: some of Claude Code's own features are mods, such as `/diff`. See [Mods built into Claude Code](#mods-built-into-claude-code).
28* **Make one**: describe what you want in a Claude Code session, and Claude writes the mod. See [Ask Claude for a mod](/docs/en/plugins/mods/create#ask-claude-for-a-mod). To learn how a mod's code works, [write one yourself](/docs/en/plugins/mods/create#write-a-mod-yourself).
28* **Make one**: describe what you want in a Claude Code session, and Claude writes the mod. See [Ask Claude for a mod](/docs/en/plugins/mods/create.md#ask-claude-for-a-mod). To learn how a mod's code works, [write one yourself](/docs/en/plugins/mods/create.md#write-a-mod-yourself).
2929* **Install one**: see [Install or update a mod](#install-or-update-a-mod), or [try a sample mod](#try-a-sample-mod)
3030 
3131### Install or update a mod
from line 39
3939* In a Claude Code session, run `/plugin install token-chart@your-org`.
4040* In your shell, run `claude plugin install token-chart@your-org`.
4141 
42[Install plugins](/docs/en/plugins/install) covers marketplaces, scopes, the VS Code extension and the Desktop app, and [keeping plugins updated](/docs/en/plugins/install#keep-plugins-updated), all of which apply to a plugin that contains a mod without changes.
42[Install plugins](/docs/en/plugins/install.md) covers marketplaces, scopes, the VS Code extension and the Desktop app, and [keeping plugins updated](/docs/en/plugins/install.md#keep-plugins-updated), all of which apply to a plugin that contains a mod without changes.
4343 
4444If you install or update a mod from your shell while a session is open, run `/reload-plugins` in that session to load it. Otherwise it loads the next time you start Claude Code.
4545 
from line 53
5353 
5454A sample mod runs with your permissions. To see what one does before you load it, [list its hooks and calls](#list-what-a-mod-does-before-you-install-one).
5555 
56To try one, clone the repository and [load the mod's directory for one session](/docs/en/plugins/create#load-a-directory-or-archive-for-one-session) with `--plugin-dir`. To confirm the mod loaded, [check which mods the session loaded](#see-which-mods-a-session-loaded).
56To try one, clone the repository and [load the mod's directory for one session](/docs/en/plugins/create.md#load-a-directory-or-archive-for-one-session) with `--plugin-dir`. To confirm the mod loaded, [check which mods the session loaded](#see-which-mods-a-session-loaded).
5757 
5858To keep one, [add the clone's `claude-code/mods` directory as a marketplace](/docs/en/plugins/install#add-a-marketplace), then install the mod from `claude-code-playground-mods`. The marketplace points at your clone, so the mod stops loading if you move or delete it.
5959 
6060## Decide whether to trust a mod
6161 
62A mod is code that runs with your permissions, inside Claude Code. Install mods only from authors and [marketplaces you trust](/docs/en/plugins/security).
62A mod is code that runs with your permissions, inside Claude Code. Install mods only from authors and [marketplaces you trust](/docs/en/plugins/security.md).
6363 
6464### What a mod can reach
6565 
from line 72
7272* **Act without asking you**: approve a tool call before you're asked
7373* **Spend your usage**: call a model on your plan or API key
7474 
75Mods aren't sandboxed. If you turn on [sandboxing](/docs/en/sandboxing), the sandbox isolates the Bash commands Claude runs, and a process that a mod starts runs outside it.
75Mods aren't sandboxed. If you turn on [sandboxing](/docs/en/sandboxing.md), the sandbox isolates the Bash commands Claude runs, and a process that a mod starts runs outside it.
7676 
77With [managed settings](/docs/en/settings#check-what-your-organization-enforces) or a Team or Enterprise [`/login`](/docs/en/authentication#authentication-precedence) as the session's credential, by default a mod's approval doesn't get a call past your `ask` rules or `PreToolUse` hooks. Without either, a mod can approve a call that an `ask` rule would prompt for, or that your `PreToolUse` hook blocked. To check when a mod can also approve a call that a `deny` rule refuses, see [Extend permissions with hooks](/docs/en/permissions#precedence-among-rules-hooks-and-mods).
77With [managed settings](/docs/en/settings.md#check-what-your-organization-enforces) or a Team or Enterprise [`/login`](/docs/en/authentication#authentication-precedence) as the session's credential, by default a mod's approval doesn't get a call past your `ask` rules or `PreToolUse` hooks. Without either, a mod can approve a call that an `ask` rule would prompt for, or that your `PreToolUse` hook blocked. To check when a mod can also approve a call that a `deny` rule refuses, see [Extend permissions with hooks](/docs/en/permissions.md#precedence-among-rules-hooks-and-mods).
7878 
7979A mod can restyle much of Claude Code's interface, but not the permission prompt. It can't change what a prompt shows you.
8080 
from line 86
8686claude plugin validate ./some-mod
8787```
8888 
89The `hooks:` and `calls:` lines in the output list the events the mod handles and what it asks Claude Code to do. [Review what a mod can do](/docs/en/plugins/mods/admin#review-what-a-mod-can-do) shows the output and which calls to look for.
89The `hooks:` and `calls:` lines in the output list the events the mod handles and what it asks Claude Code to do. [Review what a mod can do](/docs/en/plugins/mods/admin.md#review-what-a-mod-can-do) shows the output and which calls to look for.
9090 
9191## Turn mods on or off
9292 
9393Mods are on by default. In the terminal, use Claude Code v2.1.287 or later. The Desktop app includes its own copy of Claude Code, and mods work there from v2.1.286. Check the version in the place you use mods:
9494 
95* **Terminal**: in your shell, run `claude --version`. If yours is older, [update Claude Code](/docs/en/setup#update-claude-code).
96* **Desktop app**: in a local session in the Code tab, enter `/status` and read the **Claude Code** row, which shows a version such as `2.1.286`. If yours is older, [update the Desktop app](/docs/en/desktop#claude-code-version-in-the-code-tab).
95* **Terminal**: in your shell, run `claude --version`. If yours is older, [update Claude Code](/docs/en/setup.md#update-claude-code).
96* **Desktop app**: in a local session in the Code tab, enter `/status` and read the **Claude Code** row, which shows a version such as `2.1.286`. If yours is older, [update the Desktop app](/docs/en/desktop.md#claude-code-version-in-the-code-tab).
9797 
9898To turn mods off, choose how many to stop, and for how long. To turn them back on, undo the same change:
9999 
from line 101
101101* **Every installed mod, for one session**: start Claude Code with [`--safe-mode`](/docs/en/cli-reference#cli-flags), which also disables your other customizations
102102* **Every mod you installed, in every session**: set [`"disableAllHooks": true`](/docs/en/settings-reference#disableallhooks) in `~/.claude/settings.json`. Your settings hooks and custom status line stop too. What your organization manages keeps running.
103103 
104If you use Claude Code through an organization, an administrator can also limit which mods load. Administrators start at [Stop user-installed mods from loading](/docs/en/plugins/mods/admin#stop-user-installed-mods-from-loading).
104If you use Claude Code through an organization, an administrator can also limit which mods load. Administrators start at [Stop user-installed mods from loading](/docs/en/plugins/mods/admin.md#stop-user-installed-mods-from-loading).
105105 
106106`disableAllHooks` and your organization's `allowManagedModsOnly` stop a mod and leave the rest of its plugin in place: the plugin stays installed, and its skills, commands, agents, and MCP servers load. Other settings and flags reach further. [`disableAllHooks`](/docs/en/settings-reference#disableallhooks) and [What runs under `allowManagedHooksOnly`](/docs/en/settings-reference#what-runs-under-allowmanagedhooksonly) list what each one does to a plugin and its settings hooks.
107107 
108To find out whether mods can load for you, see [Check whether mods can load](/docs/en/plugins/mods/troubleshoot#check-whether-mods-can-load).
108To find out whether mods can load for you, see [Check whether mods can load](/docs/en/plugins/mods/troubleshoot.md#check-whether-mods-can-load).
109109 
110110> [!NOTE]
111111>
from line 113
113113 
114114### See which mods a session loaded
115115 
116To see which mods a terminal session loaded, run `/plugin` at the Claude Code prompt. A dim line under the tabs gives the count and the names, such as `1 mod active · first-mod`. If a mod you installed isn't named there, see [Find out why a mod does nothing](/docs/en/plugins/mods/troubleshoot#find-out-why-a-mod-does-nothing).
116To see which mods a terminal session loaded, run `/plugin` at the Claude Code prompt. A dim line under the tabs gives the count and the names, such as `1 mod active · first-mod`. If a mod you installed isn't named there, see [Find out why a mod does nothing](/docs/en/plugins/mods/troubleshoot.md#find-out-why-a-mod-does-nothing).
117117 
118118## How a mod works
119119 
120A mod is a [plugin](/docs/en/plugins/overview) whose code registers event handlers, called hooks. Claude Code runs a hook when its event happens, such as when Claude calls a tool or when the spinner is drawn. A small mod has three files:
120A mod is a [plugin](/docs/en/plugins/overview.md) whose code registers event handlers, called hooks. Claude Code runs a hook when its event happens, such as when Claude calls a tool or when the spinner is drawn. A small mod has three files:
121121 
122122```text theme={null}
123123first-mod/
from line 128
128128 └── register.js
129129```
130130 
131* **`plugin.json`**: the plugin's [manifest](/docs/en/plugins/manifest-reference)
132* **`hooks.json`**: [points to your code file](/docs/en/plugins/mods/reference#files)
133* **`register.js`**: [your code](/docs/en/plugins/mods/create#write-a-mod-yourself), called the hooks module. It tells Claude Code which events to run your functions on.
131* **`plugin.json`**: the plugin's [manifest](/docs/en/plugins/manifest-reference.md)
132* **`hooks.json`**: [points to your code file](/docs/en/plugins/mods/reference.md#files)
133* **`register.js`**: [your code](/docs/en/plugins/mods/create.md#write-a-mod-yourself), called the hooks module. It tells Claude Code which events to run your functions on.
134134 
135135This is a complete `register.js`. It counts the tool calls Claude makes and shows the count beside the spinner while Claude works, as in `Thinking · tool calls: 3…`.
136136 
from line 176
176176 
177177To do anything outside its own code, such as draw, add a command, call a model, read a file, start a process, or make a network request, a hook calls the mods API. A hook has no other way to do those things, which is why Claude Code can [list what a mod does](#list-what-a-mod-does-before-you-install-one) before you install it.
178178 
179For the code behind each choice, see [React to events](/docs/en/plugins/mods/events#how-a-hook-handles-an-event). For what a hook can call, see [Use the mods API](/docs/en/plugins/mods/api).
179For the code behind each choice, see [React to events](/docs/en/plugins/mods/events.md#how-a-hook-handles-an-event). For what a hook can call, see [Use the mods API](/docs/en/plugins/mods/api.md).
180180 
181181### Where mods run
182182 
from line 185
185185| Where you run Claude Code | Hooks run | What the mod draws appears |
186186| :- | :- | :- |
187187| `claude` in a terminal, including an editor's integrated terminal and the JetBrains plugin | Yes | Yes |
188| The Code tab of the Desktop app, except in a WSL session | Yes | Yes, except elements the [elements table](/docs/en/plugins/mods/reference#elements) marks terminal-only |
189| A [WSL session](/docs/en/desktop-wsl) in the Desktop app | No, because plugins aren't available in WSL sessions | No |
190| The VS Code extension's chat panel | Yes | Yes, with extension version 2.1.299 or later. A session that [doesn't fetch feature flags](/docs/en/env-vars#features-that-need-feature-flag-fetching), such as one on Amazon Bedrock, needs 2.1.304 or later. The [render sites](/docs/en/plugins/mods/reference#render-sites) and [elements](/docs/en/plugins/mods/reference#elements) tables mark what the panel draws. |
191| `claude -p` and the [Agent SDK](/docs/en/agent-sdk/overview) | Yes | No |
192| [Remote Control](/docs/en/remote-control) from claude.ai or the mobile app | Yes, in the session on your machine | In the terminal on your machine |
193| A [cloud session](/docs/en/claude-code-on-the-web) | Yes, for a plugin that [reaches the cloud session](/docs/en/cloud-environments#what-carries-over-from-your-setup) | No |
188| The Code tab of the Desktop app, except in a WSL session | Yes | Yes, except elements the [elements table](/docs/en/plugins/mods/reference.md#elements) marks terminal-only |
189| A [WSL session](/docs/en/desktop-wsl.md) in the Desktop app | No, because plugins aren't available in WSL sessions | No |
190| The VS Code extension's chat panel | Yes | Yes, with extension version 2.1.299 or later. A session that [doesn't fetch feature flags](/docs/en/env-vars.md#features-that-need-feature-flag-fetching), such as one on Amazon Bedrock, needs 2.1.304 or later. The [render sites](/docs/en/plugins/mods/reference.md#render-sites) and [elements](/docs/en/plugins/mods/reference.md#elements) tables mark what the panel draws. |
191| `claude -p` and the [Agent SDK](/docs/en/agent-sdk/overview.md) | Yes | No |
192| [Remote Control](/docs/en/remote-control.md) from claude.ai or the mobile app | Yes, in the session on your machine | In the terminal on your machine |
193| A [cloud session](/docs/en/claude-code-on-the-web.md) | Yes, for a plugin that [reaches the cloud session](/docs/en/cloud-environments.md#what-carries-over-from-your-setup) | No |
194194 
195195A mod that draws can check which app it's running in, and fall back to a line in the transcript or a command's text reply where nothing draws.
196196 
197197## Control mods for your organization
198198 
199Administrators decide whether mods run and which ones, through [managed settings](/docs/en/managed-settings). [Manage mods for your organization](/docs/en/plugins/mods/admin) covers what happens by default, how to review a mod, and how to enforce a policy with a mod of your own.
199Administrators decide whether mods run and which ones, through [managed settings](/docs/en/managed-settings.md). [Manage mods for your organization](/docs/en/plugins/mods/admin.md) covers what happens by default, how to review a mod, and how to enforce a policy with a mod of your own.
200200 
201201## Compare mods, settings hooks, skills, and MCP servers
202202 
from line 210
210210| What you write | JavaScript or TypeScript | A script and a `settings.json` entry | Markdown | A server in any language |
211211| Pick it when | You want a pane, a band above the prompt, a custom command, or to rewrite an event | You want to block, allow, or log an event with a script you already have | You keep pasting the same instructions into chat | Claude needs to reach an external system |
212212 
213Each of the others has its own page: [Hooks](/docs/en/hooks), [Skills](/docs/en/skills), and [MCP](/docs/en/mcp). A plugin can hold all of them, so a mod can ship in the same plugin as a skill and an MCP server.
213Each of the others has its own page: [Hooks](/docs/en/hooks.md), [Skills](/docs/en/skills.md), and [MCP](/docs/en/mcp.md). A plugin can hold all of them, so a mod can ship in the same plugin as a skill and an MCP server.
214214 
215215## Mods built into Claude Code
216216 
from line 220
220220 
221221| Name in `/plugin` | What it does | Where it's on | How to turn it off |
222222| :- | :- | :- | :- |
223| `cc-plugin-agents-md` | Loads `AGENTS.md` as project instructions | Every session, apart from [the ones that can't read `AGENTS.md`](/docs/en/memory#when-agents-md-support-is-unavailable) | Disable it in `/plugin`, or [choose which instruction files load](/docs/en/memory#choose-which-instruction-files-load) |
223| `cc-plugin-agents-md` | Loads `AGENTS.md` as project instructions | Every session, apart from [the ones that can't read `AGENTS.md`](/docs/en/memory#when-agents-md-support-is-unavailable) | Disable it in `/plugin`, or [choose which instruction files load](/docs/en/memory.md#choose-which-instruction-files-load) |
224224| `cc-plugin-diff` | Takes over [`/diff`](/docs/en/interactive-mode#review-changes-with-%2Fdiff) and draws its pane | Interactive terminal sessions | Disable it in `/plugin`. `/diff` stays, and Claude Code's built-in version of the command answers it. |
225225| `cc-plugin-plugin-authoring` | Gives Claude the [`plugin-authoring` skill](/docs/en/plugins/mods/create#ask-claude-for-a-mod) for writing mods. It holds a skill and no mod code. | Unless Anthropic has turned installed mods off remotely | Disable it in `/plugin` |
226| `cc-plugin-sec-default` | Guards what your organization manages from the mods a user installs | [Where the guard loads](/docs/en/plugins/mods/admin#know-what-happens-by-default) | You can't. An administrator [sets the order](/docs/en/plugins/mods/admin#install-your-organizations-mods) in managed settings |
226| `cc-plugin-sec-default` | Guards what your organization manages from the mods a user installs | [Where the guard loads](/docs/en/plugins/mods/admin.md#know-what-happens-by-default) | You can't. An administrator [sets the order](/docs/en/plugins/mods/admin.md#install-your-organizations-mods) in managed settings |
227227| `cc-plugin-telemetry` | Sends the analytics records that Claude Code and its built-in mods log | Wherever Claude Code's own analytics are on | Disable it in `/plugin`, or turn analytics off, for example with [`DISABLE_TELEMETRY`](/docs/en/env-vars) |
228| `cc-plugin-you-should-know` | [You should know](/docs/en/interactive-mode#you-should-know-suggestions): a side agent shows a note above the prompt when it finds something you might have missed | Off until you [turn it on](/docs/en/interactive-mode#you-should-know-suggestions) | Disable it in `/plugin` |
228| `cc-plugin-you-should-know` | [You should know](/docs/en/interactive-mode.md#you-should-know-suggestions): a side agent shows a note above the prompt when it finds something you might have missed | Off until you [turn it on](/docs/en/interactive-mode.md#you-should-know-suggestions) | Disable it in `/plugin` |
229229 
230230The settings and flags that stop installed mods, such as `disableAllHooks`, `--bare`, and `--safe-mode`, don't stop built-in mods.
231231 
from line 235
235235 
236236* [`diff`](https://github.com/anthropics/claude-code/tree/main/mods/diff): the `/diff` pane, with buttons bound to keyboard actions and scrolling the mod handles itself
237237* [`agents-md`](https://github.com/anthropics/claude-code/tree/main/mods/agents-md): loads `AGENTS.md` as project instructions, with a [`userConfig`](/docs/en/plugins/components#user-configuration) option
238* [`sec-default`](https://github.com/anthropics/claude-code/tree/main/mods/sec-default): the guard described in [Know what happens by default](/docs/en/plugins/mods/admin#know-what-happens-by-default), a model for a mod that enforces policy
238* [`sec-default`](https://github.com/anthropics/claude-code/tree/main/mods/sec-default): the guard described in [Know what happens by default](/docs/en/plugins/mods/admin.md#know-what-happens-by-default), a model for a mod that enforces policy
239239* [`telemetry`](https://github.com/anthropics/claude-code/tree/main/mods/telemetry): adds methods that other mods can call, and ships their types
240240 
241241## Next steps
242242 
243* [Create a mod](/docs/en/plugins/mods/create): build one that counts tool calls, shows the count beside the spinner, and adds a command, and learn the edit and reload loop
244* [Draw in the interface](/docs/en/plugins/mods/interface): panes, the band above the prompt, buttons, text fields, and state
245* [React to events](/docs/en/plugins/mods/events): tool calls, prompts, turns, and the order mods run in
246* [Use the mods API](/docs/en/plugins/mods/api): commands, tools, model calls, timers, and files
247* [Test a mod](/docs/en/plugins/mods/test): automated tests that run without a session
248* [Troubleshoot a mod](/docs/en/plugins/mods/troubleshoot): the reasons a mod does nothing, and the debug log
249* [Manage mods for your organization](/docs/en/plugins/mods/admin): defaults, managed settings, reviewing a mod, and policy mods
250* [Mods reference](/docs/en/plugins/mods/reference): events, methods, elements, and limits
243* [Create a mod](/docs/en/plugins/mods/create.md): build one that counts tool calls, shows the count beside the spinner, and adds a command, and learn the edit and reload loop
244* [Draw in the interface](/docs/en/plugins/mods/interface.md): panes, the band above the prompt, buttons, text fields, and state
245* [React to events](/docs/en/plugins/mods/events.md): tool calls, prompts, turns, and the order mods run in
246* [Use the mods API](/docs/en/plugins/mods/api.md): commands, tools, model calls, timers, and files
247* [Test a mod](/docs/en/plugins/mods/test.md): automated tests that run without a session
248* [Troubleshoot a mod](/docs/en/plugins/mods/troubleshoot.md): the reasons a mod does nothing, and the debug log
249* [Manage mods for your organization](/docs/en/plugins/mods/admin.md): defaults, managed settings, reviewing a mod, and policy mods
250* [Mods reference](/docs/en/plugins/mods/reference.md): events, methods, elements, and limits
251251 

plugins/mods/reference Changed · +37 / -37 lines

from line 2
22 
33> Complete reference for Claude Code mods: hooks module layout, events, mods API methods, render sites, elements by surface, limits, and settings.
44 
5Look up any event a [mod](/docs/en/plugins/mods/overview) can handle, mods API method it can call, or render site it can draw in. Entries cover the Claude Code CLI and the Desktop app as of v2.1.290, and the VS Code extension as of v2.1.299. Each entry gives the name and a one-line description, and links to the guide section that explains it where there is one.
5Look up any event a [mod](/docs/en/plugins/mods/overview.md) can handle, mods API method it can call, or render site it can draw in. Entries cover the Claude Code CLI and the Desktop app as of v2.1.290, and the VS Code extension as of v2.1.299. Each entry gives the name and a one-line description, and links to the guide section that explains it where there is one.
66 
77> [!NOTE]
88>
9> The complete reference is Claude Code's [TypeScript declarations for mods](https://github.com/anthropics/claude-code/blob/main/mods/types/claude-code.d.ts), which describe every event, method, and element, with examples. The copy on GitHub can be older than the Claude Code version you have installed. When the two disagree, trust [the copy Claude Code writes for your version](/docs/en/plugins/mods/create#get-the-types-for-your-build).
9> The complete reference is Claude Code's [TypeScript declarations for mods](https://github.com/anthropics/claude-code/blob/main/mods/types/claude-code.d.ts), which describe every event, method, and element, with examples. The copy on GitHub can be older than the Claude Code version you have installed. When the two disagree, trust [the copy Claude Code writes for your version](/docs/en/plugins/mods/create.md#get-the-types-for-your-build).
1010 
1111## Files
1212 
from line 14
1414 
1515| File | Required | Contents |
1616| :- | :- | :- |
17| `.claude-plugin/plugin.json` | Yes | The plugin [manifest](/docs/en/plugins/manifest-reference). Mods add no required fields. |
18| `hooks/hooks.json` | Yes | `modules`: an array with one path, relative to this file, to the hooks module, as in `"modules": ["./register.js"]`. Can also hold [settings hooks](/docs/en/hooks) under `hooks`. |
17| `.claude-plugin/plugin.json` | Yes | The plugin [manifest](/docs/en/plugins/manifest-reference.md). Mods add no required fields. |
18| `hooks/hooks.json` | Yes | `modules`: an array with one path, relative to this file, to the hooks module, as in `"modules": ["./register.js"]`. Can also hold [settings hooks](/docs/en/hooks.md) under `hooks`. |
1919| The hooks module, such as [`hooks/register.js`](/docs/en/plugins/mods/create#write-a-mod-yourself) | Yes | The mod's entry point. Exports `register(on, options)`. Named `.js`, `.mjs`, `.cjs`, `.jsx`, `.ts`, `.mts`, `.cts`, or `.tsx`. An ES module. |
2020| [`types/index.d.ts`](/docs/en/plugins/mods/interface#declare-the-values), named by `types` in the manifest | When the mod uses `$.state` or adds a namespace to the mods API | Declares `PluginState` values and any namespace the mod adds |
2121| Files whose names end in `.test.ts` or `.test.tsx` | No | Tests that [`claude plugin test`](/docs/en/plugins/mods/test#write-a-test) runs |
from line 24
2424 
2525## The hook function
2626 
27A mod registers each of its hooks, which are event handlers, by calling `on` inside `register`. `on` takes the event's name, an optional [matcher](/docs/en/plugins/mods/events#filter-which-events-a-hook-handles), which is a filter on the event's fields, and the hook, as in `on('tool.call', { tool: 'Bash' }, async ($, e, next) => next(e))`. `on` returns a registration with one method, `.catch(handler)`, which sets the hook's [error handler](/docs/en/plugins/mods/events#handle-a-hook-that-fails).
27A mod registers each of its hooks, which are event handlers, by calling `on` inside `register`. `on` takes the event's name, an optional [matcher](/docs/en/plugins/mods/events.md#filter-which-events-a-hook-handles), which is a filter on the event's fields, and the hook, as in `on('tool.call', { tool: 'Bash' }, async ($, e, next) => next(e))`. `on` returns a registration with one method, `.catch(handler)`, which sets the hook's [error handler](/docs/en/plugins/mods/events.md#handle-a-hook-that-fails).
2828 
2929| Argument | What it is |
3030| :- | :- |
from line 32
3232| [`e`](/docs/en/plugins/mods/events#how-a-hook-handles-an-event) | The event's input, as deeply frozen plain data. To change it, pass a copy to `next`. |
3333| [`next(e)`](/docs/en/plugins/mods/events#how-a-hook-handles-an-event) | The next handler, as in middleware. Runs the hooks after this one, then Claude Code's behavior. Resolves to the event's result. |
3434| [`next.signal`](/docs/en/plugins/mods/api#stop-background-work) | An `AbortSignal` that aborts when the event is abandoned |
35| `next.origin` | `{ plugin, tier }` of whoever fired the event. Claude Code itself is `{ plugin: 'engine', tier: 'core' }`. A mod's `tier` is its priority group in the [order mods run in](/docs/en/plugins/mods/events#the-order-mods-run-in): `prepend`, `user`, `append`, or `builtin`. |
35| `next.origin` | `{ plugin, tier }` of whoever fired the event. Claude Code itself is `{ plugin: 'engine', tier: 'core' }`. A mod's `tier` is its priority group in the [order mods run in](/docs/en/plugins/mods/events.md#the-order-mods-run-in): `prepend`, `user`, `append`, or `builtin`. |
3636| `next.budget` | The hook's time limit in milliseconds: `next.budget.ms` is the whole limit, and `next.budget.remainingMs` is what's left now |
3737| `next.to(e, tier)` | Skips to a later tier, which is `append`, `builtin`, or `core`. `next.to(e, 'append')` skips the mods a user installed. Only a mod in `prependPlugins` or `appendPlugins` can call it. |
3838| `next.error` | In a `.catch` handler only. `kind` is `throw` or `timeout` when the hook failed, and `message` is the error's text. `kind` is `re-entry` when the hook was skipped because the event came from inside a mods API call by that hook or by your mod's code outside its hooks. `re-entry` requires Claude Code v2.1.292 or later. |
from line 53
5353| :- | :- | :- |
5454| [`tool.call`](/docs/en/plugins/mods/events#guard-or-change-a-tool-call) | A tool is about to run | `next(e)`, `{ deny: reason }`, or `{ result }` |
5555| [`tool.check`](/docs/en/plugins/mods/events#where-settings-hooks-run-in-the-order) | Claude Code decides whether a tool call may run, after the `tool.call` and `PreToolUse` hooks. `next(e)` resolves to the decision the rules, the permission mode, and those hooks reached. | `next(e)` or `{ decision }`, with `decision` set to `allow`, `ask`, or `deny` and an optional `reason` |
56| `tool.describe` | Once for each tool, when its description is first sent to Claude. A second time for an MCP tool when Claude loads it through [tool search](/docs/en/mcp#scale-with-mcp-tool-search), with `e.description` set to the text Claude reads for the loaded tool. | `{ description }`, optionally with `isDeferred` set to `true` to put the tool behind tool search or `false` to load it upfront |
56| `tool.describe` | Once for each tool, when its description is first sent to Claude. A second time for an MCP tool when Claude loads it through [tool search](/docs/en/mcp.md#scale-with-mcp-tool-search), with `e.description` set to the text Claude reads for the loaded tool. | `{ description }`, optionally with `isDeferred` set to `true` to put the tool behind tool search or `false` to load it upfront |
5757 
5858#### Agent and organization fields on `tool.check`
5959 
6060In a `tool.check` hook, read these fields to tell a subagent's call from the main conversation's, and to see whether your organization requires approval for a connector tool:
6161 
62* **`e.agentId`**: set when a [subagent](/docs/en/sub-agents) or an [in-process teammate](/docs/en/agent-teams#choose-a-display-mode) makes the call, and absent when the main conversation does
63* **`e.ceiling`**: `ask` for a connector tool your organization set to `ask`, in [sessions where that setting reaches Claude Code](/docs/en/mcp#organization-controls-on-connector-tools)
62* **`e.agentId`**: set when a [subagent](/docs/en/sub-agents.md) or an [in-process teammate](/docs/en/agent-teams.md#choose-a-display-mode) makes the call, and absent when the main conversation does
63* **`e.ceiling`**: `ask` for a connector tool your organization set to `ask`, in [sessions where that setting reaches Claude Code](/docs/en/mcp.md#organization-controls-on-connector-tools)
6464 
6565On `tool.check`, `e.agentId` and `e.ceiling` require Claude Code v2.1.290 or later.
6666 
6767#### The `e.isReadOnly` field on `tool.check`
6868 
69In a `tool.check` hook, `e.isReadOnly` is `true` when the tool reports this call as read-only. Otherwise the field is absent, not `false`. The value is the tool's own report, so read [Check whether a tool call is read-only](/docs/en/plugins/mods/events#check-whether-a-tool-call-is-read-only) before you approve a call on this field alone.
69In a `tool.check` hook, `e.isReadOnly` is `true` when the tool reports this call as read-only. Otherwise the field is absent, not `false`. The value is the tool's own report, so read [Check whether a tool call is read-only](/docs/en/plugins/mods/events.md#check-whether-a-tool-call-is-read-only) before you approve a call on this field alone.
7070 
7171On `tool.check`, `e.isReadOnly` requires Claude Code v2.1.304 or later.
7272 
from line 94
9494 
9595| Field | Type | What it holds |
9696| :- | :- | :- |
97| `e.source` | string | Who provides the skill: `policySettings`, `userSettings`, or `projectSettings` for a skill in the enterprise, personal, or project [location](/docs/en/skills#where-skills-live), respectively. Other sources give a word such as `plugin`, `mcp`, `syncedSkills`, or `built-in`. |
97| `e.source` | string | Who provides the skill: `policySettings`, `userSettings`, or `projectSettings` for a skill in the enterprise, personal, or project [location](/docs/en/skills.md#where-skills-live), respectively. Other sources give a word such as `plugin`, `mcp`, `syncedSkills`, or `built-in`. |
9898| `e.pluginName` | string | The plugin's name, for a skill whose `e.source` is `plugin` |
99| `e.path` | string | The absolute path of the skill's `SKILL.md` file, or of its `.md` file for a skill written as a [command file](/docs/en/skills#where-skills-live). Absent when the skill has no file on this machine, as with a built-in skill. |
99| `e.path` | string | The absolute path of the skill's `SKILL.md` file, or of its `.md` file for a skill written as a [command file](/docs/en/skills.md#where-skills-live). Absent when the skill has no file on this machine, as with a built-in skill. |
100100| `e.frontmatter` | object | The frontmatter of the skill's file, as plain data |
101101| `e.frontmatterProblem` | string | The reason `e.frontmatter` is missing the file's frontmatter or one of its keys, as in `is a list or a single value, not a table`. Absent when `e.frontmatter` holds the whole frontmatter or the skill has none. |
102102 
103A hook can pass a changed `text` or `frontmatter` to `next`: the hooks after it read both, and Claude reads the final `text`. A hook that changes any other field [fails](/docs/en/plugins/mods/events#handle-a-hook-that-fails).
103A hook can pass a changed `text` or `frontmatter` to `next`: the hooks after it read both, and Claude reads the final `text`. A hook that changes any other field [fails](/docs/en/plugins/mods/events.md#handle-a-hook-that-fails).
104104 
105105On `skill.prompt`, `e.source`, `e.pluginName`, `e.path`, `e.frontmatter`, and `e.frontmatterProblem` require Claude Code v2.1.299 or later.
106106 
from line 134
134134| [`session.start`](/docs/en/plugins/mods/api#add-a-command-or-a-tool) | Once for each loaded mod, before the first prompt, and again after a reload of that mod. Not after `/clear`, `/resume`, or `/branch`. | `next(e)` |
135135| `session.end` | The session ends, or `/clear`, `/resume`, or `/branch` runs. `e.reason` is `clear`, `resume`, `logout`, `prompt_input_exit`, or `other`. `/branch` reports `resume`. | `next(e)` |
136136| `session.compact` | The conversation is about to be compacted | `{ skip: reason }` |
137| [`session.receive`](/docs/en/plugins/mods/api#send-and-receive-messages-between-sessions), [`session.send`](/docs/en/plugins/mods/api#send-and-receive-messages-between-sessions) | A message arrives from, or is about to go to, another agent or session. See [Send and receive messages between sessions](/docs/en/plugins/mods/api#send-and-receive-messages-between-sessions). | `{ consumed: reason }` for `receive`, `{ isDelivered: false, reason }` for `send` |
137| [`session.receive`](/docs/en/plugins/mods/api#send-and-receive-messages-between-sessions), [`session.send`](/docs/en/plugins/mods/api#send-and-receive-messages-between-sessions) | A message arrives from, or is about to go to, another agent or session. See [Send and receive messages between sessions](/docs/en/plugins/mods/api.md#send-and-receive-messages-between-sessions). | `{ consumed: reason }` for `receive`, `{ isDelivered: false, reason }` for `send` |
138138| `session.append` | Once for each row the conversation keeps, such as a prompt, a response block, a tool result, or a notice, before it's stored | `next({ ...e, message })` with a changed `message.content`, to rewrite the row's text blocks or the `content` of a `tool_result` block in it |
139139| `session.attach`, `session.detach` | Another app connects to or disconnects from the session | `next(e)` |
140140| `session.measure` | After each turn, and when a plan limit's percent used changes | `next(e)` |
from line 146
146146| Event | Fires when | A hook can return |
147147| :- | :- | :- |
148148| `agent.offer` | A subagent type is offered to Claude | `{ isOffered: false }` to withhold it |
149| `agent.spawn` | A subagent or an [agent team](/docs/en/agent-teams) teammate is about to start. For a teammate, `e.isTeammate` is `true`. | `next({ ...e, model })` to choose its model, or `{ deny: reason }` |
149| `agent.spawn` | A subagent or an [agent team](/docs/en/agent-teams.md) teammate is about to start. For a teammate, `e.isTeammate` is `true`. | `next({ ...e, model })` to choose its model, or `{ deny: reason }` |
150150 
151151When Claude resumes a subagent with the [`SendMessage`](/docs/en/sub-agents#resume-subagents) tool, your `agent.spawn` hook doesn't run again. To refuse the `SendMessage` calls that resume a subagent, match that tool in a [`tool.call`](/docs/en/plugins/mods/events#guard-or-change-a-tool-call) hook.
152152 
153153### Interface
154154 
155Interface events fire when Claude Code draws a render site and when the user uses a control a mod drew. [Draw in the interface](/docs/en/plugins/mods/interface) shows what a `ui.render` hook returns:
155Interface events fire when Claude Code draws a render site and when the user uses a control a mod drew. [Draw in the interface](/docs/en/plugins/mods/interface.md) shows what a `ui.render` hook returns:
156156 
157157| Event | Fires when |
158158| :- | :- |
from line 185
185185 
186186### Settings hook events
187187 
188Each [settings hook event](/docs/en/hooks#hook-events) is an event named `classic.<Event>`, such as `classic.Stop` or `classic.PostToolUse`. `e` is the hook's stdin JSON.
188Each [settings hook event](/docs/en/hooks.md#hook-events) is an event named `classic.<Event>`, such as `classic.Stop` or `classic.PostToolUse`. `e` is the hook's stdin JSON.
189189 
190190### Mods API calls
191191 
from line 193
193193 
194194## Mods API methods
195195 
196The mods API is the `$` argument every hook receives. Its methods are grouped in namespaces, such as `$.ui`. This table lists each namespace's methods by name, so `open` in the `$.ui` row is the call `$.ui.open(...)`. The guides show the common ones in use, and [the types for your build](/docs/en/plugins/mods/create#get-the-types-for-your-build) document every method with an example.
196The mods API is the `$` argument every hook receives. Its methods are grouped in namespaces, such as `$.ui`. This table lists each namespace's methods by name, so `open` in the `$.ui` row is the call `$.ui.open(...)`. The guides show the common ones in use, and [the types for your build](/docs/en/plugins/mods/create.md#get-the-types-for-your-build) document every method with an example.
197197 
198198| Namespace | Methods |
199199| :- | :- |
from line 210
210210| [`$.settings`](/docs/en/plugins/mods/api#reach-files-processes-and-the-network) | `read` |
211211| [`$.env`](/docs/en/plugins/mods/api#reach-files-processes-and-the-network) | `get`, `set` |
212212| [`$.fs`](/docs/en/plugins/mods/api#reach-files-processes-and-the-network) | `read`, `write`, `list`, `exists`, `stat`, `ancestors`. `write` isn't atomic: it replaces the file's content in place, so another process can read a partly written file. Keep data that several sessions change in `$.store`. |
213| [`$.store`](/docs/en/plugins/mods/interface#keep-state) | `get`, `set`, `delete`, `keys`. A key-value store that every session on the machine shares. See [Save from more than one session](/docs/en/plugins/mods/interface#save-from-more-than-one-session). |
213| [`$.store`](/docs/en/plugins/mods/interface#keep-state) | `get`, `set`, `delete`, `keys`. A key-value store that every session on the machine shares. See [Save from more than one session](/docs/en/plugins/mods/interface.md#save-from-more-than-one-session). |
214214| [`$.state`](/docs/en/plugins/mods/interface#keep-a-value-in-\$-state) | Reactive state: `get`, `set`, with the helpers `atom`, `read`, `update`, `derive`, and `memberOf` imported from `claude-code` |
215215| [`$.clock`](/docs/en/plugins/mods/api#run-work-in-the-background) | `now`, `sleep`, `after`, `every` |
216216| [`$.http`](/docs/en/plugins/mods/api#reach-files-processes-and-the-network) | `fetch` |
from line 221
221221 
222222## Render sites
223223 
224A render site is an extension point in Claude Code's interface. Each row is a value of `e.component` in a `ui.render` hook, with the fields of `e.props` and the apps that render it. `e.surface` names the app that's drawing, such as `terminal`, `desktop`, or `vscode`. [Change what Claude Code already draws](/docs/en/plugins/mods/interface#change-what-claude-code-already-draws) shows what a hook can do at a site, with an example of each choice.
224A render site is an extension point in Claude Code's interface. Each row is a value of `e.component` in a `ui.render` hook, with the fields of `e.props` and the apps that render it. `e.surface` names the app that's drawing, such as `terminal`, `desktop`, or `vscode`. [Change what Claude Code already draws](/docs/en/plugins/mods/interface.md#change-what-claude-code-already-draws) shows what a hook can do at a site, with an example of each choice.
225225 
226Rendering in the VS Code extension requires extension version 2.1.299 or later. A session that [doesn't fetch feature flags](/docs/en/env-vars#features-that-need-feature-flag-fetching) needs 2.1.304 or later. [Draw in the VS Code extension](/docs/en/plugins/mods/interface#draw-in-the-vs-code-extension) lists what the extension draws differently.
226Rendering in the VS Code extension requires extension version 2.1.299 or later. A session that [doesn't fetch feature flags](/docs/en/env-vars.md#features-that-need-feature-flag-fetching) needs 2.1.304 or later. [Draw in the VS Code extension](/docs/en/plugins/mods/interface.md#draw-in-the-vs-code-extension) lists what the extension draws differently.
227227 
228228| Site | `e.props` | `e.requestId` | Rendered on |
229229| :- | :- | :- | :- |
from line 253
253253 
254254## Elements
255255 
256Elements are the building blocks of a tree a `ui.render` hook returns, and you get them from `$.ui.resolve(e)`. [Build a tree from elements](/docs/en/plugins/mods/interface#build-a-tree-from-elements) shows the common ones with how the terminal draws them, and the [interface gallery](/docs/en/plugins/mods/gallery) has screenshots of most. A check mark means the app can draw the element.
256Elements are the building blocks of a tree a `ui.render` hook returns, and you get them from `$.ui.resolve(e)`. [Build a tree from elements](/docs/en/plugins/mods/interface.md#build-a-tree-from-elements) shows the common ones with how the terminal draws them, and the [interface gallery](/docs/en/plugins/mods/gallery.md) has screenshots of most. A check mark means the app can draw the element.
257257 
258258| Element | Main props | Terminal | Desktop | VS Code |
259259| :- | :- | :-: | :-: | :-: |
from line 267
267267| `Select` | `key`, `label`, `options`, `value`, `onSelect`, `autoFocus` | ✓ | ✓ | ✓ |
268268| `Svg` | An SVG document, up to 131,072 characters | | ✓ | ✓ |
269269| [`Client`](/docs/en/plugins/mods/interface#build-a-tree-from-elements) | `module`, `key` | ✓ | ✓ | |
270| [`Raster`](/docs/en/plugins/mods/interface#draw-a-grid-of-colored-cells) | `key`, `columns` up to 512, `rows` up to 256, `cells`. See [Draw a grid of colored cells](/docs/en/plugins/mods/interface#draw-a-grid-of-colored-cells). | ✓ | | |
271| `Image` | PNG or RGBA bytes up to 2 MiB, or a file path, `columns` and `rows` up to 255, and `alt` text. See [which terminals draw it](/docs/en/plugins/mods/gallery#image-and-client). | ✓ | | |
270| [`Raster`](/docs/en/plugins/mods/interface#draw-a-grid-of-colored-cells) | `key`, `columns` up to 512, `rows` up to 256, `cells`. See [Draw a grid of colored cells](/docs/en/plugins/mods/interface.md#draw-a-grid-of-colored-cells). | ✓ | | |
271| `Image` | PNG or RGBA bytes up to 2 MiB, or a file path, `columns` and `rows` up to 255, and `alt` text. See [which terminals draw it](/docs/en/plugins/mods/gallery.md#image-and-client). | ✓ | | |
272272 
273More `Button` rules: `action` names one of Claude Code's own [keybinding actions](/docs/en/keybindings), and the user's binding for it presses the button when that binding is a chord or a modified key. A digit `hotkey` on a button in the band also fires when the user types that digit alone into an empty prompt and pauses. When two buttons in one drawing name the same `hotkey`, the later one gets it. `autoFocus` accepts only `true` on any control, so omit the prop to leave it off.
273More `Button` rules: `action` names one of Claude Code's own [keybinding actions](/docs/en/keybindings.md), and the user's binding for it presses the button when that binding is a chord or a modified key. A digit `hotkey` on a button in the band also fires when the user types that digit alone into an empty prompt and pauses. When two buttons in one drawing name the same `hotkey`, the later one gets it. `autoFocus` accepts only `true` on any control, so omit the prop to leave it off.
274274 
275275The VS Code extension ignores some element props and draws the element as if you had left them out:
276276 
from line 313
313313 
314314If you set `gap`, `padding`, or `margin` to a step, the step applies across and down at once. For example, in the terminal and the VS Code extension, `padding: 'md'` is two cells at each side and one row above and below.
315315 
316Step names require Claude Code v2.1.299 or later. On an earlier release, Claude Code [draws its own version of the site](/docs/en/plugins/mods/interface#build-a-tree-from-elements) in place of a tree that uses a step name.
316Step names require Claude Code v2.1.299 or later. On an earlier release, Claude Code [draws its own version of the site](/docs/en/plugins/mods/interface.md#build-a-tree-from-elements) in place of a tree that uses a step name.
317317 
318318### `Text` typography props
319319 
from line 326
326326| `mono` | `true` to ask for the app's monospaced typeface | Ignored: the terminal is always monospaced | Ignored, so text keeps the extension's own typeface |
327327| `tabular` | `true` to ask for digits of equal width, so that a number that updates in place or a column of numbers stays aligned | Ignored: the terminal's digits are already one cell wide | Ignored |
328328 
329These four props require Claude Code v2.1.299 or later. On an earlier release, Claude Code [draws its own version of the site](/docs/en/plugins/mods/interface#build-a-tree-from-elements) in place of a tree that sets `size`, `weight`, `mono`, or `tabular`.
329These four props require Claude Code v2.1.299 or later. On an earlier release, Claude Code [draws its own version of the site](/docs/en/plugins/mods/interface.md#build-a-tree-from-elements) in place of a tree that sets `size`, `weight`, `mono`, or `tabular`.
330330 
331331#### Replace `bold` with `weight`
332332 
333333`bold` on a `Text` is deprecated in favor of `weight` and still works. To replace it on a `Text` with no `weight`, change `bold: true` to `weight: 'semibold'` for the same result on Claude Code v2.1.299 or later.
334334 
335On a release earlier than v2.1.299, a tree that sets `weight` doesn't draw, and Claude Code [draws its own version of the site](/docs/en/plugins/mods/interface#build-a-tree-from-elements) instead. If you set both `bold` and `weight` on a `Text`, `bold` has no effect.
335On a release earlier than v2.1.299, a tree that sets `weight` doesn't draw, and Claude Code [draws its own version of the site](/docs/en/plugins/mods/interface.md#build-a-tree-from-elements) instead. If you set both `bold` and `weight` on a `Text`, `bold` has no effect.
336336 
337337## Limits
338338 
from line 342
342342| :- | :- |
343343| A hook's own execution time for one event, not counting time inside `next` or a mods API call other than `$.clock.sleep` | 10 seconds, or 50 milliseconds for a `prompt.edit` hook |
344344| A `.catch` handler's execution time | 1 second |
345| All `session.end` hooks together | As long as the [SessionEnd hook budget](/docs/en/hooks#sessionend-input), 1.5 seconds unless you change it, counted from when your settings `SessionEnd` hooks finish |
345| All `session.end` hooks together | As long as the [SessionEnd hook budget](/docs/en/hooks.md#sessionend-input), 1.5 seconds unless you change it, counted from when your settings `SessionEnd` hooks finish |
346346| `$.process.run` timeout | 30 seconds by default, 10 minutes at most |
347347| `$.model.complete` `maxTokens` | 1024 by default, up to 64,000 or the model's output limit |
348348| `$.fs.read` and `$.fs.write` | 4 MiB for one file |
from line 350
350350| A `$.http.fetch` response body | 4 MiB. `text` holds the first 4 MiB and the rest isn't read. When the `Content-Length` header declares more, the call rejects instead, with a reason that ends `is over the 4194304-byte limit`, except when the last request after any redirects uses the `HEAD` method. The `HEAD` exemption requires Claude Code v2.1.296 or later. |
351351| One `$.http.fetch` call, redirects and body included | 30 seconds |
352352| Redirects one `$.http.fetch` call follows | 5 |
353| A hook's `drop` reason or `config.set` `deny` reason | 4,096 characters. The end of a longer reason is cut, and the drop or deny still applies. The cut requires Claude Code v2.1.292 or later, and on earlier versions the hook [fails](/docs/en/plugins/mods/events#handle-a-hook-that-fails) instead. |
353| A hook's `drop` reason or `config.set` `deny` reason | 4,096 characters. The end of a longer reason is cut, and the drop or deny still applies. The cut requires Claude Code v2.1.292 or later, and on earlier versions the hook [fails](/docs/en/plugins/mods/events.md#handle-a-hook-that-fails) instead. |
354354| Text in one tree | The first 100,000 characters are drawn |
355| A `Code`'s `language` or `path`, a `Select` option's `value`, or a `Client`'s `module` | 10,000 characters. If one is longer, Claude Code [draws its own version of the site](/docs/en/plugins/mods/interface#build-a-tree-from-elements). |
355| A `Code`'s `language` or `path`, a `Select` option's `value`, or a `Client`'s `module` | 10,000 characters. If one is longer, Claude Code [draws its own version of the site](/docs/en/plugins/mods/interface.md#build-a-tree-from-elements). |
356356| A `Link`'s `href` | 2,048 characters. A longer `href` keeps the whole tree from drawing. |
357357| `$.store` | 4 MiB of JSON in total |
358358| `$.session.messages()` | The newest 4,096 entries |
from line 371
371371| :- | :- | :- |
372372| `CLAUDE_CODE_PLUGIN_DIRS` | Environment, or `env` in `~/.claude/settings.json` | Plugin directories to load as `--plugin-dir` does, for apps you can't pass a flag to. Absolute paths separated by `:`, or `;` on Windows. |
373373| `CLAUDE_CODE_PLUGIN_DIR_WATCH` | Environment | `1` makes a long-running non-interactive session reload `--plugin-dir` mods on save |
374| `prependPlugins`, `appendPlugins` | Managed settings. User settings only on a machine with no managed settings, in a session whose credential isn't a Team or Enterprise `/login`. | Lists of plugin ids, such as `acme-guard@acme-tools`. Mods in `prependPlugins` run before every mod a user installs, and mods in `appendPlugins` run after, in the listed order. See [The order mods run in](/docs/en/plugins/mods/events#the-order-mods-run-in). |
375| `allowManagedModsOnly` | Managed settings, as an [option on the built-in guard](/docs/en/plugins/mods/admin#set-options-on-the-built-in-guard) | Only mods that [count as your organization's](/docs/en/plugins/mods/admin#install-your-organizations-mods), and mods built into Claude Code, run their hooks. Users' settings hooks keep running. |
376| `allowModsToOverrideDenyRules` | Managed settings, as an [option on the built-in guard](/docs/en/plugins/mods/admin#set-options-on-the-built-in-guard) | Lets a mod a user installed approve a tool call that a `deny` rule refuses |
377| `allowManagedHooksOnly` | Managed settings | Blocks hooks and installed mods that aren't your organization's. See [what keeps running](/docs/en/settings-reference#what-runs-under-allowmanagedhooksonly). |
374| `prependPlugins`, `appendPlugins` | Managed settings. User settings only on a machine with no managed settings, in a session whose credential isn't a Team or Enterprise `/login`. | Lists of plugin ids, such as `acme-guard@acme-tools`. Mods in `prependPlugins` run before every mod a user installs, and mods in `appendPlugins` run after, in the listed order. See [The order mods run in](/docs/en/plugins/mods/events.md#the-order-mods-run-in). |
375| `allowManagedModsOnly` | Managed settings, as an [option on the built-in guard](/docs/en/plugins/mods/admin.md#set-options-on-the-built-in-guard) | Only mods that [count as your organization's](/docs/en/plugins/mods/admin.md#install-your-organizations-mods), and mods built into Claude Code, run their hooks. Users' settings hooks keep running. |
376| `allowModsToOverrideDenyRules` | Managed settings, as an [option on the built-in guard](/docs/en/plugins/mods/admin.md#set-options-on-the-built-in-guard) | Lets a mod a user installed approve a tool call that a `deny` rule refuses |
377| `allowManagedHooksOnly` | Managed settings | Blocks hooks and installed mods that aren't your organization's. See [what keeps running](/docs/en/settings-reference.md#what-runs-under-allowmanagedhooksonly). |
378378| `disableAllHooks` | Any settings file | In managed settings, no mod or hook from an installed plugin runs. In your own settings, what your organization manages keeps running. See [`disableAllHooks`](/docs/en/settings-reference#disableallhooks). |
379379| `disableSideloadFlags` | Managed settings | Rejects `--plugin-dir` and `--plugin-url` at startup |
380380| `pluginConfigs` | User or managed settings | Holds `userConfig` values for a mod, keyed by the plugin's id, such as `acme-guard@acme-tools`, or its name and `@inline`, such as `first-mod@inline`, for one loaded with `--plugin-dir` |

plugins/mods/test Changed · +12 / -12 lines

from line 2
22 
33> Write automated tests for a Claude Code mod that fire events, stub Claude Code's answers, and press buttons, with no session, sign-in, or network.
44 
5You can write automated tests for a mod and run them from your shell with [`claude plugin test`](/docs/en/plugins/mods/reference#commands). A test fires the events your hooks handle and checks what the hooks did, so you catch a problem before it reaches a session. The first example tests the mod from [Create a mod](/docs/en/plugins/mods/create).
5You can write automated tests for a mod and run them from your shell with [`claude plugin test`](/docs/en/plugins/mods/reference#commands). A test fires the events your hooks handle and checks what the hooks did, so you catch a problem before it reaches a session. The first example tests the mod from [Create a mod](/docs/en/plugins/mods/create.md).
66 
77## Write a test
88 
from line 10
1010 
1111Give each test file a name that ends in `.test.ts`, such as `first-mod.test.ts`, and save it anywhere in the plugin directory. Every test file needs at least one `test()`, or the run fails with `declares no test(): nothing ran`. A test file can import your mod's own files and sibling `.ts` helpers, so you can unit test plain functions, such as a game's rules, without the kit.
1212 
13This test fires two tool calls, runs the `/tally` command from [Create a mod](/docs/en/plugins/mods/create), and checks that the reply counts both. Its first line is a [stub](#stub-what-claude-code-would-answer), which answers the tool calls in Claude Code's place. Save it as `first-mod/tests/first-mod.test.ts`:
13This test fires two tool calls, runs the `/tally` command from [Create a mod](/docs/en/plugins/mods/create.md), and checks that the reply counts both. Its first line is a [stub](#stub-what-claude-code-would-answer), which answers the tool calls in Claude Code's place. Save it as `first-mod/tests/first-mod.test.ts`:
1414 
1515```typescript first-mod/tests/first-mod.test.ts theme={null}
1616import { expect, test } from 'claude-code/testing'
from line 54
5454 
5555No model, store, or tool runs in a test, so wherever your mod expects Claude Code to answer, the test supplies the answer with a stub. A test function receives two arguments for that:
5656 
57* **`$`**: the test's own `$`, which acts as Claude Code. It isn't the [mods API](/docs/en/plugins/mods/reference#mods-api-methods) that a hook receives. Each of its methods fires the event of the same name, sends it through your mod's hooks, and resolves to the result: `$.tool.call({ tool: 'Bash', command: 'ls' })` fires `tool.call`. `$.command.run`, `$.prompt.submit`, `$.session.start`, and `$.turn.complete` work the same way, and `$.classic.Stop` and the other `$.classic` methods fire a [settings hook event](/docs/en/plugins/mods/events#hook-the-settings-hook-events). A test can't fire a mods API call such as `ui.close` directly. Trigger it through your mod, for example by pressing the button that closes the pane.
57* **`$`**: the test's own `$`, which acts as Claude Code. It isn't the [mods API](/docs/en/plugins/mods/reference.md#mods-api-methods) that a hook receives. Each of its methods fires the event of the same name, sends it through your mod's hooks, and resolves to the result: `$.tool.call({ tool: 'Bash', command: 'ls' })` fires `tool.call`. `$.command.run`, `$.prompt.submit`, `$.session.start`, and `$.turn.complete` work the same way, and `$.classic.Stop` and the other `$.classic` methods fire a [settings hook event](/docs/en/plugins/mods/events.md#hook-the-settings-hook-events). A test can't fire a mods API call such as `ui.close` directly. Trigger it through your mod, for example by pressing the button that closes the pane.
5858* **`on`**: call it to register stubs, which are hooks that answer in Claude Code's place. Name a stub for a mods API call without the `$.`, so a stub registered as `store.get` answers your mod's `$.store.get`. When your mod calls [`$.model.complete`](/docs/en/plugins/mods/api#call-a-model) or [`$.store.get`](/docs/en/plugins/mods/interface#keep-state), a stub supplies the answer.
5959 
60This example stubs a model call. The hook belongs to a mod named `grader`, and handles a `/grade` command that sends a sentence to a model and reports whether the reply starts with `PASS`. The file holds only the hook under test, so the mod also needs a `plugin.json` and a `hooks.json`, as in [Create a mod](/docs/en/plugins/mods/create#write-a-mod-yourself). To type `/grade` in a session, the mod also has to [register the command](/docs/en/plugins/mods/api#add-a-command):
60This example stubs a model call. The hook belongs to a mod named `grader`, and handles a `/grade` command that sends a sentence to a model and reports whether the reply starts with `PASS`. The file holds only the hook under test, so the mod also needs a `plugin.json` and a `hooks.json`, as in [Create a mod](/docs/en/plugins/mods/create.md#write-a-mod-yourself). To type `/grade` in a session, the mod also has to [register the command](/docs/en/plugins/mods/api.md#add-a-command):
6161 
6262```javascript grader/hooks/register.js theme={null}
6363export function register(on) {
from line 126
126126 await $.session.start({ surface: 'terminal', isInteractive: true, cwd: '/work' })
127127 ```
128128 
129 The second stub answers the `$.command.register` call that a `session.start` hook such as the [tutorial's](/docs/en/plugins/mods/create#write-a-mod-yourself) makes. Without it, that call rejects with `no implementation for command.register` and the kit skips your hook, so nothing after the call in the hook runs. The test doesn't fail at that point. The skipped hook is listed under `the engine reported:` only if a later check fails.
129 The second stub answers the `$.command.register` call that a `session.start` hook such as the [tutorial's](/docs/en/plugins/mods/create.md#write-a-mod-yourself) makes. Without it, that call rejects with `no implementation for command.register` and the kit skips your hook, so nothing after the call in the hook runs. The test doesn't fail at that point. The skipped hook is listed under `the engine reported:` only if a later check fails.
130130 
131131* **A hook that returns `next(e)` needs a stub to answer.** When your [`ui.render`](/docs/en/plugins/mods/reference#interface) hook returns `next(e)`, for example to draw nothing while Claude is idle, [mounting it](#test-a-drawing) fails with `no implementation for ui.render`. Register a stub that returns an element as plain data:
132132 
from line 255
255255 
256256## Test a drawing
257257 
258A test can draw one of your mod's [render sites](/docs/en/plugins/mods/reference#render-sites), then press, type into, and find the elements it drew. `$.ui.mount` draws the site through your mod's `ui.render` hook and returns a handle with a method for each of those. To cover several apps in one test, set `surface` to the app to draw for. This test opens the pane from [Build a pane with tabs](/docs/en/plugins/mods/interface#build-a-pane-with-tabs), switches tabs, presses the button, and checks the count in the terminal and the Desktop app:
258A test can draw one of your mod's [render sites](/docs/en/plugins/mods/reference.md#render-sites), then press, type into, and find the elements it drew. `$.ui.mount` draws the site through your mod's `ui.render` hook and returns a handle with a method for each of those. To cover several apps in one test, set `surface` to the app to draw for. This test opens the pane from [Build a pane with tabs](/docs/en/plugins/mods/interface.md#build-a-pane-with-tabs), switches tabs, presses the button, and checks the count in the terminal and the Desktop app:
259259 
260260```typescript hello-tabs/tests/hello-tabs.test.ts theme={null}
261261import { expect, test } from 'claude-code/testing'
from line 313
313313| `find({ key: 'more' })` or `find({ type: 'Text', text: 'Count: 2' })` | Returns the first matching element as `{ type, props, children }`, or `undefined`. `text` can be a string or a regular expression. |
314314| `unmount()` | Removes the drawing |
315315 
316Each method resolves after your handler has finished, so you can check the result on the next line. Set `props` to what Claude Code would pass for that site. The [render sites table](/docs/en/plugins/mods/reference#render-sites) lists each site's props, and [the types for your build](/docs/en/plugins/mods/create#get-the-types-for-your-build) have their types.
316Each method resolves after your handler has finished, so you can check the result on the next line. Set `props` to what Claude Code would pass for that site. The [render sites table](/docs/en/plugins/mods/reference.md#render-sites) lists each site's props, and [the types for your build](/docs/en/plugins/mods/create.md#get-the-types-for-your-build) have their types.
317317 
318318A drawing test checks the tree your hook returns and whether it's valid for that app. It doesn't check how the app paints it, so look at a new layout in a real session as well.
319319 
from line 321
321321 
322322Each test starts with every `$.state` value at its default, which is how `/clear` leaves them. To test what your mod does next, skip `session.start`, fire `classic.SessionStart` with `source: 'clear'`, and check what your mod draws.
323323 
324This test checks the module from [Load a saved value again after `/clear`](/docs/en/plugins/mods/interface#load-a-saved-value-again-after-clear). Add it to the file from [Test a drawing](#test-a-drawing), where `PANE` is defined. That file's first test expects the button to save the count, as the button in [Save from more than one session](/docs/en/plugins/mods/interface#save-from-more-than-one-session) does:
324This test checks the module from [Load a saved value again after `/clear`](/docs/en/plugins/mods/interface#load-a-saved-value-again-after-clear). Add it to the file from [Test a drawing](#test-a-drawing), where `PANE` is defined. That file's first test expects the button to save the count, as the button in [Save from more than one session](/docs/en/plugins/mods/interface.md#save-from-more-than-one-session) does:
325325 
326326```typescript hello-tabs/tests/hello-tabs.test.ts theme={null}
327327test('the saved count comes back after /clear', async ($, on) => {
from line 346
346346 
347347A mod your organization lists in [`prependPlugins`](/docs/en/plugins/mods/admin) can refuse another mod before it loads. To test one, set your mod's tier and give the test a second mod for yours to allow or refuse:
348348 
349* **`tier`**: call it once at the top of the test file, as in `tier('prepend')`, to load your mod as `prepend`, `append`, or `builtin`, its place in the [order mods run in](/docs/en/plugins/mods/events#the-order-mods-run-in). Without it, your mod loads as `user`.
349* **`tier`**: call it once at the top of the test file, as in `tier('prepend')`, to load your mod as `prepend`, `append`, or `builtin`, its place in the [order mods run in](/docs/en/plugins/mods/events.md#the-order-mods-run-in). Without it, your mod loads as `user`.
350350* **`plugins`**: pass `test` an options object ahead of the test body. Its `plugins` array holds mods you write inline, each with a `name` and a `register` function. To load one somewhere other than `user`, add `tier` to it.
351351 
352This test file loads the [policy mod from the admin page](/docs/en/plugins/mods/admin#enforce-a-policy-with-a-mod-of-your-own) first. It checks that the policy mod refuses a mod that starts a process and allows one that doesn't:
352This test file loads the [policy mod from the admin page](/docs/en/plugins/mods/admin.md#enforce-a-policy-with-a-mod-of-your-own) first. It checks that the policy mod refuses a mod that starts a process and allows one that doesn't:
353353 
354354```typescript acme-guard/tests/guard.test.ts theme={null}
355355import { expect, test, tier } from 'claude-code/testing'
from line 404
404404 
405405## Next steps
406406 
407* [Troubleshoot a mod](/docs/en/plugins/mods/troubleshoot): find out why a mod does nothing in a session
408* [Mods reference](/docs/en/plugins/mods/reference): every event's input and result, for writing stubs
407* [Troubleshoot a mod](/docs/en/plugins/mods/troubleshoot.md): find out why a mod does nothing in a session
408* [Mods reference](/docs/en/plugins/mods/reference.md): every event's input and result, for writing stubs
409409 

plugins/mods/troubleshoot Changed · +34 / -34 lines

from line 10
1010 
1111When a module doesn't load, a hook is skipped, or another mod refuses yours, Claude Code writes one line that names your mod. Where you read that line depends on the session:
1212 
13* **A session that hot-reloads a plugin directory**: a dim line in the transcript. That's an interactive session you started with `--plugin-dir`, or one where you [enabled hot reloading](/docs/en/plugins/mods/create#ask-claude-for-a-mod) for mods Claude wrote.
13* **A session that hot-reloads a plugin directory**: a dim line in the transcript. That's an interactive session you started with `--plugin-dir`, or one where you [enabled hot reloading](/docs/en/plugins/mods/create.md#ask-claude-for-a-mod) for mods Claude wrote.
1414* **Any other interactive session, such as one that runs a mod you installed from a marketplace**: the [debug log](#read-the-debug-log) only. To get one, start the session with `claude --debug`.
1515* **A `claude -p` run with `--plugin-dir`**: stderr, in the default text output format. A refusal by another mod goes to the debug log only.
1616 
from line 25
2525| `hooks modules are turned off in this process: the rollout switch served off` | Anthropic has turned installed mods off remotely. |
2626| `hooks modules are turned off in this process: the rollout switch was saved off by an earlier session` | The command used a value an earlier session saved, which may be out of date. Start `claude` once to refresh it, then run the command again. |
2727 
28An organization can also set `allowManagedModsOnly` to allow only its own mods, which this command doesn't report. In that case Claude Code refuses a mod you install, and [a message says why](/docs/en/plugins/mods/troubleshoot#messages-from-the-built-in-guard).
28An organization can also set `allowManagedModsOnly` to allow only its own mods, which this command doesn't report. In that case Claude Code refuses a mod you install, and [a message says why](/docs/en/plugins/mods/troubleshoot.md#messages-from-the-built-in-guard).
2929 
3030## The mod doesn't load
3131 
from line 33
3333 
3434### Your version is too old
3535 
36See [which version to use and how to check yours](/docs/en/plugins/mods/overview#turn-mods-on-or-off).
36See [which version to use and how to check yours](/docs/en/plugins/mods/overview.md#turn-mods-on-or-off).
3737 
3838### The `mods active` line doesn't name the mod
3939 
from line 41
4141 
4242Read the reason after the colon. The [refusal messages](#refusal-messages) section lists each one. If the log has no such line, work through the other entries in this group.
4343 
44Some settings stop a mod and leave the rest of its plugin working. [Turn mods on or off](/docs/en/plugins/mods/overview#turn-mods-on-or-off) names them.
44Some settings stop a mod and leave the rest of its plugin working. [Turn mods on or off](/docs/en/plugins/mods/overview.md#turn-mods-on-or-off) names them.
4545 
4646### A `claude -p` run prints `hooks module not loaded`
4747 
from line 60
6060| `disableAllHooks in managed settings` | Your organization turned off hooks from installed plugins |
6161| `only managed plugins and built-in plugins run` | `allowManagedHooksOnly` is set, or `disableAllHooks` is set in a settings file other than managed settings |
6262| `installed plugins that are not managed load no hooks module in this mode (--bare)` | You started Claude Code with `--bare` |
63| `another plugin of that name loads first` | Another enabled plugin has the same name as your mod and [holds the name](/docs/en/plugins/loading#hooks-when-two-enabled-plugins-share-a-name), so your hooks module doesn't load |
63| `another plugin of that name loads first` | Another enabled plugin has the same name as your mod and [holds the name](/docs/en/plugins/loading.md#hooks-when-two-enabled-plugins-share-a-name), so your hooks module doesn't load |
6464 
6565### Messages from the built-in guard
6666 
67On a machine with managed settings, or in a session whose credential is a Team or Enterprise `/login`, the [built-in guard](/docs/en/plugins/mods/admin#know-what-happens-by-default) can refuse a mod or one of its answers. Each message names the option your organization's administrator sets to change the rule.
67On a machine with managed settings, or in a session whose credential is a Team or Enterprise `/login`, the [built-in guard](/docs/en/plugins/mods/admin.md#know-what-happens-by-default) can refuse a mod or one of its answers. Each message names the option your organization's administrator sets to change the rule.
6868 
6969| Message contains | What it means | Where it appears |
7070| :- | :- | :- |
71| `mods are limited to your organization's by policy (allowManagedModsOnly)` | Your organization allows only [its own mods](/docs/en/plugins/mods/admin#install-your-organizations-mods), so yours was refused | The debug log, and the transcript in a [session that hot-reloads a plugin directory](#find-out-why-a-mod-does-nothing) |
71| `mods are limited to your organization's by policy (allowManagedModsOnly)` | Your organization allows only [its own mods](/docs/en/plugins/mods/admin.md#install-your-organizations-mods), so yours was refused | The debug log, and the transcript in a [session that hot-reloads a plugin directory](#find-out-why-a-mod-does-nothing) |
7272| `tried to lift a deny rule in your settings` | Your mod's [`tool.check`](/docs/en/plugins/mods/reference#tools) hook approved a call that a `deny` rule refuses. The call stays denied. | The transcript and the debug log, once for each mod in a session. In a `claude -p` run, the debug log only. |
7373| `the deny rules in your settings could not be checked for this call, so it is refused` | The guard failed while checking a call that a mod approved, so it refused the call | The reason Claude reads for the denied call |
7474 
from line 94
9494 
9595### `code nested too deep to scan: more than 2000 scopes`
9696 
97The line starts with the mod's name, then `hooks module did not load:`, the file, and `code nested too deep to scan: more than 2000 scopes`. A file in a hooks module can't nest scopes, such as functions, blocks, and loops, more than [2,000 deep](/docs/en/plugins/mods/reference#limits). [`claude plugin validate`](/docs/en/plugins/mods/create#check-what-claude-code-reads-from-your-mod) reports the same reason.
97The line starts with the mod's name, then `hooks module did not load:`, the file, and `code nested too deep to scan: more than 2000 scopes`. A file in a hooks module can't nest scopes, such as functions, blocks, and loops, more than [2,000 deep](/docs/en/plugins/mods/reference.md#limits). [`claude plugin validate`](/docs/en/plugins/mods/create#check-what-claude-code-reads-from-your-mod) reports the same reason.
9898 
9999Rewrite the code so its scopes nest less deeply.
100100 
from line 121
121121 
122122### Claude Code stops asking to enable hot reloading
123123 
124Claude writes a mod in an interactive session, nothing loads, and Claude Code doesn't ask again [whether to enable hot reloading](/docs/en/plugins/mods/create#ask-claude-for-a-mod). If the question ends three times without an answer picked, hot reloading stays off. For example, the question ends that way when you set [`askUserQuestionTimeout`](/docs/en/settings-reference#askuserquestiontimeout) and the time passes before you answer. That setting applies here because Claude Code asks in the same [question dialog that `AskUserQuestion` uses](/docs/en/tools-reference#question-auto-continue-timeout). A question you dismiss yourself doesn't count toward the three.
124Claude writes a mod in an interactive session, nothing loads, and Claude Code doesn't ask again [whether to enable hot reloading](/docs/en/plugins/mods/create.md#ask-claude-for-a-mod). If the question ends three times without an answer picked, hot reloading stays off. For example, the question ends that way when you set [`askUserQuestionTimeout`](/docs/en/settings-reference#askuserquestiontimeout) and the time passes before you answer. That setting applies here because Claude Code asks in the same [question dialog that `AskUserQuestion` uses](/docs/en/tools-reference#question-auto-continue-timeout). A question you dismiss yourself doesn't count toward the three.
125125 
126To run the mod, [copy its directory out of the mods folder](/docs/en/plugins/mods/create#use-the-mod-in-other-sessions), then in your shell start a new session with `--plugin-dir`, as in `claude --plugin-dir ~/mods/git-branch`.
126To run the mod, [copy its directory out of the mods folder](/docs/en/plugins/mods/create.md#use-the-mod-in-other-sessions), then in your shell start a new session with `--plugin-dir`, as in `claude --plugin-dir ~/mods/git-branch`.
127127 
128128## A hook is skipped or a mod is unloaded
129129 
from line 131
131131 
132132### `hook skipped`
133133 
134The line names the mod and the event, then says `hook skipped:` and a reason, as in `first-mod: tool.call hook skipped: threw Error: boom`. A hook threw, exceeded its [time limit](/docs/en/plugins/mods/reference#limits), or returned a result of the wrong shape. The line appears once for each event and kind of failure until the mod reloads.
134The line names the mod and the event, then says `hook skipped:` and a reason, as in `first-mod: tool.call hook skipped: threw Error: boom`. A hook threw, exceeded its [time limit](/docs/en/plugins/mods/reference.md#limits), or returned a result of the wrong shape. The line appears once for each event and kind of failure until the mod reloads.
135135 
136136Fix the error. The debug log has a line for every occurrence.
137137 
from line 139
139139 
140140You run a command your mod added, and the reply names the mod and the command, as in `first-mod registered /tally but no command.run hook answered it`, then tells you to add a hook. Claude Code prints that reply when the command reaches the end of the chain with no answer, which happens in two cases:
141141 
142* **No hook answered the command**: the module has no `command.run` hook, the hook's [filter](/docs/en/plugins/mods/events#filter-which-events-a-hook-handles) names a different command, or the hook returned `next(e)`
142* **No hook answered the command**: the module has no `command.run` hook, the hook's [filter](/docs/en/plugins/mods/events.md#filter-which-events-a-hook-handles) names a different command, or the hook returned `next(e)`
143143* **Claude Code skipped the hook**: [`hook skipped`](#hook-skipped) lists the reasons. Passing `focus: false` to [`$.ui.open`](/docs/en/plugins/mods/interface#open-a-pane-at-the-right-time) is one way to get there.
144144 
145If the module already has the hook the reply describes, look for a `hook skipped` line that names `command.run`, which gives the reason. A [test](/docs/en/plugins/mods/test) that runs the command fails with the same reason.
145If the module already has the hook the reply describes, look for a `hook skipped` line that names `command.run`, which gives the reason. A [test](/docs/en/plugins/mods/test.md) that runs the command fails with the same reason.
146146 
147147### `it crashed the hooks worker`
148148 
from line 176
176176 
177177### `a hook changed this call's input after the model wrote it`
178178 
179In auto mode, a denied tool call gives this reason. A hook changed the tool call's input after the [server-side classifier](/docs/en/permission-modes#server-side-classifier-review) reviewed it, so that review doesn't cover what would run. The hook can be a mod's [`tool.call`](/docs/en/plugins/mods/reference#tools) or [`turn.step`](/docs/en/plugins/mods/reference#turns) hook, or a [`PreToolUse`](/docs/en/hooks#pretooluse) settings hook. The message doesn't say which.
179In auto mode, a denied tool call gives this reason. A hook changed the tool call's input after the [server-side classifier](/docs/en/permission-modes.md#server-side-classifier-review) reviewed it, so that review doesn't cover what would run. The hook can be a mod's [`tool.call`](/docs/en/plugins/mods/reference#tools) or [`turn.step`](/docs/en/plugins/mods/reference#turns) hook, or a [`PreToolUse`](/docs/en/hooks#pretooluse) settings hook. The message doesn't say which.
180180 
181181The message tells Claude to issue the call once more as recorded. If that's denied too, the hook changes the input every time, so turn off the mod or hook, or leave auto mode and approve the call yourself.
182182 
from line 190
190190 
191191### `Stopped: type a message to continue; a mod cannot resume work after Stop`
192192 
193This toast means that after you stopped the turn, for example with Esc, a mod tried to start work on its own and Claude Code didn't let it. Nothing needs fixing. After your next message, mods can start work again and [some of that work comes back](/docs/en/plugins/mods/api#work-your-mod-started-before-the-interruption) on its own. If what you expected from the mod doesn't come back, ask for it again or run the mod's command again.
193This toast means that after you stopped the turn, for example with Esc, a mod tried to start work on its own and Claude Code didn't let it. Nothing needs fixing. After your next message, mods can start work again and [some of that work comes back](/docs/en/plugins/mods/api.md#work-your-mod-started-before-the-interruption) on its own. If what you expected from the mod doesn't come back, ask for it again or run the mod's command again.
194194 
195If you wrote the mod, see [Calls and background work after the user interrupts a turn](/docs/en/plugins/mods/api#calls-and-background-work-after-the-user-interrupts-a-turn).
195If you wrote the mod, see [Calls and background work after the user interrupts a turn](/docs/en/plugins/mods/api.md#calls-and-background-work-after-the-user-interrupts-a-turn).
196196 
197197## A drawing doesn't appear or respond
198198 
from line 200
200200 
201201### Another mod's band shows and yours doesn't
202202 
203There is one band above the prompt, and every mod shares it. A mod that runs [before yours](/docs/en/plugins/mods/events#the-order-mods-run-in) replaces your band when it returns a tree without the result of `next(e)` in it. To show both bands, change that mod's hook, or ask its author to:
203There is one band above the prompt, and every mod shares it. A mod that runs [before yours](/docs/en/plugins/mods/events.md#the-order-mods-run-in) replaces your band when it returns a tree without the result of `next(e)` in it. To show both bands, change that mod's hook, or ask its author to:
204204 
205* **Keep the bands after it**: put the result of `await next(e)` among the children of a `Box` in its tree, as in the Band above the prompt tab of [Pick where to draw](/docs/en/plugins/mods/interface#pick-where-to-draw)
205* **Keep the bands after it**: put the result of `await next(e)` among the children of a `Box` in its tree, as in the Band above the prompt tab of [Pick where to draw](/docs/en/plugins/mods/interface.md#pick-where-to-draw)
206206* **Keep the tree valid**: don't give that `Box`, or any `Box` around it, a `width`, `height`, `minWidth`, `minHeight`, `position`, `top`, `left`, `right`, `bottom`, `display`, or `overflow` prop
207207 
208To find that mod, [write a debug log](#read-the-debug-log) and search it for `answered ui.render without next()`. A line such as `other-mod (user) answered ui.render without next()` names a mod that returned its tree without calling `next(e)`. It doesn't name the [render site](/docs/en/plugins/mods/reference#render-sites), so a pane-only mod can appear too. A mod that calls `next(e)` and drops the result gets no line, so check the hooks before yours too.
208To find that mod, [write a debug log](#read-the-debug-log) and search it for `answered ui.render without next()`. A line such as `other-mod (user) answered ui.render without next()` names a mod that returned its tree without calling `next(e)`. It doesn't name the [render site](/docs/en/plugins/mods/reference.md#render-sites), so a pane-only mod can appear too. A mod that calls `next(e)` and drops the result gets no line, so check the hooks before yours too.
209209 
210210After the change, you see nothing in the band if any of the mods returns a tree that doesn't validate. To read the reason, look for a `ui.render (AbovePrompt) refused:` line in the transcript of a `--plugin-dir` session, or search the debug log for `does not validate`. With several mods in the band, neither line names a mod, so check each mod's tree.
211211 
212212### A pane or band is empty or shows Claude Code's usual content
213213 
214The [tree](/docs/en/plugins/mods/interface#build-a-tree-from-elements) your hook returned didn't validate. With `--plugin-dir`, the transcript says `ui.render (Pane) refused:` with the reason, as in `first-mod: ui.render (Pane) refused: Box prop "flexDirection" must be one of row, column, row-reverse, column-reverse; the engine drew its own`. The debug log has `a hook returned a tree that does not validate` with the same reason.
214The [tree](/docs/en/plugins/mods/interface.md#build-a-tree-from-elements) your hook returned didn't validate. With `--plugin-dir`, the transcript says `ui.render (Pane) refused:` with the reason, as in `first-mod: ui.render (Pane) refused: Box prop "flexDirection" must be one of row, column, row-reverse, column-reverse; the engine drew its own`. The debug log has `a hook returned a tree that does not validate` with the same reason.
215215 
216216Read the reason on that line. Common causes are a prop the element doesn't take and an element the app doesn't have.
217217 
218218### A `ui.render` line says `threw while drawn`
219219 
220The line names the [render site](/docs/en/plugins/mods/reference#render-sites), then says `threw while drawn:` and the error, as in `first-mod: ui.render (ToolUse) threw while drawn: <error>; the engine drew its own`. Claude Code hit that error while drawing the tree your [`ui.render`](/docs/en/plugins/mods/reference#interface) hook returned, or while drawing the site from the [`props` your hook passed to `next`](/docs/en/plugins/mods/interface#change-what-claude-code-already-draws). The ending `the engine drew its own` means the site shows Claude Code's usual content.
220The line names the [render site](/docs/en/plugins/mods/reference.md#render-sites), then says `threw while drawn:` and the error, as in `first-mod: ui.render (ToolUse) threw while drawn: <error>; the engine drew its own`. Claude Code hit that error while drawing the tree your [`ui.render`](/docs/en/plugins/mods/reference#interface) hook returned, or while drawing the site from the [`props` your hook passed to `next`](/docs/en/plugins/mods/interface#change-what-claude-code-already-draws). The ending `the engine drew its own` means the site shows Claude Code's usual content.
221221 
222222Read the error and fix the value in your hook that caused it.
223223 
from line 233
233233 
234234### `$.ui.open` runs and no pane appears
235235 
236The call didn't come from something the user did, and the terminal is narrower than [the width that pane needs](/docs/en/plugins/mods/interface#when-a-pane-waits-for-a-wider-terminal).
236The call didn't come from something the user did, and the terminal is narrower than [the width that pane needs](/docs/en/plugins/mods/interface.md#when-a-pane-waits-for-a-wider-terminal).
237237 
238Open the pane from a command or a button, or check the call's `isPlaced` result. See [Open a pane at the right time](/docs/en/plugins/mods/interface#open-a-pane-at-the-right-time).
238Open the pane from a command or a button, or check the call's `isPlaced` result. See [Open a pane at the right time](/docs/en/plugins/mods/interface.md#open-a-pane-at-the-right-time).
239239 
240240### A toast doesn't appear
241241 
from line 243
243243 
244244* **The line for the call is missing**: look for one that says why Claude Code refused the call, as in `first-mod: $.ui.toast dropped: timeoutMs is a whole number of ms, 1 to 60000`.
245245* **A pane is holding toasts**: your mod or another one passed [`holdToasts`](/docs/en/plugins/mods/interface#hold-toasts-behind-a-dialog) when it opened the pane that's showing. Close the pane to end the hold. If the pane is yours and is meant to stay open, remove `holdToasts` from its `$.ui.open` call and open the pane again.
246* **The toast is under the prompt**: in the [classic renderer](/docs/en/fullscreen#enable-fullscreen-rendering), look at the right under the prompt. A toast there is one line that starts with the mod's name, rather than a box at the top right.
246* **The toast is under the prompt**: in the [classic renderer](/docs/en/fullscreen.md#enable-fullscreen-rendering), look at the right under the prompt. A toast there is one line that starts with the mod's name, rather than a box at the top right.
247247* **Your mod raised a newer toast**: in the classic renderer, a newer toast from your mod can take the place of one that's showing or waiting to show. The debug log has another line for the older toast, which ends with `gave way, cut short` when it was showing, or `gave way, unseen` when it never appeared. To show both messages, put them in one toast.
248248* **The toast ran out of time undrawn**: in fullscreen rendering, Claude Code draws at most three toasts at a time, so a toast can run out of time before it's drawn. The debug log has another line for that toast, which ends with `left the stack, never drawn`. When your mod raises several at once, put the messages in one toast.
249249 
from line 260
260260 
261261Either that app doesn't draw the site or element, or the session is one where the VS Code extension draws nothing for mods. The mod's other hooks still run. Check for these causes:
262262 
263* **The site or element isn't drawn in that app**: look up your site in the [render sites](/docs/en/plugins/mods/reference#render-sites) table and your elements in the [elements](/docs/en/plugins/mods/reference#elements) table. For an element the app lacks, check `e.surface` in the hook and return a tree the app can draw.
264* **The VS Code extension is older than 2.1.299**: the chat panel draws for mods from [extension version](/docs/en/vs-code#install-the-extension) 2.1.299. Check the version in VS Code's Extensions view and update the extension there.
265* **The extension is older than 2.1.304 and the session doesn't fetch feature flags**: update the extension, or run `claude` in VS Code's integrated terminal instead. Sessions on Amazon Bedrock, Google Cloud's Agent Platform, or Microsoft Foundry skip the fetch. For the others that skip it, such as a [Claude apps gateway](/docs/en/claude-apps-gateway) session, see [Features that need feature-flag fetching](/docs/en/env-vars#features-that-need-feature-flag-fetching).
263* **The site or element isn't drawn in that app**: look up your site in the [render sites](/docs/en/plugins/mods/reference.md#render-sites) table and your elements in the [elements](/docs/en/plugins/mods/reference.md#elements) table. For an element the app lacks, check `e.surface` in the hook and return a tree the app can draw.
264* **The VS Code extension is older than 2.1.299**: the chat panel draws for mods from [extension version](/docs/en/vs-code.md#install-the-extension) 2.1.299. Check the version in VS Code's Extensions view and update the extension there.
265* **The extension is older than 2.1.304 and the session doesn't fetch feature flags**: update the extension, or run `claude` in VS Code's integrated terminal instead. Sessions on Amazon Bedrock, Google Cloud's Agent Platform, or Microsoft Foundry skip the fetch. For the others that skip it, such as a [Claude apps gateway](/docs/en/claude-apps-gateway) session, see [Features that need feature-flag fetching](/docs/en/env-vars.md#features-that-need-feature-flag-fetching).
266266 
267267## An edit or a value is lost
268268 
from line 284
284284 
285285A value resets, or a saved value is replaced by its default. Each of those commands resets `$.state` to its defaults, and `session.start` doesn't fire again.
286286 
287[Load the saved value again](/docs/en/plugins/mods/interface#load-a-saved-value-again-after-clear) in a `classic.SessionStart` hook.
287[Load the saved value again](/docs/en/plugins/mods/interface.md#load-a-saved-value-again-after-clear) in a `classic.SessionStart` hook.
288288 
289289## Read the debug log
290290 
from line 312
312312 
313313## Next steps
314314 
315* [Test a mod](/docs/en/plugins/mods/test): catch problems before they reach a session
316* [Troubleshoot plugins](/docs/en/plugins/troubleshooting): problems with installing and loading a plugin that aren't specific to mods
315* [Test a mod](/docs/en/plugins/mods/test.md): catch problems before they reach a session
316* [Troubleshoot plugins](/docs/en/plugins/troubleshooting.md): problems with installing and loading a plugin that aren't specific to mods
317317 

plugins/org Changed · +54 / -54 lines

from line 2
22 
33> Control which plugins Claude Code installs and allows across your organization through managed settings.
44 
5Managed settings let you decide which plugins Claude Code installs and allows on every machine in your organization. Users can't override them. You deliver them either as [server-managed settings](/docs/en/server-managed-settings) from the claude.ai admin console or as endpoint-managed settings through MDM or a `managed-settings.json` file. Most controls on this page take effect only from managed settings.
5Managed settings let you decide which plugins Claude Code installs and allows on every machine in your organization. Users can't override them. You deliver them either as [server-managed settings](/docs/en/server-managed-settings.md) from the claude.ai admin console or as endpoint-managed settings through MDM or a `managed-settings.json` file. Most controls on this page take effect only from managed settings.
66 
77This page is for administrators, and the settings here govern Claude Code.
88 
from line 10
1010>
1111> These cases are covered on other pages:
1212>
13> * **Installing plugins for yourself**: start at [Install plugins](/docs/en/plugins/install)
13> * **Installing plugins for yourself**: start at [Install plugins](/docs/en/plugins/install.md)
1414> * **Controlling which plugins members can use in claude.ai and Cowork**: see [Manage plugins for your organization](https://claude.com/docs/plugins/admin) on claude.com
1515> * **Rolling one plugin out to claude.ai, Cowork, and Claude Code together**: see [Choose a rollout route](https://claude.com/docs/plugins/org-rollout#choose-a-rollout-route) on claude.com
16> * **The plugins page in claude.ai's admin settings**: [**Organization settings > Plugins & skills**](https://claude.ai/admin-settings/skills?tab=inventory) turns plugins on for members' claude.ai accounts, and those reach Claude Code as [synced plugins](/docs/en/plugins/loading#synced-plugins). It doesn't set any of the keys on this page
16> * **The plugins page in claude.ai's admin settings**: [**Organization settings > Plugins & skills**](https://claude.ai/admin-settings/skills?tab=inventory) turns plugins on for members' claude.ai accounts, and those reach Claude Code as [synced plugins](/docs/en/plugins/loading.md#synced-plugins). It doesn't set any of the keys on this page
1717 
1818The sections follow the order most rollouts take: [require plugins](#pre-install-and-require-plugins) for everyone or per repository, [seed containers and CI](#seed-containers-and-ci), [restrict](#restrict-what-users-can-install) what users can add on their own, [set update policy](#set-update-policy), then [audit](#audit-and-review) what's installed. To review every policy key in one place, see the [control matrix](#control-matrix).
1919 
from line 21
2121 
2222A marketplace is a catalog of plugins that Claude Code fetches from a git repository, a URL, or a local path. Once you register a marketplace on a machine, Claude Code can install plugins from it.
2323 
24To install plugins for a fleet, set two keys together in [managed settings](/docs/en/managed-settings), the policy file or server-delivered policy that every machine in your organization reads: `extraKnownMarketplaces` registers a marketplace on each machine, and `enabledPlugins` names the plugins to install and enable from it. [Choose a delivery mechanism](#choose-a-delivery-mechanism) covers how managed settings reach each machine.
24To install plugins for a fleet, set two keys together in [managed settings](/docs/en/managed-settings.md), the policy file or server-delivered policy that every machine in your organization reads: `extraKnownMarketplaces` registers a marketplace on each machine, and `enabledPlugins` names the plugins to install and enable from it. [Choose a delivery mechanism](#choose-a-delivery-mechanism) covers how managed settings reach each machine.
2525 
2626### Choose a delivery mechanism
2727 
2828Managed settings reach a machine through one of three delivery mechanisms:
2929 
30* **Server-managed settings**: set the plugin keys as JSON at [**Organization settings > Claude Code > Managed settings**](https://claude.ai/admin-settings/claude-code). Requires an [Owner role](/docs/en/server-managed-settings#access-control) in your Claude organization. A cloud session fetches these settings before it installs plugins.
31* **MDM policies**: on macOS, deliver a plist whose top-level keys are the settings keys. On Windows, store the whole JSON document as a string in a registry value. The plist domain and the registry key are in [Where each mechanism stores the policy](/docs/en/managed-settings#where-each-mechanism-stores-the-policy).
32* **Managed settings file**: place a `managed-settings.json` at the platform's system path. You can also add files to the `managed-settings.d/` drop-in directory beside it. The file paths per platform are in [Where each mechanism stores the policy](/docs/en/managed-settings#where-each-mechanism-stores-the-policy), and the drop-in merge rules are in [Split a file-based policy across teams](/docs/en/managed-settings#split-a-file-based-policy-across-teams).
30* **Server-managed settings**: set the plugin keys as JSON at [**Organization settings > Claude Code > Managed settings**](https://claude.ai/admin-settings/claude-code). Requires an [Owner role](/docs/en/server-managed-settings.md#access-control) in your Claude organization. A cloud session fetches these settings before it installs plugins.
31* **MDM policies**: on macOS, deliver a plist whose top-level keys are the settings keys. On Windows, store the whole JSON document as a string in a registry value. The plist domain and the registry key are in [Where each mechanism stores the policy](/docs/en/managed-settings.md#where-each-mechanism-stores-the-policy).
32* **Managed settings file**: place a `managed-settings.json` at the platform's system path. You can also add files to the `managed-settings.d/` drop-in directory beside it. The file paths per platform are in [Where each mechanism stores the policy](/docs/en/managed-settings.md#where-each-mechanism-stores-the-policy), and the drop-in merge rules are in [Split a file-based policy across teams](/docs/en/managed-settings.md#split-a-file-based-policy-across-teams).
3333 
34Use server-managed settings if you have a Claude for Teams or Enterprise organization on claude.ai and your devices aren't all under MDM. Otherwise use an MDM policy or the managed settings file. For the trade-off, see [Choose between server-managed and endpoint-managed settings](/docs/en/server-managed-settings#choose-between-server-managed-and-endpoint-managed-settings).
34Use server-managed settings if you have a Claude for Teams or Enterprise organization on claude.ai and your devices aren't all under MDM. Otherwise use an MDM policy or the managed settings file. For the trade-off, see [Choose between server-managed and endpoint-managed settings](/docs/en/server-managed-settings.md#choose-between-server-managed-and-endpoint-managed-settings).
3535 
3636#### Which managed source applies on a machine
3737 
38By default, only one of these three sources applies on a machine. Claude Code uses the first that delivers a policy key, checking server-managed settings first, then MDM policies, then the managed settings file. If server-managed settings deliver even one unrelated policy key, Claude Code ignores the plugin keys in an MDM policy or managed settings file on that machine, apart from the [keys it reads from every source](/docs/en/managed-settings#keys-read-from-every-admin-source).
38By default, only one of these three sources applies on a machine. Claude Code uses the first that delivers a policy key, checking server-managed settings first, then MDM policies, then the managed settings file. If server-managed settings deliver even one unrelated policy key, Claude Code ignores the plugin keys in an MDM policy or managed settings file on that machine, apart from the [keys it reads from every source](/docs/en/managed-settings.md#keys-read-from-every-admin-source).
3939 
4040To apply every source instead, set [`managedSourcesBehavior`](/docs/en/managed-settings#compose-every-managed-source) to `"merge"`.
4141 
42[How Claude Code combines managed sources](/docs/en/managed-settings#how-claude-code-combines-managed-sources) also lists the keys Claude Code reads from every source in both modes.
42[How Claude Code combines managed sources](/docs/en/managed-settings.md#how-claude-code-combines-managed-sources) also lists the keys Claude Code reads from every source in both modes.
4343 
4444### Require a marketplace and its plugins
4545 
from line 67
6767Adjust the `autoUpdate` and `source` fields for your marketplace:
6868 
6969* **`autoUpdate`**: `true` keeps the marketplace and its plugins refreshing in the background, and `false` turns that off. See [Set update policy](#set-update-policy).
70* **`source`**: `github` is one of several source types. A `git` source takes a `url` for GitLab or an internal host, and a `url` source takes the address of a hosted `marketplace.json`. Every source shape is in the [marketplace reference](/docs/en/plugins/marketplace-reference).
70* **`source`**: `github` is one of several source types. A `git` source takes a `url` for GitLab or an internal host, and a `url` source takes the address of a hosted `marketplace.json`. Every source shape is in the [marketplace reference](/docs/en/plugins/marketplace-reference.md).
7171 
7272If the marketplace is a private git repository, each user needs read access to it. The clone of a git-based marketplace runs with git on the user's machine, using stored credentials and no prompts. For users without git-host accounts, use a [seed](#seed-containers-and-ci) instead.
7373 
from line 74
7474A managed entry also overrides a same-name marketplace entry or `--plugin-dir` copy from another source:
7575 
7676* **Marketplaces**: a managed marketplace entry replaces a lower-precedence entry with the same name, and the two entries' fields don't merge.
77* **`--plugin-dir` copies**: `--plugin-dir` loads a plugin from a local directory for one session. For what happens when that copy's name matches a plugin your managed `enabledPlugins` names, see [Name conflicts](/docs/en/plugins/loading#name-conflicts).
77* **`--plugin-dir` copies**: `--plugin-dir` loads a plugin from a local directory for one session. For what happens when that copy's name matches a plugin your managed `enabledPlugins` names, see [Name conflicts](/docs/en/plugins/loading.md#name-conflicts).
7878 
7979Anthropic's official marketplace `claude-plugins-official` needs no `extraKnownMarketplaces` entry when `enabledPlugins` sets one of its plugins to `true`. That `name@claude-plugins-official` entry declares the marketplace by itself, wherever these keys apply. If you enable none of its plugins and still want it registered on every machine, give it an explicit entry, as [Allow the official marketplace and your own](#allow-the-official-marketplace-and-your-own) does.
8080 
from line 82
8282 
8383To cover one repository's contributors instead of your whole fleet, set `extraKnownMarketplaces` and `enabledPlugins` in that repository's `.claude/settings.json`. The `extraKnownMarketplaces` entries apply only in a folder the contributor has trusted, and in an untrusted folder Claude Code ignores them without a message:
8484 
85* **Interactive sessions**: Claude Code registers the marketplace only after the contributor accepts the [workspace trust dialog](/docs/en/permissions#what-runs-before-you-trust-a-folder) for that folder.
85* **Interactive sessions**: Claude Code registers the marketplace only after the contributor accepts the [workspace trust dialog](/docs/en/permissions.md#what-runs-before-you-trust-a-folder) for that folder.
8686* **[Non-interactive `-p` runs](/docs/en/headless)**: the entries apply only in a folder whose trust the user already accepted interactively, or whose `hasTrustDialogAccepted` flag you set in `~/.claude.json`.
8787 
88A plugin that the marketplace lists by a relative path loads from the marketplace copy once the repository's `extraKnownMarketplaces` entries apply. A plugin whose marketplace entry points at an external source instead, such as the plugin's own GitHub repository, doesn't install from the repository's settings alone. Each contributor sees `Plugin "<name>" is enabled in project settings but isn't installed` until they run `claude plugin install <name>@<marketplace> --scope project`, as [Install plugins](/docs/en/plugins/install) describes.
88A plugin that the marketplace lists by a relative path loads from the marketplace copy once the repository's `extraKnownMarketplaces` entries apply. A plugin whose marketplace entry points at an external source instead, such as the plugin's own GitHub repository, doesn't install from the repository's settings alone. Each contributor sees `Plugin "<name>" is enabled in project settings but isn't installed` until they run `claude plugin install <name>@<marketplace> --scope project`, as [Install plugins](/docs/en/plugins/install.md) describes.
8989 
9090If you use a local `directory` or `file` source with a relative path, the path resolves against your repository's main checkout. When you run Claude Code from a git worktree, the path still points at the main checkout, so all worktrees share the same marketplace location.
9191 
92To roll out a bundle of plugins with dependencies, put the bundle plugin in `enabledPlugins`, as [Plugin dependencies](/docs/en/plugins/dependencies) describes.
92To roll out a bundle of plugins with dependencies, put the bundle plugin in `enabledPlugins`, as [Plugin dependencies](/docs/en/plugins/dependencies.md) describes.
9393 
9494### When each surface applies the plugin keys
9595 
96The table shows when each kind of Claude Code session applies `extraKnownMarketplaces` and `enabledPlugins`, from managed settings and from a repository's `.claude/settings.json`. For the Desktop app and the IDE extensions, see [Install a plugin](/docs/en/plugins/install#install-a-plugin).
96The table shows when each kind of Claude Code session applies `extraKnownMarketplaces` and `enabledPlugins`, from managed settings and from a repository's `.claude/settings.json`. For the Desktop app and the IDE extensions, see [Install a plugin](/docs/en/plugins/install.md#install-a-plugin).
9797 
9898| Surface | Managed `extraKnownMarketplaces` and `enabledPlugins` | Repository `.claude/settings.json` |
9999| :- | :- | :- |
100100| Terminal, interactive | Applied at session start on every machine that receives the settings | `extraKnownMarketplaces` applied after trust; `enabledPlugins` applied at session start |
101101| `-p` and CI | Applied at session start, with installs running in the background | `extraKnownMarketplaces` in trusted folders only; `enabledPlugins` applied |
102| Cloud sessions | In an Anthropic-hosted environment, only server-managed settings reach the session, which waits for them before it installs plugins. MDM policies and managed settings files stay on the user's machine. For a self-hosted environment, see [Where and when a policy applies](/docs/en/managed-settings#where-and-when-a-policy-applies) | See the **Cloud session** tab under [Install a plugin](/docs/en/plugins/install#install-a-plugin) |
102| Cloud sessions | In an Anthropic-hosted environment, only server-managed settings reach the session, which waits for them before it installs plugins. MDM policies and managed settings files stay on the user's machine. For a self-hosted environment, see [Where and when a policy applies](/docs/en/managed-settings.md#where-and-when-a-policy-applies) | See the **Cloud session** tab under [Install a plugin](/docs/en/plugins/install.md#install-a-plugin) |
103103 
104104In a `-p` or CI run, marketplaces and plugins install in the background, so a plugin can be missing from the first turn. Set `CLAUDE_CODE_SYNC_PLUGIN_INSTALL=1` to make the run wait for the install before its first query.
105105 
from line 148
148148* **Update and remove fail**: `claude plugin marketplace update <name>` and `remove` without `--scope` on a seed marketplace fail with a message that names the seed directory.
149149* **Policy still applies**: the [allowlist and blocklist](#restrict-what-users-can-install) check a seed marketplace's recorded source too. Allow the source you built the seed from.
150150 
151For fleets with no outbound git access, combine a seed with `directory` or `file` marketplace sources on a shared mount. Set `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1` as well, which also turns off [plugin auto-update](/docs/en/plugins/loading#when-auto-update-runs). If a proxy is available, see [Proxy configuration](/docs/en/network-config#proxy-configuration) for the variables to set.
151For fleets with no outbound git access, combine a seed with `directory` or `file` marketplace sources on a shared mount. Set `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1` as well, which also turns off [plugin auto-update](/docs/en/plugins/loading.md#when-auto-update-runs). If a proxy is available, see [Proxy configuration](/docs/en/network-config.md#proxy-configuration) for the variables to set.
152152 
153153## Restrict what users can install
154154 
from line 163
163163 
164164Where the two lists are enforced depends on where you set them:
165165 
166* **The claude.ai admin console**: Claude Code enforces both lists in the sessions that [read server-managed settings](/docs/en/managed-settings#where-and-when-a-policy-applies). claude.ai also checks them when anyone in your organization adds a new marketplace from a git repository on claude.ai, or from **Customize** in the Claude Desktop app outside its Code tab. That covers a marketplace a member adds for their own account and one added for the whole organization under [**Organization settings > Plugins**](https://claude.ai/admin-settings/plugins). claude.ai refuses a repository that the allowlist doesn't admit or that the blocklist names. It doesn't re-check a marketplace that was added in either place before you set the lists, and it doesn't check uploaded plugins.
166* **The claude.ai admin console**: Claude Code enforces both lists in the sessions that [read server-managed settings](/docs/en/managed-settings.md#where-and-when-a-policy-applies). claude.ai also checks them when anyone in your organization adds a new marketplace from a git repository on claude.ai, or from **Customize** in the Claude Desktop app outside its Code tab. That covers a marketplace a member adds for their own account and one added for the whole organization under [**Organization settings > Plugins**](https://claude.ai/admin-settings/plugins). claude.ai refuses a repository that the allowlist doesn't admit or that the blocklist names. It doesn't re-check a marketplace that was added in either place before you set the lists, and it doesn't check uploaded plugins.
167167* **A managed settings file, OS-level policy, or other managed source**: Claude Code enforces both lists where it reads that source. claude.ai doesn't read it.
168168 
169169While any allowlist is set, or a blocklist names any source other than [`skills-dir`](#blocklist-with-blockedmarketplaces), a plugin whose marketplace Claude Code can't find doesn't load. `/plugin` shows the policy error for it rather than a not-found error. The common case is a stale `enabledPlugins` entry for a marketplace nobody registered.
from line 176
176176| :- | :- | :- |
177177| `strictKnownMarketplaces` | Allowlist of marketplace sources. `[]` blocks every source, including the official marketplace. Alias: `allowedMarketplaces` | Doesn't register a marketplace, restrict entries inside an allowed marketplace, or block `--plugin-dir` |
178178| `blockedMarketplaces` | Blocklist of marketplace sources, checked before the allowlist | Doesn't block a marketplace already registered from a source it doesn't match |
179| `syncClaudeAiPlugins` | Set `false` to stop Claude Code downloading and loading the plugins [synced from claude.ai](/docs/en/plugins/loading#synced-plugins) for each user's account. Requires Claude Code v2.1.273 or later | Doesn't turn off one synced plugin. For that, set `"<name>@synced": false` in [`enabledPlugins`](/docs/en/settings-reference#enabledplugins) |
179| `syncClaudeAiPlugins` | Set `false` to stop Claude Code downloading and loading the plugins [synced from claude.ai](/docs/en/plugins/loading.md#synced-plugins) for each user's account. Requires Claude Code v2.1.273 or later | Doesn't turn off one synced plugin. For that, set `"<name>@synced": false` in [`enabledPlugins`](/docs/en/settings-reference#enabledplugins) |
180180| `enabledPlugins` | `true` force-enables, `false` blocks at every scope and hides the plugin | Doesn't install a plugin whose marketplace isn't registered or allowed |
181181| `disableSideloadFlags` | Rejects `--plugin-dir`, `--plugin-url`, `--agents`, the Agent SDK `plugins` option, and non-SDK `--mcp-config` at startup, and rejects folders named in the [`CLAUDE_CODE_PLUGIN_DIRS`](/docs/en/env-vars#variables) variable the same way | Doesn't restrict `.mcp.json`, `claude mcp add`, or SDK-provided servers. Pair it with [`allowedMcpServers`](/docs/en/managed-mcp) |
182182| `disableCommandPluginSources` | Blocks plugins with a `command` source from installing, updating, or loading. A `command` source is one whose plugin directory is produced by running a command on the machine. When unset, it takes the value of `allowManagedHooksOnly` | Doesn't affect other source types |
from line 184
184184| `strictPluginOnlyCustomization` | Blocks skills, agents, hooks, and MCP servers that don't come from a plugin, managed settings, or Claude Code's built-ins. It also stops [skills-directory plugins](#keep-skills-directory-plugins-loading) loading. Set `true` to cover all four types, or an array of `skills`, `agents`, `hooks`, and `mcp` values such as `["skills", "hooks"]` to cover some | Doesn't restrict which plugins users install. Pair it with `strictKnownMarketplaces` |
185185| `pluginSuggestionMarketplaces` | Marketplaces whose plugins may appear as install suggestions. See [Recommend plugins](#recommend-plugins) | Doesn't affect the built-in tips |
186186| `pluginTrustMessage` | Appends your text to the trust warning that `/plugin` shows before a plugin installs | Doesn't change the warning's own text |
187| `allowedChannelPlugins` | Replaces the default list of plugins allowed to push channel messages. Requires `channelsEnabled: true` | See [Restrict which channel plugins can run](/docs/en/channels#restrict-which-channel-plugins-can-run) |
187| `allowedChannelPlugins` | Replaces the default list of plugins allowed to push channel messages. Requires `channelsEnabled: true` | See [Restrict which channel plugins can run](/docs/en/channels.md#restrict-which-channel-plugins-can-run) |
188188| [`CLAUDE_CODE_DISABLE_OFFICIAL_MARKETPLACE_AUTOINSTALL=1`](/docs/en/env-vars) | Stops interactive terminal sessions from auto-registering the official marketplace | Doesn't remove a marketplace already registered. The allowlist and blocklist gate the same auto-registration without it. A machine that started once with it set doesn't resume auto-registration after you unset it |
189| [`allowManagedModsOnly`](/docs/en/plugins/mods/admin#stop-user-installed-mods-from-loading) | Stops every installed [mod](/docs/en/plugins/mods/overview) that doesn't [count as your organization's](/docs/en/plugins/mods/admin#install-your-organizations-mods) from running its hooks | Doesn't stop a plugin that contains a mod from installing. For that, use the marketplace keys in this table |
189| [`allowManagedModsOnly`](/docs/en/plugins/mods/admin#stop-user-installed-mods-from-loading) | Stops every installed [mod](/docs/en/plugins/mods/overview.md) that doesn't [count as your organization's](/docs/en/plugins/mods/admin.md#install-your-organizations-mods) from running its hooks | Doesn't stop a plugin that contains a mod from installing. For that, use the marketplace keys in this table |
190190 
191191Every key in the table is a managed setting, apart from `enabledPlugins`, `syncClaudeAiPlugins`, `CLAUDE_CODE_DISABLE_OFFICIAL_MARKETPLACE_AUTOINSTALL`, and `allowManagedModsOnly`:
192192 
193193* **`enabledPlugins`**: you can set it in any scope, and managed settings lock it.
194* **`syncClaudeAiPlugins`**: each user can also set it in their own user or local settings. See its [scope in the settings reference](/docs/en/settings-reference#syncclaudeaiplugins).
194* **`syncClaudeAiPlugins`**: each user can also set it in their own user or local settings. See its [scope in the settings reference](/docs/en/settings-reference.md#syncclaudeaiplugins).
195195* **`CLAUDE_CODE_DISABLE_OFFICIAL_MARKETPLACE_AUTOINSTALL`**: this is an environment variable that you deliver through the managed `env` block shown under [Turn updates off for the whole fleet](#turn-updates-off-for-the-whole-fleet).
196* **`allowManagedModsOnly`**: this is an option on a built-in plugin, which you set under `pluginConfigs` in managed settings. See [Stop user-installed mods from loading](/docs/en/plugins/mods/admin#stop-user-installed-mods-from-loading).
196* **`allowManagedModsOnly`**: this is an option on a built-in plugin, which you set under `pluginConfigs` in managed settings. See [Stop user-installed mods from loading](/docs/en/plugins/mods/admin.md#stop-user-installed-mods-from-loading).
197197 
198Each settings key here has an entry in the [settings reference](/docs/en/settings-reference).
198Each settings key here has an entry in the [settings reference](/docs/en/settings-reference.md).
199199 
200200#### Aliases for the marketplace keys
201201 
from line 213
213213* **`git`**: `{ "source": "git", "url": "https://gitlab.example.com/tools/plugins.git" }`, with optional `ref` and `path`.
214214* **`url`**: `{ "source": "url", "url": "https://plugins.example.com/marketplace.json" }`, with optional `headers`.
215215* **`file` and `directory`**: `{ "source": "file", "path": "/opt/marketplace/marketplace.json" }` or `{ "source": "directory", "path": "/opt/marketplace/plugins" }`, with absolute paths.
216* **`hostPattern`**: `{ "source": "hostPattern", "hostPattern": "^github\\.example\\.com$" }`, matched against the host of `github`, `git`, and `url` sources. The pattern matches anywhere in the hostname, so anchor it with `^` and `$` as shown to match the whole host. A `github` source always counts as `github.com`. Use a `hostPattern` entry for a GitHub Enterprise Server or GitLab host where developers create their own marketplaces. The [GHES page](/docs/en/github-enterprise-server#allowlist-ghes-marketplaces-in-managed-settings) has the worked example.
216* **`hostPattern`**: `{ "source": "hostPattern", "hostPattern": "^github\\.example\\.com$" }`, matched against the host of `github`, `git`, and `url` sources. The pattern matches anywhere in the hostname, so anchor it with `^` and `$` as shown to match the whole host. A `github` source always counts as `github.com`. Use a `hostPattern` entry for a GitHub Enterprise Server or GitLab host where developers create their own marketplaces. The [GHES page](/docs/en/github-enterprise-server.md#allowlist-ghes-marketplaces-in-managed-settings) has the worked example.
217217* **`pathPattern`**: `{ "source": "pathPattern", "pathPattern": "^/opt/approved/" }`, matched against the `path` of `file` and `directory` sources. The pattern matches anywhere in the path, so start it with `^` to pin a directory prefix. `".*"` allows every local path.
218218* **`skills-dir`**: `{ "source": "skills-dir" }` matches no marketplace. For what it does, see [Keep skills-directory plugins loading](#keep-skills-directory-plugins-loading).
219219 
from line 229
229229 
230230#### Keep skills-directory plugins loading
231231 
232Skills-directory plugins are the plugins users keep under `~/.claude/skills/` or a project's `.claude/skills/` in folders that carry a `.claude-plugin/plugin.json`. If you set any allowlist without a `{ "source": "skills-dir" }` entry, they stop loading. If you lock any customization type with [`strictPluginOnlyCustomization`](/docs/en/settings-reference#strictpluginonlycustomization), they stop loading whether or not the entry is present. The allowlist doesn't apply to plain [skills](/docs/en/skills), meaning a `SKILL.md` without that manifest.
232Skills-directory plugins are the plugins users keep under `~/.claude/skills/` or a project's `.claude/skills/` in folders that carry a `.claude-plugin/plugin.json`. If you set any allowlist without a `{ "source": "skills-dir" }` entry, they stop loading. If you lock any customization type with [`strictPluginOnlyCustomization`](/docs/en/settings-reference#strictpluginonlycustomization), they stop loading whether or not the entry is present. The allowlist doesn't apply to plain [skills](/docs/en/skills.md), meaning a `SKILL.md` without that manifest.
233233 
234234#### Marketplaces hosted on claude.ai
235235 
236The allowlist and blocklist match a [marketplace hosted on claude.ai](/docs/en/plugins/install#add-from-claude-ai) by its host. To allow or block one, add a `hostPattern` entry that matches `claude.ai` to `strictKnownMarketplaces` or `blockedMarketplaces`. On the allowlist, such an entry admits your organization's claude.ai marketplaces and the claude.ai default marketplaces, but not a marketplace made of a member's own claude.ai uploads or one whose scope claude.ai didn't state. Requires Claude Code v2.1.273 or later.
236The allowlist and blocklist match a [marketplace hosted on claude.ai](/docs/en/plugins/install.md#add-from-claude-ai) by its host. To allow or block one, add a `hostPattern` entry that matches `claude.ai` to `strictKnownMarketplaces` or `blockedMarketplaces`. On the allowlist, such an entry admits your organization's claude.ai marketplaces and the claude.ai default marketplaces, but not a marketplace made of a member's own claude.ai uploads or one whose scope claude.ai didn't state. Requires Claude Code v2.1.273 or later.
237237 
238238#### Lock every source out
239239 
240240An empty allowlist, `[]`, locks every marketplace source out, including the official marketplace.
241241 
242This lockdown doesn't cover the plugins [synced from claude.ai](/docs/en/plugins/loading#synced-plugins), which Claude Code downloads from each user's account rather than from a marketplace. To stop those as well, set [`syncClaudeAiPlugins`](/docs/en/settings-reference#syncclaudeaiplugins) to `false` in managed settings, or turn off Skills for your organization on claude.ai.
242This lockdown doesn't cover the plugins [synced from claude.ai](/docs/en/plugins/loading.md#synced-plugins), which Claude Code downloads from each user's account rather than from a marketplace. To stop those as well, set [`syncClaudeAiPlugins`](/docs/en/settings-reference#syncclaudeaiplugins) to `false` in managed settings, or turn off Skills for your organization on claude.ai.
243243 
244244### Blocklist with `blockedMarketplaces`
245245 
from line 260
260260}
261261```
262262 
263The `url` entries in `blockedMarketplaces` also apply when a user adds an `https://` repository URL that Claude Code [clones rather than fetches](/docs/en/plugins/cli-reference#plugin-marketplace-add), such as a bare `github.com` or `gitlab.com` repository URL. The user can't add that URL if an entry names it. The match ignores the `.git` suffix and any ref the user appends after `#`. Requires Claude Code v2.1.232 or later.
263The `url` entries in `blockedMarketplaces` also apply when a user adds an `https://` repository URL that Claude Code [clones rather than fetches](/docs/en/plugins/cli-reference.md#plugin-marketplace-add), such as a bare `github.com` or `gitlab.com` repository URL. The user can't add that URL if an entry names it. The match ignores the `.git` suffix and any ref the user appends after `#`. Requires Claude Code v2.1.232 or later.
264264 
265265A `{ "source": "skills-dir" }` entry here stops [skills-directory plugins](#keep-skills-directory-plugins-loading) from loading, from both `~/.claude/skills/` and a project's `.claude/skills/`.
266266 
from line 309
309309 
310310### Turn auto-update on or off per marketplace
311311 
312Plugin auto-update runs in the background after startup for marketplaces that have it turned on. For which marketplaces have it on by default, see [When auto-update runs](/docs/en/plugins/loading#when-auto-update-runs). To decide for the fleet, set `"autoUpdate": true` or `false` on a managed `extraKnownMarketplaces` entry:
312Plugin auto-update runs in the background after startup for marketplaces that have it turned on. For which marketplaces have it on by default, see [When auto-update runs](/docs/en/plugins/loading.md#when-auto-update-runs). To decide for the fleet, set `"autoUpdate": true` or `false` on a managed `extraKnownMarketplaces` entry:
313313 
314314* If the managed entry sets the field, Claude Code refuses the user's `/plugin` toggle with an error that starts `Auto-update for '<name>' is set by`.
315315* If the managed entry leaves the field unset, the user's toggle persists.
from line 326
326326}
327327```
328328 
329To stop Claude Code's own updates but keep plugin auto-update, add `"FORCE_AUTOUPDATE_PLUGINS": "1"` to the same block. The other [environment variables that stop plugin auto-update](/docs/en/plugins/loading#when-auto-update-runs) work the same way.
329To stop Claude Code's own updates but keep plugin auto-update, add `"FORCE_AUTOUPDATE_PLUGINS": "1"` to the same block. The other [environment variables that stop plugin auto-update](/docs/en/plugins/loading.md#when-auto-update-runs) work the same way.
330330 
331`DISABLE_AUTOUPDATER` doesn't cover plugins with a [`command` source](/docs/en/plugins/marketplace-reference#command-plugin-source). Claude Code re-runs each enabled one's command every session and installs the output when it changed. For what stops those runs, see [When a command source re-runs](/docs/en/plugins/loading#when-a-command-source-re-runs).
331`DISABLE_AUTOUPDATER` doesn't cover plugins with a [`command` source](/docs/en/plugins/marketplace-reference#command-plugin-source). Claude Code re-runs each enabled one's command every session and installs the output when it changed. For what stops those runs, see [When a command source re-runs](/docs/en/plugins/loading.md#when-a-command-source-re-runs).
332332 
333333### Assign release channels to user groups
334334 
335To run stable and early-access channels, host two marketplaces that point at different refs of the same plugins. Then give each user group its own marketplace through either separate endpoint-managed settings or a gateway policy. Server-managed settings from the admin console [apply to every user in your organization](/docs/en/server-managed-settings#current-limitations), so they can't assign different settings to different groups.
335To run stable and early-access channels, host two marketplaces that point at different refs of the same plugins. Then give each user group its own marketplace through either separate endpoint-managed settings or a gateway policy. Server-managed settings from the admin console [apply to every user in your organization](/docs/en/server-managed-settings.md#current-limitations), so they can't assign different settings to different groups.
336336 
337* Deploy separate [endpoint-managed settings](/docs/en/managed-settings#delivery-mechanisms), such as a managed settings file or an MDM profile, to each group's devices. To check whether the per-group file or profile applies on a device that also has an organization-wide source, see [How Claude Code combines managed sources](/docs/en/managed-settings#precedence-within-the-managed-tier).
338* Define one [Claude apps gateway policy](/docs/en/claude-apps-gateway-config#managed) per group. The gateway applies the first policy whose match rule fits a user, so order the policies so that each user reaches their group's policy. That policy's `extraKnownMarketplaces` map doesn't merge with any other policy's, so list every marketplace the group needs in it, not only its channel marketplace.
337* Deploy separate [endpoint-managed settings](/docs/en/managed-settings.md#delivery-mechanisms), such as a managed settings file or an MDM profile, to each group's devices. To check whether the per-group file or profile applies on a device that also has an organization-wide source, see [How Claude Code combines managed sources](/docs/en/managed-settings.md#precedence-within-the-managed-tier).
338* Define one [Claude apps gateway policy](/docs/en/claude-apps-gateway-config.md#managed) per group. The gateway applies the first policy whose match rule fits a user, so order the policies so that each user reaches their group's policy. That policy's `extraKnownMarketplaces` map doesn't merge with any other policy's, so list every marketplace the group needs in it, not only its channel marketplace.
339339 
340340With either mechanism, the stable group receives this configuration:
341341 
from line 349
349349}
350350```
351351 
352The early-access group receives `latest-tools` instead. To set up the two marketplaces, see [Run release channels](/docs/en/plugins/host-marketplace#run-release-channels).
352The early-access group receives `latest-tools` instead. To set up the two marketplaces, see [Run release channels](/docs/en/plugins/host-marketplace.md#run-release-channels).
353353 
354354## Recommend plugins
355355 
356356Marketplace owners can attach `relevance` signals to entries so Claude Code suggests the plugin when a project matches.
357357 
358Suggestions from a marketplace appear only when it's registered on the user's machine, you list its name in `pluginSuggestionMarketplaces` in managed settings, and you declare its source in the same policy. Declare the source either as the marketplace's `extraKnownMarketplaces` entry or as an allowlist entry. The official marketplace needs only the name. See [Enable suggestions in managed settings](/docs/en/plugins/relevance#enable-suggestions-in-managed-settings).
358Suggestions from a marketplace appear only when it's registered on the user's machine, you list its name in `pluginSuggestionMarketplaces` in managed settings, and you declare its source in the same policy. Declare the source either as the marketplace's `extraKnownMarketplaces` entry or as an allowlist entry. The official marketplace needs only the name. See [Enable suggestions in managed settings](/docs/en/plugins/relevance.md#enable-suggestions-in-managed-settings).
359359 
360360## Audit and review
361361 
362362OpenTelemetry events and the Analytics API tell you what your fleet installs and runs.
363363 
364For what a plugin can run on a machine and what each trust tier permits, read [Plugin security](/docs/en/plugins/security) before you approve a marketplace.
364For what a plugin can run on a machine and what each trust tier permits, read [Plugin security](/docs/en/plugins/security.md) before you approve a marketplace.
365365 
366366### OpenTelemetry events
367367 
368`claude_code.plugin_installed` records each install, and `claude_code.plugin_loaded` records each enabled plugin at session start. Both events redact or omit third-party plugin and marketplace names unless you set `OTEL_LOG_TOOL_DETAILS=1`, as [Redacted plugin names in your backend](/docs/en/plugins/measure#redacted-plugin-names-in-your-backend) shows. Field lists are under [Plugin installed event](/docs/en/monitoring-usage#plugin-installed-event) and [Plugin loaded event](/docs/en/monitoring-usage#plugin-loaded-event).
368`claude_code.plugin_installed` records each install, and `claude_code.plugin_loaded` records each enabled plugin at session start. Both events redact or omit third-party plugin and marketplace names unless you set `OTEL_LOG_TOOL_DETAILS=1`, as [Redacted plugin names in your backend](/docs/en/plugins/measure.md#redacted-plugin-names-in-your-backend) shows. Field lists are under [Plugin installed event](/docs/en/monitoring-usage.md#plugin-installed-event) and [Plugin loaded event](/docs/en/monitoring-usage.md#plugin-loaded-event).
369369 
370370### Analytics API
371371 
372On the Enterprise plan, `GET /v1/organizations/analytics/plugins` returns per-plugin, per-day install and invocation counts across Claude Code and Cowork. You can group the counts by user or RBAC group. Plugin activity that reaches Anthropic without a plugin name appears in one aggregate `third-party` row. See the [endpoint reference](https://platform.claude.com/docs/en/api/admin/analytics/plugins/list) and [Access data programmatically](/docs/en/analytics#access-data-programmatically) for the key it needs.
372On the Enterprise plan, `GET /v1/organizations/analytics/plugins` returns per-plugin, per-day install and invocation counts across Claude Code and Cowork. You can group the counts by user or RBAC group. Plugin activity that reaches Anthropic without a plugin name appears in one aggregate `third-party` row. See the [endpoint reference](https://platform.claude.com/docs/en/api/admin/analytics/plugins/list) and [Access data programmatically](/docs/en/analytics.md#access-data-programmatically) for the key it needs.
373373 
374374## Plan for what managed settings can't enforce
375375 
from line 379
379379* **Restricting entries inside an allowed marketplace**: the allowlist matches marketplace sources. To block one plugin from an allowed marketplace, set it to `false` in managed `enabledPlugins`.
380380* **Hiding `/plugin`**: no key disables the command. The nearest equivalent combines an allowlist naming only your marketplace, managed `enabledPlugins` entries for the plugins you supply, and `disableSideloadFlags`.
381381* **Gating `--plugin-dir` through the allowlist**: the allowlist doesn't cover `--plugin-dir`. `disableSideloadFlags` does.
382* **Enforcing the claude.ai plugin toggles through these keys**: [**Organization settings > Plugins & skills**](https://claude.ai/admin-settings/skills?tab=inventory) doesn't set the keys on this page. What members and your organization turn on there reaches the CLI as [synced plugins](/docs/en/plugins/loading#synced-plugins), which have their own controls.
382* **Enforcing the claude.ai plugin toggles through these keys**: [**Organization settings > Plugins & skills**](https://claude.ai/admin-settings/skills?tab=inventory) doesn't set the keys on this page. What members and your organization turn on there reaches the CLI as [synced plugins](/docs/en/plugins/loading.md#synced-plugins), which have their own controls.
383383 
384384## Troubleshoot policy
385385 
386386If plugin policy doesn't behave as expected on a machine, check for these symptoms first:
387387 
388* **The managed file didn't parse**: when a `managed-settings.json` isn't valid JSON, Claude Code refuses to start and prints [an error naming the file](/docs/en/errors#managed-settings-document-could-not-be-parsed). A file that parses but has one invalid entry keeps the rest of its policy. See [Invalid entries in managed settings](/docs/en/managed-settings#invalid-entries-in-managed-settings).
388* **The managed file didn't parse**: when a `managed-settings.json` isn't valid JSON, Claude Code refuses to start and prints [an error naming the file](/docs/en/errors.md#managed-settings-document-could-not-be-parsed). A file that parses but has one invalid entry keeps the rest of its policy. See [Invalid entries in managed settings](/docs/en/managed-settings.md#invalid-entries-in-managed-settings).
389389* **The managed source didn't load**: run `/status` and look for `Enterprise managed settings` in the `Setting sources` line. If it's missing, the source didn't load.
390* **A user reports `blocked by enterprise policy`**: the message names the marketplace or its source. For an allowlist, it also lists the allowed sources. The user-facing entries are on [Troubleshoot plugins](/docs/en/plugins/troubleshooting).
390* **A user reports `blocked by enterprise policy`**: the message names the marketplace or its source. For an allowlist, it also lists the allowed sources. The user-facing entries are on [Troubleshoot plugins](/docs/en/plugins/troubleshooting.md).
391391* **A plugin the user disabled in `~/.claude/settings.json` still loads**: another settings source re-enabled it, such as a managed `enabledPlugins` entry that force-enables it. `/plugin` and `claude plugin list` show `Disabled in ~/.claude/settings.json but still loads` with that settings source.
392392 
393393## Next steps
394394 
395* [Marketplace reference](/docs/en/plugins/marketplace-reference#marketplace-sources): the `source` values `extraKnownMarketplaces`, `strictKnownMarketplaces`, and `blockedMarketplaces` accept
396* [Host and maintain a marketplace](/docs/en/plugins/host-marketplace): run the marketplace your policy points at
397* [Plugin security and trust](/docs/en/plugins/security): what a plugin can do on a machine and how to review one before installing
398* [Manage mods for your organization](/docs/en/plugins/mods/admin): turn off or limit mods, the plugins that run JavaScript inside Claude Code
399* [Server-managed settings](/docs/en/server-managed-settings): deliver these keys from the claude.ai admin console
400* [Troubleshoot plugins](/docs/en/plugins/troubleshooting#blocked-by-your-organization): the messages users see when policy blocks them
395* [Marketplace reference](/docs/en/plugins/marketplace-reference.md#marketplace-sources): the `source` values `extraKnownMarketplaces`, `strictKnownMarketplaces`, and `blockedMarketplaces` accept
396* [Host and maintain a marketplace](/docs/en/plugins/host-marketplace.md): run the marketplace your policy points at
397* [Plugin security and trust](/docs/en/plugins/security.md): what a plugin can do on a machine and how to review one before installing
398* [Manage mods for your organization](/docs/en/plugins/mods/admin.md): turn off or limit mods, the plugins that run JavaScript inside Claude Code
399* [Server-managed settings](/docs/en/server-managed-settings.md): deliver these keys from the claude.ai admin console
400* [Troubleshoot plugins](/docs/en/plugins/troubleshooting.md#blocked-by-your-organization): the messages users see when policy blocks them
401401 
Feedback