🔶 Claude Code 仅在开启遥测时读取 AGENTS.md[已修复]
英文标题:🔶 Claude Code reads AGENTS.md only when telemetry is on [fixed]
Claude Code 2.1.277 宣布支持以 `AGENTS.md` 作为项目指令文件,但测试发现,当关闭遥测或非必要网络流量时,该文件不会被加载。原因是内置 `agents-md` 插件依赖远程功能开关 `tengu_agents_md_mod`,且开关无法获取时默认关闭,导致本地文件读取也被静默禁用。该问题同样影响第三方网关、Amazon Bedrock 和 Vertex 等无法解析该功能开关的环境;开发者可暂时通过在 `CLAUDE.md` 中使用 `@AGENTS.md` 导入来绕过。作者认为,隐私设置不应无提示地关闭与网络无关的本地功能,并建议提供警告、全局 `AGENTS.md` 和共享 Agent skills 的原生支持。
中文
Claude Code 2.1.277 宣布支持 AGENTS.md。在一个没有 CLAUDE.md 的项目中,它本应改为读取 AGENTS.md。我在 shell 中一直关闭遥测,而在我的仓库中,该文件从未被加载。Issue #95690 解释了原因,我也在其中补充了自己的测量结果。本文将这些信息汇总在一起。
开关位于何处
该加载器以名为 agents-md 的内置插件形式发布。它在 2.1.280 bundle 中的注册代码如下:
var W = !1;
var B = () => Oa("tengu_agents_md_mod", W);
var H =
"AGENTS.md as project instructions: by default loaded where the project has no CLAUDE.md; ...";
W 是该插件的 isOnByDefault 值,而它是 false。B 是 isAvailable,它会请求一个名为 tengu_agents_md_mod 的远程功能开关,并以 false 作为回退值。当 Claude Code 无法获取这个开关时,插件便不可用,本地文件也就永远不会被读取。
读取工作目录中的一个 Markdown 文件根本不需要网络,但在这里,它却要等待服务端开关的结果。
我的测试方法
我创建了一个空目录,目录中仅包含一个写有金丝雀词(canary word)的 AGENTS.md,然后要求 claude -p 回答该词。每种配置都在两个会话中运行,因为新配置下的第一个会话只会获取功能开关,第二个会话才会使用它。
echo 'The canary word is PERIWINKLE.' > AGENTS.md
claude -p 'What is the canary word from the project instructions? Answer NONE if you have none. Do not read files.'
我测得的结果
-
如该 issue 所述,
CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1会阻止该功能。 -
DISABLE_TELEMETRY=1也会阻止该功能。只要设置其中任一变量,AGENTS.md就永远不会加载,因此我必须同时清除两者。 -
将任一变量设置为
0并没有帮助,阻止状态依旧存在。环境变量文档说明,只要变量有任何值就会生效,但当你试图开启某项功能时,这一点很容易被忽略。 -
在项目
.claude/settings.json中添加env块以清除这两个变量也没有效果。没有办法仅为单个仓库开启该功能。 -
从第二个会话开始,会话级覆盖确实有效:
claude --settings '{"env":{"DISABLE_TELEMETRY":"","CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC":""}}'
这些情况都不会输出警告。会话会正常启动,模型会在没有项目指令的情况下作答,而且没有任何信息告诉你某个文件被跳过了。该 issue 还指出,第三方网关、Bedrock 和 Vertex 也存在同样的问题,因为在这些环境中,该功能开关同样无法解析为 true。
解决办法
CLAUDE.md 支持 @path 导入,而这种导入不依赖功能开关。在 AGENTS.md 旁边添加一行 CLAUDE.md,即使关闭遥测也能加载它:
echo '@AGENTS.md' > CLAUDE.md
添加该文件后,即使仍设置了 CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1,同样的金丝雀测试也会返回该词。代价是每个仓库都要多一个文件,而这正是 AGENTS.md 支持原本应该消除的负担。
为什么我认为这不可接受
我关闭遥测是有意为之,我预期这一选择的代价只是少一些诊断信息,而不是别的。现在,它却在没有提示的情况下让我失去了一个读取本机磁盘文件的功能。远程功能开关或许适用于需要与服务器通信的功能,但这个功能唯一需要的输入已经存在于工作目录中。
这个开关还会影响最可能关心 AGENTS.md 的人。为多个 Agent 维护同一份指令文件的人,通常会谨慎对待每个工具向外发送的内容;而使用 Bedrock、Vertex 或网关的团队,也经常因政策要求禁用非必要网络流量。他们得到的是一个被宣布可用、实际却毫无反应的功能。
最糟糕的是这种沉默。我通过金丝雀词和对二进制文件进行字符串搜索确认了原因,但大多数人不会这么做。他们会得出模型忽略其指令的结论,并把时间花在优化提示词上,而实际上文件从一开始就没有传递给模型。
隐私设置绝不应悄悄关闭无关的本地行为。如果 Anthropic 希望采用分阶段发布,那么无法获取功能开关时的回退行为应当是文档所述的默认行为;至少也应显示一条可见消息,说明跳过了什么以及原因。
我希望看到的改进
- 读取本地文件不应依赖遥测。如果这个开关必须保留以实现渐进式发布,那么当存在
AGENTS.md却被跳过时,在启动阶段显示警告,就能为用户节省我花在金丝雀测试上的时间。 - 提供全局
AGENTS.md。该插件只会在项目目录中查找AGENTS.md和.claude/AGENTS.md,而在用户级CLAUDE.md旁并不存在用户级文件。Codex 会读取全局~/.codex/AGENTS.md,Claude Code 的/import命令可以将其复制到用户CLAUDE.md,但该副本不会跟随后续编辑。如果你要为多个 Agent 维护一套个人指令,仍然需要在用户CLAUDE.md中通过@导入指向共享文件。 - 原生支持共享 Agent skills。Codex 会从项目中的
.agents/skills以及主目录中的~/.agents/skills读取 skills。Claude Code 2.1.280 仅在/import中识别这些路径,并会将 skills 复制到.claude/skills。我在.agents/skills中放置了一个金丝雀 skill,Claude Code 没有将其列出;但在同一仓库中,它能列出.claude/skills内的同一个 skill。复制文件会与源文件逐渐偏离,因此我改为将.claude/skills链接到../.agents/skills,而 Claude Code 可以跟随该符号链接。
在此之前,我会继续使用单行 CLAUDE.md 来加载指令,并使用符号链接来共享 skills。
English / 原文
Claude Code 2.1.277 announced support for AGENTS.md. In a project with no CLAUDE.md, it is supposed to read AGENTS.md instead. I keep telemetry off in my shell, and in my repos the file never loaded. Issue #95690 explains why, and I added my own measurements to it. This post collects them in one place.
Where the gate is
The loader ships as a built-in plugin called agents-md. Its registration in the 2.1.280 bundle looks like this:
var W = !1;
var B = () => Oa("tengu_agents_md_mod", W);
var H =
"AGENTS.md as project instructions: by default loaded where the project has no CLAUDE.md; ...";
W is the plugin’s isOnByDefault value and it is false. B is isAvailable, and it asks a remote feature flag called tengu_agents_md_mod, with false as the fallback. When Claude Code cannot fetch the flag, the plugin is unavailable, and the local file is never read. Reading a markdown file from the working directory needs no network at all, but here it waits on a server-side switch.
How I tested it
I made an empty directory that holds only an AGENTS.md with a canary word in it, and asked claude -p for the word. Each setup ran in two sessions, because the first session in a new configuration only fetches the flag and the second one uses it.
echo 'The canary word is PERIWINKLE.' > AGENTS.md
claude -p 'What is the canary word from the project instructions? Answer NONE if you have none. Do not read files.'
What I measured
-
CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1blocks the feature, as the issue says. -
DISABLE_TELEMETRY=1blocks it too. With either variable set,AGENTS.mdnever loaded, so I had to clear both. -
Setting either variable to
0does not help. The block stays in place. The environment variable docs say that any value counts, but that is easy to miss when you try to turn a feature on. -
An
envblock in the project’s.claude/settings.jsonthat clears both variables has no effect. There is no way to turn the feature on for a single repo. -
A session-level override does work from the second session on:
claude --settings '{"env":{"DISABLE_TELEMETRY":"","CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC":""}}'
None of these cases print a warning. The session starts, the model answers without the project instructions, and nothing tells you that a file was skipped. The issue also points out that third-party gateways, Bedrock and Vertex have the same problem, because the flag cannot resolve to true there either.
The workaround
CLAUDE.md supports @path imports, and those do not depend on the flag. A one-line CLAUDE.md next to the AGENTS.md loads it with telemetry off:
echo '@AGENTS.md' > CLAUDE.md
With that file in place, the same canary test returns the word with CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1 still set. The cost is one extra file per repo, which is what the AGENTS.md support was supposed to remove.
Why I think this is unacceptable
I turned telemetry off on purpose, and I expect that choice to cost me some diagnostics and nothing else. Here it silently costs me a feature that reads a file from my own disk. A remote flag can make sense for a feature that talks to a server, but the only input this one needs is already in the working directory.
The gate also hits the people who are most likely to care about AGENTS.md. Someone who keeps one instruction file for several agents is usually careful about what each tool sends home, and teams on Bedrock, Vertex or a gateway often disable nonessential traffic by policy. They all get a feature that is announced as available and then does nothing.
The silence is the worst part. I confirmed the cause with a canary word and a string search through the binary, and most people will not do that. They will conclude that the model ignores their instructions, and they will spend time on prompts when the file never reached the model in the first place.
A privacy setting should never quietly switch off unrelated local behavior. If Anthropic wants a staged rollout, the fallback for a flag that cannot be fetched should be the documented behavior, or at least a visible message that says what was skipped and why.
What I would like to see
- Reading a local file should not depend on telemetry. If the gate has to stay for a gradual rollout, a startup warning when an
AGENTS.mdis present and skipped would save people the time I spent on a canary test. - A global
AGENTS.md. The plugin looks forAGENTS.mdand.claude/AGENTS.mdin project directories only, and there is no user-level file next to the userCLAUDE.md. Codex reads a global~/.codex/AGENTS.md, and the/importcommand in Claude Code can copy it into the userCLAUDE.md, but the copy does not follow later edits. If you keep one set of personal instructions for several agents, you still need an@import in the userCLAUDE.mdthat points at the shared file. - Native support for shared agent skills. Codex reads skills from
.agents/skillsin the project and from~/.agents/skillsin the home directory. Claude Code 2.1.280 knows those paths only in/import, which copies the skills into.claude/skills. I put a canary skill in.agents/skillsand Claude Code did not list it, but it listed the same skill from.claude/skillsin the same repo. A copy drifts from the source, so I link.claude/skillsto../.agents/skillsinstead, and Claude Code follows that symlink.
Until then, I use the one-line CLAUDE.md for instructions and a symlink for skills.