SpyBara
Go Premium

plugins/components.md 2026-09-24 22:57 UTC to 2026-09-25 23:58 UTC

This page contains 1130 additions and 0 deletions.

2026
Fri 25 23:58

向插件添加组件

向 Claude Code 插件添加 skills、hooks、MCP 服务器和其他所有组件类型,并提供针对每种类型的验证示例。

export const Piece = ({id, children}) =>

{children}
;

export const PluginExplorer = ({children}) => { const PIECES = [{ id: 'manifest', name: 'Manifest', path: '.claude-plugin/plugin.json', required: "Required by Anthropic's directory", lines: [{ depth: 0, kind: 'folder', text: '.claude-plugin/' }, { depth: 1, kind: 'file', text: 'plugin.json' }], href: '/en/plugins/manifest-reference#manifest-file', linkText: 'Go to the manifest reference' }, { id: 'skills', name: 'Skills', path: 'skills/review/SKILL.md', lines: [{ depth: 0, kind: 'folder', text: 'skills/' }, { depth: 1, kind: 'folder', text: 'review/' }, { depth: 2, kind: 'file', text: 'SKILL.md' }], href: '/en/plugins/components#skills', linkText: 'Go to the Skills section' }, { id: 'commands', name: 'Commands', path: 'commands/about.md', lines: [{ depth: 0, kind: 'folder', text: 'commands/' }, { depth: 1, kind: 'file', text: 'about.md' }], href: '/en/plugins/components#commands', linkText: 'Go to the Commands section' }, { id: 'agents', name: 'Agents', path: 'agents/security-reviewer.md', lines: [{ depth: 0, kind: 'folder', text: 'agents/' }, { depth: 1, kind: 'file', text: 'security-reviewer.md' }], href: '/en/plugins/components#agents', linkText: 'Go to the Agents section' }, { id: 'hooks', name: 'Hooks', path: 'hooks/hooks.json', lines: [{ depth: 0, kind: 'folder', text: 'hooks/' }, { depth: 1, kind: 'file', text: 'hooks.json' }], href: '/en/plugins/components#hooks', linkText: 'Go to the Hooks section' }, { id: 'monitors', name: 'Monitors', path: 'monitors/monitors.json', lines: [{ depth: 0, kind: 'folder', text: 'monitors/' }, { depth: 1, kind: 'file', text: 'monitors.json' }], href: '/en/plugins/components#monitors', linkText: 'Go to the Monitors section' }, { id: 'output-styles', name: 'Output styles', path: 'output-styles/terse.md', lines: [{ depth: 0, kind: 'folder', text: 'output-styles/' }, { depth: 1, kind: 'file', text: 'terse.md' }], href: '/en/plugins/components#themes-and-output-styles', linkText: 'Go to the Themes and output styles section' }, { id: 'themes', name: 'Themes', path: 'themes/dracula.json', lines: [{ depth: 0, kind: 'folder', text: 'themes/' }, { depth: 1, kind: 'file', text: 'dracula.json' }], href: '/en/plugins/components#themes-and-output-styles', linkText: 'Go to the Themes and output styles section' }, { id: 'workflows', name: 'Workflows', path: 'workflows/audit-routes.js', lines: [{ depth: 0, kind: 'folder', text: 'workflows/' }, { depth: 1, kind: 'file', text: 'audit-routes.js' }], href: '/en/workflows#distribute-a-workflow-in-a-plugin', linkText: 'Go to Distribute a workflow in a plugin' }, { id: 'bin', name: 'Executables', path: 'bin/hello-plugin', lines: [{ depth: 0, kind: 'folder', text: 'bin/' }, { depth: 1, kind: 'file', text: 'hello-plugin' }], href: '/en/plugins/components#executables', linkText: 'Go to the Executables section' }, { id: 'scripts', name: 'Scripts', path: 'scripts/format.sh', lines: [{ depth: 0, kind: 'folder', text: 'scripts/' }, { depth: 1, kind: 'file', text: 'format.sh' }], href: '/en/plugins/components#hooks', linkText: 'Go to the Hooks section' }, { id: 'settings', name: 'Default settings', path: 'settings.json', lines: [{ depth: 0, kind: 'file', text: 'settings.json' }], href: '/en/plugins/components#default-settings', linkText: 'Go to the Default settings section' }, { id: 'mcp', name: 'MCP servers', path: '.mcp.json', lines: [{ depth: 0, kind: 'file', text: '.mcp.json' }], href: '/en/plugins/components#mcp-servers', linkText: 'Go to the MCP servers section' }, { id: 'lsp', name: 'LSP servers', path: '.lsp.json', lines: [{ depth: 0, kind: 'file', text: '.lsp.json' }], href: '/en/plugins/components#lsp-servers', linkText: 'Go to the LSP servers section' }]; const [selectedId, setSelectedId] = useState('manifest'); const [isFullscreen, setIsFullscreen] = useState(false); const rootRef = useRef(null); useEffect(() => { const onFsChange = () => setIsFullscreen(!!document.fullscreenElement); document.addEventListener('fullscreenchange', onFsChange); return () => document.removeEventListener('fullscreenchange', onFsChange); }, []); const toggleFullscreen = () => { if (!rootRef.current) return; if (document.fullscreenElement) document.exitFullscreen(); else rootRef.current.requestFullscreen().catch(() => {}); }; const selected = PIECES.find(p => p.id === selectedId) || PIECES[0]; const onTreeKeyDown = e => { const keys = ['ArrowDown', 'ArrowUp', 'Home', 'End']; if (keys.indexOf(e.key) === -1) return; const i = PIECES.findIndex(p => p.id === selectedId); let next = i; if (e.key === 'ArrowDown') next = Math.min(PIECES.length - 1, i + 1); if (e.key === 'ArrowUp') next = Math.max(0, i - 1); if (e.key === 'Home') next = 0; if (e.key === 'End') next = PIECES.length - 1; e.preventDefault(); if (next === i) return; const id = PIECES[next].id; setSelectedId(id); const el = document.getElementById('pe-node-' + id); if (el) el.focus(); }; const FolderIcon = () => ; const FileIcon = () => ; return <div ref={rootRef} className={isFullscreen ? 'pe-root pe-fullscreen not-prose' : 'pe-root not-prose'} data-selected={selected.id}>

  <div className="pe-head">
    <div className="pe-head-text">
      <div className="pe-title">What goes in a plugin</div>
      <div className="pe-sub">This example plugin, <code>my-plugin</code>, has one of every kind of component, each in its default location. Select a file or folder to read what it’s for and see what goes in it.</div>
    </div>
    <button type="button" className="pe-fs-btn" onClick={toggleFullscreen} aria-label={isFullscreen ? 'Exit fullscreen' : 'Fullscreen'} title={isFullscreen ? 'Exit fullscreen' : 'Fullscreen'}>
      {isFullscreen ? '⤡' : '⛶'}
    </button>
  </div>

  <div className="pe-body">
    <div className="pe-tree-pane">
      <div className="pe-caption" id="pe-tree-caption">Plugin directory</div>
      <div role="group" aria-labelledby="pe-tree-caption" onKeyDown={onTreeKeyDown}>
        <div className="pe-rootline"><FolderIcon /><span>my-plugin/</span></div>
        {PIECES.map(p => <button key={p.id} id={'pe-node-' + p.id} type="button" className="pe-node" aria-pressed={p.id === selected.id} aria-label={p.name + ', ' + p.path} onClick={() => setSelectedId(p.id)}>
            {p.lines.map((line, i) => <span key={i} className="pe-line pe-line-tree" style={{
paddingLeft: line.depth * 18 + 'px'

}}> {line.kind === 'folder' ? : } {line.text} {p.required && i === p.lines.length - 1 ? {p.required} : null} )} {p.path} {p.required ? {p.required} : null} )}

    <div className="pe-panel" role="region" aria-labelledby="pe-panel-caption" aria-live="polite" aria-atomic="true">
      <div className="pe-caption" id="pe-panel-caption">Selected piece</div>
      <div className="pe-name">{selected.name}{selected.required ? <span className="pe-req">{selected.required}</span> : null}</div>
      <div className="pe-path">{selected.path}</div>

      <div className="pe-block">{children}</div>

      <a className="pe-link" href={selected.href}>{selected.linkText}</a>
    </div>
  </div>
</div>;

};

