跳到主要内容

AGENTS.md — 架构与原理

30 秒导读: AGENTS.md 是一个约定(不是程序):在仓库根目录放一个叫 AGENTS.md 的普通 Markdown 文件,把"怎么装依赖、怎么跑测试、代码风格、提交规范"这类给 AI 编码 agent 看的说明写进去。它的全部价值在于"大家都用同一个文件名、同一种格式",于是 Codex、Cursor、Gemini CLI 等几十家 agent 都能在同一个可预测的位置读到它。


1. 这是什么(零基础也能懂)

一句话定义。 AGENTS.md 是"给 agent 看的 README"——一个放在仓库里、文件名固定为 AGENTS.md 的普通 Markdown 文件,专门写给 AI 编码助手看。

它解决谁的什么问题。 假设你让一个 AI agent(比如 OpenAI Codex、Cursor)去改你的项目代码。它一进来就懵:依赖怎么装?测试怎么跑?这个仓库用单引号还是双引号?提交信息有没有格式要求?这些信息要么散落在 README、CONTRIBUTING、各种 wiki 里,要么干脆只在某个老员工脑子里。

AGENTS.md 给这些信息一个固定的家

README.md 是给人看的(快速上手、项目简介、贡献指南);AGENTS.md 补上 agent 需要的那些"额外、有时很琐碎"的上下文——构建步骤、测试、规范——这些塞进 README 会显得乱,对人类贡献者也不一定相关。 —— 这正是项目刻意把两者分开的理由,见 components/WhySection.tsx:17-25

为什么不直接用 README? 项目方给了三条刻意分开的理由(components/WhySection.tsx:27-55):

  • 给 agent 一个清晰、可预测的指令位置;
  • 让 README 保持简洁、聚焦人类贡献者;
  • 提供精确、面向 agent的指引,与现有 README/文档互补而非打架。

用起来什么样。 它就是一段你能直接读懂的 Markdown。下面是官网首页用的最小示例(逐字来自 components/CodeExample.tsx:22-32HERO_AGENTS_MD 常量):

# AGENTS.md

## Setup commands
- Install deps: `pnpm install`
- Start dev server: `pnpm dev`
- Run tests: `pnpm test`

## Code style
- TypeScript strict mode
- Single quotes, no semicolons
- Use functional patterns where possible

一句话直觉/类比。 把 README 当成"贴在门口给客人看的欢迎牌",AGENTS.md 就是"贴在员工休息室、给新来同事看的操作手册"——同一栋楼,但读者不同、内容不同。

本节不出现底层细节。记住一点就够:AGENTS.md = 给 agent 的 README,文件名固定,内容是普通 Markdown。


2. 顶层全景(它大概怎么转)

这一节讲清"这个约定整体是怎么运作的"。

2.1 先纠正一个常见误解

AGENTS.md 这个项目本身不解析 AGENTS.md。这个仓库里只有两样东西:

  • 一份约定(文件名 + 用法规则),写在文档和网站文案里;
  • 一个 Next.js 营销网站pages/components/),部署在 https://agents.md ,用来解释这个约定、展示兼容的 agent 列表和示例。

真正"读 AGENTS.md 并照做"的,是每一个消费方 agent(Codex、Cursor、Gemini CLI……),各自在自己的代码里实现。所以这是一个协议/约定类项目,价值在"达成共识"而非"某段算法"。

2.2 约定的运作流:从写到被执行

下面这张图从左到右是时间顺序:仓库作者写文件 → agent 进场读取 → 按规则解析 → 执行任务。

仓库作者 某个编码 agent(Codex/Cursor/…)
──────── ──────────────────────────────

① 在仓库根写 AGENTS.md ② agent 接到任务,进入仓库
(普通 Markdown) │
│ ▼
│ ③ 找最近的 AGENTS.md
▼ (从被改文件往上层找)
┌──────────────┐ │
│ # Setup … │ ───读取──▶ ▼
│ ## Testing … │ ④ 把内容当上下文喂给模型
│ ## PR … │ │
└──────────────┘ ▼
⑤ 干活:改代码、
(若列了测试命令)自动跑测试、
修到全绿再收工

