Skip to content

AI CODING ASSISTANTS

Claude Code Subagents: A Practical Guide

Build a project subagent, confirm it loaded without spending a token, and see the three ways a definition fails silently — measured on Claude Code v2.1.224.

Claude Code subagents run a task in a separate context window and return only the summary, which is what keeps a 40-file search out of the conversation you are actually working in — and out of the context floor every later turn pays for. This guide builds two real project subagents for this repository, shows a probe that confirms they loaded without spending a single token, and documents the three ways a definition fails where the session tells you nothing at all. For where subagents sit among Claude Code's other extension points, see the complete Claude Code guide. Measured against Claude Code v2.1.224 on 2026-08-07.

Key takeaways

  • A subagent gets its own context window and its own system prompt — not the full Claude Code system prompt, and not your conversation history.
  • Custom subagents load your CLAUDE.md. Explore and Plan do not. That exception is documented and has no per-agent override.
  • claude --agent <nonexistent> --init-only lists every available agent and exits, so you can verify discovery for free.
  • Three definition failures are silent in-session: a : in the name, a duplicate name, and a missing name field — the last logs nothing at all, even at debug level.
  • Tool access is filtered twice, and background is the default, so the same definition can resolve to different tools depending on where it runs.

What a subagent actually is

Four things are separate from your main conversation: the context window, the system prompt, the tool list, and the permission mode.

Anthropic's subagents documentation describes the startup state precisely. A non-fork subagent does not see your conversation history, the skills you have invoked, or the files Claude has already read. It receives its own system prompt plus environment details, a delegation message Claude writes summarising the task, your CLAUDE.md hierarchy, and a git status snapshot.

That last pair is the detail people get wrong. A custom subagent does load your project instructions. The built-in Explore and Plan agents are the only two that skip CLAUDE.md and git status, and the docs state there is no frontmatter field or per-agent setting to change which agents skip them.

The consequence is worth sitting with: your project conventions reach a custom subagent as context, with the same advisory weight they carry in the main session. If a rule matters enough that a subagent must not break it, it belongs in a hook, for exactly the reasons covered in why Claude ignores CLAUDE.md.

The built-in subagents

Five are registered by default in an interactive session. We confirmed the list on this machine rather than taking it from the docs — the probe is in the next section but one. Bundled commands spawn their own on top of these: one /security-review run fanned out to nine sub-agents, one per candidate finding, which is where the bill comes from.

AgentModelUsed for
ExploreInherits, capped at OpusRead-only search and codebase discovery
PlanInheritsResearch during plan mode
general-purposeInheritsMulti-step work needing both search and edits
claudeInheritsCatch-all when nothing more specific fits
statusline-setupSonnetConfiguring your status line

Explore and Plan are read-only: Write and Edit are denied. As of v2.1.198 Explore inherits the main conversation's model rather than always running on Haiku, which made it better and more expensive at the same time. If you want the old behaviour, define a project subagent named Explore with model: haiku — a user or project definition overrides the built-in and keeps its own model field.

Write a project subagent

A subagent is a markdown file: YAML frontmatter for configuration, body for the system prompt. Only name and description are required. This repository now ships two, both checked into version control so the whole project gets them.

.claude/agents/content-auditor.md
---
name: content-auditor
description: Runs the repository's editorial checks against content/ and reports only the failures. Use before publishing an article, or after editing any file under content/.
tools: Bash, Read, Grep, Glob
model: haiku
color: yellow
---

You audit this repository's articles against its own editorial checks. You do not
write or edit files; report findings and stop.

Three choices in that frontmatter are load-bearing.

description is the routing signal, not documentation. Claude decides when to delegate by reading it, so it names the trigger conditions rather than describing the agent's personality.

tools is an allowlist that replaces inheritance. Naming four tools means this agent cannot edit files, write files, or reach any MCP server, regardless of what the main session can do.

model: haiku is a cost decision. Running three shell checks and classifying the output does not need the session's model, and the field defaults to inherit if you omit it.

The second agent, roadmap-scout, is read-only — Read, Grep, Glob — and exists because this project's roadmap is 1,800 lines that nobody should pull into the main context to answer "what is next."

Confirm it loaded without spending a token

The usual way to test a subagent is to ask Claude to use it, which costs a model turn and tells you nothing useful when it fails. There is a better way.

--init-only runs setup and session-start hooks then exits. Combined with --agent and a name that does not exist, Claude Code enumerates everything it found and quits before any model turn:

Terminal
claude --agent definitely-not-real --init-only
# → --agent 'definitely-not-real' not found. Available agents: claude, Explore,
# →   general-purpose, Plan, statusline-setup

