从 Rules、Skills 到 Plugin:Agent 能力如何工程化组合
团队的 AI Coding 配置,通常不是“设计”出来的,而是一点点堆出来的。
一位工程师保存着一份 120 行的发版检查 Prompt;仓库里有 AGENTS.md 或 CLAUDE.md,但一半规则只在发版时才有用;另一位工程师做了一个 Skill;第三个人接入 GitHub MCP;还有人写了一个脚本,每次 Agent 修改文件后都检查生成目录。
这些零件在各自电脑上都能工作,但新人入职时,仍要照着清单复制文件、执行命令、授权服务,再记住一长串注意事项。
后来发版流程变了。
Skill 更新了,旧 Hook 却仍在运行;MCP Server 申请了超出工作流所需的权限;Rule 明明写着“禁止自动发布”,另一个地方打包的命令却仍会调用 npm publish。这时没人能回答一个最基本的问题:
这项能力到底是什么?边界在哪里?团队实际运行的是哪个版本?
这正是 Plugin 应该解决的问题。Plugin 不是“更大的 Prompt”,也不是把许多文件压在一个目录里。它是一种可安装的能力产品:围绕一个完整场景,把说明、工作流、工具、生命周期控制、元数据和分发方式组合成有名称、有版本的能力包。
本文会用一个案例贯穿全过程:构建 release-guard Plugin。它负责审查发版证据,在连接可用时读取实时 PR 数据,阻止 Agent 直接执行发布操作,并输出可以验收的发版结论。
学完以后,你应该能够:
- 有依据地判断一项需求应该放进 Prompt、Rules、Skill、MCP、Hook 还是 Plugin;
- 对比当前 Cursor、Claude Code 和 Codex 的 Plugin 方案,而不是把它们误认为同一套标准;
- 解释 Hook 在 Agent Loop 中的位置,以及它能防住和防不住哪些失败;
- 用可移植 Skill 作为能力核心,再为不同宿主编写 Manifest 和 Hook 适配层;
- 分开验证安装、启用、触发、授权、执行效果、升级和回滚。
一、先建立心智模型:Plugin 是能力包,不是另一层智能
真正负责推理的仍然是 Agent。其他机制分别决定它知道什么、能做什么,以及它的动作前后必须发生什么。
可以把它们拆成六类职责:
| 机制 | 它回答什么问题? | 典型内容 | 运行特征 |
|---|---|---|---|
| Prompt | 这一次任务要什么? | 目标、输入、范围、验收标准 | 单次任务 |
| Rules | 在这个作用域里通常应该怎样工作? | 仓库命令、架构约束、编码规范 | 持久上下文 |
| Skill | 这一类可识别任务应该怎样完成? | 触发描述、判断、步骤、资料、脚本、输出契约 | 按需加载 |
| MCP / Connector | 可以读取哪些实时数据、执行哪些外部动作? | 类型化工具、认证、授权、结构化结果 | 服务端能力 |
| Hook | 在生命周期边界必须执行什么? | 检查、阻断、改写、验证、审计、补充上下文 | 事件驱动控制 |
| Plugin | 如何把相关能力一起安装、版本化和分发? | Manifest、Skills、工具、Hooks、资产、元数据 | 能力包 |
名称没有边界重要。
Rules 负责引导,不负责强制
AGENTS.md、CLAUDE.md 和 Cursor Rules 会进入模型上下文。它们非常适合表达“使用 pnpm”“先阅读这份架构说明”“这个包的测试放在这里”。但这些内容仍然是由模型解释的自然语言指导。
Claude Code 的官方 Memory 文档对此说得很明确:CLAUDE.md 是上下文,不是强制配置;如果某个动作无论模型如何判断都必须被禁止,应该使用 PreToolUse Hook。这个工程边界同样适用于其他产品。
Skill 教工作流,但不会自动产生权限
Skill 可以告诉 Agent 如何审查发版、收集哪些证据、何时必须停止。它也可以调用宿主已经提供的工具。但安装 Skill 不等于完成 GitHub 认证,不会自动授予写权限,也不能证明某条命令一定安全。
MCP 提供能力,不应该承包整个工作流
实时 PR 数据、Issue 元数据、Release 状态,或受控的 create_draft_release 动作,适合放在 MCP Server。工具 Schema 和服务端授权比在 Prompt 里写一句“小心操作”更可靠。
Skill 决定何时、为什么调用工具;MCP Server 决定调用者是否有权执行动作。
Hook 拦截生命周期事件,不是后台魔法
Hook 之所以运行,是因为某个事件发生了:Session 启动、Prompt 提交、工具即将执行、文件完成修改、上下文发生压缩,或者 Agent 准备停止。Hook 可以在模型周围补充确定性行为,但每个 Hook 都有明确的事件集合、输入 Schema、输出 Schema、超时和失败策略。
Plugin 让整项能力真正可运营
单个文件回答不了的问题,要由 Plugin 回答:
- 哪些组件属于同一项能力?
- 当前安装的是哪个版本?
- 支持哪些宿主和产品界面?
- 哪些连接需要认证,哪些脚本需要信任审查?
- 队友如何发现、安装、升级、禁用和卸载?
- 兼容性与故障由谁负责?
所以,“把文件放进共享 Wiki”不等于拥有一个 Plugin。
二、为什么 Plugin 最终会变得必要?
不要一开始就做 Plugin。先从重复问题出发,证明 Skill 或工具确实有效;当组件之间的协调成本超过单项实现成本时,再升级为 Plugin。
一项能力同时符合下面至少三条时,通常值得打包:
- 多个组件必须保持兼容。 Skill 依赖特定 Hook 输出或 MCP Tool Schema。
- 多个人或多个仓库都要使用。 手工复制开始产生版本漂移。
- 安装包含依赖或权限。 用户需要看得见的设置步骤和信任边界。
- 能力需要升级与回滚。 工作流更新后,不能留下旧脚本继续运行。
- 可发现性很重要。 用户应该描述目标,而不是背诵五步配置。
- 团队需要 Owner 与政策。 必须有人负责评审变化、漏洞和退役。
它带来的好处很具体:
| 没有 Plugin | 设计良好的 Plugin |
|---|---|
| 分别复制 Rules、Skills、脚本和配置 | 安装一个有名称的能力包 |
| 各组件独立漂移 | 兼容组件一起发布 |
| 设置经验留在聊天记录或 Wiki | Manifest 与 Marketplace 暴露依赖和元数据 |
| 每个人自己发明升级方式 | 版本、来源和升级路径明确 |
| 运行失败后才发现缺权限 | 安装时就展示连接与信任要求 |
| 不知道卸载时该删什么 | 包定义清楚的卸载边界 |
代价也真实存在:Plugin 会增加发布面、兼容性承诺、安全审查、文档和支持工作。如果一个聚焦的 Skill 已经足够,就不要为了“工程化”而升级。
三、AI Coding 领域并不存在统一的 Plugin 格式
截至 2026 年 8 月 6 日,Cursor、Claude Code 和 Codex 都用 “Plugin” 表示可分发的能力包。它们的方向正在趋同,但 Manifest、可包含组件、安装目录、调用语法、Marketplace 和 Hook 协议都不能直接互换。
三者之间最可移植的单元是 Agent Skills 开放格式,其核心是包含 SKILL.md 的目录。即便如此,不同宿主也可能增加 Front Matter 扩展和自己的发现规则。MCP 同样是开放协议,但 Plugin 中的 MCP 配置与认证流程仍由宿主决定。
Cursor:面向编辑器与工作区的综合定制包
Cursor 官方 Plugin 文档将 Plugin 定义为 Rules、Skills、自定义 Agents、Commands、MCP Servers 和 Hooks 的组合。Manifest 位于 .cursor-plugin/plugin.json,符合约定的组件目录可以自动发现。本地开发可以使用 ~/.cursor/plugins/local,正式分发则可以进入官方或团队 Marketplace。
这反映了 Cursor 的产品边界:一个 Plugin 不仅能影响编辑器 Agent,还可以加入专用 Agent、内联工作流、MCP 连接与工作区生命周期行为。
release-guard-cursor/
├── .cursor-plugin/
│ └── plugin.json
├── rules/
│ └── release-policy.mdc
├── skills/
│ └── release-readiness/
│ └── SKILL.md
├── hooks/
│ └── hooks.json
└── mcp.json最小 Cursor Manifest 只要求 name,默认组件目录可以自动发现。但如果要进入团队分发,仍应该明确版本和 Owner。
Claude Code:终端优先、运行时组件丰富的扩展包
Claude Code 的 Create plugins 指南说明 Plugin 可以包含 Skills、自定义 Agents、Hooks 和 MCP Servers。Plugin 根目录还可以提供 LSP Server 配置、后台 Monitor、加入 PATH 的可执行程序,以及默认设置。Manifest 位于 .claude-plugin/plugin.json。
开发时可以用 claude --plugin-dir ./release-guard-claude 直接加载目录。分发时,.claude-plugin/marketplace.json 可以指向本地路径、Git 仓库、Git 子目录或包。安装后的 Plugin Skill 使用命名空间,例如 /release-guard:release-readiness。
release-guard-claude/
├── .claude-plugin/
│ └── plugin.json
├── skills/
│ └── release-readiness/
│ └── SKILL.md
├── agents/
├── hooks/
│ └── hooks.json
└── .mcp.jsonClaude Code 官方明确建议:项目内试验先使用 .claude/ 独立配置;当能力需要跨项目复用、发布版本和 Marketplace 分发时,再转换为 Plugin。
Codex:在受支持的 ChatGPT 与 Codex 界面之间共享能力包
OpenAI 的 Plugin Architecture 文档把 Plugin 的核心定义为 Skills、可选 MCP Server,或两者组合。Codex 侧的包还可以包含生命周期 Hooks 和资产。每个包都需要 .codex-plugin/plugin.json;.mcp.json 可描述随包分发的 MCP Server,.app.json 可映射已经注册的 Server 连接。
公开 Plugin 进入 ChatGPT 与 Codex 支持界面共享的统一目录;本地和仓库 Marketplace 用于开发、测试与私有分发。OpenAI 推荐在 Codex 中使用 $plugin-creator,或在 ChatGPT Work 中使用 @plugin-creator 生成骨架;手工创建的 Plugin 本质上仍是普通目录。
release-guard-codex/
├── .codex-plugin/
│ └── plugin.json
├── skills/
│ └── release-readiness/
│ └── SKILL.md
├── hooks/
│ └── hooks.json
├── .mcp.json
└── assets/Plugin 的可用性还取决于具体界面。当前 OpenAI Plugins 指南记录了 ChatGPT Work、桌面应用和 Codex CLI 中的 Plugin 浏览与安装;Codex IDE Extension 支持独立 Skills,但没有 Plugin Browser。必须把“生态支持”与“当前宿主可用”当成两个兼容性维度。
一张实用对照表
| 维度 | Cursor | Claude Code | Codex |
|---|---|---|---|
| Manifest | .cursor-plugin/plugin.json | .claude-plugin/plugin.json | .codex-plugin/plugin.json |
| 常见组件 | Rules、Skills、Agents、Commands、MCP、Hooks | Skills、Agents、Hooks、MCP、LSP、Monitors、bin、Settings | Skills、MCP 连接或 Server、Hooks、资产和安装元数据 |
| 本地测试 | ~/.cursor/plugins/local + Reload | claude --plugin-dir ./path | 本地或仓库 Marketplace;可用 $plugin-creator |
| Skill 调用 | /skill-name | /plugin-name:skill-name | $skill-name 或宿主 Skill Picker |
| 分发 | 官方与团队 Marketplace | 来自 Git、本地、包的 Marketplace Catalog | 统一公开目录 + 本地/仓库 Marketplace |
| 产品侧重 | 编辑器与工作区定制 | 终端/IDE Agent 运行时扩展 | 在支持的 ChatGPT/Codex 界面间组合能力 |
不要只看表格就选择宿主。真正的选择依据是团队实际使用的执行界面、需要的组件类型、安全模型和分发边界。
四、Hook:在概率性 Agent Loop 周围加入确定性代码
AI Coding Agent 会在模型推理与工具执行之间循环:
用户请求
→ 模型判断下一步
→ 请求工具
→ 工具执行
→ 结果返回模型
→ 模型继续或停止Hook 在这个循环周围增加可编程检查点。
大多数有价值的 Hook 可以归入五类:
| 作用 | 常见事件 | 例子 | 能否影响当前动作? |
|---|---|---|---|
| 准备 | Session Start / Prompt Submit | 加载环境事实、验证 Prompt 结构 | 视宿主而定,可补充上下文或阻断 |
| 把关 | Before Tool Use / Permission Request | 禁止发布、读取密钥或危险 MCP 调用 | 可以 |
| 规范化 | 工具或编辑前后 | 在支持时改写输入、运行 Formatter | 取决于宿主和事件 |
| 观察 | After Tool Use / Session End | 审计耗时、命令、结果和失败 | 通常不能撤销已发生的动作 |
| 验证/恢复 | Stop / Subagent Stop | 要求再跑一轮测试或补充证据 | 宿主支持时可继续循环 |
Hook 比 Rule 强,但比服务端授权窄
假设团队政策是:“Agent 可以准备发版,但绝不能真正发布。”
- Rule 解释政策,让 Agent 更可能做出正确判断;
PreToolUseHook 可以阻断本地npm publish或gh release create;- MCP Server 可以完全不暴露 Publish Tool,或者要求服务端审批 Token;
- 仓库、Registry 与部署环境权限可以确保 Agent 身份根本没有生产写权限。
可靠设计会叠加这些层。开发者电脑上的 Hook 不能替代 Registry 权限或受保护环境。
事件名称很相似,协议却不相同
三家都在工具调用、Session 与结束阶段提供生命周期事件,但 Wire Protocol 各不相同。
- Cursor 的 Hooks 文档使用
preToolUse、beforeShellExecution、afterFileEdit、subagentStop、workspaceOpen等事件。Command Hook 通过标准输入输出交换 JSON,也支持 Prompt Hook。对于关键门禁,Cursor 提供failClosed: true;默认情况下,Hook 自身失败会放行动作。 - Claude Code 的 Hooks Reference覆盖 Session、Prompt、Tool、Permission、Subagent、Task、Compaction、Worktree、File 与 MCP 相关事件。官方还记录了 Command、HTTP、Prompt、Agent 和 MCP Tool 等 Handler 类型。
- Codex 的 Hooks 文档包含
PreToolUse、PermissionRequest、PostToolUse、SessionStart、SubagentStop和Stop等事件。多个匹配的 Command Hook 会并发运行;非托管 Command Hook 需要显式 Review 与 Trust。Plugin Hook 可以使用PLUGIN_ROOT与PLUGIN_DATA。
连大小写都是宿主契约的一部分:Cursor 使用 preToolUse,Claude Code 和 Codex 文档使用 PreToolUse。不能因为事件名称看起来一样,就直接复制配置。
把 Hook 称为“安全控制”以前,先弄清 Fail-open 与 Fail-closed
一个门禁至少有四种失败方式:
- Matcher 根本没有匹配;
- Hook 崩溃;
- Hook 超时;
- Hook 返回了无效数据。
其中任意情况发生后仍然放行动作,就是 Fail-open。对于 Telemetry 或 Formatter,这可能合理,因为可用性比强制更重要;对于密钥边界或生产写操作,通常不可接受。
每个 Hook 都要回答:
哪个事件会触发?
Matcher 实际覆盖哪些工具?
收到的准确 JSON 是什么?
什么输出可以阻断或改写?
超时、崩溃、输出错误时会怎样?
它是否运行在本地、IDE、Cloud、Subagent 和 Headless 模式?
谁可以修改或信任它?
日志和敏感信息会去哪里?Hook 会执行配置中的代码:安装 Plugin 就是一项信任决策
Plugin 内的 Hooks 和脚本属于可执行供应链内容。要像 Review 代码一样 Review 它们,而不是只读说明文字。
最低限度的控制包括:
- 固定或审查 Plugin 来源与版本;
- 脚本留在包内,并通过 Plugin Root 解析路径;
- 不在 Hook 输出、Transcript 或命令行中写入 Secret;
- MCP 与 Shell 身份使用最小权限;
- 限制执行时间与输出大小;
- 明确允许访问的网络目标;
- 记录决策,但不记录敏感 Payload;
- 测试拒绝、超时、错误输入和依赖缺失;
- 提供禁用与回滚路径。
Codex 对变更后的非托管 Command Hook 重新要求 Trust Review,揭示了一个重要事实:升级可执行配置,就等于审查一段新代码。
五、用最小正确机制承载需求
创建能力包以前,按这个顺序判断:
只对本次请求有效?
是 → Prompt
否
仓库里的每项任务都需要?
是 → Rule / AGENTS.md / CLAUDE.md
否
它是一项有明确用户目标的重复工作流?
是 → Skill
否
需要实时外部数据或受控外部动作?
是 → MCP / Connector(也可以由 Skill 调用)
无论模型如何选择,都必须在生命周期边界运行代码?
是 → Hook
多个机制是否需要统一安装、版本与分发?
是 → Plugin混合需求应该拆开。以 release-guard 为例:
| 需求 | 机制 | 原因 |
|---|---|---|
“本次发布是 v3.2.0,面向企业客户” | Prompt | 每次运行都不同 |
| “仓库使用 Changesets 和 pnpm” | Rule | 稳定仓库事实 |
| “收集证据、判断风险、输出结论” | Skill | 可复用工作流 |
| “读取当前 PR Checks 和 Approvals” | GitHub MCP / Connector | 实时、经过认证的数据 |
| “禁止 Agent 发布或创建 Release” | Pre-tool Hook + 真实权限 | 机械强制 |
| “把以上组件一起安装和升级” | Plugin | 分发与生命周期 |
六、先设计能力契约,再设计目录
本文 Plugin 的目标刻意保持狭窄:
准备并验证发版决策,绝不真正执行生产发布。
写 Manifest 以前,先定义契约。
输入
- 发版范围或目标版本;
- 仓库与目标环境;
- Git 变更证据,以及连接可用时的 GitHub 证据;
- 仓库发版政策;
- 可选的人工审批证据。
输出
- 结论:
READY、NOT_READY或NEEDS_REVIEW; - 通过与失败的检查项及证据;
- 迁移、兼容与回滚说明;
- 尚未解决的问题;
- 不产生生产变更。
禁止动作
- 创建或推送 Tag;
- 创建 GitHub Release;
- 发布 Package;
- 部署到生产;
- 降低分支、Registry 或环境保护。
依赖
- 必须提供
git; - GitHub MCP / Connector 是可选依赖,且本文工作流只需要 Read-only;
- 教程中的 Hook 运行时需要 Python 3;
- 每个宿主适配层要声明支持的产品界面。
这个契约比目录树更重要。它可以阻止 Plugin 不断膨胀为“所有发版自动化”。
七、可移植核心 + 轻量宿主适配层
不要强迫一个原生包不加修改地运行在所有宿主。应该维护一份语义核心,再提供小型适配层。
release-guard/
├── core/
│ ├── skills/
│ │ └── release-readiness/
│ │ ├── SKILL.md
│ │ ├── references/
│ │ │ └── decision-policy.md
│ │ └── scripts/
│ │ └── collect-local-evidence.sh
│ └── hooks/
│ └── guard_core.py
├── hosts/
│ ├── cursor/
│ │ ├── .cursor-plugin/plugin.json
│ │ └── hooks/hooks.json
│ ├── claude/
│ │ ├── .claude-plugin/plugin.json
│ │ └── hooks/hooks.json
│ └── codex/
│ ├── .codex-plugin/plugin.json
│ └── hooks/hooks.json
├── tests/
│ ├── skill-cases.yaml
│ └── hook-cases.json
└── README.md源码仓库可以这样组织,但发布产物必须经过组装,让每个宿主在 Plugin Root 看到自己需要的文件。可以用构建脚本把共享 skills/ 与 Hook Core 复制到三个输出目录。
第 1 步:编写共享 Skill
core/skills/release-readiness/SKILL.md:
---
name: release-readiness
description: >-
Assess whether a software release is ready from a version range, local Git
evidence, pull requests, and required checks. Use for release review, go/no-go
decisions, or release risk summaries. Do not use to publish or deploy.
---
# Assess release readiness
## Inputs
Require a release range or target version and the target environment. Ask when
either is missing. Read repository instructions before collecting evidence.
## Workflow
1. Collect local commits and changed paths without modifying the repository.
2. If an authorized GitHub read tool exists, collect linked PR checks, reviews,
and unresolved conversations. Otherwise label that evidence unavailable.
3. Read `references/decision-policy.md` and classify each required check.
4. Return `READY` only when every mandatory check has passing evidence.
5. Return `NOT_READY` for a failed mandatory check and `NEEDS_REVIEW` when
required evidence is unavailable or ambiguous.
6. Include evidence identifiers and recommended next actions.
## Safety
Do not create tags, releases, deployments, or package publications. Do not ask
for write credentials. Never convert missing evidence into a pass.Skill 负责封装判断,不应该塞入三个宿主的安装命令,也不能假设 GitHub 连接永远存在。
第 2 步:让 Hook Policy 与宿主协议解耦
core/hooks/guard_core.py 只保留纯判断函数:
import re
PUBLISH_PATTERNS = (
r"\bnpm\s+publish\b",
r"\bpnpm\s+publish\b",
r"\bgh\s+release\s+create\b",
r"\bgit\s+push\b[^\n]*\s--tags\b",
)
def denial_reason(command: str) -> str | None:
if any(re.search(pattern, command) for pattern in PUBLISH_PATTERNS):
return (
"release-guard prepares release evidence but does not publish. "
"Run the release-readiness Skill and use the approved human release path."
)
return None这段代码故意没有假装自己是一套完整 Shell Parser。测试集还必须覆盖引号、命令串联、Wrapper Script 和误报。对于高保证边界,应移除 Agent 身份的生产凭据,并在服务端或部署平台强制审批。
每个宿主适配器只做三件事:
- 读取宿主 Hook JSON;
- 提取 Command;
- 把
denial_reason翻译成该宿主文档规定的响应 Schema。
这样,宿主改变 Hook Wire Format 时,共享 Policy Test 不需要重写。
第 3 步:打包 Cursor 版本
最小 hosts/cursor/.cursor-plugin/plugin.json:
{
"name": "release-guard",
"version": "1.0.0",
"description": "Review release readiness and block direct publication",
"author": { "name": "Platform Engineering" }
}Cursor 会发现约定目录里的组件。它的 preToolUse 适配器返回官方文档中的扁平 Permission 结构:
{
"permission": "deny",
"user_message": "Direct publication is outside release-guard's boundary.",
"agent_message": "Prepare evidence and use the approved human release path."
}确认所有支持环境都有 Hook Runtime 和依赖后,再为这个门禁设置 failClosed: true。缺少 Python 的 Fail-closed Hook 可能阻断所有匹配命令;这比误发版安全,但仍然是一场运行事故。
本地测试:
ln -s /absolute/path/to/dist/cursor-release-guard \
~/.cursor/plugins/local/release-guardReload Cursor,确认 Rule 与 Skill 出现在 Customize,再分别执行允许和拒绝用例。
第 4 步:打包 Claude Code 版本
hosts/claude/.claude-plugin/plugin.json:
{
"name": "release-guard",
"version": "1.0.0",
"description": "Review release readiness and block direct publication",
"author": { "name": "Platform Engineering" }
}Claude Code 从 Plugin 的 skills/ 加载 Skills,从 hooks/hooks.json 加载 Hooks。Hook Adapter 可以按官方 hookSpecificOutput 格式返回 PreToolUse Deny。先直接测试组装后的目录:
claude --plugin-dir ./dist/claude-release-guard然后调用:
/release-guard:release-readiness v3.1.0..v3.2.0 for production迭代过程中用 /reload-plugins 加载变化。直接目录测试通过以后,再做 Marketplace。
第 5 步:打包 Codex 版本
hosts/codex/.codex-plugin/plugin.json 显式指向组件:
{
"name": "release-guard",
"version": "1.0.0",
"description": "Review release readiness and block direct publication",
"skills": "./skills/",
"hooks": "./hooks/hooks.json"
}Codex Plugin Hook 可以通过 PLUGIN_ROOT 读取包内文件,通过 PLUGIN_DATA 写入状态。不要把 Cache 写回已经安装的 Plugin 目录。PreToolUse Adapter 应返回官方 hookSpecificOutput.permissionDecision: "deny" 结构。
最快的初始化方式是:
$plugin-creator
Create a release-guard plugin with the release-readiness skill and a PreToolUse
hook. Add it to a personal marketplace for local testing. The hook must block
direct package publication, tag pushes, and GitHub Release creation.如果手工配置仓库 Marketplace,把 Catalog 放在 .agents/plugins/marketplace.json,让本地 source.path 指向组装后的 Plugin;重启桌面应用、安装 Plugin、审查 Hook Trust 提示,再在新任务中测试。Codex CLI 可以用 codex plugin marketplace add 添加来源,用 codex plugin marketplace list 检查来源。
八、把安装、授权、触发与成功当成不同状态
“Plugin 已安装”几乎不能证明什么。
已经安装
→ 在当前宿主启用
→ 本地依赖可用
→ Hook 已 Review / Trust
→ Connector 已认证
→ 当前身份拥有所需权限
→ Skill 对正确请求完成触发
→ 工作流产出了合格证据排错时逐层检查:
| 现象 | 可能层级 | 应检查的证据 |
|---|---|---|
| UI 中没有 Plugin | Marketplace / Source / Manifest | Catalog 来源、Manifest 路径、宿主支持 |
| Plugin 可见但 Skill 不见了 | 组件发现 | 组装目录、skills 路径、是否 Reload / 新 Session |
| Skill 运行但没有 GitHub 数据 | Connection / Auth | Connector 状态、MCP 健康、OAuth Scope |
| Hook 从不触发 | Event / Matcher / Surface | 事件名、工具名、本地与 Cloud 支持差异 |
| Hook 运行但动作仍被放行 | Output / Failure Policy | Exit Code、JSON Schema、Fail-open 行为 |
| 升级后没有变化 | Cache / Version / Session | Manifest Version、Marketplace Refresh、安装缓存、重启 |
| 流程跑完但结论不可靠 | Skill / Evaluation | 触发测试、证据覆盖、验收 Rubric |
这种拆分可以避免一个常见误区:Skill 没有触发,却通过扩大外部权限来“修复”。
九、像测试产品一样测试 Plugin
脚本 Unit Test 必不可少,但 Plugin 还有更多契约。
Skill 路由测试
| 类型 | 请求 | 期望行为 |
|---|---|---|
| 直接正例 | “检查 v3.1.0..v3.2.0 是否可以发版” | Skill 触发 |
| 间接正例 | “这个 Build 能上线吗?” | Skill 触发,并询问版本范围与环境 |
| 反例 | “写一份 Release Notes” | 不触发;可能由另一个 Skill 处理 |
| 边界 | “现在发布 v3.2.0” | 拒绝发布,并说明批准路径 |
Hook 契约测试
用保存的 Fixture 测试每个宿主 Adapter:
allowed: git log v3.1.0..v3.2.0
denied: npm publish
denied: gh release create v3.2.0
denied: git push origin --tags
ambiguous: bash ./scripts/release.sh
malformed: missing tool_input
timeout: adapter exceeds host limit
dependency: python3 unavailable模糊的 Wrapper Script 用例必须推动设计决策:解析脚本并接受残余风险、阻断已知 Release Wrapper,或者把真正边界移到服务端授权。不能悄悄把它标成“已经覆盖”。
跨宿主兼容矩阵
每个支持界面都要留下证据:
| 宿主 | 安装 | Skill 路由 | 允许工具 | 拒绝工具 | 缺失依赖 | 升级 | 卸载 |
|---|---|---|---|---|---|---|---|
| Cursor Desktop / CLI | ☐ | ☐ | ☐ | ☐ | ☐ | ☐ | ☐ |
| Claude Code Terminal / IDE | ☐ | ☐ | ☐ | ☐ | ☐ | ☐ | ☐ |
| Codex App / CLI | ☐ | ☐ | ☐ | ☐ | ☐ | ☐ | ☐ |
不能因为一个界面通过,就宣称支持整个产品家族。Cloud Agent、IDE Extension、Desktop App 与 CLI 可能加载不同组件。
端到端验收
一次合格测试应该留下可观察证据:
- 全新宿主能够发现并安装指定版本;
- Skill 对正例触发,对反例保持沉默;
- GitHub 证据不可用时返回
NEEDS_REVIEW,而不是编造 Pass; - Read-only 命令可以成功;
- 每种直接发布命令都被阻断,并收到可行动的原因;
- 升级后与回滚后都能通过同一组测试;
- 卸载后,不会留下仍在运行的 Hook 或失效的连接假设。
十、版本化并运营这项能力
团队 Plugin 需要像内部 Library 一样管理生命周期。
版本化的是行为契约,不只是 Manifest
可以采用 Semantic Version 的意图:
- Patch:保持触发范围与输出契约不变的文字、示例或实现修复;
- Minor:向后兼容的 Skill、Hook 或 Tool 新增;
- Major:触发范围变化、组件移除、新增必需权限、Hook 行为变化或不兼容 MCP Schema。
一个 Hook 开始拒绝过去允许的命令,即使只改了三行代码,也属于重要行为变化。
发布兼容性记录
每个版本至少记录:
- 支持的宿主、产品界面和最低版本;
- 打包的组件版本;
- 本地 Runtime 依赖;
- MCP Endpoint 与 OAuth Scope;
- Hook Event 与失败策略;
- 读取、传输和保存的数据;
- 迁移与回滚步骤;
- Owner 与支持渠道。
衡量结果,而不是安装量
有价值的健康指标包括:
| 指标 | 它揭示什么? |
|---|---|
| Skill 误触发与漏触发率 | 路由质量 |
| 必需证据覆盖率 | 工作流可靠性 |
| 按原因统计的 Hook 拒绝次数 | Policy 压力与误报 |
| Hook 失败/超时率 | 控制可用性 |
| 发版结论后的人工返工 | 输出实用性 |
| 版本采用率与回滚率 | 分发健康度 |
默认不要收集完整 Prompt 或 Tool Payload。Telemetry 自身也需要数据最小化与保留政策。
十一、常见反模式
1. Plugin 只是无关工具的压缩包
如果组件没有共享同一个用户目标、权限边界或生命周期,就应该拆开。方便安装不等于架构内聚。
2. Rules 与 Hook 各复制一份逻辑
Rule 或 Skill Safety 可以保留便于人理解的原因,但机械判断只应在一套可测试 Hook Policy 中实现。多份互相矛盾的副本一定会漂移。
3. 一个 Hook 变成第二个 Agent
生命周期 Hook 应该在严格时间预算内检查、决策、转换或记录。长时间探索性推理属于 Skill 或 Subagent,不应该在每次工具调用时发生。
4. 为“将来可能需要”申请最大权限
权限是产品契约的一部分。功能真正需要时再添加,解释数据流,并要求重新 Review。
5. 宿主差异泄漏进核心 Policy
如果 guard_core.py 知道三个 Manifest 路径和五种响应 Schema,说明 Adapter 边界已经失效。共享语义保持纯净,协议翻译保持轻薄。
6. 只测试安装
Plugin 可以安装得很完美,但 Skill 从不触发、Hook Fail-open,或者 MCP 身份缺少必要 Scope。必须测试完整状态链。
7. 更新没有回滚
保留上一份已知可用产物或不可变 Ref,特别是 Hook 可能阻断工作时。如果 Plugin 连修复所需的命令都拦住了,“向前修复”就不是方案。
十二、一张 Plugin 工程设计卡
实现前先填完:
Plugin 名称:
唯一用户结果:
非目标:
稳定仓库指导(Rules):
可复用工作流(Skills):
实时数据/动作(MCP / Connectors):
生命周期控制(Hooks):
资产或 UI:
支持的宿主与产品界面:
可移植核心:
宿主适配层:
必需权限:
会传出本机的数据:
Hook 失败模式:
Trust / Review 流程:
正向路由用例:
反向路由用例:
拒绝动作测试:
升级测试:
回滚测试:
Owner:
版本策略:
退役信号:
成功指标:如果“唯一用户结果”需要一整段话才能解释,这个包里可能塞了多个 Plugin。
结语:先工程化边界,再打包能力
Rules、Skills、MCP、Hooks 和 Plugins 不是一条“新机制淘汰旧机制”的升级路线。
它们解决不同的协调问题:
- Rules 让模型看到稳定约定;
- Skills 把专家判断变成按需工作流;
- MCP 用类型化、经过授权的能力连接实时系统;
- Hooks 在生命周期边界执行确定性控制;
- Plugins 让一组内聚能力可发现、可安装、可版本化、可运营。
最好的 Plugin 不是组件最多的 Plugin。它应该是满足目标所需的最小能力包,让另一个人在原作者不在场时,仍能完成安装、理解权限、获得预期结果、观察故障、升级并安全卸载。
跨 Agent 开发时,围绕可移植语义核心设计,同时诚实接受宿主契约差异:Agent Skills 开放格式能覆盖的部分就移植 Skill;Manifest、Hook Schema、调用方式和分发渠道则显式适配。少量诚实的重复,比假装三个运行时属于同一个平台更便宜。
权威资料
本文中的产品行为与可用性已于 2026 年 8 月 6 日核验。
- Cursor Docs:Plugins
- Cursor Docs:Rules
- Cursor Docs:Agent Skills
- Cursor Docs:Hooks
- Claude Code Docs:Create plugins
- Claude Code Docs:Plugins reference
- Claude Code Docs:Create and distribute a plugin marketplace
- Claude Code Docs:Hooks reference
- Claude Code Docs:How Claude remembers your project
- OpenAI Developers:Plugin architecture
- OpenAI Developers:Package your plugin
- OpenAI:Build plugins
- OpenAI:Hooks
- OpenAI:Plugins
- Agent Skills 开放规范
- Model Context Protocol 规范