Agents

Planner & Orchestrator

The planner decomposes complex user requests into a directed task graph, assigns each sub-task to the most appropriate agent, executes in parallel where possible, and synthesizes results into a final response. It acts as the intelligent backbone of multi-agent workflows, removing the need to hard-code orchestration logic into individual agents.

How it works

Planning proceeds in four stages that run automatically when a goal is submitted:

  1. Decomposition — the planner agent receives the goal and produces a directed acyclic graph (DAG) of sub-tasks. Each node in the graph represents a discrete unit of work. Edges represent dependencies — a node cannot start until all its predecessors have completed.
  2. Assignment — each sub-task node is assigned to an agent. The planner uses the specialization registry first (domain-aware routing) to find the best match, then falls back to capability matching if no domain owner is registered for that topic.
  3. Parallel execution — nodes with no unsatisfied dependencies are dispatched concurrently up to the configured parallelism limit. As each node completes, its output is written to the task graph and downstream nodes are unlocked.
  4. Synthesis — once all nodes have completed (or the plan has partially completed with acceptable coverage), the designated synthesisAgent reads the full set of outputs and produces the final response delivered to the user.

Task graph

The task graph is a directed acyclic graph where:

  • Nodes are sub-tasks, each with an ID, a natural-language description, an assigned agent ID, a status (pending, running, complete, failed), and an output slot.
  • Edges are dependencies. An edge from node A to node B means B cannot start until A has completed and written its output. Outputs from completed nodes are passed as context to dependent nodes automatically.

The planner serializes the graph as JSON and stores it under the plan ID. You can inspect the full graph structure via GET /plans/:id.

Configuration

yaml
planner:
  enabled: true
  maxDepth: 4               # Maximum nesting depth of sub-task decomposition
  parallelism: 6            # Maximum concurrently executing nodes
  synthesisAgent: orchestrator  # Agent responsible for the final synthesis step
  decompositionModel: claude-3-7-sonnet-20250219  # Model used for the planning step
  timeoutMs: 300000         # Hard timeout for the entire plan (5 minutes)
  onPartialCompletion: synthesize  # synthesize | fail — what to do if some nodes fail

Invoking the planner

Submit a goal to the planner with a POST /agents/plan call. The planner runs asynchronously and immediately returns a plan ID:

bash
POST /agents/plan
{
  "goal": "Audit the payments module: check for security vulnerabilities, missing tests, and outdated dependencies",
  "context": {
    "repoPath": "/workspace/payments"
  },
  "options": {
    "parallelism": 3,        # Override config for this run
    "timeoutMs": 120000
  }
}

# Response (immediate — plan executes asynchronously)
{
  "planId": "plan_7f3a9c",
  "status": "running",
  "nodeCount": 4,
  "createdAt": "2025-11-14T10:30:00Z"
}

Monitoring a plan

Poll the plan status or subscribe to real-time progress via Server-Sent Events:

bash
# Poll plan status and full node graph
GET /plans/:id

# Subscribe to streaming SSE progress events
GET /plans/:id/stream
Accept: text/event-stream

# SSE event format:
# event: node.started
# data: { "nodeId": "n2", "agentId": "test-agent", "task": "Write missing unit tests" }

# event: node.completed
# data: { "nodeId": "n2", "durationMs": 8420, "outputPreview": "Added 12 test cases..." }

# event: plan.completed
# data: { "planId": "plan_7f3a9c", "totalDurationMs": 34100, "status": "complete" }

The SSE stream closes automatically when the plan reaches a terminal state (complete or failed). Reconnecting with the standard Last-Event-ID header replays missed events from that point.

💡The planner integrates with specialization routing for domain-aware assignment. Sub-tasks are matched to registered domain owners before falling back to generic agents, ensuring each piece of work goes to the agent best equipped to handle it. See Agent Specialization.