Claude Code Subagents: When They Save Context and When They Hurt

By Updated

What is a subagent in Claude Code?

A Claude Code subagent is a separate Claude instance with its own context window, system prompt, and tool set that the main conversation hands a task to. It doesn't see the conversation history and returns only its final answer. That pays off when the intermediate work is large and the result is short, and it doesn't when the task is short or depends on the current conversation.

TL;DR

  • -Across the author's 535 completed subagent runs, the median subagent peaks at ~117K tokens of context and returns ~1,500 characters to the main conversation. That gap is what isolation buys.
  • -Every launch has a price: in the same setup, the median subagent starts with ~58K tokens of context. Tasks with 1-3 tool calls don't pay off: ~55K tokens at startup for a ~1,100-character answer.
  • -In a controlled experiment (Claude Code 2.1.318, n=3 per variant), a narrow tools list cut startup context by 78.5%, omitClaudeMd by 12.8%, and both together by 91.8%, down to ~4.7K tokens. Result size didn't change.
  • -Subagent model resolution order: the invocation parameter, the model field in frontmatter, CLAUDE_CODE_SUBAGENT_MODEL, then the main conversation's model. The environment variable overrides frontmatter only with CLAUDE_CODE_SUBAGENT_MODEL_FORCE=1.
  • -89% of the author's runs go to the built-in general-purpose agent. An agent file is for pinning tool restrictions, a model, and repeatable behavior, not for delegation as such.

On the author’s machine, the median Claude Code subagent peaks at about 117K tokens of context and returns about 1,500 characters to the main conversation. A subagent is a separate Claude instance with its own context window, system prompt, and tools: it does the work off to the side and hands back only the result. The gap between that peak and the result is why you launch one.

The same median has a second number. Before its first action, the subagent already holds about 58K tokens. That’s the launch price, and on a short task it eats the whole benefit. The Claude Code docs describe subagent mechanics in detail, but they don’t say what startup costs or when it pays off.

The goal here is to decide whether a specific task needs a subagent. The sources: the subagent docs (checked against Claude Code 2.1.318), aggregates from 648 of the author’s subagent transcripts, and a controlled experiment with 18 runs. The sample comes from one user with a heavy setup, so the numbers come with their limits and a script to repeat the measurement on your own machine. A reference for every agent file field already exists in Claude Code Skills and Agents, so it isn’t repeated here.

What a subagent isolates

A regular (non-fork) subagent starts with a fresh context window. It doesn’t continue the conversation. It gets a task written by the main agent and gathers the context it needs on its own.

What a subagent gets at startup and what it can’t see

GetsDoesn’t get
Its own system prompt (the agent file body)The main conversation history
The task message from the main agentFiles the main agent already read
User, project, and local CLAUDE.md (except Explore and Plan; turned off with omitClaudeMd)Skills invoked in the main conversation
A git status snapshot (except Explore and Plan)The main conversation’s auto memory
Skills from the skills field (full content)The main session’s output style
Schemas of allowed tools, MCP included

The right column holds the main limitation. Anything the main agent knows from the conversation reaches the subagent only if it made it into the task text. Per the docs, the built-in Explore and Plan agents start without CLAUDE.md and git status so exploration stays fast and cheap.

What comes back to the main conversation

Only the subagent’s final answer comes back. Intermediate tool calls, the files it read, and its reasoning stay in its transcript. Since version 2.1.277, the result arrives indented, under a header that marks it as subagent output. According to the CHANGELOG, this keeps text from the result from passing itself off as session instructions.

The docs spell out two caveats. First, results pile up in the main context, and many subagents with detailed answers take up noticeable space. Second, each subagent sends its own requests, and they count toward the same usage limits as the main conversation.

Subagent vs. fork vs. skill

SkillSubagentFork
ContextThe whole current conversationFresh, just the taskCopy of the whole conversation
System prompt and toolsMain session’sFrom the agent fileMain session’s
ModelMain session’s or from the skill fieldFrom the resolution chain (see below)Main session’s
Prompt cacheSharedSeparateShared with the main session
What lands in the main contextEverythingOnly the final answerOnly the final answer

A fork lets you hand off a side task without retelling the context. It sees what the main session sees, but its tool calls don’t land in the main conversation. You can start a fork manually with /subtask <task>. Fork mode is on by default since version 2.1.302 and turns off with CLAUDE_CODE_FORK_SUBAGENT=0. A fork can’t spawn other forks. Its system prompt and tools match the main session’s, so its first request uses the main session’s cache, and the docs call a fork the cheaper option for tasks that need the same context. A skill with context: fork also runs in a separate subagent.

