Skip to content

Course · Codex · Rules (AGENTS.md)

The size cap, fallback filenames, and why AGENTS.md is not a boundary

The chapter has now built the full picture of a rules file: what it costs, where each file lives, what a good line looks like, what the repo’s file earned. This lesson is where the chapter admits what none of that buys you - two practical limits that bite quietly if you don’t know them, and one conceptual line that matters more than the rest of the chapter combined. And this time the proof is not a constructed scenario. It is the repo’s own history.

The project side of the discovery walk - every file Codex collects from the project root down to your launch directory - has a ceiling. It is set by project_doc_max_bytes in config.toml, and the default is 32 KiB (32,768 bytes) as of this writing. A default like this is exactly the kind of value that moves between releases, so read it off the config reference rather than trusting the number here.

Here’s the part that bites: once the combined project-chain size reaches that limit, Codex stops adding files and gives you no warning that it did. Rules past the cap simply aren’t in context.

One boundary of the cap is narrower than people assume. project_doc_max_bytes governs the project chain only. Your global ~/.codex/AGENTS.md is loaded separately, before the walk, and is not charged against that budget - so a fat global file cannot push your project rules past the cap. It still costs its tokens in every session on every project; it just can’t evict the project file.

The cap itself stays a real hazard for the project side: stack a fat root file with a few nested files on a deep launch path, and the file that falls off the end might be the one you actually care about.

For budgetcli (the course’s running example, a small self-hosted personal-finance API in Python and FastAPI) this is comfortable headroom. The whole project chain today is one 460-byte file; you could add the parse-path proposal (the one drafted line this chapter adds: convert amount strings to integer cents without passing through a float) and forty like it without noticing the ceiling. The discipline is still worth having now, on a repo where mistakes cost nothing: keep each file lean so you never approach the limit. If you genuinely need more room you can raise project_doc_max_bytes, but the better instinct is to prune first.

~/.codex/config.toml
# Default is 32 KiB. Raising it is a last resort - prune first.
project_doc_max_bytes = 32768

Codex looks for AGENTS.md by name. If a project keeps its standing context under a different name, you can tell Codex to accept other filenames via project_doc_fallback_filenames - an array of additional names it tries in each directory when AGENTS.md is missing:

~/.codex/config.toml
project_doc_fallback_filenames = ["CONTEXT.md", "CONVENTIONS.md"]

The per-directory order from the discovery walk still holds: at each level Codex checks AGENTS.override.md, then AGENTS.md, then your fallback names, and uses at most one file from that directory. The fallbacks are a safety net for the base file, not a replacement for the override. Both knobs are documented in the config reference.

Now the part to internalize, and the reason this chapter exists. Everything in it - the money rule (“Money is always integer cents. Never use floats for currency.”), the date rule (“Never use locale-dependent date formats.”), the parse-path proposal, the whole file - is guidance the model interprets, not a constraint the system enforces. AGENTS.md shapes what Codex tends to do. It does not prevent anything.

And budgetcli is the proof, no hypothetical needed. A correct, auto-loaded rules file was in context when the day-first date parse ("%d/%m/%Y", line 11 of app/importers/csv.py) shipped against its date rule, and it is in context right now while line 13 of the same file (int(float(row["amount"]) * 100)) parses money through a float against its money rule. Both violations shipped. The file was read both times.

The repo’s own testing rule shows the same line from another angle. “All tests must pass before committing” is in the file, and it is a good rule - specific, checkable, exactly the shape the last lesson prescribed. But it is a wish, not a gate. Nothing in Codex consults it before a commit happens; it relies on the model choosing to comply, which it usually does, and “usually” is not a mechanism.

When a rule is load-bearing for safety - never touch this, always run that - a sentence in Markdown is the wrong tool. The right tools are the ones you already have and the ones coming: the sandbox and approval policy bound what the agent can do, and later chapters add gates that run deterministically, whatever the model’s mood.

That is the entire reason the approvals-and-sandbox chapter came before this one. The fence and the rules answer different questions. budget-audit - the saved profile that pairs a read-only sandbox with never approvals, so no write can be requested or granted - prevents writes; AGENTS.md merely discourages wrong ones. You need both, and you must never let a rule stand in for a boundary - not even a rule that just made a fix cheap.

What the chapter produced, and what it did not

Section titled “What the chapter produced, and what it did not”

Count the chapter’s own output honestly. The audit cost one read of a file the repo already had and changed no code. What it produced is understanding - the file informs, it does not enforce - plus one proposed line that states the sanctioned path from amount strings to cents. The hardening itself, the code change that kills the float parse in app/importers/csv.py, has not happened. Neither has the other job this chapter kept naming: wiring categorise() (the keyword categorizer in app/services/categorise.py, which nothing calls yet) into the import path, so imported transactions stop landing "uncategorised".

Both jobs are exactly the kind of work the next chapter prices. One is pattern-following; one is a genuine design fork - where the categorizer hooks in, how conflicts resolve, what the keyword table has to say about each. They need different amounts of thought, and thought is a dial Codex exposes: which model, how much reasoning effort, per task. That is the next chapter.