新功能先找落腳的 crate,core 是最後一檔
開啟倉庫,第一反應是往 core 里加。倉庫把這件事寫成禁令:先找現有的非 core crate,否則新建一個。依賴方向會把葉子型別擋在核心之外。
codex-core。依賴方向怎麼把它擋在某一層之外,擋住之後正確的落點在哪。這條禁令沒有機器紅燈,靠什麼還在運轉。
- workspace members 是一份顯式陣列,當前 135 個Cargo.toml L3
- 目錄叫 core,crate 名叫 codex-coreAGENTS.md L4
- 禁令:resist adding code to codex-coreAGENTS.md L76
- 先問現有的非 core crate 能不能住AGENTS.md L80
- 否則新建 workspace crate,並允許重構舊程式碼AGENTS.md L81
- 評審對不必要地進 core 的 PR 主動擋AGENTS.md L83
- core 已經依賴拆出去的 context-fragmentscore/Cargo.toml L35
- 非機械改動一次不超過 800 行AGENTS.md L127
你要給這臺 agent 加一個小功能:每輪對話開頭把當前 git 分支名寫進模型上下文。開啟倉庫,第一反應是往 codex-core 里加。session、context、guardian、tools 都在那兒,新檔案放進去最省事。依賴表不用改,呼叫鏈不用跨 crate。
過了一週,同樣的理由又進來三條。一個截斷工具輸出的 helper,一個模型供應商適配,一個會話恢復的邊角。core/src/lib.rs 頂部又多三個 mod。下游只要寫 use codex_core,編譯圖跟著變寬。有人想單獨複用上下文片段那個型別,發現它焊在 core 裡。要複用就得把整個 core 拉進來,包括沙箱、MCP、Guardian。
倉庫把這件事寫成禁令。AGENTS.md 用加粗英文寫 resist adding code to codex-core。新概念先問現有的非 core crate 能不能住。再問該不該新建一個 workspace crate,並且允許為此重構舊程式碼。core 是最後一檔。評審遇到往 core 裡堆功能的 PR,被要求主動擋回去。
出處:AGENTS.md 第 72 至 83 行
禁令寫進檔案的日期是 2026-03-26。當時 core 已經是最大 crate。立完之後 workspace 成員從 75 個長到 135 個,core 的生產程式碼卻還是漲了。擋的是預設往核心扔,擋不住核心繼續長。
清單是一份顯式陣列。codex-rs/Cargo.toml 的 members 數一遍是 135。目錄名和 crate 名要分開看:目錄叫 core,包名叫 codex-core,use 的時候寫成 codex_core。
出處:codex-rs/Cargo.toml 第 1 至 20 行;AGENTS.md 第 1 至 5 行;codex-rs/core/Cargo.toml 第 1 至 9 行
按 .rs 行數,少數幾個吃掉大半體積。core 33 萬行,tui 27 萬,app-server 14.8 萬。大於等於 1 萬行的 24 個,小於 2 千的 77 個。core 去掉測試後剩約 10.3 萬行。25 個 workspace 成員直接依賴它。tui 的 Cargo.toml 沒有這一行,它依賴 codex-app-server-client,再由 client 拉 core。往 core 加一行,直接下游 25 個要重編,tui 仍會被帶上。
出處:codex-rs/cli/Cargo.toml 第 41 至 42 行;codex-rs/tui/Cargo.toml 第 30 至 31 行
上帝包的失敗模式是這次很小、先放核心。把預設落點寫成明文,讓評審有權擋,不依賴某種語言。換個語言重寫,最小形態仍是這三問:現有包能不能住,該不該新建包,進核心憑什麼拆不出去。
依賴方向反了,編譯圖會從兩邊一起脹。core 自己已經依賴 61 個 codex-* crate,包括拆出去的 context-fragments 和 features。如果新的上下文型別再寫回 core,想複用它的人必須把沙箱和 Guardian 一起拉進來。葉子依賴核心,核心再依賴葉子,邊界就沒了。
拆出去的 crate 只帶自己需要的那一點。context-fragments 的包清單幾乎沒有業務依賴,只碰 protocol 和一段字串工具,對外 re-export 兩個片段型別和一個 trait。core 可以依賴它,它不依賴 core。git 分支名這種片段走這條路:型別落在 fragments,core 當呼叫方。模型供應商適配已經抽到 codex-model-provider。必須摸 session 內部狀態的東西,才走到最後一檔,評審仍要問為什麼拆不出去。
出處:codex-rs/context-fragments/src/lib.rs 第 1 至 6 行;codex-rs/core/Cargo.toml 第 26 至 42 行
旁邊還有兩把尺子。檔案目標 500 行,大約超過 800 行就開新模組。非機械改動一次不超過 800 行,複雜邏輯壓到 500。三層一起看,針對的是同一件事:人和 AI 都傾向於把改動寫大,寫進已經很大的檔案。
出處:AGENTS.md 第 49 至 61 行;AGENTS.md 第 125 至 131 行
這條禁令本身沒有 lint,沒有 CI job。倉庫裡檢索 resist adding code to codex-core,只命中 AGENTS.md 這一處。擋得住的是旁邊那幾條:依賴沒刷 Bazel lock,CI 紅;include_str! 沒改 BUILD.bazel,Bazel 紅。core 禁令擋得住習慣,擋不住有理由的例外,也擋不住漏看。
出處:AGENTS.md 第 37 至 43 行
編譯圖的方向是物理約束。葉子可以獨立編譯,被多箇中心複用。中心一旦吞下葉子型別,複用成本變成拉進整個中心。這個形狀換語言也成立。
DSH:能力全是外掛,沒有特權核心
DSH 根 AGENTS.md 把原則寫成加粗英文:everything is a plugin。Cordis 只收服務、型別化事件和可逆副作用。模型介面卡、工具註冊表、會話日誌、agent loop 都是外掛。沒有需要打補丁的特權核心。新包落進現有分組時,根 package.json 不用改,glob 會發現它。
Codex 用編譯期 crate 換掉了這套裝卸器,新能力必須改 members 陣列、寫 BUILD.bazel、重新編譯。能下手的位置只剩評審和 CI。評審管該不該進 core,CI 管兩份鎖有沒有一起改。
Grok Build:清單自動生成,靠目錄分層
Grok 根 Cargo.toml 第一行寫明這份 workspace 是生成的,人應該改各 crate 自己的清單。members 按同一口徑數是 79。組織方式寫在根 README:pager 是 TUI,shell 是執行時,tools 和 workspace 是領域能力,common / build 是葉子。
它沒有寫成給評審看的 core 禁令。切分本身被當成地圖,膨脹靠組合入口和抽 crate 消化。Codex 多付的是評審文字和雙構建鎖。
兩側均已核對原始碼 · 2026-08-22 · Grok · 79 個 Workspace 成員截斷工具輸出,該落在哪
又來一個小功能:工具返回太長時先截斷,再交給模型。它看起來像 helper,放進 core 的 tools 旁邊最省事。按剛才的三問推演:現有非 core crate 有沒有更合適的家,該不該新建一個只要字串工具的小包,進 core 會擋住哪一條依賴邊。
寫下你會擋哪一條邊,以及擋住之後正確的落點。如果選最後一檔,補一句評審會問什麼。