What the measurements showed

The numbers below come from two sources. The first is aggregates over the author’s real subagent transcripts for the whole period they’re kept. The second is experiment E2, which ran the same trivial task across different agent configurations. Task contents weren’t analyzed or published, only sizes.

Method and sample

Claude Code writes each subagent’s transcript to ~/.claude/projects/<project>/<session>/subagents/agent-<id>.jsonl. Every assistant message has a usage field. Context size for a turn is input_tokens + cache_read_input_tokens + cache_creation_input_tokens.

  • Startup context: size on the first turn (system prompt, CLAUDE.md, tool schemas, descriptions, task).
  • Peak: the maximum size across turns.
  • Result: the length of the subagent’s last text message in characters.

Recount on November 6, 2026, covering transcripts created before 15:00: 648 transcripts, 535 of them completed with an answer. The sample keeps growing: by that evening, new heavy runs had moved the median startup context to ~62K, so rerunning the script below will give slightly different numbers. Records with the <synthetic> model (stubs written on API errors) were excluded. By type (all 648 transcripts): general-purpose 577 runs (89%), custom agents 44 (~7%), a plugin agent that hands tasks to an external CLI 19 (3%), Explore 8 (1%).

Summing tokens across turns doesn’t work as a metric: the same 58K of startup context gets counted again on every turn. About 91% of input tokens in these transcripts are cache reads, so the dollar cost of a turn is well below its nominal size. What’s measured here is context size, not the bill.

The benefit: peak vs. result

Metric (535 subagents)Medianp10p90
Startup context, tokens~58K~17K~82K
Peak context, tokens~117K~44K~238K
Result, characters~1,500~100~6,300
Tool calls18455

The median subagent peaks at ~117K tokens, and the answer that reaches the main conversation is ~1,500 characters, a few hundred tokens. The gap is in the hundreds of times. Without a subagent, most of that volume (file contents, command output) would land in the main context and stay there until compaction.

That gives a quick check for any task. If the answer is about as big as the work behind it, isolation bought nothing.

The cost: startup context

Median startup is ~58K tokens, p10 ~17K. That’s the context a subagent holds before its first action. In the author’s setup it includes a large global CLAUDE.md with rules, tool schemas from several dozen MCP servers, agent and skill descriptions, and git status.

The distribution is uneven: about a fifth of runs start at 10-20K tokens, most at 40-90K. That makes the startup median sensitive to filtering. If you don’t exclude the <synthetic> stubs, it climbs to ~65K, while peak and result barely move. When you repeat the measurement, drop those records explicitly.

Short tasks don’t pay off

GroupRunsStartup contextPeakResult
≤3 tool calls34~55K~55K~1,100 characters
≥15 tool calls~315~66K~156K~1,900 characters

In short tasks, context barely grows after startup: the subagent loads ~55K tokens for a ~1,100-character answer. The main conversation would have made the same 1-3 calls in context it already has. Long tasks flip the ratio, and ~156K tokens of work fold into ~1,900 characters. Where the line falls depends on the startup price in a given setup, and you can lower that price.

What lowers the startup price

Experiment E2 tested three levers: the omitClaudeMd field, a narrow tools list, and running the session without MCP servers. Conditions: Claude Code 2.1.318, the sonnet model (claude-sonnet-5-5 in transcripts), a temporary project without its own CLAUDE.md, four project agents, and the task “read a one-line file and return the line”. Each variant ran 3 times via claude -p. The metric was the subagent’s startup context from the first turn of its transcript.

Agent variantStartup context, medianChange
No restrictions (baseline)56,882baseline
omitClaudeMd: true49,594−12.8%
tools: Read, Grep12,232−78.5%
tools: Read, Grep + omitClaudeMd: true4,667−91.8%
Baseline, session without MCP servers41,639−26.8%
tools + omitClaudeMd, session without MCP servers4,6670% vs. the same variant with MCP

The tools field has the biggest effect. The allowlist drops the schemas of every other tool, MCP included, from the subagent’s context, and in this setup that’s ~44.6K tokens. omitClaudeMd saved ~7.3K: the test directory had only the global CLAUDE.md, and with a project file the savings would be larger. The levers add up almost linearly. The remaining ~4.7K tokens can be treated as the floor for this version: the subagent system prompt, two tool schemas, and the agent body.

