integrations/ 缺失或过期时到底发生了什么
排查 agency-agents 的安装问题,第一件要想明白的事是:integrations/ 这个目录不是你写的东西,是脚本生成的东西。
仓库的 divisions.json 在 _note 里明确把 integrations/ 从 division 列表里排除掉了,理由写得很直白——它是 scripts/convert.sh 写出的每工具转换产物,不是源 agent。同样被排除的还有 strategy/、examples/、scripts/,这四个目录在 scripts/check-divisions.sh 里通过 NON_DIVISION_DIRS 统一过滤。
而 install.sh 的头部注释说得也很清楚:它从 integrations/ 读取已转换的文件,拷到每个工具对应的配置目录;如果 integrations/ 缺失或过期,先跑 scripts/convert.sh。
所以完整链路是三段:
division 目录里的源 agent markdown
→ scripts/convert.sh 渲染成各工具格式
→ integrations/(产物)
→ scripts/install.sh 拷贝到目标配置目录
按脚本自己写的语义推,中间那一段断了或者旧了,最后一段的输入依然是 integrations/ 里那份旧产物——拷贝这个动作本身没有任何理由失败。这就是这类问题最难受的地方:不是报错,是不对劲。
一、表象长什么样
按脚本的语义推,integrations/ 缺失或过期会表现成这几类互不相同的现象,值得先分清楚:
- 目标目录里什么都没有。比如你只想装 Claude Code,跑完之后
~/.claude/agents/里没有预期的{slug}.md。 - 目标目录里有东西,但内容是旧的。你刚改了某个 division 下的源 markdown,改的是
description或者某个##章节,装过去的还是改之前的版本。 - 某个工具一份产物都没有,其它工具却正常。
tools.json里一共 16 种工具,每种绑定一个format;某个format的渲染没跑到,只会影响用这个format的工具。 - 装完像没装。工具能识别到文件,但行为上看不出区别。
第四类要单独标记一下——它大概率不是 integrations/ 的问题,后面第五节会讲。前三类才是本文的正主。
二、怎么确认真的是这个问题
不要靠猜,仓库给了两个专门用来「先看不做」的开关。
第一步,先把安装计划打出来,不写盘:
./scripts/install.sh --dry-run
--dry-run 在 USAGE 段里的定义就是只打印计划、不写任何东西。在往 ~/.claude/agents/ 这类共享目录写 200 多个文件之前先跑一次,这是这个仓库对新手最有价值的一个开关。花名册规模是 255 个带 frontmatter 的 agent、17 个 division,全装是什么量级心里要有数。
第二步,把脚本认得的清单列出来:
./scripts/install.sh --list tools
./scripts/install.sh --list agents
--list [tools|teams|agents] 的语义是列出后退出。如果你要装的工具压根不在 --list tools 的输出里,那问题不在 integrations/,在别处(见第五节)。
第三步,直接看产物目录在不在、覆盖到哪。integrations/ 是普通目录,ls 一下就知道有没有、有哪几个工具的子集。这一步是常识性检查,不是脚本功能。
第四步,检查自己有没有加 --no-convert。install.sh 默认会在集成文件缺失时自动调 convert.sh,--no-convert 正是用来关掉这个自动行为的。如果你的命令里(或者你抄来的某个脚本里)带了这个开关,那么「缺失就自动补」这条兜底就没了。
第五步,判断「过期」。这一点要说实话:脚本注释里写的是「缺失或过期先跑 convert」,但自动 convert 的触发条件,注释给的表述是集成文件缺失时。也就是说,源 markdown 改了、产物还在但内容旧了,这种「过期」是否会被自动识别,不要凭想当然断言——比较源文件与产物文件的修改时间是通用做法(ls -l、git status 都能看),不是这个仓库提供的功能。稳妥的判断办法是:只要你动过源 agent markdown,就当产物已经过期。
三、脚本语义给出的处置
处置一:显式重跑转换。 链路里断的是中间那段,就补中间那段:
./scripts/convert.sh
./scripts/install.sh --dry-run
先转换,再用 --dry-run 看计划,确认无误后再真装。
处置二:别关掉自动兜底。 把命令里的 --no-convert 去掉,让 install.sh 在集成文件缺失时自己去调 convert.sh。--no-convert 的适用场景是你明确知道产物是新的、不想让它重复劳动,而不是常态。
处置三:收窄范围再装。 一次性把 255 个 agent 塞进全局配置目录是有代价的——上下文占用、工具启动时的加载、命名冲突都要算进去。仓库给了四个选择器,可以自由组合,全空才等于全装:
| 参数 | 含义 |
|---|---|
--tool <a,b> | 只装这些工具 |
--division <a,b> | 只装这些 division |
--agent <slug,slug> | 只装指定 agent |
--agents-file <path> | 从文件读 agent 列表,每行一个 slug 或名字,支持 # 注释 |
排查阶段尤其建议先用 --tool 锁一个工具、--division 锁一个目录,把变量降到最少。组合起来大致是这个样子:
./scripts/install.sh --tool claude-code --division engineering --dry-run
以上为按官方参数语义组合的示例,未逐项实测,以官方文档与 --help 的实际输出为准。
处置四:路径不对就覆盖路径。 install.sh 支持 --path <dir> 覆盖安装目录(单一目标),也在硬编码默认值之前检查一批环境变量,包括 CLAUDE_CONFIG_DIR、CURSOR_RULES_DIR、GEMINI_AGENTS_DIR、CODEX_AGENTS_DIR、OPENCODE_AGENTS_DIR、OPENCLAW_DIR、QWEN_AGENTS_DIR、COPILOT_AGENT_DIR、OSAURUS_SKILLS_DIR、HERMES_HOME、HERMES_PLUGIN_DIR、VIBE_HOME。这一条反过来也是排查线索:你以为文件没生成,可能只是被环境变量指到别处去了。
四、处置完怎么验证
先用 --dry-run 复核一遍计划,这是成本最低的一步。
再按 installKind 决定你该去数几个文件。 tools.json 的 _note 把 installKind 定义为安装机制,并说明它是上游真相、对每个消费方都成立。三种取值对应三种完全不同的验收预期:
per-agent:每个 agent 渲染出一个文件或一个目录,装 255 个 agent 就是 255 份产物;roster:所有 agent 合并成一个文件,Aider 的CONVENTIONS.md和 Windsurf 的.windsurfrules属于这一类;plugin:一个构建出来的产物,不能按 agent 渲染成字符串,在所有消费方都只能走 CLI,Hermes 是唯一一个。
拿着 per-agent 的预期去验收 roster 工具,你会一直觉得「怎么只转出来一个文件」。
如果你改的是源 markdown,验证要往前挪一步。 scripts/lint-agents.sh 会检查 frontmatter 是否存在、必填字段 name / description / color 是否齐全(缺任意一项报 ERROR),推荐章节缺失和正文词数不足 50 只报 WARN。改完源文件先 lint 一遍再 convert,比转换完再回头找问题省事。要提醒的是,lint 检查的是结构,不评估提示词写得好不好用。
如果你怀疑是仓库自身配置漂移,仓库有一套自检脚本可以用:check-divisions.sh 校验 division 列表与磁盘目录、convert.sh 与 lint-agents.sh 里的 AGENT_DIRS 数组、工作流路径过滤器是否一致;check-tools.sh 校验 tools.json 与 install.sh 的 ALL_TOOLS、convert.sh 的转换器集合是否一致,任何条目缺 id、label、kebab、format、installKind、dest 都会失败。这两个脚本失败,说明问题比「产物过期」深一层。
五、什么情况说明不是这个原因
这一节是本文最该看的部分。下面这些现象很容易被误判成「转换没跑」,其实原因完全在别处,重跑一百遍 convert.sh 也不会变。
一,Cursor 装完像没装。 convert.sh 里 cursor-mdc 格式的 frontmatter 是这样写的:
---
description: ${description}
globs: ""
alwaysApply: false
---
${body}
alwaysApply: false 和 globs: "" 是写死的。也就是说,转换出来的 Cursor 规则默认不会自动生效,需要在 Cursor 里按需引用。这是设计如此,不是产物过期。
二,Aider 或 Windsurf 只出现一个文件。 那是 installKind: roster 的产物形态——所有 agent 合并成一个 CONVENTIONS.md 或 .windsurfrules。同理,「为什么 Aider 里没法只装某一个 agent」这个问题的答案也在这里,跟转换没关系。
三,Hermes 那边找不到可读的 markdown。 它的 installKind 是 plugin,产物不能按 agent 渲染成字符串,只能走 CLI。
四,文件确实生成了,但你在错的目录里找。 install.sh 的注释里,opencode、cursor、aider、windsurf 这四个写的是当前目录(.opencode/agents/、.cursor/rules/、CONVENTIONS.md、.windsurfrules),其余多为家目录(~/.claude/agents/、~/.codex/agents/、~/.gemini/agents/ 等)。这个差别决定了你是给某个项目装还是给整个账户装。另外要注意,tools.json 里 opencode 的用户级路径是 .config/opencode/agents/{slug}.md,与注释里的当前目录 .opencode/agents/ 不是同一个位置,它们分别对应不同 scope——要断言某个具体路径,回源文件按当前 scope 现查,别类推。
五,路径被环境变量改过。 上一节列的那批变量在硬编码默认值之前被检查,某个 shell 配置里悄悄设过一次,你就会在默认位置找不到东西。
六,lint 报「missing frontmatter ---」,可文件开头明明就是 ---。 这是 CRLF 行尾。lint-agents.sh 的第 0 道检查专门拒绝 CRLF,源码注释解释了原因:行尾多一个 \r 会让后面的 frontmatter 检查报出这种令人困惑的信息。仓库标准是 LF,见 .gitattributes。Windows 上编辑源文件特别容易踩。
七,你要的工具压根不在这 16 种里。 那不是转换问题,是覆盖面问题。tools.json 的 _note 还有一句要如实带出:渲染器覆盖面是消费方自己的事(由 format 推导),目录本身不携带任何 app 发布状态。
八,Windows 上没在对的 shell 里跑。 install.sh 注释写明的平台支持是 Linux、macOS(需要 bash 3.2+)、Windows Git Bash / WSL。在 PowerShell 或 cmd 里直接调这些 .sh 脚本,失败原因跟 integrations/ 无关。
最后补一个理解上的着力点:tools.json 的 _note 说明了 format 的契约含义——同一个 format 名保证渲染出字节级相同的输出。这就是 claude-code 与 copilot 都用 identity、osaurus 与 antigravity 都用 skill-md 的原因。所以当你发现 Claude Code 的产物正常、Copilot 的不正常时,可以合理怀疑问题不在渲染环节,而在拷贝落点或目录权限那一侧——它们本该是同一份字节。
顺带说一句 --link:它的语义是用符号链接代替拷贝,改动会自动传播。但 install.sh 的输入始终是 integrations/,所以链接的另一端仍在这条链路上;源 agent markdown 改了,该重跑的 convert.sh 一次也少不了。
延伸阅读
本文依据 agency-agents 官方仓库(github.com/msitarzewski/agency-agents)的 README、
tools.json、divisions.json、scripts/ 下的安装与校验脚本整理,核对日 2026-08-09。
本文内容为仓库源码与文档口径,我们没有安装或运行过其中任何 agent。
目录、脚本与安装路径随上游更新而变动,请以仓库最新内容与 ./scripts/install.sh --help 的实际输出为准。