Claude Code Subagents: Best Practices

Scope each subagent to one question with a stated return shape. Give it the context you’d give a contractor who has never seen your codebase. Don’t delegate anything you’d want to watch happen. Most bad subagent runs violate one of those three.

A subagent takes about six lines of frontmatter to set up, which is part of why so many of them get used badly. The failure mode is quiet: the subagent returns something plausible, you act on it, and the cost shows up an hour later when the thing it told you turns out to have been half true. Here’s what actually holds up in practice.

scope to one question, and say what shape the answer takes

Get this one right and most of the other problems don’t happen. A subagent is not a junior teammate you hand a project to. It’s a query with a fresh context window attached.

Bad:

Look at the auth system and tell me what's wrong with it.

That gets you four paragraphs of hedged prose and no way to act. Good:

List every file under src/auth/ that reads a session token directly
instead of going through getSession(). Return file:line and the calling
function. No fixes, no commentary.

The second one has a bounded question and a stated return shape. Two things follow from that. You can check the answer in thirty seconds, because file:line either exists or it doesn’t. And the subagent knows when it’s done, which stops it wandering into the twelfth adjacent file.

State the shape explicitly, every time. “Return a markdown table with columns X, Y, Z.” “Return at most five findings, ranked.” “Return the failing test names and their error messages, nothing else.” Anthropic’s own subagent docs use exactly this framing for the canonical case: “Use a subagent to run the test suite and report only the failing tests with their error messages.”

the context you don’t pass is the context it doesn’t have

This is the one that bites people who assume delegation works like it does with a person sitting next to them.

A non-fork subagent starts with a fresh, isolated context window. It does not see your conversation history, the files Claude already read for you, or the skills you already invoked. What it does get is its own system prompt, the CLAUDE.md hierarchy your session loads, a git status snapshot, and a delegation message that Claude composed by summarizing your request.

That delegation message is the whole briefing. If you said “check the other one too” and the summary lost what “the other one” meant, the subagent goes looking for something that doesn’t exist and reports confidently about whatever it found instead.

Practical consequences:

  • Name things fully in the delegation prompt. Absolute paths, exact function names, the branch. Nothing that resolves only against your conversation.
  • Restate constraints that live in the conversation rather than in CLAUDE.md. If you told your main session to ignore vendor/, the subagent never heard it. Say it again in the prompt.
  • Watch the built-ins. The Explore and Plan agents skip CLAUDE.md and git status entirely, so project rules genuinely don’t reach them. The main conversation reads their results with full context, which covers most cases, but a rule that has to shape the search has to be in the prompt.
  • When the briefing gets long, you’re using the wrong tool. If it takes six sentences of background before the task makes sense, either fork the conversation (a fork inherits the full history and still keeps its tool calls out of your window) or don’t delegate it.

don’t delegate work you need to watch

A subagent returns a summary. That’s the contract. Every intermediate step, every file it read, every command it ran, gone unless the summary mentions it.

That’s exactly what you want for a search. It’s exactly what you don’t want for a refactor you’d have opinions about halfway through. If your instinct is “I’d want to see what it’s doing,” you’ve already got the answer: it isn’t a subagent task.

The tell is retrospective and expensive. You delegate “migrate the payment module to the new API,” get back “migrated 14 call sites, all tests pass,” and now you’re reviewing a diff you have no narrative for. You saved context and spent it back on archaeology.

Delegate the parts you’d skim. Keep the parts you’d read.

parallel fan-out is where they actually pay off

One subagent saves you context. Several at once save you time, and that’s the bigger number.

Research the auth, billing, and notification modules in parallel using
separate subagents. Each returns the public entry points and every
external service it calls.

Three independent windows, three simultaneous investigations, one synthesis at the end. This works when the paths genuinely don’t depend on each other. It fails badly when they do, because subagent two can’t see what subagent one found, and you get three partial pictures that contradict each other at the seams.

Test for independence before fanning out: could you hand each of these to a different person on a different day without them needing to talk? If yes, fan out. If no, chain them instead, and pass the relevant piece of each result into the next prompt yourself.

One caution the docs flag and people learn the hard way: results come back into your main conversation. Eight subagents each returning a detailed report is eight detailed reports in your window. Fan-out only saves context if you also constrain what comes back. Tight return shapes matter more at scale, not less.

three cheap subagents often beat one expensive one

model accepts sonnet, opus, haiku, fable, a full model ID, or inherit, and it defaults to inherit. That default is worth overriding more often than people do.

