TL;DR: Create a markdown file in .claude/agents/<your-agent>.md with frontmatter (name, description, optional tools) and a system prompt below. The main agent can delegate to it via the Agent tool β useful for tasks with isolated context.
A subagent is a specialist the main agent can delegate to β its own system prompt, its own tools, its own context window. Use one when a task has a clean boundary, when its working assumptions differ from the conversation around it, or when you simply don't want it polluting the main context.
The default mode of working with an agent is one long, growing conversation. Every prompt, every tool result, every file the agent reads β all of it accumulates in the same context window. That works fine for short tasks. It works badly for long ones, because two failure modes show up together. The first is dilution: the longer the chat, the more competing instructions the model is trying to balance, and the more important things start to drift. The second is leakage: a research task that should have been a read-only exploration ends up with the agent suggesting code changes it has no business making yet, because the main context is in "write" mode.
A subagent fixes both. It's a fresh agent invocation with its own system prompt and its own tool set, called by the main agent like a tool. The subagent does its job in isolation, returns a structured result, and disappears β its 20,000 tokens of intermediate scratch work never enter the parent conversation. Only the summary comes back.
The art of subagents is figuring out which tasks deserve one. The wrong answer is "everything" β delegating trivial work to subagents adds latency and confusion. The right answer is "tasks with a clean boundary and a different mental mode." Code review. Test generation. Codebase exploration. Anything that takes meaningful work but produces a compact result.
Subagents live in .claude/agents/<name>.md (project-local) or ~/.claude/agents/<name>.md (user-wide). Each file is markdown with YAML frontmatter:
---
name: code-reviewer
description: Use this for in-depth code review of staged or unstaged changes. Invoke when the user says "review this," "look over this diff," or before they push.
tools: [Read, Grep, Glob, Bash]
---
# Code reviewer
You are a senior code reviewer. Read the staged diff with `git diff --staged`,
and the unstaged diff with `git diff`. For each meaningful change:
- Note what was changed and whether it accomplishes the stated goal.
- Flag bugs, race conditions, and security issues.
- Flag missing tests for non-trivial logic.
- Flag style violations only if egregious.
Do NOT propose fixes β that's the main agent's job. Report findings only.
The frontmatter has three meaningful fields: name (used to invoke), description (used for routing), and optionally tools (a restricted tool whitelist).
When the main agent decides whether to delegate, it reads available subagents' descriptions and picks the one whose description matches the situation. A vague description ("helps with code") gets ignored; a specific one ("Use this for code review of staged or unstaged changes") gets picked.
Write descriptions in the form "Use this for [task]" or "Invoke when the user [says/wants/needs] [thing]." Imagine future-you reading the description cold β would you know when to dispatch?
By default a subagent can use any tool the main agent can. Restrict it with the tools field in the frontmatter to the minimum set needed for its purpose:
Read, Grep, Glob, and maybe Bash for git commands β and should NOT have Edit, Write, or anything destructive. It reviews; it doesn't fix.WebFetch. It explicitly should NOT have Edit or Write.Read, Grep, Edit, Write, Bash. The full edit set, but scoped to test files by the system prompt.The tool list is policy, not preference. A subagent that lacks Edit literally cannot edit, regardless of what the model "wants" to do. This is exactly what you want for a code reviewer: even if the model is tempted to "just fix this small thing," it can't.
Subagents are invoked two ways:
Either way, the subagent gets a fresh context window, does its work, returns a summary, and disappears. The main conversation continues with just the summary in scope.
Rule of thumb: if you want isolation, write a subagent. If you want different behavior in the same context, write a skill. If you want a fast trigger, write a slash command.