agency-agents 的 agent 文件格式:name/description/color 是必填,emoji/vibe 不是

2026-08-09

如果你打算往 agency-agents 里加一个自己的 agent,或者把它的某个 agent 改成贴合自己团队的版本,第一个要搞清楚的问题不是「提示词怎么写才好」,而是「哪些东西是格式硬要求,哪些只是惯例」。这两类东西混在一份 markdown 里,肉眼看起来长得一模一样,但改错了的后果完全不同:一类会让仓库的检查脚本直接报 ERROR,另一类只是少一条 WARN。

这篇就把这条线划清楚。所有结论都来自仓库源码本身——scripts/lint-agents.shscripts/check-agent-originality.shdivisions.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。而样例里同时出现的 emojivibe 都不在这个列表里,属于可选字段——少写不会让检查失败。

为什么偏偏是这三项?看它们被谁消费就明白了。仓库的链路是「源 agent markdown → convert.sh 渲染成各工具格式 → install.sh 拷贝到目标目录」,一共覆盖 16 种工具。这三个字段是转换器们的公共输入:

  • Codex 的 codex-toml 每个 agent 渲染一个 TOML,只写最小必需字段,namedescription 都在里面;
  • Cursor 的 cursor-mdc 生成的 .mdc frontmatter 里,description 是唯一带内容的业务字段(另外两项 globs: ""alwaysApply: false 是写死的);
  • opencode 的 opencode-md frontmatter 是 name + description + mode: subagent + color,四项里三项来自源文件。

也就是说,这三个字段的必填不是风格洁癖,而是因为任何一个缺失都会让某个转换器渲染出残缺产物。反过来,emojivibe 之所以是可选,是因为它们不进这几个渲染模板;vibe 是一句话人设标语,被 app 一类的目录工具消费——花名册导出里每个 agent 都带一句,比如「No culture is random」这种,它是给人看的展示文案。

color 这个字段值得单独说一句取值形态。翻花名册导出会发现两种写法并存:有的 agent 写 color: bluecolor: ambercolor: 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取首尾两个 --- 之间的内容
必填字段齐全ERRORname / description / color
推荐章节存在WARNRECOMMENDED_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.mdAGENTS.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.shcheck-tools.shcheck-runbooks.sh 这几个一致性检查,它们守的是配置漂移——目录、divisions.jsontools.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.jsondivisions.jsonscripts/ 下的安装与校验脚本整理,核对日 2026-08-09。 本文内容为仓库源码与文档口径,我们没有安装或运行过其中任何 agent。 目录、脚本与安装路径随上游更新而变动,请以仓库最新内容与 ./scripts/install.sh --help 的实际输出为准。

想系统学会用 AI?报名体系课或加入会员,照着学、照着用。