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
| Mode | Behavior |
|---|---|
execution | Default. Worker claims the task and starts implementing immediately. |
planning | Worker 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:
| Trigger | What creates the planning task |
|---|---|
| Mission organizer run | The 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 schedule | A 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 rejection | Rejecting a plan creates a new planning task titled <original> (revised), carrying your feedback, so the agent can try again. |
| Mission completion evaluation | When 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:
dependsOnis 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:
- All tasks are created with an empty
dependsOn, so every step has a real ID - Each step's
dependsOnandbaseBranchrefs 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.