That was this repository before the two files existed: five built-ins. After adding them:

Terminal
claude --agent definitely-not-real --init-only
# → --agent 'definitely-not-real' not found. Available agents: claude, content-auditor,
# →   Explore, general-purpose, Plan, roadmap-scout, statusline-setup

Seven. Both project agents discovered, no session started, nothing billed. This is the check to run after writing a definition and the one to run when a subagent "does not work" — because most of the time it did not load, and a delegation attempt cannot distinguish that from a bad prompt.

One discovery caveat is documented and real: the file watcher covers only directories that existed when the session started. Creating .claude/agents/ for the first time mid-session requires a restart. Edits to files in an already-existing directory are picked up within seconds.

Three ways a definition fails silently

We wrote four deliberately broken definitions into .claude/agents/, re-ran the probe, and captured the debug log with --debug-file. The session output did not change at all — the available-agents list simply did not include them.

The log did:

Debug log excerpt, v2.1.224
[ERROR] Agent file .claude\agents\_probe-colon.md has invalid name 'bad:name':
        names must not contain ':' (reserved for plugin namespacing)
[DEBUG] [agents] Duplicate agent name 'content-auditor' (projectSettings):
        _probe-dupe.md, content-auditor.md — active: _probe-dupe.md

A colon in name blocks the file. Colons are reserved for plugin-scoped identifiers like my-plugin:reviewer. This one at least logs an ERROR.

A duplicate name is the dangerous one. Two files declared content-auditor, and the log names the winner: _probe-dupe.md, the throwaway probe. Adding a file can silently take over an existing agent's name, the real definition stops being used, and the only record is a DEBUG line. Anthropic documents the selection as filesystem read order rather than any precedence rule, which is consistent with what we saw.

A definition with no name field produced no log line whatsoever — not at ERROR, not at DEBUG. It simply never registered. Of the three, this is the one you will spend the longest looking for.

The same log also shows the scope chain being walked in order, which confirms the documented precedence:

Debug log excerpt, v2.1.224
Failed to stat directory C:\Program Files\ClaudeCode\.claude\agents: ENOENT
Failed to stat directory C:\Users\<user>\.claude\agents: ENOENT
[STARTUP] Loading commands and agents...

Managed settings first, then user scope, then project. Both higher scopes were absent here, so the project definitions loaded unopposed.

Because none of this surfaces in a session, this repository now has scripts/check-agents.mjs, which validates every definition against the documented schema and reports what the CLI hides:

Terminal
npm run check:agents
# → 6 definition(s) under .claude/agents/
# →
# →   content-auditor    model=haiku    tools=4
# →   roadmap-scout      model=haiku    tools=3
# →
# → ERROR  .claude/agents/_probe-noname.md
# →        missing required field `name` — never registers, and logs nothing
# → ERROR  .claude/agents/content-auditor.md
# →        duplicate name 'content-auditor', also in _probe-dupe.md
# →
# → 2 loadable, 4 error(s), 2 warning(s).

Its own first version had a bug worth admitting: it counted definitions with fatal errors as "loadable," which is precisely the false reassurance the check exists to remove.

Tool access is filtered twice

Claude Code's tool access mode for subagents is not one list, it is two filters applied in sequence, and this is the behaviour most likely to surprise you.

The first filter removes a fixed set from every subagent regardless of the tools field: AskUserQuestion, EndConversation, EnterPlanMode, ScheduleWakeup, TaskOutput, WaitForMcpServers, and Workflow. Agent goes too, once the subagent is at the nesting depth limit.

The second filter applies to subagents running in the background — which, since v2.1.198, is the default. A background subagent keeps every MCP tool but only a reduced built-in set: Read, Grep, Glob, Bash, PowerShell, Edit, Write, NotebookEdit, WebFetch, WebSearch, TodoWrite, Skill, ToolSearch, EnterWorktree, ExitWorktree, Monitor, TaskStop, SendMessage, and Artifact.

So the same definition can resolve to different tools depending on where it runs, and the removal reports no error unless it leaves the list resolving to nothing. If nothing survives, the subagent refuses to launch and the Agent tool returns an error naming the unresolved entries — which is a better outcome than the pre-v2.1.208 behaviour of launching with no tools and returning something confusing.

Two fields control the pool. tools is an allowlist; disallowedTools is a denylist applied first, with tools resolved against what remains. Both accept MCP patterns, so disallowedTools: mcp__github drops one server while keeping the rest. That is worth using deliberately rather than leaving to inheritance: a subagent exists to keep noise out of your main context, and an MCP server's tool definitions are context it spends before doing anything — measured per server, the difference between a lean pool and the default one is thousands of bytes on every request.

