教程Claude Code系列第 8 / 11 篇

做一个 Claude Code 插件,分享给团队:把 skill、子代理和 hook 打成一包

插件是一个带清单文件的目录,把 skill、子代理、hook、MCP 服务器装在一起,可以整包分享和安装。本站把本系列前面做的三样东西打成了一个插件,实测了校验、单次加载、建本地市场、按项目安装和移除。要留意的一个结果:把 skills 目录放错位置,校验照样通过,但 skill 不会加载。

发布 · 约 11 分钟读完 · 经人工审核()· 本站的内容怎么来的

本站已实测,测试日期:2026-10-12。

本页目录(12 节)
  1. 什么时候才需要插件
  2. 第一步:建目录,写清单
  3. 第二步:放进三样东西
  4. 第三步:校验
  5. 第四步:不安装,先加载一次试试
  6. 第五步:建一个市场,让别人能装
  7. 第六步:登记市场,安装
  8. 第七步:放到团队够得着的地方
  9. 不要了怎么撤
  10. 这一趟花了多少
  11. 这次实测没有覆盖到的
  12. 下一步

这篇教程解决一个问题:你在一个项目里配好了一套 skill、子代理和 hook,想让同事也用上,或者想在自己的几个项目里都用上,怎么办。

把 .claude/ 目录复制来复制去是一个办法,但改了一处就要到处同步。Claude Code 的做法是插件:一个目录,里面按固定的位置放 skill、子代理、hook、MCP 服务器,再加一个清单文件说明它叫什么。Claude Code 把整个目录当成一个单元来加载,所以能整包分享、安装、更新。

本站把本系列前面几篇做的三样东西打成了一个插件,从零走到“别人能装上”。

实测环境
日期 2026-10-12
版本 Claude Code 2.1.296
系统 Ubuntu 24.04
模型 Opus 5.5
连接方式 通过酷站AI 中转站,不是直连官方
示例仓库 Express 的源码,v5.3.0,带一份 CLAUDE.md

什么时候才需要插件

官方文档的判断很直接:skill、子代理、hook、MCP 服务器放在项目或者个人目录里本来就能用。只服务一个项目、或者只有你自己用的时候,保持原样就行。

下面三种情况才值得做成插件:

  • 要分享给同事;
  • 要装进好几个项目;
  • 要发布带版本号的更新。

搬进插件之后有两处变化:

  • 文件的位置:都放在插件自己的目录下,分别是 skills/、agents/、hooks/hooks.json、.mcp.json。
  • 名字:插件里的 skill 和子代理会带上插件名做前缀,比如 /express-kit:commit-message。这样两个插件各有一个同名的 skill 也不会冲突。

1建目录,写清单

我们的插件叫 express-kit,装三样东西:一个写提交说明的 skill,子代理那篇里的测试评审员,一个记录改动文件的 hook。

express-kit/
├── .claude-plugin/
│   └── plugin.json              清单
├── skills/
│   └── commit-message/
│       └── SKILL.md
├── agents/
│   └── test-reviewer.md
└── hooks/
    └── hooks.json

清单是 .claude-plugin/plugin.json:

{
  "name": "express-kit",
  "description": "团队在这个仓库上用的一套约定:提交说明的格式、测试评审员、改动记录",
  "version": "0.1.0",
  "author": {
    "name": "chunduai demo"
  }
}

四个字段,按官方文档:

字段 说明
name 必填。插件的标识,也是它里面每个 skill 和子代理的前缀。不能有空格
description 别人在 /plugin 里看到的那句介绍
version 可选。写了的话,装的人会停在这个版本,直到你改它
author 署名。里面的 name 必填,email 和 url 可选

2放进三样东西

skill 放在 skills/<名字>/SKILL.md,写法和普通的 skill 完全一样(见写第一个 skill):

---
name: commit-message
description: 按团队的格式写提交说明。用户要提交、或者要一条提交说明时使用。
---

根据用户描述的改动(没有描述就看 `git diff --staged`),写一条提交说明:

