Some problems are embarrassingly parallel. If you need to refactor 10 independent service files to use a new base class, running them sequentially means waiting for each one before starting the next. Claude Code's multi-agent system lets you spawn subagents and run those 10 refactors simultaneously — each in its own context window, working independently, with results collected back by a parent agent.
This is one of Claude Code's most powerful and least-understood capabilities. It's also easy to misuse. This lesson covers when parallel tasks help, how the mechanics work, and how to avoid the common mistakes.
The Task tool
At the core of Claude Code's multi-agent system is the Task tool. When Claude decides to spawn a subagent, it calls Task with:
- A prompt describing what the subagent should do
- A description summarizing the task (shown in the UI)
- A list of tools the subagent has access to
- Optionally,
run_in_background: trueto not wait for completion
The subagent is a fresh Claude instance. It doesn't share the parent's conversation history — it only knows what's in the prompt you pass to it. It has its own context window, runs independently, and returns its output when done.
Foreground tasks
In foreground mode, the parent Claude waits for the subagent to complete before continuing:
Parent: "I'll refactor each service file. Starting with UserService..."
[Task tool call → spawns subagent with UserService.ts content]
[Parent waits]
[Subagent completes, returns refactored code]
Parent: "UserService done. Now PaymentService..."
Use foreground tasks when the output of one task feeds the next, or when you need sequential guarantees.
Background tasks
With run_in_background: true, the parent fires the task and immediately continues to the next one:
Parent: "I'll refactor all 5 service files in parallel."
[Spawns UserService subagent → background]
[Spawns PaymentService subagent → background]
[Spawns NotificationService subagent → background]
[Spawns AuthService subagent → background]
[Spawns ReportService subagent → background]
Parent: "All 5 tasks running. I'll collect results when they complete."
Claude can then retrieve results using the TaskOutput tool, which takes a task ID and returns the subagent's output. To cancel a running background task, use TaskStop.
When parallel tasks help
The key question: are the tasks independent? If task B depends on task A's output, you can't parallelize them. If tasks A, B, and C have no dependencies on each other, running them in parallel is almost always faster.
Good candidates for parallelism:
- Refactoring N independent files to use a new pattern
- Writing unit tests for multiple modules simultaneously
- Code review across multiple files (each file gets its own reviewer)
- Running analysis on many files (find all auth-related code, find all database calls)
- Generating documentation for multiple functions
- Running the same transformation against multiple configuration files
Stay sequential when:
- One task's output becomes another task's input
- Tasks write to shared state (same file, same database table) — concurrent writes cause conflicts
- You need a consistent view across all results before making any changes
- The tasks are short enough that the overhead of spawning subagents isn't worth it
A practical example: parallel refactor
Your team has just introduced a BaseService class with shared logging, error handling, and metrics. You need to update 5 service files to extend it. Without parallelism, this is 5 sequential Claude sessions. With the Task tool:
We need to refactor all 5 service files to extend BaseService. Here's the
BaseService definition:
[paste BaseService code]
The files to update are:
- src/services/UserService.ts
- src/services/PaymentService.ts
- src/services/NotificationService.ts
- src/services/AuthService.ts
- src/services/ReportService.ts
Run all 5 refactors in parallel. For each file:
1. Read the current file content
2. Identify what needs to change to extend BaseService
3. Make the changes, preserving all existing functionality
4. Run the TypeScript compiler on just that file to check for errors
5. Return the refactored file content and a summary of changes
Then collect all results and create a PR description summarizing the changes.
Claude spawns 5 background tasks, each with the file path and BaseService context. Each subagent reads its file, makes changes, and type-checks. The parent collects results from all 5, then synthesizes the PR description.
Total time: roughly as long as the slowest single file, rather than the sum of all 5.
Cost considerations
This is the honest part people skip: each subagent uses its own context window independently. Running 5 parallel tasks costs roughly the same as running 5 sequential tasks. You're trading money for time.
The calculation is usually worth it when:
- Your time is worth more than the token cost
- You're on a deadline and need results fast
- The tasks would otherwise require multiple sessions spread across hours
It's not worth it when:
- The tasks are short (under a few minutes each)
- You're doing exploratory work where you're not sure what you need
- The tasks have enough interdependency that coordination overhead eats the time savings
For large codebases, the economics get interesting. Refactoring 50 files sequentially might take 2 hours of clock time. Running them in 5 batches of 10 parallel tasks brings that to ~25 minutes. The token cost is the same either way — you're just compressing the time.
Coordinating outputs
The parent agent's job is to:
- Break the problem into independent subtasks
- Write clear prompts for each subagent (they have no shared context — be explicit)
- Spawn the subagents
- Collect results using TaskOutput
- Synthesize or validate the combined output
The biggest mistake I see: writing vague subagent prompts and expecting the subagent to "figure it out." Since subagents start with a fresh context, they need everything in the prompt. If your refactoring subagent needs to know the BaseService API, include it. If your test-writing subagent needs to know the testing framework and conventions, include them.
Think of it like delegating to a contractor who's never worked on your codebase. They're skilled, but they need a proper brief.
A complete multi-agent workflow
Here's a more complete example: a parent agent that reads 10 files, runs parallel analysis, and writes a summary report.
Step 1: Read all 10 controller files in src/controllers/
Step 2: For each file, spawn a background task to:
- Identify all database queries
- Flag any N+1 patterns (a query inside a loop)
- Flag any missing error handling on async calls
- Return a structured report: { file, issues: [{line, type, description}] }
Step 3: Collect all 10 reports using TaskOutput
Step 4: Aggregate into a single markdown report grouped by issue type
Step 5: Sort by severity (N+1 queries first, missing error handling second)
Step 6: Write the report to docs/code-review/database-audit.md
The parent agent handles steps 1, 3, 4, 5, and 6. The subagents handle step 2 in parallel. Each subagent gets a focused task with a clear output format — the structured JSON report makes aggregation in step 4 straightforward.
TaskOutput and TaskStop
To retrieve a background task's result:
[TaskOutput with task_id from the spawned task]
TaskOutput blocks until the task completes if it's still running, or returns immediately if it already finished. You can check multiple tasks in sequence after spawning them all.
To cancel a task that's taking too long or that you no longer need:
[TaskStop with task_id]
Cancellation is useful when you've spawned a long-running task, something changes (you got the information you needed from another task), and there's no point continuing the expensive work.
Multi-agent vs calling Claude programmatically
Claude Code's multi-agent system is for interactive sessions — you're in a terminal, driving the work, and you want Claude to parallelize parts of it automatically.
If you're building a system where agents orchestrate other agents programmatically (a pipeline, a scheduled job, a product feature), look at the multi-agent systems lesson in the AI Agents track. That covers the architecture patterns — orchestrators, subagents, how to design the communication between them — in depth.
The distinction: Claude Code's Task tool is for Claude to use during a session. Programmatic multi-agent systems are something you build and deploy. Both have their place, and they're often complementary — you might use Claude Code to write and debug the programmatic multi-agent system you're building.
Practical limits
A few things to know before going all-in on parallel tasks:
Context window is per-subagent. Each subagent has the same 200K token limit as a regular Claude instance. If you're passing large files to many subagents, you'll hit limits the same way you would in a single session.
Subagents don't talk to each other. They only communicate through the parent. If subagent A discovers something that subagent B needs to know, it returns that information, the parent receives it, and then the parent can incorporate it into a new task for B. There's no direct subagent-to-subagent channel.
Tool access is configurable. When spawning a subagent, you specify which tools it has. A review-only subagent shouldn't have Write access. A file-analysis subagent might only need Read, Glob, and Grep. Limiting tools limits blast radius if something goes wrong.
Parallelism doesn't speed up everything. If the bottleneck is a single step that everything else depends on (reading a large file, running a slow test suite), parallelizing the downstream steps gives you no benefit until that bottleneck resolves. Profile where time is actually being spent before reaching for parallelism.
The Task tool is a force multiplier when used well. Start with a clear decomposition of independent subtasks, write explicit subagent prompts, and collect results thoughtfully. The time savings on large codebase tasks are real — I've seen 10x wall-clock speedups on the right problems.