Claude Code 插件由多个组件构建而成,例如 skills、agents、hooks 和 MCP 服务器。每个组件在插件中都有一个默认文件夹,在 .claude-plugin/plugin.json 中有一个可选的清单键来替换或添加到该文件夹,以及用户看到的名称。有关每个键的完整字段表,请参阅清单参考。

使用此页面向已加载的插件添加组件。

添加组件后,在运行中的会话中运行 /reload-plugins 或启动新会话,以便 Claude Code 加载它。要在加载前检查组件的文件,请从插件目录在 shell 中运行 claude plugin validate .。

浏览插件目录

浏览器显示了一个示例插件 my-plugin,它在其默认位置拥有每种组件的一个副本:

每个文件都是其格式的最小有效示例,用于展示形状而不是实用性:真实的 skill 或 agent 包含完整的说明,通常还有支持文件,真实的 hook 或监视器执行真实的工作。浏览器后的部分使用与浏览器相同的文件作为示例,并链接到更完整的文件。选择一个文件或文件夹来阅读其用途、查看其内容,并找到涵盖它的部分。

[清单](/docs/zh-CN/plugins/manifest-reference)是插件 `.claude-plugin/` 目录中的 `plugin.json` 文件。它包含插件的元数据和 Claude Code 提示用户的 `userConfig` 值。只有 `name` 是必需的。在这个文件中,`description` 是用户在 `/plugin` 中看到的插件文本,`version` 使用户保持在该版本,直到您更改它:
```json theme={null}
{
  "name": "my-plugin",
  "version": "1.0.0",
  "description": "Review, formatting, and database tools for this team"
}
```
一个 [skill](/docs/zh-CN/skills) 是一个 `SKILL.md` 文件。将每个 skill 保存在 `skills/` 下的自己的目录中。Claude 读取每个 skill 的 `description`,当用户要求的内容与其匹配时,例如在这里要求 Claude 审查拉取请求,Claude 加载 skill 的说明并遵循它们。用户也可以直接将其作为 `/my-plugin:review` 运行:
```markdown theme={null}
---
description: Reviews a pull request for style and test coverage. Use when asked to review code.
---

Review the changed files. Report style problems first, then missing tests.
```
命令是用户按名称运行的单个 Markdown 文件。命令是较旧的格式:skill 以相同的方式按名称运行,也可以在其自己的目录中携带支持文件,因此将新的写成 skills,并为您已有的文件保留 `commands/`。此文件变成 `/my-plugin:about` 并采用与 skill 相同的 frontmatter:
```markdown theme={null}
---
description: Summarize the repository
---

Summarize what this repository does in three sentences.
```
一个[子代理](/docs/zh-CN/sub-agents)是一个单独的助手,拥有自己的说明和自己的上下文窗口,Claude 可以将任务委托给它并获得结果。`agents/` 下的每个 Markdown 文件定义一个:frontmatter 命名它并说明何时使用它,正文是其系统提示。这个被命名为 `my-plugin:security-reviewer`,用户可以使用 `@agent-my-plugin:security-reviewer` 调用它:
```markdown theme={null}
---
name: security-reviewer
description: Reviews code changes for security issues. Use after edits to authentication or input handling.
model: sonnet
---

You are a security reviewer. Read the changed files and report injection, authentication, and secrets-handling risks.
```
一个 [hook](/docs/zh-CN/hooks-guide) 在 Claude Code 生命周期中的某个点自动运行某些内容,例如在每次文件编辑后:shell 命令、HTTP 请求、MCP 工具调用、对模型的提示或子代理。将插件的 hooks 保存在插件根目录的 `hooks/hooks.json` 中。这个在 Claude 写入或编辑文件后运行插件的 `scripts/format.sh`:
```json theme={null}
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "\"${CLAUDE_PLUGIN_ROOT}/scripts/format.sh\""
          }
        ]
      }
    ]
  }
}
```
监视器是一个 shell 命令,Claude Code 在会话启动时在后台启动并保持运行直到会话结束,使用 [Monitor 工具](/docs/zh-CN/tools-reference#monitor-tool)。它打印的内容作为通知到达 Claude。`when` 字段可以改为在命名 skill 首次运行时启动它。这个跟踪错误日志:
```json theme={null}
[
  {
    "name": "error-log",
    "command": "tail -F ./logs/error.log",
    "description": "Application error log"
  }
]
```
插件可以包含[输出样式](/docs/zh-CN/output-styles),这改变了 Claude 如何格式化和表述其回复。将每个输出样式保存为 `output-styles/.md`。这个在 `/output-style` 中显示为 `my-plugin:terse`:
```markdown theme={null}
---
name: terse
description: Answer in as few words as possible
keep-coding-instructions: true
---

Keep every reply short. Skip preambles and summaries.
```
插件可以包含 [Claude Code 界面的颜色主题](/docs/zh-CN/terminal-config#create-a-custom-theme)。将每个主题保存为 `themes/.json`。这个在 `/theme` 中显示为 `Dracula`,标记为来自 `my-plugin`:
```json theme={null}
{
  "name": "Dracula",
  "base": "dark",
  "overrides": {
    "claude": "#bd93f9",
    "error": "#ff5555"
  }
}
```
`workflows/` 文件夹包含 [workflow](/docs/zh-CN/workflows) `.js` 文件:一个 `meta` 块,然后是协调多个子代理的脚本正文。这个作为 `/my-plugin:audit-routes` 运行:
```javascript theme={null}
export const meta = {
  name: 'audit-routes',
  description: 'Audit every route handler for missing auth checks',
}

const found = await agent('List every .ts file under src/routes/.', {
  schema: { type: 'object', required: ['files'], properties: { files: { type: 'array', items: { type: 'string' } } } },
})

const audits = await pipeline(found.files, file =>
  agent(`Audit ${file} for missing authentication checks.`, { label: file }),
)

return audits.filter(Boolean)
```
`bin/` 是插件如何提供命令行工具的方式。启用插件时,Claude Code 将此文件夹放在它运行命令的 shell 的 `PATH` 上,因此 Claude 或 skill 的说明可以按名称运行该工具,而无需用户安装任何东西。有了这个[可执行文件](#executables),`hello-plugin` 是 Claude 可以运行的命令:
```bash theme={null}
#!/bin/bash
echo "hello from my-plugin"
```
`hooks/hooks.json` 中的 hook 运行一个脚本,这个文件夹是示例保留它的地方。名称 `scripts/` 是一个约定,不是 Claude Code 查找的东西:hook 通过其路径指向文件,`${CLAUDE_PLUGIN_ROOT}/scripts/format.sh`。格式化脚本可能看起来像这样:
```bash theme={null}
#!/bin/bash
npx prettier --write .
```
插件根目录中的 `settings.json` 包含在启用插件时应用的[设置](/docs/zh-CN/settings-reference),因此插件可以改变会话的行为方式,而不仅仅是添加组件。只有两个键从插件生效,[`agent`](/docs/zh-CN/settings-reference#agent) 和 [`subagentStatusLine`](/docs/zh-CN/settings-reference#subagentstatusline);所有其他键都被丢弃。请参阅[默认设置](#default-settings)。
这个设置 `agent`,它将会话的主线程作为插件自己的 `security-reviewer` agent 运行,因此该 agent 的系统提示、工具限制和模型应用于整个会话:

```json theme={null}
{
  "agent": "security-reviewer"
}
```
一个 [MCP 服务器](/docs/zh-CN/mcp)从外部系统为 Claude 提供工具。在插件根目录的 `.mcp.json` 中声明它。这个从插件内的脚本启动本地服务器,并在 `/mcp` 中显示为 `plugin:my-plugin:db`:
```json theme={null}
{
  "mcpServers": {
    "db": {
      "command": "node",
      "args": ["${CLAUDE_PLUGIN_ROOT}/server.js"]
    }
  }
}
```
LSP 服务器为 Claude 提供[诊断和代码导航](/docs/zh-CN/plugins/code-intelligence)。在插件根目录的 `.lsp.json` 中声明服务器。这个为 `.go` 文件连接 Go 语言服务器:
```json theme={null}
{
  "gopls": {
    "command": "gopls",
    "args": ["serve"],
    "extensionToLanguage": {
      ".go": "go"
    }
  }
}
```

添加每种组件

下面的每个部分涵盖一种组件:其文件在插件中的位置、一个验证的示例、插件加载后用户看到的内容,以及改变默认位置的清单键。添加您的插件需要的那些;没有一个是必需的。

Skills

一个 skill 是一个 SKILL.md 文件,当其描述与任务匹配时 Claude 可以加载它。用户也可以将其作为命令运行。将每个 skill 保存在 skills/ 下的自己的目录中:

my-plugin/
├── .claude-plugin/
│   └── plugin.json
└── skills/
    └── review/
        └── SKILL.md

给 SKILL.md 一个 description,以便 Claude 知道何时使用它:

---
description: Reviews a pull request for style and test coverage. Use when asked to review code.
---

Review the changed files. Report style problems first, then missing tests.

加载插件后,/my-plugin:review 运行 skill。命令名称和谁可以调用它遵循这些规则:

您也可以将 skills 放在默认 skills/ 目录之外:

要在插件中包含说明,请将其写成 skill。Claude Code 不加载插件根目录中的 CLAUDE.md,claude plugin validate 警告 CLAUDE.md at the plugin root is not loaded as project context。

对于 frontmatter 字段和支持文件,请参阅 Skills。

命令

命令是用户按名称运行的单个 Markdown 文件,例如 /my-plugin:about。

将命令保存在 commands/<file>.md,它变成 /<plugin>:<file>。子目录添加一个段,所以 commands/db/migrate.md 是 /my-plugin:db:migrate。

命令文件采用与 skills 相同的 frontmatter。

在清单中定义命令

只有当您想将命令文件保留在 commands/ 之外的某个地方,或在 plugin.json 中定义一个短命令而不需要单独的 Markdown 文件时,您才需要这样做。设置 commands 清单键,Claude Code 读取它而不是扫描 commands/。该键采用路径、路径数组或将每个命令名称映射到 source 文件或内联 content 的对象。

此清单内联定义 /my-plugin:about,没有 Markdown 文件:

{
  "name": "my-plugin",
  "commands": {
    "about": {
      "content": "Summarize what this repository does in three sentences.",
      "description": "Summarize the repository"
    }
  }
}

加载插件并在会话中运行 /my-plugin:about 以确认它已加载。

对于完整的键语法,请参阅 commands。

Agents

一个子代理是一个单独的助手,拥有自己的说明和上下文窗口,Claude 可以将任务委托给它。agents/ 下的每个 Markdown 文件定义一个:

---
name: security-reviewer
description: Reviews code changes for security issues. Use after edits to authentication or input handling.
model: sonnet
---

You are a security reviewer. Read the changed files and report injection, authentication, and secrets-handling risks.

此 agent 被命名为 my-plugin:security-reviewer,用户可以显式调用它使用 @agent-my-plugin:security-reviewer。名称形式是 <plugin>:<name>,其中 <name> 来自 frontmatter,或当没有时来自文件名。

agents 清单键替换 agents/ 扫描。

在子文件夹中组织 agents

您可以将插件 agent 文件放在 agents/ 的子文件夹中。Claude Code 递归加载它们并用冒号连接插件名称、每个子文件夹名称和文件名以形成 agent 的作用域名称。例如,my-plugin 中的 agents/review/security.md 加载为 my-plugin:review:security。两个设置改变该名称:

插件 agents 中的 Frontmatter 字段

插件 agent 的 frontmatter 遵循这些规则:

对于每个字段的作用和优先级规则,请参阅 Subagents。

Hooks

一个 hook 在 Claude Code 生命周期中的某个点自动运行某些内容,例如在每次文件编辑后:shell 命令、HTTP 请求、MCP 工具调用、对模型的提示或子代理。将插件的 hooks 保存在插件根目录的 hooks/hooks.json 中,在顶级 "hooks" 键下,形状与 settings.json 中的 hooks 对象相同。这让您可以复制现有的设置 hook 而不改变。

此 hook 在每次 Write 或 Edit 后运行一个捆绑脚本:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "\"${CLAUDE_PLUGIN_ROOT}/scripts/format.sh\""
          }
        ]
      }
    ]
  }
}

