Atlas
TechnicalHow-to

Claude Code Subagents: When to Split Work and How

When Claude Code subagents help and when they don't: writing the agent file, choosing tools and models, and catching frontmatter mistakes that fail silently.

The short version

  • A Claude Code subagent works in its own context window with its own prompt, tools and permissions, and usually sends back only a summary, so noisy side tasks stay out of your main conversation.
  • Use a subagent when a task produces lots of output you won't reread, needs enforced tool limits, can be summarized on its own, or needs a reviewer that didn't write the code.
  • Stay in the main conversation when you're iterating step by step, several phases share a lot of context, the change is quick and targeted, or latency matters.
  • A fresh subagent doesn't see your conversation history, output style or auto memory, so the delegation prompt must carry every constraint it needs.
  • Misspelled frontmatter fields are ignored without an error; run claude --debug and search the debug log for 'does not recognize or apply' when a setting doesn't take effect.
On this page
  1. The short version
  2. What a Claude Code subagent is
  3. When to split work into a subagent
  4. Start with the built-in subagents
  5. How to define a subagent
  6. How to invoke a subagent
  7. Add an adversarial reviewer
  8. Mistakes that fail silently
  9. Subagents versus separate sessions
  10. Conclusion
  11. Questions people ask

Use Claude Code subagents when a side task would fill your main conversation with output you won't look at again, when a job needs tighter tool limits than your session has, or when you want a reviewer that didn't write the code. A subagent is a Markdown file with YAML frontmatter in .claude/agents/ or ~/.claude/agents/. Only name and description are required. Everything else (tools, model, permissions, hooks, memory and so on) is optional, but each one is worth a deliberate choice.

This guide covers when splitting work pays off, how to write a definition Claude actually delegates to, and the configuration mistakes that fail without an error.

What a Claude Code subagent is

A subagent runs in its own context window with its own system prompt, tool access and permissions. Claude hands it a task, it works independently, and it returns a result, usually a summary. Only that result comes back into your main conversation.

What matters more is what a fresh (non-fork) subagent sees. According to the docs, it starts with:

  • its own system prompt plus basic environment details such as the working directory, not the Claude Code system prompt
  • the delegation message Claude wrote for it
  • your CLAUDE.md files, unless the definition sets omitClaudeMd
  • a git status snapshot
  • the full content of any skills listed in its skills field
  • a list of main and the other named agents in the session

The built-in Explore and Plan agents skip CLAUDE.md and the git status snapshot to keep research fast and cheap.

A subagent does not get your conversation history, your output style or the main conversation's auto memory. The task prompt has to carry everything. If you agreed on a constraint twenty messages ago, the subagent won't know it unless the delegation prompt repeats it.

Subagent requests count toward the same usage limits as your main conversation. Splitting work doesn't make it free.

When to split work into a subagent

Split when:

  • The output is noisy. The best-practices guide notes that a single debugging session or codebase exploration can use tens of thousands of tokens. Its advice: prompt "use subagents to investigate X" so the reading happens in a separate context and only summaries come back.
  • You want enforced limits. A read-only reviewer, or a database agent that may only run SELECT, should have those limits in configuration, not just in the prompt.
  • You want an independent check. A reviewer in a fresh context sees only the diff and the criteria you give it, not the reasoning that produced the change.
  • The task is self-contained. If it fits in one prompt and can be answered with a summary, it's a good candidate.
  • You keep needing the same kind of worker. That's the point to save a definition instead of re-typing the instructions.

Keep it in the main conversation when:

  • you're iterating back and forth and each step depends on the last
  • several phases, such as planning, implementation and testing, share a lot of context
  • the change is quick and targeted
  • latency matters, because a fresh subagent may need time to gather context

If you want a reusable prompt that runs in your main context, use a skill instead. For a quick question about something already in the conversation, use /btw: it sees your context but has no tool access, and its answer isn't added to history.

Start with the built-in subagents

Claude Code ships with:

  • Explore: fast, read-only codebase search. Claude picks a thoroughness level of quick, medium or very thorough.
  • Plan: a read-only research agent used in plan mode.
  • General-purpose: every tool available to subagents, for multi-step tasks that need both exploration and action.

Explore and Plan are denied Write and Edit. A plain prompt such as "use subagents to investigate how token refresh works" often needs no custom definition. Write your own when you need a specific role, tool set or model.

How to define a subagent

Where the file lives

When names collide, the higher-priority location wins:

LocationScopePriority
Managed settingsOrganization-wide1 (highest)
--agents CLI flagCurrent session2
.claude/agents/Current project3
~/.claude/agents/All your projects4
Plugin agents/ directoryWhere the plugin is enabled5 (lowest)

