Course · Claude Code · Subagents
Delegate the balance investigation to a subagent with its own context
Some questions are one line wide and a dozen reads deep. Here is one, from a small Express plus TypeScript payments service this course uses as its example. POST /payments succeeds with a 201 and a completed payment. GET /balance/:accountId for the same account returns {"balance":0}, and keeps returning 0 after every further payment, for every account. The route handlers live in src/index.ts; the Ledger class that records money lives in src/payments/ledger.ts and exposes append, balance, and history. The six tests in tests/payments.test.ts and tests/ledger.test.ts all pass.
You could chase it yourself: open the route file, open the ledger, grep for every caller of append and balance, skim both test files. Every one of those reads would land in your context window, the finite space that holds your conversation and every tool result, and stay there after it stopped being useful. Work with that shape, high volume in and one conclusion out, is what a subagent is for: a worker with its own context window that does the reading there and returns a summary to yours.
Ask for the trace
Section titled “Ask for the trace”There is no special command. Describe the work and say to use a subagent:
use a subagent to trace why GET /balance/:accountId returns 0 aftersuccessful payments. report the write path, the read path, and wherethey disagree. note which tests cover each, and which cover neither.The subagent always gets its own context window, but what initially enters that window depends on the session’s subagent mode. A non-fork subagent starts fresh with the task Claude writes for it; in interactive fork mode, a spawned subagent can inherit the conversation so far while still doing subsequent work in its own window. Either way, its detailed tool results stay out of the main thread unless it reports them back. The run below illustrates the fresh, non-fork case; it is not captured. The tool counts are invented, while the files and finding match the example service described above:
⏵ Agent (general-purpose) tracing the zero balance ⎿ Read src/index.ts ⎿ Grep "ledger\." src/ → 6 hits ⎿ Read src/payments/ledger.ts ⎿ Read tests/ledger.test.ts ⎿ Grep "balance" src/ tests/ → 8 hits ⎿ ... a few more reads ⎿ Done (11 tool uses)
The write path and the read path disagree on the account key.
- Write: POST /payments in src/index.ts calls ledger.append(result.id, result.amount) - the entry is filed under the payment's own UUID. - Read: GET /balance/:accountId calls ledger.balance(accountId), which counts only entries whose accountId matches the request. - Every entry gets a fresh UUID no caller can predict, so every real account sums to 0.
The Ledger class itself is sound: tests/ledger.test.ts calls append("acct_1", 500) directly and passes. No test posts a payment and then reads a balance, so nothing exercises the route wiring.Count what never entered your thread. Eleven tool calls, every grep hit, three files fully read, all of it lived in the subagent’s window and was discarded when it finished. What landed in your conversation is the finding: the route files payments under their UUIDs, the balance route reads by account id, and no test connects the two. You asked a sprawling question and received a tight answer.
The footprint you did not pay
Section titled “The footprint you did not pay”The cost is worth seeing side by side. The transcript above is illustrative, but the columns list what an inline run of the same investigation would put in your window:
inline, in your window delegated, in your window---------------------------------- ----------------------------------src/index.ts, fully read the prompt abovesrc/payments/ledger.ts, fully read the finding abovetests/ledger.test.ts, fully readgrep output for append and balancethe route fix you are about to plan the route fix you are about to plan ↑ buried under the reads ↑ still the nearest thing in contextSame answer, different footprint. The fix you are about to make stays the most prominent thing in your context instead of being pushed several file-reads into the past. This is the context-as-a-resource discipline from Sessions & context, bought up front: rather than compacting the noise away after it accumulates, you arrange for it never to enter the thread.
The docs state the rule in those terms: reach for a subagent when a side task would flood your main conversation with search results, logs, or file contents you will not reference again. See isolate high-volume operations.
When the main thread is the right place
Section titled “When the main thread is the right place”Delegation has a cost, and the docs are explicit about the other side. Keep work in your main conversation when it needs frequent back-and-forth, when phases share real context (planning into implementation into testing), or when it is a quick, targeted change for which a fresh agent would re-gather what you already hold. The current guidance lives at choose between subagents and main conversation.
The test is the one delegation always asks: would you hand this to a colleague, get back a paragraph, and be satisfied? The zero-balance trace passes; you wanted the disagreement, not the reading. The fix itself fails it in the other direction: it is one line in a route you now understand, and the context a subagent would throw away is exactly the context the fix needs.
One subagent answered one question. Before you fix that line, the surrounding ground deserves an audit: test coverage, idempotency, the rate limiter, the fee math. Those four questions do not depend on each other, which is the condition for running them at once. Next we fan them out.