Course · Codex · Rules (AGENTS.md)
How Codex discovers and layers AGENTS.md files
Not every fact deserves the root file’s lease. The 115 tokens that AGENTS.md in budgetcli (the course’s running example, a small self-hosted personal-finance API in Python and FastAPI) charges buy four rules every session needs - money, dates, tests, style - and that is the right deal for them. But two other kinds of rules fit it badly. “Explain your plan before editing” is a personal habit: paste it into the shared file and every teammate who clones the repo pays rent on your working style. Importer-format details matter in exactly one directory of the tree.
Both want a narrower lease, and Codex has one - because it does not read a single AGENTS.md. It assembles a chain, and where a file lives decides which sessions pay for it.
The discovery walk
Section titled “The discovery walk”The chain is built once per session, at start, before your first prompt. The walk has two halves, broadest to most specific:
Global ~/.codex/AGENTS.md (you, every project on this machine)Project <project root>/AGENTS.md (budgetcli/AGENTS.md - typically the git root) ...one file per directory, down the launch pathLaunch dir <where you ran codex>/ (the directory you launched Codex in)Codex reads your global file first - ~/.codex/AGENTS.md if you have one. Then it starts at the project root, typically the git root, and walks down the directory tree toward the directory you launched from, taking at most one file per directory on that path. The walk stops at the launch directory. It does not sweep the whole tree.
That stopping point is the detail most people get wrong. A nested AGENTS.md loads when its directory is on the launch path - the project root down to where you started Codex. It does not load because the agent is working in that corner mid-session. Discovery runs once and never reruns, so a session launched at the repo root carries the root file and only the root file, no matter how deeply the agent later edits. If importer rules belong in context, put the launch directory on their path:
codex --cd app/importerscodex -C app/importers # the same flag, short form--cd (or -C) sets the working directory before the agent starts processing, which makes app/importers/ the launch directory - so the walk collects budgetcli/AGENTS.md, any file in app/, and the importer’s own file, in that order.
They concatenate - they don’t fight
Section titled “They concatenate - they don’t fight”Be precise about what happens to the files the walk collects, because this is the part people get wrong. They do not override each other wholesale. Codex concatenates them - global first, then root down to the launch directory - joining them with blank lines into one combined brief. Your global file and the project file and any nested file are all present at once. Scoping a rule narrower doesn’t remove it from context; it stops it from being paid for by sessions that never see it.
Order is how conflicts resolve. Files closer to your launch directory appear later in the concatenated text, and later guidance overrides earlier guidance. So a rule in app/importers/AGENTS.md beats a same-topic rule at the repo root, which beats your global file. Broadest is the default; most specific is the final word. Layering doesn’t fix a bad rule - it just decides which bad rule wins.
For budgetcli, the layering is real at two levels and illustrative at the third:
- Global (
~/.codex/AGENTS.md) - your personal working style across all projects. “Explain your plan before editing.” Follows you, ships to no one, costs no one but you. - Project root (
budgetcli/AGENTS.md) - the audited file: integer cents, ISO dates, the pytest gate, the style rules. Committed to git, so every clone gets it, and its ~115 tokens are spent by every session. - Subdirectory (
app/importers/AGENTS.md) - the repo has none today, so treat this as a constructed illustration. Say a 50-token file of import-format facts lived there. Root-launched sessions never load it and never pay for it; a session launched with--cd app/importersloads it and pays. Narrow lease, exactly as advertised - and useless to every session that does not launch through it.
AGENTS.override.md wins at its level
Section titled “AGENTS.override.md wins at its level”There is one more filename in the walk. At every level - your global home and each project directory on the path - Codex checks for AGENTS.override.md before the plain AGENTS.md, and uses the first one it finds: an override replaces the level’s AGENTS.md entirely, it does not patch it. That is the escape hatch for superseding a rule without editing the shared file everyone depends on - and it is also the trap: write only your loosened rule into the override and every other rule from the replaced file (integer cents, ISO dates, the pytest gate) stops loading for as long as the override exists. An override that means to loosen one rule must carry the whole file’s content with that one rule changed.
Concretely: if budgetcli/AGENTS.md is the committed team file and you drop a budgetcli/AGENTS.override.md next to it, the override beats the base file at the project root - the move for a local exception, like temporarily loosening a convention while you experiment, without touching version-controlled guidance. Same shape globally: ~/.codex/AGENTS.override.md wins over ~/.codex/AGENTS.md.
The full mechanics - the once-per-session walk, the launch-path rule, the per-level file choice - are pinned in the official AGENTS.md guide. And the walk is one row of Codex’s wider file map: the same global-versus-project line runs through config.toml, agents, hooks, and the .agents/skills/ standard you will meet later in the course. Hold the layout once and the rest has an address:
You now have the full map of how Codex assembles its rules: global to launch directory, concatenated in order, closer-wins, override-on-top. Scoping a rule right controls what it costs. It says nothing about whether Codex actually does what the rule asks once it is loaded - and budgetcli has already proven that a well-scoped file of good rules did not stop a 21-line importer. That is the next move: what separates a rule Codex follows from one it skims past.