Claude Code 2.1.277 开始读 AGENTS.md:跨工具项目指令文件的层级与写法

发布时间:2026/10/17 17:19:14
Claude Code 2.1.277 开始读 AGENTS.md:跨工具项目指令文件的层级与写法
1. 一个仓库三套规则文件改到怀疑人生如果你同时用 Claude Code、Cline、Windsurf 写同一个项目大概率经历过这种场面.clinerules里写着「提交前跑 pnpm lint」CLAUDE.md里写着「测试用 vitest」Windsurf 的 rules 目录里又是另一套构建命令。改一次构建脚本得挨个文件同步漏掉一个某个工具就开始按过期指令干活。Claude Code 2.1.277 这次更新把这件事往「一份文件喂多个工具」的方向推了一步当项目里没有 CLAUDE.md 时Claude Code 会去读 AGENTS.md。AGENTS.md 不是某个厂商的私有格式它是一份跨工具约定Codex、Gemini CLI、Cursor、Windsurf、Zed、Aider 等都在读它。对多工具协作的团队来说这意味着你终于可以把「构建、测试、代码风格」这类与工具无关的规则抽出来只维护一份。这篇就围绕这次改动把 AGENTS.md 和 CLAUDE.md 的加载顺序、覆盖规则、目录层级讲清楚给一套可以直接复制的目录结构和配置片段最后演示改完之后怎么验证「agent 到底读了哪份文件」。适合正在用两个以上 AI 编码工具、被规则文件同步问题折磨的开发者。2. 先搞清楚加载顺序再动手写文件动手之前必须把优先级搞明白否则你写了一份 AGENTS.md结果项目里还躺着一个 CLAUDE.mdClaude Code 根本不会读你新写的那份。2.1 回退关系不是合并关系2.1.277 官方日志 Added 部分的原文是Added AGENTS.md support: in a project with no CLAUDE.md, Claude Code reads AGENTS.md instead; change it under Project instructions in /config (not yet on Bedrock, Vertex or Foundry)这句话里有三个限定漏掉任何一个都会理解偏。第一前提是项目中没有 CLAUDE.mdCLAUDE.md 存在时仍然以它为准AGENTS.md 是回退项不是把两份文件合并后一起读。第二这条行为可以在/config的 Project instructions 下切换。第三Bedrock、Vertex、Foundry 三个后端暂不支持用这三个平台跑 Claude Code 的同学这次改动对你不生效。所以如果你打算迁移到 AGENTS.md正确做法是把 CLAUDE.md 的内容搬过去然后删掉或改名 CLAUDE.md而不是两份都留着。2.2 嵌套文件最近的一份生效AGENTS.md 官方文档给出了嵌套规则把文件放进每个子包目录agent 会自动读取目录树中离它最近的那一份最近的优先。官方举例说写作这份文档时 OpenAI 主仓库里有 88 个 AGENTS.md 文件。这条规则有一个很容易搞错的推论把packages/api/AGENTS.md放进仓库并不会影响在packages/web/目录里干活的 agent。生效的是目录树中最近的那一份靠外的那份不会在子目录里继续兜底。也就是说子目录里的 AGENTS.md 是「替换」而不是「叠加」父目录的规则。2.3 一张表看清所有层级文件 / 设置归属什么时候被读CLAUDE.mdClaude Code 原有约定存在即优先AGENTS.md 不再被读AGENTS.md跨工具约定仅在项目里没有 CLAUDE.md 时/config → Project instructions用户级开关控制上面这条回退行为是否启用企业 managed policy组织级始终加载优先级最高从这张表能读出一个设计取向指令文件是按作用域生效的不是一个全局开关。同一批版本里还有几个相关改动值得并排看——2.1.271 让omitClaudeMd进入 agent frontmatter自定义子代理可以不加载 user、project、local 三份 CLAUDE.md但 managed policy 仍然加载2.1.269 修复了当 CLAUDE.md 里有反对 commit 署名的规则时attribution reminder 不再覆盖它但 managed settings 写下的规则仍然生效。这些都是优先级的具体例证组织设置高于项目文件。3. 可复制的目录结构与配置片段理论讲完直接上能跑的东西。下面这套结构我按「根目录放通用规则、子包放专属规则」的思路设计你可以直接抄。3.1 推荐的目录结构my-monorepo/ ├── AGENTS.md # 根级全仓库通用规则 ├── packages/ │ ├── api/ │ │ ├── AGENTS.md # api 专属Node TypeScript 规则 │ │ └── src/ │ └── web/ │ ├── AGENTS.md # web 专属React 规则 │ └── src/ └── pnpm-workspace.yaml根级 AGENTS.md 只放「所有包都适用」的内容子包 AGENTS.md 放该包特有的命令和约定。注意子包文件是替换而非叠加所以子包里需要重复写一遍它依赖的通用命令或者干脆在子包里只写差异部分、把通用部分留在根级——但前提是 agent 的工作目录在根级时才会读到根级那份。3.2 根级 AGENTS.md 模板# AGENTS.md ## 项目概览 - 单仓多包packages/api服务端Node TypeScript、packages/web前端React - 本地依赖统一用 pnpm 工作区管理 ## 构建与测试 - 装依赖pnpm install - 跑全量测试pnpm test - 只跑单个包pnpm turbo run test --filter 包名 - 提交前必须通过 pnpm lint不要因为「改动很小」跳过 ## 代码风格 - TypeScript 严格模式不用 any - 单引号行尾不加分号 ## 需要特别小心的地方 - 涉及金额计算的改动必须补测试边界至少覆盖 0、1 和 10001 - 不要调整 packages/api/src/auth/ 下鉴权校验的执行顺序内容上把握两条一是可执行写成命令、字段、路径这种可以被验证的东西二是克制取舍只放你这个仓库里 agent 一定会踩的坑。像「代码要优雅」「注意性能」这类没法验证的话写进去只会稀释注意力。3.3 子包 AGENTS.md 模板# AGENTS.md — packages/api ## 本包专属命令 - 启动开发服务pnpm --filter api dev - 数据库迁移pnpm --filter api migrate ## 本包约定 - 所有对外接口必须走 src/schemas/ 下的 zod 校验 - 日志统一用 src/lib/logger.ts不要直接 console.log3.4 如果你还想保留 CLAUDE.md有些团队暂时不想动 CLAUDE.md只想让 Cline、Windsurf 读 AGENTS.md。这种情况下可以让 CLAUDE.md 只写一行指向 AGENTS.md 的说明或者干脆把 CLAUDE.md 删掉、统一用 AGENTS.md。但记住两份都留且内容冲突时Claude Code 只读 CLAUDE.md不会帮你调和。如果你是通过 API 方式接入 Claude Code 或类似工具Base URL、Key、Model ID 三件套要配全。以 TaoToken 为例Base URL 填https://taotoken.net/apiKey 在控制台生成Model ID 按你实际用的模型填。配置片段如下{ base_url: https://taotoken.net/api, api_key: sk-你的Key, model: claude-sonnet-4-20250514 }4. 验证 agent 到底读了哪份文件模型声称自己读了什么并不完全可信所以别只问它做一个对照实验更稳。4.1 对照实验三步法第一步在 AGENTS.md 里写一条只可能来自这份文件的规则比如「任何提交信息必须以 [模块名] 开头」。第二步让 agent 执行一个只有满足该规则才成立的动作比如写一条提交信息或生成一个 PR 标题。第三步保持同一仓库、同一句提示词把 AGENTS.md 改名或移走再执行一次对比两次的行为差异。行为跟着变了说明这份文件确实在读取链路上两次一样说明你改的文件它根本没读。这个实验比问模型「你读了哪个文件」可靠得多因为模型可能会根据上下文猜测而不是真的去读了文件。4.2 清点仓库里的指令文件下面这个脚本用来扫描仓库里的指令文件并标出层级自拟示意代码非官方工具# list_instruction_files.py —— 自拟示意代码非官方工具 # 用途清点仓库里所有 AGENTS.md / CLAUDE.md输出相对路径、目录深度和最近修改时间 from pathlib import Path import time NAMES (AGENTS.md, CLAUDE.md) def scan(root: str): root_path Path(root) rows [] for p in root_path.rglob(*): if p.name in NAMES and p.is_file(): rel p.relative_to(root_path) rows.append({ rel: str(rel).replace(\\, /), depth: len(rel.parts) - 1, # 目录层级越深离子项目越近 mtime: time.strftime(%Y-%m-%d %H:%M, time.localtime(p.stat().st_mtime)), }) rows.sort(keylambda r: r[rel]) for r in rows: print(f{r[rel]:50} depth{r[depth]} mtime{r[mtime]}) print(f共 {len(rows)} 份指令文件) if __name__ __main__: scan(.) # 在仓库根目录执行代码说明rglob负责递归收集候选文件depth用相对路径的目录层数表示越深越接近子项目对应官方描述的「最近者优先」mtime用来排查同一份规则被复制到多个目录后各自漂移的情况。这个脚本只做清点不判断哪份文件真正生效——是否生效要靠上面的对照实验。4.3 用 /config 确认开关状态在 Claude Code 里输入/config找到 Project instructions 这一项确认 AGENTS.md 回退读取是否开启。如果你在 Bedrock、Vertex、Foundry 上跑这一项对你不生效需要按实际后端再确认一次。5. 四个真实报错与排查路径配置过程中最容易撞上的几个问题我按报错现象、原因、解决路径整理成对照表。5.1 改了 AGENTS.md 但行为没变现象你更新了 AGENTS.md 里的构建命令但 agent 还是跑旧命令。原因大概率是项目里还有 CLAUDE.mdClaude Code 优先读了它。排查路径用上面的脚本扫一遍仓库确认有没有 CLAUDE.md 残留。如果有要么删掉要么把内容迁移到 AGENTS.md 后删除。5.2 401 报错现象请求返回 401 Unauthorized。原因通常是 API Key 没配、配错或者 Base URL 和 Key 不匹配。排查路径检查你的配置文件里api_key字段是否填了正确的 Keybase_url是否指向https://taotoken.net/api。如果用的是环境变量确认变量名和工具要求的一致。Key 可以在控制台的 API Keys 页面重新生成。5.3 local proxy failed现象报 local proxy failed 或连接超时。原因可能是本地网络配置问题或者 Base URL 填成了带路径的地址。排查路径确认base_url只填到域名和/api不要带多余路径。检查本地是否有其他进程占用了端口。如果用的是公司网络确认没有拦截。5.4 reading choices 报错现象返回结果里出现 reading choices 相关错误。原因通常是模型返回格式和工具预期不一致可能是 Model ID 填错了。排查路径确认model字段填的是工具支持的模型 ID不要填成别的厂商的模型名。如果用的是 Coding Plan 或 Agent 场景确认套餐类型和模型匹配。5.5 OAuth 相关报错现象OAuth token 失效或认证失败。原因可能是 token 过期或者配置文件里的认证方式冲突。排查路径重新走一遍认证流程确认配置文件里没有同时存在 OAuth 和 API Key 两种认证方式。如果用的是 Codex 的auth.json确认里面的字段和工具版本匹配。6. 把规则文件当成团队资产来维护这次改动本身很小多了一条回退读取路径加了一个/config开关还限定了三个后端平台不支持。但它背后是一条值得投入时间的趋势——项目级指令文件正在从一个工具的私有配置变成多个工具共享的约定。如果你手上堆着一批只服务单一工具的规则文件可以从三件事开始先把构建、测试、风格这类与工具无关的规则抽出来独立成一份 AGENTS.md再按目录层级拆出子项目专用的部分最后用一次对照实验确认它真的被读到了。规则放在哪份文件里是细节能被工具稳定读到、内容可验证才是这套机制真正的价值。如果你还没配好 API 接入可以先到 TaoToken API Keys 生成 Key再对照 接入文档 把 Base URL 和 Model ID 填全。想先验证模型对话效果可以直接用 模型对话 试一轮如果是长期编码或 Agent 场景Coding Plan 会更合适。