Subagents & Parallel Agents
Isolated context for heavy, independent work
- Explain why subagents run in isolated context and report summaries back, and when that keeps the main conversation clean
- Define a subagent with the --agents JSON shape ({name:{description,prompt}}) or the /agents manager
- Apply the Writer/Reviewer and adversarial-subagent patterns to get unbiased, fresh-context review
- Use /batch <instruction> to decompose a large change into 5-30 units, review the plan, and fan out one background subagent per unit in isolated worktrees
- Distinguish subagents from skills (model-invoked on demand) and hooks (deterministic), and choose the right one
A subagent is a helper that runs in its own fresh, isolated context, does heavy or independent work, and reports only a summary back — keeping your main conversation clean. This lesson covers defining agents via --agents JSON or the /agents manager, the Writer/Reviewer and adversarial-review patterns, and the /batch orchestrator that fans a large change out across isolated git worktrees.
- 1The mental model: a fresh pair of hands with its own desk
- 2They see the conversation but start fresh
- 3Defining subagents: --agents JSON and the /agents manager
- 4Pattern 1 — Writer / Reviewer
- 5Pattern 2 — Adversarial review
- 6The /batch orchestrator: parallel work in isolated worktrees
- 7Subagents vs. skills vs. hooks: pick the right tool
The mental model: a fresh pair of hands with its own desk
Your main conversation is a single context window. Every file Claude reads, every grep result, every verbose log dumps tokens into that one window — and as it fills, quality degrades. A subagent is the fix: a helper Claude spawns that runs in its own, separate context window, does a chunk of work there, and reports a summary back to the main thread. The heavy lifting — the hundred files it read, the dead ends it explored — never touches your main conversation.
Think of it as delegating to a colleague at their own desk. They can see the conversation that led to the request, but they start fresh — they don't inherit your full working memory, and you don't inherit theirs. When they're done, they hand you a one-page summary, not their entire scratch pad.
MAIN CONVERSATION (stays clean — only sees the summary)
│ delegates a task
▼
┌─────────────────────────────┐
│ SUBAGENT (isolated context)│ reads 100 files, greps,
│ explores freely, burns │ tries dead ends — none of
│ tokens in its own window │ this lands in your thread
└─────────────────────────────┘
│ reports a SUMMARY
▼
MAIN CONVERSATION (continues, uncluttered)This is why subagents shine for large, independent exploration: "map every place we call the payments API," "figure out why this test is flaky," "audit the codebase for hardcoded secrets." Each is a self-contained investigation whose raw output you don't want polluting the main window — you just want the answer.
Key insight
Isolated context is the whole point
A subagent's value isn't that it's a different model — it's that it has a separate context window. It absorbs the token cost of heavy exploration so your main conversation stays sharp. If a task would dump a lot of raw material (logs, search results, file dumps) you don't need verbatim, that's the signal to delegate it.
They see the conversation but start fresh
There's a subtlety that trips people up. A subagent can see the conversation that spawned it — it has the context of why it was asked. But it starts fresh: it does not carry your full accumulated working state, and crucially it may not internalize your project's conventions unless you say so.
The practical consequence: pass project conventions explicitly in the task description. Don't assume the subagent "already knows" that you use 2-space indentation, that tests live in __tests__/, or that the team forbids a particular library. A vague delegation gets a vague, off-convention result.
A weak task description:
Go review the auth module.A strong one:
Review src/auth/ for security issues. Conventions: we use Zod for all
input validation, never raw try/catch around DB calls (use the withDb()
helper), and all errors must go through reportError(). Flag any deviation.
Return a prioritized list with file:line references — no code edits.The second version tells the fresh-context subagent exactly what "correct" looks like and exactly what to hand back. The richer the task description, the better the summary you get.
Tip
Treat the task description like a system prompt for that one job
Because the subagent starts fresh, the task description is effectively its entire briefing. State the goal, the relevant conventions, the boundaries (e.g. "read-only, no edits"), and the exact shape of the output you want back. Specific instructions land; vague ones get ignored.
Defining subagents: --agents JSON and the /agents manager
There are two ways to create reusable subagents.
1. The --agents flag (JSON, at launch). Pass a JSON object keyed by agent name. Each entry carries the frontmatter-style fields plus a prompt — its standing instructions:
claude --agents '{
"reviewer": {
"description": "Reviews diffs for correctness and security, no edits",
"prompt": "You are a meticulous code reviewer. Read the diff, flag correctness bugs, security issues, and convention violations. Return a prioritized list with file:line references. Never edit files."
}
}'The shape is {name: {description, prompt}}. The description tells Claude when to reach for this agent; the prompt is how it behaves once invoked. You can define several agents in one object.
2. The /agents manager (interactive). Run /agents inside a session to open the subagent manager — create, edit, and inspect agent configurations through a UI, and set up the agents a project needs without hand-writing JSON. This is the recommended entry point for a first session in a repo (alongside /init, /memory, and /mcp).
Once defined, an agent can be invoked by Claude when its description matches the task, or you can direct work to it explicitly.
Note
description triggers, prompt governs
The description field is the matchmaker — it's what Claude reads to decide whether this agent fits the current task, so make it precise about scope. The prompt field is the agent's persistent behavior. Keep them aligned: a description that promises "read-only review" and a prompt that edits files will produce surprises.
Pattern 1 — Writer / Reviewer
The most useful subagent pattern exploits a simple truth: the context that wrote the code is biased toward believing it's correct. It just spent effort producing the change; it's primed to rationalize. A reviewer in a fresh context has no such investment — it reads the diff cold and judges it on its merits.
So split the work across contexts. One actor (the main conversation, or a Writer subagent) produces the change. A separate Reviewer subagent — fresh context, no memory of the design decisions — reviews it.
Main context → writes the feature
│
▼
Reviewer subagent (fresh context) → reads only the diff + conventions
│
▼
Returns findings → main context fixes themThe fresh context is doing the work here. Because the reviewer didn't see why each choice was made, it can't be talked into accepting a shortcut — it sees only what's actually on the page. Give it the diff and the conventions, and ask for a prioritized findings list with file:line references rather than edits, so you stay in control of the fixes.
This is the same principle behind running review as a separate session entirely — Session A writes, Session B reviews with no shared state. Subagents bring that benefit inside a single conversation.
Example
A reviewer that won't rubber-stamp
Define reviewer with --agents (read-only, returns file:line findings). After Claude implements a feature in the main thread, say: "Hand the diff to the reviewer subagent. Conventions: [list]. Have it return a prioritized findings list — no edits." You get a critique from a context that has no stake in the design, then you decide what to fix.
Pattern 2 — Adversarial review
Writer/Reviewer asks "is this good?" An adversarial subagent asks the sharper question: "how is this wrong?" Instead of evaluating quality neutrally, you task the subagent to actively try to refute the result — to find the input that breaks it, the assumption that doesn't hold, the test that's quietly passing for the wrong reason.
The framing matters. Compare:
# Neutral reviewer
Review this caching layer for issues.
# Adversarial subagent
Your job is to PROVE this caching layer is broken. Find a sequence of
operations that returns stale data, a concurrency race that corrupts the
cache, and any input that bypasses invalidation. Assume it's buggy until
you've genuinely failed to break it. Report every refutation with a
concrete reproduction.The adversarial prompt produces a different search — the subagent hunts for counterexamples instead of confirming the happy path. Because it runs in isolated context, it can explore aggressively (read everything, trace every branch) without bloating your main thread, and it reports back only the refutations it found.
Use adversarial review for anything where being confidently wrong is expensive: security boundaries, concurrency, data migrations, financial calculations. Pair it with a verifier — when the adversary claims a break, have it produce a failing test, so the refutation is reproducible, not just asserted.
Watch out
Claude stops when work 'looks done' — adversaries fight that
Left alone, an agent halts once the result appears correct, making you the verification loop. An adversarial subagent is a structural counter to that bias: its success condition is finding a break, not declaring success. Demand a concrete reproduction (a failing test, an exact input) so a claimed refutation is verifiable.
The /batch orchestrator: parallel work in isolated worktrees
When a change is too big for one agent but cleanly splits into independent pieces — "migrate every component from Solid to React," "add a license header to all source files," "convert all tests from Jest to Vitest" — the /batch command orchestrates the fan-out.
/batch migrate src/ from Solid to ReactHere's the full pipeline /batch runs:
| Step | What happens |
|---|---|
| 1. Research | It explores the codebase to understand the scope of the change |
| 2. Decompose | Breaks the work into 5 to 30 independent units |
| 3. Plan | Presents the plan for your review and approval |
| 4. Fan out | On approval, spawns one background subagent per unit, each in its own isolated git worktree |
| 5. Execute | Each subagent implements its unit, runs tests, and opens a pull request |
Two properties make this safe to run wide. First, isolation: each unit gets its own git worktree, a separate directory, so parallel subagents never collide on each other's edits. Second, the plan gate: you see the decomposition before anything runs, so you can catch a bad split before 20 agents act on it. /batch requires a git repository (worktrees and PRs depend on git).
Under the hood, /batch is a bundled workflow that fans work out across many subagents and runs in the background — monitor the running units with /tasks, and the detached agents with claude agents.
Tip
The decomposition is the leverage point
Because /batch shows the plan before fanning out, your highest-value moment is reviewing the split. Are the units genuinely independent? Is one secretly a prerequisite for another? Fix the decomposition at the plan gate — it's far cheaper than untangling 20 conflicting PRs after the fact. Reserve /batch for changes that are repetitive and parallelizable, not for work with deep cross-unit dependencies.
Subagents vs. skills vs. hooks: pick the right tool
Subagents are one of three extension mechanisms, and they're easy to confuse. The distinction is about who triggers the behavior and what guarantee you get.
| Mechanism | Triggered by | Runs in | Guarantee | Use for |
|---|---|---|---|---|
| Subagent | Claude (or you) delegating a task | Isolated context, reports a summary | Best-effort, instruction-driven | Heavy, independent work; fresh-context review; parallel fan-out |
| Skill | The model, on demand, when the task matches | The main flow (loaded when invoked) | Best-effort, model decides when | On-demand knowledge / workflows Claude pulls in itself |
| Hook | A lifecycle event (e.g. PreToolUse, Stop) | A shell command you configure | Deterministic — guaranteed to run | Enforced, non-negotiable actions (lint on save, block a pattern) |
The sharpest line is hooks vs. everything else. Hooks are deterministic shell commands wired to lifecycle points in .claude/settings.json — they always fire. Subagents and skills are model-invoked and best-effort: Claude decides to use them based on the situation. If you need a guarantee ("never let a commit through without running the linter"), that's a hook, not a subagent and not a CLAUDE.md note.
Between subagents and skills: a skill is on-demand knowledge or a workflow the model reaches for within the current flow; a subagent is delegated work that runs in an isolated context and hands back a summary. Reach for a subagent specifically when you want the work done elsewhere to keep the main conversation clean.
Key insight
Match the mechanism to the need
Need it to ALWAYS happen → hook (deterministic). Need on-demand knowledge the model pulls in → skill. Need heavy or independent work done in isolation with only a summary returned → subagent. Picking wrong is the usual cause of "I told it to always X and it sometimes skips X" — that's a hook job.
Try it: Delegate, review adversarially, and fan out
Practice the three subagent moves in a small git repository.
- Set up: in a throwaway git repo with a few source files, run
claudeand/agentsto create arevieweragent — give it adescriptionlike "read-only code reviewer, returns file:line findings" and apromptthat forbids edits and demands a prioritized findings list. (Or define it at launch with--agents '{"reviewer":{"description":"...","prompt":"..."}}'.) - Delegate exploration: ask Claude to spawn a subagent that maps every place a given function is called across the repo and reports a summary. Afterward run
/contextand note how little of the raw search landed in your main window. - Writer/Reviewer: have the main conversation implement a small feature, then hand the diff to the
reviewersubagent. In the task, paste your project conventions and ask for findings only — no edits. Observe that the fresh-context reviewer judges the diff cold. - Go adversarial: re-task a subagent with an adversarial prompt — "PROVE this is broken; find an input that breaks it and produce a failing test." Compare its output to the neutral review.
- Fan out (optional, needs git): on a repetitive change (e.g. "add a license header to every source file"), run
/batch add a license header to all files in src/. Read the plan carefully at the gate — check the units are truly independent — then either approve and watch with/tasks, or decline. - Classify: for each task above, state whether it should have been a subagent, a skill, or a hook, and why.
Deliverable: a short note contrasting the neutral vs. adversarial review output, plus one sentence on a behavior in your repo that should be a HOOK (deterministic) rather than a subagent — and why.
Key takeaways
- 1A subagent runs in its OWN isolated context and reports only a summary back — delegate heavy or independent exploration to keep the main conversation clean.
- 2Subagents can see the conversation but start fresh, so pass project conventions and the exact desired output explicitly in the task description.
- 3Define agents with --agents '{"name":{"description":"...","prompt":"..."}}' or interactively via the /agents manager; description triggers, prompt governs.
- 4Writer/Reviewer uses a fresh-context reviewer to remove the author's bias; an adversarial subagent goes further by actively trying to refute the result.
- 5/batch <instruction> researches the codebase, decomposes into 5-30 independent units, shows a plan, then spawns one background subagent per unit in isolated git worktrees (each runs tests and opens a PR).
- 6Subagents and skills are model-invoked and best-effort; hooks are deterministic and guaranteed — use a hook when you need a behavior to ALWAYS happen.
Quiz
Lock in what you learned
Check your understanding
0 / 4 answered
1.You ask Claude to audit a large monorepo for every place a deprecated API is called, expecting it to read dozens of files. Why is delegating this to a subagent the right move?
2.A teammate spins up a Reviewer subagent but just tells it 'go review the auth module' and gets sloppy, off-convention feedback. What's the core fix?
3.What distinguishes an adversarial subagent from an ordinary Writer/Reviewer review?
4.You run `/batch migrate src/ from Solid to React`. Which sequence correctly describes what happens?
Go deeper
Hand-picked sources to keep learning
Subagents for isolated work, Writer/Reviewer and adversarial review, and how subagents relate to skills and hooks.
Exact behavior of /batch (5-30 units, plan, background subagents, worktrees, PRs), /agents, /tasks, and /background.
Defining subagents, the /agents manager, and running them in the foreground or background.
How subagents, background agents, /batch, and worktrees relate as approaches to parallel work.
Isolated git worktrees — the mechanism that lets /batch fan out without edit collisions.
Source, issues, and changelog for subagent and /batch behavior across versions.