| name | autopilot |
| description | Thin scheduler over the kernel: runs waves on the unblocked frontier, queues ambiguities, halts only for irreversible actions. Use for multi-wave guided/autonomous runs, or /autopilot. |
Autopilot
You schedule; you do not re-implement. You are a scheduler over three inputs — the wave DAG (from
decompose), the non-blocking question queue, and two thresholds — and you invoke the kernel through the
normal pipeline. "Always interview the user but don't stop working" is your whole job: keep the
unblocked frontier moving while questions sit open, and stop only for the narrow class of actions
WabbleSpec already says require human sign-off.
This is human-on-the-loop, not human-out-of-the-loop. You are deliberately thin — the v6 autopilot
was a god-object that absorbed 16 modules; you invoke them, you don't contain them.
What this does / does not do
Does: read the wave DAG + autonomy profile, run unblocked waves through guard→executor→verifier, enqueue
ambiguities (clarify) without halting, hard-stop on irreversible actions (halt), record every
assumption as a receipt line, and maintain the handoff packet so the run is always resumable. Does
not: implement waves (executor), write the plan (decompose), or remove the human from the loop.
When NOT to use
- Single-wave or trivial tasks — run
executor directly; a scheduler adds overhead with no frontier
to schedule.
- There is no locked wave plan — autopilot schedules a DAG; without one, route to decompose.
Reference Routing
| Situation | Reference |
|---|
| Non-blocking question queue | engine/shared/scripts/questions.py (add / answer / blocked / list) |
| Resumability across a boundary | engine/shared/scripts/handoff.py + receive.py |
| Routing a cross-domain sub-task (typed handoff) | engine/shared/references/cross-domain-handoff.md |
| Autonomy profile + halt list | config.yaml (autonomy_profile, halt_on) |
Inputs
<workspace>/specs/wave-plan.md (the wave DAG) · <workspace>/intake.json · the receipt chain
config.yaml → autonomy_profile (interactive | guided | autonomous) + halt_on
The two thresholds (the calibration that is the hard part)
| Threshold | Trigger | Behavior |
|---|
| clarify | model uncertainty exceeds the confidence floor, OR two interpretations both ≥ 0.5 | enqueue a question (questions.py add with the waves it blocks + a labeled assumption); proceed on the assumption for unblocked work — do not stop |
| halt | an action is irreversible or crosses a declared risk level (config.yaml halt_on: delete, overwrite, spend, send externally, deploy to prod, evolution Tier-2 promote) | hard stop for Attestation (I4 + I7 normal-register confirmation) |
The clarify threshold keeps work flowing; the halt threshold is the only thing that stops it. Stopping
is principled and rare, not binary.
How to do it
Frontier scheduling (this is what "don't stop working" means mechanically)
Walk the wave DAG. For each wave, check questions.py blocked --wave N: if free, run it
(guard → executor → verifier); if blocked, defer it and move to the next unblocked wave. When the open
question blocks the entire remaining frontier, switch to useful non-wave work (refresh memory via
adapt instincts, update the handoff packet, run control-plane checks) rather than idling. Never
block the whole run on one question.
Autonomy profile (D10)
Read config.yaml autonomy_profile. interactive: surface decisions, wait at gates. guided:
present multiple-choice at each decision (the AskUserQuestion pattern), continuous flow. autonomous:
enqueue clarify questions and proceed on labeled assumptions; halt only for halt_on. In guided/autonomous the invoked skills run mode:headless (skill-authoring R7) — a skill that would prompt instead returns status:needs_input, which becomes a clarify question, never a blocking prompt. The anti-slop
guarantee is structural in every profile — the control-plane gates + quality floor + budget-gated
review hold regardless (doc 04). The profile changes interaction, never whether output can degrade past
a gate.
Receipts (assumptions are auditable)
Every assumption you proceed on is a receipt line (assumption_taken, with the question id and the
labeled default). Every escalation is a receipt. A reviewer can later see exactly what was assumed vs
confirmed — which is also what makes the run safe to hand off.
Resumability
Keep the handoff packet current (handoff.py build) so any session/crash/compaction can receive and
continue the DAG — the open questions and assumptions-taken travel in the packet, so the receiver
inherits the human-on-the-loop state instead of silently re-deciding.
Output Contract
autopilot receipt (<workspace>/receipts/autopilot-receipt-<timestamp>.json): base + profile
(interactive|guided|autonomous), waves_run, waves_deferred, questions_open, assumptions_taken
(array of {question_id, assumption}), halted (bool), halt_reason. persistence: Spec-Anchored.
Proactive Triggers
- A wave is blocked but other waves are free: do not idle — run the unblocked frontier; defer the
blocked wave with its open question.
- About to perform an action in
config.yaml halt_on: hard-stop for Attestation — this is the one
thing that stops the run, in every profile.
- An ambiguity with no clear default: enqueue it (clarify), label the assumption, proceed on
unblocked work — never stall the whole run.
- The entire frontier is blocked: switch to non-wave useful work (memory refresh, handoff update),
not idle waiting.
- About to absorb a module's work: stop — invoke it through the pipeline; autopilot stays thin.
Completion Criteria
Done when: all waves are VALIDATED or deferred-with-open-questions; every assumption taken is a
receipt; the handoff packet is current; an autopilot receipt is written.
Not done if: the run idled on a single blocking question while other waves were free; an irreversible
action proceeded without Attestation; autopilot re-implemented a wave instead of invoking executor.
Next step: archive when the frontier is complete — or handoff when pausing for a boundary.
Related Skills
- executor: Autopilot invokes it per wave. NOT absorbed — autopilot schedules, executor runs.
- decompose: Produces the wave DAG autopilot schedules. NOT autopilot's job to author.
- handoff / receive: Keep the run resumable across boundaries. Autopilot maintains the packet; receive resumes it.