Back to blog

When to Use Claude Code Subagents vs Structured Task Breakdown

When to Use Claude Code Subagents vs Structured Task Breakdown

You have a feature that needs three things done at once. You could spawn subagents inside a single Claude Code session and let them work in parallel. Or you could split the work into three independent tasks, hand each to a separate agent in its own tmux pane, and let them run without knowing about each other.

Both approaches parallelize work. They solve different problems. Pick the wrong one and you'll either burn context window on coordination overhead or create merge conflicts that take longer to fix than the original task.

This is the decision framework I use every day while running 13 Claude Code agents on the same codebase. It's not theoretical. It's the result of getting it wrong enough times to know where the boundary sits.

Two Kinds of Parallelism

Claude Code supports two distinct ways to run work concurrently.

Subagents are child processes spawned within a single Claude Code session. The parent agent kicks off multiple subagents, each tackling a piece of the problem, then collects their results. They share the same working directory and the parent's context. Think of them as threads in a single process.

Parent agent
  ├── Subagent A: "Search lib/ for all usages of parseConfig"
  ├── Subagent B: "Search server/ for all usages of parseConfig"
  └── Subagent C: "Search components/ for all usages of parseConfig"

Separate agents run in independent Claude Code sessions, typically in separate tmux panes. Each has its own context window, its own CLAUDE.md identity file, and its own view of the codebase. They don't share memory. They communicate through artifacts: task comments, status updates, committed code. Think of them as separate processes with no shared state.

tmux pane 1: eng1 agent → "Build the REST endpoint"
tmux pane 2: eng2 agent → "Build the React component"
tmux pane 3: qa1 agent  → "Write integration tests for both"

The mental model matters because it determines how work flows between units. Subagents can pass data back to the parent cheaply. Separate agents pass data through the filesystem, git, or an external task tracker.

When Subagents Win

Use subagents when the work shares state and the results need to converge.

Parallel research. You need to search five directories for a pattern, read three documentation files, and synthesize the findings into one recommendation. Subagents can each take a search path, return results, and the parent can combine them without any serialization overhead.

Independent transformations on the same data. You're refactoring a module and need to update the type definitions, the tests, and the documentation in one coherent change. Each subagent handles one file, but the parent ensures the changes are consistent because it sees all three results before committing.

Fast exploration. You're debugging and need to check the git log, the test output, and the runtime config simultaneously. Subagents can gather all three in parallel and the parent synthesizes a diagnosis.

The pattern: fan out, gather back, act on the combined result. If your parallelism ends with the parent needing to reason about all the outputs together, subagents are the right tool.

What subagents are bad at: anything that takes more than a few minutes per branch, anything that modifies files in overlapping paths, or anything that needs independent verification. Subagents share a working directory, so two subagents writing to the same file will corrupt each other's work. And because they share context, a long-running subagent eats into the parent's available window.

When Separate Agents Win

Use separate agents when the work can be verified independently and doesn't need a shared context to make sense.

Different components of the same feature. "Build the API endpoint" and "Build the frontend that calls it" are independent until integration. The API engineer doesn't need the React component in context. The frontend engineer doesn't need the database schema. Giving each its own agent with a scoped CLAUDE.md keeps context clean and prevents one agent's complexity from bleeding into the other's work.

Different acceptance criteria. If task A is done when the endpoint returns 200 with the correct JSON shape, and task B is done when the component renders the data with proper error states, those are separate verification targets. A QA agent can validate each independently. Subagents can't be independently QA'd because they produce one combined output.

Work that touches different parts of the codebase. File ownership is the simplest way to prevent merge conflicts. Agent A owns server/, Agent B owns components/. Neither reaches into the other's territory. If you tried this with subagents, you'd need the parent to manage file locking, which defeats the purpose of parallelism.

Tasks with different time horizons. One task takes 10 minutes, the other takes 2 hours. With subagents, the parent waits for the slowest child. With separate agents, the short task completes, gets verified, and ships while the long task is still running.

The pattern: fire, forget, verify separately. If each piece of work stands alone and can be checked alone, separate agents with structured tasks are cleaner.

The Handoff Problem

The real decision point comes down to handoffs.

Subagent handoffs are cheap. The child returns data to the parent in the same context. No serialization, no file writes, no waiting for a status update. The parent spawns three subagents, they return three results, the parent has everything it needs.

Separate agent handoffs are expensive but durable. Agent A completes work, commits code, updates a task status, and comments what it did. Agent B picks up that signal (either through a coordinator or by polling the task tracker) and starts its dependent work. The overhead is real: you need a task system, a status protocol, and some way for agents to discover what other agents have done.

Here's the rule of thumb: if the work requires more than one handoff between the parallel units, use subagents. If it's a single fan-out-and-gather, subagents are simpler. If Agent A's output is Agent B's input, which becomes Agent C's input, the coordination cost of separate agents is justified because each handoff produces a verified, committed artifact that won't be lost if an agent crashes or hits a context limit.

A concrete example. You need to:

  1. Find all API endpoints that return user data
  2. Add rate limiting to each one
  3. Write tests for the new rate limits
  4. Update the API documentation

Steps 1 and 2 are tightly coupled. The search results (step 1) feed directly into the modification (step 2). A subagent handles the search; the parent applies the changes. That's a subagent pattern.

Steps 3 and 4 are independent of each other but depend on step 2. The tests need the actual endpoint code. The docs need the final API shape. These are separate tasks for separate agents, each with its own acceptance criteria, each verifiable on its own.

This is the problem Beadbox solves.

Real-time visibility into what your entire agent fleet is doing.

Try it free during the beta →

Structured Task Breakdown in Practice

