Skip to main content
Module 2: Multi-Agent 1 / 6
Intermediate Session 7 Task Graph Dependencies

Task Graph & Dependencies

Learn how Claude Code coordinates multiple tasks with dependency edges, enabling complex workflows.

March 20, 2026 18 min read

What You’ll Learn

In Session 3, you learned how TodoWrite creates flat task lists. But real projects aren’t flat — tasks depend on each other. You can’t write integration tests before the API exists, and you can’t deploy before the tests pass.

By the end of this session, you’ll understand:

  • How tasks form a Directed Acyclic Graph (DAG) with dependency edges
  • How Claude Code resolves which tasks can run in parallel vs. sequentially
  • The graph traversal algorithm for executing tasks in the right order
  • How to structure prompts that produce well-formed dependency graphs

The Problem

A flat task list looks like this:

□ Create database migration
□ Add API routes
□ Create auth middleware
□ Write integration tests
□ Update the frontend

The AI works through these sequentially, top to bottom. But this misses critical information:

  1. Wasted sequentiality — “Create database migration” and “Add API routes” could run in parallel, but a flat list forces them to be sequential
  2. Incorrect ordering — Nothing prevents “Write integration tests” from running before the API routes exist
  3. Cascading failures — If “Create auth middleware” fails, the AI doesn’t know which downstream tasks are now blocked

These problems multiply as task lists grow. A 15-task implementation plan with hidden dependencies is a recipe for backtracking and wasted context.

How It Works

Tasks as a DAG

When Claude Code plans complex work, tasks naturally form a Directed Acyclic Graph. Each task is a node, and dependency relationships are edges:

                ┌──────────────┐
                │  Analyze     │
                │  Requirements│
                └──────┬───────┘

              ┌────────┴────────┐
              │                 │
              ▼                 ▼
     ┌────────────────┐  ┌────────────────┐
     │  DB Migration  │  │  Route Handlers│
     │  (users table) │  │  (auth routes) │
     └────────┬───────┘  └────────┬───────┘
              │                   │
              └────────┬──────────┘


              ┌────────────────┐
              │  Auth          │
              │  Middleware    │
              └────────┬───────┘

              ┌────────┴────────┐
              │                 │
              ▼                 ▼
     ┌────────────────┐  ┌────────────────┐
     │  Integration   │  │  Update        │
     │  Tests         │  │  Frontend      │
     └────────────────┘  └────────────────┘

In this graph:

  • DB Migration and Route Handlers are independent — they can run in parallel
  • Auth Middleware depends on both — it can’t start until both are complete
  • Integration Tests and Update Frontend depend on Auth Middleware but not on each other

Dependency Edges

Each task carries two relationship fields:

Task: "Auth Middleware"
  status: pending
  blockedBy: ["DB Migration", "Route Handlers"]
  blocks: ["Integration Tests", "Update Frontend"]

These edges encode the full graph:

FieldMeaning
blockedByTasks that must complete before this one can start
blocksTasks that cannot start until this one completes

The blockedBy / blocks relationship is symmetric — if Task A blocks Task B, then Task B is blocked by Task A.

Graph Traversal Algorithm

Claude Code traverses the task graph with a simple but effective algorithm:

REPEAT:
  1. Scan all tasks
  2. Find tasks where:
     - status = "pending"
     - ALL blockedBy tasks have status = "completed"
  3. These are "ready" tasks -- execute them
     (If multiple tasks are ready, run in parallel)
  4. Mark completed tasks
  5. Check: did completing these unlock new tasks?
  6. If no tasks remain, DONE

Here’s the algorithm visualized across time:

Time ──────────────────────────────────────────────►

Round 1:  [Analyze Requirements]
          status: pending → in_progress → completed

Round 2:  [DB Migration]────────┐  (parallel)
          [Route Handlers]──────┘

Round 3:  [Auth Middleware]
          (unlocked because both blockers completed)

Round 4:  [Integration Tests]───┐  (parallel)
          [Update Frontend]─────┘

DONE ✓

Four rounds instead of six sequential steps. The graph reveals that two rounds can run tasks in parallel, cutting total execution time.

How the AI Builds the Graph

When you ask Claude Code for a complex feature, it analyzes the natural dependencies between subtasks. The planning phase looks like this:

User: "Add authentication to the Express app"

AI internal reasoning:
  "I need to break this down. Let me think about what
   depends on what..."

  1. Analyze requirements → nothing depends on, everything starts here
  2. DB migration (users table) → needs requirements analysis
  3. Route handlers (login/signup) → needs requirements analysis
  4. Auth middleware (JWT validation) → needs both DB and routes
  5. Tests → needs middleware
  6. Frontend login page → needs middleware

