Skip to content

Course · Codex · Subagents

Delegate the parse-path audit to an isolated subagent

Evidence first. The hardening has a known suspect - the float parse in app/importers/csv.py (line 14 since the categorizer wiring nudged it down a line), flagged when the course first audited the repo and turned into a proposed rule in the rules chapter. A fix designed against one suspicious line is still a fix designed against a guess.

Before touching anything, you want the parse path walked end to end: what the importer reads, what models.py accepts, and what the tests actually pin about money. That audit is exactly the shape that should never run in your main thread.

Greps for float and amount, probe runs like python3 -c "print(int(float('0.29') * 100))", file dumps, a read of the intake model - none of it is judgment; all of it is debris you will skim once and never reference again. You need the destination, a findings list, not the journey. Verbose work whose output you will never re-read is the textbook case for delegation, and this audit is that shape exactly.

Price the reading before you delegate anything

Section titled “Price the reading before you delegate anything”

Weigh what the reading costs before deciding where it runs, because inline or delegated, it happens somewhere. A careful pass at the parse path needs three things: the importer (app/importers/csv.py, 23 lines since the wiring, about 230 estimated tokens), the intake contract (app/models.py, 24 lines, about 240), and the tests that define pinned money behavior - the shipped suite plus the regression and wiring tests the course has added along the way, another 400 or so by now. Roughly 850 tokens of orientation before the worker can trust its own verdict.

Run that inline and it sits in your window next to everything else - illustrative layout, real numbers:

in your window (inline sweep) in your window (delegated sweep)
──────────────────────────── ────────────────────────────────
csv.py + models.py + tests: "sweep the parse path, read-only;
~850 est. tokens of reads csv.py, models.py, what the tests
grep hits, python3 -c probes pin about money"
the 0.29 -> 28 dead end findings: one violation (csv.py
the hardening brief, buried line 14), one coverage gap,
intake clean. ~100 tokens.

Same answer, wildly different footprint. The work you came to do - deciding the hardening’s shape - stays the most recent, most prominent thing in your context instead of being pushed hundreds of tokens into the past where the agent half-forgets it. The return itself, priced by the prose rule at four characters a token, runs about a hundred tokens: call it eight to one, read to return.

The brief carries everything the worker needs and nothing it does not: the files, the rule the sweep checks against, the return format.

> Delegate this to a subagent. Audit the money parse path, read-only:
app/importers/csv.py, app/models.py, and what tests/test_import.py
pins about amounts. Any use of float on a money value is a finding,
per the AGENTS.md cents rule and the parse-path rule the rules
chapter proposed. You may run no-write probes (python3 -c one-liners) to
check truncation. Return file:line findings plus a one-line verdict
per cleared file. Do not edit anything.

Note what the brief asks back for: findings and one-line verdicts, not a narrative. A subagent is only as good as its brief because it starts without your conversation - though it does start with the auto-loaded rules chain, so the cents rule and the proposed parse-path rule travel with it.

findings (illustrative reconstruction; your run supplies the wording):
VIOLATION app/importers/csv.py:14 - int(float(row["amount"]) * 100)
routes every amount through a float; 0.29 parses to 28.
GAP no test pins sub-dollar amounts - the truncation is silent
on the sample CSV, which happens to survive.
CLEAR app/models.py - amount_cents is int, enforced by pydantic.

Call that trick pay once, keep the finding. It is the whole reason isolation is worth its cost, and every later lesson in this chapter reaches for the same move.

What comes back, and what you can still reach

Section titled “What comes back, and what you can still reach”

The 850-odd tokens of reading and every dead end the worker ruled out live in the child’s agent thread - not your window, and not the bin either. /agent switches you into that thread to inspect it, and the finished worker stays listed with its result until you close it. If tomorrow you want to know why models.py was cleared rather than assumed, the transcript holding the answer is one thread-switch away.

What does not happen is the trail rejoining your context. Your window keeps the hundred-token finding; the reasoning that produced it stays in the child’s thread until you go looking. Follow-ups are possible - steer the worker while it runs, or route a follow-up instruction to its thread - but they are expeditions, not continuations of your chat.

Isolation moves the trail somewhere you can reach but your window never sees. That is the honest version of “the parent pays only for the summary”: true about your context, and silent about the fact that asking “why” later means opening a door rather than glancing up.

A subagent gets its own context, not a blank trust posture: by default it inherits the sandbox and approval settings live in your session at the moment it spawns. A custom agent file can pin a role’s own settings - a sandbox_mode, a model, an effort - and any key it omits falls back to the parent’s, with your live runtime overrides reapplied on top either way. The two-axis model from the approvals & sandbox chapter still governs the worker, usually through the parent.

This audit reads code and runs no-write probes, so it fits inside the budget-audit profile you built in that chapter - read-only with never - with nothing to escalate. Tighten first, then delegate: loosening your own session to unblock yourself loosens every worker you spawn afterwards.

Two knobs deserve their names, both in the Codex configuration reference. agents.max_concurrent_threads_per_session caps how many spawned threads stay open at once, with agents.max_threads as its legacy alias; leave it unset and Codex chooses the default. A depth key, agents.max_depth - root session at depth 0, default 1 - has appeared in the reference as a guard from the older multi-agent machinery, but the current reference documents the newer agent toolset and the concurrency cap instead. Treat depth as unavailable: cap concurrency, nest on purpose.

When to keep it in the main thread instead

Section titled “When to keep it in the main thread instead”

Delegation costs you the trail’s proximity, plus a little latency. Keep work in your main conversation when it needs frequent back-and-forth, when several phases share real context - planning into implementation into testing - or when it is a quick, targeted change where a fresh worker re-gathering context just adds a follow-up you must walk to another thread to ask. For a tiny clarifying detour, a side conversation is cheaper than a spawn.

The test is the same one as delegating to a person: would I hand this off, get back a paragraph, and be happy never asking a follow-up? The parse-path audit, yes - you want the findings list, not the reasoning. A delicate change you will steer line by line, no - the context you would need to steer it with is exactly what stays in the worker’s thread.

The findings list came back short: one violation, one coverage gap, everything else clean - and one worker paid the whole reading serially. That was the parse path audited deeply. The paths money takes after storage - the ledger’s sums, the endpoints that serve them, the newly wired categorizer - have not been walked yet, and they do not depend on each other. Next we fan the audit out and price what the multiplication actually buys.