怎么读这张图:左边作者只做一件事——写文件;右边 agent 的 ③④⑤ 才是"约定"真正被执行的地方。注意 ③⑤ 是消费方 agent 实现的行为,本仓库只"规定"它们应该这么做(见 §3、§6)。

2.3 这个仓库里有什么(部件一句话职责)

部件干什么在哪个文件
约定本体定义"文件名 = AGENTS.md、内容 = 普通 Markdown"以及用法规则README.mdcomponents/WhySection.tsxcomponents/HowToUseSection.tsxcomponents/FAQSection.tsx
兼容 agent 清单列出已支持 AGENTS.md 的 agent(Codex、Cursor、Gemini CLI、Zed…),网站上滚动展示components/CompatibilitySection.tsx:14-142agents 数组)
示例库几个真实用了 AGENTS.md 的知名仓库卡片(openai/codex、apache/airflow…)components/ExampleListSection.tsx:22-45REPOS
规范化示例文件官网展示的标准 AGENTS.md 样例(Setup/Testing/PR 三段式)components/CodeExample.tsx:34-61EXAMPLE_AGENTS_MD
网站骨架Next.js 页面,把上面各 Section 拼起来pages/index.tsx:17-35

3. 核心原理(约定的几条规则)

这个项目的"原理"不是算法,而是几条约定规则。每条规则都先讲它解决什么小问题,再给出在本仓库里的出处。

3.1 规则一:固定文件名,普通 Markdown,无必填字段

它要解决的小问题。 如果每家 agent 用不同的文件名(.cursorrules.aider.confGEMINI.md……),仓库作者就得为每家维护一份——这正是项目想消灭的碎片化。

思路。 选一个中立、谁都能用的名字 AGENTS.md,格式就用谁都会写的 Markdown,不规定任何必填字段

有没有必填字段?没有。 AGENTS.md 就是标准 Markdown,用任何你喜欢的标题;agent 只是解析你提供的文本。 —— components/FAQSection.tsx:13-16

这是它和"专有配置文件"的根本区别:

与其再引入一个专有文件,我们选了一个任何人都能用的名字和格式。 —— components/WhySection.tsx:56-60

关键细节。 "无 schema"是双刃剑:上手零成本,但也意味着没有机器可校验的结构——内容质量全靠作者自觉。常见做法是写成 Setup / Testing / PR 三段式(见 §3.4 的规范示例)。

3.2 规则二:就近优先(nearest-file-wins)

它要解决的小问题。 大型 monorepo 里,根目录的通用规则和某个子包的专属规则可能冲突——agent 该听谁的?

思路。 允许在每个子目录/子包各放一个 AGENTS.md;agent 自动读"离被改文件最近"的那个,最近的优先

仓库根/
├── AGENTS.md ← 通用规则(兜底)
├── packages/
│ ├── web/
│ │ ├── AGENTS.md ← 改 web/ 里的文件时,用这个(覆盖根的)
│ │ └── src/...
│ └── api/
│ └── AGENTS.md ← 改 api/ 里的文件时,用这个
└── ...

真实出处。 官网"如何使用"第 4 步明说了这点:

在每个包里再放一个 AGENTS.md。agent 自动读目录树里最近的那个,所以最近的优先,每个子项目都能带自己定制的指令。截至撰写时,OpenAI 主仓库有 88 个 AGENTS.md 文件。 —— components/HowToUseSection.tsx:35-40

冲突裁决规则在 FAQ 里再次确认,并补了"人类聊天指令最高优先级"这条暗线:

指令冲突怎么办?离被改文件最近的 AGENTS.md 胜出;用户在聊天里给的明确指令凌驾一切。 —— components/FAQSection.tsx:18-21

这给出一条清晰的优先级链:

聊天里的明确指令 > 最近的 AGENTS.md > 上层 AGENTS.md > (兜底)根 AGENTS.md
最高 最低

注意:"就近优先"是消费方 agent 实现的行为,本仓库只规定它该如此,没有解析代码可引。(inferred) 成分:上图的完整优先级链是把 §3.2 两段原文合并推出的,原文未画成一条链。

