The Task Tool — Background Work

Running long operations in the background, getting notified on completion, and the no-polling rule that makes this fast.

Feature Intermediate
9 min read
task background async notifications sub-agents

What it is#

The Task tool launches a sub-agent in the background. The sub-agent runs in its own context window with its own tool budget, executes a discrete unit of work — usually an investigation, a refactor across many files, or a multi-step build — and reports back when it is done. The parent session is free to do other work while the sub-agent runs.

Task is one of two ways Claude Code does asynchronous work. The other is run_in_background: true on a Bash call, which is the right shape for “run a shell command and tell me when it exits”. Task is the right shape for “run a sub-agent and tell me when it returns its summary”. Both share the same notification mechanism: the harness fires an event when the work completes, and the model picks the conversation back up.

The thing that makes Task useful in practice is that it does not poll. The model fires the Task and continues; the system notifies on completion. No sleep N && check loops, no busy waiting, no wasted tokens.

When to use it#

Reach for Task when a unit of work is:

  • Long enough that synchronous waiting hurts. A repo-wide refactor that touches 40 files. A test suite that takes three minutes. A data-extraction job over a large corpus.
  • Self-contained enough that you can describe the goal once. “Find every place that calls enqueueTask and rename it to scheduleTask, then run the tests” is a complete task. “Refactor the auth system” is not — the parent agent should plan that first.
  • Bounded in scope. A Task with no clear exit criterion wanders. Give the sub-agent a definition of done.
  • Parallelisable with other work. If the parent has nothing useful to do while the Task runs, you have not gained much over a synchronous call — except a cleaner context window in the parent.

Avoid Task when:

  • The work is short. A 5-second grep does not benefit from Task — the orchestration overhead is bigger than the work.
  • The work requires tight back-and-forth. Task is a fire-and-summarise primitive, not a chat. If the work needs a clarifying question every step, do it inline.
  • You will not use the parent’s idle time productively. Task without parallel work in the parent is just a slower synchronous call.

How it works#

The launch shape#

A Task call specifies the sub-agent type, a prompt describing the work, and an optional description used in status displays. The harness spins up a fresh agent loop with its own context, gives it the requested tools, and runs it. When the sub-agent finishes (or hits its turn budget), it produces a final response. The parent receives that response as the Task tool’s return value.

Sub-agent types#

The agent type slot picks the underlying personality and tool allowlist. Built-in types typically include general-purpose (full tool access), explore (search-heavy, no edits), and project-defined ones. Custom sub-agents are configured in ~/.claude/agents/ and are how you bake a recurring workflow into a single-call primitive.

Notification, not polling#

The crucial rule: after firing a Task with background semantics, the model does not poll. The harness delivers a system notification when the Task completes; the model responds to that notification in the next turn. Chaining a Bash like while Task is running; do sleep 5; done is anti-pattern — it ignores the notification mechanism and wastes time.

This rule shows up in user-level memory often, because it is easy to fall into the polling trap when a model has been trained on patterns from other agent frameworks. Claude Code’s notification system is the right channel.

Context isolation#

A Task runs in a fresh context window. The sub-agent sees its prompt, its CLAUDE.md, and whatever it discovers via tools — but it does not see the parent’s conversation history. This is a feature: it stops sub-agents from accidentally re-litigating decisions made in the parent. The sub-agent finishes, summarises, and returns; the summary is what reaches the parent.

The implication is that the prompt has to be self-contained. “Continue what we were doing” does not work — the sub-agent does not know what you were doing. “Find every call site of enqueueTask, rename to scheduleTask, run pnpm test, report results” does.

Configuration#

Defining a custom sub-agent#

Custom sub-agents live under ~/.claude/agents/<name>.md (or <project>/.claude/agents/ for project-shared). Each file has YAML frontmatter and a system prompt body:

---
name: explore
description: Search-and-summarise agent for repository investigation
tools: [Read, Grep, Glob, WebFetch]
---
You are an investigation agent for a Claude Code session.
Goals:
- Use Grep, Glob, and Read to answer the user's question.
- Return a concise summary (under 200 words) plus absolute file paths.
- Do not edit files. Do not run shell commands.
Style:
- Reply with the conclusion first, then evidence.
- Cite paths absolutely. Include line numbers when relevant.

The tools allowlist restricts what the sub-agent can call. An Explore agent with no Edit/Write tools cannot accidentally modify the codebase no matter what the prompt asks.

Launching from the parent#

The Task call shape (illustrative):

