用一份 AGENTS.md,把代码 Agent 当成新同事来带
问题
用代码 Agent 最浪费时间的地方,不是它写错,而是它在同一个坑里反复摔。每次新会话,你都要重新说一遍:别动 migrations、测试用 pnpm 不是 npm、这个目录是生成物不要手改。
这是因为 Agent 每次开会话,上下文都是空的。你不写下来,它就不知道。
做法
在仓库根目录放一份 AGENTS.md(Claude Code 用 CLAUDE.md,Codex 用 AGENTS.md),内容按这四块写:
1. 项目是什么 一段话讲清技术栈、目录职责、入口在哪。不要写 README 那种营销文案,写”改一个接口要动哪几个文件”这种。
2. 命令清单
pnpm dev # 本地开发
pnpm test # 跑测试,改动后必跑
pnpm build # 构建
Agent 猜命令是错误的主要来源之一。写死,它就不需要猜。
3. 禁区
明确列出不能碰的东西:数据库 migration 文件、.env、生成目录、package-lock.json。写得越具体越好,“不要乱改配置”是无效指令,“不要修改 src/generated/ 下任何文件”才是。
4. 验收标准
“改完之后跑 pnpm test,全绿才算完成”。给 Agent 一个明确的终点,它才知道什么时候停。
几个实测有效的细节
- 用 @ 引用而不是复制粘贴。 需要 Agent 读某个文件时,让它自己去读,别把内容粘进对话——粘进来的会过期。
- 文档也要跟着改。 如果 Agent 发现文档和代码不一致,让它提出来,别让它自己改文档掩盖问题。
- 分层的两份。 根目录放通用约定,子目录放局部约定。Agent 通常会自动读取当前目录层级的文件。
- 写「为什么」比写「是什么」有用。 「这个文件是生成物,改了会被覆盖」比「不要改这个文件」更能让 Agent 举一反三。
一份能直接抄的模板
下面这份是我自己在用的骨架,复制到根目录改一遍大约二十分钟:
# 项目约定
## 这是什么
Next.js 15 + Postgres,App Router。`src/app` 是页面,`src/lib` 是纯函数,
`src/server` 只在服务端跑。改一个接口通常要动:route.ts → lib/xxx.ts → 类型定义。
## 命令
pnpm dev # 本地开发,端口 3000
pnpm test # 改动后必跑
pnpm build # 构建,CI 会跑
pnpm lint # 提交前跑
## 不要碰
- `src/generated/` 下所有文件(由 openapi 生成,改了会被覆盖)
- `migrations/`(建新迁移,不要改已提交的)
- `.env*`、`pnpm-lock.yaml`
- 任何 `package.json` 里的版本号,除非明确要求
## 完成标准
改完跑 `pnpm test` 和 `pnpm lint`,全绿才算完成。
新增接口要补一个测试,改动数据库结构要先说明迁移方案。
## 偏好的做法
- 类型不要 `any`,宁可先 `unknown` 再收窄
- 错误处理用已有的 `AppError`,不要自己抛裸 Error
- 提交信息用中文,一句话说清改了什么
最后那节「偏好的做法」是最容易被忽略、但回报最高的一节。你写「不要 any」是规则,写「宁可先 unknown 再收窄」是思路——后者能让 Agent 在你没覆盖到的地方也做出正确选择。
什么时候这份文档会失效
当你的项目结构发生大改而文档没跟上时,它反而会成为误导源。建议把它加进 code review 的检查项:改了目录结构,就同步改 AGENTS.md。
一句话
把 AGENTS.md 当成给新同事的入职文档来写——你不会对一个新人只说”你自己看着办”,对 Agent 也一样。