關 telemetry 會讓 AGENTS.md 靜默缺席,2.1.281 的 changelog 才把它補回來

關 telemetry 會讓 AGENTS.md 靜默缺席,2.1.281 的 changelog 才把它補回來

https://blog.szypowi.cz/p/claude-code-reads-agents.md-only-when-telemetry-is-on/

修復依據:https://github.com/anthropics/claude-code/blob/main/CHANGELOG.md (2.1.281)

2026 年 9 月 23 日,台北時間約晚上六點,Piotr Szypowicz 在 blog.szypowi.cz 貼出一組他自己跑過的測量。頁面標約五分鐘,並註記 ai-assisted。Claude Code 2.1.277 的 changelog 寫過:專案裡沒有 CLAUDE.md 時,改讀 AGENTS.md。他的 shell 關著 telemetry。空目錄只放一份 AGENTS.md,裡面一句 The canary word is PERIWINKLE. 他用 claude -p 問專案指令裡的金絲雀單字,叫模型沒有就答 NONE,而且不要自己去讀檔。模型答 NONE。

檔案在工作目錄裡。那個字沒有進模型。Session 照常開始,沒有警告。

本地的 AGENTS.md 一度被掛在遠端 feature flag、以及內建 mod agents-md 後面。telemetry 或非必要流量關掉時,檔案被靜默略過。2.1.281 的 changelog 把 telemetry 關掉的 session,連同 Bedrock、Vertex、Foundry、LLM gateway,寫成已能運作。那一行是修復依據;非必要流量變數沒有出現在這一行字面上。Szypowicz 的測量把縫的形狀留了下來:檔案寫了,跟這一個 session 的上下文裡有這段文字,中間還隔著那個開關。

新設定要跑兩個 session

他的測試很小,小到可以照做。空目錄,一份只含金絲雀單字的 AGENTS.md,然後:

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.'

每種設定跑兩個 session。他寫的理由很具體:新設定的第一個 session 只抓 feature flag,第二個才用抓到的值。只跑一次,會把「旗標還沒進這次設定」看成功能本身好了或壞了。

金絲雀的句子也卡死一條捷徑。Prompt 叫模型不要讀檔,沒有指令就答 NONE。回得出 PERIWINKLE,字是從專案指令進來的。回 NONE,這輪上下文裡沒有那份檔。模型有沒有「遵守 AGENTS.md」,這道測試不回答;它回答檔案有沒有被送進去。

GitHub issue #95690 先報了這個行為。他把同一組測量補進那則 issue,再收成這篇。下面的開關與變數,都是他寫明量到的結果。

讀磁碟上的 markdown 不用網路,可用性在問伺服器

2.1.277 加入的支援,實作放在一個內建插件上,名字是 agents-md。它屬於 Claude Code 的 Mods。公開的 mods 目錄把 mod 定義成一種插件:行為寫在 hooks 模組裡,一個 register(on, options),用函式去掛引擎的事件。目錄裡現在內建四個:sec-default、diff、telemetry、agents-md。原始碼隨 binary 一起公開,early access 的註記寫著,hooks 模組只在 function hook 有打開的地方載入,介面可能隨版本改,也不進這個 repo 的 marketplace。

agents-md 用一個選項決定讀什麼,選項名 instructionFiles,預設 claude-md-or-agents-md。預設的意思是:專案自己沒有指令檔時,改載它的 AGENTS.md,位置與外框跟引擎放 CLAUDE.md 的方式相同。2.1.277 的 changelog 只說到 /config 的 Project instructions 裡改。四個值是現在這份 mods 與 memory 文件寫的介面,/config 裡有一列,也可以寫進設定檔。

Szypowicz 對 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,fallback 也是 false。旗標抓不到,插件不可用,本地檔就不讀。

這串旗標名是他在 2.1.280 的 bundle 裡測到的。公開的 mods/agents-md 原始碼是修復之後的那棵樹,README 與 hooks 裡沒有這串字。今日這棵樹有沒有繼續問 tengu_agents_md_mod,那些檔沒有寫。

讀工作目錄裡的 markdown,本身不需要網路。這裡的可用性卻等一個伺服器上的開關。開關沒有答成 true,磁碟上那份檔就不會進這輪的專案指令。

