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

One read of Claude Code CLIclaude-code-20261020T183702Z

212 pages moved out of 228 read.

Pages moved 212 significant first
Pages read 228 in this capture
Captured 18:37 UTC
Corpus hash f4a7dc09bf09 corpus-hash

What this read moved

126-150 of 212, page 6 of 9

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

plugins/dependencies Changed · +9 / -11 lines

## Release a plugin that others depend on

from line 6
66 
77This page is for plugin authors who declare dependencies in `plugin.json` and for marketplace maintainers who tag releases.
88 
9<Note>
10 These cases are covered on other pages:
9> [!NOTE]
10>
11> These cases are covered on other pages:
12>
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)
1116 
12 * **Installing a plugin that has dependencies**: see [Manage installed plugins](/docs/en/plugins/install#manage-installed-plugins)
13 * **Reading a dependency error**: see [Dependency errors](/docs/en/plugins/troubleshooting#dependency-errors)
14 * **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)
15</Note>
16 
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 
1919## Declare dependencies
2020 
21<span id="decide-whether-to-constrain-dependency-versions" />Without a version constraint, a dependency moves to each new release its marketplace publishes the next time users update. If that release renames an MCP tool your plugin calls, your plugin breaks for everyone who updates.
21Without a version constraint, a dependency moves to each new release its marketplace publishes the next time users update. If that release renames an MCP tool your plugin calls, your plugin breaks for everyone who updates.
2222 
2323With a constraint such as `~2.1.0` on a dependency from a git-backed source, users who have your plugin installed keep receiving `2.1.x` patches of the dependency and never move to `2.2`. To upgrade on your own schedule, test against a newer release and then publish a new version of your plugin with a wider constraint.
2424 
from line 127
127127 
128128When both plugins are in one parent folder, you can pass that folder to `--plugin-dir` once. If the folder isn't itself a plugin, Claude Code loads each child folder that has a `.claude-plugin/plugin.json`. Requires Claude Code v2.1.265 or later.
129129 
130<h2 id="tag-plugin-releases-for-version-resolution">
131 Release a plugin that others depend on
132</h2>
130## Release a plugin that others depend on
133131 
134132If 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:
135133 

plugins/host-marketplace Changed · +8 / -12 lines

### Installs and updates that refuse a command instead of asking ### When a marketplace `url` source's command runs

from line 6
66 
77This page is for the person who operates a marketplace.
88 
9<Note>
10 These cases are covered on other pages:
9> [!NOTE]
10>
11> These cases are covered on other pages:
12>
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)
1115 
12 * **You haven't written the catalog file yet**: start with [Create a marketplace](/docs/en/plugins/create-marketplace)
13 * **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)
14</Note>
15 
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 
1818## Host your marketplace
from line 371
371371 
372372Claude Code runs only the command it showed, for the archive URL it showed. If the entry's command or archive URL changed in between, Claude Code refuses the install or update. A change in the query string alone doesn't count, except in the VS Code extension or with `--accept-command`.
373373 
374<h3 id="installs-and-updates-that-refuse-the-command-instead-of-asking">
375 Installs and updates that refuse a command instead of asking
376</h3>
374### Installs and updates that refuse a command instead of asking
377375 
378376On any operation other than a single-plugin install or update, Claude Code neither runs an entry's command nor downloads its archive. The plugin stays at its installed version or stays uninstalled, and the user sees one of these results:
379377 
from line 378
380378* **Installing several plugins at once, from a plugin suggestion, or as another plugin's dependency**: Claude Code refuses the plugin that has the command and directs the user to that plugin's own view in `/plugin`. The other plugins in a bulk install still install. A plugin that depends on the refused plugin fails to install until the user installs the refused plugin by itself.
381379* **Background auto-update, or session start for a plugin whose archive was never downloaded**: Claude Code lists the plugin in the `/plugin` Errors tab so the user knows to install or update it themselves.
382380 
383<h3 id="when-a-marketplace-url-sources-command-runs">
384 When a marketplace `url` source's command runs
385</h3>
381### When a marketplace `url` source's command runs
386382 
387383You declare a marketplace `url` source's `headersHelper` in a settings file, such as an [`extraKnownMarketplaces`](/docs/en/settings-reference#extraknownmarketplaces) entry, rather than in the catalog the marketplace publishes. Claude Code therefore doesn't ask the user to accept it on each install or update. Instead, the settings file that declares it decides when Claude Code runs it:
388384 

plugins/install Changed · +115 / -129 lines

### JetBrains, non-interactive runs, and the Agent SDK ### Plugins from your claude.ai account ### Add a marketplace from claude.ai

