Overview
The Planner implements the root-level planning loop that drives the entire orchestrator. It uses an LLM to continuously generate tasks, monitors their execution, and adapts based on worker handoffs. Location:packages/orchestrator/src/planner.ts
Class: Planner
Constructor
Orchestrator configuration including LLM, git, and sandbox settings
Planner-specific config with
maxIterationsSystem prompt loaded from
prompts/root-planner.mdOptional subplanner for recursive task decomposition
Core Methods
runLoop()
The main planning loop that runs until all work is complete or max iterations reached.
User’s high-level request (e.g., “Build Minecraft according to SPEC.md”)
- Initializes Pi agent session with system prompt
- Enters iteration loop with configurable sleep interval (500ms)
- Collects completed worker handoffs
- Triggers planning when:
- First iteration (iteration === 0)
- Enough handoffs received (>= 3 since last plan)
- No active work remaining
- Dispatches tasks to workers or subplanner based on scope complexity
- Implements exponential backoff on consecutive errors (max 10)
- Waits for all active tasks to complete before exit
MIN_HANDOFFS_FOR_REPLAN = 3- Minimum handoffs before replanning- Adaptive planning allows the LLM to control batch sizing
plan()
Single planning iteration that prompts the LLM and parses task responses.
Original user request
Current repository state (file tree, commits, SPEC.md, etc.)
Worker handoffs since last planning iteration
previousFileTree- Only sends new/removed filespreviousFeaturesHash- Only includes FEATURES.json if changedpreviousDecisionsHash- Only includes DECISIONS.md if changed
injectTask()
Injects tasks directly into the dispatch pipeline without LLM planning.
Task to inject (used for conflict fixes and reconciler-generated tasks)
- Merge conflict resolution tasks from
mergeQueue.onConflict - Build/test fix tasks from
reconciler.onSweepComplete
Task Dispatch
Scope-Based Routing
Tasks are routed based on scope complexity:scope.length >= 4 files
Scope Tracking
Prevents conflicting concurrent edits:Task Retry
Failed tasks are automatically retried:Message Builders
buildInitialMessage()
Constructs the first LLM prompt with full repository context.
- User request
- SPEC.md (product specification)
- FEATURES.json (feature dependency graph)
- AGENTS.md (coding conventions)
- DECISIONS.md (architecture decisions)
- Complete file tree
- Recent commits (last 40)
buildFollowUpMessage()
Constructs incremental updates for subsequent iterations.
- File tree delta (new/removed files only)
- Recent commits
- Updated FEATURES.json (if changed)
- Updated DECISIONS.md (if changed)
- New worker handoffs with:
- Task status (complete/failed/blocked)
- Summary (max 2000 chars)
- Files changed (max 10 files)
- Concerns and suggestions
- Currently active tasks
- Merge queue health (success rate, conflicts)
- Locked file scopes
- Build/test health from reconciler