将脚本保存在 scripts/format.sh 并使其可执行。

加载插件并要求 Claude 编辑文件。退出 0 的 PostToolUse hook 在记录中显示任何内容,所以用调试日志或脚本本身改变的内容确认它运行。

hooks/hooks.json 和 hooks 清单键中的 Hooks 都加载。对于每个事件及其有效负载,请参阅 Hook 事件。

插件 hooks 何时触发

插件的 hooks 不等待使用插件的一个 skills 或命令。Claude Code 在会话加载插件时注册它们,从那时起它们在其事件上触发。要限制 hook 何时运行,缩小其 matcher。

如果 hook 从不触发,请参阅不触发的 hooks。

环境、引用和匹配 MCP 工具

hook 的环境、${CLAUDE_PLUGIN_ROOT} 的引用和插件自己的 MCP 工具的匹配器工作如下:

MCP 服务器

MCP 服务器从外部系统为 Claude 提供工具。在插件根目录的 .mcp.json 中声明它,形状与项目 .mcp.json 相同。此 .mcp.json 声明一个名为 db 的服务器:

{
  "mcpServers": {
    "db": {
      "command": "node",
      "args": ["${CLAUDE_PLUGIN_ROOT}/server.js"]
    }
  }
}

您也可以省略 mcpServers 包装器并将 db 放在文件的顶级。

