Last updated on

A subagent is a context window you can throw away


A week ago I wrote about running several Claude Code sessions on one repo without them colliding. That was the heavyweight kind of multi-agent work: separate sessions, separate worktrees, separate databases. There's a lighter kind that gets far less attention, and it lives inside a single session: subagents.

Subagents might be the least understood feature in Claude Code. Most people either never touch them or use them badly: spawning an agent for a lookup that one grep would answer, or hand-building elaborate orchestration for work that needed none. Which is a shame, because used well they solve the thing that actually degrades a long coding session: the context filling up.

What a subagent actually is

Mechanically, a subagent is simple. The main session sends one prompt. A fresh instance of Claude starts with an empty context window, its own system prompt, its own tool list, and possibly a different model. It works: it reads files, greps, runs commands, and follows dead ends, then returns one final report. The parent session receives that report. Everything else the subagent did, every file it read and every wrong turn it took, is discarded.

That last sentence is the entire feature. The rest is configuration.

The framing that made subagents click for me: a subagent is not a helper. It's a context window you can throw away. You're not hiring an assistant; you're renting a room, letting it fill up with paper, and walking out with the one page that matters.

The economics

Long sessions don't fail because the model changes. They fail because the context accumulates things that stopped mattering. Ask a question like "where does revalidation happen when a post leaves a series?" and the honest way to answer it is to read across ten or fifteen files: collection hooks, the revalidation helpers, the join table config. If the main session does that reading, those fifteen files now live in its context for the rest of the conversation. The answer was three sentences. The evidence was several thousand lines, and the session carries the evidence around forever.

Hand the same question to a subagent and the parent pays for exactly the three sentences. The fifteen files fill a context window whose whole purpose is to be discarded. The phrase I keep coming back to is: keep the conclusion, not the file dumps.

This compounds. A session that delegates its reading stays coherent for hours, because its context holds decisions and conclusions rather than raw material. A session that reads everything itself hits the point where old file contents crowd out the current task, and you can feel the quality drop. The subagent's best outcome is invisible: a conversation that's still lucid an hour in.

When not to spawn one

The mistake in the other direction is just as common. If you can name the file and the symbol: "what does extractDiff in src/lib/shiki.ts actually strip?" Spawning an agent is strictly worse than reading the file. The agent boots with none of your conversation's context, re-derives things you already know, and you wait for the round trip. Delegation costs latency plus the agent's ignorance of everything you've established so far.

The rule of thumb I've settled on: delegate when the work is reading across: many files, unknown locations, a question whose answer requires a sweep. Do it inline when you can point at the answer's address.

The other case that's unambiguously worth it is independent parallel work. Three questions that don't depend on each other are three agents launched in one message, running concurrently. The parent gets three reports instead of doing three sweeps in sequence.

Specialization: the hostile reviewer

Everything above works with a general-purpose agent. The more interesting move is defining your own. Claude Code picks up agent definitions from .claude/agents/*.md: a Markdown file whose frontmatter declares the agent and whose body becomes its system prompt. This repo ships one:

---
name: adversarial-reviewer
description: Hostile, zero-sycophancy code reviewer that aggressively
  hunts for bugs, security flaws, concurrency issues, unhandled edge
  cases, and architectural anti-patterns. Report-only.
tools: Read, Grep, Glob, Bash
model: opus
---

Three of those lines do real work.

tools is an allowlist. This reviewer gets read tools and Bash, and nothing that edits. But there's a subtlety the definition has to handle in prose: dropping Edit and Write does not make a shell read-only. Bash can mutate anything. So the system prompt spells it out: Bash is for git diff, grep, and reading; never for commits, resets, installs, or anything that touches shared infrastructure. The tool list narrows the surface; the prompt carries the actual constraint.

model pins reviews to a stronger model than whatever the session happens to be running. Review is worth the spend; a file-listing sweep isn't.

description is the routing signal. It isn't documentation for humans; it's what the main agent reads when deciding whether a task should go to this agent. Write it like you're telling a dispatcher when to send this specialist.

But the real reason the reviewer is a subagent, rather than a prompt I paste into the main session, is the isolation itself. A reviewer living inside the session that wrote the code has watched the code get written. It has seen my reasoning, my justifications, my acceptance of each step. That's anchoring, and it produces the review you'd expect: agreeable. The subagent reads the diff cold, like a reviewer who wasn't in the room. Fresh context isn't a cost here: it's the point.

I ran into the same effect from a different angle in the four-reviewers experiment: identical diffs, four reviewers, four barely overlapping reviews. What a reviewer catches depends heavily on what's in its head when it starts reading. A reviewer with your whole session in its head is the worst version of that.

One more detail worth stealing. The slash command that launches this agent ends with an instruction to the parent:

Relay the agent's findings back verbatim; do not soften them,
and do not add a summary that reads as approval.

Because the parent summarizing the report is its own failure mode. The parent is invested in the code being fine, since it wrote it. Left alone, it will relay "the reviewer found two critical issues" as "mostly looks good, a couple of notes." The isolation you built on the way in gets laundered away on the way out unless you forbid it.

Isolation has levels

Read-only agents can all share the checkout: they're just looking. The moment two agents edit files in parallel, you're back to the collision problem from the sessions post, one level down: same working tree, last write wins. The fix is the same primitive. Agents can be launched with worktree isolation, giving each one its own checkout that's cleaned up if untouched.

It isn't free: each worktree costs setup time and disk, so it's worth it exactly when agents mutate files concurrently, and a waste for read-mostly fan-outs. The heuristic mirrors the session-level one: isolate the thing that's actually contended. For searches, nothing is; for parallel edits, the filesystem is.

Subagents vs. workflows

There's a boundary where subagents stop being the right tool, and it took me a failed automation to see it.

A subagent is model-driven delegation: mid-task, the model decides a piece of work should be farmed out, decides what to ask, and decides what to do with the answer. That flexibility is the feature and the liability. Every step the model decides to take is a step it can decide not to take.

This repo has a scheduled GitHub Action that reviews published posts and files editorial issues. The first version was one agentic step: review the posts, then file an issue per post with findings. It kept reviewing and then failing to file: the judgment part worked, the bookkeeping part was optional in a way no prompt fully fixed. The version that works is two-phase: the model's job shrank to reviewing and returning findings as schema-validated JSON, and a plain bash step files the issues. The model literally cannot forget to file, because filing isn't its job anymore.

That's the general principle for anything bigger than one delegation. Use the model where judgment lives; use deterministic structure where reliability lives. When you already know the shape of the fan-out: every changed file gets reviewed, every finding gets adversarially verified, keep hunting until two rounds come back empty; that shape should be code, not a hope that the model orchestrates itself correctly N times in a row. When discovery is the task and the shape emerges as you learn, that's delegation, and a subagent is the right tool.

Where I've landed

  • You can name the file and the symbol: read it inline. No agent.
  • One conclusion needs a sweep across many files: subagent. Keep the conclusion, not the file dumps.
  • Independent questions: parallel subagents, launched together.
  • Judgment that benefits from cold eyes, review above all: a specialized agent with its own definition, its findings relayed verbatim.
  • Agents editing files in parallel: worktree isolation. Agents only reading: don't bother.
  • The fan-out's shape is known up front: make the structure deterministic and give the model only the judgment steps.

The multi-session setup from the last post gets the attention because you can see it: terminals everywhere, worktrees on disk, PRs landing in parallel. Subagents do their best work where you can't see it: in all the files your main session never had to read.

Comments

No comments yet. Be the first to comment.

Leave a comment