When the answer is "separate agents," you need a way to decompose the feature into tasks that can run in parallel without stepping on each other.

The decomposition process:

1. Identify the dependency graph. Before splitting anything, map out what depends on what. Draw it on paper or just list it:

Feature: User profile page with activity feed

- API endpoint: GET /users/:id/profile     (no deps)
- API endpoint: GET /users/:id/activity     (no deps)
- React component: ProfileHeader            (depends on profile API)
- React component: ActivityFeed             (depends on activity API)
- Integration test: profile page end-to-end (depends on all above)

The two API endpoints have no dependencies. They can run in parallel. The two React components each depend on one API. The integration test depends on everything.

2. Draw the ownership boundaries. Each task gets a file scope. The profile API agent owns server/routes/profile.ts and server/services/profile.ts. The activity API agent owns server/routes/activity.ts and server/services/activity.ts. Neither touches the other's files. If a shared utility needs modification, one agent creates the change and the other waits for it.

3. Define the acceptance criteria per task. Each task needs a clear "done" condition that can be verified without looking at the other tasks. "Profile API returns 200 with correct shape" is verifiable. "Profile page works" is not, because it depends on integration.

4. Specify the handoff artifacts. What does a downstream agent need from an upstream agent? Usually: committed code on a known branch, a status update, and a comment describing the interface contract (API shape, component props, function signatures).

This decomposition turns a vague "build the profile page" into five discrete tasks with explicit dependencies and verification criteria. Each task can be assigned to an agent that has exactly the context it needs and nothing more.

Beads for Structured Breakdown

This is where having a real task system matters. You can't track five parallel tasks with sticky notes and terminal output.

beads is a local-first issue tracker that models this decomposition natively. An epic represents the feature. Children represent the subtasks. Dependencies prevent agents from starting work before prerequisites are done.

Here's what the breakdown looks like in practice:

# Create the epic
bd create --title "User profile page with activity feed" \
  --type epic --priority p2

# Create subtasks as children
bd create --title "GET /users/:id/profile endpoint" \
  --parent bb-epic1 --type task --priority p2

bd create --title "GET /users/:id/activity endpoint" \
  --parent bb-epic1 --type task --priority p2

bd create --title "ProfileHeader React component" \
  --parent bb-epic1 --type task --priority p2 \
  --deps bb-profile-api

bd create --title "ActivityFeed React component" \
  --parent bb-epic1 --type task --priority p2 \
  --deps bb-activity-api

bd create --title "Profile page integration test" \
  --parent bb-epic1 --type task --priority p2 \
  --deps bb-profile-header,bb-activity-feed

Now the structure is explicit. An agent running bd show bb-profile-header sees that it depends on the profile API task. If that task isn't done yet, the agent knows not to start. When the API agent finishes and marks its task complete, the frontend agent's dependency clears.

The agent workflow follows a predictable loop:

# Agent claims the task
bd update bb-profile-api --claim --actor eng1

# Agent comments its plan before writing code
bd comments add bb-profile-api --author eng1 "PLAN:
1. Create route handler at server/routes/profile.ts
2. Add service layer at server/services/profile.ts
3. Return shape: { id, name, avatar, bio, joinedAt }
4. Test: curl localhost:3000/users/1/profile returns 200"

# Agent implements, tests, commits
# ...

# Agent marks done with verification steps
bd comments add bb-profile-api --author eng1 "DONE: Profile endpoint implemented.
Returns { id, name, avatar, bio, joinedAt }.
Verified: curl returns 200 with correct shape.
Commit: abc1234"

bd update bb-profile-api --status ready_for_qa

Every step is recorded. The QA agent reads the DONE comment and knows exactly how to verify. The downstream agent reads the PLAN comment and knows the API contract before the code is even finished.

This isn't overhead for the sake of process. It's the minimum structure that prevents five parallel agents from producing five incompatible pieces of code.

Choosing by Default

After months of running parallel agents on production work, here's the decision tree I follow:

Start with subagents when:

  • The task is research or exploration (searching, reading, comparing)
  • Results need to converge into a single action
  • The total work fits inside one context window
  • There's no need for independent verification of each parallel unit

Switch to separate tasks when:

  • Different parts of the work touch different files
  • Each piece has its own acceptance criteria
  • You want QA to verify pieces independently
  • The work will take long enough that one piece might finish hours before another
  • Agents need different context (a frontend agent doesn't need database internals)

The hybrid approach for complex features: Use subagents for the research and planning phase (fan out, gather information, synthesize a plan), then break the implementation into separate tasks for independent agents. The spec-driven development workflow fits naturally here: a single agent with subagents writes the spec, then the spec decomposes into tasks for the multi-agent fleet.

Visualizing the Breakdown

Once you have five or ten structured tasks with dependencies between them, tracking progress in the terminal gets difficult. bd list shows you a flat list. It doesn't show you which tasks are blocked, which are ready to start, or how far the epic has progressed.

This is the problem Beadbox solves. It reads the same beads database and renders epic trees with progress indicators, dependency relationships, and agent assignments. You see which subtasks are done, which are blocked on prerequisites, and which are ready for an agent to pick up. The dependency graph that you specified with --deps becomes a visual map of your parallel work.

When an agent finishes a task and updates the status, Beadbox reflects the change in real time. No refresh, no re-running bd list. The tree updates, the progress bar moves, and blocked tasks become unblocked as their dependencies resolve.

It's the same data. Just visible.


If you're building workflows like this, star Beadbox on GitHub.

Try it yourself

Start with beads for the coordination layer. Add Beadbox when you need visual oversight.

Free while in beta. No account required. Your data stays local.

Share