加载插件并运行 /mcp 以确认服务器显示为 plugin:my-plugin:db。

claude plugin validate 检查 .mcp.json 并报告 Claude Code 在加载时会丢弃的服务器条目为错误。需要 Claude Code v2.1.281 或更高版本。

对于坏条目在加载时显示的位置,请参阅不启动的 MCP 服务器。

mcpServers 清单键采用内联服务器映射、JSON 文件的路径或这些的数组。当清单服务器与 .mcp.json 中的一个同名时,清单服务器替换它。

到达 claude.ai 和 Cowork 中的用户

本地 stdio 服务器,例如 MCP 服务器 下的 db 服务器,在 Claude Code 和在 Claude Desktop 应用中在您的机器上运行的 Cowork 会话中运行,但不在 claude.ai 上。要到达那里的用户,通过其 https:// URL 引用远程服务器,claude.ai 和 Cowork 作为连接器提供给用户。

服务器名称、工具名称和重新加载

服务器的名称、变量替换和重新加载行为遵循这些规则:

包含打包的 MCPB 服务器

mcpServers 键也接受打包的服务器作为 MCPB 文件,其扩展名是 .mcpb 或较旧的 .dxt。将键指向文件,作为插件内的路径或 https:// URL:

{
  "name": "my-plugin",
  "mcpServers": "./servers/db.mcpb"
}