3.3 规则三:列了测试命令,agent 会自动跑

它要解决的小问题。 光告诉 agent"代码怎么写"不够;你还想让它自己验证改对了没有。

思路。 如果你在 AGENTS.md 里列出测试/检查命令,agent 会主动去执行,并在收工前把失败修掉。

agent 会自动跑 AGENTS.md 里的测试命令吗?会——只要你列了。 agent 会尝试执行相关的程序化检查,并在完成任务前修复失败。 —— components/FAQSection.tsx:22-26

为什么这条重要。 它把 AGENTS.md 从"静态说明"升级成"可执行的验收契约":作者写下命令,等于给 agent 划了一条"必须过"的红线。官网建议在文件里覆盖的内容也呼应这点(components/HowToUseSection.tsx:16-29):项目概览、构建/测试命令、代码风格、测试说明、安全注意事项。

3.4 规则四:可演进 + 向后兼容迁移

它要解决的小问题。 已经有人用了 AGENT.md(单数)等旧名字,怎么平滑迁移而不破坏旧工具?

思路。 把 AGENTS.md 当成"活文档",随时改;迁移老文件时用符号链接保持兼容。FAQ 给了一条具体命令:

mv AGENT.md AGENTS.md && ln -s AGENTS.md AGENT.md

—— components/FAQSection.tsx:32-48。把内容搬到正名 AGENTS.md,再建一个软链让旧名 AGENT.md 仍指向它。

部分 agent 还需要在自己的配置里"指认" AGENTS.md,FAQ 也给了两例:

  • Aider:在 .aider.conf.ymlread: AGENTS.mdcomponents/FAQSection.tsx:49-66)。
  • Gemini CLI:在 .gemini/settings.jsoncontext.fileName 设成 "AGENTS.md"components/FAQSection.tsx:67-88)。

4. 深入:网站是怎么搭的(给要读源码的人)

约定本身没有"实现",但承载它的网站值得一看——尤其"谁在用"那块有个真实的工程小细节。

4.1 页面装配

首页就是把一串 Section 顺序拼起来(pages/index.tsx:17-35):Hero → Why → Compatibility(兼容 agent 滚动条)→ Examples → HowToUse → About → FAQ。每个 Section 是一个独立的 .tsx 组件,文案即"约定"。

4.2 "谁在用"卡片的贡献者数据

首页用 Next.js 的 getStaticProps构建/再验证时去 GitHub API 拉几个示例仓库(openai/codexapache/airflowtemporalio/sdk-javaPlutoLang/Pluto)的前 3 名贡献者头像和总人数(pages/index.tsx:47-160)。

两个值得学的细节:

  • 贡献者总数靠 Link 头算,不拉全量。 它请求 contributors?per_page=1 然后解析响应里的 Link: …rel="last" 头,从 page=N 直接读出总页数 = 总人数,避免把成千上万个贡献者整个拉回来(pages/index.tsx:114-131)。
  • 进程内缓存防限流。 GitHub 未认证 API 限 60 次/小时;代码用一个模块级变量 cachedContributors 缓存 12 小时,开发时反复刷新页面也不会打爆限额(pages/index.tsx:40-76)。

4.3 这个仓库自己的 AGENTS.md

这个仓库"吃自己的狗粮"——根目录就有一份 AGENTS.md,规定 agent 在本项目里只用 npm run dev、不要跑 npm run build(否则 .next 切到生产资源、热重载失效),并列了命令速查表(AGENTS.md:8-37)。这本身就是"规则三:列命令"的活例子。


