runbook 里的 slug 解析不到 agent 文件时怎么查
agency-agents 仓库里有一层东西是纯文本的团队配置:strategy/runbooks.json。它按场景把一组 agent 打包成 roster,runbooks.json 的 _note 说明了这份文件的用途——让上层应用把一个 runbook 变成「一键部署一个团队」:读 roster、把每个 slug 映射到目录里的 agent、然后整组安装。
映射这一步一旦断了,就是本文要讲的现象。
一、现象长什么样
典型有两种表现。一种是仓库自带的一致性脚本 scripts/check-runbooks.sh 报出问题——它守的就是「runbook 里引用的每个 slug 必须能解析到真实存在的 agent 文件」这一条。另一种是你手工照着某个 runbook 的名单往下装,把名单里的条目喂给安装脚本的 --agent 选择器,结果某几个条目对不上任何东西。
两种表现的内核是同一个:你手上的这个字符串,和磁盘上的 agent 文件对不上。
需要先划清一件事:check-runbooks.sh 这道门管的是「解析得到文件」。文件本身合不合规——有没有 frontmatter、name / description / color 三个必填字段齐不齐、行尾是不是 LF——那是 scripts/lint-agents.sh 那一套五道检查的职责。两道门解决两个问题,别指望其中一道替另一道兜底。
二、怎么确认是这个问题:三个可执行的判定动作
动作一,先把当前仓库真正认识的 agent 列出来。 安装脚本有一个列完就退出的开关:
./scripts/install.sh --list agents
--list 接受 tools、teams、agents 三种取值,列出后即退出,不写任何文件。你要找的那个字符串在不在这份清单里,一眼就有答案。在这里都找不到,说明问题在仓库这一侧,不是你的命令写错了。
动作二,用 --dry-run 走一遍完整的安装计划。 这是这个仓库对新手最有价值的开关:把计划打印出来但不落盘。
./scripts/install.sh --agent project-manager-senior --tool claude-code --dry-run
以上为按官方参数语义组合的示例,未逐项实测,以官方文档与 ./scripts/install.sh --help 的实际输出为准。它的价值在于,往 ~/.claude/agents/ 这类共享目录写上百个文件之前,你能先看一眼到底要写什么、写到哪。slug 对不上时,这一步就会暴露出来,而且什么都没弄脏。
动作三,跑仓库自己的一致性脚本。
./scripts/check-runbooks.sh
它是 CI 那一组自检脚本里专门管 runbook 的一支,和 check-divisions.sh(division 列表与磁盘、脚本数组、CI 路径过滤器保持一致)、check-tools.sh(tools.json 与 install.sh 的 ALL_TOOLS、convert.sh 的转换器集合保持一致)是同一个思路:把「配置漂移」当成明确的敌人。
Windows 上有个前置条件容易踩:这些都是 bash 脚本。install.sh 的平台注释写的是 Linux、macOS(需要 bash 3.2+)、Windows Git Bash / WSL。在 PowerShell 或 cmd 里直接敲,报的错和 slug 没有半点关系。
三、源码语义给出的处置
runbooks.json 的 _note 把规则写得很直白:agents[] 里的条目是 slug——agent .md 文件的文件名主干(corpus id)。
engineering/engineering-frontend-developer.md → engineering-frontend-developer
specialized/agents-orchestrator.md → agents-orchestrator
_note 还特别提醒了两点:文件名主干并不总是带 division 前缀;而显示名带前缀、会漂移。所以 roster 一律引用 slug——slug 抗改名、可测试。
这两句提醒基本覆盖了实际会翻车的全部情形:
偏差一:拿显示名当 slug 用。 花名册里有一个 agent 显示名是 Senior Project Manager,它的 slug 是 project-manager-senior。词序和显示名不一样,直接把显示名转成小写连字符是推不出来的。
偏差二:自己给 slug 补 division 前缀。 project-management 这个 division 下有七个 agent,其中六个的 slug 确实是 project-management- 开头(比如 project-management-studio-producer),第七个偏偏就是上面那个 project-manager-senior。再看 specialized:这个 division 有五十七个 agent,带 specialized- 前缀的只有十五个(比如 specialized-mcp-builder、specialized-codebase-archaeologist),剩下四十二个一个前缀都不带——agents-orchestrator、business-strategist、language-translator 都在这里。同一个目录下两种形态并存,前缀是文件名碰巧长成那样,不是规则。
偏差三:从编排文档里抄名字。 NEXUS 的激活提示词、七个 playbook、四份场景说明文档,正文里写的都是给人看的显示名——Trend Researcher、Evidence Collector、Studio Producer。那些是提示词文本,不是标识符。要 slug,回 runbooks.json 或花名册导出去核对,别从散文里反推。
偏差四:在不是 division 的目录里找文件。 divisions.json 的 _note 明确列了几个顶层目录不算 division:integrations/ 是 convert.sh 写出的每工具转换产物,不是源 agent;strategy/ 放 playbook 和 runbook,没有 agent frontmatter;examples/、scripts/ 同样被排除。check-divisions.sh 里用 NON_DIVISION_DIRS 排掉它们。顺带一个常被搞混的数字:仓库里 markdown 文件总数约 316,而带 frontmatter 的 agent 是 255 个,分布在 17 个 division,差额就是这些非 agent 文件。别拿 316 当 agent 数,也别在 integrations/ 里找源文件。
对应的处置方向就三条:拼错了就照文件名主干改回来;文件确实不在(改过名、还没提交、不在本次浅克隆里)就补文件或修 runbook 里的引用;找错目录就换目录。反过来说,如果你在自己项目里做类似的跨文件引用,这套设计值得直接照搬——引用稳定 id,不要引用展示名。
四、处置后怎么验证
按顺序过三道,别只过一道:
- 重跑
./scripts/check-runbooks.sh,让守 slug 解析的那道门自己说话,以脚本实际输出为准。 - 再跑一次
./scripts/install.sh --list agents,确认改后的字符串确实出现在清单里——这一步验的是「安装脚本认识它」,和上一步的口径不完全重合。 - 如果这次动作里新建或改名了 agent 文件,补跑
./scripts/lint-agents.sh。它有五道检查,其中三道是 ERROR 级:拒绝 CRLF 行尾、frontmatter 分隔符必须存在、name/description/color三个必填字段必须齐全;推荐章节缺失和正文词数少于 50 只是 WARN,不会让检查失败。
第三步在 Windows 上尤其别跳过。lint-agents.sh 拒绝 CRLF 是有原因的,源码注释解释得很清楚:行尾多一个 \r,会让后面的 frontmatter 检查报出令人困惑的「missing frontmatter ---」,可文件开头明明就是 ---。Git 的行尾转换在 Windows 上默认就可能把文件变成这样,遇到这种自相矛盾的报错,先怀疑行尾。
如果这次还新建了 division 目录,divisions.json 的 _note 给了固定顺序:建目录 → 在 divisions.json 加条目 → 跑 scripts/check-divisions.sh → 按它的报错去更新它指向的地方。别跳步,脚本会告诉你还有哪几处没同步。
五、什么情况说明不是这个原因
这一节是排查文章相对「报错大全」的真正增量。下面几种情形看着像 slug 解析失败,其实病根完全不在这里,按 slug 去改是白费功夫:
你在错的目录里找产物。 install.sh 的注释里,落点分两类:claude-code、codex、gemini-cli、copilot、qwen、zcode、osaurus、openclaw、hermes、vibe、antigravity 多在家目录,而 opencode、cursor、aider、windsurf 写的是当前目录。给某个项目装完,跑到家目录去找,当然找不到;反过来也一样。tools.json 里部分工具还有 user 与 project 两套 dest 模板,比如 Claude Code 的两者都是 .claude/agents/{slug}.md,区别只在落家目录还是当前项目目录。要断言某个具体路径,回 tools.json 现查当前 scope,不要类推。
这个工具压根不按 agent 出文件。 tools.json 把 installKind 定义为安装机制,一共三种:per-agent 是每个 agent 一份产物;roster 是所有 agent 合并成一个文件,Aider 的 CONVENTIONS.md 和 Windsurf 的 .windsurfrules 就是这一类;plugin 是构建出来的产物,不能按 agent 渲染成字符串,只能走 CLI,十六种工具里 Hermes 是唯一一个。你在 Aider 那边按 slug 找单个文件,找不到是必然的,跟 slug 写没写对无关。
装是装进去了,但工具里像没装。 Cursor 那条转换路径里,.mdc 的 frontmatter 是写死的 globs: "" 和 alwaysApply: false——转换出来的规则默认不自动生效,需要在 Cursor 里按需引用。这个现象很容易被误判成「文件没落进去」,但它是转换规则本身决定的。
integrations/ 缺失或者过期。 链路是「源 agent markdown → convert.sh 渲染成各工具格式 → integrations/ → install.sh 拷到目标目录」。install.sh 从 integrations/ 读已转换的文件;集成文件缺失时它默认会自动调 convert.sh,除非你加了 --no-convert。加了这个开关又碰上产物没生成,报出来的问题跟 slug 无关。
你找的东西在 strategy/ 里,但那里没有可安装的 agent。 divisions.json 的 _note 原话是 strategy/ 存放的是编排方法论,不是可安装的 agent。NEXUS 那套东西——三种激活模式、Phase 0 到 Phase 6 七个阶段、四份场景 runbook——是写在 markdown 里的方法论,不是一个可执行的调度器,没有任何代码在强制推进阶段或拦截质量门。它靠提示词让模型自己按阶段走。想在 strategy/ 下装出一个 agent,方向从一开始就是错的。
最后提一句 runbook 本身的设计。四份场景 runbook 里,incident-response 走的是 NEXUS-Micro,它的 roster 分成 always(6 个,含 support-infrastructure-maintainer、engineering-devops-automator、engineering-backend-architect、engineering-frontend-developer 等)和 post-fix(4 个:testing-evidence-collector、testing-api-tester、testing-workflow-optimizer、product-sprint-prioritizer)两组——把取证、回测、流程优化、重排优先级单独放在修复之后。这个「修完不算完」的结构,恰好也是排查 slug 问题时该有的态度:改对一个字符串只是修复,回头把 check-runbooks.sh 和 lint 补跑一遍,才算收尾。
另外,一次性把 255 个 agent 装进全局配置目录是有代价的——上下文占用、工具启动时的加载、命名冲突都可能找上门。用 --division 或 --agent 收窄安装范围是更稳的做法。具体影响有多大我们没有测过,不给数字。
延伸阅读
本文依据 agency-agents 官方仓库(github.com/msitarzewski/agency-agents)的 README、
tools.json、divisions.json、strategy/runbooks.json 与 scripts/ 下的安装与校验脚本整理,核对日 2026-08-09。
本文内容为仓库源码与文档口径,我们没有安装或运行过其中任何 agent,也没有跑过文中提到的任何脚本。
目录、脚本与安装路径随上游更新而变动,请以仓库最新内容与 ./scripts/install.sh --help 的实际输出为准。