單一儲存庫如何設計巢狀 AGENTS.md
大型根目錄 AGENTS.md 容易過時並浪費 context。了解根目錄與各服務目錄的巢狀配置,避免載入不相關規則,提升 agent 遵循度。
單一儲存庫中的巢狀 AGENTS.md 代表在儲存庫根目錄放置一個小型檔案,並在每個服務目錄內再放置一個檔案。根目錄檔案只放置所有目錄都適用的少數規則,以及其他檔案所在位置的對照資訊。每個服務檔案則只放置該目錄適用的命令與慣例。代理程式編輯 services/worker/queue.py 時,會先讀取根目錄檔案和 worker 檔案,因此完全不會耗用內容空間處理不會碰到的前端。
無須安裝任何項目。AGENTS.md 是一種慣例,上游專案也明確如此說明:
AGENTS.md 只是標準 Markdown。標題可依需求使用;代理程式只會解析你提供的文字。
這正是值得完整學習這項技術的原因。格式不會任意變更。真正容易出問題的是檔案位置與維護,而這兩項工作都由你負責。
為什麼一份大型根目錄 AGENTS.md 會失效?
在同時包含 Web 應用程式、背景 worker 與 Terraform 目錄的 repository 根目錄放置一份 600 行的 AGENTS.md,會產生四個問題。
它會逐漸過時,因為沒有人負責維護。 在 apps/web 中重新命名測試指令碼的工程師,實際修改的是 apps/web 下的檔案。根目錄的 AGENTS.md 不在該次 diff 中,因此沒有 reviewer 會看到不一致。六週後,檔案仍描述著早已不存在的建置步驟,而造成問題的人也已忘記當時的修改。
每項工作都會消耗額外的上下文。 這些檔案會在工作階段開始時載入,早於 agent 知道你要提出什麼要求。Claude Code 的文件提供了明確數字:「每個 CLAUDE.md 檔案建議控制在 200 行以內。較長的檔案會消耗更多上下文,並降低遵循程度。」Codex 在合併的指示檔案總大小達到 32 KiB(預設值 project_doc_max_bytes)後,就會停止繼續合併。若根目錄檔案同時記錄四個服務,每項工作都會為其中三個服務消耗上下文額度。
指示會開始互相矛盾。 Web 目錄需要 pnpm test。worker 需要 pytest -q。把這些規則寫在同一份檔案中後,每條規則只在部分情況下正確,因此 agent 必須猜測目前適用哪一條。Claude Code 的文件描述了這個結果:「如果兩條規則互相矛盾,Claude 可能會任意選擇其中一條。」分目錄放置檔案可以消除這種猜測,因為兩條規則不會同時出現在上下文中。
檔案會塞滿 agent 可以直接從程式碼讀取的資訊。 例如目錄樹、相依套件清單,以及各套件功能的摘要。Claude Code 的 /doctor 檢查正是用來移除這類內容。它會「刪除 Claude 可從 codebase 推導出的內容,例如目錄配置、相依套件清單與架構概觀」,並保留「陷阱、決策理由,以及不同於工具預設值的慣例」。這句話是我所知道判斷某行內容是否應該放入檔案的最佳標準。
代理程式會讀取根目錄檔案,還是只讀取最近的檔案?
這是多數人最容易誤解的地方,因此值得直接引用上游慣例,而不是改寫其內容:
在每個套件內再放置一個 AGENTS.md。代理程式會自動讀取目錄樹中最近的檔案,因此最近的檔案優先,每個子專案都能提供符合自身需求的指示。
關於衝突,文件說明如下:
距離遭編輯檔案最近的 AGENTS.md 優先;明確的使用者聊天提示則覆寫所有內容。
「優先」對許多人而言表示「根目錄檔案會被忽略」。實際上並非如此。在實作此慣例的工具中,會讀取從儲存庫根目錄到工作目錄路徑上的每個檔案,然後將內容合併。只有在兩個檔案針對同一主題提出不同指示時,最近的檔案才會優先。
Codex 明確說明了這項機制:「Codex 會從根目錄開始串接檔案,並以空白行分隔。距離目前目錄較近的檔案會覆寫較早的指示。」Claude Code 也會針對自身的檔名沿著相同路徑搜尋。工作目錄上層目錄中的檔案「會在啟動時完整載入」,而且「所有找到的檔案都會串接到上下文中,不會彼此覆寫」。工作目錄下方的目錄則不同:Claude Code 會在「讀取這些目錄中的檔案時」依需求載入其中的檔案。
這會帶來兩項實務上的結果。根目錄檔案會成為儲存庫每個工作階段的前置內容,因此其中每一行都應視為每週會重複付出上百次成本的內容。代理程式在其他位置工作時,不會載入特定目錄的檔案,因此在該處提供詳細指示的成本較低,詳細內容也應放在該處。
此行為已於 2026 年 8 月依據 Codex 與 Claude Code 的文件完成確認。不同工具的實作方式略有差異,而且規則也可能變更,因此請確認團隊所使用代理程式的載入規則。
適用於包含 3 個服務之 repository 的配置範例
repo/
AGENTS.md rules true everywhere, plus the map
apps/web/AGENTS.md TypeScript client, Vite, Vitest
services/worker/AGENTS.md Python queue consumer, pytest
infra/AGENTS.md Terraform and the deploy scripts根目錄檔案刻意保持簡短。它指出應查看的位置,且只包含適用於所有目錄的規則。
# AGENTS.md
This is a monorepo. Each top-level directory ships its own AGENTS.md.
Read this file and the AGENTS.md nearest the code you are editing
before you change anything.
- `apps/web` browser client
- `services/worker` queue consumer
- `infra` Terraform and deploy scripts
## Rules for the whole repository
- The package manager is `pnpm`. `npm install` writes a second lockfile
that CI ignores, so the install you tested is not the install that ships.
- Any `generated/` directory is build output. Edit the schema in
`schemas/` and run `pnpm codegen` instead.
- `.env.local` holds real credentials. Do not read it and do not print it.
- If you change code in a directory, update that directory's AGENTS.md
in the same commit.各目錄的檔案放置詳細內容,長度可依該目錄的需求調整。
# apps/web
Browser client. Vite and React, TypeScript with `strict` on.
## Commands
- `pnpm dev` serves on port 5173.
- `pnpm test` runs Vitest once and exits.
- `pnpm typecheck` runs `tsc --noEmit`.
## Conventions
- One component per file under `src/components/`.
- All HTTP goes through `src/api/client.ts`. Do not call `fetch` directly,
because the client attaches the auth header and retries on 429.
## Traps
- `pnpm build` does not type check. Vite strips the types instead of
checking them, so a broken type still produces a green build.
Run `pnpm typecheck` as a separate step.worker 檔案的結構相同,但內容不同:安裝命令、pytest -q、consumer 必須保持 idempotent 的原因,以及測試通過前必須執行的 migration。infra 檔案則用來撰寫防止 agent 造成損害的規則。絕不要執行 terraform apply。執行 terraform plan 後即停止,並指定已完成設定的 state backend,避免 agent 嘗試初始化新的 backend。
請注意,這些檔案都沒有描述各服務的用途。這部分應由人員撰寫。Upstream 也劃分了相同的界線,指出「README.md 檔案供人員使用:快速入門、專案說明與貢獻指南」,而 AGENTS.md 則包含「coding agent 所需的額外、有時相當詳細的內容:建置步驟、測試與慣例」。AGENTS.md 與面向人員的 README 之間的區分逐句說明這條界線;記錄程式碼設計原因的 DESIGN.md則涵蓋第三個檔案,說明設計決策,而不是列出命令。
程式碼變更時由誰更新檔案?
規則只有一項,並寫入根目錄的檔案:凡是在某個目錄中變更程式碼的人,都必須在同一個 commit 中更新該目錄的 AGENTS.md。
這項做法依靠的是機制,而非文化。每個目錄的檔案會與程式碼出現在同一份 diff 中,因此 pull request 的審查者能同時看到兩者。根目錄的檔案屬於所有人,也就等於沒有人負責,而且不會出現在任何人原本就要閱讀的 diff 中。
在 pull request 上加入檢查,讓規則真正生效。檢查會找出每個變更檔案上方最近的 AGENTS.md,然後在該檔案未被修改時回報。
#!/usr/bin/env bash
# Warn when code changed but the nearest AGENTS.md above it did not.
changed=$(git diff --name-only origin/main...HEAD)
nearest_doc() {
d=$(dirname "$1")
while [ "$d" != "." ]; do
if [ -f "$d/AGENTS.md" ]; then echo "$d/AGENTS.md"; return; fi
d=$(dirname "$d")
done
echo "AGENTS.md"
}
printf '%s\n' "$changed" | while read -r f; do
[ -n "$f" ] || continue
case "$f" in AGENTS.md|*/AGENTS.md) continue ;; esac
doc=$(nearest_doc "$f")
printf '%s\n' "$changed" | grep -Fqx "$doc" && continue
echo "note: $f changed but $doc was not updated"
done在未修改文件、但重新調整 API client 的分支上,輸出如下:
note: apps/web/src/api/client.ts changed but apps/web/AGENTS.md was not updated將這項檢查設為警告,不要設為失敗。強制閘門只會讓人為了讓 CI 變成綠色而在檔案中加入空白行;為了符合機器要求而修改的檔案,價值甚至低於完全沒有檔案。警告能讓審查者提出問題,而真正有效的部分就在於此。
如何找出已過時的 AGENTS.md?
今天可以執行 2 項檢查,也能在工作階段中觀察到 1 種徵兆。
比較每個檔案的時間與其所描述程式碼的時間。 %cs 會將提交日期輸出為 YYYY-MM-DD。
for f in $(git ls-files '*AGENTS.md'); do
d=$(dirname "$f")
printf '%s doc:%s code:%s\n' "$f" \
"$(git log -1 --format=%cs -- "$f")" \
"$(git log -1 --format=%cs -- "$d")"
doneapps/web/AGENTS.md doc:2026-02-11 code:2026-08-07
services/worker/AGENTS.md doc:2026-07-29 code:2026-08-09
infra/AGENTS.md doc:2026-08-01 code:2026-08-01文件日期比程式碼日期早 6 個月,並不能證明檔案內容錯誤。這只會告訴你應先讀取哪個檔案。對於只需 1 秒的檢查來說,這已經足夠。
尋找已不存在的路徑。 文件最常以一種特定方式逐漸失效:持續描述已刪除的程式碼。這些檔案中的每個路徑都以反引號括起來,因此很容易擷取並測試。
grep -o '`[^`]*`' apps/web/AGENTS.md | tr -d '`' | grep '/' | while read -r p; do
[ -e "$p" ] || [ -e "apps/web/$p" ] || echo "missing: $p"
done請閱讀輸出結果,不要將這項檢查接入 CI。它也會標記 src/**/*.ts 這類 glob,以及你引用的任何 URL,因為兩者都包含斜線,且都不是磁碟上的檔案。
工作階段中的徵兆。 agent 讀取檔案後,因為檔案如此指示而嘗試開啟 src/api/client.ts,但工具回傳:
No such file or directory因此,agent 會採取合理做法,自行撰寫 fetch wrapper。這就是檔案過時的實際成本。agent 並不是忽略你的文件,而是遵循文件內容,抵達 3 個月前已刪除的路徑,然後重新建立你已經擁有的程式碼。使用 Ponytail,可讓 agent 限制在能運作的最小變更範圍內 之類的 skill,可以降低這種重建傾向,但它無法找到檔案指向錯誤位置的 helper。
Claude Code 會讀取 AGENTS.md 檔案嗎?
不會。這點值得特別說明,因為巢狀配置取決於此行為。截至 2026 年 8 月,文件指出:「Claude Code 讀取 CLAUDE.md,而不是 AGENTS.md。」這種配置方式仍然可行,但你需要在每個 AGENTS.md 旁放置一個 CLAUDE.md。
如果你要在共用設定上加入工具專用內容,應使用匯入形式。將以下內容放入 services/worker/CLAUDE.md:
@AGENTS.md
## Claude Code
Use plan mode for changes under `services/worker/migrations/`.如果沒有工具專用內容需要加入,應使用符號連結形式。
git ls-files '*AGENTS.md' | while read -r f; do
ln -s AGENTS.md "$(dirname "$f")/CLAUDE.md"
done
ls -l apps/web/CLAUDE.mdln 成功時不會輸出任何內容,因此請檢查檔案清單:apps/web/CLAUDE.md -> AGENTS.md。接著啟動工作階段並執行 /context,載入的檔案會列在 Memory files 下。在 Windows 上建立符號連結需要系統管理員權限或 Developer Mode,因此請改用 @AGENTS.md 匯入。
這裡還有一個容易踩到的陷阱。執行 /compact 後,根目錄檔案會從磁碟重新讀取,但子目錄中的巢狀檔案不會重新注入。代理程式下次讀取該目錄中的檔案時,這些檔案才會再次載入。如果每個目錄的規則在長時間工作階段中途似乎停止套用,通常就是這個原因;接觸該目錄中的任何檔案即可讓規則恢復。
將其他代理程式指向 AGENTS.md 的設定
Codex 原生讀取 AGENTS.md。在每個層級中,它會先檢查 AGENTS.override.md,讓單一目錄可以在不修改共用檔案的情況下使用本機覆寫設定。合併內容達到 32 KiB,也就是預設的 project_doc_max_bytes 時,Codex 會停止合併。這也是根目錄檔案應保持精簡的另一個理由。
Aider 透過 .aider.conf.yml 讀取,設定行為 read: AGENTS.md。
Gemini CLI 透過 .gemini/settings.json 讀取,使用 { "context": { "fileName": "AGENTS.md" } }。
上游文件說明,仍使用較舊單數名稱的儲存庫可向後相容地重新命名為 mv AGENT.md AGENTS.md && ln -s AGENTS.md AGENT.md。
在非常大的 monorepo 中,Claude Code 的 claudeMdExcludes 設定可依路徑或 glob 略過祖先目錄中的檔案。當其他團隊的目錄位於你的目錄上層時,這項設定很有用。
這與 agent memory 或 skill 有何不同?
這些機制看似相近,但失效方式完全不同。因此,應明確判斷自己需要的是哪一種。
AGENTS.md 由你撰寫、提交至 git,經 pull request 審查,所有 clone 該 repository 的人看到的內容都相同。agent memory 由 agent 撰寫,儲存在 repository 外部,而且僅限於單一機器。Claude Code 文件也採用相同區分:CLAUDE.md 存放由你撰寫的「Instructions and rules」,auto memory 存放由 Claude 撰寫的「Learnings and patterns」,而 memory directory 不會在不同機器之間共用。判斷方式很簡單:如果某項資訊必須對使用全新 clone 的同事成立,就不能放在 memory 中。agent memory 如何在工作階段之間持續保存涵蓋了這一半的內容。
skill 是第三種機制。AGENTS.md 是每個工作階段都會載入的內容;skill 則是在需要時才載入的程序。Claude Code 文件提供了一項實用原則:「如果某項內容是多步驟程序,或只適用於程式碼庫的某個部分,請將它移至 skill 或依路徑套用的規則。」這句話的後半正是巢狀 AGENTS.md 要解決的問題。前半則是 agent skills 的用途;如果相同程序會用於多個 repository,應該在多個 repository 之間共用 skill,而不是將相同段落貼到 10 個不同的 AGENTS.md 檔案中。
上游指出:「截至撰寫本文時,主要的 OpenAI repository 有 88 個 AGENTS.md 檔案。」這個數字本身就是完整的論證。大型 repository 不需要更大的檔案,而需要更多小型檔案。每個檔案都應放在所描述的程式碼旁邊,並由最後修改該程式碼的人負責維護。
FAQ
巢狀的 AGENTS.md 會取代根目錄檔案,還是附加在其後?
會附加在其後。上游文件所說的「以距離最近的檔案為優先」,描述的是發生衝突時的處理方式,而不是載入方式。Codex「會從根目錄往下串接檔案,並以空白行連接」,Claude Code 則會從工作目錄往上逐層尋找並串接找到的所有檔案,而不是覆寫它們。只有在兩個檔案針對同一主題提供不同指示時,距離最近的檔案才會勝出。共用規則只需在根目錄撰寫一次,不要在每個目錄重複。
根目錄的 AGENTS.md 應該多大?
大小應控制在這個程度:即使該檔案會貼到你在該 repository 中提出的每個請求前面,你也不會介意。因為實際上就是如此。Claude Code 文件建議每個檔案控制在 200 行以下,並警告較長的檔案會「降低遵循程度」。Codex 預設會在合併後的指示檔案總大小達到 32 KiB 時停止。如果根目錄檔案記錄了四項服務,其中大部分內容對單一工作都是無用負擔。將詳細內容移到各目錄的檔案,並在根目錄留下索引。
如何避免這些檔案變得過時?
在根目錄檔案加入一項規則:任何修改某目錄程式碼的人,都必須在同一個 commit 更新該目錄的 AGENTS.md。將檔案放在程式碼旁邊,才能讓規則持續生效,因為該變更會與人員原本就會檢視的 pull request diff 一起提交。加入 CI 警告,將每個變更路徑對應到其上方最近的 AGENTS.md;並定期比較每個檔案中的 git log -1 --format=%cs 與在該檔案所記錄目錄上執行相同 command 的結果。
Claude Code 會讀取 AGENTS.md 檔案嗎?
不會。截至 August 2026,文件指出「Claude Code 會讀取 CLAUDE.md,而不是 AGENTS.md。」在相同目錄建立 CLAUDE.md,並在第一行加入 @AGENTS.md;這會載入共用檔案,也讓你能在其下方加入 Claude 專用指示。如果沒有額外內容要加入,使用 ln -s AGENTS.md CLAUDE.md 建立的 symlink 也能運作;但在 Windows 上需要 Administrator 權限或 Developer Mode。在工作階段中執行 /context,確認該檔案出現在 Memory files 下。
只在某些情況適用的規則應該放在哪裡?
不要放在 AGENTS.md。該檔案會在每個工作階段載入,因此其中每一行都會與你實際輸入的請求競爭注意力。偶爾才需要、且包含多個步驟的程序,應放在 skill 中,於需要時載入。只適用於單一目錄的規則,應放在該目錄的 AGENTS.md。代理程式可直接從程式碼讀取的資訊,例如目錄樹或相依套件清單,兩者都不應放入。