permissionMode is separate and can be overridden — except upward. If the parent session is in bypassPermissions or acceptEdits, that takes precedence. If the parent is in auto mode, the subagent inherits auto mode and its own permissionMode is ignored entirely.

Subagents, background agents, and panes

Three things get conflated, and picking the wrong one is the most common structural mistake here.

MechanismRuns whereResult goes
SubagentInside your sessionSummary into this conversation
Background agentIts own sessionStays there; monitor with claude agents
Agent team teammateOwn context, coordinatedMessages between agents

A subagent is for a side task within work you are doing. A background agent is a separate session you dispatch and come back to — claude agents opens the view, and attach, logs, stop, and respawn control individual sessions from the shell.

Searches for "claude panes" usually mean the third case: several agents visible side by side. That is agent teams rather than subagents, and the display is controlled by --teammate-mode, which takes in-process, auto, tmux, or iterm2. The --tmux flag creates a tmux session for a worktree and uses iTerm2 native panes when they are available. None of that applies to subagents, which have no independent display — they appear as a row in the transcript and in /tasks.

For a task that needs your conversation's full context rather than a fresh one, /subtask forks instead of spawning fresh, and /btw answers a side question with no tool access at all. Skills are the other neighbour: they run in the main conversation rather than an isolated context, and skills and slash commands covers when that is the better shape.

Common mistakes

  • Testing a new subagent by asking Claude to use it. A failed delegation cannot tell you the file never loaded. Run the --init-only probe first; it is free.
  • Reusing a name. Two definitions with one name means the wrong file can win, and the only evidence is a DEBUG line. Keep names unique across the whole tree, including subfolders.
  • Assuming Explore reads your CLAUDE.md. It does not, and neither does Plan. If a rule matters to a search task, restate it in the delegation prompt.
  • Writing a description that describes the agent. It is a routing signal. Name the conditions under which Claude should hand work over.
  • Listing tools a background subagent cannot keep. Background is the default since v2.1.198, and anything outside the reduced built-in set is removed without an error.
  • Reaching for subagents when you want parallel sessions. Many subagents returning detailed results consume the context you were trying to protect. Background agents or agent teams are the right shape for sustained parallel work.
  • Expecting /rewind to undo what a background subagent edited. Those edits usually land outside your session’s checkpoints, so git is the recovery path — see what Claude Code checkpoints can and cannot restore.

Conclusion

Write the definition, run claude --agent bogus --init-only to confirm it loaded, and only then delegate anything to it — that sequence turns most subagent debugging into a five-second check. Keep tools tight and description written as a trigger, put anything the subagent must not do in a hook rather than its system prompt, and use background agents instead when the work is genuinely parallel rather than a side task. If you maintain more than two or three definitions, validate them in CI, because every failure mode we found was silent in the session. For the wider command surface these sit behind, see the complete Claude Code command reference.

Frequently asked questions

What is a Claude Code subagent?
A specialised assistant that runs in its own context window with its own system prompt, tool access, and permissions. Claude delegates a task to it, the subagent works independently, and only its summary returns to your main conversation. The point is that verbose intermediate output, such as search results or test logs, never enters the context you are working in.
Where do subagent files live?
Project subagents go in .claude/agents/ and user subagents in ~/.claude/agents/, both scanned recursively. Precedence runs managed settings, then the --agents CLI flag, then project, then user, then plugins. When two files in the same directory declare the same name, only one loads and Claude Code picks it by filesystem read order rather than any documented rule.
Do subagents see my CLAUDE.md?
Custom subagents do. Anthropic documents that a non-fork subagent's initial context includes every level of the CLAUDE.md hierarchy the main conversation loads, plus git status. The built-in Explore and Plan agents are the two exceptions and skip both, to keep research fast. There is no frontmatter field to change which agents skip them.
How do I check a subagent definition is valid before using it?
Run claude --agent with a name that does not exist and the --init-only flag. Claude Code prints the full list of available agents and exits without starting a model turn, so the probe costs nothing. A definition missing from that list did not load. For the reason it did not load, pass --debug-file and read the log.
What is the difference between a subagent and a background agent?
A subagent runs inside your session and returns a summary to it. A background agent is a separate session you dispatch and monitor with claude agents, and it has its own conversation. Subagents suit a side task within one piece of work; background agents suit several independent pieces of work running at once.

Muhammad Kashif

Founder and editor of Devventa, covering AI coding assistants, Next.js and the modern AI development stack.