5. 巧妙之处(可借鉴的)

  • 用"约定"而非"标准"破局。 不发布 schema、不要求注册、不设必填字段——只约定一个文件名。落地阻力趋近于零,于是能滚到"60k+ 开源项目"和几十家 agent(首页声称,components/Hero.tsx:22-32;兼容清单 components/CompatibilitySection.tsx:14-142)。这是"最小公约数"式协议设计的范本。
  • 就近优先 = 把覆盖语义交给文件系统。 不需要任何配置语言来表达"子包覆盖根",直接用"目录树里最近的胜出"——复用了开发者早已熟悉的 .gitignore/.editorconfig 心智(components/HowToUseSection.tsx:35-40)。
  • 可执行契约。 "列了测试命令就会被自动跑"把文档变成验收门禁,几乎零成本地让"说明"具备"强制力"(components/FAQSection.tsx:22-26)。
  • 中立治理。 项目现由 Linux Foundation 下的 Agentic AI Foundation 托管(components/AboutSection.tsx:20-32components/Footer.tsx:7),降低了"被某一家 agent 厂商绑架"的疑虑——这对一个想让所有人采用的约定至关重要。

6. 边界与局限(诚实)

  • 本仓库不执行任何约定。 它没有解析器、没有优先级裁决代码。"就近优先""自动跑测试""聊天覆盖一切"全是消费方 agent 各自实现的行为,本仓库只"规定"它们应当如此。本文档对这些行为的描述,源头是网站自己的 FAQ/How-to 文案(components/FAQSection.tsxcomponents/HowToUseSection.tsx),不是某段可运行的实现。
  • 无 schema = 无校验。 因为"无必填字段"(components/FAQSection.tsx:13-16),没有任何机器能告诉你 AGENTS.md 写得对不对、全不全;不同 agent 对同一份文件的理解可能有出入。
  • 行为一致性靠各家自觉。 不同 agent 对"最近的优先""自动跑测试"的实现深浅不一;本约定不提供一致性测试套件。
  • 采用数字是项目自述。 "60k+ 项目""OpenAI 仓库 88 个 AGENTS.md"等来自网站文案(components/Hero.tsx:22-32components/HowToUseSection.tsx:38),本仓库内无法独立核验。

7. 横向对比(同 shelf 兄弟)

AGENTS.md 属于 ai-protocol-reference 里的 prompt-authority / coding-agents 一类——"怎么把指令可靠地交给 agent"。它的取舍很有特色:

维度AGENTS.md 的选择含义
载体仓库内一个 Markdown 文件跟代码同源、随 PR 走、可 review
结构无 schema、纯 Markdown上手零成本,但不可机器校验
作用域文件系统就近优先用目录层级表达覆盖,无需配置语言
强制力列出的命令会被自动执行"说明"升级为"验收契约"
跨厂商中立文件名 + 基金会托管一份文件,多家 agent 通用

相比把指令塞进"系统提示词"或"模型上下文协议(如 MCP 那类运行时连接)",AGENTS.md 走的是最轻量、最贴近开发者既有习惯的一条路:它不连接工具、不传输数据,只是"约定一个文件名"。这也是它和 shelf 内偏"运行时协议"兄弟项目的根本分野——一个是静态约定,一个是动态接口。


8. 代码地图(导航索引)

按"我想看哪条约定/哪段实现"直接跳。符号名优先于行号(行号会随上游漂移)。

主题文件路径符号名
约定:为什么和 README 分开components/WhySection.tsxWhySection
约定:如何使用(4 步)+ 就近优先components/HowToUseSection.tsxHowToUseSectionsteps 数组)
约定:无必填字段 / 冲突裁决 / 自动跑测试 / 迁移components/FAQSection.tsxFAQfaqItems
规范示例 AGENTS.md(Setup/Testing/PR)components/CodeExample.tsxEXAMPLE_AGENTS_MD
首页 Hero 用的最小示例components/CodeExample.tsxHERO_AGENTS_MD
兼容 agent 清单(Codex/Cursor/Gemini CLI…)components/CompatibilitySection.tsxagents(数组)
"谁在用"示例仓库卡片components/ExampleListSection.tsxREPOS
贡献者数据抓取 + 缓存 + 限流处理pages/index.tsxgetStaticPropscachedContributors
页面装配顺序pages/index.tsxLandingPage
治理归属(AAIF / Linux Foundation)components/AboutSection.tsxAboutSection
本仓库自己的 agent 规则(只用 dev,别 build)AGENTS.md