服务器从包的清单中的 name 获取其名称。

对于传输和身份验证,请参阅 MCP。

LSP 服务器

LSP 服务器为 Claude 提供诊断和代码导航。如果官方代码智能插件已经涵盖您的语言,安装那个而不是写一个。否则在插件根目录的 .lsp.json 中声明服务器:

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

文件直接将每个服务器名称映射到其配置,没有围绕映射的包装对象。command 是二进制的名称,其参数在 args 中。extensionToLanguage 需要至少一个扩展名,每个以 . 开头。

claude plugin validate 不读取此文件。当任何条目无效时,整个文件在加载时被跳过,Invalid LSP server config for ".lsp.json" 出现在 /plugin Errors 标签中。

您的插件配置连接但不安装服务器二进制,每个文件扩展名获得一个服务器:

lspServers 清单键采用相同的映射内联、JSON 文件的路径或这些的数组,其服务器添加到 .lsp.json 中的那些。当清单服务器与 .lsp.json 中的一个同名时,清单服务器替换它。

对于 transport、超时、重启和其他字段,请参阅 lspServers。

将日志输出发送到 stderr,而不是 stdout。Claude Code 仅将服务器的 stdout 读取为协议消息,并接受最多 64 KiB 的消息头和最多 32 MiB 的消息正文。

