从单个 Skill 到团队私有市场:Plugin 打包分发的最后一公里

你可能正经历这件事

Skill、Hook、Agent 散落各处,团队成员各写各的——这事儿你可能正经历。

我去年带一个 6 人小组用 Claude Code 做 DevOps 工具链,第 3 个月就出问题:每个人.claude/skills/目录里都躺着自己写的review.md,命名一样内容五花八门;新人入职要拷 4 个文件夹、改 2 处路径、再手敲一次 hooks 注册;某个 Hook 脚本升级了,谁也没通知谁,CI 上一半通过一半挂。这不是哪个人不靠谱,是缺一个"打包分发"的层。

Claude Code 在 M8 给出的答案叫 Plugin——把 Commands、Subagents、Hooks、MCP Servers 装进同一个目录、配一张身份证、能装能卸能升级的单元。M9 再叠上工程化治理,团队级用起来才稳。

下面把踩过的坑和能用上的冷门开关一条龙讲完。

Plugin 是能力的封装与分发

不要把 Plugin 想成"另一个 Skill"。Skill 是单点能力,Plugin 是容器——里面装什么由你决定。一个 Plugin 可以只放一个 Subagent,也可以同时塞进 Commands + Hooks + MCP + 条件化规则。

实际用下来,Plugin 的真正价值不在"打包",而在"分发 + 版本"。我个人的判断是:单兵作战时 Plugin 收益有限,团队超过 3 个人、跨项目复用时,Plugin 是分水岭。再小就只能靠 Git submodule 强撑,那套玩法很难管。

plugin.json:Plugin 的身份证

每个 Plugin 根目录一张plugin.json

{"name":"team-toolkit","version":"2.0.0","description":"团队标准开发工具包:代码审查、测试、安全扫描一体化","author":"Platform Team","repository":"https://github.com/our-company/team-toolkit","license":"MIT","keywords":["team","devops","code-review","security"]}

字段里我特别想点一句version80% 的人不知道 Plugin 的版本号要和 git tag 一致,否则/plugin update拉到的版本会和你 README 里写的对不上。我自己吃过亏,发布后第二天就有同事说"装出来还是旧的",排查半小时才发现版本号没递增。repository字段也别瞎填,从 GitHub 安装时它就是下载源。

四种组件格式:装什么、怎么装

Plugin 目录长这样:

team-toolkit/ ├── plugin.json ├── commands/ │ └── review.md ├── agents/ │ └── security-scanner.md ├── hooks/ │ ├── hooks.json │ └── check-bash.sh └── mcp/ └── mcp.json

四种组件各有各的格式。Subagent 用带 frontmatter 的.md,别写成纯文本:

--- name: security-scanner description: 扫描代码中的安全漏洞,生成结构化报告 tools: Read, Grep, Glob model: sonnet --- 你是安全专家,专门识别代码中的安全漏洞。 ## 扫描范围 1. 注入漏洞:SQL 注入、命令注入、XSS 2. 认证问题:弱密码策略、硬编码凭证 3. 数据暴露:敏感信息日志输出 4. 访问控制:缺少权限检查、路径遍历 ## 原则 - 只报告有实际证据的问题,不臆测 - 提供具体的修复建议,不只是指出问题

tools字段做能力隔离——安全扫描只需要 Read/Grep/Glob,就别给 Bash。model: sonnet让 Subagent 用中等模型,避免主智能体上 Opus 时成本失控。

Hooks 用.json注册 + 脚本执行

{"hooks":[{"event":"PreToolUse","matcher":"Bash","command":["bash","./hooks/check-bash.sh"]},{"event":"PostToolUse","matcher":"Write","command":["bash","./hooks/auto-format.sh"]}]}

MCP Servers 同样是.json,会话启动时加载:

{"mcpServers":{"postgres":{"command":"npx","args":["-y","@anthropic/mcp-server-postgres"],"env":{"DATABASE_URL":"${DATABASE_URL}"}}}}

安装、管理、本地测试三板斧

# 从社区市场/plugininstallreact-workflow@community# 从 GitHub 仓库(旧的 github: 前缀已废弃)/plugininstallgithub.com/username/react-workflow# 从本地目录(开发调试常用)/plugininstall./path/to/my-plugin# 日常管理/plugin list /plugin remove react-workflow /plugin update react-workflow

