Task Decomposition Strategies
From prompts to workflows
Earlier modules covered decomposition as a technique for managing agent work: breaking large requests into smaller pieces that an agent handles sequentially. Automation workflows require a different perspective. Tasks must be decomposed not just for single-agent comprehension but for orchestration across multiple agents, handling dependencies, and aggregating results.
The shift is from "how do I structure this request?" to "how do I structure this workflow?" Single-session decomposition happens within a conversation. Workflow decomposition happens before any agent starts.
Static versus dynamic decomposition
Static decomposition defines the task breakdown before execution. Every subtask, dependency, and sequence is known upfront. The workflow proceeds through predetermined steps.
# Static decomposition in a CI/CD workflow
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm run lint
test:
runs-on: ubuntu-latest
needs: lint
steps:
- uses: actions/checkout@v4
- run: npm test
deploy:
runs-on: ubuntu-latest
needs: test
steps:
- uses: actions/checkout@v4
- run: npm run deployStatic decomposition works well for:
- Well-understood, repetitive processes
- Compliance workflows requiring auditability
- Data pipelines with fixed stages
- Any scenario where the task structure is predictable
The limitation is rigidity: static workflows cannot adapt when intermediate results reveal unexpected requirements.
Dynamic decomposition adapts the breakdown during execution. An orchestrating agent analyzes results from early tasks and spawns new subtasks accordingly.
Main agent receives: "Fix all security vulnerabilities in dependencies"
Step 1: Run security audit
→ Discovers 3 critical, 12 high, 47 medium vulnerabilities
Step 2: Dynamically decompose based on audit results
→ Subtask A: Update 3 critical packages (spawn agent)
→ Subtask B: Update 12 high packages (spawn agent)
→ Subtask C: Assess 47 medium packages for false positives (spawn agent)
Step 3: Aggregate results, identify remaining issues
→ If breaking changes detected, spawn additional compatibility subtasksDynamic decomposition works well when:
- Optimal task breakdown depends on intermediate findings
- The problem space has unknown dimensions
- Error recovery requires adaptive re-planning
The trade-off is complexity: dynamic systems require more sophisticated orchestration logic and have less predictable resource consumption.
Production systems often combine both approaches. Static decomposition handles the overall workflow structure while dynamic decomposition handles adaptation within specific phases.
The granularity problem
Decomposition improves parallelism but adds coordination overhead. Finding the right granularity is where most teams struggle.
Over-decomposition symptoms:
- Tasks finish faster than they can be coordinated
- Agents spend more time on handoffs than execution
- Subtasks lack sufficient context to operate independently
- Error rates increase as context fragments across many agents
A security audit decomposed into "check dependency A," "check dependency B," and so on for 200 dependencies creates 200 coordination points. A single agent running the full audit produces results faster with fewer failure modes.
Under-decomposition symptoms:
- Single tasks run for hours without checkpoints
- Failures require full restarts rather than partial recovery
- Parallelism opportunities go unused
- Context windows exhaust before completion
A full application migration handled as one task provides no visibility, no partial progress, and no parallel acceleration.
Calibration guidelines:
These thresholds are approximate—actual boundaries depend on task complexity and team context:
| Task complexity | Suggested subtasks | Rationale |
|---|---|---|
| Trivial (< 30 min) | None | Overhead exceeds benefit |
| Small (30 min - 2 hr) | 2-3 | Natural checkpoints |
| Medium (2-8 hr) | 4-8 | Balance parallelism and coordination |
| Large (8+ hr) | 8-15 | Need visibility and recovery points |
| Massive | Decompose into medium tasks first | Avoid single orchestration layer spanning dozens of subtasks |
Each subtask should be:
- Specific enough that the agent knows exactly what to do
- Achievable with available tools and context
- Ordered so later steps can build on earlier completions
- Independent enough that failure in one does not cascade to all
Dependency graphs
Complex workflows have task dependencies: Task B cannot start until Task A completes. Modeling these dependencies as a directed acyclic graph (DAG) enables systematic orchestration.
Why dependency graphs matter
┌─────────┐ ┌─────────┐
│ Schema │────→│ Backend │────┐
└─────────┘ └─────────┘ │
▼
┌─────────┐ ┌─────────┐ ┌─────────┐
│ Tests │────→│ Docs │ │ Deploy │
└─────────┘ └─────────┘ └─────────┘
▲
┌─────────┐ ┌─────────┐ │
│ Config │────→│Frontend │────┘
└─────────┘ └─────────┘The graph reveals:
- Parallelism opportunities: Schema and Config can run simultaneously
- Critical path: The longest dependency chain determines minimum completion time
- Failure boundaries: If Backend fails, Deploy blocks but Docs remains unaffected
Dependency types:
| Type | Description | Example |
|---|---|---|
| Data dependency | Task B requires Task A's output | API tests need API implementation |
| Control dependency | Task B cannot start until Task A completes | Deploy waits for all tests |
| Resource dependency | Tasks compete for shared resources | Database migrations serialize |
Modeling dependencies in orchestration
CrewAI uses explicit context declarations:
research_task = Task(
description="Research authentication patterns",
agent=researcher
)
implementation_task = Task(
description="Implement authentication",
agent=developer,
context=[research_task] # Explicit dependency
)Claude Code's task system uses blockedBy relationships:
Task 1: Schema migration [status: in_progress]
Task 2: API implementation [blockedBy: Task 1]
Task 3: Frontend updates [blockedBy: Task 1]
Task 4: Integration tests [blockedBy: Task 2, Task 3]When Task 1 completes, Tasks 2 and 3 unblock automatically. Task 4 waits for both.
Critical path identification
The critical path is the longest weighted path through the dependency graph. Optimizing tasks off the critical path has zero impact on total completion time.
If schema migration (2 hours) blocks backend (4 hours) which blocks deploy (1 hour), the critical path is 7 hours. Speeding up frontend work from 3 hours to 1 hour does not reduce total time—frontend is not on the critical path.
Focus optimization effort on critical path tasks. Parallelize everything else.
Sequential versus parallel execution
Not every workflow benefits from parallelism. The decision depends on task characteristics.
When to parallelize:
- Tasks have no data dependencies
- Each task has sufficient context to operate independently
- Results merge without conflicts
- Resource constraints permit concurrent execution
When to stay sequential:
- Each task depends on prior results
- Shared state would conflict under parallel access
- Debugging requires deterministic execution order
- The task naturally involves iteration and refinement
Hybrid patterns:
Most workflows combine sequential and parallel phases:
Phase 1: Research (sequential)
└── Agent explores codebase, builds understanding
Phase 2: Implementation (parallel)
├── Agent A: Backend changes
├── Agent B: Frontend changes
└── Agent C: Test updates
Phase 3: Integration (sequential)
└── Agent combines changes, resolves conflicts
Phase 4: Verification (parallel)
├── Agent A: Run unit tests
├── Agent B: Run integration tests
└── Agent C: Run security scans
Phase 5: Deploy (sequential)
└── Agent deploys to staging, then productionThe pattern alternates: converge for decisions that require unified context, then diverge for independent execution.
A useful heuristic: if you can sketch the workflow as columns rather than a single line, parallelization helps. If everything must happen in strict sequence, parallelism adds overhead without benefit.
Result aggregation
Parallel agents produce parallel outputs. The orchestration layer must aggregate these results coherently.
Fan-out/fan-in pattern:
┌── Agent A: Security audit ──┐
│ │
Orchestrator ───────┼── Agent B: Performance audit──────→ Synthesizer
│ │
└── Agent C: Style audit ─────┘The synthesizer agent receives outputs from all parallel agents and produces a unified result. Each agent writes to distinct keys in shared state; the synthesizer reads all keys.
Conflict resolution strategies:
When parallel agents produce contradictory outputs:
| Strategy | Description | Best for |
|---|---|---|
| Majority voting | Most common answer wins | Classification, yes/no decisions |
| Confidence weighting | Higher-confidence outputs dominate | Quantitative assessments |
| Human escalation | Route conflicts to developer | High-stakes decisions |
| Synthesis | Agent combines perspectives | Complementary partial answers |
In practice, majority voting provides most of the gains with minimal complexity. Ensembles larger than five to seven agents typically see diminishing returns, with diversity mattering more than count.
Quality filtering:
Before aggregation, filter agent outputs:
def aggregate_results(agent_outputs):
# Filter low-quality outputs
valid_outputs = [
output for output in agent_outputs
if output.confidence > 0.7
and output.completed_successfully
and not output.contains_errors
]
# Aggregate remaining outputs
return synthesize(valid_outputs)An output that fails validation should not contaminate the aggregated result.
Partial failure handling:
Parallel execution means some agents may fail while others succeed. Design aggregation to handle incomplete results:
- Require all: Fail the workflow if any agent fails
- Require majority: Proceed if most agents succeed
- Best effort: Use whatever results are available
- Weighted quorum: Proceed if critical agents succeed
The choice depends on task requirements. A security audit might require all checks to pass. A code review might proceed with best-effort aggregation if one reviewer agent times out.
Decomposition anti-patterns
Certain decomposition approaches reliably fail.
Vague subtasks:
# Bad decomposition
Subtask 1: Do the research
Subtask 2: Implement the feature
Subtask 3: Test itEach subtask lacks actionable specificity. Agents need concrete scope, not general direction.
Wrong ordering:
# Bad decomposition
Subtask 1: Write integration tests
Subtask 2: Define the API interface
Subtask 3: Implement the APIIntegration tests cannot be written before the interface exists. Dependencies must inform ordering.
Missing steps:
# Bad decomposition
Subtask 1: Add new endpoint
Subtask 2: Deploy to productionWhere is validation? Error handling? Documentation? Incomplete decomposition creates gaps that surface during execution.
Responsibility blending:
# Bad decomposition
Subtask 1: Generate code and tests and documentationCombining conceptually distinct tasks in one subtask prevents the separation of concerns that makes agent work reliable. Code generation, test generation, and documentation are separate tasks with different validation criteria.
Practical decomposition process
When facing a complex task:
-
Identify natural boundaries: What parts of the codebase are involved? What layers of the stack?
-
Map dependencies: Which parts must complete before others can start? Which can run in parallel?
-
Calibrate granularity: Is each subtask specific and achievable? Is the total count manageable?
-
Assign ownership: Each subtask should have clear scope that does not overlap with others.
-
Define interfaces: What does each subtask produce? What does the next subtask consume?
-
Plan for failure: How does partial completion affect the workflow? Can failed subtasks retry independently?
A 20-minute decomposition conversation that produces a clear dependency graph saves hours of debugging confused agent output later. Skip this step, and you'll spend that time anyway—just in less pleasant circumstances.