Claude Code 断开超过任一限制或向 stdout 写入非协议输出的服务器,并将断开连接计为 restartOnCrash 和 maxRestarts 的崩溃。当您使用 --debug 运行时,Claude Code 将命名原因的错误写入调试日志。

可执行文件

插件根目录中 bin/ 中的文件在启用插件时位于 Bash 工具的 shell 的 PATH 上,所以 Claude 可以将它们作为裸命令运行。添加一个可执行脚本:

#!/bin/bash
echo "hello from my-plugin"

使用 chmod +x bin/hello-plugin 使其可执行并加载插件。当您要求 Claude 运行 hello-plugin 时,Bash 工具结果显示脚本的输出。

插件 bin/ 目录在用户自己的 PATH 条目之后,所以插件不能影响 git、ls 或另一个系统命令。

claude.ai 和 Cowork 不安装具有顶级 bin/ 目录的插件,包括您通过 claude.ai 组织设置分发的那个。

默认设置

要设置在启用插件时应用的默认值,在插件根目录添加 settings.json,或将相同的对象内联放在 settings 清单键中。两个键生效,agent 和 subagentStatusLine,所有其他键都被丢弃。

设置 agent 以将插件自己的一个 agents 作为主线程运行:

{
  "agent": "security-reviewer"
}

