wdi-method 0.6.1 → 0.6.2
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.
- package/README.md +14 -4
- package/bin/wdi-method.js +1 -0
- package/kit/.constitution/method/README.md +1 -1
- package/kit/.constitution/method/document/decision-guide.md +208 -199
- package/kit/.constitution/method/document/delivery-flow-guide.md +412 -409
- package/kit/.constitution/method/document/templates/decision.md +6 -1
- package/kit/.constitution/method/method-glossary.md +183 -182
- package/kit/.constitution/method/scripts/validate.py +102 -2
- package/kit/.constitution/method/why/README.md +2 -1
- package/kit/.constitution/method/why/portability.md +98 -98
- package/kit/skills/wdi-autopilot/SKILL.md +366 -0
- package/kit/skills/wdi-build/SKILL.md +371 -357
- package/kit/skills/wdi-decision/SKILL.md +197 -187
- package/kit/skills/wdi-help/SKILL.md +102 -100
- package/kit/skills/wdi-question/SKILL.md +176 -170
- package/kit-overlay/AGENTS.md +223 -217
- package/kit-overlay/README.md +1 -1
- package/kit-overlay/portability.md +98 -98
- package/package.json +1 -1
|
@@ -1,98 +1,98 @@
|
|
|
1
|
-
---
|
|
2
|
-
status: Reference
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
# Portability — what is method, what is product
|
|
6
|
-
|
|
7
|
-
**Opened when:** carrying a method change into the WDI Method package, or installing
|
|
8
|
-
the method in a product repo.
|
|
9
|
-
|
|
10
|
-
This file **explains**. It does not bind. Installing is the act, and that act lives in
|
|
11
|
-
the WDI Method package README plus `wdi-method` (`install` · `update` · `promote` ·
|
|
12
|
-
`verify`). Where this file and that README disagree, the README wins and the
|
|
13
|
-
disagreement is a defect.
|
|
14
|
-
|
|
15
|
-
It exists so that "promote the method, leave the product" is not a fresh re-reading of
|
|
16
|
-
fifty files every time.
|
|
17
|
-
|
|
18
|
-
## The seam
|
|
19
|
-
|
|
20
|
-
Most of `.constitution/` is portable as it stands. A handful name **this product**, and in most of
|
|
21
|
-
them only an *example* does — not a rule.
|
|
22
|
-
|
|
23
|
-
| File | What is this product's | What to do when carrying it |
|
|
24
|
-
|---|---|---|
|
|
25
|
-
| `../../project/constitution.md` | Articles 1, 2, and 5 | **Rewrite 2 and 5.** Article 1 cites `index.yaml` `product.name`. Articles 3, 4, 6, 7 are NOT here — they are the method's, in `../constitution.md`, and `update` replaces them. `promote` never touches this file: the room is skipped, so the package's copy is a seed and nothing more |
|
|
26
|
-
| `../document/architecture-guide.md` | Seed examples of stack and tree shape | Re-point the examples. Every rule around them travels |
|
|
27
|
-
| `../document/corpus-guide.md` | Worked examples of `_platform` ownership | Re-point the examples. **Keep both kinds**: they teach the trap better than the rule alone |
|
|
28
|
-
| `templates/design-system.md` | The pointer to wherever this project keeps its tokens | Re-point at that project's token file |
|
|
29
|
-
| `templates/oq.md` | One example of a bad question title | Cosmetic |
|
|
30
|
-
|
|
31
|
-
Everything else — the five gates, the two fields, the
|
|
32
|
-
`inventory.py`, `../method-glossary.md`, and the three files beside this one — carries without edit.
|
|
33
|
-
|
|
34
|
-
One half-exception, and it is by design: `inventory.py` is the generic engine and carries whole, but
|
|
35
|
-
it reads no code itself. The three readers live in `../../project/inventory-readers.py`, which ships
|
|
36
|
-
as a skeleton and belongs to the product. A new project runs `wdi-init` intent `readers` once and
|
|
37
|
-
rewrites that file, nothing else. No example ships, deliberately — an example is a guess about a
|
|
38
|
-
stack nobody here has seen.
|
|
39
|
-
|
|
40
|
-
## What does NOT travel
|
|
41
|
-
|
|
42
|
-
| Stays behind | Why |
|
|
43
|
-
|---|---|
|
|
44
|
-
| `.control/` | This product's state. A new project scaffolds its own through `wdi-init` intent `setup`, or receives empty stubs on first `install` |
|
|
45
|
-
| `.what/` · `.how/` | This product's promises and build |
|
|
46
|
-
| `.constitution/project/codebase-*-guide.md` | Written by the **project**, not the method. They ship as empty `Draft` stubs |
|
|
47
|
-
| `.constitution/project/inventory-readers.py` | How THIS product's code is read. Seeded as a SKELETON — no patterns and no stack. `wdi-init` intent `readers` writes it against the repo in front of it |
|
|
48
|
-
| `_bmad-output/` | Run workspace |
|
|
49
|
-
| The `bmad-*` skills themselves | BMad's, installed by BMad. Only `_bmad/custom/*.toml` is ours |
|
|
50
|
-
|
|
51
|
-
## What travels beside `.constitution/`
|
|
52
|
-
|
|
53
|
-
The method is not `.constitution/` alone. Three sets move together, and carrying one without the
|
|
54
|
-
others leaves a method that cannot run:
|
|
55
|
-
|
|
56
|
-
| Set | Note |
|
|
57
|
-
|---|---|
|
|
58
|
-
| `.constitution/` | Minus the product articles; `promote` / `install` handle the seam |
|
|
59
|
-
| `.claude/skills/wdi-*/` (and `.agents/skills/wdi-*/` when those agents are selected) | Every wrapper. A wrapper without its guide, or a guide without its wrapper, is half a method |
|
|
60
|
-
| `_bmad/custom/*.toml` | The one most likely to be forgotten. `*.user.toml` stays behind |
|
|
61
|
-
| `AGENTS.md` | The routing table is the method; from `## Code` down is the product. `install` / `update` MUST NOT overwrite an existing `AGENTS.md` |
|
|
62
|
-
|
|
63
|
-
## Two directions
|
|
64
|
-
|
|
65
|
-
```
|
|
66
|
-
a product repo with a newer working copy of the method
|
|
67
|
-
--promote-->
|
|
68
|
-
WDI Method (this package)
|
|
69
|
-
--install / update-->
|
|
70
|
-
product repos
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
- **Promote** copies the method *up* once it has settled in a working copy.
|
|
74
|
-
- **Install / update** copies that snapshot *out* to a repo that consumes it.
|
|
75
|
-
- Do not run `update` against a repo you are about to promote from — that would overwrite the newer copy.
|
|
76
|
-
- There is no SHA lock and no per-file increment. The snapshot is the unit. The package version on npm / GitHub is the name of that snapshot.
|
|
77
|
-
|
|
78
|
-
## Installing in a fresh repo
|
|
79
|
-
|
|
80
|
-
BMad first (`npx bmad-method install`), then WDI Method. There is no numbered install runbook:
|
|
81
|
-
the steps that a runbook used to carry are now `wdi-init` intent `setup`. The order the acts come in:
|
|
82
|
-
|
|
83
|
-
1. `npx bmad-method install` in the product repo.
|
|
84
|
-
2. `npx wdi-method install` (optionally `--agents …`).
|
|
85
|
-
3. Set `product.name` in `.control/registry/index.yaml`. Rewrite `../../project/constitution.md` Articles 2 and 5.
|
|
86
|
-
4. Merge the method routing into `AGENTS.md` if that file already existed.
|
|
87
|
-
5. Run `wdi-init` intent `setup`.
|
|
88
|
-
6. Sort what already existed. A file that is already the artifact one slot asks for goes into that
|
|
89
|
-
slot through the skill that owns it; everything else goes to `_bmad-output/prior-knowledge/`.
|
|
90
|
-
`corpus-guide.md` owns that test.
|
|
91
|
-
7. Then G1 — which confirms `product.name` and writes the brief under that name.
|
|
92
|
-
|
|
93
|
-
**Two things a fresh install MUST NOT do:**
|
|
94
|
-
|
|
95
|
-
- Set `mode` and `risk_accepted` before the components exist. They are per-component fields, and the
|
|
96
|
-
components are born at the tail of G2.
|
|
97
|
-
- Fill `.control/generated/` by hand. It is script output, and a hand-written table there is the one
|
|
98
|
-
lie no validator catches.
|
|
1
|
+
---
|
|
2
|
+
status: Reference
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Portability — what is method, what is product
|
|
6
|
+
|
|
7
|
+
**Opened when:** carrying a method change into the WDI Method package, or installing
|
|
8
|
+
the method in a product repo.
|
|
9
|
+
|
|
10
|
+
This file **explains**. It does not bind. Installing is the act, and that act lives in
|
|
11
|
+
the WDI Method package README plus `wdi-method` (`install` · `update` · `promote` ·
|
|
12
|
+
`verify`). Where this file and that README disagree, the README wins and the
|
|
13
|
+
disagreement is a defect.
|
|
14
|
+
|
|
15
|
+
It exists so that "promote the method, leave the product" is not a fresh re-reading of
|
|
16
|
+
fifty files every time.
|
|
17
|
+
|
|
18
|
+
## The seam
|
|
19
|
+
|
|
20
|
+
Most of `.constitution/` is portable as it stands. A handful name **this product**, and in most of
|
|
21
|
+
them only an *example* does — not a rule.
|
|
22
|
+
|
|
23
|
+
| File | What is this product's | What to do when carrying it |
|
|
24
|
+
|---|---|---|
|
|
25
|
+
| `../../project/constitution.md` | Articles 1, 2, and 5 | **Rewrite 2 and 5.** Article 1 cites `index.yaml` `product.name`. Articles 3, 4, 6, 7 are NOT here — they are the method's, in `../constitution.md`, and `update` replaces them. `promote` never touches this file: the room is skipped, so the package's copy is a seed and nothing more |
|
|
26
|
+
| `../document/architecture-guide.md` | Seed examples of stack and tree shape | Re-point the examples. Every rule around them travels |
|
|
27
|
+
| `../document/corpus-guide.md` | Worked examples of `_platform` ownership | Re-point the examples. **Keep both kinds**: they teach the trap better than the rule alone |
|
|
28
|
+
| `templates/design-system.md` | The pointer to wherever this project keeps its tokens | Re-point at that project's token file |
|
|
29
|
+
| `templates/oq.md` | One example of a bad question title | Cosmetic |
|
|
30
|
+
|
|
31
|
+
Everything else — the five gates, the two fields, the eighteen skills, the templates, `validate.py`,
|
|
32
|
+
`inventory.py`, `../method-glossary.md`, and the three files beside this one — carries without edit.
|
|
33
|
+
|
|
34
|
+
One half-exception, and it is by design: `inventory.py` is the generic engine and carries whole, but
|
|
35
|
+
it reads no code itself. The three readers live in `../../project/inventory-readers.py`, which ships
|
|
36
|
+
as a skeleton and belongs to the product. A new project runs `wdi-init` intent `readers` once and
|
|
37
|
+
rewrites that file, nothing else. No example ships, deliberately — an example is a guess about a
|
|
38
|
+
stack nobody here has seen.
|
|
39
|
+
|
|
40
|
+
## What does NOT travel
|
|
41
|
+
|
|
42
|
+
| Stays behind | Why |
|
|
43
|
+
|---|---|
|
|
44
|
+
| `.control/` | This product's state. A new project scaffolds its own through `wdi-init` intent `setup`, or receives empty stubs on first `install` |
|
|
45
|
+
| `.what/` · `.how/` | This product's promises and build |
|
|
46
|
+
| `.constitution/project/codebase-*-guide.md` | Written by the **project**, not the method. They ship as empty `Draft` stubs |
|
|
47
|
+
| `.constitution/project/inventory-readers.py` | How THIS product's code is read. Seeded as a SKELETON — no patterns and no stack. `wdi-init` intent `readers` writes it against the repo in front of it |
|
|
48
|
+
| `_bmad-output/` | Run workspace |
|
|
49
|
+
| The `bmad-*` skills themselves | BMad's, installed by BMad. Only `_bmad/custom/*.toml` is ours |
|
|
50
|
+
|
|
51
|
+
## What travels beside `.constitution/`
|
|
52
|
+
|
|
53
|
+
The method is not `.constitution/` alone. Three sets move together, and carrying one without the
|
|
54
|
+
others leaves a method that cannot run:
|
|
55
|
+
|
|
56
|
+
| Set | Note |
|
|
57
|
+
|---|---|
|
|
58
|
+
| `.constitution/` | Minus the product articles; `promote` / `install` handle the seam |
|
|
59
|
+
| `.claude/skills/wdi-*/` (and `.agents/skills/wdi-*/` when those agents are selected) | Every wrapper. A wrapper without its guide, or a guide without its wrapper, is half a method |
|
|
60
|
+
| `_bmad/custom/*.toml` | The one most likely to be forgotten. `*.user.toml` stays behind |
|
|
61
|
+
| `AGENTS.md` | The routing table is the method; from `## Code` down is the product. `install` / `update` MUST NOT overwrite an existing `AGENTS.md` |
|
|
62
|
+
|
|
63
|
+
## Two directions
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
a product repo with a newer working copy of the method
|
|
67
|
+
--promote-->
|
|
68
|
+
WDI Method (this package)
|
|
69
|
+
--install / update-->
|
|
70
|
+
product repos
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
- **Promote** copies the method *up* once it has settled in a working copy.
|
|
74
|
+
- **Install / update** copies that snapshot *out* to a repo that consumes it.
|
|
75
|
+
- Do not run `update` against a repo you are about to promote from — that would overwrite the newer copy.
|
|
76
|
+
- There is no SHA lock and no per-file increment. The snapshot is the unit. The package version on npm / GitHub is the name of that snapshot.
|
|
77
|
+
|
|
78
|
+
## Installing in a fresh repo
|
|
79
|
+
|
|
80
|
+
BMad first (`npx bmad-method install`), then WDI Method. There is no numbered install runbook:
|
|
81
|
+
the steps that a runbook used to carry are now `wdi-init` intent `setup`. The order the acts come in:
|
|
82
|
+
|
|
83
|
+
1. `npx bmad-method install` in the product repo.
|
|
84
|
+
2. `npx wdi-method install` (optionally `--agents …`).
|
|
85
|
+
3. Set `product.name` in `.control/registry/index.yaml`. Rewrite `../../project/constitution.md` Articles 2 and 5.
|
|
86
|
+
4. Merge the method routing into `AGENTS.md` if that file already existed.
|
|
87
|
+
5. Run `wdi-init` intent `setup`.
|
|
88
|
+
6. Sort what already existed. A file that is already the artifact one slot asks for goes into that
|
|
89
|
+
slot through the skill that owns it; everything else goes to `_bmad-output/prior-knowledge/`.
|
|
90
|
+
`corpus-guide.md` owns that test.
|
|
91
|
+
7. Then G1 — which confirms `product.name` and writes the brief under that name.
|
|
92
|
+
|
|
93
|
+
**Two things a fresh install MUST NOT do:**
|
|
94
|
+
|
|
95
|
+
- Set `mode` and `risk_accepted` before the components exist. They are per-component fields, and the
|
|
96
|
+
components are born at the tail of G2.
|
|
97
|
+
- Fill `.control/generated/` by hand. It is script output, and a hand-written table there is the one
|
|
98
|
+
lie no validator catches.
|
|
@@ -0,0 +1,366 @@
|
|
|
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 takes — and 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
|
+
3. `.control/generated/status`, the mandate row, and **the ledger's `## Resume` only** — see § The ledger
|
|
109
|
+
for why that is a section and not a file.
|
|
110
|
+
|
|
111
|
+
Then work § The work table
|
|
112
|
+
**from the top, for as long as the work can be done safely** — not one row and return. The loop is a safety
|
|
113
|
+
net that restarts a run that died, not the pacer of one that is alive; an iteration that stops after one step
|
|
114
|
+
while work remains turns a five-minute interval into five minutes of waiting per step.
|
|
115
|
+
|
|
116
|
+
An iteration returns at exactly **three stops**, and names which:
|
|
117
|
+
|
|
118
|
+
| Stop | Means |
|
|
119
|
+
|---|---|
|
|
120
|
+
| **Done** | Every `FR` in scope is closed, or nothing left is **runnable** — every remaining row is parked or blocked. Go to § Finish |
|
|
121
|
+
| **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 |
|
|
122
|
+
| **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 |
|
|
123
|
+
|
|
124
|
+
**Runnable** means: not listed under Blocked in `## Resume`, and not parked by the mandate. A blocked row is
|
|
125
|
+
retried only when the owner unblocks it or a later change removes the cause — and the ledger row that
|
|
126
|
+
recorded the block says which. A run that re-picks a blocked step spends the whole mandate window on it, and
|
|
127
|
+
that is the one stall this design has to prevent.
|
|
128
|
+
|
|
129
|
+
The ledger is what makes the next firing continue rather than restart, so every step boundary lands there
|
|
130
|
+
**before** the next step starts.
|
|
131
|
+
|
|
132
|
+
### The work table — where the run picks up
|
|
133
|
+
|
|
134
|
+
| The registry says | Do |
|
|
135
|
+
|---|---|
|
|
136
|
+
| `from_gate` is G1 and no brief | `wdi-problem`. Then **hold G1**: answer its ★ questions in the ledger, record `G1` in `gates_passed` |
|
|
137
|
+
| 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 |
|
|
138
|
+
| G2 passed, no components | `wdi-init` intents `component` · `mode` · `risk`. Each `mode` and `risk_accepted` is a ledger row with its reason |
|
|
139
|
+
| Components, no catalogue or spine | `wdi-blueprint` `catalog`, then `platform`. Hold G3 |
|
|
140
|
+
| G3 passed, a component above `catalog` lacks depth | `wdi-component`. Hold G4 for that component; set `g4_passed` |
|
|
141
|
+
| G4 clear for a candidate row | `wdi-report` intent `estimate`, pick the top candidate row, `wdi-build` for it — **unattended branch** |
|
|
142
|
+
| A spec is open | Continue `wdi-build` from its next phase or ticket. The frontier is read from the tickets |
|
|
143
|
+
| A spec just closed | `wdi-reconcile` over the gate scope; carry every drift finding to its owning skill in one edit pass |
|
|
144
|
+
| Every `FR` in scope closed | § Finish |
|
|
145
|
+
| Work remains but **nothing is runnable** — all of it parked or blocked | § Finish, with the run marked **incomplete** and each blocker named |
|
|
146
|
+
| `expires` passed | § Finish, with the run marked lapsed |
|
|
147
|
+
|
|
148
|
+
**Holding a gate here means answering its checklist, not skipping it.** Every ★ question is answered in the
|
|
149
|
+
ledger, `yes` or `change`; a `change` is acted on in the same iteration. The ★ questions a validator answers
|
|
150
|
+
are answered by the validator, never re-derived.
|
|
151
|
+
|
|
152
|
+
### Faster is allowed; unsafe is not
|
|
153
|
+
|
|
154
|
+
Everything that shortens the run without changing what it produces is in scope: dispatching a step to a
|
|
155
|
+
subagent, running the review panel while the next ticket's tests are being written, building tickets with no
|
|
156
|
+
blocking edge between them at once, holding G3 for several components in one pass. Four limits, all already
|
|
157
|
+
the method's, and none of them relaxes here:
|
|
158
|
+
|
|
159
|
+
- **`wdi-build` § Parallel tickets sets the conditions** — each concurrent builder in its own worktree,
|
|
160
|
+
`parallel-tickets-blocked` green for every pair released together, the shape-setting ticket closed first, no shared registry
|
|
161
|
+
write in flight. The coordinator holds every registry write and every merge into the run branch, serially.
|
|
162
|
+
- **Specs run in parallel only where `depends_on` says they may.** A wide refactor's batches never do.
|
|
163
|
+
- **Every step is judged from the artifact**, never from a builder's report — the same rule, whoever runs
|
|
164
|
+
the step. A step whose reviewer is also its builder is a self-report and does not count.
|
|
165
|
+
- **Nothing lands on the run branch red.** A ticket merges into it only with its tests green and the full
|
|
166
|
+
suite green once; a merge that turns the branch red is reverted, not patched forward. **Reverting a merge
|
|
167
|
+
leaves the branch counted as merged**, so re-merging the same branch brings back nothing: the ticket
|
|
168
|
+
returns to `ready-for-agent` and its redo lands on a **new** branch cut from the revert.
|
|
169
|
+
- **A spec MUST NOT close while the run branch's last pushed head is red.** That is a **Blocked** row, not a
|
|
170
|
+
follow-up. Closing over red carries the failure forward, and every later ticket's local "full suite green
|
|
171
|
+
once" hides it behind a suite that was never the branch's.
|
|
172
|
+
|
|
173
|
+
### One run, one branch, one PR
|
|
174
|
+
|
|
175
|
+
A mandate is **one unit of work**, and it reaches `main` through **one door**: a single PR from the run
|
|
176
|
+
branch, which the **owner** merges after the final review. This is what makes the result reviewable as a
|
|
177
|
+
whole instead of as a stream of PRs nobody read.
|
|
178
|
+
|
|
179
|
+
**The rule is about how the run ENDS, not how it works.** During the run, branches and worktrees are tools
|
|
180
|
+
and MAY be used freely — a worktree per parallel builder, a branch per ticket, a throwaway branch to try a
|
|
181
|
+
migration. What MUST NOT happen is that any of them survive: every working branch is merged into the run
|
|
182
|
+
branch by the coordinator and deleted, and **only the run branch is ever pushed**. The end state is one
|
|
183
|
+
branch, one PR, nothing else on the remote.
|
|
184
|
+
|
|
185
|
+
| In `wdi-build` | Under a mandate |
|
|
186
|
+
|---|---|
|
|
187
|
+
| 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** |
|
|
188
|
+
| 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 |
|
|
189
|
+
| `MUST NOT merge` | Holds harder. The run never merges to `main`; the owner does, once, after § Finish |
|
|
190
|
+
|
|
191
|
+
A second PR is a red flag. Where a change cannot ride the run branch — a hotfix `main` needs today — it is
|
|
192
|
+
reported for the owner, not opened by the run.
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
### What the agent decides, and what it does with the answer
|
|
196
|
+
|
|
197
|
+
| Would have asked the owner | Under a mandate |
|
|
198
|
+
|---|---|
|
|
199
|
+
| A gate checklist | Answered and recorded, as above |
|
|
200
|
+
| Seams, testing decisions, the `to-tickets` quiz | Decided; one ledger row each |
|
|
201
|
+
| 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 |
|
|
202
|
+
| 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 |
|
|
203
|
+
| A `DEC-` to accept | Accepted with `accepted_by: DEC-<mandate>`, then applied in the same pass |
|
|
204
|
+
| Drift with a clear right side | Carried to the owning skill |
|
|
205
|
+
| A conflict with no right side | A `DEC-`, accepted by delegation |
|
|
206
|
+
| 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 |
|
|
207
|
+
|
|
208
|
+
Three things the mandate MUST NOT reach, whatever `parked` says: a guard, a test, or an assertion edited to
|
|
209
|
+
turn something green; a ticket's `satisfies` amended to make a must-fix go away; a builder editing `.what/`,
|
|
210
|
+
`.how/`, or an `applied` `DEC-`. `wdi-build` owns all three and this skill adds no exception.
|
|
211
|
+
|
|
212
|
+
### Recording is not optional here
|
|
213
|
+
|
|
214
|
+
Under supervision a decision nobody recorded is normal, because the owner was in the room. Here the owner
|
|
215
|
+
was not, so **every decision this skill takes for them is a ledger row** — that is the whole price of the
|
|
216
|
+
mandate. The `DEC-` threshold in `decision-guide.md` still decides which of them also become a `DEC-`; the
|
|
217
|
+
ledger decides nothing and records everything.
|
|
218
|
+
|
|
219
|
+
### How the owner stops it
|
|
220
|
+
|
|
221
|
+
Stated on the preflight page, because a run nobody can stop is not a run anybody should start.
|
|
222
|
+
|
|
223
|
+
| To | Do | Effect |
|
|
224
|
+
|---|---|---|
|
|
225
|
+
| Pause | Cancel the loop, or interrupt the session | The current iteration finishes its step and lands its ledger row. Nothing is left half-written |
|
|
226
|
+
| 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` |
|
|
227
|
+
| 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 |
|
|
228
|
+
|
|
229
|
+
## The ledger
|
|
230
|
+
|
|
231
|
+
`.control/memlog/autopilot-<mandate-id>.md` — `autopilot-DEC-014.md` — one per mandate, **named for the
|
|
232
|
+
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
|
|
233
|
+
decisions to the first run's ledger destroys both as a record. A memlog is a run log — *which skill ran, and
|
|
234
|
+
what it decided while running* — and this is exactly one. `memlog-home` holds it where every memlog lives.
|
|
235
|
+
|
|
236
|
+
Frontmatter `artifact:` names the mandate's `DEC-` file — `memlog-home` demands it of every memlog.
|
|
237
|
+
|
|
238
|
+
**It has two readers who want opposite things, and that is what shapes it.** The next iteration needs a
|
|
239
|
+
resume point: where the last one stopped and what to do now. The owner needs every decision, with what it
|
|
240
|
+
cost. Serving both from one flat table is what made a real ledger reach 41 KB by its twenty-second
|
|
241
|
+
iteration — and every iteration after that paid to re-read decisions that were spent.
|
|
242
|
+
|
|
243
|
+
So the file has a head that is **overwritten** and a body that is **appended**, and only the head is read
|
|
244
|
+
while the run is alive:
|
|
245
|
+
|
|
246
|
+
```
|
|
247
|
+
## Resume <- rewritten every iteration. THIS is what an iteration loads.
|
|
248
|
+
## Decisions <- appended, never rewritten. The owner's, and grepped by id when a past decision is needed.
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
### `## Resume` — the only part an iteration reads
|
|
252
|
+
|
|
253
|
+
Read it, and nothing below it:
|
|
254
|
+
|
|
255
|
+
```bash
|
|
256
|
+
sed -n '1,/^## Decisions/p' .control/memlog/autopilot-<mandate-id>.md
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
Rewritten **in the same commit as the work it describes** — not at the end of the iteration, because an
|
|
260
|
+
iteration that dies between the two leaves Resume pointing at work that already landed. The **coordinator is
|
|
261
|
+
the ledger's only writer**; a dispatched step returns its rows rather than appending them, so two builders in
|
|
262
|
+
two worktrees can never both rewrite this block. It holds **only what no registry answers**:
|
|
263
|
+
|
|
264
|
+
| Line | Holds |
|
|
265
|
+
|---|---|
|
|
266
|
+
| Iteration | The number, and the commit that is its boundary |
|
|
267
|
+
| Run branch | The branch, and whether the one PR is open yet |
|
|
268
|
+
| Stopped at | Which of the three stops ended the last iteration, in a clause |
|
|
269
|
+
| Blocked | Each blocked step and what it hit its cap on, one line each, or `—` |
|
|
270
|
+
| Parked | Each mandate-parked row and the `FR` it holds, one line each, or `—` |
|
|
271
|
+
| Next | The next runnable step, one line |
|
|
272
|
+
|
|
273
|
+
**It MUST NOT restate a decision**, and it MUST NOT repeat what `specs.yaml`, a ticket's own status, or
|
|
274
|
+
`.control/generated/status` already answers. Position and intent live here; everything else is read from the
|
|
275
|
+
registry that owns it. A Resume block that starts summarising decisions is a second home for them, and it is
|
|
276
|
+
the copy that goes stale.
|
|
277
|
+
|
|
278
|
+
### `## Decisions` — one line per cell
|
|
279
|
+
|
|
280
|
+
| Column | Holds |
|
|
281
|
+
|---|---|
|
|
282
|
+
| When | Iteration number and commit |
|
|
283
|
+
| Where | The skill and step that would have asked |
|
|
284
|
+
| Decided | One sentence, present tense |
|
|
285
|
+
| Instead of | The alternative that lost, one line, or `—` |
|
|
286
|
+
| Cost if wrong | One line. `one setting changes` is a valid answer and a short one |
|
|
287
|
+
| Landed in | The files edited, or the `DEC-` / `OQ-` id |
|
|
288
|
+
|
|
289
|
+
**One line per cell is the rule, not a target.** What does not fit — a gate checklist answered question by
|
|
290
|
+
question, a panel finding adjudicated at length — goes to a companion document at
|
|
291
|
+
`.control/memlog/autopilot-<mandate-id>/<NN>-<slug>.md`, and the row keeps a pointer to it. This is
|
|
292
|
+
`wdi-question`'s rule for a question that outgrows one line, borrowed whole rather than reinvented.
|
|
293
|
+
|
|
294
|
+
A row MUST NOT carry the derivation that produced the decision — which files were read, which clause was
|
|
295
|
+
weighed. `decision-guide.md` forbids exactly that in a `DEC-`, and a ledger row is the shorter form of the
|
|
296
|
+
same thing.
|
|
297
|
+
|
|
298
|
+
The owner MAY read the whole file at any time while the loop runs. **Reading it never pauses the run**;
|
|
299
|
+
disagreeing with a row is a new `DEC-` that supersedes, opened through `wdi-decision`, and the next iteration
|
|
300
|
+
applies it.
|
|
301
|
+
|
|
302
|
+
## Finish
|
|
303
|
+
|
|
304
|
+
When § The work table reaches § Finish:
|
|
305
|
+
|
|
306
|
+
1. **Smoke test.** At `smoke_test: agent`: run the application with the commands
|
|
307
|
+
`.constitution/project/codebase-stack-guide.md` names, exercise every closed `FR`'s proof of done from
|
|
308
|
+
the PRD, record pass or fail per `FR` in the ledger. At `owner`: run nothing; the test script below is
|
|
309
|
+
the whole deliverable.
|
|
310
|
+
2. `validate.py --generate`, then `wdi-report` intent `progress`.
|
|
311
|
+
3. Raise the mandate to `applied`, `touches` naming the ledger, and rewrite `## Resume` one last time so it
|
|
312
|
+
reads as the run's end state rather than a step that never came.
|
|
313
|
+
4. **Leave the run branch in a state the owner can merge.** A ticket still in flight is either finished or
|
|
314
|
+
its merge reverted — the branch is never handed over half-applied. Then push, wait for CI to conclude on
|
|
315
|
+
that head SHA, and mark the one PR **ready for review** *only if it is green*. Red keeps the PR a
|
|
316
|
+
**draft** and is reported red: a PR marked ready is an invitation to merge, and the run MUST NOT extend
|
|
317
|
+
one over a red branch, nor patch to turn it green at the door.
|
|
318
|
+
5. Cancel the loop: in Claude Code, the `loop` skill's cancel; elsewhere, tell the owner the loop has nothing
|
|
319
|
+
left to do.
|
|
320
|
+
6. Write the final report as the Output below. The owner merges; the run never does.
|
|
321
|
+
|
|
322
|
+
## Red Flags — STOP
|
|
323
|
+
|
|
324
|
+
- Asking the owner anything through the iteration door
|
|
325
|
+
- Starting the loop before the mandate is `accepted`, or on a red validator
|
|
326
|
+
- **Opening preflight from a loop firing, or writing a mandate the owner did not confirm in this turn**
|
|
327
|
+
- Treating an expired mandate as a reason to start over rather than to finish
|
|
328
|
+
- Closing a spec, or marking the PR ready, while the last pushed head is red
|
|
329
|
+
- Re-merging a branch whose merge was reverted, instead of cutting a new one
|
|
330
|
+
- A mandate accepted by delegation, or with no `expires`
|
|
331
|
+
- Deciding something the mandate parks, or parking something the mandate did not
|
|
332
|
+
- A decision taken and not written to the ledger
|
|
333
|
+
- Reading the whole ledger when the run is alive — `## Resume` is what an iteration loads
|
|
334
|
+
- A `## Resume` that restates a decision, or repeats what the registry already answers
|
|
335
|
+
- A ledger cell longer than a line, instead of a pointer to a companion document
|
|
336
|
+
- Restarting from the first row instead of reading `## Resume`
|
|
337
|
+
- Re-picking a step `## Resume` lists as blocked, instead of taking the next runnable row
|
|
338
|
+
- Spinning until `expires` on work that is not runnable, instead of finishing and naming the blockers
|
|
339
|
+
- Returning after one step while work remains and none of the three stops applies
|
|
340
|
+
- A second PR, any branch but the run branch pushed, a working branch left alive at Finish, or any merge
|
|
341
|
+
into `main` by the run — working branches and worktrees during the run are fine; surviving ones are not
|
|
342
|
+
- Merging a red ticket into the run branch, or patching the branch forward instead of reverting the merge
|
|
343
|
+
- Marking the PR ready over red CI, or handing over a run branch with a ticket half-applied
|
|
344
|
+
- Parallel builders sharing a worktree, or a registry written by anyone but the coordinator
|
|
345
|
+
- Claiming a Skill-tool invocation of `to-spec`, `to-tickets`, or `implement` — the route is read-and-follow
|
|
346
|
+
or a repo copy, and the ledger names which
|
|
347
|
+
- Editing a guard, a test, or an assertion to go green — no mandate reaches that
|
|
348
|
+
- Answering a ★ question a validator already answered
|
|
349
|
+
|
|
350
|
+
## Output
|
|
351
|
+
|
|
352
|
+
Preflight: the one page, then the mandate id and the loop command actually issued.
|
|
353
|
+
|
|
354
|
+
Iteration: the steps taken in order, the ledger rows added, which of the three stops ended it and why, and
|
|
355
|
+
what the next firing will find.
|
|
356
|
+
|
|
357
|
+
Finish, following the Agent Rules `Answer Closing` block and carrying:
|
|
358
|
+
|
|
359
|
+
- **what was done** — the one PR, its branch and head SHA, and CI's verdict on it; every `FR` closed, with
|
|
360
|
+
its spec; the smoke test result per `FR`, or the words *not run, by mandate*; the ledger path and its row
|
|
361
|
+
count
|
|
362
|
+
- **what blocked it** — the parked list, each with the `FR` it holds and the decision the owner owes;
|
|
363
|
+
anything left red; whether the run lapsed at `expires`
|
|
364
|
+
- **what comes next** — **the test script**: for every closed `FR`, its proof of done from the PRD as one
|
|
365
|
+
step the owner performs; then every follow-up `wdi-build` recorded, and the plan-versus-code inventory
|
|
366
|
+
differences
|