{
"tool": "Task",
"subagent_type": "explore",
"description": "Find auth-related files",
"prompt": "Find every file under src/ that deals with authentication. Return absolute paths and a one-line summary of each file's role."
}

The parent gets a single response back: the sub-agent’s final message. No intermediate turns leak into the parent’s context.

Examples#

Repo-wide investigation in parallel with planning#

The parent fires an Explore Task to find every reference to an old API, and in parallel sketches a migration plan in a scratch file. By the time the parent finishes the plan, the Explore has returned its file list.

{
"tool": "Task",
"subagent_type": "explore",
"description": "Find legacy API references",
"prompt": "Find every reference to the v1 /api/users endpoint in this repo. Return absolute paths and the surrounding 3 lines for each occurrence. Do not modify any files."
}

Long refactor with isolated tool budget#

A rename across 40 files. The parent does not want to hold all 40 file contents in its context.

{
"tool": "Task",
"subagent_type": "general-purpose",
"description": "Rename enqueueTask to scheduleTask",
"prompt": "Across the entire repo, rename the symbol `enqueueTask` to `scheduleTask`. After all edits, run `pnpm test` and report whether it passes. If tests fail, show the failing assertions and stop without further changes."
}

When the Task returns, the parent sees only the summary — not the 40 Edit calls.

Multiple Tasks in parallel#

The parent can launch several Tasks in the same turn. They run concurrently in isolated contexts.

[
{ "tool": "Task", "subagent_type": "explore",
"description": "Map the auth module",
"prompt": "List all files under src/auth/. For each, give a one-line summary of its role." },
{ "tool": "Task", "subagent_type": "explore",
"description": "Map the billing module",
"prompt": "List all files under src/billing/. For each, give a one-line summary of its role." }
]

Each runs to completion; the parent gets both summaries before moving on.

Bad pattern — polling#

After firing run_in_background: true on a Bash, the model does not check on it. The system fires a notification when the command exits.

Terminal window
# BAD: do not poll after firing a background Task
sleep 5 && check-status

The correct shape is: fire, do other work, respond to the completion notification.

Gotchas#

  • The prompt has to be complete. Sub-agents do not see the parent’s history. If you write “as discussed, do X” the sub-agent has no idea what was discussed.
  • Tool allowlists are enforced. An Explore agent without Edit cannot edit even if the prompt asks it to. Match the allowlist to the agent’s job.
  • Sub-agents have their own turn budget. A very large task can exhaust the sub-agent’s budget before completing. Either break the task up in the parent first, or grant a larger budget if the agent type allows it.
  • No partial returns. A Task either finishes or hits its budget — there is no “give me what you have so far”. Plan for this when picking task size.
  • Notifications arrive between turns. The parent does not get interrupted mid-turn by a Task completion. The notification is delivered before the next user message reaches the parent’s loop.
  • Two Tasks editing the same file race. The harness does not lock. Concurrent edits to the same file from parallel Tasks produce undefined results. Partition the work or serialise it.
  • Don’t poll. This deserves its own bullet. The harness fires a notification when work completes — do not chain a polling Bash after a run_in_background: true call or a Task launch. This is a frequent enough mistake that it ends up in user-level memory in many projects.
  • The summary the sub-agent writes is all the parent sees. If the sub-agent buries the conclusion in paragraph three, the parent may misread the result. Prompts that say “lead with the conclusion” pay off.

Task vs background Bash at a glance#

Task tool
  • Runs a sub-agent in a fresh context
  • Returns the sub-agent’s final message
  • Right for “investigate”, “refactor X across many files”, “summarise this corpus”
  • Tool allowlist is the safety boundary
  • The prompt has to be self-contained
Background Bash
  • Runs a shell command without a sub-agent
  • Returns stdout/stderr/exit code
  • Right for “run the build”, “run the test suite”, “wait for a deploy”
  • Permissions allowlist is the safety boundary
  • No prompt needed — just a command
Why Task feels under-used and is usually right when in doubt

The most common reason engineers underuse Task is that the synchronous loop feels obviously productive — every turn produces a tangible result. Task feels speculative: you have to decide to delegate, write a self-contained prompt, and trust the sub-agent to come back with the right answer. The break-even is much earlier than it feels. If the work is more than a couple of minutes, or if it would otherwise add fifty unrelated file contents to the parent’s context, the delegation pays for itself the first time. Once you see the parent’s context stay clean while a refactor finishes in the background, the reflex sticks.

Search ESC

Keyboard shortcuts

Shortcuts are disabled while typing in inputs.