Running the session without MCP (--strict-mcp-config with an empty config) cut the main session’s startup context by 22.6% (69,767 → 53,993) and the unrestricted subagent’s by 26.8%. For the agent with a narrow tools list, turning off MCP added nothing, since its MCP schemas were already cut. In every variant, the subagent returned the same 39-character answer. The levers change the launch price, not what reaches the main conversation.

Limits of experiment E2

Keep these conditions in mind before applying the numbers to your setup:

  • One machine, one user, one Claude Code version, one model, one day.
  • A very heavy setup: about 65 MCP servers (436 tools in the session), ~7K tokens of global rules, about 50 agents, and a long list of skills. A 57K-token baseline is unusual for a lightweight setup, and your absolute savings will be smaller. Carry over the ratios between levers, not the numbers.
  • A trivial task, n=3 per variant. Spread within a variant is small (up to ~2%), but these are order-of-magnitude estimates, not confidence intervals.
  • Not measured: result quality on real tasks, context growth across turns, time, and how tools affects an agent’s ability to finish the task. An agent that needs Bash or Edit won’t work with a two-tool allowlist.

How to repeat the measurement

The script reads only the usage fields and answer lengths. It doesn’t print transcript contents. The jsonl format is undocumented and can change between versions.

import glob, json, os, statistics as st

KEYS = ("input_tokens", "cache_read_input_tokens", "cache_creation_input_tokens")
rows = []
for path in glob.glob(os.path.expanduser("~/.claude/projects/*/*/subagents/agent-*.jsonl")):
    first = peak = None
    result, tools = "", 0
    for line in open(path, errors="ignore"):
        try:
            rec = json.loads(line)
        except ValueError:
            continue
        msg = rec.get("message")
        if rec.get("type") != "assistant" or not isinstance(msg, dict) or msg.get("model") == "<synthetic>":
            continue  # service records and API error stubs
        ctx = sum((msg.get("usage") or {}).get(k) or 0 for k in KEYS)
        first = ctx if first is None else first
        peak = max(peak or 0, ctx)
        for c in msg.get("content") or []:
            tools += c.get("type") == "tool_use"
            if c.get("type") == "text" and c.get("text", "").strip():
                result = c["text"]
    if peak and result:
        rows.append((first, peak, len(result), tools))

med = lambda i, rs=rows: st.median(r[i] for r in rs)
print(f"n={len(rows)} start={med(0):.0f} peak={med(1):.0f} result={med(2):.0f} chars")
short = [r for r in rows if r[3] <= 3]
print(f"<=3 calls: n={len(short)} start={med(0, short):.0f} result={med(2, short):.0f} chars")

If your startup context comes out well below 58K, your break-even point shifts in favor of subagents. Claude Code deletes subagent transcripts after the cleanupPeriodDays period (30 days by default), so unless you change the setting, the sample covers roughly the last month.

When you need a subagent

The docs recommend a subagent for tasks with bulky output you won’t need again, for enforced tool and permission restrictions, and for self-contained work that returns a summary. The measurements add a threshold: the task should take more than a few calls.

Bulk search and reading

The typical case: find every place a function is used, read through logs, go over dozens of files, and return a short list. For codebase search there’s the built-in Explore agent. It only reads (Write and Edit are denied), supports quick, medium, and very thorough levels, and starts without CLAUDE.md. If the search turns into action, general-purpose fits.

A sign the task fits: you can describe the answer up front in a few lines (“a list of files and lines”, “three causes of the error”), while getting there takes dozens of calls.

Restrictions by design

A subagent with tools: Read, Grep, Glob physically can’t change anything, and that’s more reliable than asking in the prompt. A review agent without Write and Edit, or a researcher limited to reading and web search, wins twice: permissions are restricted, and startup context is smaller thanks to the short tool list. The disallowedTools field works as a denylist and applies before tools. Some tools are always missing from subagents, even if you list them: AskUserQuestion, EnterPlanMode, ExitPlanMode (except with permissionMode: plan), ScheduleWakeup, WaitForMcpServers, Workflow, EndConversation, and, at the nesting limit, Agent itself.

Independent tasks in parallel

The docs allow up to 20 subagents running at once in one session (CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS changes the limit). Subagents launched from the main conversation with no extra configuration start in the background: the main agent keeps working, and the result arrives later as a message. Parallelism makes sense when tasks don’t depend on each other, like three independent research tasks or checks of different modules. Each launch pays its own startup price, so ten small parallel tasks cost more than they look.

Isolating edits in a worktree