from line 6
66 
77This page is for anyone using plugins on their own machine or account, whether in the terminal, the desktop app, an IDE, or a cloud session: it covers installing, choosing a scope, adding marketplaces, and keeping plugins updated.
88 
9<Note>
10 These cases are covered on other pages:
9> [!NOTE]
10>
11> These cases are covered on other pages:
12>
13> * **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)
1115 
12 * **You use claude.ai chat or Cowork, not Claude Code**: see [Plugins on claude.ai and in Cowork](https://claude.com/docs/plugins/overview)
13 * **Claude Code printed an error**: find it in [Troubleshoot plugins](/docs/en/plugins/troubleshooting)
14</Note>
15 
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
from line 23
2323 
2424Pick the tab for where you run Claude Code.
2525 
26<Tabs>
27 <Tab title="Terminal">
28 Start Claude Code with `claude` in your project, then:
26**Terminal**
2927 
30 <Steps>
31 <Step title="Open the plugin's details with the install command">
32 Run `/plugin install` with the plugin's name and marketplace. In a session, this command doesn't install right away: it opens the `/plugin` panel on that plugin's details so you can review it and choose a scope first.
28Start Claude Code with `claude` in your project, then:
3329 
34 ```text theme={null}
35 /plugin install commit-commands@claude-plugins-official
36 ```
30**1. Open the plugin's details with the install command**
3731 
38 To browse instead, run `/plugin` with no plugin name: the panel opens on the **Discover** tab, which lists the plugins from your marketplaces, and you can type to search, then press **Enter** on a plugin to open its details.
39 </Step>
32Run `/plugin install` with the plugin's name and marketplace. In a session, this command doesn't install right away: it opens the `/plugin` panel on that plugin's details so you can review it and choose a scope first.
4033 
41 <Step title="Review what the plugin adds">
42 The details pane shows the plugin's description. It can also show:
34```text theme={null}
35/plugin install commit-commands@claude-plugins-official
36```
4337 
44 * **Will install**: the commands, agents, skills, hooks, and MCP and LSP servers the plugin adds.
45 * **Last updated**: shown for a plugin in Anthropic's official marketplace.
46 * **Context cost**: for a plugin in Anthropic's official marketplace, two token estimates. **Every turn** is what the plugin adds to each message you send, and **When invoked** is what its skills and agents add once Claude loads them. The estimates appear when you open the plugin by naming its marketplace, as the step 1 command does, or from the **Marketplaces** tab. The details pane you reach from the **Discover** list doesn't show them.
38To browse instead, run `/plugin` with no plugin name: the panel opens on the **Discover** tab, which lists the plugins from your marketplaces, and you can type to search, then press **Enter** on a plugin to open its details.
4739 
48 Plugins from a local or custom marketplace can show `Components will be discovered at installation` instead.
40**2. Review what the plugin adds**
4941 
50 A plugin can run hooks and MCP servers, so read the pane before you install. See [Plugin security and trust](/docs/en/plugins/security).
51 </Step>
42The details pane shows the plugin's description. It can also show:
5243 
53 <Step title="Choose a scope">
54 Select one of the three install options:
44* **Will install**: the commands, agents, skills, hooks, and MCP and LSP servers the plugin adds.
45* **Last updated**: shown for a plugin in Anthropic's official marketplace.
46* **Context cost**: for a plugin in Anthropic's official marketplace, two token estimates. **Every turn** is what the plugin adds to each message you send, and **When invoked** is what its skills and agents add once Claude loads them. The estimates appear when you open the plugin by naming its marketplace, as the step 1 command does, or from the **Marketplaces** tab. The details pane you reach from the **Discover** list doesn't show them.
5547 
56 * **Install for you (user scope)**: you get the plugin in every project on this machine
57 * **Install for all collaborators on this repository (project scope)**: it's enabled for everyone who works in this repository
58 * **Install for you, in this repo only (local scope)**: you get it in this repository only
48Plugins from a local or custom marketplace can show `Components will be discovered at installation` instead.
5949 
60 [Choose an install scope](#choose-an-install-scope) says which settings file each one writes to and which applies when the same plugin is set at more than one.
50A plugin can run hooks and MCP servers, so read the pane before you install. See [Plugin security and trust](/docs/en/plugins/security).
6151 
62 After you select a scope, Claude Code installs the plugin along with any dependencies it declares, then prints an install summary.
63 </Step>
52**3. Choose a scope**
6453 
65 <Step title="Read the install summary">
66 The last sentence of the summary tells you whether the plugin is usable in this session yet:
54Select one of the three install options:
6755 
68 * **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).
72 </Step>
56* **Install for you (user scope)**: you get the plugin in every project on this machine
57* **Install for all collaborators on this repository (project scope)**: it's enabled for everyone who works in this repository
58* **Install for you, in this repo only (local scope)**: you get it in this repository only
7359 
74 <Step title="Confirm the plugin works">
75 Type `/` and look for the plugin's skills under its name, in the form `/<plugin>:<skill>`. For `commit-commands`, `/commit-commands:commit` appears. Two other places list the plugin too:
60[Choose an install scope](#choose-an-install-scope) says which settings file each one writes to and which applies when the same plugin is set at more than one.
7661 
77 * Open the **Installed** tab in `/plugin`, which lists the plugin with its scope.
78 * In your shell, run `claude plugin list`, which prints the same list with `Version`, `Scope`, and `Status` lines.
62After you select a scope, Claude Code installs the plugin along with any dependencies it declares, then prints an install summary.
7963 
80 If `/commit-commands:commit` doesn't appear, see [After install: plugin not working](/docs/en/plugins/troubleshooting#plugin-installed-but-not-working).
81 </Step>
82 </Steps>
64**4. Read the install summary**
8365 
84 Installing 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`.
85 </Tab>
66The last sentence of the summary tells you whether the plugin is usable in this session yet:
8667 
87 <Tab title="Desktop app">
88 In a local or SSH session in the desktop app's **Code** tab:
68* **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).
8972 
90 <Steps>
91 <Step title="Open the plugin browser">
92 Click the **+** button next to the prompt box and select **Add plugins**. If the **+** menu shows **Plugins** instead of **Add plugins**, select **Plugins**, then **Browse plugins**. The plugin browser opens with the plugins from your marketplaces.
93 </Step>
73**5. Confirm the plugin works**
9474 
95 <Step title="Select the plugin">
96 Find `commit-commands` and select it.
97 </Step>
75Type `/` and look for the plugin's skills under its name, in the form `/<plugin>:<skill>`. For `commit-commands`, `/commit-commands:commit` appears. Two other places list the plugin too:
9876 
99 <Step title="Choose a scope">
100 Choose a [scope](#choose-an-install-scope): your user account, this project, or local-only.
101 </Step>
102 </Steps>
77* Open the **Installed** tab in `/plugin`, which lists the plugin with its scope.
78* In your shell, run `claude plugin list`, which prints the same list with `Version`, `Scope`, and `Status` lines.
10379 
104 To enable, disable, or uninstall a plugin later, see [Install plugins in the desktop app](/docs/en/desktop#install-plugins).
105 </Tab>
80If `/commit-commands:commit` doesn't appear, see [After install: plugin not working](/docs/en/plugins/troubleshooting#plugin-installed-but-not-working).
10681 
107 <Tab title="VS Code">
108 In the Claude Code panel in VS Code:
82Installing 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`.
10983 
110 <Steps>
111 <Step title="Open Manage plugins">
112 Type `/plugins` in the prompt box to open **Manage plugins**.
113 </Step>
84**Desktop app**
11485 
115 <Step title="Install the plugin">
116 On the **Plugins** tab, search for `commit-commands` and click **Install**. If the tab lists no plugins, add `anthropics/claude-plugins-official` on the **Marketplaces** tab first.
117 </Step>
86In a local or SSH session in the desktop app's **Code** tab:
11887 
119 <Step title="Choose a scope">
120 Choose a [scope](#choose-an-install-scope): **Install for you**, **Install for this project**, or **Install locally**.
121 </Step>
122 </Steps>
88**1. Open the plugin browser**
12389 
124 Your changes apply to open sessions without a restart. See [Manage plugins in VS Code](/docs/en/vs-code#manage-plugins).
125 </Tab>
90Click the **+** button next to the prompt box and select **Add plugins**. If the **+** menu shows **Plugins** instead of **Add plugins**, select **Plugins**, then **Browse plugins**. The plugin browser opens with the plugins from your marketplaces.
12691 
127 <Tab title="Cloud session">
128 A [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).
92**2. Select the plugin**
12993 
130 See [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.
131 </Tab>
132</Tabs>
94Find `commit-commands` and select it.
13395 
96**3. Choose a scope**
97 
98Choose a [scope](#choose-an-install-scope): your user account, this project, or local-only.
99 
100To enable, disable, or uninstall a plugin later, see [Install plugins in the desktop app](/docs/en/desktop#install-plugins).
101 
102**VS Code**
103 
104In the Claude Code panel in VS Code:
105 
106**1. Open Manage plugins**
107 
108Type `/plugins` in the prompt box to open **Manage plugins**.
109 
110**2. Install the plugin**
111 
112On the **Plugins** tab, search for `commit-commands` and click **Install**. If the tab lists no plugins, add `anthropics/claude-plugins-official` on the **Marketplaces** tab first.
113 
114**3. Choose a scope**
115 
116Choose a [scope](#choose-an-install-scope): **Install for you**, **Install for this project**, or **Install locally**.
117 
118Your changes apply to open sessions without a restart. See [Manage plugins in VS Code](/docs/en/vs-code#manage-plugins).
119 
120**Cloud session**
121 
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).
123 
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.
125 
134126### Choose an install scope
135127 
136128A plugin's install scope decides who gets the plugin and which settings file records it as enabled:
from line 137
145137 
146138The 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.
147139 
148<h3 id="other-places-you-run-claude-code">
149 JetBrains, non-interactive runs, and the Agent SDK
150</h3>
140### JetBrains, non-interactive runs, and the Agent SDK
151141 
152142Some places you run Claude Code have no plugin browser of their own:
153143 
from line 147
157147 
158148If 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).
159149 
160<Tip>
161 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).
162</Tip>
150> [!TIP]
151>
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).
163153 
164<h3 id="plugins-from-your-claude-ai-account">
165 Plugins from your claude.ai account
166</h3>
154### Plugins from your claude.ai account
167155 
168156Your claude.ai account is a separate source of plugins, alongside the marketplaces you install from:
169157 
from line 196
208196 
209197From your shell, `claude plugin marketplace add` takes the same sources.
210198 
211<Tip>
212 `/plugin market` also works as a shorter form of `/plugin marketplace`.
213</Tip>
199> [!TIP]
200>
201> `/plugin market` also works as a shorter form of `/plugin marketplace`.
214202 
215203Include 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.
216204 
from line 244
256244 
257245If 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).
258246 
259<h3 id="add-from-claude-ai">
260 Add a marketplace from claude.ai
261</h3>
247### Add a marketplace from claude.ai
262248 
263249In 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.
264250 

plugins/loading Changed · +8 / -12 lines

### Plugins synced from claude.ai ### Hooks when two enabled plugins share a name

from line 4
44 
55Use this page when a plugin didn't load, loaded a different copy than you expected, or didn't pick up an update, and you want to see which source, settings scope, or file on disk decided that. It gives the rules Claude Code applies when a session starts and each time you run `/reload-plugins`. You can also ask Claude to read this page and diagnose your setup.
66 
7<Note>
8 These cases are covered on other pages:
7> [!NOTE]
8>
9> These cases are covered on other pages:
10>
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)
913 
10 * **Install, enable, disable, and update steps**: see [Install and manage plugins](/docs/en/plugins/install)
11 * **You have a specific error message**: see [Troubleshoot plugins](/docs/en/plugins/troubleshooting)
12</Note>
13 
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 
1616* A plugin you turned off still loads: [Find where a plugin is enabled](#find-where-a-plugin-is-enabled)
from line 82
8282 
8383For how to write `--plugin-dir` and skills-directory plugins, see [Create plugins](/docs/en/plugins/create).
8484 
85<h3 id="synced-plugins">
86 Plugins synced from claude.ai
87</h3>
85### Plugins synced from claude.ai
8886 
8987A plugin you turn on for your claude.ai account also loads in Claude Code, alongside the plugins you install from marketplaces. That includes plugins your organization turns on for its members. Each of these plugins loads as `<name>@synced`, with no marketplace and no [install record](#check-which-stage-a-plugin-reached).
9088 
from line 367
369367 
370368Because the order compares manifest names, a `--plugin-dir` plugin named `hello-plugin` replaces `hello@example-marketplace` when that plugin's manifest also says `"name": "hello-plugin"`.
371369 
372<h3 id="hooks-when-two-enabled-plugins-share-a-name">
373 Hooks when two enabled plugins share a name
374</h3>
370### Hooks when two enabled plugins share a name
375371 
376372When 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.
377373 

plugins/manifest-reference Changed · +6 / -6 lines

from line 6
66 
77This reference is for plugin creators, and for marketplace owners who put component fields in a marketplace entry.
88 
9<Note>
10 These cases are covered on other pages:
11 
12 * **Learning to build a plugin**: start with [Create a plugin](/docs/en/plugins/create)
13 * **What each component does at runtime**: see [Plugin components](/docs/en/plugins/components)
14</Note>
9> [!NOTE]
10>
11> These cases are covered on other pages:
12>
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)
1515 
1616Start at the section that matches what you're looking up:
1717 

plugins/marketplace-reference Changed · +8 / -10 lines

### How an entry combines with plugin.json

from line 8
88 
99This reference is for marketplace maintainers who need an exact field name or value, and for administrators who need to know which `source` values are valid in [`extraKnownMarketplaces`](/docs/en/settings-reference#extraknownmarketplaces), [`strictKnownMarketplaces`](/docs/en/settings-reference#strictknownmarketplaces), and [`blockedMarketplaces`](/docs/en/plugins/org#restrict-what-users-can-install).
1010 
11<Note>
12 These cases are covered on other pages:
11> [!NOTE]
12>
13> These cases are covered on other pages:
14>
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)
1317 
14 * **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)
15 * **Allowlist and blocklist recipes**: see [Manage plugins for your organization](/docs/en/plugins/org)
16</Note>
17 
1818Find the section for what you're writing or reading:
1919 
2020* **The marketplace file**: [Top-level fields](#top-level-fields) and [Plugin entries](#plugin-entries)
from line 40
4040* **Community marketplace names**: `claude-community`, `claude-plugins-community`, and `healthcare`. Reserved under the same rule as the official names.
4141* **Plugin directory names**: `anthropic-plugin-directory` and `claude-plugin-directory`. Reserved under the same rule as the official names.
4242* **Names that impersonate an official marketplace**: names such as `official-claude-plugins` or `claude-plugins-v2`, and any name containing a non-ASCII character. The error is `Marketplace name impersonates an official Anthropic/Claude marketplace`. A control or bidirectional-formatting character in a name also reports `Marketplace name cannot contain control or bidirectional-formatting characters`. A marketplace already registered under such a name stops loading, along with its plugins.
43* <span id="reserved-name-spellings" />**Another spelling of a reserved name**: a name that differs from a reserved name only by a trailing dot, or by a symbol other than an underscore in place of a hyphen, so `claude.code.plugins` counts as `claude-code-plugins`. Adding the marketplace fails with [`is another spelling of "<reserved>", a reserved marketplace name`](/docs/en/errors#marketplace-name-is-another-spelling-of-a-reserved-name), and a marketplace already registered under one stops loading. This check requires Claude Code v2.1.280 or later.
43* **Another spelling of a reserved name**: a name that differs from a reserved name only by a trailing dot, or by a symbol other than an underscore in place of a hyphen, so `claude.code.plugins` counts as `claude-code-plugins`. Adding the marketplace fails with [`is another spelling of "<reserved>", a reserved marketplace name`](/docs/en/errors#marketplace-name-is-another-spelling-of-a-reserved-name), and a marketplace already registered under one stops loading. This check requires Claude Code v2.1.280 or later.
4444* **Names Claude Code uses for plugins that don't come from a marketplace**: `inline` for plugins loaded with [`--plugin-dir`](/docs/en/cli-reference), `builtin` for built-in plugins, `skills-dir` for plugins auto-loaded from [`.claude/skills/`](/docs/en/skills), and `synced` for plugins synced from your claude.ai account. `claude-plugin-test` is also reserved. `skills-dir` also appears as `{"source": "skills-dir"}` in `strictKnownMarketplaces` and `blockedMarketplaces`, described under [Source values valid only in policy lists](#source-values-valid-only-in-policy-lists).
4545* **`npm`, `pip`, `uv`, `cargo`, `github`, and `gh`**: reserved in any casing. This check requires Claude Code v2.1.275 or later.
4646* **Member names that every JavaScript object has**: `constructor`, `hasOwnProperty`, `isPrototypeOf`, `propertyIsEnumerable`, `toLocaleString`, `toString`, and `valueOf`. `claude plugin marketplace add` refuses a marketplace that uses one with [`Claude Code reserves this name and cannot register a marketplace under it`](/docs/en/plugins/troubleshooting#claude-code-reserves-this-name). This check requires Claude Code v2.1.296 or later.
from line 94
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 |
9595| `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) |
9696 
97<h3 id="entry-and-plugin-json">
98 How an entry combines with plugin.json
99</h3>
97### How an entry combines with plugin.json
10098 
10199The entry's fields apply differently to a fetched plugin that has its own `.claude-plugin/plugin.json` and to one that doesn't:
102100 

plugins/measure Changed · +7 / -9 lines

### OpenTelemetry events for plugin installs and use

from line 6
66 
77This page is for plugin authors and maintainers. If you administer Claude Code for an organization, [Measure across a fleet](#measure-across-a-fleet) covers the same questions across every machine.
88 
9<Note>
10 These cases are covered on other pages:
9> [!NOTE]
10>
11> These cases are covered on other pages:
12>
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
1115 
12 * **Testing how reliably the plugin changes Claude's behavior**: see [Test plugins with evals](/docs/en/plugin-evals)
13 * **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
14</Note>
15 
1616Start with [Measure what a plugin costs](#measure-what-a-plugin-costs).
1717 
1818## Measure what a plugin costs
from line 121
121121* **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).
122122* **Analytics API**: served from Anthropic's records, with no exporter needed. See [Query the Analytics API](#query-the-analytics-api).
123123 
124<h3 id="pick-the-opentelemetry-event-for-each-question">
125 OpenTelemetry events for plugin installs and use
126</h3>
124### OpenTelemetry events for plugin installs and use
127125 
128126These OpenTelemetry events and attributes answer each plugin question from your backend:
129127 

plugins/mods/admin Changed · +7 / -9 lines

### Install your organization's mods and set the order

from line 10
1010* **See what your users get when you change nothing**: [Know what happens by default](#know-what-happens-by-default)
1111* **Leave mods on with other limits**: [Choose how much to allow](#choose-how-much-to-allow)
1212 
13<Note>
14 These cases are covered on other pages:
13> [!NOTE]
14>
15> These cases are covered on other pages:
16>
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)
1519 
16 * **You haven't deployed managed settings before**: start with [Deploy managed settings](/docs/en/managed-settings)
17 * **You want to control which plugins users can install**: see [Manage plugins for your organization](/docs/en/plugins/org)
18</Note>
19 
2020## Stop user-installed mods from loading
2121 
2222To keep every mod your users bring from running its hooks, set the `allowManagedModsOnly` option on the [built-in guard](#know-what-happens-by-default), a policy mod that Claude Code loads ahead of every mod a user installs. The option goes in managed settings under `pluginConfigs`, keyed by `cc-plugin-sec-default@builtin`:
from line 234
234234 
235235You can deploy mods of your own to every user, choose where they run relative to users' mods, and use one to enforce a policy.
236236 
237<h3 id="install-your-organizations-mods">
238 Install your organization's mods and set the order
239</h3>
237### Install your organization's mods and set the order
240238 
241239Your 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:
242240 

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

from line 61
6161 
6262When you ask about a ticket, Claude can call `mcp__my-mod__ticket` with its id. The second hook fetches the ticket and returns the response body, which Claude reads as the tool's result. When the server answers with an error status, Claude reads `Lookup failed with status` and the number.
6363 
64<Tip>
65 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</Tip>
64> [!TIP]
65>
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.
6767 
6868## Call a model
6969 
from line 118
118118 
119119To set a breakpoint, pass `prompt` as an array of `{ text }` blocks instead of a string, and add `cache: true` to the last block of the static content. Claude Code sends that block with the API's `cache_control` field. `system` takes the same array form. To decide between them, see [Choose between `prompt` and `system`](#choose-between-prompt-and-system).
120120 
121<Note>
122 Arrays of blocks require Claude Code v2.1.292 or later. Earlier versions reject an array in `prompt` with an error that ends with `takes { model, prompt } (host check)`, and they leave an array in `system` out of the request.
123</Note>
121> [!NOTE]
122>
123> Arrays of blocks require Claude Code v2.1.292 or later. Earlier versions reject an array in `prompt` with an error that ends with `takes { model, prompt } (host check)`, and they leave an array in `system` out of the request.
124124 
125125This version of the [`/triage` hook](#send-one-prompt) sends a long set of labeling rules before the text to label, with a breakpoint after the rules. `RULES` is a string of your own:
126126 
from line 233
233233* **`the session was stopped and nobody has sent input since`**: the call was refused
234234* **`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
235235 
236In this example, call `submitPrompt` from your background job in place of [`$.prompt.submit`](#start-a-turn-from-a-background-job). 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:
236In 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:
237237 
238238```javascript theme={null}
239239// The text of the last refused or dropped prompt, or null

plugins/mods/create Changed · +164 / -178 lines

### Sessions where a mod Claude writes can't load ### Get type definitions for your version

from line 9
99 
1010If 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.
1111 
12<Note>
13 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</Note>
12> [!NOTE]
13>
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).
1515 
1616## Ask Claude for a mod
1717 
from line 19
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 
22<Steps>
23 <Step title="Describe the mod">
24 Ask for the mod in your own words, for example `make a mod that shows the current git branch above the prompt`. Claude writes the mod in a directory of its own in the session's mods folder, which is `~/.claude/dev-mods/` followed by the session's ID. A mod's full path looks like `~/.claude/dev-mods/3f2a9c1e-5b7d-4e8a-9c21-6d0f4b8a7e13/git-branch/`.
22**1. Describe the mod**
2523 
26 <Note>
27 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 </Note>
29 </Step>
24Ask for the mod in your own words, for example `make a mod that shows the current git branch above the prompt`. Claude writes the mod in a directory of its own in the session's mods folder, which is `~/.claude/dev-mods/` followed by the session's ID. A mod's full path looks like `~/.claude/dev-mods/3f2a9c1e-5b7d-4e8a-9c21-6d0f4b8a7e13/git-branch/`.
3025 
31 <Step title="Approve the mod">
32 When Claude saves the first file, Claude Code asks whether to enable hot reloading for the session. Hot reloading runs the mods Claude writes in this session and picks up each later change.
26> [!NOTE]
27>
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.
3329 
34 Choose one of these answers:
30**2. Approve the mod**
3531 
36 * **Enable for this session**: the mods in the session's mods folder load when the turn ends, and reload at the end of each turn that changes them. Your answer lasts for the session, including after you resume it.
37 * **Not now**: nothing loads for now. The files stay where Claude wrote them, and the mods load the next time that session starts. To keep a mod from ever loading, delete its directory.
38 </Step>
32When Claude saves the first file, Claude Code asks whether to enable hot reloading for the session. Hot reloading runs the mods Claude writes in this session and picks up each later change.
3933 
40 <Step title="Check that the mod loaded">
41 Run `/plugin` at the Claude Code prompt and press Tab until the **Installed** tab is selected. It lists the mod, and you can turn it off there.
42 </Step>
34Choose one of these answers:
4335 
44 <Step title="Try the mod">
45 Use what you asked for. For the example prompt, the current branch name appears above the prompt box. If the mod doesn't do what you wanted, tell Claude what to change. The mod reloads at the end of each turn that changes its files, so you can try the change as soon as Claude finishes.
46 </Step>
47</Steps>
36* **Enable for this session**: the mods in the session's mods folder load when the turn ends, and reload at the end of each turn that changes them. Your answer lasts for the session, including after you resume it.
37* **Not now**: nothing loads for now. The files stay where Claude wrote them, and the mods load the next time that session starts. To keep a mod from ever loading, delete its directory.
4838 
39**3. Check that the mod loaded**
40 
41Run `/plugin` at the Claude Code prompt and press Tab until the **Installed** tab is selected. It lists the mod, and you can turn it off there.
42 
43**4. Try the mod**
44 
45Use what you asked for. For the example prompt, the current branch name appears above the prompt box. If the mod doesn't do what you wanted, tell Claude what to change. The mod reloads at the end of each turn that changes its files, so you can try the change as soon as Claude finishes.
46 
4947### Use the mod in other sessions
5048 
5149A mod Claude wrote loads only in the session that made it, and Claude Code deletes that session's mods folder once it's older than [`cleanupPeriodDays`](/docs/en/settings-reference#cleanupperioddays). To keep the mod, copy its directory out of the mods folder to a place of your own, such as `~/mods/git-branch`. Then choose how to load it:
from line 51
5351* **In a session you start**: in your shell, run `claude --plugin-dir ~/mods/git-branch`
5452* **For other people**: [add it to a marketplace](#share-your-mod) so they can install it
5553 
56<h3 id="sessions-that-skip-the-approval">
57 Sessions where a mod Claude writes can't load
58</h3>
54### Sessions where a mod Claude writes can't load
5955 
6056A mod Claude writes loads only after you approve it, in a trusted workspace where mods are allowed to run. In these sessions it doesn't load:
6157 
from line 65
6965 
7066This recording shows the finished mod. The spinner counts tool calls, `/tally` prints the count, and an edit to the code takes effect while the session runs:
7167 
72<Frame>
73 <video autoPlay muted loop playsInline controls className="w-full dark:hidden" src="https://mintcdn.com/claude-code/dgiVO_Od1X1faduV/images/mods-first-mod-light.mp4?fit=max&auto=format&n=dgiVO_Od1X1faduV&q=85&s=eb561134afa90375777408453ba51c77" aria-label="In a Claude Code session, the prompt 'list the files here and read the README' is typed and sent. The spinner reads 'Thinking · tool calls: 1' and the count rises as Claude works. The /tally command prints 'first-mod: Claude has made 3 tool calls since this mod loaded'. A line says first-mod reloaded and lists its four hooks. On the next prompt the spinner reads 'Thinking · tools used: 1'." data-path="images/mods-first-mod-light.mp4" />
68<video autoPlay muted loop playsInline controls src="https://mintcdn.com/claude-code/dgiVO_Od1X1faduV/images/mods-first-mod-light.mp4?fit=max&auto=format&n=dgiVO_Od1X1faduV&q=85&s=eb561134afa90375777408453ba51c77" aria-label="In a Claude Code session, the prompt 'list the files here and read the README' is typed and sent. The spinner reads 'Thinking · tool calls: 1' and the count rises as Claude works. The /tally command prints 'first-mod: Claude has made 3 tool calls since this mod loaded'. A line says first-mod reloaded and lists its four hooks. On the next prompt the spinner reads 'Thinking · tools used: 1'." />
7469 
75 <video autoPlay muted loop playsInline controls className="w-full hidden dark:block" src="https://mintcdn.com/claude-code/dgiVO_Od1X1faduV/images/mods-first-mod-dark.mp4?fit=max&auto=format&n=dgiVO_Od1X1faduV&q=85&s=09779dadc7ef66c2b1e2da0c2e31ac72" aria-label="In a Claude Code session, the prompt 'list the files here and read the README' is typed and sent. The spinner reads 'Thinking · tool calls: 1' and the count rises as Claude works. The /tally command prints 'first-mod: Claude has made 3 tool calls since this mod loaded'. A line says first-mod reloaded and lists its four hooks. On the next prompt the spinner reads 'Thinking · tools used: 1'." data-path="images/mods-first-mod-dark.mp4" />
76</Frame>
77 
7870You write three files:
7971 
8072```text theme={null}
from line 82
9082* **`hooks.json`**: [points to your code file](/docs/en/plugins/mods/reference#files)
9183* **`register.js`**: your code, called the hooks module
9284 
93<Steps>
94 <Step title="Create the plugin directory">
95 Create the two directories that hold the files:
85**1. Create the plugin directory**
9686 
97 <Tabs>
98 <Tab title="Bash or Zsh">
99 ```bash theme={null}
100 mkdir -p first-mod/.claude-plugin first-mod/hooks
101 ```
102 </Tab>
87Create the two directories that hold the files:
10388 
104 <Tab title="PowerShell">
105 ```powershell theme={null}
106 New-Item -ItemType Directory -Force first-mod\.claude-plugin, first-mod\hooks
107 ```
108 </Tab>
109 </Tabs>
110 </Step>
89**Bash or Zsh**
11190 
112 <Step title="Write the manifest">
113 A 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`:
91```bash theme={null}
92mkdir -p first-mod/.claude-plugin first-mod/hooks
93```
11494 
115 ```json first-mod/.claude-plugin/plugin.json theme={null}
116 {
117 "name": "first-mod",
118 "version": "0.1.0",
119 "description": "Counts Claude's tool calls, shows the count beside the spinner, and adds a /tally command",
120 "author": { "name": "Your Name" }
121 }
122 ```
123 </Step>
95**PowerShell**
12496 
125 <Step title="Tell Claude Code where your code is">
126 When Claude Code loads a plugin, it reads the plugin's `hooks/hooks.json`. The `modules` key in that file gives the path to your code, and having it is what makes the plugin a mod. List one path, relative to `hooks.json`. Here it points to `register.js`, which you write in the next step.
97```powershell theme={null}
98New-Item -ItemType Directory -Force first-mod\.claude-plugin, first-mod\hooks
99```
127100 
128 Save this as `first-mod/hooks/hooks.json`:
101**2. Write the manifest**
129102 
130 ```json first-mod/hooks/hooks.json theme={null}
131 {
132 "description": "The first-mod hooks module",
133 "modules": ["./register.js"]
134 }
135 ```
136 </Step>
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`:
137104 
138 <Step title="Write the code">
139 This file is the mod's code, called the hooks module. When the mod loads, Claude Code calls the `register` function the file exports and passes it a function named [`on`](/docs/en/plugins/mods/reference#the-hook-function). Each call to `on` registers an event handler, called a hook, for the event it names.
105```json first-mod/.claude-plugin/plugin.json theme={null}
106{
107 "name": "first-mod",
108 "version": "0.1.0",
109 "description": "Counts Claude's tool calls, shows the count beside the spinner, and adds a /tally command",
110 "author": { "name": "Your Name" }
111}
112```
140113 
141 Save this as `first-mod/hooks/register.js`:
114**3. Tell Claude Code where your code is**
142115 
143 ```javascript first-mod/hooks/register.js theme={null}
144 // The count, shared by the hooks below
145 let calls = 0
116When Claude Code loads a plugin, it reads the plugin's `hooks/hooks.json`. The `modules` key in that file gives the path to your code, and having it is what makes the plugin a mod. List one path, relative to `hooks.json`. Here it points to `register.js`, which you write in the next step.
146117 
147 // Claude Code calls this once when the mod loads
148 export function register(on) {
149 // Runs when the session starts, before your first prompt
150 on('session.start', async ($, e, next) => {
151 // Add the /tally command
152 await $.command.register({
153 name: 'tally',
154 description: 'Show how many tool calls Claude has made',
155 })
156 // Let the session start as usual
157 return next(e)
158 })
118Save this as `first-mod/hooks/hooks.json`:
159119 
160 // Runs each time Claude is about to use a tool
161 on('tool.call', async ($, e, next) => {
162 calls += 1
163 // Ask Claude Code to draw the interface again, so the new count shows
164 $.ui.invalidate('ui.render')
165 // Let the tool run as usual
166 return next(e)
167 })
120```json first-mod/hooks/hooks.json theme={null}
121{
122 "description": "The first-mod hooks module",
123 "modules": ["./register.js"]
124}
125```
168126 
169 // Runs when you type /tally, and only then, because of the matcher
170 on('command.run', { command: 'tally' }, async () => {
171 // The text to print in the transcript
172 return { text: 'Claude has made ' + calls + ' tool calls since this mod loaded' }
173 })
127**4. Write the code**
174128 
175 // Runs each time Claude Code draws the spinner
176 on('ui.render', { component: 'Spinner' }, async ($, e, next) => {
177 // Keep Claude Code's spinner, with the count added after its word
178 return next({ ...e, props: { ...e.props, suffix: ' · tool calls: ' + calls + '…' } })
179 })
180 }
181 ```
129This file is the mod's code, called the hooks module. When the mod loads, Claude Code calls the `register` function the file exports and passes it a function named [`on`](/docs/en/plugins/mods/reference#the-hook-function). Each call to `on` registers an event handler, called a hook, for the event it names.
182130 
183 The file keeps a count in `calls` and registers four hooks:
131Save this as `first-mod/hooks/register.js`:
184132 
185 * **[`session.start`](/docs/en/plugins/mods/reference#session)** runs when the session starts, before your first prompt, and again each time the mod reloads. It adds the `/tally` command to Claude Code.
186 * **[`tool.call`](/docs/en/plugins/mods/reference#tools)** runs each time Claude is about to use a tool. It adds one to `calls` and asks Claude Code to draw the interface again.
187 * **[`command.run`](/docs/en/plugins/mods/reference#commands-and-configuration)** runs when you type `/tally`. It returns the text to print.
188 * **[`ui.render`](/docs/en/plugins/mods/reference#interface)** runs each time Claude Code draws the spinner. It adds the count after the spinner's word.
133```javascript first-mod/hooks/register.js theme={null}
134// The count, shared by the hooks below
135let calls = 0
189136 
190 [How the example mod works](#how-the-example-mod-works) explains the three arguments each hook takes and what each one returns.
191 </Step>
137// Claude Code calls this once when the mod loads
138export function register(on) {
139 // Runs when the session starts, before your first prompt
140 on('session.start', async ($, e, next) => {
141 // Add the /tally command
142 await $.command.register({
143 name: 'tally',
144 description: 'Show how many tool calls Claude has made',
145 })
146 // Let the session start as usual
147 return next(e)
148 })
192149 
193 <Step title="Load the mod">
194 Start Claude Code with the `--plugin-dir` flag, which loads a plugin directory for one session without installing it:
150 // Runs each time Claude is about to use a tool
151 on('tool.call', async ($, e, next) => {
152 calls += 1
153 // Ask Claude Code to draw the interface again, so the new count shows
154 $.ui.invalidate('ui.render')
155 // Let the tool run as usual
156 return next(e)
157 })
195158 
196 ```bash theme={null}
197 claude --plugin-dir ./first-mod
198 ```
199 </Step>
159 // Runs when you type /tally, and only then, because of the matcher
160 on('command.run', { command: 'tally' }, async () => {
161 // The text to print in the transcript
162 return { text: 'Claude has made ' + calls + ' tool calls since this mod loaded' }
163 })
200164 
201 <Step title="Try the mod">
202 Ask Claude to do something that takes a few tool calls, such as `list the files here and read the README`. While Claude works, the spinner's word is followed by a count that rises, as in `Thinking · tool calls: 2…`. When Claude finishes, type `/tally` and press Enter. The transcript shows `first-mod: Claude has made 2 tool calls since this mod loaded`, with your own count. Claude Code puts the plugin's name in front of the command's text.
165 // Runs each time Claude Code draws the spinner
166 on('ui.render', { component: 'Spinner' }, async ($, e, next) => {
167 // Keep Claude Code's spinner, with the count added after its word
168 return next({ ...e, props: { ...e.props, suffix: ' · tool calls: ' + calls + '…' } })
169 })
170}
171```
203172 
204 To check the command without an interactive session, run it in non-interactive mode:
173The file keeps a count in `calls` and registers four hooks:
205174 
206 ```bash theme={null}
207 claude -p "/tally" --plugin-dir ./first-mod
208 ```
175* **[`session.start`](/docs/en/plugins/mods/reference#session)** runs when the session starts, before your first prompt, and again each time the mod reloads. It adds the `/tally` command to Claude Code.
176* **[`tool.call`](/docs/en/plugins/mods/reference#tools)** runs each time Claude is about to use a tool. It adds one to `calls` and asks Claude Code to draw the interface again.
177* **[`command.run`](/docs/en/plugins/mods/reference#commands-and-configuration)** runs when you type `/tally`. It returns the text to print.
178* **[`ui.render`](/docs/en/plugins/mods/reference#interface)** runs each time Claude Code draws the spinner. It adds the count after the spinner's word.
209179 
210 ```text theme={null}
211 first-mod: Claude has made 0 tool calls since this mod loaded
212 ```
180[How the example mod works](#how-the-example-mod-works) explains the three arguments each hook takes and what each one returns.
213181 
214 If `/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).
215 </Step>
182**5. Load the mod**
216183 
217 <Step title="Change the code while the session runs">
218 Leave the session open. In `register.js`, change `' · tool calls: '` to `' · tools used: '` in the `ui.render` hook and save. The highlighted line is the one that changes:
184Start Claude Code with the `--plugin-dir` flag, which loads a plugin directory for one session without installing it:
219185 
220 ```javascript first-mod/hooks/register.js {4} theme={null}
221 // Runs each time Claude Code draws the spinner
222 on('ui.render', { component: 'Spinner' }, async ($, e, next) => {
223 // Keep Claude Code's spinner, with the count added after its word
224 return next({ ...e, props: { ...e.props, suffix: ' · tools used: ' + calls + '…' } })
225 })
226 ```
186```bash theme={null}
187claude --plugin-dir ./first-mod
188```
227189 
228 A line in the transcript says `first-mod` reloaded and lists its hooks, and the next spinner uses the new text, as in `Thinking · tools used: 1…`.
229 </Step>
230</Steps>
190**6. Try the mod**
231191 
192Ask Claude to do something that takes a few tool calls, such as `list the files here and read the README`. While Claude works, the spinner's word is followed by a count that rises, as in `Thinking · tool calls: 2…`. When Claude finishes, type `/tally` and press Enter. The transcript shows `first-mod: Claude has made 2 tool calls since this mod loaded`, with your own count. Claude Code puts the plugin's name in front of the command's text.
193 
194To check the command without an interactive session, run it in non-interactive mode:
195 
196```bash theme={null}
197claude -p "/tally" --plugin-dir ./first-mod
198```
199 
200```text theme={null}
201first-mod: Claude has made 0 tool calls since this mod loaded
202```
203 
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).
205 
206**7. Change the code while the session runs**
207 
208Leave the session open. In `register.js`, change `' · tool calls: '` to `' · tools used: '` in the `ui.render` hook and save. The highlighted line is the one that changes:
209 
210```javascript first-mod/hooks/register.js {4} theme={null}
211 // Runs each time Claude Code draws the spinner
212 on('ui.render', { component: 'Spinner' }, async ($, e, next) => {
213 // Keep Claude Code's spinner, with the count added after its word
214 return next({ ...e, props: { ...e.props, suffix: ' · tools used: ' + calls + '…' } })
215 })
216```
217 
218A line in the transcript says `first-mod` reloaded and lists its hooks, and the next spinner uses the new text, as in `Thinking · tools used: 1…`.
219 
232220### How the example mod works
233221 
234222Each function you pass to `on` is a hook, which is an event handler. Claude Code passes every hook the same three arguments:
from line 249
261249 
262250Files Claude saves during its turn reload when the turn ends, so you can try `/tally-reset` as soon as Claude finishes.
263251 
264<h3 id="get-the-types-for-your-build">
265 Get type definitions for your version
266</h3>
252### Get type definitions for your version
267253 
268254When Claude Code loads a mod from `--plugin-dir` in an interactive session, or a mod [Claude wrote for you](#ask-claude-for-a-mod), it writes TypeScript declaration files into the mod's `.claude-plugin/types/` directory. They describe the exact events, mods API methods, and elements in the Claude Code version you're running, so your editor can autocomplete and type-check your hooks. The directory holds these files:
269255 

plugins/mods/events Changed · +4 / -6 lines

### Handle the settings hook events

from line 201
201201 
202202The hook matches the text of the command, so treat it as a reminder for Claude. To block pushes to `main` for everyone, protect the branch on your Git host.
203203 
204<Note>
205 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).
206</Note>
204> [!NOTE]
205>
206> 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).
207207 
208208### Rewrite or add to a prompt
209209 
from line 267
267267 
268268To 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.
269269 
270<h3 id="hook-the-settings-hook-events">
271 Handle the settings hook events
272</h3>
270### Handle the settings hook events
273271 
274272Settings 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`.
275273 

plugins/mods/gallery Changed · +86 / -118 lines

from line 12
1212 
1313To 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.
1414 
15<Steps>
16 <Step title="Create the mod">
17 Create 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.
15**1. Create the mod**
1816 
19 Save the manifest as `gallery/.claude-plugin/plugin.json`:
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.
2018 
21 ```json gallery/.claude-plugin/plugin.json theme={null}
22 {
23 "name": "gallery",
24 "version": "0.1.0",
25 "description": "Opens a pane that draws one sample",
26 "author": { "name": "Your Name" }
27 }
28 ```
19Save the manifest as `gallery/.claude-plugin/plugin.json`:
2920 
30 Name your entry point in `gallery/hooks/hooks.json`:
21```json gallery/.claude-plugin/plugin.json theme={null}
22{
23 "name": "gallery",
24 "version": "0.1.0",
25 "description": "Opens a pane that draws one sample",
26 "author": { "name": "Your Name" }
27}
28```
3129 
32 ```json gallery/hooks/hooks.json theme={null}
33 {
34 "modules": ["./register.js"]
35 }
36 ```
30Name your entry point in `gallery/hooks/hooks.json`:
3731 
38 Save the code as `gallery/hooks/register.js`. It adds a `/gallery` command that opens a pane, and draws `Plain text` in that pane:
32```json gallery/hooks/hooks.json theme={null}
33{
34 "modules": ["./register.js"]
35}
36```
3937 
40 ```javascript gallery/hooks/register.js theme={null}
41 // Stands in for your own callback in the samples that take one
42 const noop = () => {}
43 // The Select sample keeps its choice here
44 let picked = 'md'
38Save the code as `gallery/hooks/register.js`. It adds a `/gallery` command that opens a pane, and draws `Plain text` in that pane:
4539 
46 // The Raster sample packs its cells with this function
47 const DEFAULT_COLOR = 0x01000000
48 function cellsOf(rows) {
49 const numbers = rows.flat().flatMap(([char, color]) => [char.codePointAt(0), color, DEFAULT_COLOR])
50 return new Uint8Array(Uint32Array.from(numbers).buffer).toBase64()
51 }
40```javascript gallery/hooks/register.js theme={null}
41// Stands in for your own callback in the samples that take one
42const noop = () => {}
43// The Select sample keeps its choice here
44let picked = 'md'
5245 
53 export function register(on) {
54 on('session.start', async ($, e, next) => {
55 await $.command.register({ name: 'gallery', description: 'Open the sample pane' })
56 return next(e)
57 })
46// The Raster sample packs its cells with this function
47const DEFAULT_COLOR = 0x01000000
48function cellsOf(rows) {
49 const numbers = rows.flat().flatMap(([char, color]) => [char.codePointAt(0), color, DEFAULT_COLOR])
50 return new Uint8Array(Uint32Array.from(numbers).buffer).toBase64()
51}
5852 
59 on('command.run', { command: 'gallery' }, async ($) => {
60 await $.ui.open({ id: 'gallery', focus: true, closeOnEscape: true })
61 return {}
62 })
53export function register(on) {
54 on('session.start', async ($, e, next) => {
55 await $.command.register({ name: 'gallery', description: 'Open the sample pane' })
56 return next(e)
57 })
6358 
64 on('ui.render', { component: 'Pane' }, async ($, e, next) => {
65 if (e.requestId !== 'gallery') return next(e)
66 const { Box, Text, Button, Input, Select, Link, Markdown, Code, Raster, Svg } = $.ui.resolve(e)
67 // Replace the element after return with a sample
68 return Text({ children: ['Plain text'] })
69 })
70 }
71 ```
72 </Step>
59 on('command.run', { command: 'gallery' }, async ($) => {
60 await $.ui.open({ id: 'gallery', focus: true, closeOnEscape: true })
61 return {}
62 })
7363 
74 <Step title="Run the mod">
75 In your shell, start Claude Code from the directory that holds `gallery`:
64 on('ui.render', { component: 'Pane' }, async ($, e, next) => {
65 if (e.requestId !== 'gallery') return next(e)
66 const { Box, Text, Button, Input, Select, Link, Markdown, Code, Raster, Svg } = $.ui.resolve(e)
67 // Replace the element after return with a sample
68 return Text({ children: ['Plain text'] })
69 })
70}
71```
7672 
77 ```bash theme={null}
78 claude --plugin-dir ./gallery
79 ```
73**2. Run the mod**
8074 
81 At the Claude Code prompt, run `/gallery`. A pane opens with `Plain text` in it.
82 </Step>
75In your shell, start Claude Code from the directory that holds `gallery`:
8376 
84 <Step title="Swap in a sample">
85 Copy a sample from this page. In `register.js`, paste it over `Text({ children: ['Plain text'] })`, so that it follows `return`, and save the file. Claude Code reloads the module each time you save, so run `/gallery` again to see the new sample.
86 </Step>
87</Steps>
77```bash theme={null}
78claude --plugin-dir ./gallery
79```
8880 
81At the Claude Code prompt, run `/gallery`. A pane opens with `Plain text` in it.
82 
83**3. Swap in a sample**
84 
85Copy a sample from this page. In `register.js`, paste it over `Text({ children: ['Plain text'] })`, so that it follows `return`, and save the file. Claude Code reloads the module each time you save, so run `/gallery` again to see the new sample.
86 
8987## Pick an element
9088 
9189The samples are grouped by what you want to put on screen:
from line 119
121119})
122120```
123121 
124<img src="https://mintcdn.com/claude-code/EXkwf0kKMewZsyod/images/mods-el-text-light.png?fit=max&auto=format&n=EXkwf0kKMewZsyod&q=85&s=90724ce3953d9347b61b6a9266fda451" className="dark:hidden" alt="A pane with nine lines of text, each named for its style: plain, bold, italic, underline, strikethrough, dimColor in gray, inverse, color red, and backgroundColor blue." width="1872" height="490" data-path="images/mods-el-text-light.png" />
122![A pane with nine lines of text, each named for its style: plain, bold, italic, underline, strikethrough, dimColor in gray, inverse, color red, and backgroundColor blue.](https://mintcdn.com/claude-code/EXkwf0kKMewZsyod/images/mods-el-text-light.png?fit=max\&auto=format\&n=EXkwf0kKMewZsyod\&q=85\&s=90724ce3953d9347b61b6a9266fda451)
125123 
126<img src="https://mintcdn.com/claude-code/EXkwf0kKMewZsyod/images/mods-el-text-dark.png?fit=max&auto=format&n=EXkwf0kKMewZsyod&q=85&s=790dd3465e06db0842639d0d8fcbbc96" className="hidden dark:block" alt="A pane with nine lines of text, each named for its style: plain, bold, italic, underline, strikethrough, dimColor in gray, inverse, color red, and backgroundColor blue." width="1872" height="490" data-path="images/mods-el-text-dark.png" />
127 
128124`dimColor` draws the text in gray. `backgroundColor` fills only as wide as the text.
129125 
130126### `Markdown`
from line 133
137133})
138134```
139135 
140<img src="https://mintcdn.com/claude-code/EXkwf0kKMewZsyod/images/mods-el-markdown-light.png?fit=max&auto=format&n=EXkwf0kKMewZsyod&q=85&s=e40eacc4e3fbe06eb003f4463f552ec1" className="dark:hidden" alt="A pane with a bold heading, Release notes, then a sentence with one bold word and one colored code word, a two-item list, and a quote drawn in italics with a bar on its left." width="1872" height="452" data-path="images/mods-el-markdown-light.png" />
136![A pane with a bold heading, Release notes, then a sentence with one bold word and one colored code word, a two-item list, and a quote drawn in italics with a bar on its left.](https://mintcdn.com/claude-code/EXkwf0kKMewZsyod/images/mods-el-markdown-light.png?fit=max\&auto=format\&n=EXkwf0kKMewZsyod\&q=85\&s=e40eacc4e3fbe06eb003f4463f552ec1)
141137 
142<img src="https://mintcdn.com/claude-code/EXkwf0kKMewZsyod/images/mods-el-markdown-dark.png?fit=max&auto=format&n=EXkwf0kKMewZsyod&q=85&s=2cc342ed0c58e752c425fff3c95a33a6" className="hidden dark:block" alt="A pane with a bold heading, Release notes, then a sentence with one bold word and one colored code word, a two-item list, and a quote drawn in italics with a bar on its left." width="1872" height="452" data-path="images/mods-el-markdown-dark.png" />
143 
144138A heading draws in bold without its `#` marks. Inline code draws in color without its backticks. A quote draws in italics with a bar on its left.
145139 
146140### `Link`
from line 145
151145Link({ href: 'https://code.claude.com/docs', label: 'Claude Code docs' })
152146```
153147 
154<img src="https://mintcdn.com/claude-code/EXkwf0kKMewZsyod/images/mods-el-link-light.png?fit=max&auto=format&n=EXkwf0kKMewZsyod&q=85&s=8217bd2dfb561a8ba57023c6d89ea977" className="dark:hidden" alt="A pane with one line: the label Claude Code docs, then the URL in gray." width="1872" height="186" data-path="images/mods-el-link-light.png" />
148![A pane with one line: the label Claude Code docs, then the URL in gray.](https://mintcdn.com/claude-code/EXkwf0kKMewZsyod/images/mods-el-link-light.png?fit=max\&auto=format\&n=EXkwf0kKMewZsyod\&q=85\&s=8217bd2dfb561a8ba57023c6d89ea977)
155149 
156<img src="https://mintcdn.com/claude-code/EXkwf0kKMewZsyod/images/mods-el-link-dark.png?fit=max&auto=format&n=EXkwf0kKMewZsyod&q=85&s=cd32f222a7d3530b070f58f5f189a1f8" className="hidden dark:block" alt="A pane with one line: the label Claude Code docs, then the URL in gray." width="1872" height="186" data-path="images/mods-el-link-dark.png" />
157 
158150The terminal draws the URL as text after the label. Whether a click opens it depends on the user's terminal.
159151 
160152## Show code and changes
from line 165
173165})
174166```
175167 
176<img src="https://mintcdn.com/claude-code/EXkwf0kKMewZsyod/images/mods-el-code-light.png?fit=max&auto=format&n=EXkwf0kKMewZsyod&q=85&s=4e13f5d506d3fdcc59d6d9524f48d2a9" className="dark:hidden" alt="A pane with two numbered lines of JavaScript in syntax colors." width="1872" height="224" data-path="images/mods-el-code-light.png" />
168![A pane with two numbered lines of JavaScript in syntax colors.](https://mintcdn.com/claude-code/EXkwf0kKMewZsyod/images/mods-el-code-light.png?fit=max\&auto=format\&n=EXkwf0kKMewZsyod\&q=85\&s=4e13f5d506d3fdcc59d6d9524f48d2a9)
177169 
178<img src="https://mintcdn.com/claude-code/EXkwf0kKMewZsyod/images/mods-el-code-dark.png?fit=max&auto=format&n=EXkwf0kKMewZsyod&q=85&s=59f797371dd91b16b874a382b784b668" className="hidden dark:block" alt="A pane with two numbered lines of JavaScript in syntax colors." width="1872" height="224" data-path="images/mods-el-code-dark.png" />
179 
180170The colors come from the user's theme.
181171 
182172### `Code` as a diff
from line 180
190180})
191181```
192182 
193<img src="https://mintcdn.com/claude-code/EXkwf0kKMewZsyod/images/mods-el-diff-light.png?fit=max&auto=format&n=EXkwf0kKMewZsyod&q=85&s=4f12c9f7229ceccd9b4f47479a7235dd" className="dark:hidden" alt="A pane with a four-line diff. The removed line is shaded red and the added line green, each with its line number. In the added line, the words that runs code have a stronger shade." width="1872" height="300" data-path="images/mods-el-diff-light.png" />
183![A pane with a four-line diff. The removed line is shaded red and the added line green, each with its line number. In the added line, the words that runs code have a stronger shade.](https://mintcdn.com/claude-code/EXkwf0kKMewZsyod/images/mods-el-diff-light.png?fit=max\&auto=format\&n=EXkwf0kKMewZsyod\&q=85\&s=4f12c9f7229ceccd9b4f47479a7235dd)
194184 
195<img src="https://mintcdn.com/claude-code/EXkwf0kKMewZsyod/images/mods-el-diff-dark.png?fit=max&auto=format&n=EXkwf0kKMewZsyod&q=85&s=9db96f34381bac8bebc32d41859b8808" className="hidden dark:block" alt="A pane with a four-line diff. The removed line is shaded red and the added line green, each with its line number. In the added line, the words that runs code have a stronger shade." width="1872" height="300" data-path="images/mods-el-diff-dark.png" />
196 
197185Claude Code draws line numbers in place of the `@@` line. Where a removed line and an added line are alike, the words that changed get a stronger shade.
198186 
199187## Arrange elements
from line 209
221209})
222210```
223211 
224<img src="https://mintcdn.com/claude-code/EXkwf0kKMewZsyod/images/mods-el-box-light.png?fit=max&auto=format&n=EXkwf0kKMewZsyod&q=85&s=cb9263bb02f5c8afb6e5b8450e0cdadc" className="dark:hidden" alt="A pane with three words in a row, four columns apart, then a blank row, then a rounded border around one line of text. The border runs the full width of the pane." width="1872" height="338" data-path="images/mods-el-box-light.png" />
212![A pane with three words in a row, four columns apart, then a blank row, then a rounded border around one line of text. The border runs the full width of the pane.](https://mintcdn.com/claude-code/EXkwf0kKMewZsyod/images/mods-el-box-light.png?fit=max\&auto=format\&n=EXkwf0kKMewZsyod\&q=85\&s=cb9263bb02f5c8afb6e5b8450e0cdadc)
225213 
226<img src="https://mintcdn.com/claude-code/EXkwf0kKMewZsyod/images/mods-el-box-dark.png?fit=max&auto=format&n=EXkwf0kKMewZsyod&q=85&s=dae83407af4d667a58717f68f13848e2" className="hidden dark:block" alt="A pane with three words in a row, four columns apart, then a blank row, then a rounded border around one line of text. The border runs the full width of the pane." width="1872" height="338" data-path="images/mods-el-box-dark.png" />
227 
228214The border stretches to the width of the pane.
229215 
230216## Take input
from line 234
248234})
249235```
250236 
251<img src="https://mintcdn.com/claude-code/EXkwf0kKMewZsyod/images/mods-el-button-light.png?fit=max&auto=format&n=EXkwf0kKMewZsyod&q=85&s=8c638c15e12d9736f327dfcaa797b512" className="dark:hidden" alt="A pane with three buttons, one per line: Save in brackets, n: Next without brackets and with the n in color, and Skip in brackets in gray." width="1872" height="262" data-path="images/mods-el-button-light.png" />
237![A pane with three buttons, one per line: Save in brackets, n: Next without brackets and with the n in color, and Skip in brackets in gray.](https://mintcdn.com/claude-code/EXkwf0kKMewZsyod/images/mods-el-button-light.png?fit=max\&auto=format\&n=EXkwf0kKMewZsyod\&q=85\&s=8c638c15e12d9736f327dfcaa797b512)
252238 
253<img src="https://mintcdn.com/claude-code/EXkwf0kKMewZsyod/images/mods-el-button-dark.png?fit=max&auto=format&n=EXkwf0kKMewZsyod&q=85&s=6a88a1fe18ba63b050366dcfab14be45" className="hidden dark:block" alt="A pane with three buttons, one per line: Save in brackets, n: Next without brackets and with the n in color, and Skip in brackets in gray." width="1872" height="262" data-path="images/mods-el-button-dark.png" />
254 
255239A button that has the focus draws in inverse video. Here the user has pressed Tab twice:
256240 
257<img src="https://mintcdn.com/claude-code/EXkwf0kKMewZsyod/images/mods-el-button-plain-focused-light.png?fit=max&auto=format&n=EXkwf0kKMewZsyod&q=85&s=a6224e58d10752a894615047d9824ad9" className="dark:hidden" alt="The same three buttons, with the second one, n: Next, drawn in inverse video." width="1872" height="262" data-path="images/mods-el-button-plain-focused-light.png" />
241![The same three buttons, with the second one, n: Next, drawn in inverse video.](https://mintcdn.com/claude-code/EXkwf0kKMewZsyod/images/mods-el-button-plain-focused-light.png?fit=max\&auto=format\&n=EXkwf0kKMewZsyod\&q=85\&s=a6224e58d10752a894615047d9824ad9)
258242 
259<img src="https://mintcdn.com/claude-code/EXkwf0kKMewZsyod/images/mods-el-button-plain-focused-dark.png?fit=max&auto=format&n=EXkwf0kKMewZsyod&q=85&s=9aeb7145615e77c84e7436180ed69e86" className="hidden dark:block" alt="The same three buttons, with the second one, n: Next, drawn in inverse video." width="1872" height="262" data-path="images/mods-el-button-plain-focused-dark.png" />
260 
261243### `Input`
262244 
263245An `Input` is a one-line text field that runs `onSubmit` when the user presses Enter:
from line 257
275257 
276258Without the focus, the field shows its label and its placeholder:
277259 
278<img src="https://mintcdn.com/claude-code/EXkwf0kKMewZsyod/images/mods-el-input-light.png?fit=max&auto=format&n=EXkwf0kKMewZsyod&q=85&s=7d580be1aaf5507032e1962b9167d725" className="dark:hidden" alt="A pane with one line: the label Title, then the placeholder Type a title and press Enter in gray." width="1872" height="186" data-path="images/mods-el-input-light.png" />
260![A pane with one line: the label Title, then the placeholder Type a title and press Enter in gray.](https://mintcdn.com/claude-code/EXkwf0kKMewZsyod/images/mods-el-input-light.png?fit=max\&auto=format\&n=EXkwf0kKMewZsyod\&q=85\&s=7d580be1aaf5507032e1962b9167d725)
279261 
280<img src="https://mintcdn.com/claude-code/EXkwf0kKMewZsyod/images/mods-el-input-dark.png?fit=max&auto=format&n=EXkwf0kKMewZsyod&q=85&s=9d254a8adc5959ba173717fb45eabd52" className="hidden dark:block" alt="A pane with one line: the label Title, then the placeholder Type a title and press Enter in gray." width="1872" height="186" data-path="images/mods-el-input-dark.png" />
281 
282262With the focus, the label turns bold, a cursor appears, and the `submitLabel` shows after `⏎`:
283263 
284<img src="https://mintcdn.com/claude-code/EXkwf0kKMewZsyod/images/mods-el-input-focused-light.png?fit=max&auto=format&n=EXkwf0kKMewZsyod&q=85&s=dcfcce0174480cc624d06c8521734fe7" className="dark:hidden" alt="The same field with its label in bold, a block cursor on the first letter of the placeholder, and a return sign followed by the word save." width="1872" height="186" data-path="images/mods-el-input-focused-light.png" />
264![The same field with its label in bold, a block cursor on the first letter of the placeholder, and a return sign followed by the word save.](https://mintcdn.com/claude-code/EXkwf0kKMewZsyod/images/mods-el-input-focused-light.png?fit=max\&auto=format\&n=EXkwf0kKMewZsyod\&q=85\&s=dcfcce0174480cc624d06c8521734fe7)
285265 
286<img src="https://mintcdn.com/claude-code/EXkwf0kKMewZsyod/images/mods-el-input-focused-dark.png?fit=max&auto=format&n=EXkwf0kKMewZsyod&q=85&s=2f5cf7d0e5f813983070e883009f528e" className="hidden dark:block" alt="The same field with its label in bold, a block cursor on the first letter of the placeholder, and a return sign followed by the word save." width="1872" height="186" data-path="images/mods-el-input-focused-dark.png" />
287 
288266Typing replaces the placeholder:
289267 
290<img src="https://mintcdn.com/claude-code/EXkwf0kKMewZsyod/images/mods-el-input-typed-light.png?fit=max&auto=format&n=EXkwf0kKMewZsyod&q=85&s=4eb6d4443763a21415dad4e426bc747a" className="dark:hidden" alt="The same field holding the typed letters Rel, followed by the return sign and the word save." width="1872" height="186" data-path="images/mods-el-input-typed-light.png" />
268![The same field holding the typed letters Rel, followed by the return sign and the word save.](https://mintcdn.com/claude-code/EXkwf0kKMewZsyod/images/mods-el-input-typed-light.png?fit=max\&auto=format\&n=EXkwf0kKMewZsyod\&q=85\&s=4eb6d4443763a21415dad4e426bc747a)
291269 
292<img src="https://mintcdn.com/claude-code/EXkwf0kKMewZsyod/images/mods-el-input-typed-dark.png?fit=max&auto=format&n=EXkwf0kKMewZsyod&q=85&s=90fbac3c7a47ab26a4fb71401975eac6" className="hidden dark:block" alt="The same field holding the typed letters Rel, followed by the return sign and the word save." width="1872" height="186" data-path="images/mods-el-input-typed-dark.png" />
293 
294270### `Select`
295271 
296272A `Select` lets the user pick one of several options, and runs `onSelect` with the option's `value`:
from line 289
313289 
314290Closed, it shows its label and the current option:
315291 
316<img src="https://mintcdn.com/claude-code/EXkwf0kKMewZsyod/images/mods-el-select-light.png?fit=max&auto=format&n=EXkwf0kKMewZsyod&q=85&s=4e3b18268ffd87d2cad06442e6d661a9" className="dark:hidden" alt="A pane with one line: the label Format, the current option Markdown, and a small down arrow." width="1872" height="186" data-path="images/mods-el-select-light.png" />
292![A pane with one line: the label Format, the current option Markdown, and a small down arrow.](https://mintcdn.com/claude-code/EXkwf0kKMewZsyod/images/mods-el-select-light.png?fit=max\&auto=format\&n=EXkwf0kKMewZsyod\&q=85\&s=4e3b18268ffd87d2cad06442e6d661a9)
317293 
318<img src="https://mintcdn.com/claude-code/EXkwf0kKMewZsyod/images/mods-el-select-dark.png?fit=max&auto=format&n=EXkwf0kKMewZsyod&q=85&s=1e329e6aee748c2dd70e92dbe4960de0" className="hidden dark:block" alt="A pane with one line: the label Format, the current option Markdown, and a small down arrow." width="1872" height="186" data-path="images/mods-el-select-dark.png" />
319 
320294Open, it lists its options and marks one:
321295 
322<img src="https://mintcdn.com/claude-code/EXkwf0kKMewZsyod/images/mods-el-select-moved-light.png?fit=max&auto=format&n=EXkwf0kKMewZsyod&q=85&s=deb6ce0a49d213235feedaa79ac658c0" className="dark:hidden" alt="The picker open, with its three options listed under the label. The second option, HTML, is drawn in inverse video." width="1872" height="300" data-path="images/mods-el-select-moved-light.png" />
296![The picker open, with its three options listed under the label. The second option, HTML, is drawn in inverse video.](https://mintcdn.com/claude-code/EXkwf0kKMewZsyod/images/mods-el-select-moved-light.png?fit=max\&auto=format\&n=EXkwf0kKMewZsyod\&q=85\&s=deb6ce0a49d213235feedaa79ac658c0)
323297 
324<img src="https://mintcdn.com/claude-code/EXkwf0kKMewZsyod/images/mods-el-select-moved-dark.png?fit=max&auto=format&n=EXkwf0kKMewZsyod&q=85&s=d69edeecd4f97dad4bdb39b908e3d98e" className="hidden dark:block" alt="The picker open, with its three options listed under the label. The second option, HTML, is drawn in inverse video." width="1872" height="300" data-path="images/mods-el-select-moved-dark.png" />
325 
326298After the user picks an option, the list closes:
327299 
328<img src="https://mintcdn.com/claude-code/EXkwf0kKMewZsyod/images/mods-el-select-picked-light.png?fit=max&auto=format&n=EXkwf0kKMewZsyod&q=85&s=f065ab5bc479868f03088dc736f17097" className="dark:hidden" alt="The picker closed again, now showing HTML as the current option." width="1872" height="186" data-path="images/mods-el-select-picked-light.png" />
300![The picker closed again, now showing HTML as the current option.](https://mintcdn.com/claude-code/EXkwf0kKMewZsyod/images/mods-el-select-picked-light.png?fit=max\&auto=format\&n=EXkwf0kKMewZsyod\&q=85\&s=f065ab5bc479868f03088dc736f17097)
329301 
330<img src="https://mintcdn.com/claude-code/EXkwf0kKMewZsyod/images/mods-el-select-picked-dark.png?fit=max&auto=format&n=EXkwf0kKMewZsyod&q=85&s=f084630e325825f3831219215a6a595e" className="hidden dark:block" alt="The picker closed again, now showing HTML as the current option." width="1872" height="186" data-path="images/mods-el-select-picked-dark.png" />
331 
332302## Draw pictures
333303 
334304### `Raster`
from line 317
347317})
348318```
349319 
350<img src="https://mintcdn.com/claude-code/EXkwf0kKMewZsyod/images/mods-el-raster-light.png?fit=max&auto=format&n=EXkwf0kKMewZsyod&q=85&s=5ed719481d3dd45b568bab696e57bf16" className="dark:hidden" alt="A pane with a small grid of colored blocks, two rows of three: green, amber, and red, then green, green, and amber." width="1872" height="224" data-path="images/mods-el-raster-light.png" />
351 
352<img src="https://mintcdn.com/claude-code/EXkwf0kKMewZsyod/images/mods-el-raster-dark.png?fit=max&auto=format&n=EXkwf0kKMewZsyod&q=85&s=b381f05d4cc99e2abfacb505c77b17f5" className="hidden dark:block" alt="A pane with a small grid of colored blocks, two rows of three: green, amber, and red, then green, green, and amber." width="1872" height="224" data-path="images/mods-el-raster-dark.png" />
320![A pane with a small grid of colored blocks, two rows of three: green, amber, and red, then green, green, and amber.](https://mintcdn.com/claude-code/EXkwf0kKMewZsyod/images/mods-el-raster-light.png?fit=max\&auto=format\&n=EXkwf0kKMewZsyod\&q=85\&s=5ed719481d3dd45b568bab696e57bf16)
353321 
354322A `Raster` rounds each color to a smaller palette, so `0x2e7d32` draws as `#337733`.
355323 

plugins/mods/interface Changed · +280 / -304 lines

### `Link` in the Desktop app and VS Code ### When a `Client` fails ### Keyboard focus and hotkeys ## Redraw a site ### Load a saved value again after `/clear`

The two sides of this change are more than 400 edits apart, too far apart to line up, so this is the differ's own diff of it and the words inside a line are not marked.

from line 6
66 
77This map shows where a mod can draw in a terminal session:
88 
9<img src="https://mintcdn.com/claude-code/dgiVO_Od1X1faduV/images/mods-screen-map.svg?fit=max&auto=format&n=dgiVO_Od1X1faduV&q=85&s=5fda26b6609c62b68c6f9e528c1590ea" className="dark:hidden" alt="Map of a Claude Code terminal session in fullscreen rendering. A mod can add a pane as a sidebar on the right, a toast at the top right of the transcript, a log line in the transcript, a band above the prompt, and a status line under the prompt. A mod can redraw messages, tool call rows, and the spinner. The prompt is Claude Code's own." width="600" height="336" data-path="images/mods-screen-map.svg" />
10 
11<img src="https://mintcdn.com/claude-code/dgiVO_Od1X1faduV/images/mods-screen-map-dark.svg?fit=max&auto=format&n=dgiVO_Od1X1faduV&q=85&s=5b4161581a1bd2c0450b0c8b57bc1225" className="hidden dark:block" alt="Map of a Claude Code terminal session in fullscreen rendering. A mod can add a pane as a sidebar on the right, a toast at the top right of the transcript, a log line in the transcript, a band above the prompt, and a status line under the prompt. A mod can redraw messages, tool call rows, and the spinner. The prompt is Claude Code's own." width="600" height="336" data-path="images/mods-screen-map-dark.svg" />
9![Map of a Claude Code terminal session in fullscreen rendering. A mod can add a pane as a sidebar on the right, a toast at the top right of the transcript, a log line in the transcript, a band above the prompt, and a status line under the prompt. A mod can redraw messages, tool call rows, and the spinner. The prompt is Claude Code's own.](https://mintcdn.com/claude-code/dgiVO_Od1X1faduV/images/mods-screen-map.svg?fit=max\&auto=format\&n=dgiVO_Od1X1faduV\&q=85\&s=5fda26b6609c62b68c6f9e528c1590ea)
1210 
1311In a narrower terminal, the pane sits above the prompt instead of beside the transcript.
1412 
1513Build 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.
1614 
17<Note>
18 To look up one prop or limit, see the [reference](/docs/en/plugins/mods/reference#render-sites).
19</Note>
15> [!NOTE]
16>
17> To look up one prop or limit, see the [reference](/docs/en/plugins/mods/reference#render-sites).
2018 
2119## Build a pane with tabs
2220 
from line 22
2422 
2523The finished mod looks like this. The recording opens the pane, switches to the second tab, presses the button a few times, and returns to the first tab:
2624 
27<Frame>
28 <video autoPlay muted loop playsInline controls className="w-full dark:hidden" src="https://mintcdn.com/claude-code/dgiVO_Od1X1faduV/images/mods-hello-tabs-light.mp4?fit=max&auto=format&n=dgiVO_Od1X1faduV&q=85&s=49d520094d87b5b44bfe50fa49677f06" aria-label="The /hello-tabs command is typed at the Claude Code prompt and a framed pane opens above it, with '1: One' and '2: Two' across the top and the text 'This is the first tab.' The second tab shows an 'Add one' button beside 'Count: 1', and the count rises to 3. The pane then returns to the first tab." data-path="images/mods-hello-tabs-light.mp4" />
29 
30 <video autoPlay muted loop playsInline controls className="w-full hidden dark:block" src="https://mintcdn.com/claude-code/dgiVO_Od1X1faduV/images/mods-hello-tabs-dark.mp4?fit=max&auto=format&n=dgiVO_Od1X1faduV&q=85&s=ff7a14d713d6e5d3b0000efa8522ea4b" aria-label="The /hello-tabs command is typed at the Claude Code prompt and a framed pane opens above it, with '1: One' and '2: Two' across the top and the text 'This is the first tab.' The second tab shows an 'Add one' button beside 'Count: 1', and the count rises to 3. The pane then returns to the first tab." data-path="images/mods-hello-tabs-dark.mp4" />
31</Frame>
25<video autoPlay muted loop playsInline controls src="https://mintcdn.com/claude-code/dgiVO_Od1X1faduV/images/mods-hello-tabs-light.mp4?fit=max&auto=format&n=dgiVO_Od1X1faduV&q=85&s=49d520094d87b5b44bfe50fa49677f06" aria-label="The /hello-tabs command is typed at the Claude Code prompt and a framed pane opens above it, with '1: One' and '2: Two' across the top and the text 'This is the first tab.' The second tab shows an 'Add one' button beside 'Count: 1', and the count rises to 3. The pane then returns to the first tab." />
3226 
3327The tabs are two buttons in a row. The mod keeps track of which one is active and draws that tab's content under the row.
3428 
35<Steps>
36 <Step title="Create the plugin">
37 A 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.
38 
39 Save the manifest as `hello-tabs/.claude-plugin/plugin.json`:
40 
41 ```json hello-tabs/.claude-plugin/plugin.json theme={null}
42 {
43 "name": "hello-tabs",
44 "version": "0.1.0",
45 "description": "Opens a pane with two tabs and a counter",
46 "author": { "name": "Your Name" }
47 }
48 ```
49 
50 Name your entry point in `hello-tabs/hooks/hooks.json`:
51 
52 ```json hello-tabs/hooks/hooks.json theme={null}
53 {
54 "modules": ["./register.js"]
55 }
56 ```
57 </Step>
58 
59 <Step title="Write the code">
60 This list says what each hook does, in the order they appear in the code:
61 
62 * Adds the `/hello-tabs` command, and loads the count an earlier session saved
63 * Opens the pane when you run that command
64 * Draws the pane's content: the row of tabs and the open tab's body
65 
66 Two module-level variables, `tab` and `count`, hold the pane's state.
67 
68 Save this as `hello-tabs/hooks/register.js`:
69 
70 ```javascript hello-tabs/hooks/register.js theme={null}
71 // The pane's id, used to open the pane and to recognize it when drawing
72 const PANE = 'hello-tabs'
73 
74 // What the pane shows: which tab is open, and the counter's value
75 let tab = 'one'
76 let count = 0
77 
78 export function register(on) {
79 // Runs before your first prompt, and again after a reload
80 on('session.start', async ($, e, next) => {
81 await $.command.register({ name: 'hello-tabs', description: 'Open the hello-tabs pane' })
82 // Load the count an earlier session saved, if there is one
83 const saved = await $.store.get('count')
84 if (typeof saved === 'number') count = saved
85 return next(e)
29**1. Create the plugin**
30 
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.
32 
33Save the manifest as `hello-tabs/.claude-plugin/plugin.json`:
34 
35```json hello-tabs/.claude-plugin/plugin.json theme={null}
36{
37 "name": "hello-tabs",
38 "version": "0.1.0",
39 "description": "Opens a pane with two tabs and a counter",
40 "author": { "name": "Your Name" }
41}
42```
43 
44Name your entry point in `hello-tabs/hooks/hooks.json`:
45 
46```json hello-tabs/hooks/hooks.json theme={null}
47{
48 "modules": ["./register.js"]
49}
50```
51 
52**2. Write the code**
53 
54This list says what each hook does, in the order they appear in the code:
55 
56* Adds the `/hello-tabs` command, and loads the count an earlier session saved
57* Opens the pane when you run that command
58* Draws the pane's content: the row of tabs and the open tab's body
59 
60Two module-level variables, `tab` and `count`, hold the pane's state.
61 
62Save this as `hello-tabs/hooks/register.js`:
63 
64```javascript hello-tabs/hooks/register.js theme={null}
65// The pane's id, used to open the pane and to recognize it when drawing
66const PANE = 'hello-tabs'
67 
68// What the pane shows: which tab is open, and the counter's value
69let tab = 'one'
70let count = 0
71 
72export function register(on) {
73 // Runs before your first prompt, and again after a reload
74 on('session.start', async ($, e, next) => {
75 await $.command.register({ name: 'hello-tabs', description: 'Open the hello-tabs pane' })
76 // Load the count an earlier session saved, if there is one
77 const saved = await $.store.get('count')
78 if (typeof saved === 'number') count = saved
79 return next(e)
80 })
81 
82 // Runs when you type /hello-tabs
83 on('command.run', { command: 'hello-tabs' }, async ($) => {
84 // Open the pane, give it the keyboard, and let Esc close it
85 await $.ui.open({ id: PANE, title: 'Hello tabs', focus: true, closeOnEscape: true })
86 // Print nothing in the transcript
87 return {}
88 })
89 
90 // Runs each time Claude Code draws a pane
91 on('ui.render', { component: 'Pane' }, async ($, e, next) => {
92 // Leave other mods' panes alone
93 if (e.requestId !== PANE) return next(e)
94 // Get the elements this app can draw
95 const { Box, Text, Button } = $.ui.resolve(e)
96 // Ask Claude Code to run this hook again
97 const redraw = () => $.ui.invalidate('ui.render')
98 
99 // One tab: a button that switches to its tab when pressed
100 const tabButton = (name, label, hotkey) =>
101 Button({
102 key: 'tab-' + name,
103 label,
104 hotkey,
105 plain: true,
106 // Dim the tab that isn't open
107 dimColor: tab !== name,
108 onPress: () => {
109 tab = name
110 redraw()
111 },
86112 })
87113 
88 // Runs when you type /hello-tabs
89 on('command.run', { command: 'hello-tabs' }, async ($) => {
90 // Open the pane, give it the keyboard, and let Esc close it
91 await $.ui.open({ id: PANE, title: 'Hello tabs', focus: true, closeOnEscape: true })
92 // Print nothing in the transcript
93 return {}
94 })
95 
96 // Runs each time Claude Code draws a pane
97 on('ui.render', { component: 'Pane' }, async ($, e, next) => {
98 // Leave other mods' panes alone
99 if (e.requestId !== PANE) return next(e)
100 // Get the elements this app can draw
101 const { Box, Text, Button } = $.ui.resolve(e)
102 // Ask Claude Code to run this hook again
103 const redraw = () => $.ui.invalidate('ui.render')
104 
105 // One tab: a button that switches to its tab when pressed
106 const tabButton = (name, label, hotkey) =>
107 Button({
108 key: 'tab-' + name,
109 label,
110 hotkey,
111 plain: true,
112 // Dim the tab that isn't open
113 dimColor: tab !== name,
114 onPress: () => {
115 tab = name
116 redraw()
117 },
118 })
119 
120 // What goes under the tabs, depending on which one is open
121 const body =
122 tab === 'one'
123 ? [Text({ children: ['This is the first tab.'] })]
124 : [
125 Box({
126 flexDirection: 'row',
127 columnGap: 2,
128 children: [
129 Button({
130 key: 'more',
131 label: 'Add one',
132 hotkey: 'a',
133 onPress: async () => {
134 count += 1
135 redraw()
136 // Save the count so it's there after a restart
137 await $.store.set('count', count)
138 },
139 }),
140 Text({ children: ['Count: ' + count] }),
141 ],
142 }),
143 ]
144 
145 // The whole pane: the row of tabs, a blank line, then the body
146 return Box({
147 flexDirection: 'column',
148 children: [
114 // What goes under the tabs, depending on which one is open
115 const body =
116 tab === 'one'
117 ? [Text({ children: ['This is the first tab.'] })]
118 : [
149119 Box({
150120 flexDirection: 'row',
151 columnGap: 3,
152 children: [tabButton('one', 'One', '1'), tabButton('two', 'Two', '2')],
121 columnGap: 2,
122 children: [
123 Button({
124 key: 'more',
125 label: 'Add one',
126 hotkey: 'a',
127 onPress: async () => {
128 count += 1
129 redraw()
130 // Save the count so it's there after a restart
131 await $.store.set('count', count)
132 },
133 }),
134 Text({ children: ['Count: ' + count] }),
135 ],
153136 }),
154 Text({ children: [' '] }),
155 ...body,
156 ],
157 })
158 })
159 }
160 ```
161 
162 Each hook also does something the code doesn't make plain:
163 
164 * **[`session.start`](/docs/en/plugins/mods/reference#session)** also reads the saved count from [`$.store`](#keep-state), a key-value store that persists between sessions.
165 * **[`command.run`](/docs/en/plugins/mods/api#add-a-command)** only tells Claude Code the pane exists. Opening a pane draws nothing by itself: Claude Code then fires `ui.render` to ask what goes in it.
166 * **`ui.render`** returns the element tree, a `Box` that holds other boxes, text, and buttons, and builds it again from `tab` and `count` each time it runs.
167 
168 Pressing a button runs its `onPress` callback, which changes a variable and calls `redraw`. Claude Code then runs the `ui.render` hook again, and the hook builds a new tree from the new values. Every interactive drawing uses that render cycle: a callback changes state, and the hook renders again from the new state.
169 </Step>
170 
171 <Step title="Open the pane">
172 In your shell, start Claude Code with `claude --plugin-dir ./hello-tabs`. At the Claude Code prompt, run `/hello-tabs`. A pane opens with `1: One` and `2: Two` across the top. Press `2`, then press `a`, the hotkey for **Add one**, a few times. The count rises.
173 </Step>
174 
175 <Step title="Check that the count was saved">
176 Press Esc to close the pane, then exit the session. In your shell, start Claude Code again with the same `claude --plugin-dir ./hello-tabs` command, and at the Claude Code prompt run `/hello-tabs`. The count is where you left it.
177 
178 To clear the count, have the mod call `$.store.delete('count')`. [Keep state](#keep-state) covers how long each kind of value lasts.
179 </Step>
180</Steps>
137 ]
138 
139 // The whole pane: the row of tabs, a blank line, then the body
140 return Box({
141 flexDirection: 'column',
142 children: [
143 Box({
144 flexDirection: 'row',
145 columnGap: 3,
146 children: [tabButton('one', 'One', '1'), tabButton('two', 'Two', '2')],
147 }),
148 Text({ children: [' '] }),
149 ...body,
150 ],
151 })
152 })
153}
154```
155 
156Each hook also does something the code doesn't make plain:
157 
158* **[`session.start`](/docs/en/plugins/mods/reference#session)** also reads the saved count from [`$.store`](#keep-state), a key-value store that persists between sessions.
159* **[`command.run`](/docs/en/plugins/mods/api#add-a-command)** only tells Claude Code the pane exists. Opening a pane draws nothing by itself: Claude Code then fires `ui.render` to ask what goes in it.
160* **`ui.render`** returns the element tree, a `Box` that holds other boxes, text, and buttons, and builds it again from `tab` and `count` each time it runs.
161 
162Pressing a button runs its `onPress` callback, which changes a variable and calls `redraw`. Claude Code then runs the `ui.render` hook again, and the hook builds a new tree from the new values. Every interactive drawing uses that render cycle: a callback changes state, and the hook renders again from the new state.
163 
164**3. Open the pane**
165 
166In your shell, start Claude Code with `claude --plugin-dir ./hello-tabs`. At the Claude Code prompt, run `/hello-tabs`. A pane opens with `1: One` and `2: Two` across the top. Press `2`, then press `a`, the hotkey for **Add one**, a few times. The count rises.
167 
168**4. Check that the count was saved**
169 
170Press Esc to close the pane, then exit the session. In your shell, start Claude Code again with the same `claude --plugin-dir ./hello-tabs` command, and at the Claude Code prompt run `/hello-tabs`. The count is where you left it.
171 
172To clear the count, have the mod call `$.store.delete('count')`. [Keep state](#keep-state) covers how long each kind of value lasts.
181173 
182174## Pick where to draw
183175 
from line 177
185177 
186178The 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:
187179 
188<Tabs>
189 <Tab title="Pane">
190 A pane is a sidebar beside the transcript in a wide fullscreen terminal, or a framed region above the prompt otherwise. With several panes open, each gets a tab that shows its title.
191 
192 A pane appears when your mod calls `$.ui.open` with an `id` you choose, as in `$.ui.open({ id: 'hello-tabs' })`. [Open a pane at the right time](#open-a-pane-at-the-right-time) covers the other fields and when a pane waits for a wider terminal.
193 
194 To draw in your pane, filter on `{ component: 'Pane' }` and check that `e.requestId` is your `id`.
195 </Tab>
196 
197 <Tab title="Band above the prompt">
198 The band is a strip directly above the prompt input. It's always there, and every mod shares it.
199 
200 Your 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.
201 
202 To draw in the band, filter on `{ component: 'AbovePrompt' }`.
203 </Tab>
204</Tabs>
180**Pane**
181 
182A pane is a sidebar beside the transcript in a wide fullscreen terminal, or a framed region above the prompt otherwise. With several panes open, each gets a tab that shows its title.
183 
184A pane appears when your mod calls `$.ui.open` with an `id` you choose, as in `$.ui.open({ id: 'hello-tabs' })`. [Open a pane at the right time](#open-a-pane-at-the-right-time) covers the other fields and when a pane waits for a wider terminal.
185 
186To draw in your pane, filter on `{ component: 'Pane' }` and check that `e.requestId` is your `id`.
187 
188**Band above the prompt**
189 
190The band is a strip directly above the prompt input. It's always there, and every mod shares it.
191 
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.
193 
194To draw in the band, filter on `{ component: 'AbovePrompt' }`.
205195 
206196### Change what Claude Code already draws
207197 
from line 210
220210 
221211At 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).
222212 
223<Tabs>
224 <Tab title="Change a detail">
225 To keep Claude Code's drawing and change one part of it, pass `next` a copy of the event with changed `props`. This hook changes the text after the spinner's word:
226 
227 ```javascript theme={null}
228 on('ui.render', { component: 'Spinner' }, async ($, e, next) => {
229 // Keep Claude Code's spinner, and change the text after its word
230 return next({ ...e, props: { ...e.props, suffix: ' · tool calls: ' + calls + '…' } })
231 })
232 ```
233 
234 The spinner keeps its animation and its word, and your text follows the word:
235 
236 ```text theme={null}
237 Thinking · tool calls: 2…
238 ```
239 </Tab>
240 
241 <Tab title="Replace the drawing">
242 To draw something of your own in the site's place, return a tree and don't call `next`. This hook draws one line of text where the spinner would be:
243 
244 ```javascript theme={null}
245 on('ui.render', { component: 'Spinner' }, async ($, e) => {
246 const { Text } = $.ui.resolve(e)
247 // No call to next, so this line is drawn in the spinner's place
248 return Text({ children: ['Claude has made ' + calls + ' tool calls'] })
249 })
250 ```
251 
252 While Claude works, your line shows and Claude Code's spinner doesn't:
253 
254 ```text theme={null}
255 Claude has made 2 tool calls
256 ```
257 </Tab>
258 
259 <Tab title="Leave it alone">
260 To leave the site as Claude Code draws it, return `next(e)`. A hook often does that for some events and not others. This hook leaves the spinner alone until there's a call to count:
261 
262 ```javascript theme={null}
263 on('ui.render', { component: 'Spinner' }, async ($, e, next) => {
264 // Nothing to show yet, so pass the event on unchanged
265 if (calls === 0) return next(e)
266 return next({ ...e, props: { ...e.props, suffix: ' · tool calls: ' + calls + '…' } })
267 })
268 ```
269 
270 Before the first tool call, the spinner looks the way it does without the mod:
271 
272 ```text theme={null}
273 Thinking…
274 ```
275 </Tab>
276</Tabs>
213**Change a detail**
214 
215To keep Claude Code's drawing and change one part of it, pass `next` a copy of the event with changed `props`. This hook changes the text after the spinner's word:
216 
217```javascript theme={null}
218on('ui.render', { component: 'Spinner' }, async ($, e, next) => {
219 // Keep Claude Code's spinner, and change the text after its word
220 return next({ ...e, props: { ...e.props, suffix: ' · tool calls: ' + calls + '…' } })
221})
222```
223 
224The spinner keeps its animation and its word, and your text follows the word:
225 
226```text theme={null}
227Thinking · tool calls: 2…
228```
229 
230**Replace the drawing**
231 
232To draw something of your own in the site's place, return a tree and don't call `next`. This hook draws one line of text where the spinner would be:
233 
234```javascript theme={null}
235on('ui.render', { component: 'Spinner' }, async ($, e) => {
236 const { Text } = $.ui.resolve(e)
237 // No call to next, so this line is drawn in the spinner's place
238 return Text({ children: ['Claude has made ' + calls + ' tool calls'] })
239})
240```
241 
242While Claude works, your line shows and Claude Code's spinner doesn't:
243 
244```text theme={null}
245Claude has made 2 tool calls
246```
247 
248**Leave it alone**
249 
250To leave the site as Claude Code draws it, return `next(e)`. A hook often does that for some events and not others. This hook leaves the spinner alone until there's a call to count:
251 
252```javascript theme={null}
253on('ui.render', { component: 'Spinner' }, async ($, e, next) => {
254 // Nothing to show yet, so pass the event on unchanged
255 if (calls === 0) return next(e)
256 return next({ ...e, props: { ...e.props, suffix: ' · tool calls: ' + calls + '…' } })
257})
258```
259 
260Before the first tool call, the spinner looks the way it does without the mod:
261 
262```text theme={null}
263Thinking…
264```
277265 
278266At these sites, `next(e)` returns a reference to Claude Code's drawing, `{ type: 'engine', ref }`, unless a mod that runs after yours returned a tree of its own. To change what's in that drawing, pass `next` a copy of the event with different props, as the **Change a detail** tab does. You can return the reference as it is, or place it in a `Box` beside elements of your own:
279267 
from line 353
365353 
366354Select a tab to see each of the most common elements and how the terminal draws it:
367355 
368<Tabs>
369 <Tab title="Text">
370 `Text` draws a string, with optional styling such as `bold` and `color`:
371 
372 ```javascript theme={null}
373 Text({ children: ['This is the first tab.'] })
374 ```
375 
376 ```text theme={null}
377 This is the first tab.
378 ```
379 </Tab>
380 
381 <Tab title="Box">
382 `Box` arranges what's inside it, in a row or a column. This one puts a button and a line of text side by side, two columns apart:
383 
384 ```javascript theme={null}
385 Box({
386 flexDirection: 'row',
387 columnGap: 2,
388 children: [
389 Button({ key: 'more', label: 'Add one', onPress: addOne }),
390 Text({ children: ['Count: 0'] }),
391 ],
392 })
393 ```
394 
395 ```text theme={null}
396 [ Add one ] Count: 0
397 ```
398 </Tab>
399 
400 <Tab title="Button">
401 `Button` is a control the user can press. It runs your `onPress` callback. With `plain: true` it has no brackets and shows its hotkey:
402 
403 ```javascript theme={null}
404 Button({ key: 'more', label: 'Add one', onPress: addOne })
405 Button({ key: 'tab-one', label: 'One', hotkey: '1', plain: true, onPress: showTabOne })
406 ```
407 
408 ```text theme={null}
409 [ Add one ]
410 1: One
411 ```
412 </Tab>
413 
414 <Tab title="Input">
415 `Input` is a text field. It runs your `onSubmit` callback with the text when the user presses Enter:
416 
417 ```javascript theme={null}
418 Input({
419 key: 'new-note',
420 label: 'Note',
421 placeholder: 'Type a note and press Enter',
422 value: '',
423 submitLabel: 'add',
424 onSubmit: addNote,
425 })
426 ```
427 
428 ```text theme={null}
429 Note: Type a note and press Enter
430 ```
431 </Tab>
432</Tabs>
356**Text**
357 
358`Text` draws a string, with optional styling such as `bold` and `color`:
359 
360```javascript theme={null}
361Text({ children: ['This is the first tab.'] })
362```
363 
364```text theme={null}
365This is the first tab.
366```
367 
368**Box**
369 
370`Box` arranges what's inside it, in a row or a column. This one puts a button and a line of text side by side, two columns apart:
371 
372```javascript theme={null}
373Box({
374 flexDirection: 'row',
375 columnGap: 2,
376 children: [
377 Button({ key: 'more', label: 'Add one', onPress: addOne }),
378 Text({ children: ['Count: 0'] }),
379 ],
380})
381```
382 
383```text theme={null}
384[ Add one ] Count: 0
385```
386 
387**Button**
388 
389`Button` is a control the user can press. It runs your `onPress` callback. With `plain: true` it has no brackets and shows its hotkey:
390 
391```javascript theme={null}
392Button({ key: 'more', label: 'Add one', onPress: addOne })
393Button({ key: 'tab-one', label: 'One', hotkey: '1', plain: true, onPress: showTabOne })
394```
395 
396```text theme={null}
397[ Add one ]
3981: One
399```
400 
401**Input**
402 
403`Input` is a text field. It runs your `onSubmit` callback with the text when the user presses Enter:
404 
405```javascript theme={null}
406Input({
407 key: 'new-note',
408 label: 'Note',
409 placeholder: 'Type a note and press Enter',
410 value: '',
411 submitLabel: 'add',
412 onSubmit: addNote,
413})
414```
415 
416```text theme={null}
417Note: Type a note and press Enter
418```
433419 
434420The [interface gallery](/docs/en/plugins/mods/gallery) has samples and screenshots of most elements. This table lists every element:
435421 
from line 436
450436 
451437In 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.
452438 
453<h3 id="link-in-the-desktop-app">
454 `Link` in the Desktop app and VS Code
455</h3>
439### `Link` in the Desktop app and VS Code
456440 
457441In the Desktop app and the VS Code extension, a `Link` draws as plain text unless its `href` meets these requirements:
458442 
from line 446
462446 
463447In the terminal, these requirements don't apply.
464448 
465<h3 id="when-a-client-fails">
466 When a `Client` fails
467</h3>
449### When a `Client` fails
468450 
469451In the terminal, when the file a `Client` runs fails, a dimmed line such as `my-mod: Client client/spinner.js: boom` takes the `Client`'s place, and the rest of your drawing still shows.
470452 
from line 490
508490 
509491In the terminal, the pane shows the grid:
510492 
511<img src="https://mintcdn.com/claude-code/dgiVO_Od1X1faduV/images/mods-heat-map.svg?fit=max&auto=format&n=dgiVO_Od1X1faduV&q=85&s=b91bcce3bad74bc851149133d4acc5d5" alt="A pane in the terminal that holds a small grid of colored blocks, two rows of three. The top row is green, amber, and red. The bottom row is green, green, and amber." width="360" height="132" data-path="images/mods-heat-map.svg" />
493![A pane in the terminal that holds a small grid of colored blocks, two rows of three. The top row is green, amber, and red. The bottom row is green, green, and amber.](https://mintcdn.com/claude-code/dgiVO_Od1X1faduV/images/mods-heat-map.svg?fit=max\&auto=format\&n=dgiVO_Od1X1faduV\&q=85\&s=b91bcce3bad74bc851149133d4acc5d5)
512494 
513495The `rows` array is the part you'd change, and `cellsOf` turns it into the packed string. The hook draws only in a pane whose `id` is `heat`, so open one with `$.ui.open({ id: 'heat' })` from a command, as the [`hello-tabs` example](#build-a-pane-with-tabs) opens its pane.
514496 
from line 506
524506 
525507A test presses or types into a control by its `key`, so give each control one. Each use of a control also fires [`ui.press`, `ui.input`, or `ui.select`](/docs/en/plugins/mods/reference#interface) with the `key` in `e.element`, and another mod can handle those events. Its hook runs before your callback, so it sees what the user types into your `Input` and can change it or answer in place of your callback. The mods API has no method that presses another mod's button.
526508 
527<h3 id="know-which-keys-your-mod-can-receive">
528 Keyboard focus and hotkeys
529</h3>
509### Keyboard focus and hotkeys
530510 
531511Your 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.
532512 
from line 651
671651 
672652Submitting an `Input` doesn't start a turn unless your callback calls [`$.prompt.submit`](/docs/en/plugins/mods/api#start-a-turn-from-a-background-job).
673653 
674<h2 id="redraw-when-something-changes">
675 Redraw a site
676</h2>
654## Redraw a site
677655 
678656A drawing is a snapshot: it shows what your `ui.render` hook returned the last time the hook ran. To show something new, the hook has to run again. Claude Code runs it again for some changes, and your mod asks for the rest.
679657 
from line 796
818796 
819797Keep `redraw` for the tab buttons, because `tab` is still a variable.
820798 
821<h3 id="load-a-saved-value-again-after-clear">
822 Load a saved value again after `/clear`
823</h3>
799### Load a saved value again after `/clear`
824800 
825801If your mod copies a saved value from `$.store` into `$.state` at `session.start`, it has to copy it again after `/clear`, `/resume`, or `/branch`. Those commands reset every `$.state` value to its default, and `session.start` doesn't fire again. [`classic.SessionStart`](/docs/en/plugins/mods/events#hook-the-settings-hook-events) does fire after each of them, with `e.source` set to `clear`, `resume`, or `fork`, so copy the value again in a hook on it. Otherwise your drawing shows the default, and a callback that saves the `$.state` value writes the default over what you stored.
826802 
827803 

plugins/mods/overview Changed · +10 / -14 lines

from line 4
44 
55A 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).
66 
7<Note>
8 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</Note>
7> [!NOTE]
8>
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".
1010 
1111## What a mod can do
1212 
from line 30
3030 
3131### Install or update a mod
3232 
33<Warning>
34 A mod is code that runs with your permissions. It can read and write your files, start processes, and make network requests. Install mods only from authors and marketplaces you trust. See [Decide whether to trust a mod](#decide-whether-to-trust-a-mod).
35</Warning>
33> [!WARNING]
34>
35> A mod is code that runs with your permissions. It can read and write your files, start processes, and make network requests. Install mods only from authors and marketplaces you trust. See [Decide whether to trust a mod](#decide-whether-to-trust-a-mod).
3636 
3737A mod installs as a plugin, from a marketplace. Give the plugin's name, an `@`, and the marketplace's name. These examples install a plugin named `token-chart` from a marketplace named `your-org`:
3838 
from line 107
107107 
108108To find out whether mods can load for you, see [Check whether mods can load](/docs/en/plugins/mods/troubleshoot#check-whether-mods-can-load).
109109 
110<Note>
111 If you set `CLAUDE_CODE_ENABLE_FUNCTION_HOOKS` during early access, remove it. Claude Code v2.1.287 and later ignores it, so setting it to `0` doesn't keep mods off.
112</Note>
110> [!NOTE]
111>
112> If you set `CLAUDE_CODE_ENABLE_FUNCTION_HOOKS` during early access, remove it. Claude Code v2.1.287 and later ignores it, so setting it to `0` doesn't keep mods off.
113113 
114114### See which mods a session loaded
115115 
from line 164
164164 
165165This recording shows the mod at work. Watch the spinner line above the prompt box: while Claude lists a directory and reads two files, it reads `Thinking · tool calls: 1…`, then `2…`, then `3…`.
166166 
167<Frame>
168 <video autoPlay muted loop playsInline controls className="w-full dark:hidden" src="https://mintcdn.com/claude-code/dgiVO_Od1X1faduV/images/mods-overview-light.mp4?fit=max&auto=format&n=dgiVO_Od1X1faduV&q=85&s=00a18aa0743b59a700f0275ce226e6d1" aria-label="In a Claude Code session, the prompt 'list the files here and read the README' is typed and sent. While Claude works, the spinner reads 'Thinking · tool calls: 1', then 2, then 3, as Claude lists the files and reads two of them." data-path="images/mods-overview-light.mp4" />
169 
170 <video autoPlay muted loop playsInline controls className="w-full hidden dark:block" src="https://mintcdn.com/claude-code/dgiVO_Od1X1faduV/images/mods-overview-dark.mp4?fit=max&auto=format&n=dgiVO_Od1X1faduV&q=85&s=d5223da2fef16ceaaa214a36d72c0536" aria-label="In a Claude Code session, the prompt 'list the files here and read the README' is typed and sent. While Claude works, the spinner reads 'Thinking · tool calls: 1', then 2, then 3, as Claude lists the files and reads two of them." data-path="images/mods-overview-dark.mp4" />
171</Frame>
167<video autoPlay muted loop playsInline controls src="https://mintcdn.com/claude-code/dgiVO_Od1X1faduV/images/mods-overview-light.mp4?fit=max&auto=format&n=dgiVO_Od1X1faduV&q=85&s=00a18aa0743b59a700f0275ce226e6d1" aria-label="In a Claude Code session, the prompt 'list the files here and read the README' is typed and sent. While Claude works, the spinner reads 'Thinking · tool calls: 1', then 2, then 3, as Claude lists the files and reads two of them." />
172168 
173169### What a hook can do with an event
174170 

plugins/mods/reference Changed · +9 / -21 lines

#### Source and frontmatter fields on `skill.prompt` ### Session ### `Box` border styles ### `Box` spacing steps ### `Text` typography props #### Replace `bold` with `weight`

from line 4
44 
55Look 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.
66 
7<Note>
8 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</Note>
7> [!NOTE]
8>
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).
1010 
1111## Files
1212 
from line 82
8282| [`skill.prompt`](/docs/en/plugins/mods/events#rewrite-or-add-to-a-prompt) | A skill's text is expanded for Claude | `{ text }` |
8383| `attribution.text` | Claude Code composes commit or pull request attribution text | `{ text }` |
8484 
85<h4 id="skill-prompt-fields">
86 Source and frontmatter fields on `skill.prompt`
87</h4>
85#### Source and frontmatter fields on `skill.prompt`
8886 
8987In a `skill.prompt` hook, you can read these fields along with the skill's name in `e.skill` and the text Claude reads in `e.text`:
9088 
from line 119
121119| [`turn.step`](/docs/en/plugins/mods/events#follow-a-turn) | One request is about to go to the model | `yield* next(e)`, or `next({ ...e, model })`, `next({ ...e, effort })` |
122120| [`turn.complete`](/docs/en/plugins/mods/events#follow-a-turn) | A turn ended | `next(e)`, or `{ text }` to show a line under the answer |
123121 
124<h3 id="session">
125 Session
126</h3>
122### Session
127123 
128124Session events mark the session starting, ending, compacting, and exchanging messages with other sessions:
129125 
from line 274
278274* **`Code`**: `language`, `path`, `startLine`, `format`, and `wrap`, so code draws without colors or line numbers, and a `format: 'diff'` block shows the diff's raw text
279275* **`Input` and `Select`**: `autoFocus`
280276 
281<h3 id="box-border-styles">
282 `Box` border styles
283</h3>
277### `Box` border styles
284278 
285279To draw a border around a `Box`, set its `borderStyle` to one of these names, as in `borderStyle: 'round'`. Each row says what the terminal draws for that name and shows the top edge of the border.
286280 
from line 293
299293 
300294A `Box` whose `borderStyle` names anything else, such as `'rounded'`, draws with no border.
301295 
302<h3 id="box-spacing-steps">
303 `Box` spacing steps
304</h3>
296### `Box` spacing steps
305297 
306298The `Box` spacing props are `gap`, `columnGap`, `rowGap`, `padding`, `margin`, and the one-side and one-axis forms of `padding` and `margin`, such as `paddingX` and `marginTop`. Each takes a number of terminal cells such as `gap: 1`, or a step name such as `gap: 'md'`. In the terminal and the VS Code extension, each step is this many cells:
307299 
from line 309
317309 
318310Step 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.
319311 
320<h3 id="text-typography">
321 `Text` typography props
322</h3>
312### `Text` typography props
323313 
324314Set `size`, `weight`, `mono`, or `tabular` on a `Text` to ask the app drawing your tree for a text size, a weight, a monospaced typeface, or equal-width digits. Before you rely on a prop, check what the terminal and the VS Code extension do with it. If an app ignores a prop you set, your tree still draws there, with the text as if you'd left that prop out.
325315 
from line 322
332322 
333323These 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`.
334324 
335<h4 id="text-bold">
336 Replace `bold` with `weight`
337</h4>
325#### Replace `bold` with `weight`
338326 
339327`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.
340328 

plugins/mods/test Changed · +2 / -6 lines

### Test a drawing after `/clear` ## Test a policy mod

from line 316
316316 
317317A 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.
318318 
319<h3 id="test-a-drawing-after-clear">
320 Test a drawing after `/clear`
321</h3>
319### Test a drawing after `/clear`
322320 
323321Each 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.
324322 
from line 341
343341 
344342The test passes when your `classic.SessionStart` hook has copied the stored `7` into `$.state` before the pane draws. Without that hook in your module, the pane draws `Count: 0`, `find` returns `undefined`, and the test fails at `toBeDefined`.
345343 
346<h2 id="test-a-mod-that-judges-other-mods">
347 Test a policy mod
348</h2>
344## Test a policy mod
349345 
350346A 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:
351347 

plugins/mods/troubleshoot Changed · +2 / -6 lines

### `Stopped: type a message to continue; a mod cannot resume work after Stop` ### Another mod's band shows and yours doesn't

from line 177
177177 
178178## A toast appears after a turn is stopped
179179 
180<h3 id="stopped-type-a-message-to-continue">
181 `Stopped: type a message to continue; a mod cannot resume work after Stop`
182</h3>
180### `Stopped: type a message to continue; a mod cannot resume work after Stop`
183181 
184182This 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.
185183 
from line 187
189187 
190188The mod loaded, and its pane, band, toast, or controls don't behave as you expect.
191189 
192<h3 id="another-mods-band-shows-and-yours-doesnt">
193 Another mod's band shows and yours doesn't
194</h3>
190### Another mod's band shows and yours doesn't
195191 
196192There 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:
197193 

plugins/org Changed · +30 / -32 lines

from line 6
66 
77This page is for administrators, and the settings here govern Claude Code.
88 
9<Note>
10 These cases are covered on other pages:
9> [!NOTE]
10>
11> These cases are covered on other pages:
12>
13> * **Installing plugins for yourself**: start at [Install plugins](/docs/en/plugins/install)
14> * **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
15> * **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
1117 
12 * **Installing plugins for yourself**: start at [Install plugins](/docs/en/plugins/install)
13 * **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
14 * **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
15 * **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</Note>
17 
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 
2020## Pre-install and require plugins
from line 116
116116 
117117A seed also serves users who have no git-host account.
118118 
119<Note>
120 In CI/CD environments, configure a git credential helper before installing plugins from private repositories. On GitHub Actions, export a token with read access to the marketplace repository as `GH_TOKEN`, then run `gh auth setup-git`. The default workflow token can only access the workflow's own repository, so a private marketplace in another repository needs a personal access token or app token.
121</Note>
119> [!NOTE]
120>
121> In CI/CD environments, configure a git credential helper before installing plugins from private repositories. On GitHub Actions, export a token with read access to the marketplace repository as `GH_TOKEN`, then run `gh auth setup-git`. The default workflow token can only access the workflow's own repository, so a private marketplace in another repository needs a personal access token or app token.
122122 
123<Steps>
124 <Step title="Install into the seed at build time">
125 Set `CLAUDE_CODE_PLUGIN_CACHE_DIR` to the seed path so the marketplace and plugins install there instead of `~/.claude/plugins`:
123**1. Install into the seed at build time**
126124 
127 ```bash theme={null}
128 CLAUDE_CODE_PLUGIN_CACHE_DIR=/opt/claude-seed claude plugin marketplace add your-org/your-marketplace
129 CLAUDE_CODE_PLUGIN_CACHE_DIR=/opt/claude-seed claude plugin install code-formatter@your-marketplace
130 ```
125Set `CLAUDE_CODE_PLUGIN_CACHE_DIR` to the seed path so the marketplace and plugins install there instead of `~/.claude/plugins`:
131126 
132 The seed has the same layout as `~/.claude/plugins`: `known_marketplaces.json`, `marketplaces/<name>/`, and `cache/<marketplace>/<plugin>/<version>/`. You can mount the seed at a different path than you built it at.
133 </Step>
127```bash theme={null}
128CLAUDE_CODE_PLUGIN_CACHE_DIR=/opt/claude-seed claude plugin marketplace add your-org/your-marketplace
129CLAUDE_CODE_PLUGIN_CACHE_DIR=/opt/claude-seed claude plugin install code-formatter@your-marketplace
130```
134131 
135 <Step title="Point the runtime at the seed">
136 Set `CLAUDE_CODE_PLUGIN_SEED_DIR=/opt/claude-seed` in the container's environment. To use several seeds, separate their paths with `:` on Unix or `;` on Windows. Claude Code uses the first seed that contains a given marketplace or plugin cache.
137 </Step>
132The seed has the same layout as `~/.claude/plugins`: `known_marketplaces.json`, `marketplaces/<name>/`, and `cache/<marketplace>/<plugin>/<version>/`. You can mount the seed at a different path than you built it at.
138133 
139 <Step title="Enable the plugins">
140 The plugins in a seed aren't enabled on their own. Set `enabledPlugins` for each seed plugin you want loaded, in managed settings or in the repository's `.claude/settings.json`.
141 </Step>
142</Steps>
134**2. Point the runtime at the seed**
135 
136Set `CLAUDE_CODE_PLUGIN_SEED_DIR=/opt/claude-seed` in the container's environment. To use several seeds, separate their paths with `:` on Unix or `;` on Windows. Claude Code uses the first seed that contains a given marketplace or plugin cache.
137 
138**3. Enable the plugins**
139 
140The plugins in a seed aren't enabled on their own. Set `enabledPlugins` for each seed plugin you want loaded, in managed settings or in the repository's `.claude/settings.json`.
143141 
144142To verify a seed, run `claude -p` with `--output-format stream-json --verbose` in the image. In the `init` event's `plugins` list, each loaded plugin's `path` is under the seed, such as `/opt/claude-seed/cache/your-marketplace/code-formatter/1.0.0`.
145143 

plugins/overview Changed · +15 / -19 lines

from line 4
44 
55A Claude Code plugin is a directory of skills, agents, hooks, MCP servers, or other components that Claude Code installs and loads as one unit. Most plugins come from a marketplace, which is a catalog that lists plugins and where to fetch each one. You can also load a plugin from a folder someone gives you, or [build your own](/docs/en/plugins/create).
66 
7<Note>
8 These cases are covered on other pages:
7> [!NOTE]
8>
9> These cases are covered on other pages:
10>
11> * **You use claude.ai chat or Cowork and not Claude Code**: see [Plugins on claude.ai and in Cowork](https://claude.com/docs/plugins/overview)
12> * **You built an MCP server and want it in Anthropic's directory**: see [Publish to the directory](https://claude.com/docs/directory/publish)
13> * **You want Claude Code inside VS Code or a JetBrains IDE**: that's the VS Code extension or the JetBrains plugin, not a Claude Code plugin. See [Use Claude Code in VS Code](/docs/en/vs-code) or [JetBrains IDEs](/docs/en/jetbrains)
914 
10 * **You use claude.ai chat or Cowork and not Claude Code**: see [Plugins on claude.ai and in Cowork](https://claude.com/docs/plugins/overview)
11 * **You built an MCP server and want it in Anthropic's directory**: see [Publish to the directory](https://claude.com/docs/directory/publish)
12 * **You want Claude Code inside VS Code or a JetBrains IDE**: that's the VS Code extension or the JetBrains plugin, not a Claude Code plugin. See [Use Claude Code in VS Code](/docs/en/vs-code) or [JetBrains IDEs](/docs/en/jetbrains)
13</Note>
14 
1515To try a plugin now, run `/plugin` in a Claude Code terminal session and install one from the **Discover** tab, which lists the plugins from your marketplaces. From there:
1616 
1717* [Install and manage plugins](/docs/en/plugins/install): the full install steps, scopes, and other surfaces
from line 30
3030 
3131This diagram shows a plugin named `my-plugin` that holds a skill, an agent, hooks, and an MCP server, and what you get from each file once the plugin loads.
3232 
33<img src="https://mintcdn.com/claude-code/2Q_GtOEovg5qaBem/images/plugin-directory.svg?fit=max&auto=format&n=2Q_GtOEovg5qaBem&q=85&s=f623b64e82713b830e48174f0a922888" className="dark:hidden" alt="Diagram in two columns joined by five straight arrows. Left, the directory of a plugin named my-plugin, holding a manifest at .claude-plugin/plugin.json, skills/review/SKILL.md, agents/reviewer.md, hooks/hooks.json, .mcp.json, and other components. Right, what each file gives you in your session: the manifest sets the plugin name, my-plugin; the skill runs as /my-plugin:review; the agent file is a subagent Claude can delegate to; the hooks file holds hooks that run on lifecycle events; and .mcp.json adds an MCP server that gives Claude tools." width="760" height="336" data-path="images/plugin-directory.svg" />
33![Diagram in two columns joined by five straight arrows. Left, the directory of a plugin named my-plugin, holding a manifest at .claude-plugin/plugin.json, skills/review/SKILL.md, agents/reviewer.md, hooks/hooks.json, .mcp.json, and other components. Right, what each file gives you in your session: the manifest sets the plugin name, my-plugin; the skill runs as /my-plugin:review; the agent file is a subagent Claude can delegate to; the hooks file holds hooks that run on lifecycle events; and .mcp.json adds an MCP server that gives Claude tools.](https://mintcdn.com/claude-code/2Q_GtOEovg5qaBem/images/plugin-directory.svg?fit=max\&auto=format\&n=2Q_GtOEovg5qaBem\&q=85\&s=f623b64e82713b830e48174f0a922888)
3434 
35<img src="https://mintcdn.com/claude-code/2Q_GtOEovg5qaBem/images/plugin-directory-dark.svg?fit=max&auto=format&n=2Q_GtOEovg5qaBem&q=85&s=17ee2bd45b63154fcc148ae1d1f736d8" className="hidden dark:block" alt="Diagram in two columns joined by five straight arrows. Left, the directory of a plugin named my-plugin, holding a manifest at .claude-plugin/plugin.json, skills/review/SKILL.md, agents/reviewer.md, hooks/hooks.json, .mcp.json, and other components. Right, what each file gives you in your session: the manifest sets the plugin name, my-plugin; the skill runs as /my-plugin:review; the agent file is a subagent Claude can delegate to; the hooks file holds hooks that run on lifecycle events; and .mcp.json adds an MCP server that gives Claude tools." width="760" height="336" data-path="images/plugin-directory-dark.svg" />
36 
3735For every component type a plugin can hold, with an example of each, see [Plugin components](/docs/en/plugins/components). To see where each piece is located in a plugin's directory, use the [plugin explorer](/docs/en/plugins/components#explore-the-plugin-directory) on that page.
3836 
3937### Decide whether you need a plugin
from line 58
6058 
6159A marketplace is a repository or directory with a `.claude-plugin/marketplace.json` file that lists plugins and where to fetch each one. It's a catalog, not a hosted store. You add a marketplace once, then install plugins from it by name, such as `commit-commands@claude-plugins-official`.
6260 
63<Note>
64 A plugin marketplace isn't [Claude Marketplace](https://claude.com/marketplace). Claude Marketplace is the website at claude.com/marketplace where you browse plugins, connectors, partner products, and service partners. It isn't a marketplace you add with `/plugin marketplace add`.
65</Note>
61> [!NOTE]
62>
63> A plugin marketplace isn't [Claude Marketplace](https://claude.com/marketplace). Claude Marketplace is the website at claude.com/marketplace where you browse plugins, connectors, partner products, and service partners. It isn't a marketplace you add with `/plugin marketplace add`.
6664 
6765Claude Code adds Anthropic's official marketplace the first time you start an interactive terminal session, unless a [managed policy](/docs/en/plugins/org#allow-the-official-marketplace-and-your-own) blocks it. Claude Code doesn't add Anthropic's community and demo marketplaces on its own. To distinguish the three Anthropic marketplaces, read [Anthropic's marketplaces](/docs/en/plugins/anthropic-marketplaces). To see what the official one lists, open the **Discover** tab of `/plugin` in a session or browse [Claude Marketplace](https://claude.com/marketplace/plugins).
6866 
6967This diagram shows the path from a marketplace to your session. A marketplace lists a plugin, you install that plugin, and Claude Code loads its components.
7068 
71<img src="https://mintcdn.com/claude-code/2Q_GtOEovg5qaBem/images/plugins-model.svg?fit=max&auto=format&n=2Q_GtOEovg5qaBem&q=85&s=4196344954b7c2e27fc0bd6a9a1113a1" className="dark:hidden" alt="Diagram of the marketplace path in three boxes, left to right. A marketplace, a catalog of plugins, lists a plugin. The plugin is one directory installed as a unit, holding skills, agents, hooks, MCP servers, and other components. You install the plugin into Claude Code, which loads its components." width="760" height="252" data-path="images/plugins-model.svg" />
69![Diagram of the marketplace path in three boxes, left to right. A marketplace, a catalog of plugins, lists a plugin. The plugin is one directory installed as a unit, holding skills, agents, hooks, MCP servers, and other components. You install the plugin into Claude Code, which loads its components.](https://mintcdn.com/claude-code/2Q_GtOEovg5qaBem/images/plugins-model.svg?fit=max\&auto=format\&n=2Q_GtOEovg5qaBem\&q=85\&s=4196344954b7c2e27fc0bd6a9a1113a1)
7270 
73<img src="https://mintcdn.com/claude-code/2Q_GtOEovg5qaBem/images/plugins-model-dark.svg?fit=max&auto=format&n=2Q_GtOEovg5qaBem&q=85&s=f6cdefe1fc05daf3b253d26e9f3f70f6" className="hidden dark:block" alt="Diagram of the marketplace path in three boxes, left to right. A marketplace, a catalog of plugins, lists a plugin. The plugin is one directory installed as a unit, holding skills, agents, hooks, MCP servers, and other components. You install the plugin into Claude Code, which loads its components." width="760" height="252" data-path="images/plugins-model-dark.svg" />
74 
7571[Install and manage plugins](/docs/en/plugins/install#install-a-plugin) has the install steps for each place you run Claude Code. While you're developing a plugin, you don't need a marketplace: load it straight from its folder with `--plugin-dir`, as [Develop without a marketplace](/docs/en/plugins/create#develop-without-a-marketplace) shows.
7672 
7773### Make an installed plugin available in your session
from line 104
108104 
109105A cloud session, including one in the browser at claude.ai/code, doesn't load the plugins in your local settings. For install steps in the terminal, VS Code, and the desktop app, and for what a cloud session loads, see [Install a plugin](/docs/en/plugins/install#install-a-plugin).
110106 
111<Note>
112 The same plugin format also installs on claude.ai and in Cowork, where a different set of components loads. For those surfaces, see [Plugins on claude.ai and in Cowork](https://claude.com/docs/plugins/overview) on claude.com and its [component support table](https://claude.com/docs/plugins/platform-support#compare-component-support-by-app).
113</Note>
107> [!NOTE]
108>
109> The same plugin format also installs on claude.ai and in Cowork, where a different set of components loads. For those surfaces, see [Plugins on claude.ai and in Cowork](https://claude.com/docs/plugins/overview) on claude.com and its [component support table](https://claude.com/docs/plugins/platform-support#compare-component-support-by-app).
114110 
115111## Next steps
116112 

plugins/publish Changed · +42 / -48 lines

## Submit to Anthropic's directory

from line 6
66 
77This page is for the author of a working plugin who is ready to share it.
88 
9<Note>
10 These cases are covered on other pages:
9> [!NOTE]
10>
11> These cases are covered on other pages:
12>
13> * **Your plugin isn't finished yet**: start with [Create a plugin](/docs/en/plugins/create)
14> * **You maintain a CLI or SDK with a plugin in an official marketplace**: see [Recommend your plugin from your CLI](/docs/en/plugins/cli-hints)
1115 
12 * **Your plugin isn't finished yet**: start with [Create a plugin](/docs/en/plugins/create)
13 * **You maintain a CLI or SDK with a plugin in an official marketplace**: see [Recommend your plugin from your CLI](/docs/en/plugins/cli-hints)
14</Note>
15 
1616Start with [Choose how to distribute](#choose-how-to-distribute) to compare the distribution options. If you already know your route, go to [Prepare your plugin for release](#prepare-your-plugin-for-release), then follow your route's section for what to tell your users and how they receive your updates.
1717 
1818## Choose how to distribute
from line 31
3131 
3232The name, the version, validation, and an install from a marketplace decide whether a release works for the people who install it. Check them before the first release and again before each later one.
3333 
34<Steps>
35 <Step title="Choose a permanent name">
36 Users install, enable, and configure your plugin by `name@marketplace`, so a renamed plugin is a different plugin to every existing install. Choose a kebab-case name such as `deploy-helper`, because `claude plugin validate` warns on other forms, and treat it as permanent. Set `displayName` in `plugin.json` for the label users see.
37 </Step>
34**1. Choose a permanent name**
3835 
39 <Step title="Decide how you'll version">
40 If you set `version` in `plugin.json` and later push commits without changing it, `claude plugin update` prints `<name> is already at the latest version (1.0.0).` and users keep the old copy. Either increment `version` on every release, or omit it in a git-hosted marketplace so Claude Code uses the commit SHA instead. See [Versions and updates](/docs/en/plugins/loading#versions-and-updates).
41 </Step>
36Users install, enable, and configure your plugin by `name@marketplace`, so a renamed plugin is a different plugin to every existing install. Choose a kebab-case name such as `deploy-helper`, because `claude plugin validate` warns on other forms, and treat it as permanent. Set `displayName` in `plugin.json` for the label users see.
4237 
43 <Step title="Validate">
44 In your shell, run `claude plugin validate --strict ./your-plugin`. A clean run prints `✔ Validation passed`.
38**2. Decide how you'll version**
4539 
46 * **In CI**: keep `--strict`, which also fails the run with exit code 1 on warnings such as an unknown manifest field or a missing `version`. Drop `--strict` if you chose to omit `version` in the previous step.
47 * **Paths**: validation reports component paths that don't start with `./`. Inside hook commands and MCP server configs, refer to files as `${CLAUDE_PLUGIN_ROOT}/...`. See [path rules](/docs/en/plugins/manifest-reference#path-rules).
48 </Step>
40If you set `version` in `plugin.json` and later push commits without changing it, `claude plugin update` prints `<name> is already at the latest version (1.0.0).` and users keep the old copy. Either increment `version` on every release, or omit it in a git-hosted marketplace so Claude Code uses the commit SHA instead. See [Versions and updates](/docs/en/plugins/loading#versions-and-updates).
4941 
50 <Step title="Install it from a local marketplace">
51 In your shell, add a local marketplace that lists the plugin with `claude plugin marketplace add ./path-to-marketplace`, install the plugin from it, and start a session to confirm it loads.
42**3. Validate**
5243 
53 * For the smallest marketplace that works, see [Create a marketplace](/docs/en/plugins/create-marketplace).
54 * To know whether an install loads your source directory or a cached copy, see [In-place and copied plugins](/docs/en/plugins/loading#in-place-and-copied-plugins).
55 </Step>
44In your shell, run `claude plugin validate --strict ./your-plugin`. A clean run prints `✔ Validation passed`.
5645 
57 <Step title="Fill in the metadata users see">
58 Set `description`, `author`, `homepage`, and `repository` in `plugin.json`, and add a `README.md` at the plugin root. `homepage` must parse as a URL. The [manifest reference](/docs/en/plugins/manifest-reference#fields) lists every field.
59 </Step>
46* **In CI**: keep `--strict`, which also fails the run with exit code 1 on warnings such as an unknown manifest field or a missing `version`. Drop `--strict` if you chose to omit `version` in the previous step.
47* **Paths**: validation reports component paths that don't start with `./`. Inside hook commands and MCP server configs, refer to files as `${CLAUDE_PLUGIN_ROOT}/...`. See [path rules](/docs/en/plugins/manifest-reference#path-rules).
6048 
61 <Step title="Run your eval suite">
62 If you have an eval suite, run `claude plugin eval` in your shell. It runs the plugin's test cases and scores the results, which catches regressions when you change the plugin. See [Test plugins with evals](/docs/en/plugin-evals).
63 </Step>
64</Steps>
49**4. Install it from a local marketplace**
6550 
51In your shell, add a local marketplace that lists the plugin with `claude plugin marketplace add ./path-to-marketplace`, install the plugin from it, and start a session to confirm it loads.
52 
53* For the smallest marketplace that works, see [Create a marketplace](/docs/en/plugins/create-marketplace).
54* To know whether an install loads your source directory or a cached copy, see [In-place and copied plugins](/docs/en/plugins/loading#in-place-and-copied-plugins).
55 
56**5. Fill in the metadata users see**
57 
58Set `description`, `author`, `homepage`, and `repository` in `plugin.json`, and add a `README.md` at the plugin root. `homepage` must parse as a URL. The [manifest reference](/docs/en/plugins/manifest-reference#fields) lists every field.
59 
60**6. Run your eval suite**
61 
62If you have an eval suite, run `claude plugin eval` in your shell. It runs the plugin's test cases and scores the results, which catches regressions when you change the plugin. See [Test plugins with evals](/docs/en/plugin-evals).
63 
6664## Share a plugin without a marketplace
6765 
6866If the plugin is in a git repository, people can clone it and load the checkout, or start Claude Code from their shell with `--plugin-url` pointed at a `.zip` you attach to a release. To get your next version they pull or download again. If it isn't in a repository, send them the directory or a `.zip` of it. They load it in one of two ways:
from line 118
120118 
121119[Install plugins](/docs/en/plugins/install) covers the user-side commands, and [when auto-update runs](/docs/en/plugins/loading#when-auto-update-runs) covers the timing.
122120 
123<h2 id="submit-to-anthropics-directory">
124 Submit to Anthropic's directory
125</h2>
121## Submit to Anthropic's directory
126122 
127123[Anthropic's directory](https://claude.ai/directory) is the catalog people browse on claude.ai and in Cowork to add plugins and connectors. One listing there reaches people on claude.ai, in Cowork, and in Claude Code. You submit from the developer portal at [claude.ai/directory/manage](https://claude.ai/directory/manage), and [Submit a plugin](https://claude.com/docs/plugins/submit#submit-a-plugin) on claude.com walks through the portal.
128124 
from line 126
130126 
131127To submit a plugin:
132128 
133<Steps>
134 <Step title="Confirm you can submit">
135 Submitting requires a paid claude.ai plan. On Pro and Max you submit from your own account. On Team and Enterprise, an Owner can submit, and on Enterprise an Owner can also grant the **Directory** permission to other members through a custom role under **Organization settings > Roles**. See [Confirm you can submit to the directory](https://claude.com/docs/directory/publish#confirm-you-can-submit-to-the-directory).
136 </Step>
129**1. Confirm you can submit**
137130 
138 <Step title="Validate the plugin locally">
139 Run `claude plugin validate ./your-plugin --strict` in your shell. Replace `./your-plugin` with the path to your plugin directory. The command catches manifest errors locally; [plugin validate](/docs/en/plugins/cli-reference#plugin-validate) lists which files each run reads. The portal applies additional directory rules that the CLI doesn't check, so a clean local run doesn't guarantee a clean portal validation.
131Submitting requires a paid claude.ai plan. On Pro and Max you submit from your own account. On Team and Enterprise, an Owner can submit, and on Enterprise an Owner can also grant the **Directory** permission to other members through a custom role under **Organization settings > Roles**. See [Confirm you can submit to the directory](https://claude.com/docs/directory/publish#confirm-you-can-submit-to-the-directory).
140132 
141 The [plugin pre-submission checklist](https://claude.com/docs/plugins/pre-submission-checklist#run-the-checks-before-you-submit) on claude.com has the checks to run and fix before you submit.
142 </Step>
133**2. Validate the plugin locally**
143134 
144 <Step title="Check what loads where">
145 Some plugin components are Claude Code-only and don't load on claude.ai or in Cowork. The [component support table](https://claude.com/docs/plugins/platform-support#compare-component-support-by-app) lists each component by app, so you know what users outside Claude Code will get.
146 </Step>
135Run `claude plugin validate ./your-plugin --strict` in your shell. Replace `./your-plugin` with the path to your plugin directory. The command catches manifest errors locally; [plugin validate](/docs/en/plugins/cli-reference#plugin-validate) lists which files each run reads. The portal applies additional directory rules that the CLI doesn't check, so a clean local run doesn't guarantee a clean portal validation.
147136 
148 <Step title="Submit in the developer portal">
149 Open the developer portal at [claude.ai/directory/manage](https://claude.ai/directory/manage) and follow [Submit a plugin](https://claude.com/docs/plugins/submit#submit-a-plugin) on claude.com.
150 </Step>
151</Steps>
137The [plugin pre-submission checklist](https://claude.com/docs/plugins/pre-submission-checklist#run-the-checks-before-you-submit) on claude.com has the checks to run and fix before you submit.
138 
139**3. Check what loads where**
140 
141Some plugin components are Claude Code-only and don't load on claude.ai or in Cowork. The [component support table](https://claude.com/docs/plugins/platform-support#compare-component-support-by-app) lists each component by app, so you know what users outside Claude Code will get.
142 
143**4. Submit in the developer portal**
144 
145Open the developer portal at [claude.ai/directory/manage](https://claude.ai/directory/manage) and follow [Submit a plugin](https://claude.com/docs/plugins/submit#submit-a-plugin) on claude.com.
152146 
153147The rest of the process is documented on claude.com:
154148 

plugins/relevance Changed · +6 / -6 lines

from line 6
66 
77A marketplace operator writes the `relevance` entries. An administrator then allowlists the marketplace in managed settings. Users see no suggestions from a marketplace until it's allowlisted.
88 
9<Note>
10 These cases are covered on other pages:
11 
12 * **You want to install plugins**: see [Install and manage plugins](/docs/en/plugins/install)
13 * **You want to turn suggestions off**: see [Understand how plugin relevance works](#understand-how-plugin-relevance-works)
14</Note>
9> [!NOTE]
10>
11> These cases are covered on other pages:
12>
13> * **You want to install plugins**: see [Install and manage plugins](/docs/en/plugins/install)
14> * **You want to turn suggestions off**: see [Understand how plugin relevance works](#understand-how-plugin-relevance-works)
1515 
1616Start with the sections for your role:
1717 

plugins/security Changed · +24 / -28 lines

## Identify Anthropic's marketplaces by name

from line 8
88 
99Read this page if you're deciding whether to install a plugin, or if you review tools before your team can use them.
1010 
11<Note>
12 These cases are covered on other pages:
11> [!NOTE]
12>
13> These cases are covered on other pages:
14>
15> * **Claude Code's own security model**: see [Security](/docs/en/security)
16> * **Restricting or requiring plugins for an organization**: see [Manage plugins for your organization](/docs/en/plugins/org)
17> * **The `security-guidance` or `claude-security` plugins**: this page isn't about them. See [`security-guidance`](/docs/en/security-guidance) and [`claude-security`](/docs/en/claude-security)
1318 
14 * **Claude Code's own security model**: see [Security](/docs/en/security)
15 * **Restricting or requiring plugins for an organization**: see [Manage plugins for your organization](/docs/en/plugins/org)
16 * **The `security-guidance` or `claude-security` plugins**: this page isn't about them. See [`security-guidance`](/docs/en/security-guidance) and [`claude-security`](/docs/en/claude-security)
17</Note>
18 
1919Start with [what a plugin can do](#understand-what-a-plugin-can-do) and [which marketplaces are Anthropic's](#marketplace-tiers), then [review the plugin before you install it](#review-a-plugin-before-you-install).
2020 
2121## Understand what a plugin can do
from line 26
2626* **Monitors**: a plugin's [monitors](/docs/en/plugins/components#monitors) run as background shell commands that Claude Code starts on its own when the session starts, when you reload plugins, or the first time a named skill runs.
2727* **Mods**: a plugin's [mod](/docs/en/plugins/mods/overview) runs JavaScript inside Claude Code with your permissions. To list what a mod does before you install it, see [Decide whether to trust a mod](/docs/en/plugins/mods/overview#decide-whether-to-trust-a-mod).
2828* **MCP and LSP servers**: Claude Code connects to the [MCP servers](/docs/en/mcp) an enabled plugin declares and gives Claude their tools. A stdio MCP server runs as a process that Claude Code starts on your machine. Claude Code also starts the language servers the plugin declares.
29* **`bin/` directory**: Claude Code adds each enabled plugin's `bin/` directory to the `PATH` of the Bash tool's shell, so Claude's Bash commands can run any executable there.
29* **`bin/` directory**: Claude Code adds each enabled plugin's `bin/` directory to the `PATH` of the Bash tool's shell, so Claude's Bash commands can run any executable there. A command that Claude runs with the [PowerShell tool](/docs/en/tools-reference#powershell-tool) gets those directories on its `PATH` when it runs outside the [sandbox](/docs/en/sandboxing), and not when it runs inside it.
3030* **Skills, commands, and agents**: these enter Claude's context as instructions, so they influence what Claude does with the tools it already has.
3131* **Updates**: when auto-update is on for the marketplace you installed a plugin from, Claude Code updates that plugin in the background, so the files you reviewed can change on disk. [When auto-update runs](/docs/en/plugins/loading#when-auto-update-runs) has the timing. To turn auto-update on or off per marketplace, see [Keep plugins updated](/docs/en/plugins/install#keep-plugins-updated).
3232 
from line 39
3939 
4040To remove a plugin you no longer trust, see [Remove a plugin you no longer trust](#remove-a-plugin-you-no-longer-trust).
4141 
42<h2 id="marketplace-tiers">
43 Identify Anthropic's marketplaces by name
44</h2>
42## Identify Anthropic's marketplaces by name
4543 
4644A marketplace's name places it in one of three tiers: official, community, or third-party. Claude Code accepts the official and community names only for marketplaces sourced from `github.com/anthropics/` repositories, so a third-party marketplace can't present itself as an Anthropic one. A marketplace that a coworker or your organization publishes is third-party.
4745 
from line 78
8078 
8179Before you install a plugin, look at what it adds and where it comes from.
8280 
83<Steps>
84 <Step title="Check the marketplace's source">
85 In your shell, run `claude plugin marketplace list` to print the source each marketplace was added from, such as a GitHub repository or a directory.
86 </Step>
81**1. Check the marketplace's source**
8782 
88 <Step title="Read the details pane">
89 In a Claude Code session, run `/plugin` and select the plugin. The details pane shows a **Will install** section listing the plugin's commands, agents, skills, hooks, and MCP and LSP servers. For a plugin Anthropic has no published component data for, the section shows what the marketplace entry declares, or a note: `Components will be discovered at installation` for a plugin stored inside the marketplace, or `Component summary not available for remote plugin` for one fetched from elsewhere.
90 </Step>
83In your shell, run `claude plugin marketplace list` to print the source each marketplace was added from, such as a GitHub repository or a directory.
9184 
92 <Step title="Read the plugin's source">
93 In the details pane, select **Open homepage** or **View on GitHub** below the install options. If the pane offers neither, open the marketplace repository you found in the first step. Find the plugin's directory there. The **Will install** section shows that a hook exists but not what it runs, so read these files in the plugin's directory:
85**2. Read the details pane**
9486 
95 * **`hooks/hooks.json`**: the command each hook runs
96 * **`.mcp.json`**: each server's command or URL
97 * **`bin/`**: every file in the directory
98 </Step>
87In a Claude Code session, run `/plugin` and select the plugin. The details pane shows a **Will install** section listing the plugin's commands, agents, skills, hooks, and MCP and LSP servers. For a plugin Anthropic has no published component data for, the section shows what the marketplace entry declares, or a note: `Components will be discovered at installation` for a plugin stored inside the marketplace, or `Component summary not available for remote plugin` for one fetched from elsewhere.
9988 
100 <Step title="List what the plugin contains">
101 Clone the repository that holds the plugin's directory, then run `claude --plugin-dir <plugin directory> plugin details <plugin name>` in your shell to see what Claude Code finds in it. The command reads the plugin's files without starting a session and prints a `Component inventory` listing the plugin's skills and commands, agents, hooks with each hook's event, and MCP and LSP servers.
102 </Step>
103</Steps>
89**3. Read the plugin's source**
90 
91In the details pane, select **Open homepage** or **View on GitHub** below the install options. If the pane offers neither, open the marketplace repository you found in the first step. Find the plugin's directory there. The **Will install** section shows that a hook exists but not what it runs, so read these files in the plugin's directory:
92 
93* **`hooks/hooks.json`**: the command each hook runs
94* **`.mcp.json`**: each server's command or URL
95* **`bin/`**: every file in the directory
96 
97**4. List what the plugin contains**
98 
99Clone the repository that holds the plugin's directory, then run `claude --plugin-dir <plugin directory> plugin details <plugin name>` in your shell to see what Claude Code finds in it. The command reads the plugin's files without starting a session and prints a `Component inventory` listing the plugin's skills and commands, agents, hooks with each hook's event, and MCP and LSP servers.
104100 
105101After you install a plugin, run `claude plugin details <plugin name>` in your shell to print the same `Component inventory` for the installed copy under `~/.claude/plugins/cache/<marketplace>/<plugin>/<version>/`.
106102 

plugins/troubleshooting Changed · +192 / -304 lines

### `/plugin isn't available in this environment` ### `zsh: no such file or directory: /plugin` ### `The term '/plugin' is not recognized as the name of a cmdlet` ### `claude: command not found` after `claude plugin ...` ### `Unknown command` and command spellings that don't exist ### `Marketplace "claude-plugins-official" not found` ### `Marketplace "<name>" not found` ### `Invalid marketplace source format` ### `'<source>' is not a valid GitHub owner/repo shorthand` ### `Invalid git URL` ### `Path does not exist: <path>` ### `Marketplace file not found at <path>/.claude-plugin/marketplace.json` ### `Cannot add marketplace "<name>": Claude Code cannot install plugins from a marketplace with this name` ### `Cannot add marketplace "<name>": Claude Code reserves this name and cannot register a marketplace under it` ### `SSH authentication failed` or `HTTPS authentication failed` ### `SSH host key is not in your known_hosts file` ### `Command 'git' not found or is in an unsafe location` ### `Git clone timed out after 120s` ### Marketplace updates keep failing offline ### Marketplace add fails on a GitHub Enterprise Server host ### `Plugin "<name>" not found in marketplace "<marketplace>"` #### `not found in marketplace` with a refresh hint #### `not found in marketplace` with no hint ### `Plugin "<name>" not found in any marketplace` ### `Plugin '<name>@<marketplace>' is already installed globally` ### `"<plugin>" was not installed: it would share its folder with "<other>"` ### `This plugin uses a source type your Claude Code version does not support` ### `Plugin archive integrity check failed` ### `An npm plugin source must name a registry package` ### `Marketplace "<name>" is registered from an untrusted source` ### `Marketplace "<name>" is added but ignored` ### `Plugin <name> has a corrupt manifest file` or `has an invalid manifest file` ### `Plugin directory not found at path: <path>` ### `No plugins available` or `No marketplaces configured` ### `Marketplace "<name>" is already added from a different source` ### `Cannot add marketplace "<name>": its source doesn't match its extraKnownMarketplaces entry in user or managed settings` ### `Failed to install: <plugin> (<reason>)` ### `Could not move the new copy of this plugin version into <path>` ### Dependency errors ### Plugin doesn't appear or its skills don't show up ### `Run /reload-plugins to apply.` ### `The packages it lists are not installed` or `were not installed, because ...` ### `Plugin "<name>" not cached at <path>` ### `installed_plugins.json holds a record under "<id>" that this version of Claude Code cannot read` ### `installed_plugins.json could not be read and was rebuilt` ### `install records under names that no version of Claude Code can use were removed from installed_plugins.json` ### `does not load (...), so Claude Code ignores the whole file` ### `Disabled in ~/.claude/settings.json but still loads` ### `Plugin "<name>" is enabled in project settings but isn't installed here` ### A plugin stays installed after `plugin uninstall` on Windows ### A plugin installed from a git repository shows version `unknown` ### `Failed to load hooks from <path>` and hooks that don't fire ### `Plugin directory does not exist: <path>` ### `Invalid MCP server config for "<server>"` and MCP servers that don't start ### Language server doesn't start, uses too much memory, or reports wrong diagnostics ### `commands path not found: <path>` ### `--plugin-dir` at a marketplace root doesn't load the plugins under `plugins/` ### Files the plugin references outside its directory aren't found ### `${CLAUDE_PLUGIN_ROOT}` shows forward slashes on Windows ### Plugin loads but its skills are missing ### Skill loads but Claude never invokes the skill ### `<directory> is not a plugin or skill folder` from `claude plugin eval init` ### The `userConfig` dialog never appears ### `claude plugin validate` reports errors ### `Plugin <name> has conflicting manifests` ### `Warning: No commands found in plugin <name> custom directory` ### Plugins with relative paths fail in URL-based marketplaces ### Marketplace validation errors ### `Marketplace source '<source>' is blocked by enterprise policy` ### `Marketplace "<name>" is not in the allowed marketplace list` ### `Plugin "<name>" is blocked by your organization's policy and cannot be installed` ### `--plugin-dir is disabled by your organization's managed settings (disableSideloadFlags)` ### `Plugins from ~/.claude/skills/ are blocked by your organization's managed settings` ### `Command-sourced plugins are disabled by your organization's managed settings` ### `Marketplace '<name>' is seed-managed`

The two sides of this change are more than 400 edits apart, too far apart to line up, so this is the differ's own diff of it and the words inside a line are not marked.

from line 8
88 
99Use this page whether you install plugins, build them, host a marketplace, or administer plugins for an organization.
1010 
11<Note>
12 These cases are covered on other pages:
13 
14 * **Why scopes, the cache, and precedence behave the way they do**: read [Plugin loading reference](/docs/en/plugins/loading)
15 * **Looking up a flag, field, or command**: use the [plugin commands reference](/docs/en/plugins/cli-reference), the [manifest reference](/docs/en/plugins/manifest-reference), or the [marketplace reference](/docs/en/plugins/marketplace-reference)
16 * **A `hooks module not loaded` or `hooks module did not load` message**: the plugin is a [mod](/docs/en/plugins/mods/overview), so read [The mod doesn't load](/docs/en/plugins/mods/troubleshoot#the-mod-doesn’t-load)
17</Note>
11> [!NOTE]
12>
13> These cases are covered on other pages:
14>
15> * **Why scopes, the cache, and precedence behave the way they do**: read [Plugin loading reference](/docs/en/plugins/loading)
16> * **Looking up a flag, field, or command**: use the [plugin commands reference](/docs/en/plugins/cli-reference), the [manifest reference](/docs/en/plugins/manifest-reference), or the [marketplace reference](/docs/en/plugins/marketplace-reference)
17> * **A `hooks module not loaded` or `hooks module did not load` message**: the plugin is a [mod](/docs/en/plugins/mods/overview), so read [The mod doesn't load](/docs/en/plugins/mods/troubleshoot#the-mod-doesn’t-load)
1818 
1919Search for the exact message you saw. Each message is listed under the stage that produces it, which isn't always the command you ran. For example, an install can fail because a marketplace is missing, so that message is under [Add a marketplace](#add-a-marketplace).
2020 
from line 22
2222 
2323`/plugin` is a command you type inside a running Claude Code terminal session, and it opens an interactive panel. The entries in this section cover the places where you can type it but it can't run, and the command spellings that don't exist.
2424 
25<h3 id="plugin-isnt-available-in-this-environment">
26 `/plugin isn't available in this environment`
27</h3>
25### `/plugin isn't available in this environment`
2826 
2927You typed `/plugin` somewhere other than a Claude Code terminal session, and Claude replied with this line instead of opening anything.
3028 
from line 39
4139 
4240When a terminal install works, `/plugin` prints an install summary that starts with `✓ Installed <plugin>.` and `claude plugin install` prints `Successfully installed plugin: <plugin>@<marketplace>`.
4341 
44<h3 id="zsh-no-such-file-or-directory-plugin">
45 `zsh: no such file or directory: /plugin`
46</h3>
42### `zsh: no such file or directory: /plugin`
4743 
4844You typed `/plugin ...` at a shell prompt, and the shell reported that no file named `/plugin` exists. Bash reports `bash: /plugin: No such file or directory`.
4945 
from line 59
6359 
6460To install from the shell without starting a session, run `claude plugin install <plugin>@<marketplace>` instead.
6561 
66<h3 id="the-term-plugin-is-not-recognized-as-the-name-of-a-cmdlet">
67 `The term '/plugin' is not recognized as the name of a cmdlet`
68</h3>
62### `The term '/plugin' is not recognized as the name of a cmdlet`
6963 
7064You typed `/plugin ...` at a PowerShell prompt, and `/plugin` is a Claude Code command, not a program. Bash and Zsh report [their own form of this error](#zsh-no-such-file-or-directory-plugin).
7165 
from line 68
7468* Run `claude`, then type `/plugin` at the Claude Code prompt
7569* Run `claude plugin install <plugin>@<marketplace>` in PowerShell without starting a session
7670 
77<h3 id="claude-command-not-found-after-claude-plugin">
78 `claude: command not found` after `claude plugin ...`
79</h3>
71### `claude: command not found` after `claude plugin ...`
8072 
8173You ran `claude plugin install ...` in your shell, and the shell couldn't find `claude` at all. On Windows the message is `'claude' is not recognized as the name of a cmdlet` or `'claude' is not recognized as an internal or external command`.
8274 
8375The cause isn't the plugin command. Follow [Verify your PATH](/docs/en/troubleshoot-install#verify-your-path), then retry the plugin command.
8476 
85<h3 id="unknown-command-and-command-spellings-that-dont-exist">
86 `Unknown command` and command spellings that don't exist
87</h3>
77### `Unknown command` and command spellings that don't exist
8878 
8979You typed a plugin command you saw somewhere and got `Unknown command: /<name>` in a session, or `error: unknown command '<name>'` or `error: unknown option '<flag>'` from the `claude` binary in your shell.
9080 
from line 98
10898 
10999A marketplace is a catalog you add to Claude Code from a git repository, a URL, or a local path. These entries cover the messages you get when adding one fails or a later refresh fails.
110100 
111<h3 id="marketplace-claude-plugins-official-not-found">
112 `Marketplace "claude-plugins-official" not found`
113</h3>
101### `Marketplace "claude-plugins-official" not found`
114102 
115103You ran `/plugin install <plugin>@claude-plugins-official` in a session, and Claude Code reported that it has no marketplace by that name.
116104 
from line 122
134122 
135123The same string also appears in the `/plugin` **Errors** tab, the panel's list of load failures, when a plugin listed in your settings names a marketplace you haven't added.
136124 
137<h3 id="marketplace-not-found">
138 `Marketplace "<name>" not found`
139</h3>
125### `Marketplace "<name>" not found`
140126 
141127You ran `/plugin install` in a session and Claude Code reported that it has no marketplace by that name. Two forms of the command reach this message:
142128 
from line 137
151137 
152138If you already added the marketplace, check the spelling against `/plugin marketplace list`.
153139 
154<h3 id="invalid-marketplace-source-format">
155 `Invalid marketplace source format`
156</h3>
140### `Invalid marketplace source format`
157141 
158142You ran `/plugin marketplace add <source>`, `claude plugin marketplace add <source>`, or `claude plugin install <plugin> --marketplace <source>`, and Claude Code replied `Invalid marketplace source format. Try: owner/repo, https://..., or ./path`.
159143 
from line 158
174158 
175159Claude Code prints `Successfully added marketplace: <name>` when the add works.
176160 
177<h3 id="is-not-a-valid-github-owner-repo-shorthand">
178 `'<source>' is not a valid GitHub owner/repo shorthand`
179</h3>
161### `'<source>' is not a valid GitHub owner/repo shorthand`
180162 
181163You passed a source with a slash that isn't `owner/repo`, such as `github.com/owner/repo` or a `gitlab.example.com/group/project` path. Claude Code refused it with this message and a list of accepted forms.
182164 
from line 176
194176 
195177A successful add prints `Successfully added marketplace: <name>`.
196178 
197<h3 id="invalid-git-url">
198 `Invalid git URL`
199</h3>
179### `Invalid git URL`
200180 
201181You added a marketplace, installed a plugin, or ran an update from a git address, and the command failed with `Invalid git URL` in its message.
202182 
from line 186
206186 
207187A refusal that instead says `is blocked by enterprise policy` comes from your organization's settings. See [Marketplace source is blocked by enterprise policy](#marketplace-source-is-blocked-by-enterprise-policy).
208188 
209<h3 id="path-does-not-exist">
210 `Path does not exist: <path>`
211</h3>
189### `Path does not exist: <path>`
212190 
213191You passed a local path to `marketplace add`, and nothing exists at that path. A relative path resolves against your current directory.
214192 
from line 194
216194 
217195Claude Code accepts a directory that contains `.claude-plugin/marketplace.json`, or a path to a `.json` file. A path to any other file fails with `File path must point to a .json file (marketplace.json)`.
218196 
219<h3 id="marketplace-file-not-found-at-claude-plugin-marketplace-json">
220 `Marketplace file not found at <path>/.claude-plugin/marketplace.json`
221</h3>
197### `Marketplace file not found at <path>/.claude-plugin/marketplace.json`
222198 
223199Claude Code cloned or downloaded the marketplace but found no `marketplace.json` at the expected path inside it. The add command reports it as `Failed to add marketplace: Marketplace file not found at ...`.
224200 
from line 205
229205* **You own the marketplace**: put the file at that location and re-add the marketplace
230206* **Someone else hosts it**: ask the owner for the exact source they publish
231207 
232<h3 id="cannot-install-plugins-from-a-marketplace-with-this-name">
233 `Cannot add marketplace "<name>": Claude Code cannot install plugins from a marketplace with this name`
234</h3>
208### `Cannot add marketplace "<name>": Claude Code cannot install plugins from a marketplace with this name`
235209 
236210You added a marketplace, and the [`name`](/docs/en/plugins/marketplace-reference#top-level-fields) in its `marketplace.json` isn't valid as the part after `@` in a [plugin id](/docs/en/plugins/loading#find-where-a-plugin-came-from) such as `my-plugin@my-marketplace`. Claude Code refuses the add and registers nothing.
237211 
from line 222
248222 
249223Before v2.1.295, Claude Code reported the add in this example as successful.
250224 
251<h3 id="claude-code-reserves-this-name">
252 `Cannot add marketplace "<name>": Claude Code reserves this name and cannot register a marketplace under it`
253</h3>
225### `Cannot add marketplace "<name>": Claude Code reserves this name and cannot register a marketplace under it`
254226 
255227You added a marketplace, and the [`name`](/docs/en/plugins/marketplace-reference#top-level-fields) in its `marketplace.json` is one of the member names that every JavaScript object has, such as `constructor`, `toString`, or `valueOf`. Claude Code reserves those names, so it refuses the add and registers nothing. [Reserved names](/docs/en/plugins/marketplace-reference#reserved-names) lists them.
256228 
from line 241
269241 
270242Before v2.1.296, adding such a marketplace failed with an internal error in place of this message.
271243 
272<h3 id="ssh-authentication-failed-or-https-authentication-failed">
273 `SSH authentication failed` or `HTTPS authentication failed`
274</h3>
244### `SSH authentication failed` or `HTTPS authentication failed`
275245 
276246You added or updated a marketplace from a git repository, and the clone failed with `Failed to clone marketplace repository:` followed by one of these lines.
277247 
from line 258
288258 
289259For what background auto-updates can and can't do with your credentials, see [What background auto-update does with credentials](/docs/en/plugins/host-marketplace#what-background-auto-update-does-with-credentials).
290260 
291<h3 id="ssh-host-key-is-not-in-your-known-hosts-file">
292 `SSH host key is not in your known_hosts file`
293</h3>
261### `SSH host key is not in your known_hosts file`
294262 
295263You added a marketplace over SSH from a host you've never connected to, and the clone failed with this line and a `ssh -T git@<host>` hint. For a host whose key changed, the message is `SSH host key has changed` with a `ssh-keygen -R <host>` hint instead.
296264 
from line 270
302270 
303271For a public repository, add the marketplace by its `https://` URL instead to avoid SSH entirely.
304272 
305<h3 id="command-git-not-found-or-is-in-an-unsafe-location">
306 `Command 'git' not found or is in an unsafe location`
307</h3>
273### `Command 'git' not found or is in an unsafe location`
308274 
309275On Windows, you added a marketplace and Claude Code reported `Failed to clone marketplace repository: Command 'git' not found or is in an unsafe location (current directory)`.
310276 
311277Claude Code looks for `git` on your `PATH` and refuses to run one found only in the current directory. To fix it, install Git and retry:
312278 
313<Steps>
314 <Step title="Install Git for Windows">
315 Install Git for Windows so that `git` is on your `PATH`.
316 </Step>
317 
318 <Step title="Open a new terminal">
319 Open a new terminal so the updated `PATH` applies.
320 </Step>
321 
322 <Step title="Confirm git runs">
323 Confirm `git --version` prints a version.
324 </Step>
325 
326 <Step title="Retry the add">
327 Run the `marketplace add` command again.
328 </Step>
329</Steps>
330 
331<h3 id="git-clone-timed-out-after-120s">
332 `Git clone timed out after 120s`
333</h3>
279**1. Install Git for Windows**
280 
281Install Git for Windows so that `git` is on your `PATH`.
282 
283**2. Open a new terminal**
284 
285Open a new terminal so the updated `PATH` applies.
286 
287**3. Confirm git runs**
288 
289Confirm `git --version` prints a version.
290 
291**4. Retry the add**
292 
293Run the `marketplace add` command again.
294 
295### `Git clone timed out after 120s`
334296 
335297You added or updated a marketplace, and it failed with `Git clone timed out after 120s`, followed by a hint to set `CLAUDE_CODE_PLUGIN_GIT_TIMEOUT_MS`.
336298 
337299Cloning a marketplace, and re-cloning one to update it, gets 120 seconds by default. For a large repository or a slow connection, raise the limit. The value is in milliseconds:
338300 
339<Tabs>
340 <Tab title="Bash or Zsh">
341 ```bash theme={null}
342 export CLAUDE_CODE_PLUGIN_GIT_TIMEOUT_MS=300000
343 ```
344 </Tab>
345 
346 <Tab title="PowerShell">
347 ```powershell theme={null}
348 $env:CLAUDE_CODE_PLUGIN_GIT_TIMEOUT_MS = "300000"
349 ```
350 </Tab>
351</Tabs>
301**Bash or Zsh**
302 
303```bash theme={null}
304export CLAUDE_CODE_PLUGIN_GIT_TIMEOUT_MS=300000
305```
306 
307**PowerShell**
308 
309```powershell theme={null}
310$env:CLAUDE_CODE_PLUGIN_GIT_TIMEOUT_MS = "300000"
311```
352312 
353313Then retry in the same shell.
354314 
355315If the repository is a monorepo, limit the checkout to the directories you name with `claude plugin marketplace add <source> --sparse <paths>`.
356316 
357<h3 id="marketplace-updates-keep-failing-offline">
358 Marketplace updates keep failing offline
359</h3>
317### Marketplace updates keep failing offline
360318 
361319You work in an environment where the marketplace's git host is unreachable, and every session repeats a failed refresh in the background. Your existing checkout of the marketplace stays in place and startup isn't delayed.
362320 
from line 322
364322 
365323Set this variable to skip the re-clone attempt and keep using the existing checkout when the check can't reach the host:
366324 
367<Tabs>
368 <Tab title="Bash or Zsh">
369 ```bash theme={null}
370 export CLAUDE_CODE_PLUGIN_KEEP_MARKETPLACE_ON_FAILURE=1
371 ```
372 </Tab>
373 
374 <Tab title="PowerShell">
375 ```powershell theme={null}
376 $env:CLAUDE_CODE_PLUGIN_KEEP_MARKETPLACE_ON_FAILURE = "1"
377 ```
378 </Tab>
379</Tabs>
325**Bash or Zsh**
326 
327```bash theme={null}
328export CLAUDE_CODE_PLUGIN_KEEP_MARKETPLACE_ON_FAILURE=1
329```
330 
331**PowerShell**
332 
333```powershell theme={null}
334$env:CLAUDE_CODE_PLUGIN_KEEP_MARKETPLACE_ON_FAILURE = "1"
335```
380336 
381337With the variable set, Claude Code skips the re-clone only for a checkout that already contains `.claude-plugin/marketplace.json`. A marketplace that was never cloned or whose clone stopped partway still gets the clone attempt, so add it once while online.
382338 
383339For a fully offline deployment, pre-populate the plugins directory at image build time with `CLAUDE_CODE_PLUGIN_SEED_DIR` instead, following [Seed containers and CI](/docs/en/plugins/org#seed-containers-and-ci).
384340 
385<h3 id="marketplace-add-fails-on-a-github-enterprise-server-host">
386 Marketplace add fails on a GitHub Enterprise Server host
387</h3>
341### Marketplace add fails on a GitHub Enterprise Server host
388342 
389343You added a marketplace from a GitHub Enterprise Server (GHES) URL and got a policy error, or you added it from claude.ai and got a GitHub access error.
390344 
from line 351
397351 
398352You added a marketplace and ran an install, and the install stopped with a message instead of installing anything. These entries cover those messages. They also cover the related messages that appear later in the `/plugin` **Errors** tab, or as an empty **Discover** tab, when a plugin or its marketplace can't be found, read, or trusted.
399353 
400<h3 id="plugin-not-found-in-marketplace">
401 `Plugin "<name>" not found in marketplace "<marketplace>"`
402</h3>
354### `Plugin "<name>" not found in marketplace "<marketplace>"`
403355 
404356You ran `/plugin install <name>@<marketplace>` or `claude plugin install <name>@<marketplace>`, and the plugin name isn't in the copy of that marketplace's catalog on your machine.
405357 
406358`claude plugin install` in your shell prints the same message when you haven't added the marketplace at all. If `claude plugin marketplace update <marketplace>` then answers `Marketplace '<marketplace>' not found`, [add the marketplace](#add-a-marketplace) first.
407359 
408<h4 id="the-message-ends-with-a-refresh-hint">
409 `not found in marketplace` with a refresh hint
410</h4>
360#### `not found in marketplace` with a refresh hint
411361 
412362The hint reads `Your local copy may be out of date — try claude plugin marketplace update <marketplace>` or `The marketplace couldn't be refreshed (...)`. Claude Code didn't refresh the marketplace before the lookup, such as when you're offline, so your copy of the catalog may be stale. Refresh with the marketplace's name, then install again:
413363 
from line 367
417367 
418368`claude plugin marketplace update` prints `Successfully updated marketplace: <name>`, and `/plugin marketplace update` shows `✔ Updated 1 marketplace`. If the retried install prints the same message, check the name as [`not found in marketplace` with no hint](#the-message-has-no-hint) describes. [When Claude Code refreshes a marketplace before an install](/docs/en/plugins/loading#when-claude-code-refreshes-a-marketplace-before-an-install) lists the other cases where the refresh doesn't run.
419369 
420<h4 id="the-message-has-no-hint">
421 `not found in marketplace` with no hint
422</h4>
370#### `not found in marketplace` with no hint
423371 
424372The name is the likeliest problem. Open `/plugin`, go to **Discover**, and copy the name from the list.
425373 
426374Before v2.1.232, Claude Code refreshed the named marketplace only after the lookup missed, and only when auto-update was on for it.
427375 
428<h3 id="plugin-not-found-in-any-marketplace">
429 `Plugin "<name>" not found in any marketplace`
430</h3>
376### `Plugin "<name>" not found in any marketplace`
431377 
432378You ran `/plugin install <name>` with no `@marketplace`, and no registered marketplace has that plugin. `claude plugin install <name>` reports `Plugin "<name>" not found in any configured marketplace`.
433379 
from line 387
441387 
442388If you don't know which marketplace lists the plugin, run `/plugin marketplace list` for the marketplaces you have, and browse **Discover** in `/plugin` for the plugin name.
443389 
444<h3 id="plugin-is-already-installed-globally">
445 `Plugin '<name>@<marketplace>' is already installed globally`
446</h3>
390### `Plugin '<name>@<marketplace>' is already installed globally`
447391 
448392You ran `/plugin install` for a plugin that's already installed at user scope or by managed settings, and Claude Code refused with `Use '/plugin' to manage existing plugins.` If you typed the plugin name without `@<marketplace>`, the message omits `globally`.
449393 
from line 397
453397 
454398`claude plugin install` in your shell prints a different message. For a plugin already installed at the target scope, it prints `Plugin "<name>@<marketplace>" is already installed (scope: user)` and exits 0. If its cache directory is missing, the same command re-downloads it.
455399 
456<h3 id="plugin-would-share-its-folder">
457 `"<plugin>" was not installed: it would share its folder with "<other>"`
458</h3>
400### `"<plugin>" was not installed: it would share its folder with "<other>"`
459401 
460402You installed a plugin through `claude plugin install`, `/plugin`, or an install suggestion in a session, and Claude Code refused it with this line, or with `would share its saved data with`.
461403 
from line 408
466408* **The other plugin is installed**: the message says `Only one of the two can be installed.` and names the `claude plugin uninstall` command, or the uninstall step in `/plugin`, that removes the other plugin. Run it, then install again. For what the uninstall removes, see [What an uninstall deletes and keeps](/docs/en/plugins/cli-reference#what-an-uninstall-deletes-and-keeps).
467409* **Both ids arrive in one install**, such as a plugin and a dependency it needs: no install order helps. Only a maintainer of the marketplace that lists the two plugins can fix it, by renaming one of them. When the two come from different marketplaces, a maintainer of either one can.
468410 
469<h3 id="this-plugin-uses-a-source-type-your-claude-code-version-does-not-suppo">
470 `This plugin uses a source type your Claude Code version does not support`
471</h3>
411### `This plugin uses a source type your Claude Code version does not support`
472412 
473413You installed a plugin whose marketplace entry uses a source type this version of Claude Code can't fetch, and Claude Code stopped with this message and `Update Claude Code and try again.`
474414 
475415Update Claude Code, then retry the install. Source types are on the [marketplace reference](/docs/en/plugins/marketplace-reference).
476416 
477<h3 id="plugin-archive-integrity-check-failed">
478 `Plugin archive integrity check failed`
479</h3>
417### `Plugin archive integrity check failed`
480418 
481419You installed a plugin that's distributed as a zip archive, and Claude Code refused it with this line and `The archive was not installed.` The plugin's marketplace entry uses an [`archive` source](/docs/en/plugins/marketplace-reference) with a `sha256` pin, and the downloaded file's digest doesn't match the pin.
482420 
from line 429
491429* **You publish the plugin**: recompute the digest of the exact file the URL serves and update the `sha256` in the marketplace entry. Use `shasum -a 256 my-plugin.zip`, or `Get-FileHash -Algorithm SHA256 my-plugin.zip` in PowerShell
492430* **You install the plugin**: run `/plugin marketplace update <name>` in a session to refresh the catalog in case the entry was corrected, then retry the install. If the digests still disagree after the refresh, ask the marketplace owner which file they pinned before installing
493431 
494<h3 id="an-npm-plugin-source-must-name-a-registry-package">
495 `An npm plugin source must name a registry package`
496</h3>
432### `An npm plugin source must name a registry package`
497433 
498434A plugin whose marketplace entry uses an [`npm` source](/docs/en/plugins/marketplace-reference#npm-plugin-source) failed to install, update, or load, and the message includes this sentence. Claude Code checked the entry's `package` value before fetching anything and refused it. The message names the value and the reason:
499435 
from line 442
506442* **If that's you**: change `package` to a value the [npm plugin source reference](/docs/en/plugins/marketplace-reference#npm-plugin-source) accepts, or switch the entry to a `github`, `url`, or `git-subdir` source
507443* **If it isn't you**: report the message to the marketplace owner
508444 
509<h3 id="marketplace-is-registered-from-an-untrusted-source">
510 `Marketplace "<name>" is registered from an untrusted source`
511</h3>
445### `Marketplace "<name>" is registered from an untrusted source`
512446 
513447A marketplace you added earlier stopped loading, and so did its plugins. This line appears in the `/plugin` **Errors** tab or on the next refresh.
514448 
from line 461
527461 
528462Before v2.1.205, Claude Code checked the name only when you added the marketplace, so an entry registered before its name became reserved kept loading.
529463 
530<h3 id="marketplace-is-added-but-ignored">
531 `Marketplace "<name>" is added but ignored`
532</h3>
464### `Marketplace "<name>" is added but ignored`
533465 
534466The marketplace has an entry in `~/.claude/plugins/known_marketplaces.json`, but the entry failed a check Claude Code runs every time it reads that file, so the marketplace and the plugins installed from it stop loading. In your shell, `claude plugin list` reports each affected plugin with a line that names the reason and the fix:
535467 
from line 488
556488 
557489Before v2.1.286, whatever the reason, `claude plugin list` reported such a marketplace as `Marketplace <name> not found`, and the `/plugin` **Errors** tab reported it as `Marketplace "<name>" is registered but was refused (see the debug log)`. The reason appeared only in the debug log. In v2.1.286, the reason and fix sentences used different wording, such as `Its recorded location is network-shaped or unclassifiable (never probed)`.
558490 
559<h3 id="plugin-has-a-corrupt-manifest-file-or-has-an-invalid-manifest-file">
560 `Plugin <name> has a corrupt manifest file` or `has an invalid manifest file`
561</h3>
491### `Plugin <name> has a corrupt manifest file` or `has an invalid manifest file`
562492 
563493Claude Code fetched the plugin, then failed to read its `.claude-plugin/plugin.json`. In the shell, the `<name>` in this line can be a temporary directory name; the `Failed to install plugin "<name>@<marketplace>"` prefix carries the plugin's real name. The wording says which check failed:
564494 
from line 502
572502* **If that's you**: run `claude plugin validate <plugin-directory>` in your shell to see the same error with the offending path, then fix the file
573503* **If it isn't you**: report the message to the marketplace owner
574504 
575<h3 id="plugin-directory-not-found-at-path">
576 `Plugin directory not found at path: <path>`
577</h3>
505### `Plugin directory not found at path: <path>`
578506 
579507The **Errors** tab in `/plugin` shows this for an enabled plugin that its marketplace lists by a relative path, such as `./plugins/my-plugin`, when no directory exists at that path inside the marketplace. If you maintain the marketplace, correct the entry's `source` path or restore the folder. Otherwise, report the message to the marketplace owner.
580508 
581509`Marketplace directory not found at path: <path>` means the marketplace's own directory is missing instead. For a marketplace you added from a local path, that directory moved or was deleted. Restore it, or remove the marketplace and add it again from its new location.
582510 
583<h3 id="no-plugins-available-or-no-marketplaces-configured">
584 `No plugins available` or `No marketplaces configured`
585</h3>
511### `No plugins available` or `No marketplaces configured`
586512 
587513You opened `/plugin` and the **Discover** tab is empty, or `claude plugin marketplace list` printed `No marketplaces configured`.
588514 
from line 520
594520 
595521Claude Code prints `Successfully added marketplace: claude-plugins-official`, and **Discover** lists its plugins. The [Anthropic marketplaces](/docs/en/plugins/anthropic-marketplaces) page lists the other marketplaces you can add.
596522 
597<h3 id="marketplace-is-already-added-from-a-different-source">
598 `Marketplace "<name>" is already added from a different source`
599</h3>
523### `Marketplace "<name>" is already added from a different source`
600524 
601525You named a new marketplace source with [`--marketplace <source>` on the install command](/docs/en/plugins/install#add-a-marketplace-and-install-in-one-command), in a session or from your shell. The catalog Claude Code fetched from that source has the same name as a marketplace you already added from a different source. Claude Code keeps the existing marketplace instead of replacing it, and the plugin isn't installed.
602526 
from line 535
611535* **The marketplace you already added**: install from it by name with `/plugin install <plugin>@<name>`
612536* **The new source**: run `/plugin marketplace remove <name>`, then retry the install
613537 
614<h3 id="cannot-add-marketplace-source-doesnt-match">
615 `Cannot add marketplace "<name>": its source doesn't match its extraKnownMarketplaces entry in user or managed settings`
616</h3>
538### `Cannot add marketplace "<name>": its source doesn't match its extraKnownMarketplaces entry in user or managed settings`
617539 
618540You added a marketplace, and the `name` in its `marketplace.json` already has an [`extraKnownMarketplaces`](/docs/en/settings-reference#extraknownmarketplaces) entry in your user settings or managed settings. The source you gave differs from the one that entry lists, so Claude Code refuses the add and registers nothing.
619541 
from line 553
631553 
632554Before v2.1.287, the message read `Cannot add marketplace "<name>": its network source differs from the one declared for it in settings (kind, target, or a fetch-shaping field such as headers / ref / path / sparsePaths)`.
633555 
634<h3 id="failed-to-install-from-the-plugin-menu">
635 `Failed to install: <plugin> (<reason>)`
636</h3>
556### `Failed to install: <plugin> (<reason>)`
637557 
638558You selected plugins to install in the `/plugin` menu, none of them installed, and the menu closed with this summary of what failed.
639559 
from line 564
644564* Fix what the reason in parentheses names
645565* When the reason was shortened, run `/plugin`, select the plugin on the **Discover** tab, and press **Enter** to install it from its details. If the install fails there, the details view shows the whole error
646566 
647<h3 id="could-not-move-the-new-copy-of-this-plugin-version">
648 `Could not move the new copy of this plugin version into <path>`
649</h3>
567### `Could not move the new copy of this plugin version into <path>`
650568 
651569When you install a plugin, Claude Code downloads a fresh copy of its files and moves it into that version's folder in the [plugin cache](/docs/en/plugins/loading#find-plugins-on-disk). This message means the move failed, usually because another program was using the folder while the install ran. The file-system code appears in parentheses:
652570 
from line 587
669587* Close other Claude Code sessions, editors, and terminals that are using the plugin's folder under `~/.claude/plugins/cache`, then run the install again
670588* When the message says to check the plugin cache folder's permissions, restore your write permission on the folder it names and free disk space, then run the install again
671589 
672<h3 id="dependency-errors">
673 Dependency errors
674</h3>
590### Dependency errors
675591 
676592A plugin that declares dependencies can fail to install, or install and stay disabled, when a dependency can't be satisfied. The message reaches you at install time or at load time:
677593 
from line 613
697613 
698614The install succeeded, but the plugin's skills, hooks, or servers aren't doing anything. Start with [Plugin doesn't appear or its skills don't show up](#plugin-doesnt-appear-or-its-skills-dont-show-up), which tells you where Claude Code reports what it loaded, then match the message.
699615 
700<h3 id="plugin-doesnt-appear-or-its-skills-dont-show-up">
701 Plugin doesn't appear or its skills don't show up
702</h3>
616### Plugin doesn't appear or its skills don't show up
703617 
704618You installed a plugin and typed `/` expecting its skills, or asked Claude to use it, and nothing happened.
705619 
706620Check the plugin's state before changing anything:
707621 
708<Steps>
709 <Step title="Confirm the plugin is installed and enabled">
710 Run `/plugin` and open **Installed**. Confirm the plugin is listed and enabled. `claude plugin list` in your shell prints the same list with each plugin's version, scope, and `Status: ✔ enabled`.
711 </Step>
712 
713 <Step title="Read the Errors tab">
714 Open the **Errors** tab in the same panel. Each entry pairs a message with a guidance line. Most messages in the rest of this section come from that tab.
715 </Step>
716 
717 <Step title="Reload if you installed during this session">
718 If the plugin is installed and error-free but you installed it during this session, run `/reload-plugins`. It prints `Reloaded:` with counts of plugins, skills, agents, hooks, and servers. When something failed it adds `N errors during load. Run /plugin for details.`
719 </Step>
720</Steps>
622**1. Confirm the plugin is installed and enabled**
623 
624Run `/plugin` and open **Installed**. Confirm the plugin is listed and enabled. `claude plugin list` in your shell prints the same list with each plugin's version, scope, and `Status: ✔ enabled`.
625 
626**2. Read the Errors tab**
627 
628Open the **Errors** tab in the same panel. Each entry pairs a message with a guidance line. Most messages in the rest of this section come from that tab.
629 
630**3. Reload if you installed during this session**
631 
632If the plugin is installed and error-free but you installed it during this session, run `/reload-plugins`. It prints `Reloaded:` with counts of plugins, skills, agents, hooks, and servers. When something failed it adds `N errors during load. Run /plugin for details.`
721633 
722634If the plugin loads with no error and its skills still don't appear, the next step differs for your own plugin and for someone else's:
723635 
724636* **A plugin you're building**: see [Plugin loads but its skills are missing](#plugin-loads-but-its-skills-are-missing)
725637* **A plugin someone else published**: open **Installed** in `/plugin` and open the plugin's details pane, which lists what the plugin contains. A plugin that lists no skills there has none to offer when you type `/`
726638 
727<h3 id="run-reload-plugins-to-activate">
728 `Run /reload-plugins to apply.`
729</h3>
639### `Run /reload-plugins to apply.`
730640 
731641The install summary in `/plugin` ended with `Run /reload-plugins to apply.` instead of `Plugin is now active.` A `Plugins changed. Run /reload-plugins to activate.` notice can appear above the prompt at the same time.
732642 
from line 653
743653 
744654Before v2.1.246, the skills count in that summary included only a plugin's `commands/` entries, so a reload could load a plugin's `SKILL.md` skills and still report `0 skills`.
745655 
746<h3 id="the-packages-it-lists-are-not-installed">
747 `The packages it lists are not installed` or `were not installed, because ...`
748</h3>
656### `The packages it lists are not installed` or `were not installed, because ...`
749657 
750658`/plugin` and `claude plugin list` show one of these notes on a plugin whose dependency install left no `node_modules` directory. The plugin loads, but the parts that need the missing packages may not work.
751659 
from line 667
759667 
760668* **`were not installed, because ...`**: the install can't run for this plugin, and the note names the reason, such as a Yarn, pnpm, or `bun.lockb` lockfile, or a lockfile whose package manager isn't installed on this computer. Updating the plugin doesn't install the packages while that reason stands. If the reason is the lockfile, the plugin's author has to replace it. If it's a missing package manager, install it, then update the plugin
761669 
762<h3 id="plugin-not-cached-at">
763 `Plugin "<name>" not cached at <path>`
764</h3>
670### `Plugin "<name>" not cached at <path>`
765671 
766672The **Errors** tab shows this line with the guidance `Run /plugin to refresh the plugin cache`. Claude Code has an install record for the plugin, but the directory the record points at is missing, for example after you cleared the cache.
767673 
from line 679
773679 
774680Then run `/reload-plugins` in your session. The **Errors** tab entry disappears and the plugin is back under **Installed**.
775681 
776<h3 id="installed-plugins-json-holds-a-record-this-version-cannot-read">
777 `installed_plugins.json holds a record under "<id>" that this version of Claude Code cannot read`
778</h3>
682### `installed_plugins.json holds a record under "<id>" that this version of Claude Code cannot read`
779683 
780684The message surfaces in these forms:
781685 
from line 699
7956992. If you can't update, uninstall the named plugin with the version of Claude Code that wrote the record.
7967003. If neither helps, delete the record from `installed_plugins.json` by hand, then restart Claude Code or run `/reload-plugins`.
797701 
798<h3 id="installed-plugins-json-could-not-be-read-and-was-rebuilt">
799 `installed_plugins.json could not be read and was rebuilt`
800</h3>
702### `installed_plugins.json could not be read and was rebuilt`
801703 
802704`claude plugin list` prints this note, with the path of a kept file named `installed_plugins.unreadable.<date>.<hash>.kept`, for as long as that file sits beside `installed_plugins.json`.
803705 
from line 707
805707 
806708Open the `.kept` file to see what the old file recorded, and reinstall the plugins you're missing. Claude Code never reads the file back, and the file ages out on the [`cleanupPeriodDays`](/docs/en/settings-reference#cleanupperioddays) schedule.
807709 
808<h3 id="install-records-under-names-that-no-version-can-use">
809 `install records under names that no version of Claude Code can use were removed from installed_plugins.json`
810</h3>
710### `install records under names that no version of Claude Code can use were removed from installed_plugins.json`
811711 
812712`claude plugin list` prints this note, with the path of a copy named `installed_plugins.set-aside.<date>.<hash>.json`, for as long as that copy sits beside `installed_plugins.json`. The note ends `Nothing needs doing about these copies.`
813713 
from line 715
815715 
816716Claude Code copies the unusable records into the `.set-aside` file and drops them from the list. Claude Code never reads the copies back, and the copies age out on the [`cleanupPeriodDays`](/docs/en/settings-reference#cleanupperioddays) schedule.
817717 
818<h3 id="does-not-load-so-claude-code-ignores-the-whole-file">
819 `does not load (...), so Claude Code ignores the whole file`
820</h3>
718### `does not load (...), so Claude Code ignores the whole file`
821719 
822720The command worked. The settings file the warning names has an error, so Claude Code ignores the whole file, including anything the command wrote there, until you fix it.
823721 
from line 732
834732* **`its "<key>" is not valid`**: the quoted setting holds a value Claude Code doesn't accept. Look up the setting in the [settings reference](/docs/en/settings-reference) for the values it takes. When more than one value fails, the text names the first setting and counts the others, as in `its "permissions" and 1 other value are not valid`.
835733* **`it is not a JSON object`**: the file's top level isn't a JSON object, such as a file whose top level is an array.
836734 
837<h3 id="a-plugin-you-disabled-still-loads">
838 `Disabled in ~/.claude/settings.json but still loads`
839</h3>
735### `Disabled in ~/.claude/settings.json but still loads`
840736 
841737You set a plugin to `false` in `~/.claude/settings.json`, and its row in `claude plugin list` or `/plugin` shows this message followed by the source that enables it, such as `— project settings enable it, which overrides your user setting`. A `true` in that higher-precedence source is overriding your user setting.
842738 
from line 740
844740 
845741If `claude plugin list` instead marks the plugin `required by your org`, no settings file is involved: your organization marks that synced plugin as required on claude.ai, and it loads even if you disabled it earlier. See [Plugins synced from claude.ai](/docs/en/plugins/loading#synced-plugins).
846742 
847<h3 id="plugin-is-enabled-in-project-settings-but-isnt-installed-here">
848 `Plugin "<name>" is enabled in project settings but isn't installed here`
849</h3>
743### `Plugin "<name>" is enabled in project settings but isn't installed here`
850744 
851745The **Errors** tab shows this line for a plugin your project's `.claude/settings.json` enables, with the guidance `Run claude plugin install <name>@<marketplace> --scope project to install it for this project`.
852746 
from line 754
860754 
861755If your organization pre-installs plugins for you, it does so through managed settings instead. See [Pre-install and require plugins](/docs/en/plugins/org#pre-install-and-require-plugins).
862756 
863<h3 id="a-plugin-stays-installed-after-plugin-uninstall-on-windows">
864 A plugin stays installed after `plugin uninstall` on Windows
865</h3>
757### A plugin stays installed after `plugin uninstall` on Windows
866758 
867759On Windows, you run `claude plugin uninstall` at project or local scope and it reports success, but `claude plugin list` or `/plugin` still lists the plugin.
868760 
from line 770
878770 
879771Before v2.1.295, the second run fails with `Plugin "<name>" is not installed in project scope`. Run `claude update`, then run the uninstall again.
880772 
881<h3 id="failed-to-load-hooks-from-and-hooks-that-dont-fire">
882 `Failed to load hooks from <path>` and hooks that don't fire
883</h3>
773### A plugin installed from a git repository shows version `unknown`
774 
775`Version: unknown` in `claude plugin list` can mean Claude Code couldn't read the commit it uses as a git-sourced plugin's version. The plugin may have its own repository or be inside a git-hosted marketplace.
776 
777Run these commands in your shell, replacing `formatter@my-marketplace` with the plugin's `name@marketplace` line from `claude plugin list`:
778 
779**1. Update Claude Code**
780 
781[Update Claude Code](/docs/en/setup#update-claude-code) to v2.1.302 or later, which clones in a format it can read the commit from:
782 
783```shell theme={null}
784claude update
785```
786 
787**2. Update the marketplace**
788 
789Update Claude Code's copy of the marketplace, which holds the commit for plugins inside the marketplace repository:
790 
791```shell theme={null}
792claude plugin marketplace update my-marketplace
793```
794 
795**3. Update the plugin**
796 
797Update the plugin to rewrite its recorded version:
798 
799```shell theme={null}
800claude plugin update formatter@my-marketplace
801```
802 
803**4. Check the version**
804 
805Check the `Version:` line for a value such as a [12-character commit ID](/docs/en/plugins/loading#how-claude-code-computes-the-version):
806 
807```shell theme={null}
808claude plugin list
809```
810 
811`claude plugin update` [changes one scope's block per run](/docs/en/plugins/cli-reference#which-scope-the-command-updates). For a block still showing `unknown`, rerun it with that block's `Scope:` value:
812 
813```shell theme={null}
814claude plugin update formatter@my-marketplace --scope project
815```
816 
817If the block still shows `unknown` after the rerun, see [Get more help](/docs/en/troubleshooting#get-more-help).
818 
819### `Failed to load hooks from <path>` and hooks that don't fire
884820 
885821A plugin's hooks don't run, or one blocks an action. Either the **Errors** tab shows a load failure for them, the hooks load and you see `<Event> hook error` notices or a blocking error in the transcript, or a hook loads without error and never fires.
886822 
from line 847
911847 
912848If a hook loads without error but never fires, first run `/plugin` in your session and open the plugin's details. A note there that begins `Its hooks.json hooks do not run` means another enabled plugin with the same name registered its hooks instead, and [Hooks when two enabled plugins share a name](/docs/en/plugins/loading#hooks-when-two-enabled-plugins-share-a-name) says which copy that is and how to switch. Otherwise, check the hook's definition and then watch it run:
913849 
914<Steps>
915 <Step title="Check the event name">
916 Event names are case-sensitive, so confirm yours matches exactly, for example `PostToolUse`.
917 </Step>
918 
919 <Step title="Check the matcher">
920 Confirm the hook's `matcher` matches the tool name.
921 </Step>
922 
923 <Step title="Trigger the event on purpose">
924 For a `PostToolUse` hook, ask Claude to edit a file.
925 </Step>
926 
927 <Step title="Read the debug log">
928 Open the [debug log](/docs/en/hooks#debug-hooks), which records which hooks matched. A hook that ran shows up there with its exit code.
929 </Step>
930</Steps>
931 
932<h3 id="plugin-directory-does-not-exist">
933 `Plugin directory does not exist: <path>`
934</h3>
850**1. Check the event name**
851 
852Event names are case-sensitive, so confirm yours matches exactly, for example `PostToolUse`.
853 
854**2. Check the matcher**
855 
856Confirm the hook's `matcher` matches the tool name.
857 
858**3. Trigger the event on purpose**
859 
860For a `PostToolUse` hook, ask Claude to edit a file.
861 
862**4. Read the debug log**
863 
864Open the [debug log](/docs/en/hooks#debug-hooks), which records which hooks matched. A hook that ran shows up there with its exit code.
865 
866### `Plugin directory does not exist: <path>`
935867 
936868Run `/reload-plugins` at the Claude Code prompt first, even though the message says to reinstall. A plugin's hook fails with `Failed to run: Plugin directory does not exist: <path> (<plugin> — run /plugin to reinstall)`, and the hook doesn't run, when the directory your session loaded the plugin's hooks from is gone from disk. [`Plugin directory not found at path: <path>`](#plugin-directory-not-found-at-path) is a different message, about a marketplace entry.
937869 
from line 873
941873* **`N errors during load. Run /plugin for details.`**: open the **Errors** tab in `/plugin` and follow this page's entry for the message it shows
942874* **A line that ends `Run /reload-plugins --force to apply.`**: nothing reloaded, and the hooks keep failing. Run `/reload-plugins --force` at the Claude Code prompt
943875 
944<h3 id="invalid-mcp-server-config-for-and-mcp-servers-that-dont-start">
945 `Invalid MCP server config for "<server>"` and MCP servers that don't start
946</h3>
876### `Invalid MCP server config for "<server>"` and MCP servers that don't start
947877 
948878A plugin bundles an MCP server, and the **Errors** tab shows `Invalid MCP server config for "<server>": <error>`, or the server is listed but `/mcp` never shows it connected.
949879 
from line 909
979909 
980910For paths that reach outside the plugin directory, see [Files the plugin references outside its directory aren't found](#files-the-plugin-references-outside-its-directory-arent-found).
981911 
982<h3 id="language-server-doesnt-start">
983 Language server doesn't start, uses too much memory, or reports wrong diagnostics
984</h3>
912### Language server doesn't start, uses too much memory, or reports wrong diagnostics
985913 
986914You installed a [code intelligence plugin](/docs/en/plugins/code-intelligence) and Claude isn't seeing diagnostics, or the language server is using too much memory or reporting errors that aren't real.
987915 
from line 938
1010938* **A hook that doesn't fire**: see [hooks that don't fire](#failed-to-load-hooks-from-and-hooks-that-dont-fire)
1011939* **An MCP server that doesn't start**: see [MCP servers that don't start](#invalid-mcp-server-config-for-and-mcp-servers-that-dont-start)
1012940 
1013<h3 id="commands-path-not-found">
1014 `commands path not found: <path>`
1015</h3>
941### `commands path not found: <path>`
1016942 
1017943The **Errors** tab shows `commands path not found: <absolute path>` with the guidance `Check that the path in your manifest or marketplace config is correct`. The same message appears for `skills`, `agents`, and `hooks`.
1018944 
from line 946
1020946 
1021947Paths in the manifest are relative to the plugin root and start with `./`. A path that resolves outside the plugin root is reported as `<component> path escapes plugin directory` instead and is dropped.
1022948 
1023<h3 id="plugin-dir-loads-a-plugin-with-no-components">
1024 `--plugin-dir` at a marketplace root doesn't load the plugins under `plugins/`
1025</h3>
949### `--plugin-dir` at a marketplace root doesn't load the plugins under `plugins/`
1026950 
1027951You started `claude --plugin-dir <path>` and see no error, but the plugin's skills, agents, and hooks aren't there.
1028952 
from line 958
1034958 
1035959Then open **Installed** in `/plugin`, where the plugin's details pane lists its components.
1036960 
1037<h3 id="files-the-plugin-references-outside-its-directory-arent-found">
1038 Files the plugin references outside its directory aren't found
1039</h3>
961### Files the plugin references outside its directory aren't found
1040962 
1041963A plugin works from its source directory with `--plugin-dir` but fails after install, with errors about a path such as `../shared-utils`.
1042964 
1043965Claude Code copies an installed plugin into its cache and loads it from there, so a path that reaches outside the plugin's own directory points at nothing in the cache. Move the shared files inside the plugin directory, or reference them through a symlink inside it. For where the cache is and how paths resolve, see [Find plugins on disk](/docs/en/plugins/loading#find-plugins-on-disk).
1044966 
1045<h3 id="claude-plugin-root-shows-forward-slashes-on-windows">
1046 `${CLAUDE_PLUGIN_ROOT}` shows forward slashes on Windows
1047</h3>
967### `${CLAUDE_PLUGIN_ROOT}` shows forward slashes on Windows
1048968 
1049969On Windows, a plugin hook receives `${CLAUDE_PLUGIN_ROOT}` as `C:/Users/you/...` rather than `C:\Users\you\...`, and a script that expected backslashes breaks.
1050970 
from line 975
1055975* An exec-form hook, which spawns the process directly with an `args` array
1056976* A hook with `"shell": "powershell"`
1057977 
1058<h3 id="plugin-loads-but-its-skills-are-missing">
1059 Plugin loads but its skills are missing
1060</h3>
978### Plugin loads but its skills are missing
1061979 
1062980Your plugin is listed under **Installed** with no errors, but its skills aren't offered when you type `/`.
1063981 
from line 983
1065983 
1066984Each skill is a directory containing `SKILL.md`. A `skills` entry in the manifest that points at a `SKILL.md` file rather than its directory is reported as `path is a file; skills entries must be directories containing SKILL.md`.
1067985 
1068<h3 id="skill-loads-but-claude-never-invokes-the-skill">
1069 Skill loads but Claude never invokes the skill
1070</h3>
986### Skill loads but Claude never invokes the skill
1071987 
1072988Your plugin's skill runs when you type its `/<plugin>:<skill>` command, but Claude never invokes it in response to a plain request.
1073989 
from line 995
1079995 
1080996To measure how often the skill triggers across realistic prompts rather than checking one at a time, write an eval case with a [`tool_used: Skill` grader](/docs/en/plugin-evals#create-your-first-eval-suite) and run it with `claude plugin eval` after each description change.
1081997 
1082<h3 id="is-not-a-plugin-or-skill-folder">
1083 `<directory> is not a plugin or skill folder` from `claude plugin eval init`
1084</h3>
998### `<directory> is not a plugin or skill folder` from `claude plugin eval init`
1085999 
10861000You ran `claude plugin eval init` from a directory that isn't a plugin's root, such as your home directory or the root of a repository that keeps the plugin in a subdirectory. `init` writes the suite under the working directory, so it stops instead of creating an `evals/` directory the plugin would never see.
10871001 
10881002Change to the plugin's root, the directory that holds `.claude-plugin/plugin.json` or the skill's `SKILL.md`, and run the command again. To scaffold the suite somewhere else on purpose, pass `--eval-dir`. See [Test plugins with evals](/docs/en/plugin-evals).
10891003 
1090<h3 id="the-userconfig-dialog-never-appears">
1091 The `userConfig` dialog never appears
1092</h3>
1004### The `userConfig` dialog never appears
10931005 
10941006Your plugin declares `userConfig` options, but no configuration dialog appears when you install it.
10951007 
from line 1025
11131025 
11141026For a plugin that ships an [MCPB bundle file](/docs/en/plugins/components#include-a-packaged-mcpb-server) declaring `user_config` of its own, the message reads `isn't declared in this plugin's userConfig or by its bundled MCP servers.` instead, and the known keys include that server's keys, written `<server>.<key>`. A bundle the manifest references by URL isn't read at install time, so its keys aren't listed and the message says to configure it in `/plugin`. Setting `<server>.<key>` keys requires Claude Code v2.1.285 or later.
11151027 
1116<h3 id="claude-plugin-validate-reports-errors">
1117 `claude plugin validate` reports errors
1118</h3>
1028### `claude plugin validate` reports errors
11191029 
11201030You ran `claude plugin validate <path>`, or `/plugin validate <path>` in a session, and it printed `Found N errors` and `Validation failed`, then exited with code 1.
11211031 
from line 1049
11391049 
11401050`plugin.json` fields are on the [manifest reference](/docs/en/plugins/manifest-reference), and marketplace-level messages are under [Marketplace validation errors](#marketplace-validation-errors).
11411051 
1142<h3 id="plugin-has-conflicting-manifests">
1143 `Plugin <name> has conflicting manifests`
1144</h3>
1052### `Plugin <name> has conflicting manifests`
11451053 
11461054The plugin fails to load with `Plugin <name> has conflicting manifests: both plugin.json and marketplace entry specify components.`
11471055 
11481056The plugin has its own `plugin.json`, and its marketplace entry sets `strict: false` while also declaring any of `commands`, `agents`, `skills`, `hooks`, `outputStyles`, or `themes`. Remove those fields from the entry, or set `strict: true` in the entry so Claude Code appends them to `plugin.json`. See [Strict mode](/docs/en/plugins/marketplace-reference#strict-mode).
11491057 
1150<h3 id="warning-no-commands-found-in-plugin-custom-directory">
1151 `Warning: No commands found in plugin <name> custom directory`
1152</h3>
1058### `Warning: No commands found in plugin <name> custom directory`
11531059 
11541060When the plugin loads, the `claude --debug` log at `~/.claude/debug/<session-id>.txt` records `Warning: No commands found in plugin <name> custom directory: <path>. Expected .md files or SKILL.md in subdirectories.` Nothing appears in the session or the **Errors** tab.
11551061 
from line 1065
11591065 
11601066You publish a marketplace and a user reports an error, or your own validation fails. These entries are for the marketplace owner.
11611067 
1162<h3 id="plugins-with-relative-paths-fail-in-url-based-marketplaces">
1163 Plugins with relative paths fail in URL-based marketplaces
1164</h3>
1068### Plugins with relative paths fail in URL-based marketplaces
11651069 
11661070Users added your marketplace with an `https://example.com/marketplace.json` URL. Installs of plugins whose `source` is a relative path, such as `./plugins/my-plugin`, fail with `its marketplace entry path does not stay inside the marketplace directory`. Already-installed plugins fail to load with `Plugin source path refused`. Both messages have an [error reference entry](/docs/en/errors#marketplace-entry-path-does-not-stay-inside-the-marketplace-directory).
11671071 
from line 1077
11731077 
11741078Alternatively, host the marketplace in a git repository and tell users to add it with the repository URL. For a git source, Claude Code clones the whole repository, so relative paths resolve. Source types are on the [marketplace reference](/docs/en/plugins/marketplace-reference).
11751079 
1176<h3 id="marketplace-validation-errors">
1177 Marketplace validation errors
1178</h3>
1080### Marketplace validation errors
11791081 
11801082You ran `claude plugin validate .` from your marketplace directory and it reported errors or warnings on the marketplace file itself.
11811083 
from line 1106
12041106 
12051107Your organization deploys managed settings that restrict plugins, and a command was refused with a policy message. These entries name the setting behind each refusal so you know what to ask your administrator for. For the admin side, see [Manage plugins for your organization](/docs/en/plugins/org).
12061108 
1207<h3 id="marketplace-source-is-blocked-by-enterprise-policy">
1208 `Marketplace source '<source>' is blocked by enterprise policy`
1209</h3>
1109### `Marketplace source '<source>' is blocked by enterprise policy`
12101110 
12111111You ran `/plugin marketplace add`, `update`, or an install, and Claude Code refused with this line. For a GitHub or git source, the host follows the source in parentheses, as in `'github:owner/repo' (github.com)`.
12121112 
from line 1120
12201120 
12211121A marketplace you added before the policy became more restrictive stops refreshing too, because the policy applies on every refresh.
12221122 
1223<h3 id="marketplace-is-not-in-the-allowed-marketplace-list">
1224 `Marketplace "<name>" is not in the allowed marketplace list`
1225</h3>
1123### `Marketplace "<name>" is not in the allowed marketplace list`
12261124 
12271125The **Errors** tab shows this line, or `Marketplace "<name>" is blocked by enterprise policy`, for a marketplace you already have registered.
12281126 
12291127The same managed settings that block a [marketplace source](#marketplace-source-is-blocked-by-enterprise-policy) apply at load time. `strictKnownMarketplaces` doesn't include this marketplace, or `blockedMarketplaces` names it, so Claude Code stops loading it and its plugins. For the allowlist variant, the guidance line shows the allowed sources, or `Contact your administrator to configure allowed marketplace sources`. For the blocklist variant it reads `This marketplace source is explicitly blocked by your administrator`.
12301128 
1231<h3 id="plugin-is-blocked-by-your-organizations-policy-and-cannot-be-installed">
1232 `Plugin "<name>" is blocked by your organization's policy and cannot be installed`
1233</h3>
1129### `Plugin "<name>" is blocked by your organization's policy and cannot be installed`
12341130 
12351131An install was refused with this line, an enable with the same line ending `cannot be enabled`, or an install or update with one naming the reason: `Plugin "<name>" is from marketplace "<marketplace>", which is blocked by your organization's policy`, or `Plugin "<name>" depends on "<dep>", which is blocked by your organization's policy`.
12361132 
12371133Managed settings block this plugin, its marketplace, or a dependency it needs. Ask your administrator which entry applies. A blocked dependency means the plugin can't install until the dependency's marketplace is allowed.
12381134 
1239<h3 id="plugin-dir-is-disabled-by-your-organizations-managed-settings-disables">
1240 `--plugin-dir is disabled by your organization's managed settings (disableSideloadFlags)`
1241</h3>
1135### `--plugin-dir is disabled by your organization's managed settings (disableSideloadFlags)`
12421136 
12431137You started `claude` with `--plugin-dir`, `--plugin-url`, `--agents`, or `--mcp-config`. Claude Code exited with this message and `Plugins, custom agents, and MCP servers can only be loaded from sources your administrator has approved.`
12441138 
from line 1140
12461140 
12471141A related message in the `/plugin` **Errors** tab is `--plugin-dir copy of "<name>" ignored: plugin is locked by managed settings`. Managed settings enable or disable that plugin by name, and Claude Code ignores your `--plugin-dir` copy of it so the flag can't override the policy.
12481142 
1249<h3 id="plugins-from-claude-skills-are-blocked-by-your-organizations-managed-s">
1250 `Plugins from ~/.claude/skills/ are blocked by your organization's managed settings`
1251</h3>
1143### `Plugins from ~/.claude/skills/ are blocked by your organization's managed settings`
12521144 
12531145You ran `claude plugin init` or `claude plugin enable`, and it stopped with this line. The message names `strictKnownMarketplaces or blockedMarketplaces` and asks your administrator to add `{"source":"skills-dir"}` to `strictKnownMarketplaces` or remove it from `blockedMarketplaces`.
12541146 
12551147The `skills-dir` source stands for plugins Claude Code loads from your `~/.claude/skills/` directory. Ask your administrator to make the change the message names.
12561148 
1257<h3 id="command-sourced-plugins-are-disabled-by-your-organizations-managed-set">
1258 `Command-sourced plugins are disabled by your organization's managed settings`
1259</h3>
1149### `Command-sourced plugins are disabled by your organization's managed settings`
12601150 
12611151You installed or updated a plugin with a `command` source, and it stopped with this line and `The plugin was not installed or updated and its command was not run.`
12621152 
12631153Your administrator set `disableCommandPluginSources`, so Claude Code refuses to run the marketplace-declared command that produces the plugin. Setting `allowManagedHooksOnly` alone has the same effect when `disableCommandPluginSources` is unset. Ask your administrator whether the plugin can be published from a source type the policy allows.
12641154 
1265<h3 id="marketplace-is-seed-managed">
1266 `Marketplace '<name>' is seed-managed`
1267</h3>
1155### `Marketplace '<name>' is seed-managed`
12681156 
12691157You ran `claude plugin marketplace update <name>`, and it failed with `Marketplace '<name>' is seed-managed (<dir>)` and a hint to ask your admin.
12701158 
12711159 

prompt-caching Changed · +10 / -12 lines

from line 12
1212 
1313The API caches by matching the start of each request, called the prefix, against content it recently processed. On a normal turn, the prefix is the entire previous request and only the latest exchange is new. The match is exact, so a change anywhere in the prefix recomputes everything after it. There is no per-file or per-segment caching. See [how prompt caching works](https://platform.claude.com/docs/en/build-with-claude/prompt-caching#how-prompt-caching-works) in the API reference for the underlying mechanism.
1414 
15<img src="https://mintcdn.com/claude-code/VbDJw--l6T9a9Wvm/images/prompt-caching-prefix.svg?fit=max&auto=format&n=VbDJw--l6T9a9Wvm&q=85&s=f2e8f0b8298a50305fe428ca3f1d1594" className="dark:hidden" alt="Four turns shown as growing horizontal bars. Each turn's request contains everything from the previous turn plus the latest exchange appended at the end. On turns two and three, the unchanged prefix is read from cache and only the new exchange is processed. On turn four, the system prompt changed, so the prefix no longer matches and the entire request is reprocessed and written." width="720" height="454" data-path="images/prompt-caching-prefix.svg" />
15![Four turns shown as growing horizontal bars. Each turn's request contains everything from the previous turn plus the latest exchange appended at the end. On turns two and three, the unchanged prefix is read from cache and only the new exchange is processed. On turn four, the system prompt changed, so the prefix no longer matches and the entire request is reprocessed and written.](https://mintcdn.com/claude-code/VbDJw--l6T9a9Wvm/images/prompt-caching-prefix.svg?fit=max\&auto=format\&n=VbDJw--l6T9a9Wvm\&q=85\&s=f2e8f0b8298a50305fe428ca3f1d1594)
1616 
17<img src="https://mintcdn.com/claude-code/_xqph1dUOslCOwsj/images/prompt-caching-prefix-dark.svg?fit=max&auto=format&n=_xqph1dUOslCOwsj&q=85&s=297dc1c639f0915cae858d0c4b6f3be5" className="hidden dark:block" alt="Four turns shown as growing horizontal bars. Each turn's request contains everything from the previous turn plus the latest exchange appended at the end. On turns two and three, the unchanged prefix is read from cache and only the new exchange is processed. On turn four, the system prompt changed, so the prefix no longer matches and the entire request is reprocessed and written." width="720" height="454" data-path="images/prompt-caching-prefix-dark.svg" />
18 
1917To get the most out of prefix matching, Claude Code orders each request so content that rarely changes between turns comes first:
2018 
2119| Layer | Content | Changes when |
from line 31
3331* **Model**: each model has its own cache. Switching models recomputes the entire request even when the content is identical. See [Switching models](#switching-models) below.
3432* **Effort level**: on most models, each effort level has its own cache, so changing effort mid-session recomputes the entire request. On Opus 5.5, Sonnet 5.5, Haiku 5.5, and Fable 5.1 with an API key or a Claude subscription, the cache stays intact by default. See [Changing effort level](#changing-effort-level) below.
3533 
36<Tip>
37 Pick your model and effort level at the top of a session, then save `/compact` for natural breaks between tasks. The fewer changes you make mid-task, the higher your cache hit rate.
38</Tip>
34> [!TIP]
35>
36> Pick your model and effort level at the top of a session, then save `/compact` for natural breaks between tasks. The fewer changes you make mid-task, the higher your cache hit rate.
3937 
4038### Where the cache lives
4139 
from line 171
173171 
174172After a break longer than the [cache lifetime](#cache-lifetime), there is no cache left to read, so the summarization request reprocesses the full history as uncached input. This is why `/compact` costs the most when you [resume an old session](/docs/en/sessions#resume-a-session). In both the warm and cold cases, the turn after compaction rebuilds the conversation cache for only the much shorter summary, so that turn is not the slow part.
175173 
176<Tip>
177 Compaction works in your favor when the context you discard is content you no longer need. To choose when its overhead happens, run `/compact` at a natural break in your work, such as between tasks, instead of waiting for auto-compaction to trigger mid-task. If you've gone down a path you want to abandon entirely, [`/rewind`](#rewinding-the-conversation) to an earlier turn instead. Rewinding truncates back to a prefix that is already cached, rather than building a new one as compaction does.
178</Tip>
174> [!TIP]
175>
176> Compaction works in your favor when the context you discard is content you no longer need. To choose when its overhead happens, run `/compact` at a natural break in your work, such as between tasks, instead of waiting for auto-compaction to trigger mid-task. If you've gone down a path you want to abandon entirely, [`/rewind`](#rewinding-the-conversation) to an earlier turn instead. Rewinding truncates back to a prefix that is already cached, rather than building a new one as compaction does.
179177 
180178If you leave a long conversation idle in a terminal session while it is on the [one-hour TTL](#which-ttl-each-request-gets), Claude Code can compact it shortly before the cache expires. To turn idle compaction off, set [`idleCompaction`](/docs/en/settings-reference#idlecompaction) to `false`, which requires Claude Code v2.1.290 or later.
181179 
from line 189
191189 
192190A new Claude Code version typically updates the system prompt or tool definitions, so the first conversation you start after an upgrade builds its cache from the top. [Auto-update](/docs/en/setup#auto-updates) downloads new versions in the background but applies them on the next launch, never mid-session, so you see this as an uncached first turn after restarting rather than a surprise during a session. Set `DISABLE_AUTOUPDATER=1` to control when upgrades apply.
193191 
194<Note>
195 For what it costs to resume a conversation you started before the upgrade, see [Resuming a session](#resuming-a-session).
196</Note>
192> [!NOTE]
193>
194> For what it costs to resume a conversation you started before the upgrade, see [Resuming a session](#resuming-a-session).
197195 
198196## Actions that keep the cache
199197 

quickstart Changed · +101 / -105 lines

from line 12
1212* A code project to work with
1313* A [Claude subscription](https://claude.com/pricing?utm_source=claude_code\&utm_medium=docs\&utm_content=quickstart_prereq) (Pro, Max, Team, or Enterprise), [Claude Console](https://platform.claude.com/) account, or access through a [supported cloud provider](/docs/en/third-party-integrations)
1414 
15<Note>
16 These cases are covered on other pages:
15> [!NOTE]
16>
17> These cases are covered on other pages:
18>
19> * **Never used a terminal before**: start with the [terminal guide](/docs/en/terminal-guide)
20> * **Want Claude Code somewhere other than the terminal**: Claude Code is also available on the [web](https://claude.ai/code), as a [desktop app](/docs/en/desktop), in [VS Code](/docs/en/vs-code) and [JetBrains IDEs](/docs/en/jetbrains), in [Slack](/docs/en/slack), and in CI/CD with [GitHub Actions](/docs/en/github-actions) and [GitLab](/docs/en/gitlab-ci-cd). See [all interfaces](/docs/en/overview#use-claude-code-everywhere).
1721 
18 * **Never used a terminal before**: start with the [terminal guide](/docs/en/terminal-guide)
19 * **Want Claude Code somewhere other than the terminal**: Claude Code is also available on the [web](https://claude.ai/code), as a [desktop app](/docs/en/desktop), in [VS Code](/docs/en/vs-code) and [JetBrains IDEs](/docs/en/jetbrains), in [Slack](/docs/en/slack), and in CI/CD with [GitHub Actions](/docs/en/github-actions) and [GitLab](/docs/en/gitlab-ci-cd). See [all interfaces](/docs/en/overview#use-claude-code-everywhere).
20</Note>
21 
2222## Step 1: Install Claude Code
2323 
2424To install Claude Code, open a terminal and run the command for your system. If you haven't used a terminal before, the [terminal guide](/docs/en/terminal-guide) shows how to open one and paste the command.
2525 
26<Tabs>
27 <Tab title="Native Install (Recommended)">
28 **macOS, Linux, WSL:**
26**Native Install (Recommended)**
2927 
30 ```bash theme={null}
31 curl -fsSL https://claude.ai/install.sh | bash
32 ```
28**macOS, Linux, WSL:**
3329 
34 On Windows, your prompt shows `PS C:\` when you're in PowerShell and `C:\` without the `PS` when you're in CMD.
30```bash theme={null}
31curl -fsSL https://claude.ai/install.sh | bash
32```
3533 
36 **Windows PowerShell:**
34On Windows, your prompt shows `PS C:\` when you're in PowerShell and `C:\` without the `PS` when you're in CMD.
3735 
38 ```powershell theme={null}
39 irm https://claude.ai/install.ps1 | iex
40 ```
36**Windows PowerShell:**
4137 
42 **Windows CMD:**
38```powershell theme={null}
39irm https://claude.ai/install.ps1 | iex
40```
4341 
44 ```batch theme={null}
45 curl -fsSL https://claude.ai/install.cmd -o install.cmd && install.cmd && del install.cmd
46 ```
42**Windows CMD:**
4743 
48 The install command shows no progress while it downloads Claude Code. When the installer finishes, open a new terminal window and run `claude --version`. A working installation prints a version number. If your shell says `claude` isn't found or isn't recognized, the install directory isn't on your PATH yet: see [Fix your PATH](/docs/en/troubleshoot-install#command-not-found-claude-after-installation).
44```batch theme={null}
45curl -fsSL https://claude.ai/install.cmd -o install.cmd && install.cmd && del install.cmd
46```
4947 
50 If you see `The token '&&' is not a valid statement separator`, you're in PowerShell, not CMD. If you see `'irm' is not recognized as an internal or external command`, you're in CMD, not PowerShell.
48The install command shows no progress while it downloads Claude Code. When the installer finishes, open a new terminal window and run `claude --version`. A working installation prints a version number. If your shell says `claude` isn't found or isn't recognized, the install directory isn't on your PATH yet: see [Fix your PATH](/docs/en/troubleshoot-install#command-not-found-claude-after-installation).
5149 
52 If the install command fails with `syntax error near unexpected token '<'`, a `403`, or any other error, see [Troubleshoot installation](/docs/en/troubleshoot-install#find-your-error) to match the error to a fix and for alternative install methods.
50If you see `The token '&&' is not a valid statement separator`, you're in PowerShell, not CMD. If you see `'irm' is not recognized as an internal or external command`, you're in CMD, not PowerShell.
5351 
54 [Git for Windows](https://git-scm.com/downloads/win) is recommended on native Windows so Claude Code can use the Bash tool. If Git for Windows is not installed, Claude Code uses PowerShell as the shell tool instead. WSL setups do not need Git for Windows.
52If the install command fails with `syntax error near unexpected token '<'`, a `403`, or any other error, see [Troubleshoot installation](/docs/en/troubleshoot-install#find-your-error) to match the error to a fix and for alternative install methods.
5553 
56 <Info>
57 Native installations automatically update in the background to keep you on the latest version.
58 </Info>
59 </Tab>
54[Git for Windows](https://git-scm.com/downloads/win) is recommended on native Windows so Claude Code can use the Bash tool. If Git for Windows is not installed, Claude Code uses PowerShell as the shell tool instead. WSL setups do not need Git for Windows.
6055 
61 <Tab title="Homebrew">
62 ```bash theme={null}
63 brew install --cask claude-code
64 ```
56> [!NOTE]
57>
58> Native installations automatically update in the background to keep you on the latest version.
6559 
66 Homebrew offers two casks. `claude-code` tracks the stable release channel, which is typically about a week behind and skips releases with major regressions. `claude-code@latest` tracks the latest channel and receives new versions as soon as they ship.
60**Homebrew**
6761 
68 <Info>
69 Homebrew installations do not auto-update. Run `brew upgrade claude-code` or `brew upgrade claude-code@latest`, depending on which cask you installed, to get the latest features and security fixes.
70 </Info>
71 </Tab>
62```bash theme={null}
63brew install --cask claude-code
64```
7265 
73 <Tab title="WinGet">
74 ```powershell theme={null}
75 winget install Anthropic.ClaudeCode
76 ```
66Homebrew offers two casks. `claude-code` tracks the stable release channel, which is typically about a week behind and skips releases with major regressions. `claude-code@latest` tracks the latest channel and receives new versions as soon as they ship.
7767 
78 <Info>
79 WinGet installations do not auto-update. Run `winget upgrade Anthropic.ClaudeCode` periodically to get the latest features and security fixes.
80 </Info>
81 </Tab>
82</Tabs>
68> [!NOTE]
69>
70> Homebrew installations do not auto-update. Run `brew upgrade claude-code` or `brew upgrade claude-code@latest`, depending on which cask you installed, to get the latest features and security fixes.
8371 
72**WinGet**
73 
74```powershell theme={null}
75winget install Anthropic.ClaudeCode
76```
77 
78> [!NOTE]
79>
80> WinGet installations do not auto-update. Run `winget upgrade Anthropic.ClaudeCode` periodically to get the latest features and security fixes.
81 
8482You can also install with [apt, dnf, or apk](/docs/en/setup#install-with-linux-package-managers) on Debian, Fedora, RHEL, and Alpine.
8583 
8684To confirm the installation worked, run:
from line 149
151149can Claude Code work with Docker?
152150```
153151 
154<Note>
155 Claude Code reads your project files as needed. You don't have to manually add context.
156</Note>
152> [!NOTE]
153>
154> Claude Code reads your project files as needed. You don't have to manually add context.
157155 
158156## Step 4: Make your first code change
159157 
from line 225
227225review my changes and suggest improvements
228226```
229227 
230<Tip>
231 Talk to Claude like you would a helpful colleague. Describe what you want to achieve, and it will help you get there.
232</Tip>
228> [!TIP]
229>
230> Talk to Claude like you would a helpful colleague. Describe what you want to achieve, and it will help you get there.
233231 
234232## Essential commands
235233 
from line 263
265263 
266264For more, see [best practices](/docs/en/best-practices) and [common workflows](/docs/en/common-workflows).
267265 
268<AccordionGroup>
269 <Accordion title="Be specific with your requests">
270 Instead of: "fix the bug"
266> **Be specific with your requests**
267>
268> Instead of: "fix the bug"
269>
270> Try: "fix the login bug where users see a blank screen after entering wrong credentials"
271271 
272 Try: "fix the login bug where users see a blank screen after entering wrong credentials"
273 </Accordion>
272> **Use step-by-step instructions**
273>
274> Break complex tasks into steps:
275>
276> ```text wrap theme={null}
277> 1. create a new database table for user profiles
278> 2. create an API endpoint to get and update user profiles
279> 3. build a webpage that allows users to see and edit their information
280> ```
274281 
275 <Accordion title="Use step-by-step instructions">
276 Break complex tasks into steps:
282> **Let Claude explore first**
283>
284> Before making changes, let Claude understand your code:
285>
286> ```text wrap theme={null}
287> analyze the database schema
288> ```
289>
290> ```text wrap theme={null}
291> build a dashboard showing products that are most frequently returned by our UK customers
292> ```
277293 
278 ```text wrap theme={null}
279 1. create a new database table for user profiles
280 2. create an API endpoint to get and update user profiles
281 3. build a webpage that allows users to see and edit their information
282 ```
283 </Accordion>
284 
285 <Accordion title="Let Claude explore first">
286 Before making changes, let Claude understand your code:
287 
288 ```text wrap theme={null}
289 analyze the database schema
290 ```
291 
292 ```text wrap theme={null}
293 build a dashboard showing products that are most frequently returned by our UK customers
294 ```
295 </Accordion>
296 
297 <Accordion title="Save time with shortcuts">
298 * Type `/` to see the commands and skills available to you
299 * Use Tab for command completion
300 * Press ↑ for command history
301 * Press `Shift+Tab` to cycle permission modes
302 </Accordion>
303</AccordionGroup>
294> **Save time with shortcuts**
295>
296> * Type `/` to see the commands and skills available to you
297> * Use Tab for command completion
298> * Press ↑ for command history
299> * Press `Shift+Tab` to cycle permission modes
304300 
305301## What's next?
306302 
Feedback