- 用英文,只写一行,不超过 72 个字符,结尾不加句号。
- 以类型开头,只能是 `fix:`、`docs:`、`test:`、`refactor:` 之一。
- 类型后面用祈使句说明做了什么,不写为什么。
- 只输出这一行,不要解释,不要代码块。

子代理 放在 agents/ 下,一个 Markdown 文件一个,头部和正文与项目里的写法相同。我们直接用了之前那个只读的测试评审员。

hook 放在 hooks/hooks.json。最外层是一个 "hooks" 键,里面的结构和设置文件里的 hooks 一模一样:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          { "type": "command", "command": "jq -r '.tool_input.file_path' >> /tmp/c7-edited-files.log" }
        ]
      }
    ]
  }
}

这个 hook 很简单:每次它改完或写完一个文件,把路径记进一个日志。hook 怎么写见Hooks 实战。

已经在项目的 .claude/ 下有这些文件的,不用重写,复制过去就行:cp -r .claude/skills express-kit/,子代理同理;hook 则是把设置文件里的 hooks 对象整个复制进 hooks/hooks.json。

最容易放错的地方

.claude-plugin/ 里只放 plugin.json 一个文件。 skill、子代理、hook 都放在插件的根目录下,和 .claude-plugin/ 并排,不是放在它里面。

这一条官方文档用警告框强调了,我们专门试了放错会怎样,结果见下一节。

3校验

claude plugin validate ./express-kit
Validating plugin manifest: /home/ccdemo/demo/c7-plugin/express-kit/.claude-plugin/plugin.json

✔ Validation passed

我们故意弄错了两处,看它查不查得出。

名字里带空格,查得出,退出码非零:

✘ Found 1 error:

  ❯ name: Plugin name cannot contain spaces. Use kebab-case (e.g., "my-plugin")

✘ Validation failed

把 skills/ 放进了 .claude-plugin/ 里面,查不出:

✔ Validation passed

校验通过了,但加载之后会话里登记的东西是这样的:

{"plugins":["express-kit", ...],"skills":[],"agents":["express-kit:test-reviewer"]}

插件在,子代理在,skill 一个都没有,也没有任何报错。

所以校验通过只说明清单和各个文件的头部写得合法,不说明东西都加载上了。校验之后一定要实际加载一次,看清单。

4不安装,先加载一次试试

--plugin-dir 让一个插件只在这一次会话里生效,不写任何设置,适合开发时用:

claude --plugin-dir ../express-kit

我们用 -p 配合流式输出,看会话启动时登记了什么(写法见把 Claude Code 接进脚本和 CI):

{
  "plugins": [
    {"name": "express-kit", "path": "/home/ccdemo/demo/c7-plugin/express-kit"},
    {"name": "cc-plugin-agents-md", "path": "builtin"},
    ...
  ],
  "skills": ["express-kit:commit-message"],
  "agents": ["express-kit:test-reviewer"]
}

三样逐个验证。

skill,用带前缀的名字调用:

$ claude --plugin-dir ../express-kit -p "/express-kit:commit-message 我把 lib/utils.js 里的 var 都换成了 const 和 let,行为没有变"

refactor: replace var with const and let in lib/utils.js

注意:CLAUDE.md 规定提交类型只能用 `fix:`、`docs:` 或 `test:`,但这个技能也允许用 `refactor:`。
这次改动不影响行为,三种类型都不贴切,所以我用了 `refactor:`……

第一行是我们要的。后面多出来的一段值得注意:这个仓库的 CLAUDE.md 里写着提交类型只有三种,而插件的 skill 允许四种。两处的规矩对不上,它两份都读到了,于是多说了一段。

这是做插件时真会碰到的事:插件是装进别人项目里的,那个项目有自己的 CLAUDE.md。 插件里的约定和项目的约定冲突时,它不会默默挑一个,结果也就不是你设想的那一行干净的输出。给多个项目用的插件,约定要么写得足够通用,要么在说明里讲清楚以谁为准。

不加 --plugin-dir 跑同一条命令,它会告诉你没有这个命令:

这个会话里没有安装 `/express-kit:commit-message` 命令,它没有运行。我直接按项目约定帮你写提交说明。

