Day 22 的結尾提過,只寫在個人設定裡的防護,只保護得了自己。這件事在新同事加入的那天最明顯。
新同事 clone 了專案,打開 Claude Code,交代一個團隊裡做過很多次的任務。跑出來的結果跟其他人的差很多:測試的寫法不一樣,commit message 的格式不一樣,其他人平常直接就能跑的指令,在他那邊一直跳出確認。
專案的程式碼一模一樣,差別在程式碼以外的地方。其他人的電腦上,累積了半年的個人規則、自己寫的 skills、agent 自己記下的筆記,還有幾條當初為了省事加在個人設定裡的權限。這些東西從來沒有進過 repo,新同事一樣都沒有。
2012 年,Martin Fowler 寫過一篇短文,描述一種很常見的伺服器。它一開始照標準裝好,接著被一次次手動修補、升級、改設定,日子一久,就變成世上獨一無二的一台。他用雪花來形容它:在滑雪場很美,放在機房就是災難。
雪花伺服器的麻煩,在於沒辦法重現。硬體壞了,沒人能裝出一台一模一樣的;測試環境也很難跟正式環境保持一致。久了大家連碰都不敢碰,因為沒人說得清楚哪個設定是重要的,升級一個小元件,可能在意想不到的地方出事。
Fowler 給的解法,是把整台伺服器的設定寫成自動化的腳本,用文字檔存進版本控制。設定變得看得懂、改得動,每一次修改都留下紀錄。
Claude Code 的設定,很容易就長成同一個樣子。全域的 CLAUDE.md 裡加了幾條規則,個人設定裡開放了幾個常用指令,自己寫了幾個 skill 放在家目錄,auto memory,也就是 Claude 根據使用者的糾正自己記下的筆記,又在背後累積了一堆。每一項當下都說得通,加起來,就是一台只存在於自己電腦上的 agent。
但類比到這裡要轉個彎。伺服器之間的差異,幾乎都是壞事;AI 的設定裡,有些差異卻是應該的。有人喜歡 agent 解釋得詳細一點,有人只要結論,這種偏好留在自己的設定裡完全沒問題。要消除的,只有會讓團隊的產出不一致的那部分。
判斷的方式,是看這個設定會不會影響交出去的東西。測試要怎麼寫、commit 的格式、哪些指令不准跑、哪些檢查一定要做,這些會讓同一個任務在不同人手上做出不同的結果,就該寫成檔案進版本控制。
具體來說,專案的 CLAUDE.md、.claude/settings.json 裡的權限規則和 hooks(在特定動作前後自動執行的腳本)、專案的 skills、.mcp.json 裡的 MCP server,還有在專案設定裡宣告要啟用的 plugins,都可以跟著 repo 走。
留在自己電腦上的,是真正屬於個人的東西。.claude/settings.local.json 放只對自己生效的例外,Claude Code 第一次寫入它時,會把它加進全域的 git 排除設定,不會被誤 commit;如果是手動建立的,就要自己加進 .gitignore。CLAUDE.local.md 放個人在這個專案的偏好,同樣要自己加進 .gitignore。auto memory 則存在自己的電腦上,不會跟著 repo 走。
同一個專案裡同時有個人和團隊的設定時,Claude Code 怎麼決定聽誰的,答案依設定的種類而不同。
一般的設定看層級。由高到低依序是組織統一下發的設定、啟動時在命令列指定的設定、自己在這個專案的設定、團隊共用的專案設定、自己的全域設定,同一個項目,高的一層蓋過低的一層;權限規則這類清單則例外,各層的內容會合併起來。合併之後怎麼判斷,Day 8 講過:禁止優先於確認,確認優先於允許。官方文件也寫明,任何一層的禁止規則都會生效。所以個人設定可以多開放一些指令,卻放寬不了團隊明確擋下或要求確認的那些。
CLAUDE.md 則是全部串在一起。個人的、專案的、組織的 CLAUDE.md,內容都會放進 context,不會互相覆蓋。個人的 CLAUDE.md 寫「縮排用 tab」,專案的寫「縮排用空格」,兩句都會出現在 Claude 面前,由模型自己決定聽哪一句。官方文件也提到,兩份檔案給出互相矛盾的指示時,模型遵守的程度會下降。這種衝突不會報錯,只會讓同一個專案在不同人手上出現不同的結果。
把設定 commit 進 repo,也不代表隊友那邊立刻生效。允許類的權限規則、額外的工作目錄、要安裝 plugin 的來源,還有大部分的環境變數,都要等隊友信任這個資料夾之後才會套用;禁止和必須確認的規則則是一開始就有效。Day 13 也提過,.mcp.json 裡的 MCP server,每個人都要自己核准一次。另外,有些設定基於安全考量,根本不能從 repo 裡的檔案生效。從別人的 repo 拿到的設定,不應該一 clone 下來就替自己打開權限,這個設計說得通,但「已經 commit 了」跟「團隊都套用了」確實是兩件事。
設定進了 repo,改它就跟改程式碼一樣,會影響整個團隊。CLAUDE.md 多一條規則、權限規則開放一個指令,都值得在 PR 裡被看過一遍。Day 17 談過的 eval,也就是替 agent 設定寫的回歸測試,在這時候派得上用場:改完跑一次,確認沒有把原本好好的行為改壞。
團隊需要強制統一的部分,交給組織層級的設定。它在最高一層,一般情況下個人和專案的設定都蓋不過它;組織層級的 CLAUDE.md,也沒辦法被個人設定排除。
Fowler 同一天還寫了另一篇短文,介紹同事 Kornelis Sietsma 取的名字:鳳凰伺服器。做法是定期把伺服器整台砍掉,照著版本控制裡的設定重建。能重建成功,就證明設定真的都寫進去了。
放到 AI 設定上,可以借用官方除錯文件裡的一個做法:把 CLAUDE_CONFIG_DIR 這個環境變數指到一個空資料夾,家目錄裡的個人設定、CLAUDE.md、skills 和記憶就會全部跳過。再把 repo 重新 clone 一份,在這份乾淨的副本裡啟動,避開自己工作目錄裡沒進 git 的 local 檔案,看到的就很接近新同事拿到的那台 agent。這樣啟動需要重新登入,組織層級的設定也照樣會套用。在 session 裡打 /status 可以看到目前套用了哪些設定來源,/context 則能看到實際載入了哪些 CLAUDE.md。
拿幾個平常的任務跑一次,比對的重點是規則有沒有被遵守:測試的寫法、commit 的格式、該擋的指令有沒有擋。模型本身每次跑的結果就會有些差異,逐字比對沒有意義。哪一條規則在這裡沒被遵守,就代表它還留在自己的雪花上,沒有寫進 repo。
2012 年的雪花伺服器,是在一次次手動修改中慢慢長出來的,沒有人刻意把它弄成那樣。AI 的設定也是這樣長成雪花的:每一次「這條規則先加在我自己的設定就好」,當下都說得通。
不同的是,這一次的雪花有一部分值得留著。真正該問的,是新同事第一天打開 Claude Code 時,拿到的那台 agent,會不會交出跟團隊一樣的東西。
延伸閱讀