wdi-method 0.6.6 → 0.6.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,375 +1,383 @@
1
- ---
2
- name: wdi-autopilot
3
- description: Use when the owner wants the agent to carry the product from where it stands to every FR delivered, without being asked a question in between. Two doors — a preflight that ends in one mandate the owner accepts, then unattended iterations fired by a loop, each working as far as it safely can. One run, one branch, one PR. Every decision the agent takes lands in one ledger the owner reviews in parallel, never as a prompt.
4
- ---
5
-
6
- # WDI Autopilot
7
-
8
- The method spends owner time at five gates. This skill spends it at **two points instead**: one **mandate**
9
- before the work, one **review of the result** after it. Between them the agent decides, records, and keeps
10
- going. Nothing else in the method changes — the same skills write the same documents, the same validators
11
- hold, the same panel reviews the code. What changes is who answers when a skill would otherwise stop and ask.
12
-
13
- **Three doors**, and the mandate row in `decisions.yaml` picks which:
14
-
15
- | Door | When | Does | Asks |
16
- |---|---|---|---|
17
- | **Preflight** | **No mandate row exists at all**, and the owner asked for one in this turn | Checks everything, prints one page, waits for the owner's confirmation, writes the mandate, starts the loop | Yes — this is the only place this skill MAY ask |
18
- | **Iteration** | A mandate at `accepted` whose `expires` has not passed | Reads the registry and the ledger's `## Resume`, works from where the last iteration stopped for as long as it safely can, records, returns only at one of three stops | **Never** |
19
- | **Finish, lapsed** | A mandate at `accepted` whose `expires` **has** passed | Goes straight to § Finish, marks the run lapsed, cancels the loop | **Never** |
20
-
21
- **A run MUST NOT write itself a mandate.** Preflight is reachable only when the owner asked for it in the
22
- turn that is running; a loop firing MUST NOT open it, whatever the mandate's state. Without that, an expired
23
- mandate would put the next firing back at preflight — where the defaults are already filled in and nobody is
24
- awake to refuse them — and the run would renew its own authority. The lapsed door exists precisely so the
25
- expiry ends the run instead of restarting it.
26
-
27
- Typing `/wdi-autopilot` while a mandate is active opens the iteration door, not the preflight. To change a
28
- setting, the owner supersedes the mandate with a new one — `wdi-decision` owns supersession.
29
-
30
- ## Door 1 — Preflight
31
-
32
- Run every check, then print **one page**. A check that fails is printed with what fixes it; the page MUST
33
- NOT start the loop while any row in the first two groups is red.
34
-
35
- ### What is checked
36
-
37
- | Group | Row | Red when |
38
- |---|---|---|
39
- | **Engines** | BMad installed; every `wdi-*` skill the run will call present | A wrapper is missing — name it and `npx wdi-method update` |
40
- | | `to-spec` · `to-tickets` · `implement` found, with the **path** of each `SKILL.md` | Not found. Name the two install paths `wdi-build` names |
41
- | | A route past `disable-model-invocation` see below | Neither route is available |
42
- | | The tracker the engines publish to is configured `docs/agents/issue-tracker.md`, written once by `/setup-matt-pocock-skills` | Missing. `to-tickets` would stop to ask for it, and this skill never asks; the owner runs the setup before confirming |
43
- | | Reviewers separate from the builder can be dispatched | The session cannot spawn a second agent and any touched component is `risk_accepted: low` Step 3 of `wdi-build` would block |
44
- | | `.constitution/project/codebase-stack-guide.md` names build and test commands, **and the test command exits 0 here** | Absent or failing. Every ticket's "full suite green once" and the smoke test read it. Found at minute one, not at hour six |
45
- | | The remote accepts the run branch `git push --dry-run` and `main` is reachable as a PR base | Auth or remote failure. The first real push is at the first spec close, hours in |
46
- | | A CI workflow is configured | None. Step 5 would wait for checks that never arrive; say so and read Step 2's own runs as the evidence instead |
47
- | **Position** | `gates_passed` in `index.yaml`, `g4_passed` per component, validators green (`validate.py`) | A red validator. Name it; autopilot MUST NOT start on a corpus already red |
48
- | | An isolated worktree | A shared checkout. `wdi-build` refuses one, so this skill refuses earlier |
49
- | | `from_gate` the first gate the run will hold itself | Below the last passed gate. Default: the gate after the last one passed |
50
- | **Settings** | `scope` the `FR` ids to deliver, or `all` | (default `all` open `FR`) |
51
- | | `parked` — what stops for the owner instead of being decided: any of `promise` · `ad-n` · `sensitive` | (default **`ad-n`**, and nothing else. `decision-guide.md` says narrowing an invariant MUST NOT be softened further, so removing it is the owner's to say out loud — not a default they never saw) |
52
- | | `smoke_test` — `agent` or `owner` | — (default `agent`, and **`owner` when `codebase-stack-guide.md` names no way to run the app** — an agent cannot smoke-test what it cannot launch) |
53
- | | `loop` — the interval between iterations | — (default `5m`) |
54
- | | `expires` — the date the mandate lapses | — (default 7 days from today; a `/loop` task expires then too) |
55
- | | Where the ledger and the final report will be written | — |
56
- | | The **run branch** `autopilot/<mandate-id>`, using the next free `DEC-` id from `decisions.yaml`, which the mandate then takesand that the run will open **one** PR from it | The branch already exists with commits nobody can account for |
57
- | **Runtime** | The session runs with permission prompts bypassed | Cannot be verified from inside the session. Printed as a line the owner confirms |
58
-
59
- **Every row arrives with its default already in it**, and the owner changes only what they want changed
60
- the same rule the installer follows. A preflight that asks fourteen questions one at a time has failed.
61
-
62
- ### The route past `disable-model-invocation`
63
-
64
- The three engines carry `disable-model-invocation: true`. That flag blocks the Skill tool — for this session
65
- and for every subagent — and no setting lifts it. It does **not** block reading the file. Two routes exist,
66
- and preflight names which one it found:
67
-
68
- | Route | How | Trade |
69
- |---|---|---|
70
- | **Read and follow** preferred | The builder brief says: *read `<path>/SKILL.md` and carry out its process*. The engine's rules arrive whole; only the trigger changed | Nothing in the plugin is touched; the author's updates still arrive |
71
- | **Copy into the repo** | `npx skills@latest add mattpocock/skills` copies the skills under the repo's skill folder; the flag is removed from the three copies, and the project skill `/to-spec` coexists with the plugin's namespaced one | The copies stop receiving the author's updates |
72
-
73
- The `to-tickets` quiz granularity and blocking edges is **answered by this skill**: ticket count from the
74
- size table in `delivery-flow-guide.md`, edges from `depends_on` and `touches`. Each answer is one ledger row.
75
-
76
- ### Confirmation becomes the mandate
77
-
78
- On the owner's confirmation, and not before:
79
-
80
- 1. Open a `DEC-` through `wdi-decision`, `type: mandate`, at `status: accepted`. `accepted_by` names the
81
- owner a person and a date, the way `risk_accepted_by` does. **Ask for that name here if the repo does
82
- not already carry it**, because it is the one thing the run cannot invent later and every person-and-date
83
- field it writes will need it. **The mandate is the one `DEC-` that MUST
84
- NOT be accepted by delegation** (`mandate-accept`). Its parameters — `from_gate` · `scope` · `parked` ·
85
- `smoke_test` · `loop` · `expires` live **only** on its row in `decisions.yaml`; the file carries
86
- Decision, Why, and Cost, and points at the row. One fact, one home.
87
- 2. Write the ledger header see § The ledger.
88
- 3. Start the loop. In Claude Code, invoke the `loop` skill with `<interval> /wdi-autopilot`. Where that is
89
- not available, print the command for the owner to type, and name the alternative the platform has:
90
-
91
- ```
92
- /loop 5m /wdi-autopilot
93
- ```
94
-
95
- The interval is the **pause between** iterations, not the length of one. An iteration that outlives it
96
- finishes first; the next firing waits.
97
-
98
- ## Door 2 — One iteration
99
-
100
- Open with three reads, in this order:
101
-
102
- 1. `validate.py --generate`. `.control/generated/` is written by that flag and nothing else, so without it
103
- every iteration reads a status file from before the run and re-holds gates that already passed. It sweeps
104
- the validators for free at the same time.
105
- 2. **Reconcile `## Resume` against git.** Compare the run branch HEAD with the commit Resume names. A
106
- difference is work that landed before the last iteration died — rebuild Resume from what git shows
107
- **before** starting anything new. Trusting a stale Resume is how a merged ticket gets implemented twice.
108
-
109
- **A ledger with no `## Resume` heading at all is the same case, one step further back.** It is a
110
- pre-0.6.2 ledger a flat table with nothing else and `update` only ever renames the file, never
111
- restructures its content, because that restructuring needs exactly this read. Heal it once, here,
112
- before touching anything else: wrap the existing table under a `## Decisions` heading if it is not
113
- already, then **build a fresh `## Resume`** the same way as a stale one above — from the mandate row,
114
- `.control/generated/status`, and the run branch's actual HEAD, never from the table's last row read as
115
- prose. The table's own rows are untouched; only the missing head is added.
116
- 3. `.control/generated/status`, the mandate row, and **the ledger's `## Resume` only** see § The ledger
117
- for why that is a section and not a file.
118
-
119
- Then work § The work table
120
- **from the top, for as long as the work can be done safely** — not one row and return. The loop is a safety
121
- net that restarts a run that died, not the pacer of one that is alive; an iteration that stops after one step
122
- while work remains turns a five-minute interval into five minutes of waiting per step.
123
-
124
- An iteration returns at exactly **three stops**, and names which:
125
-
126
- | Stop | Means |
127
- |---|---|
128
- | **Done** | Every `FR` in scope is closed, or nothing left is **runnable** — every remaining row is parked or blocked. Go to § Finish |
129
- | **Capacity** | The session's context is near its limit, or a dispatched step cannot be spawned here. The ledger's last row is a boundary the next firing resumes from. **The same capacity reason twice in a row is recorded under Blocked instead** — the next firing is the same session on the same machine, so a spawn that is unavailable now is unavailable then, and retrying it is the spin this design exists to prevent |
130
- | **Blocked** | A step failed at its cap — two return trips in `wdi-build`, a third failed fix — and is recorded under **Blocked** in `## Resume`. The next firing takes the next **runnable** row, never this one again |
131
-
132
- **Runnable** means: not listed under Blocked in `## Resume`, and not parked by the mandate. A blocked row is
133
- retried only when the owner unblocks it or a later change removes the causeand the ledger row that
134
- recorded the block says which. A run that re-picks a blocked step spends the whole mandate window on it, and
135
- that is the one stall this design has to prevent.
136
-
137
- The ledger is what makes the next firing continue rather than restart, so every step boundary lands there
138
- **before** the next step starts.
139
-
140
- ### The work table where the run picks up
141
-
142
- | The registry says | Do |
143
- |---|---|
144
- | `from_gate` is G1 and no brief | `wdi-problem`. Then **hold G1**: answer its ★ questions in the ledger, record `G1` in `gates_passed` |
145
- | G1 passed, no PRD for the scope | `wdi-product` intent `prd` `wdi-ux` first where the interface is the promise. Hold G2 the same way |
146
- | G2 passed, no components | `wdi-init` intents `component` · `mode` · `risk`. Each `mode` and `risk_accepted` is a ledger row with its reason |
147
- | Components, no catalogue or spine | `wdi-blueprint` `catalog`, then `platform`. Hold G3 |
148
- | G3 passed, a component above `catalog` lacks depth | `wdi-component`. Hold G4 for that component; set `g4_passed` |
149
- | G4 clear for a candidate row | `wdi-report` intent `estimate`, pick the top candidate row, `wdi-build` for it — **unattended branch** |
150
- | A spec is open | Continue `wdi-build` from its next phase or ticket. The frontier is read from the tickets |
151
- | A spec just closed | `wdi-reconcile` over the gate scope; carry every drift finding to its owning skill in one edit pass |
152
- | Every `FR` in scope closed | § Finish |
153
- | Work remains but **nothing is runnable** all of it parked or blocked | § Finish, with the run marked **incomplete** and each blocker named |
154
- | `expires` passed | § Finish, with the run marked lapsed |
155
-
156
- **Holding a gate here means answering its checklist, not skipping it.** Every question is answered in the
157
- ledger, `yes` or `change`; a `change` is acted on in the same iteration. The questions a validator answers
158
- are answered by the validator, never re-derived.
159
-
160
- ### Faster is allowed; unsafe is not
161
-
162
- Everything that shortens the run without changing what it produces is in scope: dispatching a step to a
163
- subagent, running the review panel while the next ticket's tests are being written, building tickets with no
164
- blocking edge between them at once, holding G3 for several components in one pass. Four limits, all already
165
- the method's, and none of them relaxes here:
166
-
167
- - **`wdi-build` § Parallel tickets sets the conditions** each concurrent builder in its own worktree,
168
- `parallel-tickets-blocked` green for every pair released together, the shape-setting ticket closed first, no shared registry
169
- write in flight. The coordinator holds every registry write and every merge into the run branch, serially.
170
- - **Specs run in parallel only where `depends_on` says they may.** A wide refactor's batches never do.
171
- - **Every step is judged from the artifact**, never from a builder's report — the same rule, whoever runs
172
- the step. A step whose reviewer is also its builder is a self-report and does not count.
173
- - **Nothing lands on the run branch red.** A ticket merges into it only with its tests green and the full
174
- suite green once; a merge that turns the branch red is reverted, not patched forward. **Reverting a merge
175
- leaves the branch counted as merged**, so re-merging the same branch brings back nothing: the ticket
176
- returns to `ready-for-agent` and its redo lands on a **new** branch cut from the revert.
177
- - **A spec MUST NOT close while the run branch's last pushed head is red.** That is a **Blocked** row, not a
178
- follow-up. Closing over red carries the failure forward, and every later ticket's local "full suite green
179
- once" hides it behind a suite that was never the branch's.
180
-
181
- ### One run, one branch, one PR
182
-
183
- A mandate is **one unit of work**, and it reaches `main` through **one door**: a single PR from the run
184
- branch, which the **owner** merges after the final review. This is what makes the result reviewable as a
185
- whole instead of as a stream of PRs nobody read.
186
-
187
- **The rule is about how the run ENDS, not how it works.** During the run, branches and worktrees are tools
188
- and MAY be used freely a worktree per parallel builder, a branch per ticket, a throwaway branch to try a
189
- migration. What MUST NOT happen is that any of them survive: every working branch is merged into the run
190
- branch by the coordinator and deleted, and **only the run branch is ever pushed**. The end state is one
191
- branch, one PR, nothing else on the remote.
192
-
193
- | In `wdi-build` | Under a mandate |
194
- |---|---|
195
- | Step 4 pushes a ticket branch and opens a PR per ticket | The ticket is committed to the run branch directly, or merged in from its own worktree by the coordinator. The ticket-closing checklist is still answered first. **No PR per ticket** |
196
- | Step 5 watches CI per PR | The coordinator pushes the run branch **at every spec close**; the first push opens the one PR as a **draft**; CI is watched per push, on the pushed head SHA, and judged exactly as Step 5 says |
197
- | `MUST NOT merge` | Holds harder. The run never merges to `main`; the owner does, once, after § Finish |
198
-
199
- A second PR is a red flag. Where a change cannot ride the run branch — a hotfix `main` needs today — it is
200
- reported for the owner, not opened by the run.
201
-
202
-
203
- ### What the agent decides, and what it does with the answer
204
-
205
- | Would have asked the owner | Under a mandate |
206
- |---|---|
207
- | A gate checklist | Answered and recorded, as above |
208
- | Seams, testing decisions, the `to-tickets` quiz | Decided; one ledger row each |
209
- | An `owner` row in `wdi-question` | Answered with a default, filed in `assumptions.md` with its cost and `under: DEC-<mandate>`, closed in `answered.md` in the same pass. **A row whose owner is the client or a stakeholder is treated as parked** — `wdi-question` says it is never the agent's, mandate or not, and the mandate came from the owner so it cannot delegate what was never theirs |
210
- | Code right, document wrong (`wdi-build` § When the code turns out to be right) | Decided; the owning skill edits in the present tense; one ledger row naming the promise that moved |
211
- | A `DEC-` to accept | Accepted with `accepted_by: DEC-<mandate>`, then applied in the same pass |
212
- | Drift with a clear right side | Carried to the owning skill |
213
- | A conflict with no right side | A `DEC-`, accepted by delegation |
214
- | Anything in `parked` | **Not decided.** One row in the final report's parked list; the `FR` it holds is skipped and the run moves to the next |
215
-
216
- Three things the mandate MUST NOT reach, whatever `parked` says: a guard, a test, or an assertion edited to
217
- turn something green; a ticket's `satisfies` amended to make a must-fix go away; a builder editing `.what/`,
218
- `.how/`, or an `applied` `DEC-`. `wdi-build` owns all three and this skill adds no exception.
219
-
220
- ### Recording is not optional here
221
-
222
- Under supervision a decision nobody recorded is normal, because the owner was in the room. Here the owner
223
- was not, so **every decision this skill takes for them is a ledger row** — that is the whole price of the
224
- mandate. The `DEC-` threshold in `decision-guide.md` still decides which of them also become a `DEC-`; the
225
- ledger decides nothing and records everything.
226
-
227
- ### How the owner stops it
228
-
229
- Stated on the preflight page, because a run nobody can stop is not a run anybody should start.
230
-
231
- | To | Do | Effect |
232
- |---|---|---|
233
- | Pause | Cancel the loop, or interrupt the session | The current iteration finishes its step and lands its ledger row. Nothing is left half-written |
234
- | Resume | `/wdi-autopilot` again, or start the loop again | The mandate is still active, so it comes in through the iteration door and continues from `## Resume` |
235
- | End it for good | Supersede the mandate through `wdi-decision`, or let `expires` pass | **Cancelling the loop does NOT revoke the mandate.** Until it is superseded or lapses, any later firing resumes the run |
236
-
237
- ## The ledger
238
-
239
- `.control/memlog/autopilot-<mandate-id>.md` `autopilot-DEC-014.md` one per mandate, **named for the
240
- mandate and not for the day** (`mandate-accept` looks for it there), because two mandates can share a date and appending the second run's
241
- decisions to the first run's ledger destroys both as a record. A memlog is a run log — *which skill ran, and
242
- what it decided while running* — and this is exactly one. `memlog-home` holds it where every memlog lives.
243
-
244
- Frontmatter `artifact:` names the mandate's `DEC-` file — `memlog-home` demands it of every memlog.
245
-
246
- **It has two readers who want opposite things, and that is what shapes it.** The next iteration needs a
247
- resume point: where the last one stopped and what to do now. The owner needs every decision, with what it
248
- cost. Serving both from one flat table is what made a real ledger reach 41 KB by its twenty-second
249
- iteration and every iteration after that paid to re-read decisions that were spent.
250
-
251
- So the file has a head that is **overwritten** and a body that is **appended**, and only the head is read
252
- while the run is alive:
253
-
254
- ```
255
- ## Resume <- rewritten every iteration. THIS is what an iteration loads.
256
- ## Decisions <- appended, never rewritten. The owner's, and grepped by id when a past decision is needed.
257
- ```
258
-
259
- ### `## Resume` — the only part an iteration reads
260
-
261
- Read it, and nothing below it:
262
-
263
- ```bash
264
- sed -n '1,/^## Decisions/p' .control/memlog/autopilot-<mandate-id>.md
265
- ```
266
-
267
- Rewritten **in the same commit as the work it describes** — not at the end of the iteration, because an
268
- iteration that dies between the two leaves Resume pointing at work that already landed. The **coordinator is
269
- the ledger's only writer**; a dispatched step returns its rows rather than appending them, so two builders in
270
- two worktrees can never both rewrite this block. It holds **only what no registry answers**:
271
-
272
- | Line | Holds |
273
- |---|---|
274
- | Iteration | The number, and the commit that is its boundary |
275
- | Run branch | The branch, and whether the one PR is open yet |
276
- | Stopped at | Which of the three stops ended the last iteration, in a clause |
277
- | Blocked | Each blocked step and what it hit its cap on, one line each, or `—` |
278
- | Parked | Each mandate-parked row and the `FR` it holds, one line each, or `—` |
279
- | Next | The next runnable step, one line |
280
-
281
- **It MUST NOT restate a decision**, and it MUST NOT repeat what `specs.yaml`, a ticket's own status, or
282
- `.control/generated/status` already answers. Position and intent live here; everything else is read from the
283
- registry that owns it. A Resume block that starts summarising decisions is a second home for them, and it is
284
- the copy that goes stale.
285
-
286
- ### `## Decisions` one line per cell
287
-
288
- | Column | Holds |
289
- |---|---|
290
- | When | Iteration number and commit |
291
- | Where | The skill and step that would have asked |
292
- | Decided | One sentence, present tense |
293
- | Instead of | The alternative that lost, one line, or `—` |
294
- | Cost if wrong | One line. `one setting changes` is a valid answer and a short one |
295
- | Landed in | The files edited, or the `DEC-` / `OQ-` id |
296
-
297
- **One line per cell is the rule, not a target.** What does not fit — a gate checklist answered question by
298
- question, a panel finding adjudicated at length goes to a companion document at
299
- `.control/memlog/autopilot-<mandate-id>/<NN>-<slug>.md`, and the row keeps a pointer to it. This is
300
- `wdi-question`'s rule for a question that outgrows one line, borrowed whole rather than reinvented.
301
-
302
- A row MUST NOT carry the derivation that produced the decisionwhich files were read, which clause was
303
- weighed. `decision-guide.md` forbids exactly that in a `DEC-`, and a ledger row is the shorter form of the
304
- same thing.
305
-
306
- The owner MAY read the whole file at any time while the loop runs. **Reading it never pauses the run**;
307
- disagreeing with a row is a new `DEC-` that supersedes, opened through `wdi-decision`, and the next iteration
308
- applies it.
309
-
310
- ## Finish
311
-
312
- When § The work table reaches § Finish:
313
-
314
- 1. **Smoke test.** At `smoke_test: agent`: run the application with the commands
315
- `.constitution/project/codebase-stack-guide.md` names, exercise every closed `FR`'s proof of done from
316
- the PRD, record pass or fail per `FR` in the ledger. At `owner`: run nothing; the test script below is
317
- the whole deliverable.
318
- 2. `validate.py --generate`, then `wdi-report` intent `progress`.
319
- 3. Raise the mandate to `applied`, `touches` naming the ledger, and rewrite `## Resume` one last time so it
320
- reads as the run's end state rather than a step that never came.
321
- 4. **Leave the run branch in a state the owner can merge.** A ticket still in flight is either finished or
322
- its merge reverted — the branch is never handed over half-applied. Then push, wait for CI to conclude on
323
- that head SHA, and mark the one PR **ready for review** *only if it is green*. Red keeps the PR a
324
- **draft** and is reported red: a PR marked ready is an invitation to merge, and the run MUST NOT extend
325
- one over a red branch, nor patch to turn it green at the door.
326
- 5. Cancel the loop: in Claude Code, the `loop` skill's cancel; elsewhere, tell the owner the loop has nothing
327
- left to do.
328
- 6. Write the final report as the Output below. The owner merges; the run never does.
329
-
330
- ## Red Flags STOP
331
-
332
- - Asking the owner anything through the iteration door
333
- - Starting the loop before the mandate is `accepted`, or on a red validator
334
- - **Opening preflight from a loop firing, or writing a mandate the owner did not confirm in this turn**
335
- - Treating an expired mandate as a reason to start over rather than to finish
336
- - Closing a spec, or marking the PR ready, while the last pushed head is red
337
- - Re-merging a branch whose merge was reverted, instead of cutting a new one
338
- - A mandate accepted by delegation, or with no `expires`
339
- - Deciding something the mandate parks, or parking something the mandate did not
340
- - A decision taken and not written to the ledger
341
- - A pre-0.6.2 ledger left un-healed no `## Resume` wrapped and rebuilt on first touch
342
- - Reading the whole ledger when the run is alive `## Resume` is what an iteration loads
343
- - A `## Resume` that restates a decision, or repeats what the registry already answers
344
- - A ledger cell longer than a line, instead of a pointer to a companion document
345
- - Restarting from the first row instead of reading `## Resume`
346
- - Re-picking a step `## Resume` lists as blocked, instead of taking the next runnable row
347
- - Spinning until `expires` on work that is not runnable, instead of finishing and naming the blockers
348
- - Returning after one step while work remains and none of the three stops applies
349
- - A second PR, any branch but the run branch pushed, a working branch left alive at Finish, or any merge
350
- into `main` by the run working branches and worktrees during the run are fine; surviving ones are not
351
- - Merging a red ticket into the run branch, or patching the branch forward instead of reverting the merge
352
- - Marking the PR ready over red CI, or handing over a run branch with a ticket half-applied
353
- - Parallel builders sharing a worktree, or a registry written by anyone but the coordinator
354
- - Claiming a Skill-tool invocation of `to-spec`, `to-tickets`, or `implement` the route is read-and-follow
355
- or a repo copy, and the ledger names which
356
- - Editing a guard, a test, or an assertion to go green no mandate reaches that
357
- - Answering a question a validator already answered
358
-
359
- ## Output
360
-
361
- Preflight: the one page, then the mandate id and the loop command actually issued.
362
-
363
- Iteration: the steps taken in order, the ledger rows added, which of the three stops ended it and why, and
364
- what the next firing will find.
365
-
366
- Finish, following the Agent Rules `Answer Closing` block and carrying:
367
-
368
- - **what was done** — the one PR, its branch and head SHA, and CI's verdict on it; every `FR` closed, with
369
- its spec; the smoke test result per `FR`, or the words *not run, by mandate*; the ledger path and its row
370
- count
371
- - **what blocked it** the parked list, each with the `FR` it holds and the decision the owner owes;
372
- anything left red; whether the run lapsed at `expires`
373
- - **what comes next** — **the test script**: for every closed `FR`, its proof of done from the PRD as one
374
- step the owner performs; then every follow-up `wdi-build` recorded, and the plan-versus-code inventory
375
- differences
1
+ ---
2
+ name: wdi-autopilot
3
+ description: Use when the owner wants the agent to carry the product from where it stands to every FR delivered, without being asked a question in between. Two doors — a preflight that ends in one mandate the owner accepts, then unattended iterations fired by a loop, each working as far as it safely can. One run, one branch, one PR. Every decision the agent takes lands in one ledger the owner reviews in parallel, never as a prompt.
4
+ ---
5
+
6
+ # WDI Autopilot
7
+
8
+ The method spends owner time at five gates. This skill spends it at **two points instead**: one **mandate**
9
+ before the work, one **review of the result** after it. Between them the agent decides, records, and keeps
10
+ going. Nothing else in the method changes — the same skills write the same documents, the same validators
11
+ hold, the same panel reviews the code. What changes is who answers when a skill would otherwise stop and ask.
12
+
13
+ **Three doors**, and the mandate row in `decisions.yaml` picks which:
14
+
15
+ | Door | When | Does | Asks |
16
+ |---|---|---|---|
17
+ | **Preflight** | **No mandate row exists at all**, and the owner asked for one in this turn | Checks everything, prints one page, waits for the owner's confirmation, writes the mandate, starts the loop | Yes — this is the only place this skill MAY ask |
18
+ | **Iteration** | A mandate at `accepted` whose `expires` has not passed | Reads the registry and the ledger's `## Resume`, works from where the last iteration stopped for as long as it safely can, records, returns only at one of three stops | **Never** |
19
+ | **Finish, lapsed** | A mandate at `accepted` whose `expires` **has** passed | Goes straight to § Finish, marks the run lapsed, cancels the loop | **Never** |
20
+
21
+ **A run MUST NOT write itself a mandate.** Preflight is reachable only when the owner asked for it in the
22
+ turn that is running; a loop firing MUST NOT open it, whatever the mandate's state. Without that, an expired
23
+ mandate would put the next firing back at preflight — where the defaults are already filled in and nobody is
24
+ awake to refuse them — and the run would renew its own authority. The lapsed door exists precisely so the
25
+ expiry ends the run instead of restarting it.
26
+
27
+ Typing `/wdi-autopilot` while a mandate is active opens the iteration door, not the preflight. To change a
28
+ setting, the owner supersedes the mandate with a new one — `wdi-decision` owns supersession.
29
+
30
+ ## Door 1 — Preflight
31
+
32
+ Run every check, then print **one page**. A check that fails is printed with what fixes it; the page MUST
33
+ NOT start the loop while any row in the first two groups is red.
34
+
35
+ ### What is checked
36
+
37
+ | Group | Row | Red when |
38
+ |---|---|---|
39
+ | **Engines** | BMad installed; every `wdi-*` skill the run will call present | A wrapper is missing — name it and `npx wdi-method update` |
40
+ | | All six engines present IN this repo — `to-spec` · `to-tickets` · `implement` · `tdd` · `code-review` · `domain-modeling` — with the **path** of each `SKILL.md` | Any missing. `npx skills@latest add mattpocock/skills`; a user-level plugin does not count |
41
+ | | The three flagged engines are **invocable**: no `disable-model-invocation` in the repo's copies | Any still flagged no skill can invoke it, so Phase 2 would stall. `npx wdi-method engines --fix`, or the `wdi-init` / `wdi-upgrade` skill |
42
+ | | The retired BMad G5 wrappers are locked out of model invocation, and `.claude/settings.json` denies them | Any still invocable. Same fix BMad's installer restores its wrappers whenever it runs |
43
+ | | This skill and `wdi-build` are themselves invocable no `skillOverrides` entry in `settings.json` set to `off` or `user-invocable-only` | Either is overridden. Nothing else can start the loop, and the override is silent |
44
+ | | The tracker the engines publish to is configured `docs/agents/issue-tracker.md`, written once by `/setup-matt-pocock-skills` | Missing. `to-tickets` would stop to ask for it, and this skill never asks; the owner runs the setup before confirming |
45
+ | | Reviewers separate from the builder can be dispatched | The session cannot spawn a second agent and any touched component is `risk_accepted: low` Step 3 of `wdi-build` would block |
46
+ | | `.constitution/project/codebase-stack-guide.md` names build and test commands, **and the test command exits 0 here** | Absent or failing. Every ticket's "full suite green once" and the smoke test read it. Found at minute one, not at hour six |
47
+ | | The remote accepts the run branch — `git push --dry-run` — and `main` is reachable as a PR base | Auth or remote failure. The first real push is at the first spec close, hours in |
48
+ | | A CI workflow is configured | None. Step 5 would wait for checks that never arrive; say so and read Step 2's own runs as the evidence instead |
49
+ | **Position** | `gates_passed` in `index.yaml`, `g4_passed` per component, validators green (`validate.py`) | A red validator. Name it; autopilot MUST NOT start on a corpus already red |
50
+ | | An isolated worktree | A shared checkout. `wdi-build` refuses one, so this skill refuses earlier |
51
+ | | `from_gate` — the first gate the run will hold itself | Below the last passed gate. Default: the gate after the last one passed |
52
+ | **Settings** | `scope` — the `FR` ids to deliver, or `all` | — (default `all` open `FR`) |
53
+ | | `parked` — what stops for the owner instead of being decided: any of `promise` · `ad-n` · `sensitive` | — (default **`ad-n`**, and nothing else. `decision-guide.md` says narrowing an invariant MUST NOT be softened further, so removing it is the owner's to say out loud — not a default they never saw) |
54
+ | | `smoke_test` — `agent` or `owner` | — (default `agent`, and **`owner` when `codebase-stack-guide.md` names no way to run the app** — an agent cannot smoke-test what it cannot launch) |
55
+ | | `loop` the interval between iterations | — (default `5m`) |
56
+ | | `expires` — the date the mandate lapses |(default 7 days from today; a `/loop` task expires then too) |
57
+ | | Where the ledger and the final report will be written | |
58
+ | | The **run branch** — `autopilot/<mandate-id>`, using the next free `DEC-` id from `decisions.yaml`, which the mandate then takes — and that the run will open **one** PR from it | The branch already exists with commits nobody can account for |
59
+ | **Runtime** | The session runs with permission prompts bypassed | Cannot be verified from inside the session. Printed as a line the owner confirms |
60
+
61
+ **Every row arrives with its default already in it**, and the owner changes only what they want changed —
62
+ the same rule the installer follows. A preflight that asks fourteen questions one at a time has failed.
63
+
64
+ ### The engines are invoked there is no route to find
65
+
66
+ `to-spec`, `to-tickets` and `implement` ship with `disable-model-invocation: true`, which blocks the Skill
67
+ tool for this session and every subagent, and no setting lifts it: the gate reads the frontmatter and
68
+ consults nothing else. Two releases of this skill worked around that by reading the engine's `SKILL.md`
69
+ and carrying out its process. **That route is retired.** The engines are installed in the repo, the
70
+ installer strips the flag from the repo's own copies, and `wdi-build` invokes them like any other skill.
71
+
72
+ What preflight checks is therefore not *which route exists* but *whether the flag is back* — `npx skills
73
+ update` restores the author's file byte for byte, and `engines-invocable` in `validate.py` is red when it
74
+ has. A stalled Phase 2 three hours into an unattended run is what this replaces.
75
+
76
+ The `to-tickets` quiz granularity and blocking edges — is still **answered by this skill**: ticket
77
+ count from the size table in `delivery-flow-guide.md`, edges from `depends_on` and `touches`. The answers
78
+ are passed IN the invocation, and each one is a ledger row. An engine that stops to ask inside an
79
+ unattended run is a run that stalls with nobody there to answer.
80
+
81
+ ### Confirmation becomes the mandate
82
+
83
+ On the owner's confirmation, and not before:
84
+
85
+ 1. Open a `DEC-` through `wdi-decision`, `type: mandate`, at `status: accepted`. `accepted_by` names the
86
+ owner a person and a date, the way `risk_accepted_by` does. **Ask for that name here if the repo does
87
+ not already carry it**, because it is the one thing the run cannot invent later and every person-and-date
88
+ field it writes will need it. **The mandate is the one `DEC-` that MUST
89
+ NOT be accepted by delegation** (`mandate-accept`). Its parameters `from_gate` · `scope` · `parked` ·
90
+ `smoke_test` · `loop` · `expires` — live **only** on its row in `decisions.yaml`; the file carries
91
+ Decision, Why, and Cost, and points at the row. One fact, one home.
92
+ 2. Write the ledger header — see § The ledger.
93
+ 3. Start the loop. In Claude Code, invoke the `loop` skill with `<interval> /wdi-autopilot`. Where that is
94
+ not available, print the command for the owner to type, and name the alternative the platform has:
95
+
96
+ ```
97
+ /loop 5m /wdi-autopilot
98
+ ```
99
+
100
+ The interval is the **pause between** iterations, not the length of one. An iteration that outlives it
101
+ finishes first; the next firing waits.
102
+
103
+ ## Door 2 One iteration
104
+
105
+ Open with three reads, in this order:
106
+
107
+ 1. `validate.py --generate`. `.control/generated/` is written by that flag and nothing else, so without it
108
+ every iteration reads a status file from before the run and re-holds gates that already passed. It sweeps
109
+ the validators for free at the same time.
110
+ 2. **Reconcile `## Resume` against git.** Compare the run branch HEAD with the commit Resume names. A
111
+ difference is work that landed before the last iteration died rebuild Resume from what git shows
112
+ **before** starting anything new. Trusting a stale Resume is how a merged ticket gets implemented twice.
113
+
114
+ **A ledger with no `## Resume` heading at all is the same case, one step further back.** It is a
115
+ pre-0.6.2 ledger — a flat table with nothing else and `update` only ever renames the file, never
116
+ restructures its content, because that restructuring needs exactly this read. Heal it once, here,
117
+ before touching anything else: wrap the existing table under a `## Decisions` heading if it is not
118
+ already, then **build a fresh `## Resume`** the same way as a stale one above — from the mandate row,
119
+ `.control/generated/status`, and the run branch's actual HEAD, never from the table's last row read as
120
+ prose. The table's own rows are untouched; only the missing head is added.
121
+ 3. `.control/generated/status`, the mandate row, and **the ledger's `## Resume` only** see § The ledger
122
+ for why that is a section and not a file.
123
+
124
+ Then work § The work table
125
+ **from the top, for as long as the work can be done safely** — not one row and return. The loop is a safety
126
+ net that restarts a run that died, not the pacer of one that is alive; an iteration that stops after one step
127
+ while work remains turns a five-minute interval into five minutes of waiting per step.
128
+
129
+ An iteration returns at exactly **three stops**, and names which:
130
+
131
+ | Stop | Means |
132
+ |---|---|
133
+ | **Done** | Every `FR` in scope is closed, or nothing left is **runnable**every remaining row is parked or blocked. Go to § Finish |
134
+ | **Capacity** | The session's context is near its limit, or a dispatched step cannot be spawned here. The ledger's last row is a boundary the next firing resumes from. **The same capacity reason twice in a row is recorded under Blocked instead** — the next firing is the same session on the same machine, so a spawn that is unavailable now is unavailable then, and retrying it is the spin this design exists to prevent |
135
+ | **Blocked** | A step failed at its cap — two return trips in `wdi-build`, a third failed fix — and is recorded under **Blocked** in `## Resume`. The next firing takes the next **runnable** row, never this one again |
136
+
137
+ **Runnable** means: not listed under Blocked in `## Resume`, and not parked by the mandate. A blocked row is
138
+ retried only when the owner unblocks it or a later change removes the cause — and the ledger row that
139
+ recorded the block says which. A run that re-picks a blocked step spends the whole mandate window on it, and
140
+ that is the one stall this design has to prevent.
141
+
142
+ The ledger is what makes the next firing continue rather than restart, so every step boundary lands there
143
+ **before** the next step starts.
144
+
145
+ ### The work table — where the run picks up
146
+
147
+ | The registry says | Do |
148
+ |---|---|
149
+ | `from_gate` is G1 and no brief | `wdi-problem`. Then **hold G1**: answer its questions in the ledger, record `G1` in `gates_passed` |
150
+ | G1 passed, no PRD for the scope | `wdi-product` intent `prd` `wdi-ux` first where the interface is the promise. Hold G2 the same way |
151
+ | G2 passed, no components | `wdi-init` intents `component` · `mode` · `risk`. Each `mode` and `risk_accepted` is a ledger row with its reason |
152
+ | Components, no catalogue or spine | `wdi-blueprint` `catalog`, then `platform`. Hold G3 |
153
+ | G3 passed, a component above `catalog` lacks depth | `wdi-component`. Hold G4 for that component; set `g4_passed` |
154
+ | G4 clear for a candidate row | `wdi-report` intent `estimate`, pick the top candidate row, then **invoke `wdi-build`** for it — **unattended branch** |
155
+ | A spec is open | **Invoke `wdi-build`**, which continues from its next phase or ticket. The frontier is read from the tickets |
156
+ | A spec just closed | `wdi-reconcile` over the gate scope; carry every drift finding to its owning skill in one edit pass |
157
+ | Every `FR` in scope closed | § Finish |
158
+ | Work remains but **nothing is runnable** — all of it parked or blocked | § Finish, with the run marked **incomplete** and each blocker named |
159
+ | `expires` passed | § Finish, with the run marked lapsed |
160
+
161
+ **Holding a gate here means answering its checklist, not skipping it.** Every ★ question is answered in the
162
+ ledger, `yes` or `change`; a `change` is acted on in the same iteration. The ★ questions a validator answers
163
+ are answered by the validator, never re-derived.
164
+
165
+ ### Faster is allowed; unsafe is not
166
+
167
+ Everything that shortens the run without changing what it produces is in scope: dispatching a step to a
168
+ subagent, running the review panel while the next ticket's tests are being written, building tickets with no
169
+ blocking edge between them at once, holding G3 for several components in one pass. Four limits, all already
170
+ the method's, and none of them relaxes here:
171
+
172
+ - **`wdi-build` § Parallel tickets sets the conditions** each concurrent builder in its own worktree,
173
+ `parallel-tickets-blocked` green for every pair released together, the shape-setting ticket closed first, no shared registry
174
+ write in flight. The coordinator holds every registry write and every merge into the run branch, serially.
175
+ - **Specs run in parallel only where `depends_on` says they may.** A wide refactor's batches never do.
176
+ - **Every step is judged from the artifact**, never from a builder's report the same rule, whoever runs
177
+ the step. A step whose reviewer is also its builder is a self-report and does not count.
178
+ - **Nothing lands on the run branch red.** A ticket merges into it only with its tests green and the full
179
+ suite green once; a merge that turns the branch red is reverted, not patched forward. **Reverting a merge
180
+ leaves the branch counted as merged**, so re-merging the same branch brings back nothing: the ticket
181
+ returns to `ready-for-agent` and its redo lands on a **new** branch cut from the revert.
182
+ - **A spec MUST NOT close while the run branch's last pushed head is red.** That is a **Blocked** row, not a
183
+ follow-up. Closing over red carries the failure forward, and every later ticket's local "full suite green
184
+ once" hides it behind a suite that was never the branch's.
185
+
186
+ ### One run, one branch, one PR
187
+
188
+ A mandate is **one unit of work**, and it reaches `main` through **one door**: a single PR from the run
189
+ branch, which the **owner** merges after the final review. This is what makes the result reviewable as a
190
+ whole instead of as a stream of PRs nobody read.
191
+
192
+ **The rule is about how the run ENDS, not how it works.** During the run, branches and worktrees are tools
193
+ and MAY be used freely a worktree per parallel builder, a branch per ticket, a throwaway branch to try a
194
+ migration. What MUST NOT happen is that any of them survive: every working branch is merged into the run
195
+ branch by the coordinator and deleted, and **only the run branch is ever pushed**. The end state is one
196
+ branch, one PR, nothing else on the remote.
197
+
198
+ | In `wdi-build` | Under a mandate |
199
+ |---|---|
200
+ | Step 4 pushes a ticket branch and opens a PR per ticket | The ticket is committed to the run branch — directly, or merged in from its own worktree by the coordinator. The ticket-closing checklist is still answered first. **No PR per ticket** |
201
+ | Step 5 watches CI per PR | The coordinator pushes the run branch **at every spec close**; the first push opens the one PR as a **draft**; CI is watched per push, on the pushed head SHA, and judged exactly as Step 5 says |
202
+ | `MUST NOT merge` | Holds harder. The run never merges to `main`; the owner does, once, after § Finish |
203
+
204
+ A second PR is a red flag. Where a change cannot ride the run branch — a hotfix `main` needs today — it is
205
+ reported for the owner, not opened by the run.
206
+
207
+
208
+ ### What the agent decides, and what it does with the answer
209
+
210
+ | Would have asked the owner | Under a mandate |
211
+ |---|---|
212
+ | A gate checklist | Answered and recorded, as above |
213
+ | Seams, testing decisions, the `to-tickets` quiz | Decided; one ledger row each |
214
+ | An `owner` row in `wdi-question` | Answered with a default, filed in `assumptions.md` with its cost and `under: DEC-<mandate>`, closed in `answered.md` in the same pass. **A row whose owner is the client or a stakeholder is treated as parked** — `wdi-question` says it is never the agent's, mandate or not, and the mandate came from the owner so it cannot delegate what was never theirs |
215
+ | Code right, document wrong (`wdi-build` § When the code turns out to be right) | Decided; the owning skill edits in the present tense; one ledger row naming the promise that moved |
216
+ | A `DEC-` to accept | Accepted with `accepted_by: DEC-<mandate>`, then applied in the same pass |
217
+ | Drift with a clear right side | Carried to the owning skill |
218
+ | A conflict with no right side | A `DEC-`, accepted by delegation |
219
+ | Anything in `parked` | **Not decided.** One row in the final report's parked list; the `FR` it holds is skipped and the run moves to the next |
220
+
221
+ Three things the mandate MUST NOT reach, whatever `parked` says: a guard, a test, or an assertion edited to
222
+ turn something green; a ticket's `satisfies` amended to make a must-fix go away; a builder editing `.what/`,
223
+ `.how/`, or an `applied` `DEC-`. `wdi-build` owns all three and this skill adds no exception.
224
+
225
+ ### Recording is not optional here
226
+
227
+ Under supervision a decision nobody recorded is normal, because the owner was in the room. Here the owner
228
+ was not, so **every decision this skill takes for them is a ledger row** — that is the whole price of the
229
+ mandate. The `DEC-` threshold in `decision-guide.md` still decides which of them also become a `DEC-`; the
230
+ ledger decides nothing and records everything.
231
+
232
+ ### How the owner stops it
233
+
234
+ Stated on the preflight page, because a run nobody can stop is not a run anybody should start.
235
+
236
+ | To | Do | Effect |
237
+ |---|---|---|
238
+ | Pause | Cancel the loop, or interrupt the session | The current iteration finishes its step and lands its ledger row. Nothing is left half-written |
239
+ | Resume | `/wdi-autopilot` again, or start the loop again | The mandate is still active, so it comes in through the iteration door and continues from `## Resume` |
240
+ | End it for good | Supersede the mandate through `wdi-decision`, or let `expires` pass | **Cancelling the loop does NOT revoke the mandate.** Until it is superseded or lapses, any later firing resumes the run |
241
+
242
+ ## The ledger
243
+
244
+ `.control/memlog/autopilot-<mandate-id>.md` — `autopilot-DEC-014.md` one per mandate, **named for the
245
+ mandate and not for the day** (`mandate-accept` looks for it there), because two mandates can share a date and appending the second run's
246
+ decisions to the first run's ledger destroys both as a record. A memlog is a run log *which skill ran, and
247
+ what it decided while running* and this is exactly one. `memlog-home` holds it where every memlog lives.
248
+
249
+ Frontmatter `artifact:` names the mandate's `DEC-` file `memlog-home` demands it of every memlog.
250
+
251
+ **It has two readers who want opposite things, and that is what shapes it.** The next iteration needs a
252
+ resume point: where the last one stopped and what to do now. The owner needs every decision, with what it
253
+ cost. Serving both from one flat table is what made a real ledger reach 41 KB by its twenty-second
254
+ iteration — and every iteration after that paid to re-read decisions that were spent.
255
+
256
+ So the file has a head that is **overwritten** and a body that is **appended**, and only the head is read
257
+ while the run is alive:
258
+
259
+ ```
260
+ ## Resume <- rewritten every iteration. THIS is what an iteration loads.
261
+ ## Decisions <- appended, never rewritten. The owner's, and grepped by id when a past decision is needed.
262
+ ```
263
+
264
+ ### `## Resume` the only part an iteration reads
265
+
266
+ Read it, and nothing below it:
267
+
268
+ ```bash
269
+ sed -n '1,/^## Decisions/p' .control/memlog/autopilot-<mandate-id>.md
270
+ ```
271
+
272
+ Rewritten **in the same commit as the work it describes** — not at the end of the iteration, because an
273
+ iteration that dies between the two leaves Resume pointing at work that already landed. The **coordinator is
274
+ the ledger's only writer**; a dispatched step returns its rows rather than appending them, so two builders in
275
+ two worktrees can never both rewrite this block. It holds **only what no registry answers**:
276
+
277
+ | Line | Holds |
278
+ |---|---|
279
+ | Iteration | The number, and the commit that is its boundary |
280
+ | Run branch | The branch, and whether the one PR is open yet |
281
+ | Stopped at | Which of the three stops ended the last iteration, in a clause |
282
+ | Blocked | Each blocked step and what it hit its cap on, one line each, or `—` |
283
+ | Parked | Each mandate-parked row and the `FR` it holds, one line each, or `—` |
284
+ | Next | The next runnable step, one line |
285
+
286
+ **It MUST NOT restate a decision**, and it MUST NOT repeat what `specs.yaml`, a ticket's own status, or
287
+ `.control/generated/status` already answers. Position and intent live here; everything else is read from the
288
+ registry that owns it. A Resume block that starts summarising decisions is a second home for them, and it is
289
+ the copy that goes stale.
290
+
291
+ ### `## Decisions` one line per cell
292
+
293
+ | Column | Holds |
294
+ |---|---|
295
+ | When | Iteration number and commit |
296
+ | Where | The skill and step that would have asked |
297
+ | Decided | One sentence, present tense |
298
+ | Instead of | The alternative that lost, one line, or `—` |
299
+ | Cost if wrong | One line. `one setting changes` is a valid answer and a short one |
300
+ | Landed in | The files edited, or the `DEC-` / `OQ-` id |
301
+
302
+ **One line per cell is the rule, not a target.** What does not fit a gate checklist answered question by
303
+ question, a panel finding adjudicated at length goes to a companion document at
304
+ `.control/memlog/autopilot-<mandate-id>/<NN>-<slug>.md`, and the row keeps a pointer to it. This is
305
+ `wdi-question`'s rule for a question that outgrows one line, borrowed whole rather than reinvented.
306
+
307
+ A row MUST NOT carry the derivation that produced the decision which files were read, which clause was
308
+ weighed. `decision-guide.md` forbids exactly that in a `DEC-`, and a ledger row is the shorter form of the
309
+ same thing.
310
+
311
+ The owner MAY read the whole file at any time while the loop runs. **Reading it never pauses the run**;
312
+ disagreeing with a row is a new `DEC-` that supersedes, opened through `wdi-decision`, and the next iteration
313
+ applies it.
314
+
315
+ ## Finish
316
+
317
+ When § The work table reaches § Finish:
318
+
319
+ 1. **Smoke test.** At `smoke_test: agent`: run the application with the commands
320
+ `.constitution/project/codebase-stack-guide.md` names, exercise every closed `FR`'s proof of done from
321
+ the PRD, record pass or fail per `FR` in the ledger. At `owner`: run nothing; the test script below is
322
+ the whole deliverable.
323
+ 2. `validate.py --generate`, then `wdi-report` intent `progress`.
324
+ 3. Raise the mandate to `applied`, `touches` naming the ledger, and rewrite `## Resume` one last time so it
325
+ reads as the run's end state rather than a step that never came.
326
+ 4. **Leave the run branch in a state the owner can merge.** A ticket still in flight is either finished or
327
+ its merge reverted — the branch is never handed over half-applied. Then push, wait for CI to conclude on
328
+ that head SHA, and mark the one PR **ready for review** *only if it is green*. Red keeps the PR a
329
+ **draft** and is reported red: a PR marked ready is an invitation to merge, and the run MUST NOT extend
330
+ one over a red branch, nor patch to turn it green at the door.
331
+ 5. Cancel the loop: in Claude Code, the `loop` skill's cancel; elsewhere, tell the owner the loop has nothing
332
+ left to do.
333
+ 6. Write the final report as the Output below. The owner merges; the run never does.
334
+
335
+ ## Red Flags STOP
336
+
337
+ - Asking the owner anything through the iteration door
338
+ - Starting the loop before the mandate is `accepted`, or on a red validator
339
+ - **Opening preflight from a loop firing, or writing a mandate the owner did not confirm in this turn**
340
+ - Treating an expired mandate as a reason to start over rather than to finish
341
+ - Closing a spec, or marking the PR ready, while the last pushed head is red
342
+ - Re-merging a branch whose merge was reverted, instead of cutting a new one
343
+ - A mandate accepted by delegation, or with no `expires`
344
+ - Deciding something the mandate parks, or parking something the mandate did not
345
+ - A decision taken and not written to the ledger
346
+ - A pre-0.6.2 ledger left un-healed — no `## Resume` wrapped and rebuilt on first touch
347
+ - Reading the whole ledger when the run is alive `## Resume` is what an iteration loads
348
+ - A `## Resume` that restates a decision, or repeats what the registry already answers
349
+ - A ledger cell longer than a line, instead of a pointer to a companion document
350
+ - Restarting from the first row instead of reading `## Resume`
351
+ - Re-picking a step `## Resume` lists as blocked, instead of taking the next runnable row
352
+ - Spinning until `expires` on work that is not runnable, instead of finishing and naming the blockers
353
+ - Returning after one step while work remains and none of the three stops applies
354
+ - A second PR, any branch but the run branch pushed, a working branch left alive at Finish, or any merge
355
+ into `main` by the run — working branches and worktrees during the run are fine; surviving ones are not
356
+ - Merging a red ticket into the run branch, or patching the branch forward instead of reverting the merge
357
+ - Marking the PR ready over red CI, or handing over a run branch with a ticket half-applied
358
+ - Parallel builders sharing a worktree, or a registry written by anyone but the coordinator
359
+ - Reproducing an engine's process inline instead of invoking it — `to-spec`, `to-tickets`, `implement`,
360
+ `tdd` and `code-review` are invoked, and a paraphrase of an engine is not the engine. If one will not
361
+ invoke, that is a stop with a named cause and a one-command fix, not something to write around
362
+ - Reaching for a retired BMad wrapper when an engine will not invoke — `bmad-build` is the closest
363
+ thing to hand and the furthest thing from allowed
364
+ - Editing a guard, a test, or an assertion to go green — no mandate reaches that
365
+ - Answering a ★ question a validator already answered
366
+
367
+ ## Output
368
+
369
+ Preflight: the one page, then the mandate id and the loop command actually issued.
370
+
371
+ Iteration: the steps taken in order, the ledger rows added, which of the three stops ended it and why, and
372
+ what the next firing will find.
373
+
374
+ Finish, following the Agent Rules `Answer Closing` block and carrying:
375
+
376
+ - **what was done** — the one PR, its branch and head SHA, and CI's verdict on it; every `FR` closed, with
377
+ its spec; the smoke test result per `FR`, or the words *not run, by mandate*; the ledger path and its row
378
+ count
379
+ - **what blocked it** — the parked list, each with the `FR` it holds and the decision the owner owes;
380
+ anything left red; whether the run lapsed at `expires`
381
+ - **what comes next** — **the test script**: for every closed `FR`, its proof of done from the PRD as one
382
+ step the owner performs; then every follow-up `wdi-build` recorded, and the plan-versus-code inventory
383
+ differences