Skip to content

Course · Codex · Subagents

Delegate a noisy recategorisation to an isolated subagent context

The recategorisation is exactly the kind of task that should never run in your main thread: high-volume, thousands of rows, the same classification judgement applied over and over, pages of output you’ll skim once and never reference again. You don’t need the journey through every row, only the destination - the set of recategorised transactions and a summary of what changed. That shape, verbose work whose output you’ll never look at again, is the textbook case for delegating to a subagent. Here’s the tension underneath that textbook case, though: the isolation that makes the delegation worth doing is the same isolation that erases the reasoning behind the answer the moment the task finishes. You get the finding. You lose the ability to interrogate it.

Price the reading before you delegate anything

Section titled “Price the reading before you delegate anything”

Before you weigh whether to hand this off, weigh what it costs to do it at all - inline or delegated, the reading has to happen somewhere. A careful pass at the recategorisation needs three things to work from: the importer that shapes every row it’s about to classify (src/budgetcli/importers/csv.py, 210 lines, about 2,100 estimated tokens), the rules it’s checking each row against (src/budgetcli/categorise/rules.py, 512 lines, about 5,120 tokens), and the test suite that already pins down what “correctly categorised” means for this repo, so it doesn’t invent a rule the tests forbid (1,240 lines across the suite, about 12,400 tokens). Add it up: 19,620 tokens of reading, just to get oriented, before a single row gets reclassified.

Remember that number - 19,620. It’s about to turn into the whole case for isolation.

Run that reading inline and it sits in your window next to everything else you’re doing:

in your main thread (inline) in your main thread (delegated)
───────────────────────────── ───────────────────────────────
19,620 tokens of orientation read "recategorise history against the
3,000 rows read + reasoned over corrected taxonomy"
every reclassification logged a summary: 412 rows changed
the review you came here to do… the review you came here to do…
↑ buried under row dumps ↑ still right there, in reach

Same answer, wildly different footprint. The work you actually came to do - reviewing the changes, signing off - stays the most recent, most prominent thing in your context, instead of being pushed thousands of tokens into the past where the agent half-forgets it.

A subagent is only as good as the brief, because it starts without your context. So the delegation message has to carry everything the worker needs and nothing it doesn’t. For the recategorisation that means: the corrected category list (which lives in your AGENTS.md from the rules chapter - children inherit the in-scope AGENTS.md, so the taxonomy travels with them), the rule that money is integer cents, and a sharp definition of done.

> Delegate this to a subagent. Recategorise every transaction in the
imported history against the category list in AGENTS.md. For each row
that changes category, record the old and new category and the rule that
fired. Do not touch amounts - they're integer cents and stay untouched.
Return a summary table: count per category before and after, plus any
rows you couldn't classify confidently.

Notice what the brief asks back for: a summary, not the rows. Written out, a table like that runs a little over a paragraph - call it 1,200 characters, which the prose estimator puts at about 300 tokens. Set the two numbers next to each other: 19,620 tokens read, 300 tokens returned. The subagent paid about 65 times its own answer in reading you never see, in a window that isn’t yours.

Call that trick pay once, keep the finding. It’s the whole reason isolation is worth its cost, and you’ll reach for the same move in every later lesson that touches a subagent.

What “keep the finding” actually throws away

Section titled “What “keep the finding” actually throws away”

The finding is real, and 65-to-1 is a good trade in tokens. But the cost of delegating was never the reading - that reading happens whether or not you delegate it, and paying it in a window you never open is strictly better than paying it in the one you’re working in. The real cost shows up the moment the subagent’s window closes: the 19,620 tokens of reasoning that produced the 300-token finding are gone with it. Not archived, not searchable in a transcript - gone. If tomorrow you want to know why row 412 changed category and the summary table didn’t say, there is no “it” left to ask. You spawn a fresh subagent, hand it the same brief, and pay the 19,620 tokens again, hoping it reasons its way to the same answer twice.

Isolation doesn’t erase the cost of the search. It just moves it somewhere you can’t go back to.

That’s the honest version of “the parent pays only for the aggregated summary”: true about tokens, and silent about the fact that the parent also can’t ask a follow-up. Keep that trade-off in view every time a subagent’s answer looks a little too clean.

A subagent gets its own context window, but it does not start from a blank trust posture: by default it inherits the sandbox and approval settings live in your main thread at the moment you spawn it. A custom agent definition can pin its own - marking a summariser read-only, say - and any key it leaves out falls back to the parent’s; runtime overrides you set in your session are reapplied on top either way. The two-axis model from the approvals & sandbox chapter still governs the worker, it just usually governs it through the parent. The recategoriser is reading your transaction history and writing classification changes back; it has no business hitting the network or touching anything outside the data directory. So set that posture in your own session before you hand the task over - scoped to the workspace, network off, which is the workspace-write default - and the worker runs inside it. Different trust levels for different workers is still a security primitive worth using where a worker definition supports it; just don’t assume isolation you didn’t configure. The corollary to remember: loosening your own session to unblock yourself loosens every worker you spawn afterwards, so tighten first, then delegate.

Codex exposes a concurrency cap through agents.max_concurrent_threads_per_session (legacy alias agents.max_threads), while the current public config reference does not document a general maximum-depth key. Leave the concurrency setting unset to use Codex’s default, or set it explicitly after checking the official configuration reference. Do not build a workflow around an undocumented depth knob.

When to keep it in the main thread instead

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

Delegation isn’t free, and now you know exactly what it isn’t free in: not tokens, which it saves, but the reasoning trail, which it destroys. Keep the 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’s a quick, targeted change where spinning up a fresh worker that has to re-gather context just adds latency and a follow-up you can no longer ask. For a tiny clarifying detour (“does this bank export use DD/MM or MM/DD?”), a lightweight in-session side conversation is cheaper than a full subagent spawn; isolation is a cost you opt into, not a default.

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 recategorisation, yes - you want the result and the summary, not the reasoning. A delicate money refactor you’ll be steering line by line, no - the context the worker throws away is exactly the context you’d need to steer it.

One subagent could grind through the whole history in sequence, paying that 65-to-1 trade once. But notice the history splits cleanly - by account, by year, by import batch - into slices that don’t depend on each other. When a problem decomposes like that, one worker working serially is leaving speed on the table, and the same isolation cost you just paid once is about to get paid several times at once. Next we fan the work out and find out what that multiplication actually buys you.