Skip to main content

How Kiwi decomposes a task into parallel agent workers

The Planner is the Control Plane component (pkg/planner) that turns a high-level task into a DAG of worker specs, persists it as an immutable manifest, and enqueues one unit of work per worker onto the lease queue.

From a task to a plan

You submit a PlanRequest — a task description, a repo URL and ref, an optional target file (or files), the worker model, and a test command that defines "done". The Planner asks a frontier model to decompose that task into a Plan:

// pkg/planner/planner.go
type Plan struct {
Summary string // one-line description of the whole plan
Workers []PlannedWorker // the DAG nodes
}

type PlannedWorker struct {
ID string // node id, unique within the plan
Task string // the natural-language goal for this worker
File string // target file this worker edits
Files []string // optional: multiple target files
Model string // the model this worker runs on (customer's key)
TestCmd string // per-worker "definition of done" (optional)
DependsOn []string // ids of workers that must SUCCEED first
}

Two seams keep this flexible:

  • The Planner interface has two implementations: a deterministic HeuristicPlanner (used by default and in tests) and a frontier-model-backed LLMPlanner (production). Both produce the same Plan shape.
  • The planner model that does the decomposition is distinct from the worker model that does the edits. The planner runs on the Control Plane's own planning key; the workers run on your provider key. An optional planner_model overrides the decomposition model, falling back to the platform default when empty.

What a worker spec contains

Each planned worker is expanded into a worker-spec payload — the self-contained unit a daemon leases and executes:

FieldMeaning
id<job_id>-<worker_id> — the queued task id
taskthe worker's natural-language goal
job_taskthe original top-level task (for context)
file / filesthe target file(s) to edit
modelthe worker model (runs on the customer's key)
test_cmdthe command that must pass — the definition of done
depends_onids of sibling workers that must SUCCEED first
repo_url / refwhere to get the code
job_idlinks the worker back to its job and manifest

The test_cmd resolves per-worker first, then falls back to the plan-wide command from the request. If neither is set, the daemon cannot run a verifying loop for that worker.

Decomposition flow

The manifest is immutable and content-addressed

Once the Planner produces a Plan, the service canonicalizes the task, repo, ref, summary, and workers into a JSON document and hashes it with SHA-256 — that hash is the manifest id. The manifest and all of its worker tasks are then written in a single database transaction: if any worker fails to enqueue, the manifest is rolled back too, so there are never partial plans. Submissions can be made idempotent with an Idempotency-Key header, which dedupes retried submissions to the same job.

Shared context (opt-in)

At submit time the planner can optionally draw on your org's prior jobs so related work informs the new decomposition:

  • Auto — semantic nearest-neighbour over past jobs using pgvector embeddings.
  • Manual — you pick specific prior jobs to reference.

It is off by default, strictly org-scoped (you can only ever reference your own jobs), and injected at plan time only. Auto mode may use extra tokens for the embedding lookup.

Next: DAGs — what the depends_on edges buy you, and how they are scheduled.