加载插件并启动会话。Claude 然后在主对话中使用 security-reviewer agent 的系统提示和模型回答。

对于键控制的所有内容,请参阅 agent 设置。

当相同的键在多个地方设置时,这些规则决定哪个值应用:

对于 subagentStatusLine 形状,请参阅子代理状态行。

主题和输出样式

插件可以包含颜色主题和输出样式。两者都显示在与用户自己相同的选择器中。对于任一个,设置清单键替换文件夹扫描。

组件 保存为 格式 显示在 清单键
主题 themes/<slug>.json 用户在 ~/.claude/themes/ 中写入的自定义主题文件格式 /theme,在文件的 name 下 experimental.themes
输出样式 output-styles/<name>.md 自定义输出样式格式,带有 name 和 description frontmatter /output-style,作为 <plugin>:<name> outputStyles

插件主题是只读的,所以当用户在 /theme 中编辑一个时,编辑被保存为他们自己的主题目录中的副本。

此主题在深色预设上重新着色提示符强调和错误文本:

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

频道

一个频道让外部系统(例如聊天应用)将消息发送到会话中。在插件中,频道是 MCP 服务器之一加上一个 channels 条目,将其绑定并可以提示其自己的配置。此清单将频道绑定到 telegram 服务器并要求机器人令牌:

{
  "name": "my-plugin",
  "mcpServers": {
    "telegram": {
      "command": "node",
      "args": ["${CLAUDE_PLUGIN_ROOT}/server.js"],
      "env": { "BOT_TOKEN": "${user_config.bot_token}" }
    }
  },
  "channels": [
    {
      "server": "telegram",
      "userConfig": {
        "bot_token": {
          "type": "string",
          "title": "Bot token",
          "description": "Telegram bot token",
          "sensitive": true
        }
      }
    }
  ]
}

