Skip to content

Course · Codex · Rules (AGENTS.md)

The AGENTS.md budgetcli already has

You never wrote this file. It came with the clone, sitting next to README.md at the repo root, and it has been quietly doing its job since your first session. Here it is in full, exactly as the repo ships it:

AGENTS.md (as shipped)
# BudgetCLI - Agent Rules
## Money handling
- Money is always integer cents. Never use floats for currency.
- A $5.75 coffee is stored as `575`.
## Dates
- Dates are ISO 8601 UTC (e.g. `2024-03-15T00:00:00Z`).
- Never use locale-dependent date formats.
## Testing
- Run tests with `pytest`.
- All tests must pass before committing.
## Code style
- Use type hints on all function signatures.
- Prefer pydantic models over raw dicts for data validation.

Codex reads it without being asked. At the start of every session - before your first prompt - it builds an instruction chain that includes this file, no flag, no command, nothing to remember. That behavior is documented in the official AGENTS.md guide: the chain is assembled once per run, once per launched session. Twenty-one lines, 460 characters of standing context, present whether the session is about money or not.

Now hold the file against the code it governs, because this is where the chapter’s premise lives. app/importers/csv.py violates two of these rules. Not subtly, and not because the rules were missing.

The date rule says ISO 8601 only, never locale-dependent formats. The parser as shipped called datetime.strptime(row["date"], "%d/%m/%Y") on ISO data - a locale-dependent format string pointed at the one format the rules forbid. That one is now dead: a fix (covered in the course’s first-change lesson) replaced the format string, and the file did real work in the fixing - the agent’s plan cited this exact rule before editing, because the rule was in its context for free. A rule can inform a fix without having prevented the bug.

The money rule is still being broken. Line 13 of app/importers/csv.py reads amount_cents = int(float(row["amount"]) * 100) - every amount in the file routes through a float, against “Never use floats for currency.” The sample data happens to survive it; a quick Python check (int(float("0.29") * 100)) shows why it should not have to, landing 0.29 as 28 cents. This line shipped under a correct, auto-loaded rules file, and it sits there still, in a live money path, with the suite green.

So what is the file actually worth? Notice what the audit shows: it did not stop either violation, it made one fix cheap, and it was correct both times. A rules file is context - the cheapest possible place to be right. It is not a guard, and the last lesson of this chapter returns to that line with teeth.

Read the money rule again and ask what it tells an agent asked to parse an amount string. It states the destination - integer cents - but not the path there. And the natural first instinct for getting from "82.30" to 8230 is exactly the float shortcut already in the code. The rule forbids floats for currency and never says what to do instead at the boundary where strings become cents.

That is the file’s next line, and this is a proposal, not a repo fact - you would be its first author:

AGENTS.md - proposed addition
- When parsing an amount string, convert to integer cents without passing
through a float - use `Decimal` or string math, rounding half up.

The proposed line costs about 35 estimated tokens by the estimator below, taking the file from roughly 115 to roughly 150. It is written for the exact violation already on disk: it names the input (an amount string), the output (integer cents), the forbidden path (through a float), and the sanctioned ones. Whether it should live in the root file or next to the importer is the next lesson’s question.

Count what the repo is paying. Four hundred sixty characters of Markdown, at this course’s prose estimator of four characters per token, is roughly 115 tokens - every session, from clone to deletion, regardless of what the session is about. That is the rent. What it is not is fixed: the cost scales with the file’s size, in direct proportion. Twice as many rules would cost roughly 230 tokens a session. The mechanism is what never changes - loaded in full, every run, automatically.

Scale it honestly. The whole repo is about 2,000 estimated tokens, so the rules file is a small fraction of one read of the codebase it governs, and a rounding error against a 200,000-token window. Cheap - but recurring, so every line had better be load-bearing. A file this lean can justify itself with one informed fix; a file twice as long has to justify twice as much, every single session.

The check takes one fresh session. Start codex at the repo root, let the chain load, and give it a task that touches money without mentioning any convention - say, sketching an endpoint that reports spend per category using the ledger’s by_category() method. Then read the plan it writes back. Watch for the tells: amounts described in cents, dates in ISO, pytest named as the check. None of that came from your prompt. It came from 460 characters the repo has been carrying all along.

One file at the root now charges every session that rent - audit, proposal, and all. That is the right lease for facts every session needs, and the wrong one for facts only some sessions do. Where a file lives decides who pays for it, and that is a mechanism with rules of its own. Next: how Codex discovers and layers several AGENTS.md files at once.