Mechanical work does not need your best model. Finding every call site, listing every file that imports a module, extracting the error messages from a test run: these are pattern-matching jobs where a fast model is right nearly all the time and wrong in ways you’ll spot immediately. Running three of those on haiku costs a fraction of one opus pass and finishes sooner.

The split that holds up: cheap models gather, expensive models decide. Fan out searches on haiku, synthesize in your main session. Where the judgment is the actual deliverable, a security review, an architecture call, a “is this a good idea,” pay for the model.

restrict the tools, especially for reviewers

tools sets what a subagent can use and inherits everything if you leave it off. disallowedTools subtracts from whatever it would otherwise have.

An auditor defined with tools: Read, Grep, Glob cannot edit a file. Not “was told not to.” Cannot. That difference matters most for the subagents you’re least likely to watch closely, which is the same set you’re most tempted to run in bulk.

---
name: dep-auditor
description: Use when checking dependencies for unpinned versions or
  abandoned packages before a release.
tools: Read, Grep, Glob, WebFetch
model: haiku
maxTurns: 15
---

Report unpinned versions and packages with no release in 18 months.
Return a table: package, current spec, last release date, risk note.
Do not propose upgrades.

maxTurns is the other underused field. It caps how long a subagent can loop, which turns “this one went strange and burned tokens for six minutes” into a bounded failure.

verify before you act

A subagent’s summary is a claim, not a result. It’s a claim made by a process whose reasoning you can’t inspect, about files you haven’t opened.

Cheap verification beats careful prompting:

  • If it reports file:line, open one or two. Wrong line numbers mean the whole list is suspect.
  • If it says tests pass, run the tests. This costs one command.
  • If it says “no other call sites exist,” grep once yourself. Negative claims are where subagents are least reliable, because “I didn’t find any” and “there aren’t any” look identical in a summary.
  • If two subagents cover overlapping ground, compare them. Disagreement is free signal.

None of this is distrust for its own sake. It’s the natural cost of a format that hands you conclusions without evidence, and it’s much cheaper than acting on a wrong one.

good tasks, bad tasks

Good subagent taskWhyBad subagent taskWhy
”Run the test suite, return failing test names and error messages only”Huge output, tiny useful answer”Fix the failing tests”You’d want to see each fix
”List every component importing useAuth, with file:line”Bounded, checkable, mechanical”Improve the auth code”No return shape, no way to verify
”Read these four RFC pages and summarize what changed in v3”Fetching is verbose, summary is small”Design our v3 migration”Judgment work you should be in
”For each of these three modules, list external service calls”Genuinely independent, parallel-safe”Refactor these three modules consistently”They need to see each other
”Find the commit that introduced this behavior”One question, one answer”Clean up the repo”Unbounded, invisible, unreviewable

The pattern across the good column: you could verify the answer faster than producing it.

write descriptions as routing rules

For subagents you define as files, description isn’t documentation. It’s the text Claude reads to decide whether to delegate at all. Write the trigger, not the title.

Weak: A code reviewer.

Strong: Use after a feature is complete and before opening a PR, to check the unstaged diff against project conventions. Specify which files to focus on when it isn't the recent diff.

The strong one tells the model when, what to look at, and what to pass along. The weak one gets ignored or fires at random.

where subagents stop being the answer

Subagents solve one problem well: keeping work out of your context window. They solve nothing about visibility, and past a certain size that becomes the problem you actually have.

When a task is big enough that you’d want to read its reasoning, interrupt it partway, or let it run for an hour, a summary-only format is working against you. Nested subagents make it worse rather than better: only the top-level summary comes back, so the intermediate work vanishes twice over.

That work wants to be its own session, somewhere you can see it. That’s what crystl is for. Each shard is a full agent session with a visible transcript, so conversation history shows what a worker did rather than what it decided to summarize, and the agent activity panel shows every running shard’s live activity and token spend in one view. Independent work gets an isolated shard with its own git worktree, so parallel agents do not share a live working directory. Notifications tell you when one finishes or parks on an approval, which is the thing a silent subagent can never do.

Use subagents for the searches, the test runs, the doc fetches, the bounded questions. Use orchestration and parallel sessions for the work you’d want to watch.

Related reading: Claude Code subagents explained for the full mechanics, skills vs subagents if you’re choosing between the two formats, Claude Code agents for the four different things people mean by “agent,” and git worktrees with Claude Code for keeping parallel work off each other’s toes.