isolation: worktree runs the subagent in a temporary git worktree, so its edits don’t touch your working copy. The docs point out a detail that’s easy to miss: by default the worktree branches from the repository’s default branch, not from the parent session’s current HEAD. If the subagent needs to work on top of uncommitted or fresh changes, plan for that.

When a subagent gets in the way

Short, targeted tasks

Fix a typo, read one file, check a config value. The measurement above shows that in a heavy setup such tasks cost ~55K tokens of startup for an answer of ~1,000 characters. The docs name the main conversation as the right place for quick targeted edits and latency-sensitive tasks, because a new subagent needs time to gather context.

Work that needs the conversation history

If a task builds on what you discussed over the last half hour (decisions, rejected options, clarifications), a regular subagent starts from scratch. Retelling it in the task text loses details. You have three options: continue in the main conversation, launch a fork that sees the whole history, or use /btw for a question about something already discussed. The docs describe /btw as having no tool access, and it doesn’t add the answer to history.

Iterative work with frequent clarifications also fits a subagent poorly. Each round of edits goes through a retelling instead of shared context.

When cheap indexed search is available

If the project has a code index connected (for example, a symbol graph via an MCP tool), the question “where is this defined and who calls it” takes one or two index queries. A subagent that searches for the same thing by reading files adds the startup price and dozens of calls. The author’s global rules say this outright for such projects: code exploration happens in the main conversation through the index, not through Explore. There are no measurements for this comparison. It’s a working rule, not an experimental result.

Piling-up results and retelling errors

A subagent’s answer is a summary, and summaries can be wrong: miss a file, generalize badly, state something unchecked with confidence. The main agent sees only the result and can’t check it without redoing the work. For high-stakes decisions, ask for file and line references in the answer so you can spot-check them.

The second effect: with many launches, results pile up in the main context. Ten subagents at 6K characters of answer each (p90 from the measurements) already take noticeable space in the window, and the task prompts add to that.

Background runs and nesting

Background subagents run with a trimmed set of built-in tools, while MCP tools stay. Permission prompts surface in the main session with the name of the subagent that’s asking, and with several parallel runs that gets distracting. Since version 2.1.318, a background subagent’s shell command moves to the background on its own after 3 minutes so the prompt cache doesn’t expire.

Subagents can launch their own subagents up to three levels below the main conversation (CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH; a value of 1 turns nesting off). Each level pays its own startup price and retells the task, so deep nesting multiplies both cost and the risk of distortion.

Decision tree: subagent, fork, or main conversation

SituationWhere to run itWhy
1-3 calls, a targeted editMain conversationSubagent startup costs more than the work
Iterations with clarifications, large shared contextMain conversationA subagent doesn’t see the history
A question about something already discussed/btwNo tools, doesn’t clutter history
A side task that needs the full contextFork (/subtask)Sees the history, shares the cache, returns only the result
Dozens of reads and searches, short answerExplore or general-purposeIsolation pays off
Strict permission limits neededCustom agent with toolsRestricted by design, smaller startup
Edits that must not touch the working copyAgent with isolation: worktreeSeparate branch and directory
Several independent tasksParallel subagentsUp to 20 at once, each with its own window
Long work that doesn’t fit in one windowSeparate sessions, background agents, or agent teamsThe docs recommend this
A code index is availableMain conversation with the indexSearch is cheaper than a subagent reading files

Two questions settle most cases. The first is how many tool calls the task needs. With one to three, a subagent probably won’t pay off. The second is whether the task needs the conversation history. If it does, you’re left with a fork or the main conversation.

How a subagent’s model is chosen

Resolution order

Per the docs, a subagent’s model is resolved in this order:

  1. The model parameter Claude passes in a specific Agent call.
  2. The model field in the agent’s frontmatter.
  3. The CLAUDE_CODE_SUBAGENT_MODEL environment variable.
  4. The main conversation’s model.

Allowed field values: sonnet, opus, haiku, fable, a full ID (for example, claude-opus-5-5), or inherit, which means the main conversation’s model. When you connect to the Anthropic API, the opus, sonnet, and haiku aliases point to Opus 5.5, Sonnet 5.5, and Haiku 5.5, and fable points to Fable 5.1. On cloud providers the mapping may differ.

