CLAUDE.md 太長怎麼辦:我重新拆了一遍 AGENTS.md、Skills 和 CI 的邊界
如果你長期用 Codex、Claude Code 這類 Coding Agent,專案裡的 AGENTS.md、CLAUDE.md 很容易越寫越長。這個過程通常不是誰一開始設計錯了,反而經常是因為你真的用得多:Agent 改多了檔案,就補一句「不要動無關範圍」;測試沒跑就說完成,再補一句「必須拿真實輸出證明」;某次資料庫遷移把失敗現場清掉了,再補一條禁止自動清理。每一條單獨看都合理,最後根檔案卻越來越像一份混著開發規範、事故復盤、工作流程和提醒事項的內部手冊。
我自己真正開始在意這個問題,也不是因為多幾百行 Markdown 看著不舒服,而是發現這些規則一旦全部常駐,很多原本只屬於某個目錄、某類任務的東西,也會跟著每一次任務一起出現。你只是改一段文件,前端元件邊界、發佈流程、協議相容、資料庫遷移注意事項可能都還在;再往後,根檔案寫一遍,Skill 裡寫一遍,docs 裡又解釋一遍,CI 裡還有真正執行的一份,慢慢就會變成「大家都在管,但誰都不是唯一 owner」。
前幾天我在 GitHub 上看到 Nession 的 issue #1437,它剛好把這個問題做了一次比較徹底的遷移。這個儲存庫原本的根 CLAUDE.md 大約 760 行,裡面塞了非常多專案級和任務級規則。作者後來沒有繼續在原檔案上做刪減,而是把 root、局部規則、Skills 和可執行 Gate 重新分層。對應的實作最後合進了 PR #1442。
這個思路我覺得很對,但我不太想直接把它改寫成「某個儲存庫用了四層架構,所以大家也應該這樣」。這種文章寫起來很快,資訊增量卻不大。我更想知道的是:把規則拆開以後,預設常駐的東西到底少了多少;這些邊界能不能被 CI 檢查;以及現在 Codex 和 Claude Code 自己的載入規則,和很多舊文章裡講的還是不是一樣。
所以這篇不是把 Nession 的 issue 翻成繁中。我先拿它遷移前後的固定 commit 做了一次唯讀分析,又在自己的 Content Lab 裡寫了一個很小的 instruction-contract validator。做到後面,我反而越來越覺得,真正值得保留的不是「CLAUDE.md 最好多少行」,而是另一個更簡單的判斷:這條規則到底應該由誰擁有,什麼時候才需要載入,它能不能交給機器驗證。
我真正想解決的不是「檔案太長」
如果只是嫌 760 行太長,最容易的辦法當然是拆檔案。但把 700 行從 CLAUDE.md 挪到另一個每次都要讀的檔案裡,數字是變漂亮了,問題其實一點沒解決。
我現在更願意把根指令理解成「幾乎任何任務都繞不過去的最小公共層」。專案最核心的目標、安全邊界、指令從哪裡繼續往下找、所有改動都必須遵守的驗證原則,這些可以放在 root。可一條規則如果只在 web/ 目錄裡成立,那它更適合跟著這個目錄走;如果它講的是「發佈一次 staging 應該做什麼」「做 code review 應該怎麼走」,那它本質上是任務流程,放進 Skill 會更自然;至於像「根檔案不能無限增長」「Skill 名稱不能重複」「某個相容連結不能失效」這種能被程式判斷的事情,我現在反而不願意繼續只寫成一句提醒,而是希望 CI 直接擋住。
也就是說,我最後並沒有把問題理解成「AGENTS.md 和 CLAUDE.md 應該怎麼分」,而是把它看成一張 ownership graph。根檔案只是其中一個 owner,目錄級 instruction 是另一個 owner,Skill 負責把重複工作流程串起來,docs 保存那些不該常駐但以後還要查的解釋和背景,能確定性判斷的東西則盡量交給程式碼。
這個邊界其實比「所有經驗都做成 Skill」更實用。Skill 很容易被用成另一本百科全書,最後只是把 root 的臃腫搬家。我現在判斷一條規則放哪,通常先問幾個很土的問題:如果我只是改 README,它還必須出現嗎?如果只有進入某個目錄才需要,為什麼不讓它靠近那個目錄?如果它是一套會反覆執行的流程,為什麼不讓 Skill 來負責?如果機器已經能判斷對錯,又為什麼要每次都拜託 Agent「請務必記得」?
Nession 這次遷移讓我覺得有意思的地方,也正在這裡。它遷移後的知識並沒有消失,而是重新有了位置。root 變小了,局部 owner 反而更多了,這和單純「刪文件」完全是兩回事。
我拿遷移前後兩個版本重新測了一遍
為了避免直接引用 PR 裡的自報資料,我沒有執行 Nession 自己的腳本,而是用 GitHub API 讀取它兩個固定 SHA 的 tree 和 blob。遷移前是 2d57f38ca917a327e5e4bdd7545d1e5dc90bc0bb,遷移後是 7d89c460ea302ea3eeb4380341055b6f2a1da39c。分析器只讀檔案內容,不 checkout,也不執行第三方 hook、package script 或 workflow。
重新算出來以後,root instruction 從 760 行降到了 116 行,減少約 84.74%;字元數從 55,160 降到 5,734。8 個主要 Skill 的入口檔案也從合計 4,079 行變成 1,327 行,少了約 67.47%。
| 指標 | 遷移前 | 遷移後 | 降幅 |
|---|---|---|---|
| root instruction 行數 | 760 | 116 | 84.74% |
| root decoded characters | 55,160 | 5,734 | 89.60% |
| 8 個 Skill 主入口總行數 | 4,079 | 1,327 | 67.47% |
| 8 個 Skill 主入口字元數 | 161,324 | 42,710 | 73.53% |
但這張表最容易被誤讀。它不代表遷移後專案只剩 116 行「規則」,更不代表 token 成本就按 84% 的比例下降。遷移後的儲存庫裡,root、Web、protocol、agent runtime、design、scripts、GitHub workflows、docs 都有自己的 canonical AGENTS.md。知識還在,只是不再預設都擠在同一個入口裡。
我反而覺得這才是 progressive loading 真正有價值的地方。你不是在比賽誰的 CLAUDE.md 更短,而是在盡量減少「每次任務都必須常駐」的內容。一個前端任務需要前端約束時再去讀前端 owner,一個 CI 任務需要發佈規則時再把那部分帶進來。對長期維護來說,這種局部性比單純壓行數重要得多。
這次我也順手把結構本身做成了一個小實驗。Content Lab 裡現在有一個和 Nession 路徑無關的 validator,它只看一張抽象的 instruction graph:root 有沒有超預算,CLAUDE.md 相容面是不是又變成了可編輯副本,本地連結有沒有斷,Skill 名稱有沒有衝突,frontmatter 是否缺欄位,目錄裡只有相容檔案卻沒有 canonical owner,symlink 是否已經指向不存在的位置。
我給這些情況各做了正負 fixture,8 組測試全部按預期觸發了對應錯誤。這個結果談不上複雜,但對我來說反而很重要,因為它說明「保持指令架構乾淨」不一定要靠人記。很多最容易慢慢腐化的地方,其實幾十到幾百行普通程式碼就能守住。
真正麻煩的是,Codex 和 Claude Code 的規則還在變
做到這裡以後,我本來很容易順手寫出一個看起來很漂亮的目錄:
AGENTS.md
CLAUDE.md -> AGENTS.md
.agents/skills -> .claude/skills
Nession 自己現在確實有類似的相容面,但我最後沒有把它當成文章裡的「標準答案」,因為目前 Codex 和 Claude Code 的行為已經比很多舊文章裡講的複雜。
OpenAI 現在的 Codex prompting guide 明確說明,Codex 會從全域位置和儲存庫 root 一路向目前工作目錄讀取 AGENTS.md,越靠近工作目錄的 instruction 越晚進入上下文。所以「root 保持最小,目錄裡再放 scoped owner」這條路是有官方行為基礎的。
Skill 目錄就沒那麼適合寫死了。OpenAI 目前不同資料裡能看到不只一種 repo-scope 的組織方式,例如 Skill eval 文章 和 Claude Agent SDK migration guide 裡出現的路徑並不完全一樣。對我來說,這反而強化了前面的判斷:真正該穩定的是內容 owner 和相容關係,不是某個目錄名稱。
Claude Code 這邊變化也很明顯。現在的 memory / instruction 文件 已經支援直接讀取 AGENTS.md,同時仍然建議 CLAUDE.md 保持精簡,官方給出的目標大約是 200 行以內;路徑相關規則可以交給 scoped rules,多步驟流程則更適合放 Skills。Skills 文件 也明確是按需載入主體內容,而不是把所有 Skill 正文一直塞在上下文裡。
所以「為了相容 Claude,所有專案都必須維護 CLAUDE.md -> AGENTS.md」現在已經不是一個可以隨手下的結論。如果專案同時存在 CLAUDE.md 和 AGENTS.md,載入行為還和版本以及 Project instructions 設定有關;symlink 在 macOS/Linux 下很順手,到了 Windows 又要考慮 Git symlink 的 checkout 和編輯問題。
這也是為什麼我現在更願意維護一張很小的 compatibility matrix,而不是維護兩份幾乎一樣的指令檔案。哪邊是 canonical owner,哪邊只是 adapter,目前客戶端版本實際會發現哪些 Skill 路徑,Windows 是否需要換成腳本產生副本,這些都應該是明確的工程決策。路徑只是實作細節,owner 才是架構。
如果現在讓我重新整理一個儲存庫,我會先管「誰負責」,再管「寫什麼」
如果是一個剛開始用 Agent 的小專案,我不會一上來就搭十幾個目錄,也不會為了看起來「專業」把 root 拆得很碎。幾十行 AGENTS.md 能說清楚的東西,就先讓它保持幾十行。
真正值得動手重構,通常是當你開始反覆遇到幾種信號:根檔案越來越像內部手冊;同一條規則在 root、Skill、docs 裡來回複製;不同目錄的要求互相干擾;或者每次 Agent 出錯以後,你唯一的處理方式還是「再往 prompt 裡補一句」。
到了這個階段,我會先把規則逐條問一遍「誰負責」。所有任務都需要的,留在 root;只跟某個目錄有關的,放到那個目錄附近;重複執行的動作,交給 Skill;很長的解釋和背景,回到 docs;能確定性判斷的約束,直接寫成 validator 或 CI。這個過程看起來像是在整理 Markdown,實際是在給專案補一層很輕的設定治理。
我尤其不建議把「高風險規則」只留在自然語言裡。比如遷移失敗後不能清理現場、發佈前必須跑某一組檢查、某個目錄不能出現 mock implementation,這類事情一旦代價比較大,就不應該只靠 Agent 每次都剛好記住。Prompt 可以解釋為什麼,Skill 可以告訴它怎麼走,最後真正兜底的還是 executable gate。
這次實驗能證明的也就到這裡。我能確認 Nession 的 root 和 Skill 入口確實發生了明顯的結構縮減,也能確認這種 instruction graph 可以用一個很小的 validator 抓住不少常見回歸。我沒有在這裡跑一個完整的 Codex/Claude Code 客戶端 benchmark,所以不會把它寫成「這樣改以後成功率提高多少」或者「token 一定能省多少」。
但這已經足夠讓我改變一個習慣:以後再看到 CLAUDE.md 或 AGENTS.md 越寫越大,我不會先想著「怎麼把這 500 行寫得更聰明」,而會先看裡面到底混了多少本來不該常駐的東西。
很多時候,真正該優化的不是提示詞本身,而是這些規則有沒有一個清楚的家。
如果你也在繼續把 Coding Agent 接進日常開發,可以順著看 新版 Codex 有什麼變化:為什麼它現在更像一個開發環境;如果你更關心模型外面的權限、上下文和安全邊界,那篇 Claude Code 原始碼洩露後,我們能學到什麼:系統提示詞、權限分級和記憶系統 會更接近這篇文章的下一層問題。