简介
Claude Code的本质是"大模型+工具调用循环+有限上下文窗口"。围绕这个本质,第2~6章逐层造出了各种定制件:持久注入的CLAUDE.md、按需加载的Skill(技能)、隔离执行的Sub-Agent(子智能体)、确定性控制的Hooks(钩子)、扩展工具边界的MCP(Model Context Protocol,模型上下文协议)服务器。《8.SDK》的结尾留下了最后一个问题:这些定制资产越攒越多,却散落在各个项目的.claude/目录和settings.json里,共享给同事靠手动拷贝,既没有版本,也没法批量更新。
本章讨论Plugins(插件)。插件不引入新能力,它是一个分发容器:把Skills、Agents、Hooks、MCP配置打包成一个可安装、可版本化的单元,再通过Marketplace(插件市场)分发给团队或社区。这是全系列的最后一章,文末我们回到本质模型,把九章串成一张完整的地图。
插件的结构
一套团队工作流往往同时包含几类组件:几个Skill、一两个Sub-Agent、几条Hook、一份MCP配置。独立形态下它们分处不同位置、安装方式各不相同,接收方要逐一理清每个组件放哪、怎么生效。插件的做法是:把它们收进同一个目录,用一份清单描述,整体安装、整体卸载。
目录布局
一个插件就是一个遵循固定布局的目录:
1 | my-plugin/ |
包括plugin.json清单在内,各部分都是可选的,有什么放什么。commands/存放旧式自定义命令文件,新插件优先用skills/(旧式命令与Skills的关系见《3.Skills》)。
结构红线:只有plugin.json放在.claude-plugin/子目录里;skills/、agents/、hooks/等组件目录以及.mcp.json必须放在插件根目录,不能放进.claude-plugin/内,放错位置的组件不会生效。这是最常见的插件结构错误。
plugin.json
plugin.json是插件的清单。它本身是可选的——只有需要声明元数据时才必须提供。
| 字段 | 必需 | 说明 |
|---|---|---|
name |
是 | 插件标识,也是组件的命名空间前缀 |
description |
否 | 插件管理器中展示的描述,建议提供 |
version |
否 | 版本号;省略时以git commit SHA作为版本,见下文"版本与路径" |
author |
否 | 作者信息,对象形式{name, email},email可省略 |
homepage |
否 | 文档或主页URL |
repository |
否 | 仓库URL |
license |
否 | SPDX许可证标识,如MIT、Apache-2.0 |
命名空间
name不只是展示名,它决定命名空间:插件里的Skill以/plugin-name:skill的形式调用。比如插件quality-review里名为review的Skill,调用名是/quality-review:review。这让多个插件、以及插件与本地配置之间的同名组件互不冲突,团队可以放心组合安装多个插件,不必预先协调命名。
插件形态与独立形态
插件形态与独立.claude/形态的对应关系如下表。各组件自身的机制、字段与协议本章一概不重复,见各归属章。
| 组件 | 独立形态 | 插件形态 | 机制详见 |
|---|---|---|---|
| Skill | .claude/skills/<name>/SKILL.md,调用名/<skill> |
skills/<name>/SKILL.md,调用名/<plugin>:<skill> |
《3.Skills》 |
| Sub-Agent | .claude/agents/*.md |
agents/*.md,个别字段不支持,见文末经验 |
《4.SubAgent》 |
| Hooks | settings.json的hooks字段 |
hooks/hooks.json,脚本路径用${CLAUDE_PLUGIN_ROOT}引用 |
《5.Hooks》 |
| MCP服务器 | .mcp.json |
插件根的.mcp.json,命令路径用${CLAUDE_PLUGIN_ROOT}引用 |
《6.MCP》 |
| 旧式自定义命令 | .claude/commands/ |
commands/ |
《3.Skills》 |
两种形态的取舍:独立形态适合个人试验与单项目专用,配置与项目代码同仓,改起来直接;插件形态适合团队共享、跨项目重用与社区分发,有命名空间、有版本、能一键安装。不是所有配置都值得打包——只服务当前项目的配置,放在.claude/里随代码提交就够了。
安装与管理
会话内命令
插件在会话内用/plugin命令族管理。不带参数的/plugin打开交互管理器,含Discover、Installed、Marketplaces、Errors四个标签页。
| 命令 | 作用 |
|---|---|
/plugin install <name>@<marketplace> |
安装插件,交互式选择作用范围 |
/plugin uninstall <name>@<marketplace> |
卸载插件 |
/plugin enable <name>@<marketplace> |
启用插件 |
/plugin disable <name>@<marketplace> |
禁用插件 |
/plugin list [--enabled\|--disabled] |
列出已安装插件 |
/plugin details <name>@<marketplace> |
查看插件详情 |
/plugin validate [path] |
校验plugin.json或marketplace.json语法 |
/plugin marketplace add <source> |
添加市场 |
/plugin marketplace list |
列出已配置的市场 |
/plugin marketplace remove <name> |
移除市场 |
/plugin marketplace update [name] |
更新指定市场或全部市场 |
/reload-plugins |
重新加载活动插件,无需重启会话 |
注意:/reload-plugins不是免费的——它会使插件携带的MCP服务器缓存失效,带来额外的token成本。开发调试之外不必频繁执行。
终端命令
脚本或自动化场景下可用claude plugin前缀的终端命令,安装时以--scope显式指定作用范围:
| 命令 | 作用 |
|---|---|
claude plugin init <name> |
创建插件骨架目录(默认位于~/.claude/skills/下) |
claude plugin install <name>@<marketplace> --scope <user\|project\|local> |
在指定作用范围安装插件 |
claude plugin marketplace add <source> [--scope] [--sparse] |
添加市场 |
claude plugin validate . |
校验当前目录 |
本地开发
开发插件时不必走市场安装流程,用--plugin-dir直接把本地目录当作已安装插件加载。示例代码:
1 | claude --plugin-dir ./my-plugin |
改完文件重新启动即可测试,省去反复安装卸载的循环。
Marketplace
插件解决打包,市场解决"去哪找、怎么装"。一个市场本质上是一份插件索引:仓库或目录的.claude-plugin/marketplace.json文件,列出若干插件条目及其来源。添加市场时,/plugin marketplace add <source>的<source>支持GitHub的owner/repo简写、git URL、本地路径和远程URL。
marketplace.json
| 字段 | 必需 | 说明 |
|---|---|---|
name |
是 | 市场标识,kebab-case,安装时@<marketplace>引用的就是它 |
owner |
是 | 维护者信息,对象形式{name, email},email可省略 |
plugins |
是 | 插件条目数组 |
description |
否 | 市场描述 |
version |
否 | 市场清单自身的版本 |
metadata.pluginRoot |
否 | 相对路径的基准目录,如"./plugins" |
renames |
否 | {"旧名": "新名"}映射,用于插件重命名或移除,见下文"版本与路径" |
插件条目与来源
plugins数组中每个条目的字段:
| 字段 | 说明 |
|---|---|
name |
插件标识,必需 |
source |
插件来源,必需;字符串形式的相对路径,或对象形式的远程来源 |
displayName |
UI显示名,缺省时回退用name |
version |
该条目声明的插件版本 |
strict |
默认true:plugin.json是权威,市场条目仅作补充;设为false时市场条目全权控制,与plugin.json冲突会导致加载失败 |
relevance |
推荐信号,需管理员设置允许才生效 |
defaultEnabled |
安装后是否默认启用,默认true |
source支持五种来源类型:
| 类型 | 写法 | 可选锁定 |
|---|---|---|
| 相对路径 | "./plugins/quality-review" |
— |
| GitHub | {"source": "github", "repo": "owner/repo"} |
ref、sha |
| git URL | {"source": "url", "url": "https://gitlab.com/team/plugin.git"} |
ref、sha |
| git子目录 | {"source": "git-subdir", "url": "owner/repo", "path": "tools/plugin"} |
ref、sha |
| npm | {"source": "npm", "package": "@org/plugin"} |
version、registry |
团队自动安装
要让团队成员在某个项目里自动获得指定插件,不必人人手动执行安装命令:在项目的.claude/settings.json里声明extraKnownMarketplaces(市场从哪来)与enabledPlugins(启用哪些插件)即可,settings的层级与优先级见《1.概述》。
示例代码:
1 | { |
这份文件随项目代码提交,队友在该项目里使用Claude Code时即可获得同一套插件,插件的变更也随代码评审流程可追溯。
版本与路径
版本策略
插件版本有三种玩法,各有陷阱:
- 省略
version
以git commit SHA自动版本化,每次提交即新版本。开发中的插件建议这么做,用户总能拿到最新提交。 - 只在
plugin.json里设version
发布节奏由你控制,但设置了就意味着锁定——用户只有在你手动改了这个字段之后才能更新。"发了新代码却忘了改版本号"是"更新不生效"最常见的原因。 - 两处都设
plugin.json与市场条目都写了version时,plugin.json优先,市场条目里的被忽略。避免两处都写,徒增困惑。
重命名与迁移
市场维护者要重命名或下架插件时,在marketplace.json里声明renames映射:{"旧名": "新名"}表示重命名,值为null表示移除,已安装用户的配置会自动迁移。
注意:如果插件的远程源本身换了位置,用户仍需手动重新执行一次/plugin install。
缓存与路径
插件安装后被复制到本机缓存目录运行,而不是在原仓库位置运行:
1 | ~/.claude/plugins/cache/<marketplace>/<plugin>/<version>/ |
这带来一个路径陷阱:插件内部写的、指向插件目录之外的相对路径(比如../shared)在运行时不可达。规则很简单——凡是引用插件自带的文件(Hook脚本、MCP服务器可执行文件等),一律用${CLAUDE_PLUGIN_ROOT}变量,它在运行时展开为插件的实际根目录;需要跨会话持久保存数据时,用${CLAUDE_PLUGIN_DATA}。想自定义缓存位置,见文末的环境变量表。
示例
下面用同一个场景贯穿三个示例:我们为团队维护一个代码质量插件quality-review,先做出最小可用版本,再通过团队市场分发,最后为它加上Hooks与MCP。
最小插件
一个插件最少只需要一个Skill,这里加上一份清单来声明名称与版本。
示例代码(目录结构):
1 | quality-review/ |
示例代码(.claude-plugin/plugin.json):
1 | { |
示例代码(skills/review/SKILL.md):
1 | --- |
用--plugin-dir本地调试。示例代码:
1 | claude --plugin-dir ./quality-review |
会话里以命名空间全名调用:
1 | /quality-review:review src/ |
市场配置
团队市场是一个GitHub仓库acme-corp/claude-plugins,quality-review以相对路径放在仓库内,另一个插件deploy-tool引用外部仓库。
示例代码(.claude-plugin/marketplace.json):
1 | { |
团队成员添加市场并安装:
1 | /plugin marketplace add acme-corp/claude-plugins |
注意:install时@后面写的是市场清单里的name(team-plugins),不是仓库地址。
带Hooks与MCP的插件
随着功能演进,quality-review加入两样东西:写文件后自动跑lint的Hook,以及连接公司内部API的MCP服务器。
示例代码(目录结构):
1 | quality-review/ |
示例代码(hooks/hooks.json):
1 | { |
示例代码(.mcp.json):
1 | { |
两份配置里凡是指向插件自带文件的路径,都用了${CLAUDE_PLUGIN_ROOT}——原因见上文"缓存与路径"。Hook与MCP各字段的含义本章不展开,见前文对照表所链各章。
经验
- 结构错误排第一位
插件不生效时,先按"目录布局"一节的结构红线检查,组件目录是否被误放进了.claude-plugin/里。 - 发布前的核验清单
组件目录都在插件根;/plugin validate通过,plugin.json与marketplace.json是合法JSON;市场里的相对路径source以./开头;Hooks与MCP配置引用插件文件一律用${CLAUDE_PLUGIN_ROOT};若设置了version,发布流程里有"更新版本号"这一步;市场条目的strict设置与plugin.json实际内容一致、无冲突字段。 - 插件Agent的字段限制
插件里的Agent不支持hooks、mcpServers、permissionMode三个字段,需要这些能力时改用独立.claude/agents/形态,字段含义见《4.SubAgent》。 - URL市场不支持相对路径
通过远程URL添加的市场,清单文件能下载,但相对路径source指向的插件目录并不在本机,这类市场里的条目要改用GitHub或git URL来源。 - 私有仓库与环境变量
私有仓库插件的自动更新依赖GITHUB_TOKEN/GITLAB_TOKEN/BITBUCKET_TOKEN认证。插件相关的环境变量如下表。
| 环境变量 | 用途 |
|---|---|
CLAUDE_CODE_PLUGIN_CACHE_DIR |
自定义插件缓存目录 |
CLAUDE_CODE_PLUGIN_SEED_DIR |
容器构建时预装插件的目录 |
CLAUDE_CODE_PLUGIN_GIT_TIMEOUT_MS |
插件git操作超时,毫秒,默认120000 |
CLAUDE_CODE_PLUGIN_KEEP_MARKETPLACE_ON_FAILURE |
git拉取失败时保留已有缓存,适合离线环境 |
GITHUB_TOKEN / GITLAB_TOKEN / BITBUCKET_TOKEN |
私有仓库插件自动更新时的认证 |
全系列到此收束。回到第一章的那句话:Claude Code的本质是"大模型+工具调用循环+有限上下文窗口"。大模型只会生成文本,工具调用循环(agent loop)让它作用于真实工程环境,有限的上下文窗口是整个循环的根本约束。九章的每一章,都是这个本质引出的一个根本问题的解法:
| 章 | 根本问题 | 解法 |
|---|---|---|
| 《1.概述》 | 只会生成文本的模型,如何安全地作用于真实代码库 | 工具调用循环+权限系统+Settings |
| 《2.Memory》 | 上下文易失,/clear、自动压缩、新会话都会丢指令 |
启动时自动加载的持久指令层 |
| 《3.Skills》 | 常驻注入有token成本,工作流不该常驻 | 调用时才加载的指令包 |
| 《4.SubAgent》 | 高噪声子任务污染并耗尽主上下文 | 独立上下文窗口内委派执行 |
| 《5.Hooks》 | 有些事必须百分之百发生,不能靠模型自觉 | 生命周期事件上的确定性执行 |
| 《6.MCP》 | 循环的能力上限等于工具集上限,内置工具止步于本地 | 标准协议接入外部系统 |
| 《7.Headless》 | CI/CD与脚本需要把人移出循环 | -p非交互模式 |
| 《8.SDK》 | 嵌入自有应用需要进程内的控制粒度 | 工具调用循环的库形态 |
| 9.Plugins(本章) | 定制件散落各处,共享靠拷贝 | 打包与分发 |
这九层机制没有一层是魔法,每一层都在回应同一个本质带来的某个具体约束。往后Claude Code还会增加新特性,拿到任何新特性,都可以先问同一个问题:它解决的是大模型、工具调用循环,还是上下文窗口的哪个约束。想清楚这个问题,新特性就自然落进这张地图里。