A common mistake is assuming CLAUDE_CODE_SUBAGENT_MODEL overrides everything. That was true in older versions. Now it’s a default, and frontmatter or the call parameter overrides it. To put one model on every subagent, add CLAUDE_CODE_SUBAGENT_MODEL_FORCE=1 (since version 2.1.257). Built-in agents have their own rules. Plan inherits the main conversation’s model, and so does Explore, but if the main conversation runs on Fable and you connect through a Claude subscription, a Console account, or an LLM gateway, Explore switches to the model behind the opus alias.

Model policy and what the measurements don’t show

The author’s rules set agent models by policy: search and information gathering on Sonnet; analysis, planning, and decisions on Opus; no Haiku for agents. That’s a working convention, not a conclusion from the measurements.

The transcripts can’t support such a conclusion anyway. They mix models from several generations, the reason behind each choice (frontmatter, call parameter, variable, inheritance) can’t be recovered from a transcript, and answer quality wasn’t measured. There were no paired comparisons of one task on two models, so this data can’t back the claim that Sonnet handles the same tasks as well as Opus. For pricing and model differences, see Claude Opus vs Sonnet.

Effort and thinking

Subagents inherit the main conversation’s extended thinking setting. The effort level comes from the effort field in frontmatter (low, medium, high, xhigh, max), the call parameter, or the CLAUDE_CODE_SUBAGENT_EFFORT variable, which applies when nothing else sets the level. For a research agent with a narrow task, it makes sense to start lower and raise the level if the answers come out shallow.

Agent file format: fields that affect cost

An agent is a markdown file with YAML frontmatter in .claude/agents/ (project) or ~/.claude/agents/ (user). For basic Claude Code setup, see the complete guide. Here’s a read-only reviewer with the fields that affect cost and behavior:

---
name: code-reviewer
description: Reviews a diff for bugs and security issues. Use after a feature is implemented. Read-only; for writing tests use test-writer.
tools: Read, Grep, Glob
model: sonnet
maxTurns: 20
---

Review the changes you are pointed to. Report issues by priority
with file:line references. Do not propose rewrites of unrelated code.
FieldWhat it doesWhen to set it
toolsTool allowlist; without it, the agent inherits all toolsAlmost always: it covers both permissions and startup context
modelAgent model (see above)When the agent shouldn’t run on the session model
maxTurnsTurn limit; when reached, the result is marked partialAuditors and researchers that tend to wander
omitClaudeMdStart without CLAUDE.md (since 2.1.271); managed policy still loadsAgents that don’t need project rules
isolationworktree: a temporary git worktreeAgents that edit code in parallel with you
autoCompactWindowEarly compaction for the subagent, 100,000-1,000,000 tokensAgents that read long logs

Write autoCompactWindow as an integer. The docs warn that 200k in frontmatter is read as 200 and ignored as out of range. The other fields (permissionMode, memory, skills, mcpServers, hooks, background, color) are covered in the skills and agents reference.

The agent description as a router

Claude decides whom to delegate to based on the description field. The descriptions of all agents sit in the main conversation’s context permanently. Per the docs, if their total size (excluding built-ins) exceeds 15,000 tokens, Claude Code shows a warning at startup.

What works

Two patterns in the author’s catalog make agent selection easier:

  1. Trigger first. “Use after completing a logical unit of code” or “Use when…” followed by a list of situations.
  2. Boundary with a neighbor at the end. A phrase like “for reference patterns, use the /mcp-server command” or “for test code, there’s the test-writer agent” removes the selection conflict between similar agents, commands, and skills.

The docs say adding “use proactively” raises the chance of automatic delegation.

Anti-patterns

  • Long descriptions with examples. The catalog has agents with 900-1,000-character descriptions that contain “Example: User says… use this agent” blocks. You pay for such a description on every request, even when the agent isn’t needed.
  • Bilingual descriptions. They work, but they lengthen text that sits in context permanently.
  • Outdated names in tools. An agent written for an older version may still list tools that no longer exist or that subagents never get (AskUserQuestion). The author hasn’t checked in a live run what Claude Code does with partially unresolved names, so compare the list against the current tool set.

Why an agent doesn’t get called

  • The file was skipped. Without description or with invalid YAML, the agent doesn’t load, and the reason goes to the debug log. A file without name is treated as documentation.
  • A typo in a field. Unknown fields are silently ignored. In claude --debug (since 2.1.296), such fields show up in a does not recognize or apply line.
  • The description doesn’t set the agent apart. If two agents have similar descriptions, Claude may pick the neighbor or fall back to general-purpose.
  • You need a guaranteed run. Mentioning @agent-<name> in the request, or picking the agent from the @ list, launches that specific agent. Claude still writes the task wording for it.

