·Skills & Commands
A 2026 deep dive on Claude Code subagents — five scope layers (managed / CLI flag / project / user / plugin), the full frontmatter field set, built-in agent trade-offs, context isolation, SendMessage resume reuse, nesting depth and concurrency limits, and the 2026 worktree + background combination pitfall.
Claude Code Subagents Deep Dive: Parallel Research, Restricted Tools, Nested Tasks (2026)
Claude Code's subagent mechanism — launched in late 2025 and matured through 2026 — is a core capability that lets you spin up independent-context-window Claude instances, each with its own system prompt, tool allowlist, and ability to call back to the parent. Subagents are not mere function calls; they're "let Claude run a sub-task in isolation and return the result" by design. This guide, based on the official Claude Code Subagents docs, covers: five scope layers, the full frontmatter field set, built-in agent differences, background vs foreground, context isolation and SendMessage reuse, nesting depth limits, and the most common 2026 pitfalls.
TL;DR
- A subagent is a smaller Claude with its own context window, with restricted tools, callable by the parent agent
- Five scope layers: managed (MDM) > --agents flag >
.claude/agents/(project) >~/.claude/agents/(user) > plugin- The
skillsfield injects the full SKILL.md into the subagent's context at startup (not just the description)- Nesting depth limit:
CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH(default 3) + concurrency limit 20 simultaneous subagentsSendMessagewithresumereuses one agent_id and preserves the full conversation history- 2026 pitfall: the real behaviour of
isolation: worktree+background: truetogether
Five scope layers: where subagents load from
The Claude Code Subagents docs define five scopes, ordered by priority:
| Scope | Path | Use | Priority |
|---|---|---|---|
| managed | MDM push / org settings | Company-mandated subagent templates | Highest |
| CLI flag | claude --agents '{"name": {...}}' | One-off / ad-hoc subagent | High |
| Project-level | <project>/.claude/agents/*.md | Team-shared, checked into git | Medium |
| User-level | ~/.claude/agents/*.md | Personal cross-project | Low |
| Plugin | Subagent contributed by a plugin | Third-party package | Medium |
Merge rule: same as CLAUDE.md memory and .mcp.json — higher priority overrides lower. When the same name appears in multiple layers, the highest layer wins. That means a team's subagent template can be MDM-enforced; individuals can't bypass it.
Practical choice:
- Personal experiments / one-off exploration → CLI flag or user-level
- Team-shared (PR reviewer, docs maintainer) → project-level
.claude/agents/ - Reusable across multiple projects → user-level
- Company-mandated → managed (MDM)
Full frontmatter: every field a subagent supports
A subagent is a .md file with YAML frontmatter. Here's the full field list per the Subagents spec:
---
name: pr-reviewer
description: Reviews pull requests for the team — triggers on "review my changes" or auto-loads when a PR URL is mentioned.
tools: Read, Grep, Bash(git diff:*), Bash(gh pr diff:*)
disallowedTools: Edit, Write, NotebookEdit
model: claude-sonnet-4-5
permissionMode: bypassPermissions
maxTurns: 20
skills:
- code-review
- security-checklist
mcpServers:
- github
isolation: worktree
background: true
effort: medium
color: cyan
initialPrompt: "Review the staged changes against references/checklist.md."
---
# PR Reviewer
You are a meticulous reviewer. Always check the security checklist first.
When you find a blocker, escalate to the parent agent via SendMessage.
Key field meanings:
tools/disallowedTools: tool allowlist / denylist — finer-grained thanallowed-tools(skill dimension)model: which model the subagent uses —sonnet,haiku, or a specific IDpermissionMode: four valuesdefault/acceptEdits/plan/bypassPermissions, matching the main Claude CodemaxTurns: maximum tool-call rounds — exceeded and the subagent is force-stopped (runaway protection)skills: which SKILL.md files to preload (full text, not just description)mcpServers: which MCP servers the subagent can callisolation: worktree: run in an independent git worktree (file-system isolation)background: true: return an agent_id immediately; the main session doesn't blockeffort: model reasoning effort (low / medium / high)color/initialPrompt: UI colour and the first-turn prompt
Built-in agent differences: don't reinvent the wheel
Claude Code ships a few built-in subagents. Understand their differences before writing your own:
| Built-in | Tool scope | When it auto-fires | When to invoke manually |
|---|---|---|---|
| Explore | Read, Grep, Glob (read-only) | "find files / search for / look up" | Task tool + subagent_type: Explore |
| Plan | Read, Grep + Bash(read-only) | "plan / design / how would I" | Task tool + subagent_type: Plan |
| General-purpose | All tools (no restriction) | Generic fallback | Task tool + subagent_type: general-purpose |
| statusline-setup | Edit (project-internal) | "statusline / status bar" | Automatic |
Common mistake: writing general-purpose when Explore would do — the former loads the entire toolset into context, the latter only loads Read/Grep/Glob. Only use general-purpose when Explore can't satisfy the task.
Background vs foreground: scheduling philosophy
Claude Code v2.1.198 onwards, subagents default to background: true — they return an agent_id immediately, the main session doesn't block. Two modes' actual behaviour:
- Foreground (
background: false): the main session blocks; the subagent must finish before the main continues. Result visible synchronously, but the main agent can't do anything else while waiting. - Background (
background: true): the subagent runs in the background; the main session continues. Get results viaSendMessage— let the main agent handle other tasks while the subagent runs.
Practical patterns:
- Single-step investigation (find a file, read a module) → Foreground, because the result is needed immediately
- Long-running task (PR review, batch analysis) → Background, let the main agent do other things meanwhile
- Multiple parallel subagents → multiple Backgrounds run concurrently, main agent orchestrates
Ctrl+B (toggle background) can switch on the fly — see the Claude Code status bar.
Context isolation and SendMessage reuse
Subagents run in isolated context: they can't see the main session's history, nor any other subagent's context. /compact on the main session won't compress a subagent's, and vice versa. This implies:
- Subagents don't get the main agent's conversation history by default — they see only
initialPromptplus their own tool results - A
forksskill borrows a named agent's system prompt, giving the subagent a consistent role definition SendMessageis how multiple subagents communicate — passing data and coordinating decisions
SendMessage resume reuse: pass the same agent_id, the subagent preserves its full history and continues the conversation. Use cases: multi-turn collaboration (subagent explores code → you review → subagent modifies) + long-running tasks you push incrementally.
Nesting depth and concurrency limits
The Subagents docs define:
CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH: nesting depth limit, default 3 (a subagent can itself spawn a subagent, up to 3 layers deep)- Per main session, subagent concurrency limit: 20 simultaneous
Pitfall 1: nesting too deep. Agent A spawns B, B spawns C, C spawns D — what D sees is its own context plus what C passed in; main-session info is already gone. Practical rule: keep subagents as "leaves" (don't recursively spawn); complex coordination goes back up to the main agent.
Pitfall 2: concurrency above 20. New Task calls queue rather than error. Practical rule: when splitting large tasks into multiple Background tasks, keep concurrency < 10 to leave room for the main session.
Pitfall 3: isolation: worktree + background: true together. 2026 pitfall — in worktree mode every subagent runs in its own git worktree, but the worktree's changes don't auto-merge with the main branch. You have to explicitly git merge to bring the subagent's changes back to the trunk.
Common pitfalls and anti-patterns
Five high-frequency pitfalls, each broken down as symptom → cause → fix — all from real team retrospectives:
Pitfall 1: a vague description means the subagent never fires.
Symptom: you defined a subagent, but the main agent keeps doing the work itself. Cause: description is the main agent's routing signal — "helps with code tasks" gives it nothing to route on. Fix: include trigger scenarios and example phrases in the description (e.g. triggers on "review my changes"), plus when not to use it.
Pitfall 2: a tool allowlist without Read makes the subagent hallucinate.
Symptom: a reviewer subagent's findings don't match the code; it invents functions that don't exist. Cause: tools granted Grep but not Read — the model is guessing file contents from grep fragments. Fix: the allowlist should always include Read, and use disallowedTools to subtract rather than narrowing tools to the bone.
Pitfall 3: busy-polling background subagents.
Symptom: right after launching a background subagent, the main agent sends SendMessage asking "done yet?", burning turns. Cause: misunderstanding when background results arrive. Fix: have the main agent work on independent tasks while the subagent runs, then resume to collect; if the result is needed immediately, use foreground.
Pitfall 4: expecting subagents to share state through "memory".
Symptom: two subagents' outputs don't line up; the second has no idea what the first did. Cause: context isolation is a design decision, not a bug — subagents can't see each other. Fix: have each subagent write results to files (a scratch directory / JSON / YAML); the main agent reads them and distils key facts into the next subagent's initialPrompt.
Pitfall 5: assuming isolation: worktree auto-merges.
Symptom: the subagent reports "changes complete", but the main branch has nothing. Cause: in worktree mode the changes stay on the worktree's own branch. Fix: put "report your worktree branch name when done" into the subagent's output contract, and let the main agent (or a human) merge explicitly.
Real-world walkthroughs: two production orchestrations
Case A — a parallel code-research team (1 main + 3 explorers + 1 synthesiser).
Scenario: you've inherited an unfamiliar monorepo and the main agent must produce an architecture survey in minutes. Orchestration: the main agent dispatches three Explore-type subagents (read-only), each investigating one layer — data, services, entry points — and each writing findings to scratch/research-*.md; the main agent then reads the three files and synthesises the survey.
The assignment table (what the main agent actually dispatches):
| Subagent | Scope | Output |
|---|---|---|
| Explore #1 | src/db/, schema, migrations | scratch/research-data.md |
| Explore #2 | src/services/, RPC boundaries | scratch/research-services.md |
| Explore #3 | Entry points, routing, env config | scratch/research-entry.md |
Why it's designed this way: the Explore toolset is only Read/Grep/Glob — cheaper than general-purpose; files act as the shared layer, sidestepping "subagents can't see each other"; and the main agent reads three summaries instead of absorbing three raw output streams into its own context.
Case B — a PR reviewer subagent's output contract. The role definition handles how to review; the output contract handles how the main agent reliably consumes the review. Fix the verdict enum in the subagent's system prompt:
# PR Reviewer (system prompt excerpt)
For every finding, output exactly one block:
VERDICT: BLOCKER | WARNING | NIT
FILE: <path>:<line>
ISSUE: <one sentence>
FIX: <suggested change, one sentence>
End with: SUMMARY: <BLOCKER count> blockers, <WARNING count> warnings.
The main agent parses the SUMMARY line to decide the next step — zero blockers auto-approves; any BLOCKER and it SendMessage resumes the reviewer to elaborate. The key point: collapsing free-text review into an enum plus counts turns the main agent's follow-up decision from "read an essay" into "read structured fields" — the most commonly missed piece of subagent orchestration.
Frequently asked questions
What's the difference between a subagent and a regular Bash call?
A Bash call is one tool use within the same context — the main agent sees the result directly, tokens count against the main session. A subagent is a separate Claude with its own context — its own system prompt, configurable independent tool set, and its own maxTurns limit. One-line summary: Bash is "let Claude run a command"; subagent is "let another Claude run a task".
Should I put subagents at project-level or user-level?
Team-shared goes project-level (.claude/agents/*.md, checked into git); personal cross-project goes user-level (~/.claude/agents/). Key decision — if every team member uses this subagent, project-level; if only you, user-level (to avoid noise). The MDM layer is configured by company IT and can't be bypassed by individuals.
How deep can sub-tasks nest?
Default 3 layers (CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH=3). Setting it higher blows up tokens (each layer loads independent context) — unless you specifically need subagents that spawn subagents, use the default. Deep nesting is also extremely hard to debug (you need to trace multi-layer SendMessage stacks).
A Background subagent crashed — how do I get its results?
Three ways: (1) launch with claude --debug to print SendMessage state; (2) explicitly resume the agent_id via the Task tool to see history; (3) the subagent's own isError return value is written to logs. The most reliable approach: have the subagent write key intermediate results to a scratch file in initialPrompt; the main session reads from the file later — no SendMessage dependency.
How do I write a subagent description so the main agent actually picks it?
The description is the only routing signal the main agent has for deciding whether to delegate. Include trigger scenarios with example phrases (e.g. triggers on "review my changes"), state the tool/perspective difference (read-only research vs writable edits), and spell out when not to use it. Avoid blanket phrases like "helps with tasks" — if the main agent can't read a routing signal, the subagent might as well not exist.
How do multiple subagents share state?
By default they can't see each other — context isolation is by design. The recommended shared layer is files: each subagent writes conclusions to its own file under scratch/, the main agent reads them, distils the points, and packs them into the next subagent's initialPrompt. SendMessage suits point-to-point messaging (resuming the same agent to continue a conversation), not shared storage. Keep the orchestration logic in the main agent and the isolation in the subagents — that's the stable shape of multi-agent work.
Official references
- Claude Code Subagents official documentation
- Claude Code Skills documentation (pairs with subagent
skillsfield) - Claude Code Hooks documentation (subagents trigger hooks)
- Claude Code Settings documentation (CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH config)
- Claude Code IAM documentation (cloud backends and permissions)
- Claude Code repository (anthropics/claude-code)
- Claude Plugins Official (manifest and subagent bundle examples)
- Superpowers (obra/superpowers — multi-subagent coordination reference)
This guide is current as of Claude Code v2.1.198+ (August 2026). The subagent schema evolves; check the spec version every six months.