Claude Code 支持 AGENTS.md 后,我删了全局 CLAUDE.md,规则静默失效了一周

Claude Code 2.1.277 开始原生读取 AGENTS.md,我据此删掉了 ~/.claude/CLAUDE.md,只保留 ~/.claude/AGENTS.md,结果全局规则在 Claude Code 里失效了一周。原因是这个回退机制只作用于工作目录及其上级目录,不覆盖用户级目录。本文记录排查过程、官方文档与 agents-md mod 源码里的依据,正确的配置方式,以及用户级、项目级、CLAUDE.local.md 和自动记忆各自的加载规则。

Claude Code 宣布支持 AGENTS.md 的当天,我删掉了全局的 ~/.claude/CLAUDE.md。

之后整整一周,我写在全局配置里的规则在 Claude Code 里一条都没生效。没有报错,没有提示,Claude 照常干活,只是不再知道那些规则。

问题出在一个词上:公告里说的「folder」。

我当时是怎么配置的

我同时用 Claude Code 和 Codex,希望两边共用一份全局规则。原来的做法是:

  • 规则写在 ~/.claude/AGENTS.md
  • ~/.codex/AGENTS.md 软链到这个文件
  • ~/.claude/CLAUDE.md 里只有一行 @AGENTS.md,把它引入给 Claude Code

这是 Claude Code 不认识 AGENTS.md 时的标准做法,一直工作正常。

9 月 19 日,Claude Code 团队的 Thariq 发了一条推文:

We’re adding support for AGENTS.md to Claude Code.

Starting today in version 2.1.277, if there is no CLAUDE.md in a folder, Claude will check for and use AGENTS.md.

Thariq 宣布 Claude Code 支持 AGENTS.md 的推文,下方回复说明它基于 Claude Code mods 实现

我的理解是:~/.claude 也是一个 folder,里面只要没有 CLAUDE.md,Claude 就会去读 AGENTS.md。那个只写了一行 @AGENTS.md 的 CLAUDE.md 已经是多余的中间层,删掉,单一数据源更干净。

我还在 AGENTS.md 开头留了一行注释:

<!-- 单一数据源:Claude Code 原生支持无 CLAUDE.md 时回退读 AGENTS.md,故不再用 ~/.claude/CLAUDE.md 做 @AGENTS.md 引入 -->

这行注释本身就是错的。

删文件、写注释,都是我让 Claude Code 做的。当时用的是 还是 Opus 5,Opus 5.5 要到 9 月 22 日才发布,而 Opus 5 发布后的口碑普遍不好。它照着我的理解改完了配置,没有指出这个理解有问题。

怎么发现的

一周后,我在一个博客项目里整理配置,发现一件事:会话开始时加载进来的只有项目的 CLAUDE.md 和记忆文件,全局 AGENTS.md 里的 GitHub 双账号规则、本地 Postgres 端口约定,都不在上下文里。

为了排除「是不是 Claude 没注意到」,我用 claude -p 起一个全新会话,禁用读文件的工具,让它只凭启动时加载的内容回答:

claude -p "不要读取任何文件,不要调用工具。只根据你启动时上下文里已加载的指令回答:有没有关于 GitHub 双账号或本地 Postgres 端口的规则?有就原样引用一句,没有就回答『没有』。" --disallowedTools "Read,Bash,Grep,Glob"

两种配置各跑一次:

~/.claude 的状态 结果
只有 AGENTS.md 「没有」
CLAUDE.md 里写一行 @AGENTS.md 原样引用了两条规则

Claude Code 版本是 2.1.283,满足 2.1.277 的要求,不是版本问题。只有 AGENTS.md 时,它确实读不到。

原因:「folder」指的是项目目录链

推文里的「a folder」没有限定范围。真正的范围写在官方文档和 mod 源码里。

官方文档

Claude Code 的 memory 文档对 AGENTS.md 的定位是项目说明:

Claude Code can read AGENTS.md as your project instructions, so a repository already set up for other coding agents works without adding a CLAUDE.md …

读取范围是工作目录及其上级目录:

By default, Claude reads AGENTS.md only when you have no CLAUDE.md in your working directory or above it.