冷门开关来了:--plugin-dir是本地开发神器,不正式安装就能加载:

claude --plugin-dir ./my-plugin-dev

改一行 frontmatter,重跑命令立刻验证。我开发 Plugin 时几乎不/plugin install,全是--plugin-dir起步,稳定了再发版。

实战:打包一个安全扫描 Plugin

把前面的零碎串起来。目标:能扫注入漏洞、又能在 Bash 危险命令时拦下来的 Plugin。

目录骨架:

team-toolkit/ ├── plugin.json ├── agents/security-scanner.md ├── hooks/ │ ├── hooks.json │ └── check-bash.sh

plugin.json已在上面给出,Hooks 拦截脚本hooks/check-bash.sh

#!/bin/bash# 检查 Bash 命令是否安全INPUT=$(cat)COMMAND=$(echo"$INPUT"|jq-r'.tool_input.command // empty')DANGEROUS_PATTERNS=("rm -rf /""rm -rf ~""sudo rm""> /dev/""chmod 777")forpatternin"${DANGEROUS_PATTERNS[@]}";doifecho"$COMMAND"|grep-qF"$pattern";thencat<<EOF {"decision": "deny", "reason": "Blocked dangerous pattern:$pattern"} EOFexit0fidoneecho'{"decision": "allow"}'

注意脚本要chmod +x,否则 Hook 不触发——这是新手最容易漏的一步。

发布流程走 git tag:

cdteam-toolkitgitinitgitadd.gitcommit-m"v2.0.0: 添加安全扫描和自动格式化"gittag v2.0.0gitremoteaddorigin https://github.com/our-company/team-toolkitgitpush-uorigin main--tags

发布前自查清单:plugin.json的 version 已递增、JSON 合法、frontmatter 齐全、Hooks 脚本有执行权限、本地--plugin-dir测试通过、git tag 与 version 一致。这套清单我踩过坑才总结出来,发布前老老实实跑一遍。

团队成员拉下来一行命令:

/plugininstallgithub.com/our-company/team-toolkit

私有市场:团队的 Plugin 仓库

GitHub 仓库能解决分发,但解决不了"发现"——团队里有哪些 Plugin、各自什么版本,新人根本不知道。私有市场就是干这个的。

创建私有市场,本质是一个marketplace.json

{"name":"Our Company Plugins","description":"内部插件市场","plugins":[{"name":"team-toolkit","description":"团队标准开发工具包","repository":"https://github.com/our-company/team-toolkit","version":"2.0.0"},{"name":"db-tools","description":"数据库操作工具集","repository":"https://github.com/our-company/db-tools","version":"1.2.0"}]}

把这个文件丢到公司 GitHub 的our-company/claude-plugins仓库根目录,团队成员这样接入:

# 添加公司市场/plugin marketplaceaddour-company/claude-plugins# 从公司市场安装/plugininstallteam-toolkit@our-company

@our-company后缀就是市场名。这个冷门功能很多人没碰过,但它就是 Plugin 体系里"团队级"和"个人级"的分水岭。

工程化治理:分发完了才刚开始

Plugin 装上不等于万事大吉。模型选错烧钱、出问题没法排查、有人偷偷改配置绕过安全——这些坑都得治理层兜底。

模型选择策略,按任务复杂度分级:

# 简单任务用 Haiku,设置低预算claude-p"检查这个函数的变量命名"--modelclaude-haiku-4-5 --max-budget-usd0.05# 复杂的架构分析,使用 Opus 并允许更高预算claude-p"分析整个支付系统的设计问题"--modelclaude-opus-4-6 --max-budget-usd2.00

简单任务跑 Opus 就是烧钱,复杂任务跑 Haiku 就是出垃圾。--max-budget-usd是硬上限,CI 里必加。

成本追踪,把每次调用的钱记下来:

result=$(claude-p"review this PR"--output-format json)cost=$(echo"$result"|jq-r'.total_cost_usd')echo"PR_REVIEW_COST:$cost">>/var/log/claude-costs.log

跑一个月再awk聚合,哪个项目烧钱一眼看穿。我们组上个月就靠这套发现一个测试任务每天烧 $4,改 Haiku 后降到 $0.3。

调试三板斧--debug看全过程,stream-json实时观察,PostToolUse Hook 做审计日志。