Project agents are found by walking up from the current working directory to the repository root, and agent directories are scanned recursively, so subfolders such as agents/review/ work. If two files in the same directory tree declare the same name, only one loads, chosen by filesystem read order. /doctor reports these duplicates. Check project agents into version control so your team shares them.

A minimal, useful definition

This is the read-only code reviewer from the official examples, shortened (the full version also has a review checklist). It shows three habits: a narrow role, a restricted tool list and a prompt that says exactly what to output.

markdown
---
name: code-reviewer
description: Expert code review specialist. Proactively reviews code for quality, security, and maintainability. Use immediately after writing or modifying code.
tools: Read, Grep, Glob, Bash
model: inherit
---

You are a senior code reviewer ensuring high standards of code quality and security.

When invoked:
1. Run git diff to see recent changes
2. Focus on modified files
3. Begin review immediately

Provide feedback organized by priority:
- Critical issues (must fix)
- Warnings (should fix)
- Suggestions (consider improving)

Include specific examples of how to fix issues.

Claude Code watches the agent directories and picks up edits within a few seconds. You need a restart in three cases: after creating the first agent file in an agents directory that didn't exist when the session started, after changing agents in a directory added with --add-dir or /add-dir, and in sessions started with --disable-slash-commands.

Write the description for routing

Claude reads description to decide when to delegate, so write it as a routing rule:

  • Make it specific enough to point to one subagent. Overlapping descriptions lead to the wrong pick.
  • Add a phrase like "use proactively" if you want Claude to delegate without being asked.
  • Keep it short and put detail in the body, which loads only when the subagent runs. Claude Code warns at startup when the combined descriptions of your non-built-in subagents exceed 15,000 tokens.

Restrict tools deliberately

If you leave out tools, the subagent inherits every tool available to subagents. tools is an allowlist and disallowedTools a denylist:

yaml
---
name: no-writes
description: Inherits the available tools except file writes
disallowedTools: Write, Edit
---

If both are set, disallowedTools is applied first and tools is resolved against what remains. Two details:

  • mcp__<server> grants or removes every tool from one MCP server. In disallowedTools, mcp__* removes all MCP tools.
  • Bash(git push *) in disallowedTools removes the whole Bash tool, not just that command. To keep Bash and block specific commands, add a deny rule such as Bash(git push *) to permissions.deny in your settings. For finer, conditional checks, use a PreToolUse hook.

The docs' db-reader example takes the hook route. The agent gets Bash, and a PreToolUse hook in its frontmatter runs a script that reads the hook input as JSON from stdin and extracts the command. If it contains SQL write keywords such as INSERT, UPDATE, DELETE, DROP or ALTER, the script exits with code 2 and the command is blocked. On macOS and Linux the script must be executable, or the hook fails instead of blocking anything. The prompt tells the agent it is read-only; the hook is the backstop.

Choose a model and effort level per role

model accepts sonnet, opus, haiku, fable, a full model ID, or inherit. The docs suggest controlling costs by routing tasks to faster, lower-cost models like Haiku, which suits narrow work such as searching or summarizing logs. Reviewers and anything that reasons about design usually deserve a stronger model.

The model is resolved in this order: a model Claude passes for that invocation, then the frontmatter value, then the CLAUDE_CODE_SUBAGENT_MODEL environment variable, then the main conversation's model. To force one model on every subagent (Claude Code v2.1.257 or later), set both variables:

json
{
  "env": {
    "CLAUDE_CODE_SUBAGENT_MODEL": "haiku",
    "CLAUDE_CODE_SUBAGENT_MODEL_FORCE": "1"
  }
}

The effort field takes low, medium, high, xhigh or max; which levels are available depends on the model.

Other fields worth knowing

  • permissionMode: ignored when the main session is in bypassPermissions, acceptEdits or auto mode; the subagent runs in that mode instead.
  • maxTurns: caps the agent's turns. At the cap, output is returned marked as partial and Claude can resume the agent.
  • skills: preloads the full content of listed skills (up to 32 names). Without it, the subagent can still find and invoke skills while it works.
  • memory: user, project or local persistent memory. The docs recommend project as the default because it can be shared through version control.
  • isolation: worktree: runs the subagent in a temporary git worktree; it is removed automatically if the subagent makes no changes.
  • background: true: keeps the subagent in the background even when Claude asks for the foreground.

How to invoke a subagent

  • Automatically: Claude matches the task to a description.
  • By name: Use the code-reviewer subagent to review the auth changes
  • @-mention: @"code-reviewer (agent)" look at the auth changes, or type @agent-<name>.
  • Whole session: claude --agent code-reviewer. Unless its prompt is empty, the agent's prompt replaces the default Claude Code system prompt.
  • Session-only: pass JSON with --agents, where prompt replaces the Markdown body, for example claude --agents '{"code-reviewer": {"description": "...", "prompt": "...", "tools": ["Read", "Grep"], "model": "sonnet"}}'.

