Monorepo 如何設定巢狀 AGENTS.md 檔案
在 Monorepo 根目錄使用單一 AGENTS.md 常導致上下文耗盡與規則衝突。本文介紹如何透過巢狀結構將指令分散至各服務目錄,有效提升 Claude Code 的執行準確度並節省 Token 配額。
在 Monorepo 中巢狀 AGENTS.md 的含義
在 Monorepo 中,巢狀 AGENTS.md 代表在儲存庫根目錄放置一個小型檔案,並在每個服務目錄內各放置一個檔案。根目錄檔案包含適用於全域的少數規則,以及指向其他檔案位置的對應表。每個服務檔案則僅包含該目錄專屬的指令與慣例。當代理程式編輯 services/worker/queue.py 時,它會讀取根目錄檔案與該工作目錄的檔案,完全不會耗費任何與前端相關的上下文,因為它永遠不會觸及前端。
此機制無需安裝任何軟體。AGENTS.md 是一種慣例,上游專案對此說明得非常清楚:
AGENTS.md 僅是標準的 Markdown 檔案。您可以使用任何標題;代理程式會直接解析您提供的文字。
這正是此技術值得深入學習的原因。其格式不會隨意變更。真正會出問題的是檔案的放置與維護,而這些皆屬於您的職責。
為什麼單一根目錄下的 AGENTS.md 會失效?
當儲存庫根目錄下存在一個 600 行的 AGENTS.md,且同時包含網頁應用程式、背景工作處理器與 Terraform 目錄時,會導致四種問題。
它會因為無人維護而過時。 在 apps/web 修改測試指令碼的工程師,其編輯範圍僅限於 apps/web 下的檔案。根目錄的 AGENTS.md 不在該差異比對(diff)中,因此審閱者不會發現兩者不一致。六週後,該檔案描述的建置步驟已不存在,而當初更動的人早已遺忘此事。
它在每次任務中都會消耗上下文(context)。 這些檔案會在對話開始時載入,此時 Agent 尚未得知您的需求。Claude Code 的說明文件明確指出:「每個 CLAUDE.md 檔案應控制在 200 行以內。過長的檔案會消耗更多上下文並降低執行準確度。」當指令檔總大小達到預設的 project_doc_max_bytes(32 KiB)時,Codex 將停止合併。一個記錄四個服務的根目錄檔案,會在處理每個任務時,將此配額浪費在其中三個無關的服務上。
指令開始相互矛盾。 網頁目錄可能需要 pnpm test,而背景工作處理器則需要 pytest -q。當兩者寫入同一個檔案時,每條規則都只有部分時間適用,導致 Agent 必須猜測該套用哪一條。Claude Code 的文件描述了後果:「若兩條規則相互矛盾,Claude 可能會隨機選擇其中一條。」採用分目錄檔案可消除猜測,因為每次只有一條規則會進入上下文。當您確信已清楚撰寫的規則仍被忽略時,與其第四次修改措辭,不如深入了解 指令無法生效的原因。
它充斥著 Agent 本可從程式碼中讀取的資訊。 例如目錄樹、相依性列表或各套件的功能摘要。Claude Code 的 /doctor 檢查機制正是為了剔除這些內容。它會「刪除 Claude 可從程式碼庫推導出的內容,如目錄結構、相依性列表與架構概覽」,並保留「與工具預設值不同的陷阱、邏輯與慣例」。這句話是判斷某一行內容是否該寫入檔案的最佳準則。
代理程式是讀取根目錄檔案,還是僅讀取最近的檔案?
這是大多數人對模型產生誤解的地方,因此引用上游慣例而非自行轉述是有價值的:
在每個套件內放置另一個 AGENTS.md。代理程式會自動讀取目錄樹中最近的檔案,因此最接近的檔案具有優先權,且每個子專案都能發布客製化的指令。
關於衝突:
最接近編輯檔案的 AGENTS.md 勝出;明確的使用者對話提示會覆蓋所有設定。
「具有優先權」對許多人來說讀起來像是「根目錄檔案被忽略了」。事實並非如此。在實作此慣例的工具中,從儲存庫根目錄到工作目錄路徑上的每個檔案都會被讀取並合併。只有當兩個檔案對同一主題有不同說明時,最近的檔案才會勝出。
Codex 對此機制有明確說明:「Codex 會從根目錄向下串接檔案,並以空行連接。越接近目前目錄的檔案,其指導原則的優先權越高。」Claude Code 對其自身的檔案名稱也採取相同的路徑。位於工作目錄上方的目錄階層檔案「會在啟動時完整載入」,且「所有發現的檔案都會串接至上下文,而非互相覆蓋」。位於工作目錄「下方」的目錄行為則不同:Claude Code 會在「Claude 讀取這些目錄中的檔案時」按需載入。
這會產生兩個實際後果。根目錄檔案是儲存庫中每個工作階段的前綴,因此請將該處的每一行視為每週需支付百次成本的內容。特定目錄的檔案在代理程式於其他位置工作時不會產生成本,這意味著細節在該處的成本很低,且適合放在該處。
此行為已於 2026 年 8 月針對 Codex 與 Claude Code 的文件進行驗證。各工具實作此慣例的方式略有不同且會隨時間變更,因此請務必確認貴團隊所使用代理程式的載入規則。
包含三個服務的儲存庫配置範例
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 file)結構相同但內容各異:包含安裝指令 pytest -q、消費者必須保持冪等性(idempotent)的原因,以及測試通過前必須執行的遷移程序。基礎架構檔案(infra file)用於定義防止代理程式(agent)造成損害的規則。切勿執行 terraform apply。請執行 terraform plan 並在此停止,同時指定已設定好的狀態後端(state backend),以避免代理程式嘗試初始化新的後端。
請注意,這些檔案中均未包含各服務用途的描述。這些資訊應由人類維護。Upstream 採取相同的界線劃分,指出「README.md 檔案是給人類看的:包含快速入門、專案描述與貢獻指南」,而 AGENTS.md 則包含「程式碼代理程式所需的額外且有時極為詳細的背景資訊:建置步驟、測試與慣例」。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 是否已過期?
目前您可以執行兩項檢查,並留意工作階段中出現的一種徵兆。
比較每個檔案的日期與其所描述程式碼的日期。 %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文件日期若比程式碼日期晚六個月,並不代表該檔案一定有誤。這只是告訴您應該優先閱讀哪些檔案,而這正是這項僅需一秒鐘的檢查所能提供的全部資訊。
尋找已不存在的路徑。 文件損壞有一種非常具體的表現方式:它持續描述已被刪除的程式碼。這些檔案中的每個路徑都以反引號標示,因此很容易提取並進行測試。
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 之類的萬用字元以及您引用的任何 URL,因為兩者皆包含斜線,且都不是磁碟上的檔案。
工作階段中的徵兆。 Agent 讀取該檔案,並因為檔案指示而嘗試開啟 src/api/client.ts,此時工具會回傳:
No such file or directory因此,它會採取合理的做法,自行編寫一個 fetch 封裝程式。這就是過期檔案的真正代價。Agent 並不會忽略您的文件。它會遵循文件指示,進入一個三個月前就已刪除的路徑,並重新建置您現有的程式碼。像 Ponytail,將 Agent 限制在最小可行變更 這類技能,能減少這種重新建置的本能反應,但它無法找出您檔案中指向錯誤位置的輔助程式。
Claude Code 會讀取 AGENTS.md 檔案嗎?
不會。這點值得特別說明,因為巢狀配置的運作方式取決於此。截至 2026 年 8 月,官方文件指出:「Claude Code 讀取 CLAUDE.md,而非 AGENTS.md。」此模式依然有效,您只需在每個 AGENTS.md 旁放置一個 CLAUDE.md 即可。
當您需要在共用設定之上加入特定工具的指令時,請使用匯入(import)格式。請將此內容放入 services/worker/CLAUDE.md:
@AGENTS.md
## Claude Code
Use plan mode for changes under `services/worker/migrations/`.當沒有需要額外加入的特定工具設定時,請使用符號連結(symlink)格式。
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 上,建立符號連結需要管理員權限或開發者模式,因此在該環境下請改用 @AGENTS.md 匯入方式。
此處有一個常見陷阱。執行 /compact 後,根目錄檔案會從磁碟重新讀取,但子目錄中的巢狀檔案不會被重新注入。直到代理程式下次讀取該目錄中的檔案時,這些設定才會恢復。若發現某個目錄層級的規則在長時間的工作階段中失效,通常就是這個原因,此時只需觸碰(touch)該目錄下的任一檔案即可恢復。
將其他代理程式指向 AGENTS.md 的設定
Codex 原生讀取 AGENTS.md。它會在每個層級優先檢查 AGENTS.override.md,這讓您無需編輯共用檔案,即可為單一目錄設定本地覆寫。當合併後的檔案大小達到 32 KiB(預設的 project_doc_max_bytes)時,它會停止合併,這也是保持根目錄檔案精簡的另一個原因。
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 審核,且對於所有複製儲存庫的人來說都是一樣的。代理記憶體則由代理程式自行寫入、儲存於儲存庫之外,且僅限於單一機器。Claude Code 的文件劃分了相同的界線:CLAUDE.md 存放您編寫的「指令與規則」,自動記憶體存放 Claude 自行學習的「經驗與模式」,且記憶體目錄不會在不同機器間共享。判斷標準很簡單:如果某個事實對於剛複製儲存庫的同事來說必須成立,它就不能存放在記憶體中。代理記憶體如何在工作階段間持久化 涵蓋了這部分內容。
技能(skill)是第三種機制。AGENTS.md 是每個工作階段都會載入的上下文;而技能則是僅在需要時才載入的程序。Claude Code 文件提供了一個實用的規則:「如果條目是多步驟程序,或僅與程式碼庫的某個部分有關,請將其移至技能或路徑範圍內的規則。」該句的後半部分正是巢狀 AGENTS.md 所解決的問題。前半部分則是 代理技能 的用途;當多個儲存庫需要相同的程序時,請 跨儲存庫共享技能,而不是將相同的段落複製貼上到十個不同的 AGENTS.md 檔案中。
上游文件指出:「撰寫本文時,主要的 OpenAI 儲存庫擁有 88 個 AGENTS.md 檔案」。這個數字就是最好的證明。大型儲存庫不需要更大的檔案,而是需要更多的小型檔案,每個檔案都放置在它所描述的程式碼旁邊,並由最後修改該程式碼的人負責維護。
FAQ
巢狀的 AGENTS.md 是會取代根目錄檔案,還是與其合併?
是合併。上游文件指出「最接近的檔案優先」,這僅描述發生衝突時的處理方式,而非載入機制。Codex 會「從根目錄向下串接檔案,並以空行連接」,而 Claude Code 則是從工作目錄向上遍歷並串接所有找到的檔案,而非覆蓋。只有當兩個檔案對同一主題給出不同指令時,最接近的檔案才會勝出。請將共用規則寫在根目錄一次,不要在每個目錄重複撰寫。
根目錄的 AGENTS.md 應該多大?
大小應控制在讓你不會介意它被附加在該儲存庫中每次請求的最上方,因為這正是系統運作的方式。Claude Code 文件建議每個檔案控制在 200 行以內,並警告過長的檔案會「降低遵循度」。Codex 預設在合併指令檔案時,總大小上限為 32 KiB。如果你的根目錄檔案記錄了四項服務,那麼對於單一任務而言,大部分內容都是無效負擔。請將細節移至各目錄的檔案中,並在根目錄留下索引。
如何防止這些檔案過期?
在根目錄檔案中加入一條規則:任何修改目錄內程式碼的人,都必須在同一次 commit 中更新該目錄的 AGENTS.md。將檔案放置在程式碼旁能確保規則落實,因為變更會出現在人類審閱者正在閱讀的同一個 pull request diff 中。請加入 CI 警告,將每個變更的路徑對應到其上方最近的 AGENTS.md,並定期對每個檔案執行 git log -1 --format=%cs,再與該檔案所記錄目錄下執行的相同指令進行比對。
Claude Code 會讀取 AGENTS.md 檔案嗎?
不會。截至 2026 年 8 月,文件說明「Claude Code 讀取 CLAUDE.md,而非 AGENTS.md」。請在相同目錄建立一個 CLAUDE.md,並在第一行寫入 @AGENTS.md,這會載入共用檔案,讓你能在下方加入 Claude 專屬的指令。若沒有額外內容需要加入,使用 ln -s AGENTS.md CLAUDE.md 建立的符號連結(symlink)也能運作,但在 Windows 上需要管理員權限或開發者模式。在 session 中執行 /context,並確認該檔案出現在 Memory files 下方。
那些只在特定情況下才需要的規則該放在哪裡?
不要放在 AGENTS.md。該檔案會在每個 session 中載入,因此其中的每一行都會與你實際輸入的請求爭奪注意力。偶爾才需要、包含多個步驟的程序,應歸類為技能(skill),並在需要時載入。適用於單一目錄的規則,應放在該目錄的 AGENTS.md 中。至於代理程式能直接從程式碼讀取的資訊(例如目錄樹或相依性列表),則兩者都不需要放。