When names collide, the definition with the higher priority wins: managed settings, then the --agents flag, then the project’s .claude/agents/, the user’s ~/.claude/agents/, and finally plugin agents.

How many agents you need

The author’s user catalog has 33 agent files. About 10 of them were written by the author, and the rest came with a third-party package. Yet 89% of all runs go to the built-in general-purpose agent, and all custom agents together account for ~7%. The most frequently launched ones are a research agent limited to read-only and web search tools and a read-only reviewer.

The number of agent files says nothing about their value. An agent file is worth having when it pins something down: a narrow tool set, a model, a turn limit, an answer format. For one-off delegation, general-purpose with a well-written task is enough. A sensible start is 2-3 agents for recurring roles with clear boundaries between them, not a catalog “for every occasion” whose descriptions permanently occupy context.

Hooks and observability

To control subagents, there are SubagentStart and SubagentStop events with a matcher on the agent name. SubagentStop receives the path to the subagent’s transcript and its last message, which is enough to log runs or check the answer format. You can also declare hooks in the agent’s frontmatter. They run while the agent is active, and in that case Stop turns into SubagentStop. The Claude Code hooks article goes through the events and the hook format in detail.

/tasks shows the model of each running subagent. For after-the-fact analysis, you have the transcripts in subagents/ and the .meta.json files next to them, which record the agent type.

CLAUDE.md is part of a subagent’s startup context, so its size also affects the cost of delegation. How to keep CLAUDE.md short is covered in the CLAUDE.md guide, and the general logic of managing the window is in the context engineering guide.

Where to start

  1. Run the measurement script on your transcripts and find your subagent startup price. It determines the task length at which delegation pays off.
  2. Don’t delegate 1-3-call tasks or work that needs the conversation history. For the latter, use a fork or /btw.
  3. Set tools on every custom agent. In the experiment on a heavy setup, it was the strongest lever: −78.5% startup context, plus permissions restricted by design.
  4. Add omitClaudeMd: true to agents that don’t need project rules, and remove unused MCP servers from the session.
  5. Keep descriptions short: trigger first, boundary with neighbors at the end, no example blocks. Set the model explicitly in frontmatter, and remember that CLAUDE_CODE_SUBAGENT_MODEL doesn’t override it without _FORCE=1.

Frequently Asked Questions

Do subagents save tokens in Claude Code?
A subagent saves space in the main conversation's context. It spends its own tokens, which count toward the same usage limits, and every launch has a startup cost: system prompt, CLAUDE.md, tool schemas. It pays off when the intermediate work is large (dozens of tool calls) and the answer is short.
Does a subagent see my conversation and CLAUDE.md?
A regular subagent doesn't see the conversation history. It gets its own system prompt, the task message, CLAUDE.md, a git status snapshot, and preloaded skills. The built-in Explore and Plan agents start without CLAUDE.md and git status. For a custom agent, you can turn CLAUDE.md off with omitClaudeMd: true. Only a fork sees the full history.
How do I choose the model for a Claude Code subagent?
Set the model field in frontmatter: sonnet, opus, haiku, fable, a full model ID, or inherit. The model parameter in the Agent call overrides frontmatter, and CLAUDE_CODE_SUBAGENT_MODEL acts as a default. To put every subagent on one model, you also need CLAUDE_CODE_SUBAGENT_MODEL_FORCE=1.
How many subagents can run in parallel?
Per the docs, up to 20 at once in one session by default; CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS changes the limit. Nesting goes up to three levels below the main conversation by default and is set by CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH (a value of 1 turns nesting off).
How is a subagent different from a skill and a fork?
A skill runs in the current context, together with the conversation history. A subagent starts with a clean context and returns only its answer. A fork is a subagent that inherits the whole conversation, system prompt, tools, and model of the main session and shares its prompt cache; it also returns only the result.
Why doesn't Claude call my agent?
Common causes: the file was skipped because the description is missing or the YAML is invalid, a field name has a typo (unknown fields are silently ignored), or the description doesn't set the agent apart from its neighbors. claude --debug shows why a file was skipped. Mentioning @agent- in the request guarantees the agent runs.
How do I reduce a subagent's startup context?
The strongest lever is a narrow tools list: the allowlist drops the schemas of all other tools, MCP included, from the context. Next come omitClaudeMd: true and fewer MCP servers in the session. In the author's experiment, tools and omitClaudeMd together cut startup by 91.8%, but in a lightweight setup the absolute savings will be smaller.