New features find a crate first. core is last.
Open the repo and your first move is dumping it into core. The repo writes that down as a ban: look for an existing non-core crate, or make a new one. Dependency direction keeps leaf types out of the kernel.
codex-core. How dependency direction keeps it out of a layer, and where it should land after that. This ban has no machine red light — what still keeps it running.
- workspace members is an explicit array, 135 todayCargo.toml L3
- The directory is core; the crate name is codex-coreAGENTS.md L4
- The ban: resist adding code to codex-coreAGENTS.md L76
- Ask first whether an existing non-core crate can host itAGENTS.md L80
- Otherwise make a workspace crate, and allow refactoring old codeAGENTS.md L81
- Review actively blocks PRs that pile into core without needAGENTS.md L83
- core already depends on the extracted context-fragmentscore/Cargo.toml L35
- A non-mechanical change stays under 800 linesAGENTS.md L127
You want a small feature on this agent: at the start of each turn, write the current git branch into the model context. Open the repo and your first move is adding it to codex-core. session, context, guardian, tools all live there. Dropping a new file in is the cheap path. No dependency table to edit. No call chain across crates.
A week later, the same reason brings three more: a helper that truncates tool output, a model-provider adapter, a session-restore corner. core/src/lib.rs grows three more mods at the top. Downstream writes use codex_core and the compile graph widens. Someone wants to reuse just the context-fragment type and finds it welded into core. Reuse means pulling the whole core — sandbox, MCP, Guardian.
The repo writes this as a ban. AGENTS.md says in bold English resist adding code to codex-core. A new concept asks first whether an existing non-core crate can host it. Then whether to make a workspace crate — and you may refactor old code to do it. core is last. Review is told to actively push back PRs that pile features into core.
Source: AGENTS.md lines 72–83
The ban landed in the file on 2026-03-26. core was already the largest crate. After that, workspace members grew from 75 to 135 — and core’s production code still grew. It stops the default toss into the kernel. It does not stop the kernel from growing.
The roster is an explicit array. Count members in codex-rs/Cargo.toml and you get 135. Directory name and crate name split: the directory is core, the package is codex-core, and use writes codex_core.
Source: codex-rs/Cargo.toml lines 1–20; AGENTS.md lines 1–5; codex-rs/core/Cargo.toml lines 1–9
By .rs line count, a few crates eat most of the volume. core 330k, tui 270k, app-server 148k. 24 are ≥10k lines; 77 are under 2k. Drop tests and core is about 103k. 25 workspace members depend on it directly. tui’s Cargo.toml has no such line — it depends on codex-app-server-client, and the client pulls core. Add one line to core and 25 direct dependents rebuild. tui still gets pulled along.
Source: codex-rs/cli/Cargo.toml lines 41–42; codex-rs/tui/Cargo.toml lines 30–31
The god-crate failure mode is “this one’s small, drop it in the kernel.” Write the default landing in plain text so review has the right to block — no language required. Rewrite in another language and the minimum shape is still these three questions: can an existing package host it, should you make a new one, and if it enters the kernel, why can’t it be extracted.
Reverse the dependency direction and the compile graph swells from both sides. core already depends on 61 codex-* crates, including extracted context-fragments and features. Write a new context type back into core, and anyone who wants to reuse it must pull the sandbox and Guardian too. Leaves depend on the kernel, the kernel depends on leaves — the boundary is gone.
An extracted crate carries only what it needs. The context-fragments package list has almost no business deps — protocol plus a string helper — and re-exports two fragment types and one trait. core may depend on it. It does not depend on core. A git branch-name fragment takes this road: the type lands in fragments, core is the caller. Model-provider adapters already live in codex-model-provider. Only things that must touch session internals go to last resort, and review still asks why they can’t be extracted.
Source: codex-rs/context-fragments/src/lib.rs lines 1–6; codex-rs/core/Cargo.toml lines 26–42
Two more rulers sit beside it. File target 500 lines; past about 800, open a new module. A non-mechanical change stays under 800, complex logic down to 500. Read the three together and they aim at the same thing: humans and AIs both like to write a change large, into a file that is already large.
Source: AGENTS.md lines 49–61; AGENTS.md lines 125–131
The ban itself has no lint, no CI job. Search the repo for resist adding code to codex-core and you hit only AGENTS.md. What does fire is the neighbors: skip a Bazel lock refresh and CI goes red; include_str! without a BUILD.bazel change and Bazel goes red. The core ban stops the habit. It does not stop a reasoned exception, or a miss.
Source: AGENTS.md lines 37–43
Compile-graph direction is a physical constraint. A leaf can compile alone and be reused by many centers. Once a center swallows a leaf type, reuse means pulling the whole center. That shape holds in any language.
DSH: every capability is a plugin. No privileged kernel.
DSH’s root AGENTS.md writes the principle in bold English: everything is a plugin. Cordis only takes services, typed events, and reversible side effects. Model adapters, the tool registry, session logs, the agent loop — all plugins. No privileged kernel to patch. When a new package lands in an existing group, the root package.json stays put. A glob finds it.
Codex swapped that loader for compile-time crates. A new capability must edit the members array, write BUILD.bazel, and recompile. The only hands left are review and CI. Review asks whether it should enter core. CI asks whether both locks moved together.
Grok Build: the roster is generated. Layering is directories.
Grok’s root Cargo.toml says on line 1 that this workspace is generated. People should edit each crate’s own manifest. Count members the same way and you get 79. The root README is the map: pager is the TUI, shell is the runtime, tools and workspace are domain capability, common / build are leaves.
It never wrote a core ban for review to read. The split itself is the map. Growth is digested by composing entries and extracting crates. What Codex pays extra is review prose and a dual build lock.
Source-checked on both sides · 2026-08-22 · Grok · 79 workspace membersTruncating tool output — where should it land?
Another small feature: when a tool return is too long, truncate it before the model sees it. It looks like a helper. Parking it next to tools in core is the cheap path. Walk the three questions: does an existing non-core crate have a better home, should you make a tiny string-utility crate, and which dependency edge does core block.
Write down which edge you would block, and the right landing after that. If you pick last resort, add the question review will ask.