When a background subagent needs permission for a tool, the prompt appears in your main session with the subagent's name; Esc denies that one call without stopping it. Press Ctrl+B to move a running task to the background. Resumed subagents keep their full history, except Explore and Plan, which are one-shot and can't be resumed.

Forks are a different tool

A fork inherits the whole conversation, system prompt, tools and model. Its first request reuses the main session's prompt cache, so it costs less than a fresh subagent when the task needs the same context. Start one with /subtask <task> (on v2.1.161 through v2.1.211 the command is /fork). Use a fork when the side task needs everything you've discussed; use a defined subagent for a clean slate and a specific role.

Add an adversarial reviewer

The best-practices guide recommends a review step before you count unattended work as done. For a plain bug check of the current diff, the bundled /code-review skill runs in a fresh subagent. To check against a plan, name the work, the standard and what counts as a finding:

text
Use a subagent to review the rate limiter diff against PLAN.md. Check that
every requirement is implemented, the listed edge cases have tests, and
nothing outside the task's scope changed. Report gaps, not style preferences.

The guide also warns that a reviewer asked to find gaps will usually report some even when the work is sound. Chasing every finding leads to extra abstraction, defensive code and tests for cases that can't happen. Tell the reviewer to flag only gaps that affect correctness or the stated requirements.

Mistakes that fail silently

  • Typos in frontmatter. Unrecognized field names are ignored without an error. Run claude --debug and search the session's log in ~/.claude/debug/ for does not recognize or apply.
  • Missing fields or broken YAML. A file with no name is treated as documentation and never loads. A name with no description, or YAML that doesn't parse, is skipped with only a note in the debug log.
  • Shorthand numbers. In autoCompactWindow, 200k is read as 200, outside the allowed range of 100,000 to 1,000,000. Write 200000.
  • Assuming shared context. Repeat key constraints in the delegation prompt, including CLAUDE.md rules if the agent sets omitClaudeMd.
  • Spawning without limits. By default subagents can nest up to three layers below the main conversation, and spawning fails once 20 are running. Change these with CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH and CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS. Each extra subagent adds to token spend.

Subagents versus separate sessions

Subagents are workers inside one session; their results come back to a single orchestrator's context. For longer-lived roles, the next step is separate Claude Code sessions, each with its own working folder. Atlas works this way: each of its engineers is its own Claude Code session with a written role, its own working folder, and a model and effort level suited to the role. Either way, give each worker one clear job, the tools it needs and a defined deliverable.

Conclusion

Start with the built-in Explore agent and plain "use subagents to investigate…" prompts. Write a custom definition when you keep needing the same role. Keep the description short and specific, restrict tools in configuration rather than in the prompt, pick a model that fits the job, and put everything the agent needs in the task prompt. Add a fresh-context reviewer before trusting long unattended runs, and check the claude --debug log when a field doesn't seem to take effect.

Questions people ask

What is a Claude Code subagent?

A helper that runs in its own context window with its own system prompt, tool access and permissions. Claude hands it a task, it works on its own, and usually only a summary comes back to your main conversation. You define one as a Markdown file with YAML frontmatter in .claude/agents/ or ~/.claude/agents/.

When should I use a subagent instead of the main conversation?

Use one when the output is noisy, when you want tool limits enforced in configuration, when you want an independent reviewer, or when the task is self-contained and can be summarized. Stay in the main conversation if you're iterating step by step, several phases share a lot of context, the change is quick, or latency matters.

Does a subagent know what I discussed earlier in the session?

Not a fresh one. It doesn't get your conversation history, output style or the main conversation's auto memory, though it does load your CLAUDE.md files unless it sets omitClaudeMd. Repeat key constraints in the delegation prompt. A fork is the exception: it inherits the whole conversation.

Which fields are required in a subagent file?

Only name and description. Tools, model, effort, permissions, hooks and memory are optional. If you leave out tools, the subagent inherits every tool available to subagents, so decide on that field deliberately.

Why isn't my subagent setting taking effect?

Misspelled field names are ignored without an error. A file without a name never loads, and one without a description or with broken YAML is skipped with only a debug-log note. Run claude --debug and search ~/.claude/debug/ for 'does not recognize or apply'.

Sources

  1. Create custom subagents - Claude Code Docs
  2. Best practices for Claude Code - Claude Code Docs

Researched and drafted with Claude, then checked against the sources above. Atlas is an independent product, not affiliated with Anthropic or OpenAI. Claude and Claude Code are trademarks of Anthropic; Codex is a product of OpenAI.