Understanding Claude Code subagents (the Task tool)
When a Claude Code run needs to do several independent things, like searching across a large codebase or working through a list of files, it can spawn subagents through the Task tool. Each subagent is its own agent working in parallel, and the main run gathers their results. Here is what that means, how to define your own, and how to keep an eye on it.
What a subagent is
A subagent is a separate Claude Code agent that the main session launches to handle a scoped piece of work. Instead of doing everything itself in one long thread, the main agent fans the work out: several subagents run at once, each on its own task, and report back with a summary rather than everything they read.
The important detail is that a subagent has its own context window. It can grep through forty files, read three of them in full, and hand back six lines. None of that noise lands in the main conversation, which is why a run that uses subagents well stays coherent much longer than one that does everything inline.
Why it matters
Subagents make a run faster on parallelisable work, and they keep the main context clean. But they also make it busier and harder to read: the main session can sit "working" for a while because five subagents are running underneath it, with nothing printed in between. Knowing whether a session is genuinely busy or actually stuck is exactly the kind of thing that gets murky here.
Defining your own
Beyond the generic ones Claude spawns on its own, you can define named subagents as markdown files, one per agent:
- Project agents:
.claude/agents/*.md, committed with the repository and shared with your team. - User agents:
~/.claude/agents/*.md, available in every project.
The frontmatter declares the agent, and the body is its system prompt:
---
name: test-runner
description: Runs the test suite and fixes failing tests. Use after code changes.
tools: Read, Edit, Bash, Grep
model: sonnet
---
You run the project's test suite, read the failures, and fix them.
Run `npm test` first. Fix only what the failures point at, never refactor
around them, and re-run until the suite is green. Report which tests failed
and what you changed, nothing else.
A few things to get right:
descriptionis how the main agent decides to delegate, so write it as a trigger ("use after code changes"), not as a title.toolsnarrows what the subagent may do. Leave it out and it inherits the full set; naming a short list is both safer and cheaper.modelpins a model per agent, which is worth it when a task is mechanical enough for a smaller one.- A project agent and a user agent with the same name collide, and the project one wins.
The /agents command inside a session lists what is available and walks you through creating one, writing the same files for you.
Getting one to actually run
Delegation is a decision the main agent makes, based on the description you wrote, so a vague one means your agent never gets used. Two things fix that: phrase the description as a situation rather than a capability, and say so in the prompt when you want it. "Use the test-runner agent on the auth module" is unambiguous, and it also tells you whether the agent is doing its job before you rely on it being picked automatically.
Where subagents do not help
They are not free. Each one starts from a blank context, so it knows nothing about the conversation so far beyond the instructions it is handed, and briefing it properly costs tokens. A subagent also cannot spawn its own subagents, and it cannot ask you a question mid-flight. That makes them excellent for wide, read-heavy work (search, audit, review, per-file transformations) and poor for anything that needs the thread of the discussion you have been having.
The SubagentStop hook
Claude Code fires a dedicated hook, SubagentStop, each time a subagent finishes, distinct from Stop, which fires when the whole turn ends. That lets you track subagents completing independently:
{
"hooks": {
"SubagentStop": [
{ "hooks": [{ "type": "command", "command": "echo 'a subagent finished' >> ~/claude-subagents.log" }] }
]
}
}
The payload carries the usual session_id, transcript_path and cwd, so on a machine running several projects you can tell which one the subagent belonged to:
#!/usr/bin/env bash
payload=$(cat)
project=$(basename "$(echo "$payload" | jq -r '.cwd')")
echo "$(date +%H:%M:%S) $project subagent done" >> ~/claude-subagents.log
One warning if you plan to notify on it: a fan-out of eight subagents fires this hook eight times in a row. Wire SubagentStop to a desktop alert or a sound and you will regret it within one run. Counting is fine; announcing is not. See the reference of every hook event for how SubagentStop sits alongside Stop, Notification and the rest.
Seeing "busy with subagents" at a glance
The number of live subagents is a great signal for how busy a session really is, but a log line does not convey it, and a notification per subagent is worse than nothing. Blooby reads SubagentStop (and every other event) and reflects it in the session's mascot, so a session churning through subagents visibly looks hard at work, and you can tell it apart from one that is idle or waiting on you.
See it for yourself
download Get Blooby free