At session start: every AGENTS.md and .claude/AGENTS.md in your working directory and the directories above it.

而用户级文件的位置表里,全局配置只有一个:

User instructions:~/.claude/CLAUDE.md

整篇文档没有出现过 ~/.claude/AGENTS.md。

mod 源码

Thariq 在推文下面补充说,AGENTS.md 支持是基于 Claude Code mods 实现的内置 mod,源码在 anthropics/claude-code/mods/agents-md。

README 的「What it hooks」一节,第 94 行描述了它在每轮组装上下文时做的事:

walks $.fs.ancestors for the AGENTS.md files above the working directory and answers them as project instruction files

从工作目录往上逐级找 AGENTS.md,找到的当作 project 类型加载。

我的工作目录是 ~/Documents/myblog/techblog,往上依次是 ~/Documents/myblog、~/Documents、~、/。这条路径不经过 ~/.claude。

用户级的 ~/.claude/CLAUDE.md 是 Claude Code 按固定路径单独加载的,不在这次逐级查找里。mod 只接管了项目目录链这一条路径,用户级没有对应的 AGENTS.md 版本。

推文里说的「在 /config 里切换」,对应的是 /config 中的 Project instructions 这一项,也就是 mod 唯一的配置项 instructionFiles:

/config 中 Project instructions 的四个选项,默认是 claude-md-or-agents-md

设置项的名字就叫「Project instructions」,默认值的说明里,主语也是「a project」(a project with no … gets its AGENTS.md files instead)。四个选项管的都是项目说明,即使切到 claude-md-and-agents-md,多读的也只是项目链上的 AGENTS.md。

正确的配置

用户级仍然用引入的方式:

# ~/.claude/CLAUDE.md
@AGENTS.md
  • ~/.claude/AGENTS.md:放全部规则
  • ~/.codex/AGENTS.md:软链到上面的文件
  • ~/.claude/CLAUDE.md:只有一行 @AGENTS.md

~/.claude 目录下 AGENTS.md 和 CLAUDE.md 两个文件并存

文档里「Remove an earlier AGENTS.md workaround」一节确实教人删掉旧的 @AGENTS.md 引入,但它针对的是项目里的 CLAUDE.md。项目级现在有原生支持,用户级从来没有。所以全局这一行引入不是过时写法,而是目前唯一的办法。

把加载模型补全

这次踩坑,根源是我脑子里只有一张模糊的图:「Claude Code 会读一些 CLAUDE.md」。把 memory 文档从头读完,完整的图是这样的:

层级 位置 什么时候进上下文 谁写
组织策略 macOS 上是 /Library/Application Support/ClaudeCode/CLAUDE.md 启动时,个人设置排除不掉 IT / 运维
用户级 ~/.claude/CLAUDE.md、~/.claude/rules/*.md 启动时 你
项目级 工作目录及每一级上级目录的 CLAUDE.md、.claude/CLAUDE.md(都没有时回退到 AGENTS.md),以及项目的 .claude/rules/*.md 启动时 团队,进版本库
本地级 同一条目录链上的 CLAUDE.local.md 启动时 你,加进 .gitignore
子目录 工作目录下层的 CLAUDE.md / CLAUDE.local.md,带 paths 的 rules Claude 读到对应文件时 同项目级
自动记忆 ~/.claude/projects/<project>/memory/MEMORY.md 启动时,只读前 200 行或 25KB Claude
记忆主题文件 同一目录下的其他 .md Claude 需要时自己去读 Claude

表里藏着几件比「有哪些文件」更值得注意的事。

三种加载方式,AGENTS.md 只接进了一种

这些文件按三种方式进入上下文:

  • 固定路径:组织策略、~/.claude/CLAUDE.md、~/.claude/rules/。不管在哪个目录启动,都去同一个位置读
  • 目录链:从工作目录往上一直走到根目录,沿途的 CLAUDE.md、.claude/CLAUDE.md、CLAUDE.local.md
  • 按需:子目录的 CLAUDE.md、带 paths 的 rules、记忆主题文件,碰到相关文件才加载

AGENTS.md 回退只挂在目录链上,而用户级走的是固定路径。我的坑就落在这两条路径的缝隙里。

反过来,家目录 ~ 本身在目录链上。~/CLAUDE.md 不是用户级配置,而是家目录下每个项目都会读到的「项目级」文件。按文档的判定规则,工作目录或任一上级目录只要有 CLAUDE.md,就不读 AGENTS.md。所以一个 ~/CLAUDE.md,会让家目录下所有仓库的 AGENTS.md 回退一起失效。~/.claude/CLAUDE.md 反而不参与这个判定,能和项目的 AGENTS.md 同时加载。

拼接,不是覆盖

所有找到的文件都拼进上下文,谁也不覆盖谁。顺序是组织策略、用户级、项目级;目录链上从根目录往下读到工作目录,同一级目录里 CLAUDE.local.md 接在 CLAUDE.md 后面。

「项目规则覆盖全局规则」是个很自然的直觉,但它是错的。后读的只是位置靠后,不是优先级更高。文档对冲突的描述是:

if a user rule and a project rule conflict, Claude may follow either one

两条规则打架时,Claude 可能随便挑一条。必须保证的行为不该靠 CLAUDE.md 的先后顺序,而应该交给 hook 或 settings 里的 permissions,这两个由客户端执行,不依赖 Claude 的判断。

CLAUDE.local.md:私人补丁,也是 AGENTS.md 的开关

CLAUDE.local.md 放在项目根目录,写只和自己有关的东西,比如本机的测试地址、个人习惯,加进 .gitignore 不提交。它和 CLAUDE.md 一样加载,排在同级 CLAUDE.md 后面。

它有两个不太显眼的副作用。

第一,它算作 CLAUDE.md。一个只靠 AGENTS.md 的仓库,你加一个 CLAUDE.local.md 记私人笔记,Claude 就不再读 AGENTS.md 了。和我遇到的一样,这也是静默的。文档给的解法是把 Project instructions 设成 claude-md-and-agents-md。

第二,它被 gitignore,所以只存在于创建它的那个 worktree。多个 worktree 要共用个人说明,文档建议在 CLAUDE.md 里引入家目录下的文件,比如 @~/.claude/my-project-instructions.md。

自动记忆:Claude 的笔记,不是你的规则

自动记忆和前面几层性质不同。前面的都是你写给 Claude 的指令,自动记忆是 Claude 写给自己的笔记:

  • 按 user、feedback、project、reference 四类记录。你对 Claude 说「记住……」,存进的是这里,不是 CLAUDE.md
  • 按 git 仓库划分,同一仓库的子目录和 worktree 共用一份;只存在本机,不跨机器同步
  • 启动时只加载 MEMORY.md 这个索引的前 200 行或 25KB,超出的部分直接丢掉;具体内容在主题文件里,Claude 判断需要时才去读
  • 不会传给 subagent(fork 出来的除外)
  • CLAUDE.md 里已经写了的,它不会重复记

所以它适合放纠正和偏好,不适合放必须每次生效的规则:索引可能被截断,主题文件读不读取决于 Claude 自己,换一台机器就没有了。一条规则如果漏掉会出事,就应该写进 CLAUDE.md。

公告是摘要,文档才是规格

这次踩坑,推文本身没说错,只是省略了范围。「in a folder」对大多数人的用法(在仓库根目录放一个 AGENTS.md)是准确的,偏偏我的用法落在了省略掉的那部分。

更麻烦的是失败方式:静默。Claude Code 不会提示「你的全局 AGENTS.md 没被加载」,它只是少知道一些事,然后照常回答。规则失效和规则被遵守,从外面看不出区别。

以后看到类似的功能公告,我会先做两件事再动配置:

  1. 用 /context 看 Memory files 列表,确认实际加载了哪些文件(/memory 列出的是所有可能的位置,包括还不存在的文件)
  2. 找到文档里描述范围的那一段,而不是只看公告

关于

关注我获取更多资讯

月球基地博客公众号二维码,扫码关注获取更多 AI 与编程资讯
📢 公众号
月球基地博客作者个人微信二维码,扫码交流 AI 与编程话题
💬 个人号
使用 Hugo 构建
主题 Stack 由 Jimmy 设计