首页
/ ECC 插件清单约束指南:Claude Code plugin.json 验证器的未公开规则与正确姿势

ECC 插件清单约束指南:Claude Code plugin.json 验证器的未公开规则与正确姿势

2026-09-04 11:05:16作者:劳婵绚Shirley

本文围绕 ECC 仓库中的 PLUGIN_SCHEMA_NOTES.md 展开,系统讲解 Claude Code 插件清单(plugin.json)验证器那些未在公开 schema 文档中记载、但实际强制执行的约束:必填的 version 字段、必须为数组的组件字段、严禁添加的 agents/hooks 字段、用于 MCP 隔离的空 mcpServers 声明等。读完本文,你能够安全地修改、校验 ECC 或任何 Claude Code 插件的清单文件,避开「本地验证通过、安装时报 Invalid input」这类隐蔽故障,并理解 ECC 如何用回归测试把这些规则固化下来。

背景:一个「严格且有主见」的验证器

Claude Code 插件清单验证器的典型故障模式是:

清单文件看起来完全合理,但验证器却拒绝它,只抛出一个模糊的错误,例如 agents: Invalid input

这类问题很难排查,因为公开 schema 参考并没有完整描述验证器的全部行为。ECC 仓库把基于真实安装失败、验证器实际行为、以及和已知可用插件对比得出的约束记录在 PLUGIN_SCHEMA_NOTES.md 中,目的正是「防止静默破坏和重复回归」。该文档的定位很明确:如果你要编辑 plugin.json,先读这份笔记

必填字段:version

version 字段是验证器的强制要求,即使某些官方示例里省略了它。缺失时,安装可能失败在 marketplace 安装阶段或 CLI 校验阶段。

{
  "version": "1.1.0"
}

从仓库自身的 schema 可以进一步看出取值约束:plugin.schema.jsonversion 的 pattern 为 ^[0-9]+\.[0-9]+\.[0-9]+(?:-[0-9A-Za-z.-]+)?$,即标准 SemVer(可选带预发布后缀)。当前 ECC 的实际清单中 version"2.2.1",与 marketplace.json 中声明的版本保持一致——两处版本号同步也是仓库测试所约束的。

字段形状规则:commands / skills / hooks 必须永远是数组

以下字段必须始终是数组

  • commands
  • skills
  • hooks(如果存在)

即使只有一个条目,字符串值也不被接受。这条规则一致地适用于所有组件路径字段。仓库的 plugin.json 遵循了这一点:

{
  "name": "ecc",
  "version": "2.2.1",
  "mcpServers": {},
  "skills": ["./skills/"],
  "commands": ["./commands/"]
}

对应的回归测试位于 tests/plugin-manifest.test.jsclaude plugin.json commands is an array),确保 commands 字段一旦退化为字符串就会被测试捕获。

路径解析规则

  • commandsskills 接受目录路径,但仅当它们被包裹在数组中
  • 显式文件路径最安全、也最具前瞻性(most future-proof)。

这与「避免依赖推断路径」的防反模式列表一脉相承:能用显式路径就不要让验证器去猜。

Agent 的 tools frontmatter:使用标量,而不是数组

上一条数组规则只适用于 plugin.json不适用于 agent 的 Markdown frontmatter。Claude Code 的 agent 文件使用逗号分隔的标量来声明工具白名单:

tools: Read, Glob, Grep

不要写成 YAML 序列,例如 tools: [Read, Glob, Grep]。省略 tools 字段会让 agent 获得所有工具的访问权限,但 ECC 的 agent 都显式声明白名单,且仓库验证器要求该字段存在。

仓库中的 agent 文件与这一规则完全一致,例如 agents/code-reviewer.md

---
name: code-reviewer
description: Expert code review specialist. ...
tools: Read, Grep, Glob, Bash
model: sonnet
---

这里 tools: Read, Grep, Glob, Bash 正是标准的逗号分隔标量写法,68 个 agent 文件均遵循同样的形状。

agents 字段:不要添加

警告:不要在 plugin.json 中添加 "agents" 字段。Claude Code 插件验证器会完全拒绝它。

agents 不是 Claude Code 插件清单 schema 的一部分。它的任何形式——字符串路径、路径数组、目录数组——都会导致校验错误:

agents: Invalid input

agents/ 目录下的 agent .md 文件会按约定自动发现(与 hooks 的机制类似),不需要在清单中声明。

历史沿革:本仓库曾把 agents 以文件路径数组的形式显式列入 plugin.json。这种做法通过了仓库自己的 schema 校验,却通不过 Claude Code 实际验证器——因为后者根本不认识这个字段。该字段已在 PR #1459 中移除。

hooks 字段:不要添加(有回归测试强制)

警告:不要在 plugin.json 中添加 "hooks" 字段。这一条由回归测试强制保护。

Claude Code v2.1+ 会按约定自动加载任何已安装插件的 hooks/hooks.json。如果你同时在 plugin.json 里再声明一次,就会触发重复加载错误:

Duplicate hooks file detected: ./hooks/hooks.json resolves to already-loaded file.
The standard hooks/hooks.json is loaded automatically, so manifest.hooks should
only reference additional hook files.

反复横跳的历史

这条规则在仓库中造成了多轮「修复/回滚」循环:

Commit 动作 触发原因
22ad036 添加 hooks 用户报告 "hooks not loading"
a7bc5f2 移除 hooks 用户报告 "duplicate hooks error"(#52)
779085e 添加 hooks 用户报告 "agents not loading"(#88)
e3a1306 移除 hooks 用户报告 "duplicate hooks error"(#103)

根因:Claude Code CLI 在不同版本间改变了行为——

  • v2.1 之前:需要在清单中显式声明 hooks
  • v2.1 及以后:按约定自动加载,重复声明会直接报错。

当前规则:由测试固化

这个「不要再加回去」的规则被写进了两处回归测试:

  • tests/hooks/hooks.test.js 中的 plugin.json does NOT have explicit hooks declaration,断言 plugin.json 不含 hooks 字段;
  • tests/plugin-manifest.test.js 中的同名测试,直接断言 !('hooks' in claudePlugin),并注明「Claude Code v2.1+ 按约定自动加载 hooks/hooks.json」。

注意边界:如果你在添加的是额外的 hook 文件(不是 hooks/hooks.json 本身),那些可以在清单中声明;但标准的 hooks/hooks.json 绝不能声明。ECC 的 hook 入口正是 hooks/hooks.json,配合 hooks/codex-hooks.json 支持 Codex 侧的安装。

mcpServers 字段:保留显式的空对象(MCP 隔离开关)

ECC 在仓库根目录保留 .mcp.json 用于 Codex 插件安装和手工 MCP 配置,此外还有更完整的 mcp-configs/mcp-servers.json(包含 GitHub、Jira、Supabase、firecrawl 等多个 server 定义)。

但 Claude Code 也会按约定自动发现插件根目录的 .mcp.json,这会把同样的 MCP server 打包进 Claude 插件安装。因此 plugin.json 中刻意保留了这个显式空对象:

{
  "mcpServers": {}
}

这个 opt-out 的作用是阻止 Claude 插件安装自动加载 ECC 根目录的 MCP 定义。为什么必须这样做?因为 Claude 插件 slug 虽然已刻意取短名(ecc),但遗留安装和严格的 provider 网关在更长的插件标识符上会生成超长 MCP 工具名并直接拒绝。例如形如 mcp__plugin_everything-claude-code_github__create_pull_request_review 的工具名超过 64 个字符,会被严格的 OpenAI 兼容网关拒收。

这一行为被 tests/plugin-manifest.test.js 精确验证:测试先断言该历史超长工具名确实超过 64 字符,再断言 mcpServers 键必须显式存在且严格等于 {}Object.prototype.hasOwnProperty + deepStrictEqual),保证未来重构不会无意移除这个 opt-out。想要使用打包 MCP server 的用户,应手动从 .mcp.jsonmcp-configs/mcp-servers.json 配置。

验证器行为特征小结

  • claude plugin validate 比部分 marketplace 预览更严格;
  • 路径有歧义时,本地验证可能通过、安装时却失败;
  • 错误信息往往很笼统(Invalid input),不指示根因;
  • 跨平台安装(尤其是 Windows)对路径假设更不宽容。

一句话心态:假定验证器是敌对且字面化的(Assume the validator is hostile and literal)。

已知反模式清单

以下写法「看起来正确」但会被拒绝:

  • 用字符串值代替数组;
  • 以任何形式添加 "agents" —— 不是被识别的清单字段,会报 Invalid input
  • 缺少 version
  • 依赖推断路径(inferred paths);
  • 假设 marketplace 行为与本地验证一致;
  • 添加 "hooks": "./hooks/hooks.json" —— 该文件已被约定自动加载,会触发重复错误;
  • 移除 "mcpServers": {} —— 会重新启用 Claude 插件安装的根目录 .mcp.json 自动发现,可能产生超长的 MCP 工具名。

原则:避免取巧,保持显式(Avoid cleverness. Be explicit.)。

最小可用示例与 ECC 实际清单对照

文档给出的「已知可用最小示例」:

{
  "version": "1.1.0",
  "commands": ["./commands/"],
  "skills": ["./skills/"]
}

该结构已经过 Claude 插件验证器验证。注意其中既没有 "hooks" 字段,也没有 "agents" 字段——两者都按约定自动加载,显式添加任何一个都会导致错误。

ECC 实际发布的 plugin.json 在此骨架上额外携带了元数据(descriptionauthorhomepagerepositorylicensekeywords)和两个 userConfig 偏好项:hooks_enabled(布尔,默认 true,控制是否启用本地 hook 自动化)和 hook_profile(字符串,取 minimal/standard/strict,非法值安全回退到 standard)。tests/plugin-manifest.test.js 专门断言 userConfig 暴露这两个 key,且字段形状固定为 type/title/description/default 四项——注释说明 Claude 的 userConfig 不支持 enum,所以 hook_profile 只能声明为 string 并在运行时做回退。

贡献者检查清单

在提交任何触碰 plugin.json 的变更之前:

  1. 确保所有组件字段都是数组;
  2. 包含 version
  3. 不要添加 agentshooks 字段(两者都按约定自动加载);
  4. 除非有意改变 Claude 插件的 MCP 打包行为,否则保留 "mcpServers": {}
  5. 运行验证:
claude plugin validate .claude-plugin/plugin.json

如有疑问,宁要冗长、不要方便(choose verbosity over convenience)。

为什么这份文档值得长期维护

ECC 是一个被广泛 fork、并常被当作参考实现的仓库,把验证器的「怪癖」文档化可以:阻止问题反复出现、降低贡献者的挫败感、并在生态演进时保住插件的稳定性。文档的最后一句规则值得记住:如果验证器本身变了,先更新这份文档——它和 tests/plugin-manifest.test.jstests/hooks/hooks.test.js 中的断言一起,构成了「文档 + 测试」双层防线,防止上述任何一条约束在后续版本中被无意破坏。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
528
590
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
904
1.82 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
889
5.78 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.52 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.33 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
983
503
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384