agency-agents 的 agent 文件格式:name/description/color 是必填,emoji/vibe 不是
如果你打算往 agency-agents 里加一个自己的 agent,或者把它的某个 agent 改成贴合自己团队的版本,第一个要搞清楚的问题不是「提示词怎么写才好」,而是「哪些东西是格式硬要求,哪些只是惯例」。这两类东西混在一份 markdown 里,肉眼看起来长得一模一样,但改错了的后果完全不同:一类会让仓库的检查脚本直接报 ERROR,另一类只是少一条 WARN。
这篇就把这条线划清楚。所有结论都来自仓库源码本身——scripts/lint-agents.sh、scripts/check-agent-originality.sh、divisions.json,以及 engineering/engineering-ai-engineer.md 这个样例文件。我们没有运行过其中任何一个脚本,下面说的全是脚本里写了什么,不是脚本跑起来是什么样。
先看一个 agent 文件长什么样
agency-agents 本质上就是一批 markdown:截至 2026-08-09 的仓库快照里,带 frontmatter 的 agent markdown 共 255 个,分布在 17 个 division。样例 engineering/engineering-ai-engineer.md 的开头是这样:
---
name: AI Engineer
description: Expert AI/ML engineer specializing in machine learning model development, deployment, and integration into production systems. ...
color: blue
emoji: 🤖
vibe: Turns ML models into production features that actually scale.
---
# AI Engineer Agent
You are an **AI Engineer**, an expert AI/ML engineer specializing in ...
## 🧠 Your Identity & Memory
- **Role**: AI/ML engineer and intelligent systems architect
...
结构上就三层:YAML frontmatter → 角色声明段 → 分节的职责与规则正文。正文是直接喂给模型的第二人称提示词,所以你会看到大量 “You are…” “You remember…” 这样的句子。
这里先插一句提醒:agent 文件里出现的 Experience: You've built and deployed ML systems at scale 这类句子,写在人设段而不是简历里,是给模型看的角色设定,不是对任何真人经历的陈述。把它当成能力证明来转述,是读法上的错误。
必填只有三项,写在脚本第 34 行
scripts/lint-agents.sh 里有一行数组定义,它就是这个问题的最终答案:
REQUIRED_FRONTMATTER=("name" "description" "color")
缺其中任意一项,lint 报 ERROR。而样例里同时出现的 emoji 和 vibe 都不在这个列表里,属于可选字段——少写不会让检查失败。
为什么偏偏是这三项?看它们被谁消费就明白了。仓库的链路是「源 agent markdown → convert.sh 渲染成各工具格式 → install.sh 拷贝到目标目录」,一共覆盖 16 种工具。这三个字段是转换器们的公共输入:
- Codex 的
codex-toml每个 agent 渲染一个 TOML,只写最小必需字段,name与description都在里面; - Cursor 的
cursor-mdc生成的.mdcfrontmatter 里,description是唯一带内容的业务字段(另外两项globs: ""和alwaysApply: false是写死的); - opencode 的
opencode-mdfrontmatter 是name+description+mode: subagent+color,四项里三项来自源文件。
也就是说,这三个字段的必填不是风格洁癖,而是因为任何一个缺失都会让某个转换器渲染出残缺产物。反过来,emoji 和 vibe 之所以是可选,是因为它们不进这几个渲染模板;vibe 是一句话人设标语,被 app 一类的目录工具消费——花名册导出里每个 agent 都带一句,比如「No culture is random」这种,它是给人看的展示文案。
color 这个字段值得单独说一句取值形态。翻花名册导出会发现两种写法并存:有的 agent 写 color: blue、color: amber、color: purple 这样的命名色,有的写 color: "#D97706" 这样的十六进制。lint 这一道检查管的是「这个键在不在」,我们读到的检查清单里没有针对 color 取值格式的单独条目;真正处理形态差异的是转换器——opencode 那条链路会通过 resolve_opencode_color() 把命名色解析成十六进制。判断依据:所以你新写 agent 时,两种写法都能过 lint,但如果你的目标工具链上没有对应的解析步骤,命名色就可能原样落进产物。要稳妥就抄同 division 里已有 agent 的写法。
ERROR 与 WARN 分得很清楚
lint-agents.sh 的用法是 ./scripts/lint-agents.sh [file ...],不给文件参数就扫描所有 agent 目录。它的检查项级别分得很清楚:
| 检查 | 级别 | 说明 |
|---|---|---|
| 拒绝 CRLF 行尾 | ERROR | 仓库标准是 LF |
| frontmatter 分隔符存在 | ERROR | 取首尾两个 --- 之间的内容 |
| 必填字段齐全 | ERROR | name / description / color |
| 推荐章节存在 | WARN | RECOMMENDED_SECTIONS=("Identity" "Core Mission" "Critical Rules"),大小写不敏感 |
| 正文有实质内容 | WARN | 正文词数小于 50 就警告 |
| 章节标题能映射到两个目标文件 | WARN | 见下一节 |
第一道值得展开。源码注释解释了为什么把行尾单独拎出来当 ERROR:行尾多一个 \r,会让后面的 frontmatter 检查报出「missing frontmatter ---」这种令人困惑的错——明明文件开头就是 ---。这对 Windows 用户是个直接的判断依据:如果你在 Windows 上编辑 agent 文件,看到「找不到 frontmatter」的报错先别怀疑自己 YAML 写错了,先查行尾。
推荐章节那道只是 WARN,意味着你完全可以写一个没有 Identity 段的 agent 并让检查通过。但下一节会说明,章节标题这件事的后果不止于一条警告。
★ 你给章节起的标题,其实是一条路由规则
这是整个格式里最反直觉的一条。lint-agents.sh 里有个 classify_header_target() 函数(第 40–53 行),把每个 ## 级标题分流到两个目标:
if [[ "$header_lower" =~ identity ]] ||
[[ "$header_lower" =~ learning.*memory ]] ||
[[ "$header_lower" =~ communication ]] ||
[[ "$header_lower" =~ style ]] ||
[[ "$header_lower" =~ critical.rule ]] ||
[[ "$header_lower" =~ rules.you.must.follow ]]; then
printf 'soul'
else
printf 'agents'
fi
命中 identity、learning + memory、communication、style、critical rule、rules you must follow 的标题去 SOUL.md,其余全部去 AGENTS.md,默认桶就是 agents。lint 要求两边都至少有一个标题,否则各报一条 WARN,文案是 no section headers map to SOUL.md in convert.sh 和对应的 AGENTS.md 版本。
为什么 lint 要管这件事:因为这两个文件名对应的是 convert.sh 里 OpenClaw 格式的工作区结构——OpenClaw 的 installKind 是每个 agent 渲染成一个目录,正文按同一套关键词拆成 SOUL.md 与 AGENTS.md 两个文件。lint 和 convert 用的是同一套分流逻辑,所以 lint 能提前替你发现「这个 agent 转到 OpenClaw 会有一个空文件」。
由此得到一条可以直接照做的规则:写 agent 正文时,标题不是排版,是路由。你想让某段内容进 SOUL,就得让标题里出现上面那几个关键词之一;你把「Critical Rules」改成一个更漂亮的名字,那段规则就会悄悄掉进 AGENTS.md。这个后果在只用 Claude Code 一类 identity 格式(原样输出、不做改写)的场景里看不出来,只有转到 OpenClaw 时才显形。
顺带一提原创性检查的阈值怎么读
新增 agent 还有一道 scripts/check-agent-originality.sh。它防的是「查找替换换皮」——把已有 agent 里的国家名、平台名一换就当新 agent 提交,评审时很难发现,但会用重复内容把库撑肿。
它的做法是把候选 agent 与整个花名册对比,用实体中性化后的 8 词 shingle 重叠率打分,vietnam、chinese、douyin、tiktok、korean、japanese 这类专有名词会先被中性化,所以换名字藏不住。两个默认阈值可以用环境变量覆盖:ORIGINALITY_FAIL 默认 40,达到或超过这个百分比视为重复、退出码 1;ORIGINALITY_WARN 默认 20,达到就警告但不失败。
这两个数怎么读:源码注释给出了库内校准结论——在现有 agent 库里,同一对之间最差的相似度约 1.5%,中位数 0%。也就是说双位数已经是强异常,默认阈值留了很宽的误判余量。这是对这一个库的校准值,不是对任意 agent 库的普适结论。脚本给文件参数就只查这些(CI 用于变更文件),不给参数则全库两两互查;它依赖 python3,缺了直接退出码 2。
最后划一下边界
仓库还有 check-divisions.sh、check-tools.sh、check-runbooks.sh 这几个一致性检查,它们守的是配置漂移——目录、divisions.json、tools.json 与脚本里的数组不能各说各话。加一个新 division 的正确顺序,divisions.json 的 _note 里写得很明白:建目录 → 在 divisions.json 加条目 → 跑 scripts/check-divisions.sh → 按它的报错去更新它指向的地方。
但这些检查合起来,管的是结构与重复度,不评估提示词好不好用。一个 frontmatter 齐全、章节标题两边都命中、相似度 0% 的 agent,照样可能写得很平庸。lint 全绿只说明它能被正确转换和安装,不说明它能干活——这条边界值得在提 PR 之前先记住。
延伸阅读
本文依据 agency-agents 官方仓库(github.com/msitarzewski/agency-agents)的 README、
tools.json、divisions.json、scripts/ 下的安装与校验脚本整理,核对日 2026-08-09。
本文内容为仓库源码与文档口径,我们没有安装或运行过其中任何 agent。
目录、脚本与安装路径随上游更新而变动,请以仓库最新内容与 ./scripts/install.sh --help 的实际输出为准。