Claude Code subagents: two files, 125 dispatches, and the work that never touched my context
- claude-code
- agent-ops
- context-engineering
Claude Code subagents are separate Claude instances that take one task from your main session, run it in their own context window with their own system prompt, tools and permissions, and hand back a result. The searches, logs and file dumps they produce stay in their transcript, not yours. I run two of them from two markdown files, and a grep over my session transcripts on 4 September counted 125 dispatches across 44 sessions. This post is what the docs promise, what those runs taught me, and one leaked secrets file.
- What it is. Per the docs, "specialized AI assistants that handle specific types of tasks", and each one "runs in its own context window with a custom system prompt, specific tool access, and independent permissions". A markdown file with YAML frontmatter defines one.
- What comes back. Only the final result. Conversation history does not flow in, except for forks, and tool output does not flow out.
- What decides delegation. The
descriptionfield. Claude reads it to match tasks, so it is the most important line in the file. - What mine look like.
deep-reasoneronopusfor the hard thinking,fast-workeronhaikufor mechanical jobs with a spec. Twenty lines each. - The rule I learned the hard way. A subagent on a file with secrets gets
grep -nfor one line, nevercat. It will run the literal command and paste the result into your transcript.
Everything here runs inside the Claude Code install I already reviewed.
Can Claude Code have multiple agents?
Yes. Claude Code ships with built-in subagents and lets you define your own, and a session can run many of them at once. The subagents documentation puts the default ceiling at 20 concurrent subagents and three levels of nesting below the main conversation. Each one is a fresh instance, not a continuation of an earlier one.
The docs name six. Three do the general work. Explore is a fast, read-only agent
for searching and analyzing a codebase, invoked with a thoroughness level of quick,
medium or very thorough. Plan is the read-only research agent used in plan mode.
general-purpose gets the full tool set for multi-step work. The other three sit in
the docs' "Other" tab: claude, the catch-all with every tool available to
subagents, for a task that fits no specialized agent; statusline-setup behind
/statusline; and claude-code-guide for questions about Claude Code itself.
Explore and Plan skip CLAUDE.md files and the parent session's git status, in the
docs' words "to keep research fast and inexpensive".
Where a definition can live, in the docs' priority order: managed settings, a JSON
blob passed with the --agents CLI flag for one session, .claude/agents/ in the
project, ~/.claude/agents/ for every project on the machine, and a plugin's agents/
directory. Project definitions are found by walking up from the working directory;
the closest wins.
What a subagent gets, and what it never sees
The isolation is the point, and the docs list both sides. A subagent receives:
- its own system prompt rather than Claude Code's;
- the task message Claude wrote for it;
- the CLAUDE.md hierarchy, except for Explore and Plan;
- a git status snapshot, with the same exception;
- any skills listed in its
skillsfield; - a roster of sibling agents, if it has
SendMessagein its tools and at least one other agent in the session carries a name.
It does not receive the conversation history, the session's output style, the session's auto memory, or skills the main session invoked earlier, which it has to rediscover through the Skill tool. The docs name one exception: a fork "inherits the entire conversation so far instead of starting fresh" and "sees the same system prompt, tools, model, and message history as the main session". Even then, "the fork's own tool calls still stay out of your conversation and only its final result comes back".
Two consequences follow. "Fix the bug we discussed" delegates nothing, because the
message and the files are all it has. And the return path is a summary, so a finding
that did not make it into the final report might as well not exist. The transcript
survives on disk under
~/.claude/projects/{project}/{sessionId}/subagents/agent-{agentId}.jsonl for 30 days
by default (cleanupPeriodDays), but nothing reads it back for you.
Does Claude Code automatically use subagents?
Yes, when a task matches a subagent's description. Claude reads that field to decide
whether to delegate, so the wording matters most. The docs also let you force or
block delegation: @agent-<name> in a prompt guarantees a run, claude --agent <name>
makes one agent the whole session, and a permissions.deny entry such as
Agent(Explore) blocks a type.
The automatic path has a cost the docs quantify. Subagent descriptions load into
context at startup. When your own subagents' combined descriptions, built-in ones
excluded, pass 15,000 tokens, Claude Code shows a warning at startup with the total.
Keep the description short and move the detail into the body,
which only loads when the subagent runs. The docs also list the tools a subagent
never gets, whatever the file says, forks excepted: AskUserQuestion, EnterPlanMode and
ExitPlanMode (the latter stays when the subagent's permissionMode is plan),
ScheduleWakeup, TaskOutput, Workflow, EndConversation,
WaitForMcpServers, and Agent itself once the depth limit is reached. So a subagent
cannot stop to ask you a question; whether it guesses or reports back depends on what
you wrote in its file.
To turn the automatic behavior off entirely, deny the Agent tool in
permissions.deny. To drop only Explore and Plan, set
CLAUDE_CODE_DISABLE_EXPLORE_PLAN_AGENTS=1 (v2.1.198 and later).
The two subagent files on my disk
My ~/.claude/agents/ holds two files. Both are 20 lines.
| Field | deep-reasoner.md | fast-worker.md |
|---|---|---|
model | opus | haiku |
| Used for | Architecture, hard debugging, data analysis with hypotheses, reviewing a plan before a build | Mass file edits, boilerplate, parsing logs and CSV, simple scripts, pulling data from an API to a written spec |
| The rule that matters | Missing data: say exactly what is missing and where to find it, instead of guessing | Spec unclear or contradictory: stop and return the question, do not guess |
| Numbers and state | Only from a source: file, query, log. No "will probably work" | No design decisions: names, architecture, thresholds belong to the orchestrator |
| Secrets | Credentials only from the panel file, never pasted into the answer | Same, plus no destructive operation (delete, overwrite, push) without an explicit line in the brief |
| Report format | Recommendation in one or two sentences, three to five points of evidence, risks and what would overturn the conclusion, what was missing | What was done, which files or results, what did not work or was skipped |
Matching the model to the job that way is my rule, not the docs'. What the docs
fix is the resolution order: a model value on the invocation wins, then the
frontmatter, then the CLAUDE_CODE_SUBAGENT_MODEL environment variable, then the
main conversation's model.
Set CLAUDE_CODE_SUBAGENT_MODEL_FORCE=1 alongside CLAUDE_CODE_SUBAGENT_MODEL
(v2.1.257 and later) and every subagent runs on the environment variable regardless of
its file; set the force flag alone and subagents run on the main conversation's model.
My frontmatter is three lines: name, description, model; the docs require
only the first two. Three optional fields
are on my list to try. isolation: worktree runs the
subagent in a temporary git worktree with an isolated copy of the repository, branched
by default from your default branch rather than the parent session's HEAD, and
cleaned up automatically if the subagent makes no changes. memory: user gives the
agent its own persistent notes under ~/.claude/agent-memory/<name>/, with its
MEMORY.md preloaded up to 200 lines or 25 KB. hooks in the frontmatter take any
hook event, most often PreToolUse, PostToolUse or Stop (Stop becomes
SubagentStop at runtime), and fire only while that subagent is active, the same
mechanism as the production hook I run at the session level.
Three details matter before you write an agent file. A file with
no name, or whose opening --- is not the first line, is read as documentation and
skipped without a word. A name that starts with - or contains a colon is skipped
too, but that one lands in the debug log. And
claude plugin validate ~/.claude/agents (v2.1.233 and later) checks the YAML before
the session does.
How many subagents can Claude Code spawn?
By default, 20 at the same time and three layers deep. Both numbers are settings: the
docs name CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS for the concurrent limit and
CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH for nesting, where a value of 1 means no nesting.
The count is layers below your main conversation, so a value of 2 lets your subagent
delegate once and stops the layer under it.
Foreground or background is the other axis. In an interactive session with fork mode
on, the default, a subagent runs in the background and its result arrives as a
completion notification; Ctrl+B sends a foreground one to the background; and
background: true in the frontmatter forces it. Permission prompts from a background
subagent surface in the main session with the subagent's name attached. Under
claude -p and in the Agent SDK fork mode is off unless you turn it on. With fork
mode off Claude still runs a subagent in the background by default, and moves it to
the foreground only when it needs the result before continuing.
Are Claude Code subagents worth it?
For work that produces more text than you will read, yes; for a task you want to steer mid-way, no. The dispatch that pays for the design is independent review of another agent's draft, because a subagent has no memory of how the draft came to be.
That is the worker and judge pattern this blog runs on. The writer is a fork, so it
knows every source, rule and prior finding. The judge is deep-reasoner on a clean
context with the draft and the brief. On 4 September the first
judge pass on a post about an ad platform returned three blockers, two of them one
false claim stated twice: that everyone who pays for a plan is outside the ad
audience, when the vendor's help center says one paid tier sees ads.
The cost side is real: every run is a full model call with its own context, which is
why the docs put cost control on the list of what subagents are for, and point at
faster, cheaper models like Haiku. /tasks lists what is running; the transcripts
under subagents/ are what you open when a result looks too clean.
Subagents vs skills, hooks and agent teams
Four mechanisms get confused in the same sentence. A skill is instructions that load
into your context when invoked; a subagent is a separate context that runs and
returns. "Do it this way" is a skill, "do it over there and tell me the result" is a
subagent, and the skills field lets a subagent preload the former.
A hook is a shell command at a fixed lifecycle event. Subagent frontmatter can carry
hooks scoped to that agent, and settings can carry SubagentStart and SubagentStop
hooks around every run. Frontmatter hooks on a project-level agent in .claude/agents/
run only after you accept the workspace trust dialog for the folder holding the file;
until then the subagent still runs and Claude Code skips its hooks and logs an error
(v2.1.218 and later). Hooks on user-level agents in ~/.claude/agents/, and on
definitions passed with --agents, run without that step.
Agent teams are peers that write to each other by design, experimental and off
until you set CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1. A subagent can reach a
sibling too: the roster from the list above names main and every other named
agent, each a valid recipient (v2.1.206 and later), and it is a snapshot taken when
the subagent starts, so agents named later are not on it. The difference is who holds the
plan: subagents report to the caller. SendMessage to a named subagent also resumes
it with its context intact instead of starting a new one.
Since v2.1.210 Claude Code scans a subagent's report before Claude reads it, inserting backslashes into text that imitates Claude Code's own output and prepending a marker when a report imitates those tags or mentions permission settings. It removes nothing; it guards against a subagent, or a file it read, smuggling instructions back up the tree.
The trap: a haiku worker and cat .env
On 3 June a subagent on haiku had one job: set one variable in a profile's
.env file on a server, with "minus secrets" in its brief. It ran cat on the file,
476 lines, and pasted all of them into its report, an API key and a bot token
included. The report landed in my session transcript, which outlives the session on
disk.
The subagent did nothing wrong by its own rules: "minus secrets" is not an instruction
a literal worker can execute. The fix went into the brief template, not the agent
file. On any file that may hold credentials the worker gets three shapes:
grep -n '^KEY=' file for the one line it needs,
grep -q '^KEY=' file && echo PRESENT || echo ABSENT to check existence without
printing, and an append that never reads the file. The cheaper the model, the narrower
the instruction has to be, because it will do exactly what the words say.
Subagents in Codex and Cursor
Codex documents subagents at
learn.chatgpt.com/docs/agent-configuration/subagents:
"ChatGPT Work and Codex can run subagent workflows by spawning specialized agents in
parallel and then collecting their results in one response." A custom Codex subagent
is a TOML file under ~/.codex/agents/ or .codex/agents/ carrying a name, a
description and developer instructions. It inherits the parent's model and reasoning
effort, plus sandbox mode, MCP servers and skills, when its own file leaves them out.
Cursor documents its own at cursor.com/docs/subagents:
"Subagents are specialized AI assistants that Cursor's agent can delegate tasks to.
Each subagent operates in its own context window, handles specific types of work, and
returns its result to the parent agent." Its file is markdown with frontmatter under
.cursor/agents/ or ~/.cursor/agents/, closer to Claude Code's shape than Codex's
TOML, and Explore, Bash and Browser are built in. Every path, field and limit
in the sections above is Claude Code's.
Best practices I actually follow
- One agent file per job shape, not per project; the task message carries the specifics.
- Write the
descriptionas the one-sentence condition for delegation; the rest goes below the frontmatter, where it costs nothing until the run. - Pick the model by the job:
haikuwith a written spec,opusfor anything that needs a hypothesis. - Put every fact the subagent needs in the message or in a file path; it cannot ask.
- Ask for a fixed report shape; the parent reads only that.
- Never let a subagent
cata file that may hold a secret. One line bygrep, or nothing. - Use a fresh-context subagent, not a fork, to judge anything a fork wrote, and start it after the writer's completion notification.
- Run
claude plugin validate ~/.claude/agentsafter editing an agent file.
Public catalogs of agent files exist, awesome-claude-code-subagents on
GitHub among them; a reading list, not an install.
For tasks that change files in parallel, isolate parallel edits with Claude Code worktrees. Review each branch before combining the changes.
The pattern underneath all eight is the one from production-ready agents: the model that did the work is not the model that grades it, and the context window that matters is the one you keep the noise out of. A subagent is the simplest agent you will define.
Sources, read on 4 September 2026: Claude Code's Create custom subagents page and its CLI reference; every path, limit, version number and quotation above comes from those two. Codex: subagents. Cursor: subagents. The agent files, the dispatch count and the June incident are from my own machine.