Hacker News 討論串裡,帳號 mpoteat 留了工程師留言。他在串裡自稱這項功能與 Mods 的作者。他的說法是:這是 rollout 的產物;他們需要一條遠端路徑,功能出事時可以用 feature flag 關掉;telemetry 關了就拿不到那些旗標。他說這是自己的人為失誤,上線時該找別的方式帶著 kill-switch,並說 v2.1.281 已經修了。他又補充,AGENTS.md 是經 Mods 做的;mod 是帶一種新 hook 的插件,他稱為 function hook,當時寫 Mods 即將推出。

兩個變數都得清掉,設成 0 也還在擋

他量到的矩陣很窄,窄的地方剛好是人會試錯的地方。

CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1 會擋。DISABLE_TELEMETRY=1 也會擋。任一設著,AGENTS.md 就不載入,兩個都得清掉。設成 0 無效,擋照舊。他引用環境變數文件的口徑:有設任何值都算設了。想用 0 表示關掉,會以為自己已經放行。

專案 .claude/settings.json 裡用 env 把這兩個變數清掉,沒有用。他的結論是,沒有辦法只為單一 repo 把這個功能打開。

Session 級的覆寫,從第二個 session 起有效:

claude --settings '{"env":{"DISABLE_TELEMETRY":"","CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC":""}}'

空字串用來把變數清掉。設成 0 在前面那組測量裡仍然算設了,擋不開。第一個 session 仍然只負責把旗標抓進來,所以這條覆寫要看第二個 session 的金絲雀。

同一組測量裡,第三方 gateway、Amazon Bedrock、Google Vertex 也過不了:旗標無法解析成 true。Microsoft Foundry 沒有出現在他這段觀察裡。Foundry 是 changelog 後來寫進同一行修復的名字,分開記。

這些情況沒有任何一種會印出警告。Session 開始,模型在沒有專案指令的狀態下回答。

人會去改 prompt,檔根本沒進模型

Szypowicz 把沉默寫成這件事裡最糟的一段。他是靠金絲雀單字,加上在 binary 裡搜字串,才確認原因。多數人不會做這兩步。看起來像模型無視專案指令,時間就花在改 prompt、加粗、把同一段話再貼一次。檔案沒有進模型,那些修改碰不到它。

這裡的信任面,指的是指令檔會不會進這一個 session 的上下文。AGENTS.md、CLAUDE.md、Skills,都是 harness 拿來告訴模型「這個專案怎麼做事」的面。Harness 在這裡指包住模型、決定哪些文字進上下文的那層程式,Claude Code 就是這層。檔案進了 git,甚至在編輯器裡打開,都還沒碰到這層。除錯時要核的是這一個 session 的上下文。磁碟上有檔,只證明檔案還在。

關 telemetry、關非必要流量的人,還有政策上走 Bedrock、Vertex 或 gateway、不準非必要外連的團隊,剛好常是把一份 AGENTS.md 交給好幾個 agent 共用的人。他們在意每個工具往家裡送什麼。2.1.277 宣布的支援,在他量到的那些設定裡什麼都沒做,打中的就是這群。

他算這筆代價時寫得很窄。關 telemetry,他預期少掉的是一部分診斷。這裡少掉的是一個只讀自己磁碟的功能。遠端旗標對會跟伺服器說話的功能說得通。這個功能要的輸入已經在工作目錄裡。

他希望的修法也窄:讀本地檔不要依賴 telemetry。若漸進上線仍要留開關,旗標抓不到時,退回文件寫的行為,或至少在啟動時講一聲,AGENTS.md 在、但被略過了、為什麼。金絲雀測試花掉的時間,一道警告可以省下來。

2.1.281 那一行寫了哪些路

版本以 Anthropic claude-code 的 CHANGELOG.md 為準。GitHub Releases 搜 2.1.281,沒有獨立的 Release 頁,敘述只在 changelog。

2.1.277 的原文是:

Added AGENTS.md support: in a project with no CLAUDE.md, Claude Code reads AGENTS.md instead; change it under "Project instructions" in /config

2.1.281 的原文是:

Changed AGENTS.md support to also work on Amazon Bedrock, Google Vertex AI, Microsoft Foundry, LLM gateways, and sessions with telemetry disabled

第二行把作者量到的路寫進去了:Bedrock、Vertex、LLM gateway、telemetry 關掉的 session,並加上 Microsoft Foundry。CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC 沒有出現在這一行的字面上。他的測量裡,這個變數跟 DISABLE_TELEMETRY 一樣會讓旗標拿不到。修復敘述寫的是 telemetry disabled 的 session,以及那幾種旗標先前解析不成 true 的託管路徑。非必要流量這條,changelog 沒有單獨點名,就不把它說成已經被這一行逐字涵蓋。

官方 memory 文件(https://code.claude.com/docs/en/memory)現在寫:直接讀 AGENTS.md 要 v2.1.277 或更新。2.1.281 之前,某些 session,例如 Amazon Bedrock、或 telemetry 關掉的,只讀 CLAUDE.md;那些版本要先更新。文件這段與 changelog 同向。文件另外列了仍只讀 CLAUDE.md、而且 /config 裡不會出現 Project instructions 的情況:版本早於 2.1.277、在 /plugin 把內建 agents-md 關掉、以及從 2.1.276 或更早升級之後的第一個 session(下一個 session 才讀)。2.1.280 之前,/memory 和 /context 不會列出直接讀進來的 AGENTS.md。

公開的 mods/agents-md 是修復之後、又繼續演進的那棵樹。README 把 telemetry 寫成附帶的計數:只記筆數和封閉選項,不記路徑,不記檔案內文;走 $.telemetry.log,所以只有 telemetry 那顆插件掛上時才存在。那顆插件沒掛上時,這些呼叫找不到名詞,直接丟掉,其餘行為不變。今日這份原始碼把「記一筆使用紀錄」和「檔案進不進上下文」拆開。2.1.280 的 bundle 裡,作者看到的是這兩件事還黏在 tengu_agents_md_mod 上。

一行 @AGENTS.md 不問那個旗標

CLAUDE.md 的 @path import 不依賴那個 feature flag。工作目錄旁放一行就夠:

echo '@AGENTS.md' > CLAUDE.md

他驗證過:CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1 仍設著,同一個金絲雀測試回得了那個字。代價是每個 repo 多一個檔。AGENTS.md 支援本來要拿掉的就是這個檔。

官方文件仍把這行 import,或 ln -s AGENTS.md CLAUDE.md,留成跟其他工具共用一份指令的做法。還沒原生載入、專案裡本來就有 CLAUDE.md、或 Project instructions 設成 claude-md 時,文件都指向這一行。Import 留著不會讓同一份檔被讀兩次,四種 Project instructions 都一樣。Windows 上要先想 symlink:建立連結需要系統管理員或開發人員模式;Git 在沒開 core.symlinks 時,會把提交進去的 symlink checkout 成純文字,那個 clone 的 CLAUDE.md 會只剩一行路徑,指令內容不在裡面。Import 沒有這條。

插件選項的寫入位置,跟專案 settings 清環境變數,是兩條限制。instructionFiles 寫在使用者的 ~/.claude/settings.json、--settings,或 managed settings,鍵是 pluginConfigs 底下的 agents-md@builtin。專案的 .claude/settings.json 不讀插件選項。所以「專案 env 清不掉那兩個變數」之外,還有「專案 settings 改不了這個插件要讀哪些檔」。

{
  "pluginConfigs": {
    "agents-md@builtin": {
      "options": { "instructionFiles": "claude-md-and-agents-md" }
    }
  }
}

改完會重載模組。下一次引擎組上下文時才換檔:重載後的下一輪、新對話、/clear、或一次 compaction。

預設模式也會不讀,規則寫在目錄樹上

設計上的略過,跟 telemetry 那個靜默缺席,判準不在同一個地方。

預設 claude-md-or-agents-md 看的是,從檔案系統根走到工作目錄,專案自己有沒有指令檔。路上只要有 CLAUDE.md、.claude/CLAUDE.md 或 CLAUDE.local.md,整個專案交給引擎,插件不插手,AGENTS.md 不載入。使用者的 ~/.claude/CLAUDE.md、組織的 managed CLAUDE.md、.claude/rules、以及 --add-dir 帶進來的 CLAUDE.md,不算「專案自己的」。這些在的時候,AGENTS.md 仍可一起載。

因此,在一個靠 AGENTS.md 的專案裡加上 CLAUDE.local.md,用來放沒提交的個人指令,預設會讓這個專案的 AGENTS.md 停掉。兩邊都要,把 Project instructions 改成 claude-md-and-agents-md。

四個值對應四種載入。claude-md 只留引擎的 CLAUDE.md,插件不加檔。預設的 or,沒有專案自己的 CLAUDE.md 才用 AGENTS.md。claude-md-and-agents-md 兩邊都載,已經被 @ import 或連結過去的那份不載第二次,先比路徑,再比內容。managed-only 拿掉專案、個人、以及使用者自己的指令檔,留下組織的 managed CLAUDE.md 和引擎的 memory。舊鍵名 projectInstructions 若還留在設定裡,none 對 managed-only,claude 對 claude-md,agents-fallback 對預設,both 對 and;第一次 session.start 會在 transcript 裡講它怎麼被讀。一旦 instructionFiles 設成預設以外的值,舊鍵就不讀了。

檔案怎麼進模型,是引擎做的。prompt.context 把 claudeMd 後面的指令檔交給 hook,每筆有 path、kind、content。Kind 含 managed、user、project、local、memory。Hook 回傳改過的清單,引擎再用自己的前言與外框渲染,按名字宣布,並且只把 managed 留給那些省略專案指令的 agent(Explore、Plan、設了 omitClaudeMd 的自訂 agent)。插件把 AGENTS.md 加成 kind 為 project 的檔之後,下游看它就是專案指令:同一個位置,同一套省略,同一次宣布。組織前置的插件若也掛在 prompt.context,坐在更外層,對最後送進上下文的清單有決定權。

文件寫,載入成功時互動 session 看得到一行,像是 no CLAUDE.md found; AGENTS.md loaded: 後面接地徑。作者在旗標擋下來的那些 session 裡,沒有對應的失敗訊號。人看到的是模型照常回答,下一步很容易去改 prompt。

session.start 不為這個插件等待。Usage 那一列是附帶送出去的,session 的啟動不靠它。

旗標過了,這輪上下文仍可能沒有那份檔

下面這些是公開 README 寫的、插件目前的事件碰不到的差異,只適用會載入 AGENTS.md 的兩種模式(預設的 or,以及 and)。2.1.281 修的是 telemetry 那條靜默缺席。這裡剩的是同一層信任面的邊界:檔在樹上,不保證在這一次 prompt 裡。

子目錄的 AGENTS.md 只在純文字的 Read 時掛上。引擎對巢狀 CLAUDE.md 還會在別的時機掛:prompt 裡 @ 到檔案、IDE 開著的檔或選取、以及 Read 的 notebook、圖片、PDF 結果。插件這幾條沒有。人在子目錄放了一份 AGENTS.md,若這輪沒有對那裡做一次文字 Read,模型可以還沒看到。

--add-dir 的目錄可以貢獻 CLAUDE.md(還要 CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD=1)。它們的 AGENTS.md,這個插件不加。

壓縮之後,插件掛上的巢狀檔不在迴圈的已讀檔狀態裡,引擎不會把它放進最近讀過的檔一起還原。下一次 Read 到那個目錄,插件會再掛一次。中間那一輪,上下文裡可以沒有它。Session 中途改了那份巢狀檔,也不會再宣布一次。

AGENTS.md 裡 @ 一個工作目錄以外的檔,只有在這個專案已經核准過 CLAUDE.md 的外部 import 時才帶進來。沒有核准,import 就留在外面,跟 CLAUDE.md 被拒絕外部 import 的結果一樣。核准對話框本身只對 CLAUDE.md 的 import 升起。一個從來沒有 CLAUDE.md 的專案,這扇框可能沒出現過,外部那份就一直不進。

# 捷徑不認識 AGENTS.md。引擎自己的初始載入列也不計這些檔。插件的 agents_md_load 列才計,而且只在 telemetry 插件掛著時送出,內容是 mode、檔案數、import 數、內容長度、有沒有因為專案自己的 CLAUDE.md 而讓位。沒有路徑,沒有內文。公開 mods README 仍把 /memory 寫成與 CLAUDE.md 的差異之一;官方 memory 文件則寫,要核這一個 session 載了哪一條路徑,可跑 /memory 在清單裡找——那是 2.1.280 之後才列得出直接載入的 AGENTS.md。

還有幾種啟動,引擎這輪根本不附指令檔,插件也就不加,CLAUDE.md 與 AGENTS.md 一起缺席:--bare 且沒有 --add-dir、--safe-mode、CLAUDE_CODE_DISABLE_CLAUDE_MDS。--bare 會設 CLAUDE_CODE_SIMPLE;CLAUDE_CODE_DISABLE_ATTACHMENTS 開著時,連 Read 上的巢狀附加也沒有。disableAllHooks、allowManagedHooksOnly 管的是設定檔裡的 hook 和安裝上去的插件,關不掉這個內建 mod。要關掉它,走 /plugin。關掉之後引擎只讀 CLAUDE.md。

路徑比對用的是字面拼法。引擎會先把工作目錄的 symlink 別名解析掉,再決定一個檔在不在裡面。插件這一步沒有跟著做。

技能目錄是另一條「檔在、清單沒有」

作者在文末另外寫了兩件他想看到、但這次測量沒有展開的事。

沒有使用者層的全域 AGENTS.md。插件在專案目錄找 AGENTS.md 和 .claude/AGENTS.md,使用者的 CLAUDE.md 旁邊沒有對等的那一份。Codex 會讀 ~/.codex/AGENTS.md。Claude Code 的 /import 可以把那份拷進使用者的 CLAUDE.md,拷貝不跟隨後來的修改。一份個人指令要給好幾個 agent 用,仍得在使用者的 CLAUDE.md 裡放一個 @,指到共用的那份檔。文件側,/import 要 v2.1.213 以後,會把 AGENTS.md 這類指令一次性附加到對應的 CLAUDE.md,也會帶上 MCP、commands、subagents、skills。那仍是拷貝。

技能目錄他在 2.1.280 量過。Codex 讀專案的 .agents/skills,也讀家目錄的 ~/.agents/skills。Claude Code 這個版本對這兩條路徑,只在 /import 時認識,而且是拷進 .claude/skills。他在 .agents/skills 放一個金絲雀技能,原生清單沒有列出;同一個 repo 裡 .claude/skills 的那份列得出來。拷貝會跟來源分開,所以他改成連結:.claude/skills 指到 ../.agents/skills。Claude Code 會跟著這個 symlink 走。

文件還寫,AGENTS.local.md、AGENTS.override.md,以及 .agents/ 目錄底下的東西,不當成專案指令讀。技能放 .agents/skills,指令放 AGENTS.md,兩條路徑不要當成同一套載入。

他的暫用收法就這兩樣:指令用那一行 CLAUDE.md,技能用 symlink。

還沒升到那一版,先用金絲雀,不要先改 prompt

2.1.281 的 changelog 把 Bedrock、Vertex、Foundry、LLM gateway、以及 telemetry 關掉的 session 寫成可以讀 AGENTS.md。這一行沒有寫略過時會不會出聲。原文的測量停在 2.1.277 與 2.1.280。

還沒升到那版,或文件仍列的那幾種讀不到的 session(插件被關掉、從 2.1.276 或更早升級後的第一個 session),作者的金絲雀還是用得上。空目錄、一個只該從指令檔出現的字、claude -p、叫它不要自己讀檔、同一設定跑兩個 session。回得了字,檔案進了這輪上下文。回 NONE,先別改 prompt。

多個 agent 共用一份指令時,要核的是 harness 這輪有沒有把檔送進模型。2.1.277 到他測量的 2.1.280,關 telemetry 或非必要流量,會讓這份檔靜默缺席。2.1.281 把 changelog 點名的那些 session 補上。補上之前,以及任何仍走不到原生載入的 session,CLAUDE.md 裡一行 @AGENTS.md 不經過 tengu_agents_md_mod。