server 必须匹配 mcpServers 中的键。每个频道的 userConfig 采用与顶级 userConfig 键相同的形状。

对于服务器必须实现的内容以及用户如何启用频道插件,请参阅频道参考中的打包为插件。对于字段表,请参阅 channels。

监视器

监视器是在整个会话中在后台运行的 shell 命令。它打印的内容作为通知到达 Claude,所以 Claude 可以对日志或状态更改做出反应,而无需被要求观看它。将条目保存在 monitors/monitors.json 中:

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

命令在 shell 中运行,在会话启动的工作目录中。

监视器的命令在它启动的位置和它可以引用的内容中受到限制:

experimental.monitors 清单键采用相同的数组内联或 JSON 文件的路径,并代替 monitors/monitors.json 读取。

对于 when 触发器和其他字段,请参阅 monitors。

要求用户提供配置值

在 userConfig 清单键中声明您的插件需要的值,以便用户不自己编辑 settings.json。每个选项显示在一个对话框中,其 title 作为标签,其 description 在下方。

为令牌或密码设置 "sensitive": true。对话框然后掩盖输入,值存储在安全存储中而不是 settings.json。

此清单要求端点和令牌:

{
  "name": "my-plugin",
  "userConfig": {
    "api_url": {
      "type": "string",
      "title": "API URL",
      "description": "Base URL of your team's API"
    },
    "api_token": {
      "type": "string",
      "title": "API token",
      "description": "Token for your team's API",
      "sensitive": true
    }
  }
}

配置对话框何时出现

对话框仅在交互式 /plugin 界面中出现。当用户执行以下任何操作时,它为任何尚未设置的选项打开:

要在任何时间打开相同的对话框,用户运行 /plugin configure <plugin>@<marketplace>。

claude plugin install shell 命令从不提示 userConfig 值。要从 shell 设置值,将每个值作为 --config KEY=VALUE 传递。当选项保持未设置时,命令打印一个 userConfig options not yet set 行,命名两种设置它们的方式。userConfig 对话框从不出现引用该行。

对于选项字段、每个值存储的位置、组件如何引用保存的值以及哪些字段拒绝 ${user_config.*},请参阅用户配置。

引用插件路径和存储数据

您不知道您的插件将被安装在哪里,所以通过这些变量而不是固定路径引用其文件和数据。它们在 skill、命令和 agent 内容、hook 和监视器命令以及 MCP 和 LSP 服务器配置中被替换。它们也被导出到 hook、MCP 和 LSP 进程:

在数据目录路径中,<id> 是插件标识符,每个字符除了字母、数字、_ 和 - 被替换为 -,所以 my-plugin@my-marketplace 变成 my-plugin-my-marketplace。

在 Windows 上,替换的路径使用正斜杠,所以 shell 不将反斜杠读取为转义。

将依赖项安装到数据目录

对于市场安装的插件,Claude Code 在缓存插件时自动安装符合条件的 Node.js 包依赖项,所以您可能不需要自己安装它们。当您这样做时,此 SessionStart hook 在首次运行时将 node_modules 安装到 ${CLAUDE_PLUGIN_DATA} 中,并在更新改变 package.json 后再次安装:

{
  "hooks": {
    "SessionStart": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "diff -q \"${CLAUDE_PLUGIN_ROOT}/package.json\" \"${CLAUDE_PLUGIN_DATA}/package.json\" >/dev/null 2>&1 || (cd \"${CLAUDE_PLUGIN_DATA}\" && cp \"${CLAUDE_PLUGIN_ROOT}/package.json\" . && npm install) || rm -f \"${CLAUDE_PLUGIN_DATA}/package.json\""
          }
        ]
      }
    ]
  }
}

在第一个会话后,~/.claude/plugins/data/<id>/node_modules 存在。MCP 服务器然后可以在其 env 中设置 NODE_PATH 为 ${CLAUDE_PLUGIN_DATA}/node_modules。对于哪些字段替换哪个变量,请参阅环境变量。

后续步骤