Skip to content

Source Code

The runnable TypeScript source for this lesson is in lessons/15-planning/

Lesson 15: Planning & Decomposition

Breaking complex goals into manageable, dependency-tracked tasks

What You'll Learn

  1. Task Decomposition: Breaking goals into smaller tasks
  2. Dependency Graphs: Tracking which tasks depend on others
  3. Plan Validation: Detecting cycles and invalid structures
  4. Execution Ordering: Topological sorting for correct execution
  5. Progress Tracking: Monitoring plan execution

Why This Matters

Complex tasks like "refactor the authentication system" can't be done in one step. Planning enables:

  • Organization: Clear structure for complex work
  • Parallelization: Identify tasks that can run concurrently
  • Progress Tracking: Know where you are in a long task
  • Failure Recovery: Re-plan when things go wrong
  • Estimation: Better predict time and resources

Key Concepts

Plan Structure

interface Plan {
  id: string;
  goal: string;
  tasks: Task[];
  status: 'draft' | 'ready' | 'executing' | 'completed' | 'failed';
  estimatedSteps: number;
  actualSteps: number;
}

interface Task {
  id: string;
  description: string;
  status: TaskStatus;
  dependencies: string[];  // IDs of tasks that must complete first
  complexity?: number;     // 1-10 scale
  result?: TaskResult;
}

Dependency Graph

Goal: Deploy application

    +---------+
    |  Setup  |  (no deps)
    +----+----+
         |
    +----v----+
    |  Build  |  (depends on Setup)
    +----+----+
         |
    +----+----+
    |         |
+---v---+ +--v--+
| Test  | |Lint |  (both depend on Build)
+---+---+ +--+--+
    |        |
    +---+----+
        |
   +----v----+
   | Deploy  |  (depends on Test AND Lint)
   +---------+

Task Status Flow

pending -> blocked -> ready -> in_progress -> completed
                                     |
                                     +--------> failed
                                     |
                                     +--------> skipped

Files in This Lesson

File Purpose
types.ts Plan, Task, and configuration types
planner.ts Creates plans from goals
decomposer.ts Breaks tasks into subtasks
executor.ts Runs plans with dependency order
validator.ts Validates plan structure
main.ts Demonstration of all concepts

Running This Lesson

npm run lesson:15

Code Examples

Creating a Plan

import { Planner } from './planner.js';

const planner = new Planner({
  maxTasks: 20,
  validatePlans: true,
});

const plan = planner.createPlan(
  'Refactor the authentication module',
  {
    cwd: '/project',
    availableTools: ['read_file', 'write_file', 'search'],
  }
);

console.log('Tasks:', plan.tasks.length);
for (const task of plan.tasks) {
  console.log(`- ${task.description}`);
}

Decomposing Tasks

import { TaskDecomposer } from './decomposer.js';

const decomposer = new TaskDecomposer({
  strategy: 'hierarchical',
  maxSubtasks: 5,
});

const complexTask = {
  id: 'auth-1',
  description: 'Implement OAuth authentication',
  status: 'pending',
  dependencies: [],
  complexity: 8,
};

const result = decomposer.decompose(complexTask);

console.log('Strategy:', result.strategy);
for (const subtask of result.subtasks) {
  console.log(`- ${subtask.description}`);
}

Validating Plans

import { PlanValidator } from './validator.js';

const validator = new PlanValidator();
const result = validator.validate(plan);

if (!result.valid) {
  console.error('Validation errors:');
  for (const error of result.errors) {
    console.error(`  ${error.type}: ${error.message}`);
  }
}

if (result.warnings.length > 0) {
  console.warn('Warnings:', result.warnings);
}

Executing Plans

import { PlanExecutor } from './executor.js';

const executor = new PlanExecutor({
  concurrency: 2,  // Run up to 2 tasks at once
  stopOnFailure: false,
});

// Subscribe to events
executor.on((event) => {
  if (event.type === 'task.completed') {
    console.log(`Completed: ${event.taskId}`);
  }
});

// Run the plan
const taskRunner = async (task) => {
  // Your task execution logic here
  return { success: true, output: 'Done', durationMs: 100 };
};

const executed = await executor.execute(plan, taskRunner);
console.log('Status:', executed.status);

Decomposition Strategies

Sequential

Tasks must be done in order:

Analyze -> Plan -> Implement -> Test -> Review

Parallel

Independent tasks can run simultaneously:

+-- Part 1 --+
              +-- Merge Results
+-- Part 2 --+
              |
+-- Part 3 --+

Hierarchical

Complex tasks have nested subtasks:

Implement Feature
├── Analysis
|   ├── Review requirements
|   └── Identify dependencies
├── Implementation
|   ├── Write code
|   └── Add tests
└── Review
    └── Code review

Validation Checks

The validator catches:

  1. Missing Dependencies: Referencing non-existent tasks
  2. Circular Dependencies: A -> B -> C -> A
  3. Invalid Tasks: Empty IDs or descriptions
  4. Unreachable Tasks: Tasks blocked by cycles

Topological Sort

Determines valid execution order:

const sortResult = validator.topologicalSort(tasks);

if (sortResult.valid) {
  console.log('Execution order:', sortResult.order);
  // ['setup', 'config', 'build', 'test', 'deploy']
} else {
  console.log('Cycle detected:', sortResult.cycle);
}

Parallel Execution Levels

Find tasks that can run concurrently:

const levels = validator.findParallelizable(tasks);

// Level 0: [setup, config]     <- can run in parallel
// Level 1: [build]             <- must wait for level 0
// Level 2: [test, lint]        <- can run in parallel
// Level 3: [deploy]            <- must wait for level 2

Re-Planning

When a task fails, revise the plan:

if (task.status === 'failed') {
  const revisedPlan = planner.revisePlan(
    plan,
    'Task failed, adjusting approach'
  );

  // Re-execute with revised plan
  await executor.execute(revisedPlan, taskRunner);
}

Best Practices

Keep Tasks Atomic

Each task should do one thing well.

Limit Dependencies

Tasks with 5+ dependencies are often too broad.

Estimate Complexity

Helps with resource allocation and time estimation.

Plan for Failure

Include fallback tasks or alternative approaches.

Track Progress

Use events to monitor execution status.

Next Steps

In Lesson 16: Self-Reflection & Critique, we'll add the ability for agents to evaluate and improve their own output. Combined with planning, this enables:

  • Plan quality assessment
  • Automatic plan revision
  • Learning from failures
  • Continuous improvement