hook,让它改一个文件,然后看日志:

$ cat /tmp/c7-edited-files.log
/home/ccdemo/demo/c7-plugin/app/Readme.md

hook 触发了。

子代理在登记的清单里是 express-kit:test-reviewer,点名时用这个带前缀的名字。这次我们只确认了它登记上了,没有再派它干一次活。

开发时改了插件的文件,在会话里输入 /reload-plugins 就能重新加载,不用退出。这一条我们没有试。

用 claude plugin list 也能看到单次加载的插件,前提是把 --plugin-dir 写在前面:

$ claude --plugin-dir ../express-kit plugin list
Session-only plugins (--plugin-dir / --plugin-url):

  ❯ express-kit@inline
    Version: 0.1.0
    Path: /home/ccdemo/demo/c7-plugin/express-kit
    Status: ✔ loaded

5建一个市场,让别人能装

把插件交到别人手里,官方文档给了三条路:

做法 适合
直接把目录或者 zip 包发给对方 只给几个人,不需要发布
放进你自己的市场 团队或组织。对方登记一次市场,按名字安装,之后能收到更新
提交到 Anthropic 的目录 面向所有人,要经过审核

团队里用,走第二条。市场也只是一个目录,里面有一个 .claude-plugin/marketplace.json,列出有哪些插件、各自去哪取。

team-marketplace/
├── .claude-plugin/
│   └── marketplace.json
└── plugins/
    └── express-kit/             把插件整个复制进来
{
  "name": "team-marketplace",
  "description": "团队内部的插件",
  "owner": {
    "name": "chunduai demo"
  },
  "plugins": [
    {
      "name": "express-kit",
      "source": "./plugins/express-kit",
      "description": "提交说明的格式、测试评审员、改动记录"
    }
  ]
}

两条规矩,官方文档说大多数装不上的情况都出在这两处:

  • source 的相对路径从市场的根目录算起,也就是包含 .claude-plugin/ 的那个目录,不是从 .claude-plugin/ 里面算。路径里不能有 ..。
  • 条目里的 name 要和插件自己 plugin.json 里的 name 一样。 前者是安装时用的名字,后者是 skill 的前缀。两个不一样的话,别人照着 skill 前缀上的名字去装,会提示在市场里找不到这个插件。

校验同一条命令,这次指向市场的目录:

claude plugin validate ./team-marketplace
Validating marketplace manifest: /home/ccdemo/demo/c7-plugin/team-marketplace/.claude-plugin/marketplace.json

✔ Validation passed

6登记市场,安装

先在自己机器上把整个流程走一遍,这也是你的同事之后要走的流程。

登记市场:

claude plugin marketplace add ./team-marketplace
Adding marketplace…✔ Successfully added marketplace: team-marketplace (declared in user settings)

安装。安装用的标识是“插件名@市场名”:

claude plugin install express-kit@team-marketplace --scope project
Installing plugin "express-kit@team-marketplace"...✔ Successfully installed plugin: express-kit@team-marketplace (scope: project)

安装范围

--scope 决定谁能用上这个插件,以及记在哪个设置文件里:

范围 谁能用 记在哪
用户(默认) 你,这台机器上的所有项目 ~/.claude/settings.json
项目(--scope project) 在这个仓库里干活的所有人 .claude/settings.json,要提交
本地(--scope local) 你,只在这个仓库里 .claude/settings.local.json

我们选了项目范围。装完之后项目的 .claude/settings.json 里多了这一段:

{
  "enabledPlugins": {
    "express-kit@team-marketplace": true
  }
}

官方文档对项目范围有一句要注意的说明:把这一段提交进仓库,是给同事启用了这个插件,但不会把插件下载到他们的机器上。每个同事还得自己登记市场、运行一次安装。

装上之后看什么

$ claude plugin list
Installed plugins:

  ❯ express-kit@team-marketplace
    Version: 0.1.0
    Read from: /home/ccdemo/demo/c7-plugin/team-marketplace/plugins/express-kit
    Scope: project
    Status: ✔ enabled

