Skip to content
claude ~ claude-code/38-plugins-reference— 23 min read

38 · 插件参考手册:把自己那套配置,打成一个能发出去的包

📚 系列导航:上一篇 37 检查点(Checkpoints) 教你怎么给会话「存档读档」,改坏了一键回到上一个安全点。这一篇换个层面——第 24 篇教你「用别人的插件」,这一篇教你「造自己的插件」:插件的目录到底怎么摆、plugin.json 每个字段管什么、能打包哪些组件、依赖怎么写、怎么建市场把它发给团队。这是插件的「参考手册」深度版。

给一个插件跑一下 claude plugin details,输出里常有一行数字值得留意:这个插件每个会话常驻占 ~180 token,里头两个 skill 触发时各自再吃掉 ~2400 和 ~1800 token

就这么个看着人畜无害的小插件,光「挂在那儿什么都没干」就先占了一截工作台。这时候就能意识到:插件不是个黑盒——它由几类明确的组件拼成,每一类占多少、放哪儿、怎么触发,全是有据可查的。你把这套结构吃透,才谈得上「自己造一个、还造得干净」。

第 24 篇我们已经把「用别人的插件」走通了:加市场、装插件、/reload-plugins 生效、装前看信任。这一篇不重复那些,专啃更硬的一块——插件的内部构造和开发发布。说白了,第 24 篇是「会开车」,这一篇是「会拆发动机、还能自己攒一台」。

这一篇偏「参考手册」,信息密度会比前面高。你不用一次记全,先跟着把一个能跑的插件造出来、发出去,剩下的字段表当字典随用随查。

看完这一篇,你会拿到:

  • 插件的标准目录长相,以及那条「.claude-plugin/ 里只放 plugin.json」铁律背后的完整结构
  • plugin.json 清单的字段全景:必填的、元数据、组件路径、用户配置、依赖,一张表查到底
  • 插件能打包的全部组件(skill / command / agent / hook / MCP / LSP / monitor)各自放哪、有什么限制
  • ${CLAUDE_PLUGIN_ROOT} 这几个路径变量为什么必须用、不用会怎样
  • 从零造一个插件、本地测、建市场、发给团队的完整链路,全程给命令和预期输出
  • 版本管理和依赖这两个发布时绕不开的坑,怎么填

01 先把插件的「骨架」摆正:标准目录长相

第 24 篇你已经见过插件最简的样子——一个 plugin.json 加几个组件文件夹。但要自己造一个像样的插件,得先把完整骨架看清楚,不然加到一半就乱。

先给结论:一个插件就是一个文件夹,里头一个「清单文件」定身份,其余按组件类型分门别类摆在根目录下。

类比:一套乐高积木。 一盒乐高里有两样东西——一本拼装说明书,告诉你这套叫什么、有哪些零件;几个分格的零件盒,按类型把积木块装好(轮子一格、窗户一格)。插件就是这么个结构:plugin.json 是那本说明书,skills/agents/hooks/ 这些文件夹是分格零件盒。说明书有它专属的位置,零件盒全摊在外面——这就是下面那条铁律的由来。

官方给的完整插件目录长这样(我删掉了不常用的,留核心):

text
my-plugin/
├── .claude-plugin/           # 元数据目录
│   └── plugin.json           # 清单(说明书)——只有它放这儿
├── skills/                   # Skills,每个一个 <名字>/SKILL.md
│   └── code-reviewer/
│       └── SKILL.md
├── commands/                 # Skills 的扁平 .md 写法(老形式)
│   └── status.md
├── agents/                   # Subagent 定义
│   └── security-reviewer.md
├── hooks/                    # Hook 配置
│   └── hooks.json
├── .mcp.json                 # MCP server 定义
├── .lsp.json                 # LSP server 配置
├── bin/                      # 加进 PATH 的可执行文件
├── scripts/                  # Hook 和工具脚本
└── settings.json             # 插件的默认设置

这里有条官方用警告框圈起来、新手必踩的铁律,我替你钉死:

.claude-plugin/ 目录包含 plugin.json 文件。所有其他目录(commands/、agents/、skills/、output-styles/、themes/、monitors/、hooks/)必须在 plugin 根目录,而不是在 .claude-plugin/ 内。

