Ultradocket
The docket is the portfolio layer above single-plan execution. It never
authors plans — ultrapowers:ultrawrite does, interactively, with the operator. The
docket decides which issues are worth planning, holds their state between
sessions, and reasons about the approved plans as a set.
First run: objectives
If docs/objectives.md does not exist, interview the operator (ten minutes,
brainstorm-style) and write it: what the business is optimizing for this
quarter, in plain English. Triage scores against whatever it currently says.
It is a versioned doc the operator edits freely.
Mode: triage (bare /ultradocket)
A READ-ONLY discovery pass — it mutates nothing. Fan out over gh issue list and the repository. Skip every issue
carrying a wayfinder:* label — those are wayfinder decision tickets
(questions resolved by a decision, worked through their map), not build
issues; sweeping one into an implementation plan builds an answer to an
unresolved question. For each remaining open, well-defined issue, score
well-definedness, alignment to docs/objectives.md,
estimated blast radius (likely files), and risk; cluster duplicates and
shared root causes. Write the ranked slate to docs/superpowers/docket.md
using the entry format below, every entry State: triaged. Then present the
docket gate: the operator strikes, reorders, and sets a budget ceiling;
accepted entries become State: accepted.
Record each entry's triage rationale in the durable **Notes:** field (it
survives every lifecycle transition, unlike free text packed into the Score
line). Triage assigns no verification disposition at all: how a plan is verified
is the plan's own business, and every plan is verified the same way — by the
suite the run records. There is nothing to guess here.
Entry format (parsed by scripts/docket_lib.py — the single source of truth):
### #214: Stripe webhooks dropped on retry
**State:** accepted
**Score:** 8.5 — revenue-reliability objective
**Est-files:** services/billing/*, lib/webhooks.py
**Notes:** triage rationale — durable, survives transitions (e.g. "already fixed in main, verify & close")
**Plan:** docs/superpowers/plans/2026-06-14-stripe-webhook-retry.md
docket_lib still parses a **Seal:** field and round-trips whatever it finds
there — compile_docket no longer validates it (#612) — but do not write
one. The subsystem it named was cut in One Driver Phase 0 and nothing
downstream reads the field. Deleting the residual machinery is #386.
Lifecycle: triaged → accepted → planned → queued → executed → verified; any
non-terminal state → parked. Transitions go through docket_lib.transition,
never hand-edited prose.
Mode: plan (/ultradocket plan) — the continuous sweep
Bare /ultradocket plan is a continuous sweep: it drains the entire
accepted queue through back-to-back, pre-seeded brainstorms, in docket-rank
order, until the queue is empty or the operator stops. There is no single-issue
form — the sweep is the only planning entry point. Throughput is capped by
operator attention here, by design; everything downstream of the operator's
signature runs at machine speed in the drain (run mode).
One iteration:
- Pop the highest-rank
acceptedentry. - Pre-seed a standard
superpowers:brainstormingsession with the issue body, the triage notes, and the matched line(s) ofdocs/objectives.md. A well-defined issue is half a spec, so the interview is short. - Plan through the normal pipeline: brainstorm →
ultrapowers:ultrawrite(the one owned authoring skill since #390) → operator approval. Per-plan approval is the default contract: the sweep pauses at each plan for the operator's signature before advancing — plan approval is the operator's control point, and they should never have to interrupt mid-sweep to reclaim it ([92e1c33dd33a3f12]). Batching approvals across entries is an explicit operator opt-in only. When the operator asks the sweep to "review it for me", summarize the plan against the issue's stated scope and any standing scope cuts, flag every deviation, and still take an explicit per-plan yes. A plan the sweep writes carries no verification-disposition line at all: the compiler stopped reading one, and the drain's gate is the suite result the run records.compile_plan.py --checkis still the pipeline's own step, and it must printPLAN OK. - Choose the engine. Apply the shared execution-fit rubric — the same
one the routing hook and ultrawrite use (pinned by
tests/test_recommendation_rubric.py) — to the finished marked plan, and record the chosen engine. Do not restate the rubric's branch clauses here; reference it. The value is one ofultrapowers | subagent-driven | inline. - Write back in one atomic entry update — plan path and engine —
advancing the entry
accepted → planned → queuedviadocket_lib.transition(plannedis the approved intermediate; the entry advances straight toqueued). Never hand-edit the docket prose. - Auto-advance to the next
acceptedentry.
The sweep loops until no accepted entry remains or the operator stops. Docket
state is durable, so a sweep may span sittings freely: stopping is simply not
continuing; resuming re-reads the remaining accepted entries. No new
persistence mechanism is introduced.
In-sweep controls, offered at each iteration boundary:
- continue — the default; plan the next entry.
- skip-park — park this entry with a reason (covers both "I don't want to
build this" and "this issue is underspecified / needs decomposition") via
docket_lib.transition(→parked), then continue. - stop — end the sweep here; the remaining
acceptedentries are untouched and picked up on the next/ultradocket plan.
Mode: run (/ultradocket run) — the autonomous build drain
/ultradocket run executes the queued plans. It is the machine-speed back
half of the docket: the operator kicks it off and walks away, and every plan's
outcome lands at a single end gate. main is never touched unattended.
The drain is this agent loop — not a headless workflow — because two of the
three engines are superpowers skills that run in the loop. It owns a docket
integration branch ultra/docket-<stamp> and walks the queued entries in
docket-rank order (the order compile_docket emits). For each entry, run one
executor-agnostic wrapper:
- Branch off the current docket integration line HEAD.
- Dispatch by the entry's recorded
Engine, auto-advancing any human-in-the-loop checkpoint (see "The exam-gated auto-approve" below):ultrapowers→ commit the plan on the docket line, thennode fleet/drive-one.mjs <plan.md> <runId>on the orchestrator (fleet/RUNBOOK.md§Live W1 run). Since 0.3.0 the sandbox runsfleet/run-main.mjs— a deterministic driver, gate included. There is no LLM engine session to invoke and no--engineflag to pass; One Driver is the only path. The orchestrator's PR/receipt is the gate, so step 3 reads that receipt instead of administering a second gate, and step 4 merges or parks on its verdict.subagent-driven→ invokesuperpowers:subagent-driven-developmentagainst the per-plan branch.inline→ invokesuperpowers:executing-plansagainst the per-plan branch.
- Read the correctness gate for the plan's branch. There is one gate and no
dispatch on a per-plan disposition: the committed suite (
python3 -m pytest) run on that branch, in a clone of its own so the verdict is agnostic to the current checkout, and its exit code is the authority — exit 0 ⇒ pass. For a fleet-driven entry the run has already recorded that verdict, so read it off the gate receipt rather than administering a second one; for a sequential executor, run the suite on the branch yourself. This is the whole gate for ultrapowers' own engine/skill/doc work, which authors no held-out exam, and the engine sims are inside it, because they live infleet/tests/and ride the pytest suite (issue #79's concern, now covered by construction). A branch with no recorded suite verdict is unverified work: park it for the operator at the end gate rather than auto-merging. - Merge or park — the deterministic step:
- Green gate → run
scripts/merge_entry.py --repo <repo> --branch <plan-branch> --docket docs/superpowers/docket.md --issue <n>. It is the only merge path: one command does the dirty-checkout refusal, the merge, the ancestry verification (git mergeexit 0 ANDgit merge-base --is-ancestor <plan-branch> HEAD— exit code alone is not authority), and thequeued → executedtransition, and it commits the docket write on the integration line; it parks with the reason named on every other outcome. Exit 0 ⇒ merged; 1 ⇒ parked and recorded; 2 ⇒ refused or errored with git and the docket untouched. Never merge and transition as two steps (#252: a docket that claimedexecutedafter a merge that had failed on a dirty checkout). The next plan branches off the new HEAD. - Red gate or executor failure → park: keep the branch, transition the
entry to
parkedwith a reason (the gate'sredKindor the failure), and skip the plan's collision-dependents (fromcompile_docket's collision graph). Disjoint plans continue. - Missing/uncompilable Plan →
compile_docket/plan_writesraises a friendly error naming the plan; park that entry with the reason before spending execution cost. Never surface a raw stack trace.
- Green gate → run
- Auto-advance to the next
queuedentry. Stop on an empty queue or an operator-set budget ceiling (a stop condition between plans where cost is observable; v1 builds no new cost accounting).
Review posture: suite-gate authority, review by exception. The drain
dispatches no per-task reviewer of its own, and its step-2 dispatch
instructs the sequential executor to skip its review passes — per-task
and final — the step-3 gate is the verification. One exception: each task
its plan marks **Review:** peer (from launch_waves[].review
of step 3's own compile_plan run — no extra compile) gets one fresh
review via superpowers:requesting-code-review against the diff from
docket-line HEAD plus the plan text, before the plan's gate;
Critical/Important findings park the entry exactly as a red gate does
(Minor: noted at the end gate). Posture drift after this declaration is
the recurrence that buys enforcement.
The gate-driven auto-approve
The drain runs unattended over non-deterministic executors, so the keep-going decision is split from the correctness decision, and the merge keys stay on the deterministic side:
- Auto-advance, don't block. When a sequential executor reaches a checkpoint that would normally ask the operator to review, advance it yourself — log the call for the end gate — so the run never blocks. This is catastrophe-only autonomy: only a dependency cycle or an inability to create the integration branch stops the drain early.
- Trust the gate, not "looks done." A "finished" signal from a non-deterministic executor is never enough to merge. Correctness is decided by the recorded suite result on the branch (exit-code authority) — for a fleet-driven entry, the one on the orchestrator's gate receipt: exit 0 ⇒ merge; any non-zero ⇒ park. An over-eager auto-advance therefore cannot land broken work on the integration line — the gate it can't touch gates the merge.
The drain widens the set of trusted write-side executors to include the
committed superpowers executors (subagent-driven-development,
executing-plans) alongside the fleet driver (fleet/run-main.mjs; the
waves registry harness it replaced was deleted at 0.3.0). Those are fixed,
audited skills — not orchestration improvised at runtime — and the safety
guarantee holds regardless of which one wrote a branch: nothing reaches the
docket integration line, or main, without clearing the deterministic suite
gate and the single end gate.
The single end gate
When the queue drains or the budget ceiling hits, present one pre-merge
portfolio gate. Per entry: the recorded suite verdict and its output, engine,
cost, outcome (executed/merged or parked + reason), branch, the review
posture used (suite-gate authority, or the escalated tasks named); plus
portfolio totals and the could-have-parallelized projection. Then the operator
disposes of the portfolio: merge the docket integration line to base, or open
per-issue PRs (mind the GitHub closing-keyword gotcha in PR bodies). Accepting
the portfolio advances merged entries executed → verified. Parked entries are
presented with their gate evidence; a re-drive is a new run with a narrower
plan — there is no in-place salvage or redirect.
The drain is origin-agnostic: the entry issue field is an opaque label,
and any gh issue close / comment-back is an optional operator post-step you
offer at the gate — never part of the drain core, which makes no GitHub calls.