buildd
Features

Planning Mode

How planning tasks are created, how plans are returned, and how they become child tasks

Planning Mode

A task in planning mode does not write code. It investigates, returns a structured plan, and then waits for that plan to be approved — at which point Buildd materializes the plan's steps into child execution tasks.

Task Modes

ModeBehavior
executionDefault. Worker claims the task and starts implementing immediately.
planningWorker investigates, returns a plan as structured output, then stops. Approval creates the child tasks that do the work.

mode is a task column whose only values are execution and planning, and it defaults to execution.

How Planning Tasks Get Created

You cannot create a planning task directly, by either public write path. POST /api/tasks accepts a mode field in the request body but never reads it — it hardcodes mode: 'execution' on insert, so passing "mode": "planning" is silently ignored. The MCP create_task action is stricter: mode is absent from its parameter allowlist, so passing it fails loudly with Unknown create_task parameter(s): mode.

Planning tasks are created by the orchestration layer instead. These are the paths that produce one:

TriggerWhat creates the planning task
Mission organizer runThe most common path by far. An auto mission plans its next step as soon as work finishes, and also when a dependency lands, it is resumed or its budget raised, one of its PRs merges, or you add a note or answer a question. Auto-start and the dashboard Run button do the same. Each run opens a planning task to decide what work the mission needs next.
Mission scheduleA mission's schedule writes a task template with mode: 'planning'. For a mission with check-ins, a tick materializes it only when the mission looks stuck. For a recurring mission with check-ins off, every tick does.
Plan rejectionRejecting a plan creates a new planning task titled <original> (revised), carrying your feedback, so the agent can try again.
Mission completion evaluationWhen a planning cycle asserts the mission is complete but the deterministic completion check refuses, Buildd opens an independent Evaluate mission completion: <title> planning task to adjudicate.

So in practice: to get planning behaviour, create a mission, and let its organizer cycle plan. See Missions.

A database constraint allows at most one in-flight planning task per mission (a partial unique index over non-terminal planning rows), so a mission cannot accumulate competing planning cycles. Completed and failed planning tasks do not block the next cycle.

Workflow

1. Worker Claims the Task

The worker claims a planning-mode task like any other task. The mode is included in the claim response, and the runner uses it to request structured output.

2. Worker Returns a Plan as Structured Output

The plan must come back as validated JSON in the task's structured output, not as markdown the agent prints. The runner automatically constrains every planning task to the planning schema, and the plan is submitted with complete_task:

buildd action=complete_task params={
  summary: "Plan for consolidating auth middleware",
  structuredOutput: {
    plan: [
      {
        ref: "extract",
        title: "Extract auth logic into shared middleware",
        description: "Move the per-route auth checks into lib/auth.ts. Runs in a fresh session with no memory of this plan, so state everything needed.",
        outputRequirement: "pr_required"
      },
      {
        ref: "adopt",
        title: "Update API routes to use the middleware",
        description: "Replace the inline checks in each route handler with the shared middleware.",
        dependsOn: ["extract"],
        outputRequirement: "pr_required"
      }
    ],
    summary: "Extract first, then adopt across routes.",
    missionComplete: false
  }
}

plan, summary and missionComplete are required. Each step requires ref, title and description, and may also set dependsOn, baseBranch, roleSlug, outputRequirement, priority, kind and complexity.

Two things are worth calling out:

  • dependsOn is load-bearing. A step you leave undeclared is treated as independent and becomes claimable immediately, so it can run at the same time as the step it actually needed. The agent then finds no PR and the attempt is wasted.
  • A planning task that completes without structured output is force-failed. The server rejects it with "the plan was not returned as validated JSON, so no child tasks could be created" rather than completing a task that produced nothing actionable.

update_progress also accepts a plan parameter, but that is only a progress-log milestone for the dashboard timeline. It does not produce a reviewable plan and does not gate anything.

3. The Plan Is Reviewed

A planning task that has completed is awaiting review. There is no dedicated status for this — the review state is derived from the pair (mode = 'planning', status = 'completed'), which the dashboard surfaces as the plan_review phase. Both approve and reject reject anything that is not in exactly that state.

Dashboard — Plan Review Panel

The task detail page displays a Plan Review Panel showing each proposed step with its ref, title, description, dependencies, and required capabilities:

  • Approve Plan — creates child execution tasks from the plan steps, with dependencies wired automatically
  • Reject Plan — opens a feedback form; submitting creates a new planning task with the feedback attached for the agent to revise

API

# Approve
curl -X POST https://buildd.dev/api/tasks/{id}/approve-plan \
  -H "Authorization: Bearer bld_xxx"

# Reject
curl -X POST https://buildd.dev/api/tasks/{id}/reject-plan \
  -H "Authorization: Bearer bld_xxx" \
  -H "Content-Type: application/json" \
  -d '{ "feedback": "Add error handling for the edge cases" }'

MCP (admin)

buildd action=approve_plan params={ taskId: "..." }
buildd action=reject_plan params={ taskId: "...", feedback: "Add tests" }

4. Child Tasks Execute

On approval, Buildd creates one child task per plan step using a two-pass approach:

  1. All tasks are created with an empty dependsOn, so every step has a real ID
  2. Each step's dependsOn and baseBranch refs are resolved to those IDs and branch names

Child tasks inherit each step's priority, outputRequirement, roleSlug and baseBranch. They are always created in execution mode — plan steps have no mode of their own, so approving a plan never produces another planning task. Workers claim and execute them like any other task, with dependency blocking enforced automatically.

5. Auto-Aggregation

When all child tasks of a planning parent complete, Buildd automatically creates an Aggregate results: <parent title> task so a worker can collect the children's results into a final summary or deliverable. The aggregation task itself runs in execution mode. Duplicate aggregation tasks are prevented — only one is created per planning parent.

Steering a Running Worker

You cannot ask an already-running worker to switch into planning mode. What you can do is steer it mid-flight with an admin message:

buildd action=send_agent_message params={
  taskId: "...",
  message: "Stop implementing and write up your intended approach in the task notes first"
}

See Worker Instructions for delivery semantics and the urgent path.

On this page