说白了:.claude-plugin/ 这个文件夹里只准躺着 plugin.json 一个东西skills/agents/hooks/ 全部摆在它的外面、跟它平级。这个坑第 24 篇就提过——第一次打包很容易手贱把 skills/ 塞进 .claude-plugin/,结果插件能加载、skill 死活不出现,排查半天才发现是位置摆错。记住乐高那个画面:说明书归说明书的盒,零件盒全摆外头。

还有个容易被忽略的点,官方写得很明确:插件根目录里的 CLAUDE.md 不会被当成项目上下文加载。插件想给 Claude 喂指令,得通过 skill、agent、hook 这些组件,不能靠在插件里塞一个 CLAUDE.md。这跟第 18 篇讲的项目级 CLAUDE.md 是两码事,别搞混。

💡 一句话总结:插件 = 一本说明书(.claude-plugin/plugin.json)+ 根目录下分格的零件盒(各组件文件夹);铁律就一条——.claude-plugin/ 里只放 plugin.json,别的文件夹全摆根目录


02 plugin.json:这份「清单」每个字段管什么

骨架摆正了,来拆那本说明书——plugin.json。它声明插件的身份和配置,是整个插件的核心。

先记一个反直觉但很省心的事实:清单是可选的。 官方原话——如果你省略 plugin.json,Claude Code 会自动去默认位置(skills/agents/ 这些)找组件,连插件名都从文件夹名推出来。只有当你需要写元数据、或自定义组件路径时,才需要这份清单。 但凡你想正经发布,肯定要写,所以咱们按写的来讲。

类比:报关单。 一批货物出关,得附一份报关单——里头写清这批货叫什么名字、谁发的、版本批次、装了哪些东西。海关(Claude Code)照着这份单子核对、登记、上架。plugin.json 就是插件的报关单:名字、作者、版本、装了哪些组件,全在这一张纸上说清。

唯一的必填字段

如果你写了清单,只有一个字段是必填的

字段类型说明
namestring唯一标识符,kebab-case(小写加连字符)、不带空格

name 为什么这么关键?因为它就是组件的命名空间(namespace)前缀。一个叫 plugin-dev 的插件里有个 agent 叫 agent-creator,在界面里会显示成 plugin-dev:agent-creator;skill 调用就是 /plugin-dev:xxx命名空间是插件防撞名的根本机制——你装十个插件,各家的 skill 都带自家前缀,不会打架。

元数据字段(描述插件「是什么」)

这些不影响功能,但发布时该填,让用户看得明白:

字段干什么
displayName界面里显示的人类可读名,能带空格大小写;省了就回退用 name
version语义版本号(semantic versioning)。设了它,用户只在你提版本号时才收到更新(这是个大坑,第 08 节细说)
description一句话说清插件干嘛,浏览/安装时显示
author作者信息(name / email / url
homepage / repository / license文档地址 / 源码地址 / 许可证
keywords发现标签,帮人搜到你

组件路径字段(指明组件「在哪」)

默认情况下组件就放在 skills/agents/ 这些标准位置,你完全可以不写这些字段。只有当你想把组件放到非标准路径时才用:

字段指向什么
skills额外的 skill 目录(追加到默认 skills/
commands / agents / outputStyles自定义路径(替换默认目录)
hooks / mcpServers / lspServers配置文件路径,或直接内联写在这儿
dependencies这个插件依赖的其他插件(第 08 节讲)

这里藏着一个特别容易栽的细节,官方专门列了「路径行为规则」:有的字段是「替换默认」,有的是「追加到默认」

  • 替换默认commandsagentsoutputStyles。一旦你写了 commands,默认的 commands/ 目录就不再被扫描了。想保留默认还加别的,得显式列上:"commands": ["./commands/", "./extras/"]
  • 追加到默认skills。默认 skills/ 永远会被扫描,你在 skills 字段里列的目录是跟它一起加载的。

这个坑很容易踩:给一个插件加了 "agents": ["./extra-agents/reviewer.md"],想着「再加一个 agent」,结果原来 agents/ 目录里那俩 agent 全不见了——因为 agents替换不是追加。改成把三个都列进数组才好。记不住就查这张规则,别凭感觉。

一份带元数据的完整清单大概长这样:

json
{
  "name": "deployment-tools",
  "displayName": "Deployment Tools",
  "version": "1.2.0",
  "description": "Deployment automation tools",
  "author": { "name": "Dev Team", "email": "[email protected]" },
  "license": "MIT",
  "keywords": ["deployment", "ci-cd"]
}

💡 一句话总结:plugin.json 是插件的报关单,唯一必填的是 name(它定命名空间);组件路径字段里要分清「替换默认」(commands/agents)和「追加默认」(skills),搞反了组件会凭空消失。


03 插件能打包哪些组件:七类零件认全

这是本篇最该记牢的一节——插件这个盒子,到底能装哪七类零件。第 24 篇粗讲过几类,这里把官方支持的全列清,标明各自放哪、有什么独有的限制。

类比:乐高那几格零件盒,每格只装一种件。 轮子格、窗户格、人仔格——分门别类才拼得快。插件的组件也是一格一类:

组件放哪一句话作用触发方式
Skillsskills/<名字>/SKILL.md可调用的专项能力(第 26 篇)/插件名:skill名,或 Claude 自动调
Commandscommands/*.mdskill 的扁平老写法,新插件用 skills同上
Agentsagents/*.md专项 subagent(第 23 篇)出现在 /agents,Claude 派或你点
Hookshooks/hooks.json事件触发的自动动作(第 33 篇)生命周期事件自动触发
MCP servers.mcp.json连外部服务(第 22 篇)启用即自动起,工具混进工具箱
LSP servers.lsp.json实时代码智能(跳定义、查引用)处理代码时自动用,需另装语言服务器
Monitorsmonitors/monitors.json后台监视日志/状态,有动静通知 Claude插件激活时自动起(实验性)

几类需要单独点几句,都是官方文档里写明、但容易漏的限制:

Agents 在插件里被「削权」了。 这点很关键。官方明确:出于安全原因,插件提供的 agent 不支持 hooksmcpServerspermissionMode 这三个 frontmatter 字段。 也就是说,插件里的 subagent 不能自己偷偷挂 hook、起 MCP、或改权限模式——这是防止你装个插件,它的 agent 在背后给你换权限。它支持的字段包括 namedescriptionmodeleffortmaxTurnstoolsdisallowedToolsskillsmemorybackgroundisolation 这些(isolation 唯一合法值是 "worktree")。

Hooks 能监听的事件巨多。 插件 hook 跟你自己写的 hook(第 33 篇)监听的是同一批生命周期事件——从 SessionStart(会话开始)、PreToolUse(工具调用前,能拦)、PostToolUse(调用成功后),到 Stop(回答结束)、SessionEnd(会话终止),官方列了三十个。新手不用记全,记住「几乎任何时机都能挂个动作」就行,具体留到第 33 篇。

Hook 类型不止「跑脚本」。 除了最常见的 command(跑 shell 命令),还有 http(把事件发到一个 URL)、mcp_tool(调 MCP 工具)、prompt(用模型评估一段提示)、agent(跑个 agentic 验证器)。

Monitors 是实验性的。 它让插件在后台盯着日志或状态,有新行就当通知喂给 Claude,不用你开口让它监视。实验性,架构可能变,且只在交互式会话里跑、需要 Claude Code v2.1.105 以上。新手了解有这么个东西即可。

还有两类「半组件」值得知道:bin/ 目录里的可执行文件,插件启用时会被加进 Bash 工具的 PATH,能当裸命令直接调;settings.json 是插件的默认设置,但目前只支持 agentsubagentStatusLine 两个键——其中设 agent 能让插件启用时直接把某个自定义 agent 顶成主线程,等于「装上这个插件就换了套人设」。

💡 一句话总结:插件能装七类零件——skill / command / agent / hook / MCP / LSP / monitor,各有固定位置;重点记两条限制:插件里的 agent 不许带 hook/MCP/权限模式(安全削权)、monitor 是实验性的


04 ${CLAUDE_PLUGIN_ROOT}:为什么路径必须用变量,不能写死

这一节单拎出来,因为它是自己造插件时最高频的报错来源,而道理一句话能说透。

先看场景:你的插件里有个 hook 要跑 scripts/format.sh,或者 MCP server 要 node server.js。你想当然地写绝对路径 /Users/你/my-plugin/scripts/format.sh——完蛋,这条路在别人机器上根本不存在,而且就算在你机器上,插件每次更新缓存目录都会变

官方的解法是给你三个路径变量,在 hook 命令、MCP/LSP 配置、skill/agent 内容里都会被自动替换:

变量指向用来
${CLAUDE_PLUGIN_ROOT}插件安装目录的绝对路径引用插件自带的脚本、二进制、配置
${CLAUDE_PLUGIN_DATA}插件的持久数据目录(更新后保留)node_modules、缓存、跨版本要保留的状态
${CLAUDE_PROJECT_DIR}项目根目录引用项目里的脚本/配置

类比:活页夹里写「本夹位置」,而不是抄死页码。 想象一份会被反复重新装订的活页夹,你要在里头写「去附录那页」。如果你写死「第 87 页」,一重新装订页码全乱;聪明的做法是写「本夹的附录」这种相对本夹的占位说法${CLAUDE_PLUGIN_ROOT} 就是这个「本店地址」占位符——不管插件被装到哪、更新到第几版,它永远指向当前这一版的根目录

所以插件里引用自带脚本,标准写法长这样(注意双引号,防路径带空格):

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

这里有个官方反复强调的硬规矩,值得贴脑门上:

当 plugin 更新时,此路径会更改。前一个版本的目录在更新后约七天内保留在磁盘上以进行清理,但应将其视为临时的,不要在此处写入状态。

翻译一下:${CLAUDE_PLUGIN_ROOT} 是临时的,别往里写要长期保留的东西(比如装好的依赖、缓存)——那些该写进 ${CLAUDE_PLUGIN_DATA},因为数据目录跨版本保留。常见的翻车是把插件装的 node_modules 放进 ROOT,结果插件一更新依赖全没了,得重装。自带的脚本用 ROOT,要保留的状态用 DATA,这条分清就不出事。

还有个相关坑,官方在「插件缓存」那节专门讲:已安装的插件不能引用自己目录外的文件。你写 ../shared-utils 这种往外跳的相对路径,安装后会失效——因为插件被装时是整个复制进缓存~/.claude/plugins/cache)的,外面的文件根本没被复制过去。要跨插件共享文件,得用符号链接,这是进阶话题,新手先记住「别往插件外引用」。

💡 一句话总结:插件里引用路径必须用 ${CLAUDE_PLUGIN_ROOT} 这类变量,不能写死绝对路径(每次更新都变);自带脚本用 ROOT、要保留的状态用 DATA,且绝不引用插件目录外的文件


05 动手:从零造一个能跑的插件,再本地测

讲了四节构造,该真上手了。下面带你亲手造一个最小但完整的插件、本地加载、跑通它的 skill——全程不依赖任何复杂环境,跟着抄就行。我们造一个 my-greeter 插件,带一个打招呼的 skill。

第一步:用官方脚手架命令起一个插件骨架

最省事的不是手动建目录,而是用官方的 plugin init 命令,它会把骨架搭好:

bash
claude plugin init my-greeter --with skills

--with skills 表示顺便搭一个示例 skill 文件夹。这条命令会在 ~/.claude/skills/my-greeter/ 下建好 .claude-plugin/plugin.json 和一个启动用的 SKILL.md

预期:终端提示插件骨架已创建,告诉你建在了 ~/.claude/skills/my-greeter/

这里有个官方设计的便利:放在 ~/.claude/skills/ 下、带 plugin.json 清单的文件夹,下个会话会自动作为 my-greeter@skills-dir 加载,不用建市场、不用安装。这种叫「skills 目录插件」,是开发自用插件最轻的路子。

第二步:看看脚手架生成了什么

直接列一下目录(注意用绝对路径):

bash
ls -R ~/.claude/skills/my-greeter

预期:你会看到 .claude-plugin/plugin.jsonskills/(或一个 SKILL.md)。确认 plugin.json.claude-plugin/ 里、skill 在外面——这就是第 01 节那条铁律的实物。

第三步:写一个属于自己的 skill

打开(或新建)~/.claude/skills/my-greeter/skills/hello/SKILL.md,内容写成:

markdown
---
description: 用热情的语气跟用户打招呼
---

# Hello Skill

热情地跟名叫 "$ARGUMENTS" 的用户打招呼,问问今天能帮上什么忙。语气友好、鼓励一点。

$ARGUMENTS 是占位符——它会捕获你在 skill 名后面打的任何文字。这是给 skill 传参的标准做法(第 26、27 篇讲过 skill,这里复用)。

第四步:本地加载这个插件

开发期不用建市场,--plugin-dir 直接加载本地插件目录,这是官方专给开发测试的标志:

bash
claude --plugin-dir ~/.claude/skills/my-greeter

预期:Claude Code 正常启动。敲 /help,能在插件命名空间下看到你的 skill 列出来。

第五步:喊起你的 skill,亲眼看它跑

插件 skill 永远带命名空间,所以这么调(后面跟个名字当参数):

text
/my-greeter:hello Walter

预期:Claude 用一段热情的、带上「Walter」这个名字的话回应你。看到它按你写的 description 和正文打了招呼,说明这个插件不光建对了、它带的 skill 真能用了。

第六步:改了 skill,热重载看效果

SKILL.md 的正文改两句(比如让它用中文加 emoji),然后不用重启,在 Claude Code 里敲:

text
/reload-plugins

预期:重新跑一遍 /my-greeter:hello Walter,能看到改动生效了。

⚠️ 一个官方写明的区别:SKILL.md 当前会话立即生效;但改 hooks、.mcp.jsonagents/ 这些,得 /reload-plugins 或重启才生效。别改了 hook 发现没反应就以为写错了,先 reload 一下。

跑通这六步,你就把「造骨架 → 写组件 → 本地加载 → 调用 → 热重载」这条插件开发的完整内循环亲手走了一遍。以后造任何插件,本质都是这套流程,只是组件更多。

💡 一句话总结:claude plugin init 起骨架、--plugin-dir 本地加载、/reload-plugins 热重载——这三条命令是插件开发的内循环;放进 ~/.claude/skills/ 的还能免市场免安装自动加载。


06 把插件发出去:建一个市场

自用的插件,放 ~/.claude/skills/--plugin-dir 就够了。但要发给团队、发给社区,得走「市场(marketplace)」这一层——第 24 篇你是市场的「消费者」,这一节当一回市场的「店主」。

先理清两个长得像、极易混的概念,官方专门用 Note 框区分过:

概念是什么在哪定义
市场源(marketplace source)去哪拿那本「商品目录」(marketplace.json用户 /plugin marketplace add 时,或设置里
插件源(plugin source)目录里每个插件本体从哪拿marketplace.json 里每个插件条目的 source 字段

类比:商场 vs 商场里每件商品的供货地。 「市场源」是这家商场开在哪、目录册从哪取;「插件源」是目录册里每件商品实际从哪个工厂发货。两者完全可以不在一处——商场目录可以挂在 A 仓库,里头某件商品从 B 工厂直发。

市场的核心是一个文件:仓库根目录下的 .claude-plugin/marketplace.json。它声明市场名、所有者、和插件清单。最小的一个长这样:

json
{
  "name": "my-plugins",
  "owner": { "name": "Your Name" },
  "plugins": [
    {
      "name": "my-greeter",
      "source": "./plugins/my-greeter",
      "description": "A friendly greeting plugin"
    }
  ]
}

每个插件条目至少要 namesource(从哪拿这个插件)。source 支持好几种来源,这是市场最实用的部分:

插件源类型怎么写适合
相对路径"./plugins/my-greeter"插件就在市场同一个仓库里(最常见)
github{ "source": "github", "repo": "owner/repo" }插件在另一个 GitHub 仓库
git-subdirurl + path插件在某个大仓库(monorepo,多项目合一仓库)的子目录,稀疏克隆省带宽
npm{ "source": "npm", "package": "@org/plugin" }作为 npm 包发布的插件

动手:把第 05 节那个插件,装进一个本地市场试试。 假设你按上面的结构建好了 my-marketplace/(里头 .claude-plugin/marketplace.json + plugins/my-greeter/),在 Claude Code 里:

text
/plugin marketplace add ./my-marketplace
/plugin install my-greeter@my-plugins

预期:第一条提示市场添加成功;第二条把插件装上。然后 /my-greeter:hello 就能调了——这条链路跟第 24 篇你装别人插件时一模一样,只不过这次货是你自己的

发布前一定先验证,官方给了专门命令:

bash
claude plugin validate ./my-marketplace

预期:检查 marketplace.json 的 schema、有没有重复插件名、源路径有没有非法的 ..、版本对不对得上。指向市场目录时它只查 marketplace.json;要连 skill/agent 的 frontmatter 一起查,得指向具体插件目录claude plugin validate ./my-marketplace/plugins/my-greeter)。

真要发给团队,把这个市场仓库推到 GitHub,同事一句 /plugin marketplace add owner/repo 就能加。想自动让团队装,可以在项目的 .claude/settings.json 里写 extraKnownMarketplaces,同事信任项目目录时会被提示安装——这块属于团队配置,新手先知道有这条路即可。

💡 一句话总结:发布走市场——根目录建 .claude-plugin/marketplace.json,列出插件和它们的 source(相对路径/github/npm 等);分清「市场源」(目录从哪来)和「插件源」(每个插件从哪来);发布前 claude plugin validate


07 一组对照:自用、本地测、正式发布,三条路别走错

造插件的人最常犯的不是写错代码,是用错了「分发方式」——明明只是自己试,却去吭哧建市场;或者要发团队了,还在用只对自己生效的 --plugin-dir。这一节一张表把三条路钉清。

你的处境该用命令特点
纯自用、想随手改随手用skills 目录插件放进 ~/.claude/skills/<名>/(带 plugin.json自动加载,免市场免安装,改 SKILL.md 立即生效
开发中、反复测一个本地包--plugin-dirclaude --plugin-dir ./my-plugin直接加载,不入库;可多次指定加载多个;.zip 也行
发给团队/社区市场marketplace.json + /plugin install能版本管理、能自动更新、能共享

几个用起来才知道的细节:

--plugin-dir 是开发利器,但只管当前这一次会话。 你这次启动加载了,关掉再开就没了——它不写进任何配置。好处是干净:测完插件,关掉会话就一干二净,不留痕迹。开发时一个顺手的做法是一直挂着一个 --plugin-dir 的会话,改完 /reload-plugins,比每次重装市场快太多。官方还有个贴心设计:--plugin-dir 的本地副本,会临时盖过同名的已装市场插件——所以你能拿本地改动直接覆盖测试一个线上插件,不用先卸载。

skills 目录插件有个范围陷阱。~/.claude/skills/(个人级)的,每个项目都能用;但放项目 .claude/skills/ 的(项目级),官方明确警告:它只从你启动 Claude Code 的那个目录加载,不会像普通 skill 那样往仓库根目录上找。所以从子目录启动会漏掉根目录的插件——要么从仓库根启动,要么 /reload-plugins

别一上来就建市场。 这是过度工程的典型。官方的建议很实在:先用 .claude/ 散装或 --plugin-dir 快速迭代,准备好共享了再转成插件、建市场。一个插件通常要在 --plugin-dir 下改十几轮才稳定,这期间建市场纯属给自己找麻烦——每改一次还得提交、刷新市场。

💡 一句话总结:三条路别走错——自用塞 ~/.claude/skills/、开发用 --plugin-dir、发布才建市场--plugin-dir 只活一次会话(干净),发布前先在前两条路上把插件迭代稳。


08 发布绕不开的两个坑:版本管理与依赖

插件能跑、能装,不代表能「发好」。版本管理和依赖是发布时两个最容易翻车的地方,官方都用警告框圈过,这一节专门填。

坑一:设了 version,推新提交却没人更新

这是最反直觉、最坑人的一个。Claude Code 怎么判断「插件有没有新版本」?它按这个顺序取版本号:

  1. plugin.json 里的 version
  2. 市场条目里的 version
  3. 都没有的话,用 git 提交的 SHA

关键就在这儿。官方警告说得很重:

设置 version 会固定 plugin。如果 plugin.json 声明 "version": "1.0.0",推送新提交而不改变该字符串对现有用户没有任何作用,因为 Claude Code 看到相同的版本并保留缓存副本。

翻译成大白话:你一旦写死了 "version": "1.0.0",光往仓库推新代码是没用的——用户那边版本号没变,/plugin update 会回你「已是最新」,缓存压根不刷新。 你必须每次发版都手动把版本号往上提(1.0.11.1.0……)。

所以官方给了两种策略,二选一,别混:

策略怎么做更新行为适合
显式版本plugin.json 里设 version,每次发版手动提用户只在你提版本号时收到更新有稳定发布节奏的正式插件
提交 SHA 版本不写 version,git 托管每推一个新提交都算新版本,用户自动拿到内部、团队、快速迭代的插件

还有个加倍坑的:别在 plugin.json 和市场条目里都写 version 官方明确——plugin.json 的值会无声地盖过市场条目的,你在 marketplace.json 里改了版本可能根本不生效,因为被那个陈旧的 plugin.json 版本号压住了。

显式版本这个坑很容易栽:一个团队内部插件设了 "version": "1.0.0",改了好几次代码推上去,同事一直反馈「怎么没更新」。你很容易以为是市场没刷新,折腾半天才反应过来——版本号没动,Claude Code 当然认为没变化。内部插件一律不写 version、让它用 SHA,推一次同事更新一次,就清净了。结论:快速迭代的内部插件别设 version,稳定发布的正式插件才设、且每次记得提。

坑二:依赖怎么声明

如果你的插件 A 必须有插件 B 才能工作,用 dependencies 字段声明:

json
{
  "name": "my-plugin",
  "dependencies": [
    "helper-lib",
    { "name": "secrets-vault", "version": "~2.1.0" }
  ]
}

声明后,装/启用你的插件时,Claude Code 会自动把依赖也装上/启上。版本可以用 semver(语义版本范围)约束(像 ~2.1.0),免得依赖出个大版本把你的插件搞崩。卸载时,claude plugin uninstall --prune 能顺手清掉那些「只为满足依赖而自动装、现在没人要」的插件;你手动直接装的插件永远不会被 prune 碰

类比:配料表里标「需另购的配件」。 一份家具说明书末尾写着「本款需另购 M4 螺丝包(2.1 规格)」——你照单备齐配件,家具才装得起来。dependencies 就是插件的这张配件清单:它把「我需要谁、要哪个版本」写明,Claude Code 照单自动备齐

💡 一句话总结:发布两个坑——设了 version 就必须每次发版手动提,否则用户收不到更新(快速迭代干脆别设、用 SHA);依赖用 dependencies 声明、可加 semver 约束,装你的插件时会自动连依赖一起装。


09 小结

这一篇把插件从「会用」推进到「会造、会发」——它本质就是一盒乐高:一本说明书(plugin.json)定身份,几格零件盒(组件文件夹)装能力,整盒打包就能发给任何人

把核心要点串起来回顾:

你要搞清的事关键点
目录骨架.claude-plugin/只放 plugin.json,其余组件全摆根目录
清单字段唯一必填 name(定命名空间);组件路径分「替换」(agents/commands)和「追加」(skills)
能装哪些组件skill/command/agent/hook/MCP/LSP/monitor 七类;插件里的 agent 被削权(无 hook/MCP/权限模式)
路径怎么写必须用 ${CLAUDE_PLUGIN_ROOT} 等变量,不写死、不引用目录外文件;状态放 DATA 不放 ROOT
开发内循环plugin init 起骨架 → --plugin-dir 加载 → /reload-plugins 热重载
发布marketplace.json,分清市场源/插件源,claude plugin validate 验证
两个坑设了 version 必须每次提;依赖用 dependencies 声明

你现在应该能: 看懂任何一个插件的目录在干嘛、自己从零搭一个能跑的插件骨架、用 --plugin-dir 本地测、再建个市场把它发给团队;也清楚 ${CLAUDE_PLUGIN_ROOT} 为什么不能写死、version 那个「不提就不更新」的坑怎么躲。第 24 篇你学会了消费别人的插件,这一篇你成了能生产插件的人——把自己那套攒了好久的配置打成一个包发出去,从此不再是只能抄别人的。

到这里,Claude Code 的「扩展 + 配置 + 打包分发」这条线就齐全了。从第 18 篇的 CLAUDE.md、第 22 篇的 MCP、第 23 篇的 subagent,到第 24、38 这两篇的插件——你不光会用这些工具,还会把它们组装、打包、交付给别人


下一篇 39「实战入门」——前面三十多篇全是「一个个功能拆开讲」,你手里的零件已经堆成山了。下一篇不再讲新功能,而是把这些零件第一次串成一条完整的实战路径:拿一个真实的小需求,从开工到交付走一遍,让你亲眼看见「学过的东西怎么拧成一股绳干活」。想想看——你现在会的每一招,单独使都顺手,但真打一仗时,该先抽哪把、再接哪把?