TodoWrite output:
  Task 1: Analyze requirements          blockedBy: []
  Task 2: Create users table migration  blockedBy: [1]
  Task 3: Create auth route handlers    blockedBy: [1]
  Task 4: Implement auth middleware     blockedBy: [2, 3]
  Task 5: Write integration tests       blockedBy: [4]
  Task 6: Update frontend with login    blockedBy: [4]

The key is that Tasks 2 and 3 share the same blocker (Task 1) but don’t block each other. The AI recognizes they’re independent and can run concurrently.

Parallel Execution with Subagents

When multiple tasks become ready simultaneously, Claude Code can delegate them to parallel subagents:

Round 2 — Two tasks ready:

  Parent Agent

    ├──► Subagent A: "Create users table migration"
    │    └── Works in isolated context

    └──► Subagent B: "Create auth route handlers"
         └── Works in isolated context

  Both return results → Parent continues to Round 3

This combines two concepts from the course: the task graph identifies parallelizable work, and subagents (Session 4) provide the isolated contexts to execute them.

Key Insight

Task graphs let the AI do more work per turn by identifying parallelizable subtasks. Without a graph, the AI processes tasks one-by-one in a linear sequence. With a graph, it can batch independent tasks and execute them concurrently.

But the deeper insight is about correctness, not just speed. A flat task list has no way to express “don’t start this until that finishes.” The dependency graph makes ordering constraints explicit, preventing the AI from writing tests against code that doesn’t exist yet, or integrating a middleware before its dependencies are ready.

Think of it like a build system. make doesn’t compile files randomly — it reads the dependency graph, builds leaves first, and works its way up. Claude Code’s task graph works the same way. And just like make -j4 can parallelize independent compilation units, Claude Code can parallelize independent tasks.

Hands-On Example

Structuring Prompts for Good Dependency Graphs

You can guide Claude Code to produce well-structured task graphs by being explicit about the relationships in your prompt:

Add a notification system to the app. Break it into tasks
with clear dependencies:

Phase 1 (no dependencies):
  - Design the notification data model
  - Research WebSocket libraries

Phase 2 (depends on Phase 1):
  - Create notifications table migration
  - Set up WebSocket server

Phase 3 (depends on Phase 2):
  - Build notification API endpoints
  - Implement real-time push via WebSocket

Phase 4 (depends on Phase 3):
  - Create frontend notification component
  - Write end-to-end tests

Use TodoWrite with blockedBy edges. Run parallel tasks
where possible.

Recognizing Dependency Patterns

Common dependency patterns you’ll encounter:

Linear Chain:        Fan-Out:           Fan-In:
A → B → C           A → B              D ←─ A
                     A → C              D ←─ B
                     A → D              D ←─ C

Diamond:             Independent:
    A                A    B    C
   / \               (no edges)
  B   C
   \ /
    D

The diamond pattern is the most common in real projects. One analysis task fans out to parallel implementation tasks, which converge on an integration task.

Handling Failures in the Graph

When a task fails, its downstream dependents are blocked:

Before failure:
  ✓ Analyze requirements
  → DB Migration (in progress)
  → Route Handlers (in progress)
  □ Auth Middleware (blocked by 2, 3)

DB Migration fails:
  ✓ Analyze requirements
  ✗ DB Migration (FAILED)
  ✓ Route Handlers
  ⊘ Auth Middleware (BLOCKED — dependency failed)

Recovery:
  The AI diagnoses the failure, fixes the migration,
  re-runs it, and then Auth Middleware becomes unblocked.

The graph makes the blast radius of a failure visible. Without it, the AI might try to proceed with Auth Middleware and encounter cryptic errors because the database table doesn’t exist.

Reading the Graph at a Glance

During execution, the task list becomes a live dashboard:

Task Graph Status:
  ✓ [1] Analyze requirements
  ✓ [2] Create users table migration
  ✓ [3] Create auth route handlers
  → [4] Implement auth middleware      (blockedBy: 2✓, 3✓)
  □ [5] Write integration tests        (blockedBy: 4)
  □ [6] Update frontend with login     (blockedBy: 4)

Progress: 3/6 tasks completed | 1 in progress | 2 blocked
Next parallel batch: [5, 6] when [4] completes

What Changed

Flat Task ListTask Graph with Dependencies
Sequential execution onlyParallel execution of independent tasks
No ordering guaranteesExplicit dependency edges prevent wrong order
Failure blocks everythingFailure blocks only downstream dependents
No progress visibility beyond current taskFull graph shows what’s done, running, and waiting
AI must remember ordering in contextDependencies encoded in data, survive compaction
One task at a timeMultiple subagents on independent tasks

Next Session

Session 8 covers Background Tasks — how Claude Code launches long-running operations (builds, test suites, deployments) in the background and continues productive work while waiting for results.