# X 光模式:API、工具、记忆全展开claude--debug-p"列出当前目录的文件"# 流式 JSON,逐条消息实时观察claude-p"分析 src/ 目录的架构问题"--output-format stream-json|jq'.'

审计日志 Hook.claude/hooks/audit-log.sh

#!/bin/bash# .claude/hooks/audit-log.shINPUT=$(cat)TOOL=$(echo"$INPUT"|jq-r'.tool_name')TIMESTAMP=$(date-u+"%Y-%m-%dT%H:%M:%SZ")echo"$TIMESTAMP|$TOOL|$(echo"$INPUT"|jq-c'.tool_input')">>.claude/audit.logexit0

配套注册到settings.json

{"hooks":{"PostToolUse":[{"matcher":"*","hooks":[{"type":"command","command":"bash .claude/hooks/audit-log.sh"}]}]}}

事后追溯谁在什么时候跑了什么命令,全在audit.log里。

层次化 CLAUDE.md + 组织级策略

CLAUDE.md 是 6 级加载,越往下越具体:

第1级 企业级 /etc/claude-code/CLAUDE.md 全体员工基线 第2级 组织级 ~/.claude/CLAUDE.md 部门/团队规范 第3级 项目级 ./CLAUDE.md 项目说明 第4级 条件级 ./.claude/rules/*.md 按路径加载 第5级 本地级 ./CLAUDE.local.md 个人偏好 第6级 会话级 对话中直接输入 临时指令

第 4 级条件化规则是冷门开关:

--- paths: - "src/api/**/*.ts" --- # API 开发规范 - 所有 API 端点必须包含输入验证 - 错误响应使用统一的 ErrorResponse 类型 - 认证中间件已全局配置,不需要在每个端点重复

只在编辑src/api/**/*.ts时加载,避免把所有规范一次性塞进上下文。

组织级策略管理才是真正的"宪法"。Linux 下放在/etc/claude-code/managed-settings.json

{"disableBypassPermissionsMode":"disable","allowManagedPermissionRulesOnly":true,"allowManagedHooksOnly":true,"permissions":{"deny":["Bash(curl *)","Bash(wget *)","Read(./.env)","Read(./.env.*)"]}}

三个字段记住:disableBypassPermissionsMode禁掉--dangerously-skip-permissionsallowManagedPermissionRulesOnly让项目级 settings.json 不能放宽权限,allowManagedHooksOnly让项目级不能自定义 Hooks。一句话——项目级只能更严,不能更松。这套我建议任何上规模的组织第一时间配上,别等出事再补。

ConfigChange Hook 顺手配上,谁动配置谁留痕:

{"hooks":{"ConfigChange":[{"matcher":"*","hooks":[{"type":"command","command":"echo '[AUDIT] Config changed: $CONFIG_FILE' >> ~/.claude/config-audit.log"}]}]}}

一份能直接抄的完整配置

plugin.json

{"name":"team-toolkit","version":"2.0.0","description":"团队标准开发工具包:代码审查、测试、安全扫描一体化","author":"Platform Team","repository":"https://github.com/our-company/team-toolkit","license":"MIT","keywords":["team","devops","code-review","security"]}

私有市场marketplace.json

{"name":"Our Company Plugins","description":"内部插件市场","plugins":[{"name":"team-toolkit","description":"团队标准开发工具包","repository":"https://github.com/our-company/team-toolkit","version":"2.0.0"},{"name":"db-tools","description":"数据库操作工具集","repository":"https://github.com/our-company/db-tools","version":"1.2.0"}]}

顺便一提,雷达鸭 App(收录中国一人公司赚钱案例,华为应用市场+微信小程序,Uni-app+ArkTS+UniCloud)团队内部也是用这套私有市场统一分发 Plugin,新人入职/plugin install一行命令拉齐全部能力。


Plugin 这层搭好,剩下的问题就不再是"工具够不够",而是"治理跟不跟得上"。当你的私有市场里堆到第 10 个 Plugin、第 5 个团队成员各装各的子集时——你打算用什么机制保证每个人都跑在受治理的版本上?

关于作者:雷达鸭 App 独立开发者,10+ 年软件开发经验,软件设计师、人工智能应用工程师,专注鸿蒙 ArkTS + Web 前端,正在探索 AI 自动化的工程化落地。

本文基于《Claude Code 实战:Harness 工程之道》(黄佳 著)第 9、10 章整理,代码示例遵循 MIT 协议,可自由使用与修改。