更有用的是 details,它列出插件里实际被识别出来的东西,以及每样占多少上下文:

$ claude plugin details express-kit
express-kit 0.1.0
  Description: 提交说明的格式、测试评审员、改动记录
  Source: express-kit@team-marketplace

Component inventory
  Skills (1)  commit-message
  Agents (1)  test-reviewer
  Hooks (1)  PostToolUse  (harness-only — no model context cost)
  MCP servers (0)
  LSP servers (0)

Projected token cost
  Always-on:   ~134 tok   added to every session

Per-component (rounded)
  component       always-on  on-invoke
  commit-message        ~70       ~270
  test-reviewer         ~60       ~160

前面“skill 放错位置”的问题,在这里一眼就能看出来:Skills 后面的数字对不对。

下面那张表回答的是装一个插件的代价:这个插件让每次会话多带约 134 个 token(skill 和子代理的名字加说明),正文在用到时才加载。hook 标着不占模型的上下文,因为它是 Claude Code 自己执行的,不经过模型。装别人的插件之前,也可以用这条命令看看它会往每次会话里加多少东西。

验证

在这个项目里,不加任何参数:

$ claude -p "/express-kit:commit-message 给 req.subdomains 补了一个 IPv6 主机名的测试"
test: add IPv6 hostname case for req.subdomains

换到另一个没装它的项目,会话里就没有这个 skill。项目范围起作用了。

7放到团队够得着的地方

上面的市场还在你自己的硬盘上。要给团队用,把市场的目录推到一个 git 仓库,私有的也可以。同事那边:

claude plugin marketplace add 你的组织/仓库名
claude plugin install express-kit@team-marketplace

GitHub 上的仓库可以用“组织/仓库”的简写,别的 git 托管用完整的仓库地址。这一步我们没有实测,实测环境没有可以推送的远程仓库。

插件本身不一定要放在市场的目录里。source 可以指向别处,文档列的常用写法:

source 用在
"./plugins/express-kit" 插件就在市场的目录里
{ "source": "github", "repo": "你的组织/express-kit" } 插件自己是一个 GitHub 仓库
{ "source": "git-subdir", "url": "你的组织/monorepo", "path": "tools/express-kit" } 插件是某个仓库里的一个子目录

有一种错误校验查不出来:source 指向的目录不存在。文档说明这种情况校验会通过,到安装时才报 Source path does not exist。所以发给别人之前,自己先装一遍。

不要了怎么撤

claude plugin marketplace remove team-marketplace
✔ Successfully removed marketplace: team-marketplace
Also uninstalled 1 plugin from this marketplace:
  express-kit@team-marketplace
The removal also deletes their saved options, secrets and data where it can.

移除市场会连带卸载从它装的插件。之后 claude plugin list 显示没有已安装的插件,项目设置里的 enabledPlugins 也清空了。

这一趟花了多少

校验、登记、安装、查看、移除这些命令都不调用模型,不花钱。花钱的是验证 skill 和 hook 的那几次 claude -p,合计约 1 美元,是 Claude Code 按官方价格估算的数字,不是中转站实际扣的金额。

这次实测没有覆盖到的

  • 市场没有推到远程仓库。 同事从 git 仓库登记和安装、收到更新、私有仓库的访问,都按官方文档写的。
  • 插件里的 MCP 服务器、LSP 服务器、userConfig 配置项没有做。
  • 子代理只确认了登记上,没有实际派出去。
  • /reload-plugins、--plugin-url、claude plugin init、把插件放在 ~/.claude/skills/ 下每次自动加载,都没有试。
  • 会话里的 /plugin 面板没有试,全程用的是 shell 里的 claude plugin 命令。
  • 版本更新没有试。 改了 version 之后装过的人怎么收到,文档在“维护市场”那一页。
  • claude plugin eval(衡量插件有没有真的改变它的行为)没有试。
  • 只跑了一次。

下一步

来源

通过 API 中转站使用这些模型?到 Veridrop 免费检测中转站给你的是不是它声称的模型,或者看看中转站排行榜前 100 名。

相关文章