Skip to main content

Overview

The PlannerWorkerSwarm implements a planner-worker-judge architecture for parallel multi-agent task execution. Based on Cursor’s “Scaling long-running autonomous coding” research, it separates planning from execution: a planner decomposes goals into prioritized tasks, worker agents claim and execute tasks concurrently from a shared queue, and a judge evaluates the cycle results. The swarm follows a cycle-based workflow:
  1. Planning: A planner agent decomposes the goal into concrete, prioritized tasks with dependencies
  2. Execution: Worker agents independently claim tasks from a shared queue and execute them concurrently via ThreadPoolExecutor — no worker-to-worker coordination
  3. Evaluation: A judge agent evaluates the combined results and decides: complete, fill gaps, or fresh start
  4. Iteration: If not complete, the planner receives judge feedback and produces new tasks for the next cycle

Installation

Attributes

str
default:"PlannerWorkerSwarm"
Name identifier for this swarm instance
str
default:"A planner-worker execution swarm"
Description of the swarm’s purpose
List[Union[Agent, Callable]]
required
Worker agents that execute tasks. Must not be empty.
int
default:"1"
Maximum planner-worker-judge cycles (must be greater than 0)
str
default:"gpt-5.4"
Model for the planner agent
str
default:"gpt-5.4"
Model for the judge agent
int
default:"1"
Max recursive sub-planner depth. 1 = no sub-planners; 2 = CRITICAL tasks are decomposed once.
Optional[float]
default:"None"
Max seconds for the entire worker pool per cycle
Optional[float]
default:"None"
Max seconds per individual task execution
Optional[int]
default:"None"
Max concurrent worker threads. Defaults to min(len(agents), os.cpu_count()).
OutputType
default:"dict-all-except-first"
Format for the final result
bool
default:"False"
Whether to save conversation history
bool
default:"False"
Enable verbose logging
Raises:

Methods

run()

Executes the planner-worker-judge cycle up to max_loops times or until the judge declares the goal complete.
Parameters:
  • task (str): The goal to accomplish
  • img (str, optional): Optional image input
Returns: Formatted conversation history per output_type Raises:
  • ValueError: If task is not provided

get_status()

Returns a structured status report of the swarm and its task queue.
Returns: Status dict with name, original_task, and queue (containing total, progress, status_counts, and per-task details)

Usage Examples

Quick Start

Multi-Cycle with Judge Feedback

Set max_loops > 1 so the judge can request additional planning cycles when the goal is not yet achieved:
The judge evaluates each cycle:
  • Cycle 1: Judge finds gaps (“missing regional analysis”) — planner creates targeted tasks
  • Cycle 2: Judge finds remaining issues (“outlook section too shallow”) — planner fills gaps
  • Cycle 3: Judge marks complete with quality 9/10

Recursive Sub-Planners

Set max_planner_depth > 1 to automatically decompose CRITICAL-priority tasks via sub-planner agents:
When the top-level planner produces a CRITICAL task (e.g., “Design the database schema and API endpoints”), it gets cancelled and replaced by the sub-planner’s more granular subtasks.

Timeouts

  • worker_timeout: Total wall time for the worker pool per cycle. Workers stop claiming new tasks after this deadline.
  • task_timeout: Per-task execution limit. If exceeded, the task fails with a TimeoutError and may be retried.

Checking Swarm Status

SwarmRouter Integration

PlannerWorkerSwarm is available as a swarm type in SwarmRouter:

Architecture

Design Principles (from the Cursor blog)

Task State Machine

Cycle Flow

How It Works

Planner Agent: Created internally each cycle. Uses structured output (PlannerTaskSpec) to produce a plan narrative and a list of concrete tasks with title, description, priority (0-3), and dependency titles. On subsequent cycles, the planner receives the judge’s feedback (gaps + follow-up instructions) appended to the original task. Worker Execution: Each worker runs in a ThreadPoolExecutor thread, independently claiming tasks from a shared TaskQueue. Workers never coordinate with each other. Each worker loop: claims a task, resets agent memory, builds context (WORKER_SYSTEM_PROMPT + task description + dependency results), executes via agent.run(), and marks the task complete or failed. Optimistic concurrency: every task has a version field. State transitions check the expected version — if another worker modified the task, the operation is rejected. This avoids lock-based coordination problems (deadlocks, forgotten releases). Claim priority: highest priority first, then oldest first, with dependency satisfaction required. Judge Agent: Created internally after workers complete. Evaluates the cycle results and produces a CycleVerdict:

Fresh Start vs Gap Fill

Schemas

PlannerTask

Represents a single task in the shared queue.

TaskPriority

Best Practices

Error Handling

Performance Considerations

Source Code

View the source code on GitHub