wdi-method 0.6.31 → 0.6.32

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,104 +1,107 @@
1
- ---
2
- status: Accepted
3
- ---
4
-
5
- # BMad Skill Register
6
-
7
- **Loaded when:** deciding which BMad skill a piece of work needs, or checking what one writes
8
-
9
- This used to be the full catalogue of all 59 installed BMad skills. **That catalogue is retired.** It was a
10
- copy of somebody else's inventory, it went stale on every BMad update, and nothing in this method read more
11
- than a dozen of its rows. What binds is the division of labour below; for anything about a BMad skill this
12
- method does not invoke, ask `bmad-help`, which reads BMad's own documentation.
13
-
14
- ## Who writes what
15
-
16
- | Artifact | Written by | Wrapped in |
17
- |---|---|---|
18
- | Product brief | `bmad-product-brief` | `wdi-problem` |
19
- | PRD | `bmad-prd` | `wdi-product` |
20
- | UX — `EXPERIENCE.md` + `DESIGN.md` | `bmad-ux` | `wdi-ux` |
21
- | Architecture spine + the C4 set | `bmad-architecture` | `wdi-blueprint` intent `platform` |
22
- | **UC catalogue · actors · entities · business rules** | **nothing in BMad** | `wdi-blueprint` writes it itself |
23
- | **SRS and all of `.what/<pc>/`** | **nothing in BMad** | `wdi-component` writes it itself |
24
- | **SDD and all of `.how/<pc>/`** | **nothing in BMad** | `wdi-component` writes it itself |
25
- | Document review | `bmad-review` | `wdi-review` |
26
- | Course correction | `bmad-correct-course` | `wdi-decision` |
27
-
28
- **Everything below G5 left this table.** `SPEC.md`, the tickets, the code, and the code panel are produced
29
- by `to-spec`, `to-tickets`, `implement`, `tdd`, and `code-review` — engines that are not BMad's. Three of
30
- the five ship with `disable-model-invocation: true`; `wdi-method` strips it from the copies installed in
31
- this repo and writes a guard line naming who may drive them, so **`wdi-build` and `wdi-autopilot` invoke
32
- them directly** and an unattended iteration needs nobody. `wdi-build` owns that pipeline;
33
- `bmad-guide.md` owns the reasoning.
34
-
35
- **The three bold rows are why this method exists.** BMad stops at the promise and starts again at the
36
- mechanism, and every behaviour in between had no author. Three consequences attach to those artifacts and
37
- MUST be handled deliberately rather than discovered: no `doc_standards` fires a review, no memlog is born on
38
- its own, and no template enforces itself.
39
-
40
- ## No BMad skill is invoked directly
41
-
42
- Every one above has a wrapper, and the wrapper is what checks position, verifies the result against the
43
- guide, and lands the memlog. Routing past it produces an artifact nothing verifies.
44
-
45
- **One exception, and it is narrow:** on the Fast Path the owner runs `/implement` directly, with no wrapper.
46
- A Fast Path that turns out to touch an `FR` MUST stop and become a spec `S`, which puts it back inside
47
- `wdi-build`.
48
-
49
- ## What is available but writes nothing
50
-
51
- | Skill | Use |
52
- |---|---|
53
- | `bmad-advanced-elicitation` · `bmad-party-mode` | Thinking aids. They produce no artifact and MUST NOT be treated as authors |
54
- | `bmad-deep-recon` | Research, before a brief rests on outside data. Its output stays in `_bmad-output/` permanently and MUST NOT be folded into the brief |
55
- | `bmad-qa-generate-e2e-tests` | Tests for a feature that **already exists**. `tdd` is test-first for work being built, so this has no replacement here and is NOT retired — but what it writes is a test, never a contract, and it MUST NOT be read as one |
56
- | `bmad-checkpoint-preview` | A human reading aid over a change, the same class as `bmad-advanced-elicitation`. It MUST NOT be counted as the Step 3 panel: that one is a separate dispatch by a different agent |
57
- | `bmad-help` | Questions about BMad itself. It MUST NOT be used to answer "where am I" — that is `wdi-help` |
58
-
59
- ## What is NOT USED, and MUST NOT be
60
-
61
- **The criterion, and it binds every row below.** A BMad skill is retired only where this method has a
62
- **named replacement** for what it produces. Without one it is not retired — it goes in the table above
63
- instead, as something that may be used but MUST NOT author. Banning a capability with nothing in its
64
- place is how a method gets worked around rather than followed.
65
-
66
- ### Retired at G5 — enforced by install and update
67
-
68
- **This is enforced, not only stated.** `install` and `update` set `disable-model-invocation: true` on
69
- every wrapper below and add a `Skill(<name>)` deny rule to `.claude/settings.json`, both re-applied on
70
- every run because BMad's installer rewrites its own wrappers. A person typing `/bmad-build` still gets
71
- it: the method retires a default, it does not confiscate a tool. The list lives in
72
- `bin/wdi-method.js` as `BMAD_RETIRED_G5`, and a test fails when this table and that array disagree.
73
-
74
- | Skill | Replaced by | Why |
75
- |---|---|---|
76
- | `bmad-spec` | `to-spec` | **Retired.** The contract below G5 is no longer BMad's. Its `_bmad/custom/*.toml` override is withdrawn and `update` removes any still installed |
77
- | `bmad-build` · `bmad-build-auto` | `implement` · `wdi-autopilot` | **Retired.** `bmad-build` describes itself as implementing "any user intent, requirement, story, bug fix or change request" — the most inviting description in the repo's skill index, for the one thing this method owns most tightly. `bmad-build-auto` is an unattended loop, which is `wdi-autopilot`'s |
78
- | `bmad-code-review` | `code-review` | **Retired.** The panel at Step 3 is a separate dispatch by a different agent; BMad's own review layers are the builder reviewing itself |
79
- | `bmad-retrospective` | — | **Retired** with `RTR-` and `V19`. A frozen `RTR-` file stays where it is |
80
- | `bmad-agent-dev` | `implement` | **Retired.** "Senior software engineer for story execution and code implementation" is `implement`'s sentence |
81
- | `bmad-create-epics-and-stories` | `to-tickets` | **Retired**, and not merely by preference: the `epics` level between a spec and its tickets is **repealed in code** — `validate.py` reads a flat `tickets:` list. A skill whose only output is a shape nothing reads |
82
- | `bmad-create-story` · `bmad-dev-story` · `bmad-dev-auto` · `bmad-quick-dev` | `implement` | **Retired.** BMad deprecated all four in favour of `bmad-build`, which is itself retired here. An alias to a retired skill is retired |
83
- | `bmad-sprint-planning` · `bmad-sprint-status` | the ticket itself | **Retired.** The sprint route keeps status in a hand-edited file; this method reads status from the ticket — `bmad-guide.md` owns the reasoning |
84
-
85
- ### Not used for other reasons — not enforced, and not G5's
86
-
87
- These are outside the enforced list above: nothing locks them, because nothing here replaces them and
88
- none of them competes for G5's work.
89
-
90
- | Skill | Why |
91
- |---|---|
92
- | `bmad-editorial-review*` · `bmad-review-*` | Shims onto `bmad-review` lenses. Ask for the lens, not the shim |
93
- | `bmad-document-project` · `bmad-generate-project-context` | Forward to `bmad-project-context`. This repo's agent instructions are maintained by hand |
94
- | Any skill named as a **gate condition** | A gate is passed by its checklist and its validators, never by a skill having run |
95
-
96
- ## The class that decides where output lands
97
-
98
- `bmad-guide.md` owns the class definitions; what matters here is that **class B** exists because some skills
99
- write several things at once that belong to different layers. `bmad-ux` is the case: `EXPERIENCE.md` is a
100
- promise and `DESIGN.md` is a build detail, and no configuration can send them to two places. Its output
101
- lands in a neutral folder first, and `wdi-ux` places it.
102
-
103
- Which skill lands which output is the ownership table in `corpus-guide.md`, and it MUST NOT be duplicated
104
- here.
1
+ ---
2
+ status: Accepted
3
+ ---
4
+
5
+ # BMad Skill Register
6
+
7
+ **Loaded when:** deciding which BMad skill a piece of work needs, or checking what one writes
8
+
9
+ This used to be the full catalogue of all 59 installed BMad skills. **That catalogue is retired.** It was a
10
+ copy of somebody else's inventory, it went stale on every BMad update, and nothing in this method read more
11
+ than a dozen of its rows. What binds is the division of labour below; for anything about a BMad skill this
12
+ method does not invoke, ask `bmad-help`, which reads BMad's own documentation.
13
+
14
+ ## Who writes what
15
+
16
+ | Artifact | Written by | Wrapped in |
17
+ |---|---|---|
18
+ | Product brief | `bmad-product-brief` | `wdi-problem` |
19
+ | PRD | `bmad-prd` | `wdi-product` |
20
+ | UX — `EXPERIENCE.md` + `DESIGN.md` | `bmad-ux` | `wdi-ux` |
21
+ | Architecture spine + the C4 set | `bmad-architecture` | `wdi-blueprint` intent `platform` |
22
+ | **UC catalogue · actors · entities · business rules** | **nothing in BMad** | `wdi-blueprint` writes it itself |
23
+ | **SRS and all of `.what/<pc>/`** | **nothing in BMad** | `wdi-component` writes it itself |
24
+ | **SDD and all of `.how/<pc>/`** | **nothing in BMad** | `wdi-component` writes it itself |
25
+ | Document review | `bmad-review` | `wdi-review` |
26
+ | Course correction | `bmad-correct-course` | `wdi-decision` |
27
+
28
+ **Everything below G5 left this table.** `SPEC.md`, the tickets, the code, and the code panel are produced
29
+ by `to-spec`, `to-tickets`, `implement`, `tdd`, and `code-review` — engines that are not BMad's. Three of
30
+ the five ship with `disable-model-invocation: true`; `wdi-method` strips it from the copies installed in
31
+ this repo and writes a guard line naming who may drive them, so **`wdi-build` and `wdi-autopilot` invoke
32
+ them directly** and an unattended iteration needs nobody. `wdi-build` owns that pipeline;
33
+ `bmad-guide.md` owns the reasoning.
34
+
35
+ **The three bold rows are why this method exists.** BMad stops at the promise and starts again at the
36
+ mechanism, and every behaviour in between had no author. Three consequences attach to those artifacts and
37
+ MUST be handled deliberately rather than discovered: no `doc_standards` fires a review, no memlog is born on
38
+ its own, and no template enforces itself.
39
+
40
+ ## No BMad skill is invoked directly
41
+
42
+ Every one above has a wrapper, and the wrapper is what checks position, verifies the result against the
43
+ guide, and lands the memlog. Routing past it produces an artifact nothing verifies.
44
+
45
+ **One exception, and it is narrow:** on the Fast Path the owner runs `/implement` directly, with no wrapper.
46
+ A Fast Path that turns out to touch an `FR` MUST stop and become a spec `S`, which puts it back inside
47
+ `wdi-build`.
48
+
49
+ ## What is available but writes nothing
50
+
51
+ | Skill | Use |
52
+ |---|---|
53
+ | `bmad-advanced-elicitation` · `bmad-party-mode` | Thinking aids. They produce no artifact and MUST NOT be treated as authors |
54
+ | `bmad-deep-recon` | Research, before a brief rests on outside data. Its output stays in `_bmad-output/` permanently and MUST NOT be folded into the brief |
55
+ | `bmad-qa-generate-e2e-tests` | Tests for a feature that **already exists**. `tdd` is test-first for work being built, so this has no replacement here and is NOT retired — but what it writes is a test, never a contract, and it MUST NOT be read as one |
56
+ | `bmad-checkpoint-preview` | A human reading aid over a change, the same class as `bmad-advanced-elicitation`. It MUST NOT be counted as the Step 3 panel: that one is a separate dispatch by a different agent |
57
+ | `bmad-help` | Questions about BMad itself. It MUST NOT be used to answer "where am I" — that is `wdi-help` |
58
+
59
+ ## What is NOT USED, and MUST NOT be
60
+
61
+ **The criterion, and it binds every row below.** A BMad skill is retired only where this method has a
62
+ **named replacement** for what it produces. Without one it is not retired — it goes in the table above
63
+ instead, as something that may be used but MUST NOT author. Banning a capability with nothing in its
64
+ place is how a method gets worked around rather than followed.
65
+
66
+ ### Retired at G5 — enforced by install and update
67
+
68
+ **This is enforced, not only stated — as far as each host allows.** `install` and `update` set
69
+ `disable-model-invocation: true` on every wrapper below (every host that honours the key holds it),
70
+ add a `Skill(<name>)` deny rule to `.claude/settings.json` for Claude Code and `"<name>": "ask"` under
71
+ `permission.skill` in `opencode.json` for OpenCode, all re-applied on every run because BMad's installer
72
+ rewrites its own wrappers. On a host with no lock at all, the `AGENTS.md` method block — mirrored into
73
+ that host's own rule file — is what forbids them. A person typing `/bmad-build` still gets
74
+ it: the method retires a default, it does not confiscate a tool. The list lives in
75
+ `bin/wdi-method.js` as `BMAD_RETIRED_G5`, and a test fails when this table and that array disagree.
76
+
77
+ | Skill | Replaced by | Why |
78
+ |---|---|---|
79
+ | `bmad-spec` | `to-spec` | **Retired.** The contract below G5 is no longer BMad's. Its `_bmad/custom/*.toml` override is withdrawn and `update` removes any still installed |
80
+ | `bmad-build` · `bmad-build-auto` | `implement` · `wdi-autopilot` | **Retired.** `bmad-build` describes itself as implementing "any user intent, requirement, story, bug fix or change request" — the most inviting description in the repo's skill index, for the one thing this method owns most tightly. `bmad-build-auto` is an unattended loop, which is `wdi-autopilot`'s |
81
+ | `bmad-code-review` | `code-review` | **Retired.** The panel at Step 3 is a separate dispatch by a different agent; BMad's own review layers are the builder reviewing itself |
82
+ | `bmad-retrospective` | — | **Retired** with `RTR-` and `V19`. A frozen `RTR-` file stays where it is |
83
+ | `bmad-agent-dev` | `implement` | **Retired.** "Senior software engineer for story execution and code implementation" is `implement`'s sentence |
84
+ | `bmad-create-epics-and-stories` | `to-tickets` | **Retired**, and not merely by preference: the `epics` level between a spec and its tickets is **repealed in code** — `validate.py` reads a flat `tickets:` list. A skill whose only output is a shape nothing reads |
85
+ | `bmad-create-story` · `bmad-dev-story` · `bmad-dev-auto` · `bmad-quick-dev` | `implement` | **Retired.** BMad deprecated all four in favour of `bmad-build`, which is itself retired here. An alias to a retired skill is retired |
86
+ | `bmad-sprint-planning` · `bmad-sprint-status` | the ticket itself | **Retired.** The sprint route keeps status in a hand-edited file; this method reads status from the ticket — `bmad-guide.md` owns the reasoning |
87
+
88
+ ### Not used for other reasons — not enforced, and not G5's
89
+
90
+ These are outside the enforced list above: nothing locks them, because nothing here replaces them and
91
+ none of them competes for G5's work.
92
+
93
+ | Skill | Why |
94
+ |---|---|
95
+ | `bmad-editorial-review*` · `bmad-review-*` | Shims onto `bmad-review` lenses. Ask for the lens, not the shim |
96
+ | `bmad-document-project` · `bmad-generate-project-context` | Forward to `bmad-project-context`. This repo's agent instructions are maintained by hand |
97
+ | Any skill named as a **gate condition** | A gate is passed by its checklist and its validators, never by a skill having run |
98
+
99
+ ## The class that decides where output lands
100
+
101
+ `bmad-guide.md` owns the class definitions; what matters here is that **class B** exists because some skills
102
+ write several things at once that belong to different layers. `bmad-ux` is the case: `EXPERIENCE.md` is a
103
+ promise and `DESIGN.md` is a build detail, and no configuration can send them to two places. Its output
104
+ lands in a neutral folder first, and `wdi-ux` places it.
105
+
106
+ Which skill lands which output is the ownership table in `corpus-guide.md`, and it MUST NOT be duplicated
107
+ here.
@@ -1976,10 +1976,65 @@ def corpus_in_git(c: Corpus, r: Result) -> None:
1976
1976
  pass
1977
1977
 
1978
1978
 
1979
- ENGINE_HOMES = (".claude", ".agents", ".agent", ".cursor", ".codex")
1980
1979
  ENGINE_FLAGGED = ("to-spec", "to-tickets", "implement")
1981
1980
  ENGINE_SKILLS = ENGINE_FLAGGED + ("tdd", "code-review", "domain-modeling")
1982
1981
  FLAG_RE = re.compile(r"^disable-model-invocation\s*:\s*true", re.M)
1982
+ STAMP = Path(".control") / "wdi-method.yaml"
1983
+ HOST_ID_RE = re.compile(r"^\s+-\s+id:\s*([A-Za-z0-9_.-]+)\s*$")
1984
+ HOST_READS_RE = re.compile(r"^\s+reads:\s*\[(.*)\]\s*$")
1985
+
1986
+
1987
+ def _skill_roots(root: Path) -> list[Path]:
1988
+ """Every folder in the repo that may hold skills — matched by PATTERN, not by a list of hosts.
1989
+
1990
+ The list this replaced named five folders while the installer offered forty hosts, so engines
1991
+ installed for Kiro, Cline, or Trae were reported as no engines at all. Every `.<host>/skills` at
1992
+ the root counts, plus every directory a host in the stamp's `hosts:` is recorded to read.
1993
+ """
1994
+ found: dict[str, Path] = {}
1995
+ try:
1996
+ entries = sorted(root.iterdir())
1997
+ except OSError:
1998
+ entries = []
1999
+ for entry in entries:
2000
+ if entry.name.startswith(".") and entry.name != ".git" and (entry / "skills").is_dir():
2001
+ found[f"{entry.name}/skills"] = entry / "skills"
2002
+ for reads in _stamp_hosts(root).values():
2003
+ for rel in reads:
2004
+ if (root / rel).is_dir():
2005
+ found.setdefault(rel, root / rel)
2006
+ return list(found.values())
2007
+
2008
+
2009
+ def _stamp_hosts(root: Path) -> dict[str, list[str]]:
2010
+ """`hosts:` from `.control/wdi-method.yaml` — host id → the skill folders it reads.
2011
+
2012
+ The installer writes it from `lib/platforms.mjs`; this reads it so the two never keep separate
2013
+ lists. An older stamp has no `hosts:`, and the check then falls back to "anywhere in the repo".
2014
+ """
2015
+ path = root / STAMP
2016
+ if not path.is_file():
2017
+ return {}
2018
+ out: dict[str, list[str]] = {}
2019
+ current = None
2020
+ in_hosts = False
2021
+ for line in path.read_text(encoding="utf-8", errors="replace").splitlines():
2022
+ if re.match(r"^hosts:\s*$", line):
2023
+ in_hosts = True
2024
+ continue
2025
+ if in_hosts and line.strip() and not line.startswith(" "):
2026
+ break
2027
+ if not in_hosts:
2028
+ continue
2029
+ m = HOST_ID_RE.match(line)
2030
+ if m:
2031
+ current = m.group(1)
2032
+ out[current] = []
2033
+ continue
2034
+ m = HOST_READS_RE.match(line)
2035
+ if m and current:
2036
+ out[current] = [s.strip().strip('"').strip("'") for s in m.group(1).split(",") if s.strip()]
2037
+ return out
1983
2038
 
1984
2039
 
1985
2040
  def _engine_files(root: Path, name: str) -> list[Path]:
@@ -1990,8 +2045,8 @@ def _engine_files(root: Path, name: str) -> list[Path]:
1990
2045
  one finding read as two.
1991
2046
  """
1992
2047
  seen: dict[Path, Path] = {}
1993
- for home in ENGINE_HOMES:
1994
- path = root / home / "skills" / name / "SKILL.md"
2048
+ for home in _skill_roots(root):
2049
+ path = home / name / "SKILL.md"
1995
2050
  if not path.is_file():
1996
2051
  continue
1997
2052
  try:
@@ -2037,6 +2092,16 @@ def engines_invocable(c: Corpus, r: Result) -> None:
2037
2092
  if not installed[name]:
2038
2093
  r.fail("engines-invocable", name, "is not installed in this repo — G5 needs all six, and "
2039
2094
  "a user-level plugin does not count: its files are not this repo's to unlock")
2095
+ # Present somewhere is not present for every host. Kiro reads `.kiro/skills` and nothing else, so
2096
+ # an engine only in `.agents/skills` leaves `wdi-build` unable to run there.
2097
+ for host, reads in _stamp_hosts(c.root).items():
2098
+ for name in ENGINE_SKILLS:
2099
+ if not installed[name]:
2100
+ continue
2101
+ if not any((c.root / rel / name / "SKILL.md").is_file() for rel in reads):
2102
+ r.fail("engines-invocable", name,
2103
+ f"is not in any folder {host} reads ({', '.join(reads)}) — that host cannot "
2104
+ f"run it. `npx wdi-method engines` names the `npx skills add --agent` to use")
2040
2105
  for name in ENGINE_FLAGGED:
2041
2106
  for path in installed[name]:
2042
2107
  if FLAG_RE.search(_frontmatter(path.read_text(encoding="utf-8", errors="replace"))):
@@ -146,7 +146,7 @@ Named for the **gate they serve**, so *"which skill do I run"* is answered by *"
146
146
  | Skill | Its trigger |
147
147
  |---|---|
148
148
  | `wdi-daily-what-to-build` | Hand-testing notes to turn into a reviewed spec or ticket. Stops before code, commit, or push |
149
- | `wdi-daily-autopilot` | Start the daily loop: checks for an accepted mandate (preflight if none), resolves reviewers, launches `/loop` over `wdi-autopilot` |
149
+ | `wdi-daily-autopilot` | Start the daily loop: checks for an accepted mandate (preflight if none), resolves reviewers, starts the host's own scheduler over `wdi-autopilot` (one iteration where the host has none) |
150
150
  | `wdi-daily-what-to-test` | After a merge: sync, prune merged branches, prepare the app, build the hand-test checklist |
151
151
  | `wdi-prune-or-archive` | Closed specs to archive or prune, through `lifecycle.py` |
152
152
 
@@ -56,9 +56,26 @@ others leaves a method that cannot run:
56
56
  | Set | Note |
57
57
  |---|---|
58
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 |
59
+ | `.<host>/skills/wdi-*/` for every host selected at install | Every wrapper. A wrapper without its guide, or a guide without its wrapper, is half a method |
60
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` |
61
+ | `AGENTS.md`, and each rule file a selected host reads beside it | The routing table is the method; from `## Code` down is the product. `install` / `update` MUST NOT overwrite an existing `AGENTS.md` |
62
+
63
+ ## One method, many hosts
64
+
65
+ The method runs on every host the installer offers, and each host differs in five ways that matter.
66
+ `lib/platforms.mjs` in the package is the one record of them; `install` writes the selected hosts into
67
+ `.control/wdi-method.yaml` under `hosts:`, and the skills and `validate.py` read them from there.
68
+
69
+ | Difference | What the method does about it |
70
+ |---|---|
71
+ | **Where skills are read** (`reads:`) | The `wdi-*` skills go to each host's own folder. The six engines MUST be in a folder every selected host reads — Kiro reads only `.kiro/skills` — and `npx wdi-method engines` names the `npx skills add --agent` that puts them there |
72
+ | **How a skill is loaded** | Through the host's own mechanism: a skill tool where it has one, otherwise reading the whole `SKILL.md`. Both are invocation; a paraphrase is neither |
73
+ | **How a person types one** (`invoke:`) | `/name`, `$name`, `/skill:name`, `@name`, or asked for by name. `wdi-help` names the next skill in this host's form |
74
+ | **Manual-only** (`manual_only:`) | Three layers. The host's own lock where it has one (`disable-model-invocation`; `.claude/settings.json` deny rules; `opencode.json` `ask`). A guard line at the top of each manual-only skill. The `AGENTS.md` block, mirrored into every rule file a host reads. On a host with no lock the last two are all there is, and that is the host's limit, not a gap in the install |
75
+ | **A scheduler of its own** (`loop:`) | `wdi-daily-autopilot` and `wdi-autopilot` start it where it exists. Where it does not, they run one iteration per invocation — a shell loop or an OS scheduler is not a substitute |
76
+
77
+ A host the method dropped is named by `update` and left alone: its folders may hold the product's own
78
+ files too, so removing them is the owner's call.
62
79
 
63
80
  ## Two directions
64
81
 
@@ -43,8 +43,8 @@ NOT start the loop while any row in the first two groups is red.
43
43
  | **Engines** | BMad installed; every `wdi-*` skill the run will call present | A wrapper is missing — name it and `npx wdi-method update` |
44
44
  | | 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 |
45
45
  | | 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 |
46
- | | 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 |
47
- | | 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 |
46
+ | | The retired BMad G5 wrappers are locked out of model invocation wherever this host offers a lock (`.claude/settings.json` deny rules, `opencode.json` `ask`) | Any still invocable. Same fix — BMad's installer restores its wrappers whenever it runs |
47
+ | | This skill and `wdi-build` are themselves invocable — on Claude Code, 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 |
48
48
  | | 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 |
49
49
  | | 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 |
50
50
  | | `.constitution/project/codebase-stack-guide.md` names build and test commands, **and the test command exits 0 here** (prefer quiet output flags, e.g. `-- --quiet`, to keep context compact; on non-zero exit, surface the failure details and abort preflight) | Absent or failing. Every ticket's "full suite green once" and the smoke test read it. Found at minute one, not at hour six |
@@ -57,8 +57,8 @@ NOT start the loop while any row in the first two groups is red.
57
57
  | **Settings** | `scope` — the `FR` ids to deliver, or `all` | — (default `all` open `FR`) |
58
58
  | | `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) |
59
59
  | | `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) |
60
- | | `loop` — the interval between iterations | — (default `5m`) |
61
- | | `expires` — the date the mandate lapses | — (default 7 days from today; a `/loop` task expires then too) |
60
+ | | `loop` — the interval between iterations | — (default `5m`). On a host with no scheduler of its own (`loop: none` in `hosts:`) the row reads **once** — see § Starting the loop |
61
+ | | `expires` — the date the mandate lapses | — (default 7 days from today; a scheduled task expires then too) |
62
62
  | | Where the ledger and the final report will be written | — |
63
63
  | | 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 |
64
64
  | **Runtime** | The session runs with permission prompts bypassed | Cannot be verified from inside the session. Printed as a line the owner confirms |
@@ -69,15 +69,16 @@ the same rule the installer follows. A preflight that asks fourteen questions on
69
69
 
70
70
  ### The engines are invoked — there is no route to find
71
71
 
72
- `to-spec`, `to-tickets` and `implement` ship with `disable-model-invocation: true`, which blocks the Skill
73
- tool for this session and every subagent, and no setting lifts it: the gate reads the frontmatter and
74
- consults nothing else. Two releases of this skill worked around that by reading the engine's `SKILL.md`
75
- and carrying out its process. **That route is retired.** The engines are installed in the repo, the
76
- installer strips the flag from the repo's own copies, and `wdi-build` invokes them like any other skill.
72
+ `to-spec`, `to-tickets` and `implement` ship with `disable-model-invocation: true`. Where the host
73
+ honours that key it blocks every model-initiated load, and no setting lifts it. The engines are installed
74
+ in the repo, the installer strips the flag from the repo's own copies, and `wdi-build` invokes them like
75
+ any other skill — through the host's own skill mechanism, which on a host with no skill tool is reading the
76
+ engine's whole `SKILL.md` from the repo (`wdi-build` § All six engines).
77
77
 
78
- What preflight checks is therefore not *which route exists* but *whether the flag is back* — `npx skills
79
- update` restores the author's file byte for byte, and `engines-invocable` in `validate.py` is red when it
80
- has. A stalled Phase 2 three hours into an unattended run is what this replaces.
78
+ What preflight checks is therefore not *which route exists* but *whether the flag is back* and *whether
79
+ this host can see the engines* — `npx skills update` restores the author's file byte for byte, an engine
80
+ installed for one host is invisible to another, and `engines-invocable` in `validate.py` is red for both.
81
+ A stalled Phase 2 three hours into an unattended run is what this replaces.
81
82
 
82
83
  The `to-tickets` quiz — granularity and blocking edges — is still **answered by this skill**: ticket
83
84
  count from the size table in `delivery-flow-guide.md`, edges from `depends_on` and `touches`. The answers
@@ -96,19 +97,31 @@ On the owner's confirmation, and not before:
96
97
  `smoke_test` · `loop` · `expires` — live **only** on its row in `decisions.yaml`; the file carries
97
98
  Decision, Why, and Cost, and points at the row. One fact, one home.
98
99
  2. Write the ledger header — see § The ledger.
99
- 3. Start the loop. In Claude Code, invoke the `loop` skill with `<interval> /wdi-autopilot`. Where that is
100
- not available, print the command for the owner to type, and name the alternative the platform has:
100
+ 3. Start the loop — § Starting the loop.
101
101
 
102
- ```
103
- /loop 5m /wdi-autopilot
104
- ```
102
+ ### Starting the loop
103
+
104
+ The loop is the **host's own scheduler**, and nothing else counts: a shell `while`, an OS cron job, or a
105
+ second agent firing this one is not a loop this skill starts. Read this host's `loop:` from `hosts:` in
106
+ `.control/wdi-method.yaml` (the entry whose `id` is the host running this session):
107
+
108
+ | `loop:` | What this skill does |
109
+ |---|---|
110
+ | `{kind: command, how: …}` | Types the command, filling `{interval}` and `{prompt}` (`/wdi-autopilot`) — e.g. `/loop 5m /wdi-autopilot` on Claude Code |
111
+ | `{kind: scheduler, how: …}` | Creates the schedule the way `how` names it, with the same interval and prompt |
112
+ | `none` | **Runs one iteration now**, in this turn (Door 2), and reports that this host has no scheduler: the next iteration starts when the owner invokes this skill again. The mandate, the ledger, and the branch carry over unchanged, so each invocation resumes where the last stopped |
113
+
114
+ A host missing from `hosts:` (an old stamp) is treated as `none`. The `none` row is not a lesser run: one
115
+ iteration works as far as it safely can, exactly as a scheduled one does, and stops only at the same three
116
+ stops.
105
117
 
106
118
  The interval is the **pause between** iterations, not the length of one. An iteration that outlives it
107
- finishes first; the next firing waits.
119
+ finishes first; the next firing waits. "Cancel the loop", wherever this skill says it, means cancelling
120
+ that scheduled task; where there is none, it means nothing further is started.
108
121
 
109
122
  **Session survivability across environments:**
110
123
  - **Linux / Remote SSH:** Run inside a session manager such as `tmux` (`tmux new -s autopilot`) or `screen` before starting the loop. Disconnecting SSH or closing the terminal then leaves the autonomous loop running unharmed.
111
- - **Windows (PowerShell / Windows Terminal):** `tmux` is not native to Windows PowerShell. Run the session in a dedicated persistent Windows Terminal tab or window left active, or via background subagent tools (`run_in_background`). Do not invoke or require `tmux` on Windows environments.
124
+ - **Windows (PowerShell / Windows Terminal):** `tmux` is not native to Windows PowerShell. Run the session in a dedicated persistent Windows Terminal tab or window left active. Do not invoke or require `tmux` on Windows environments.
112
125
 
113
126
  ## Door 2 — One iteration
114
127
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: wdi-build
3
- description: Use at G5 Release — one spec from open to closed in one supervised run. Opens the spec, hands the owner to-spec and to-tickets, ships every ticket to a green PR through a five-step pipeline, then closes the spec. One invocation, not four.
3
+ description: Use at G5 Release — one spec from open to closed in one supervised run. Opens the spec, drives to-spec and to-tickets, ships every ticket to a green PR through a five-step pipeline, then closes the spec. One invocation, not four.
4
4
  ---
5
5
 
6
6
  # WDI Build
@@ -16,29 +16,37 @@ without them. Thirteen BMad skills are **retired** at this gate and MUST NOT be
16
16
  `bmad-spec`, `bmad-build`, `bmad-build-auto`, `bmad-code-review`, `bmad-retrospective`,
17
17
  `bmad-agent-dev`, `bmad-create-epics-and-stories`, `bmad-create-story`, `bmad-dev-story`,
18
18
  `bmad-dev-auto`, `bmad-quick-dev`, `bmad-sprint-planning`, `bmad-sprint-status`. That is enforced, not
19
- requested: `install` and `update` lock each one out of model invocation and add a `Skill()` deny rule.
20
- `bmad-skill-register.md` carries the list and the criterion behind it.
21
-
22
- **All five engines are INVOKED, by this skill, through the Skill tool.** Upstream ships `to-spec`,
23
- `to-tickets` and `implement` with `disable-model-invocation: true`; `wdi-method` strips it from the
24
- copies this repo owns, so there is no command to hand to the owner and no reading-and-following to do.
25
- Where an engine needs a decision — the seams, the `to-tickets` quiz — that decision is made before the
26
- invocation and passed IN it, because an engine that stops to ask inside an unattended run is a run
27
- that stalls with nobody there to answer.
19
+ requested: `install` and `update` lock each one out of model invocation wherever the host offers a lock
20
+ (`disable-model-invocation`, `.claude/settings.json` deny rules, `opencode.json` `ask`), and the
21
+ `AGENTS.md` block forbids them on every host. `bmad-skill-register.md` carries the list and the
22
+ criterion behind it.
23
+
24
+ **All six engines are INVOKED, by this skill, through the host's own skill mechanism.** Which mechanism
25
+ that is belongs to the host, not to this skill: a skill tool where the host has one (Claude Code's
26
+ `Skill`, OpenCode's `skill`, Gemini's `activate_skill`), and where the host has none — Kiro, Codex,
27
+ Cursor, and most others — loading the engine is reading its `SKILL.md` **in full, from the repo's
28
+ own copy**, and carrying it out. That is not a workaround on those hosts; it is the only way they load any
29
+ skill. `hosts:` in `.control/wdi-method.yaml` says where this host reads skills. Upstream ships
30
+ `to-spec`, `to-tickets` and `implement` with `disable-model-invocation: true`; `wdi-method` strips it
31
+ from the copies this repo owns, so on every host this skill drives the engines itself and hands no command
32
+ to the owner. Where an engine needs a decision — the seams, the `to-tickets` quiz — that decision is
33
+ made before the invocation and passed IN it, because an engine that stops to ask inside an unattended run
34
+ is a run that stalls with nobody there to answer.
28
35
 
29
36
  **If an engine will not invoke, stop and say why.** `disable-model-invocation` back in its frontmatter
30
37
  is what `npx skills update` does, and the fix is one command: `npx wdi-method engines --fix`, or the
31
- `wdi-init` / `wdi-upgrade` skill. MUST NOT work around it by pasting the engine's process inline: the
32
- engine's rules are its own, and a paraphrase of them is not the engine.
38
+ `wdi-init` / `wdi-upgrade` skill. An engine missing from every folder this host reads is the other
39
+ cause, and `npx wdi-method engines` names the `npx skills add --agent` that fixes it. MUST NOT work
40
+ around either by paraphrasing the engine from memory, summarising it into a brief, or reading a copy from
41
+ outside the repo: the engine's rules are its own, and anything short of its whole `SKILL.md` is not the
42
+ engine.
33
43
 
34
44
  **Under an active mandate the owner's part is `wdi-autopilot`'s.** A `DEC-` of `type: mandate` at
35
45
  `status: accepted`, unexpired, moves **every** "the owner runs" and "the owner decides" in this skill to the
36
46
  coordinator — G5's checklist and Step 2's *stop and reach the owner* included, which reach the coordinator and
37
- not a person. Three of them change **shape** as well as owner: the engines run by **read-and-follow** — a builder brief
38
- that names the engine's `SKILL.md` path and carries out its process — or from a copy in the repo, and the ledger
39
- names which; the seams, the `to-tickets` quiz, and § When the code turns out to be right are decided by the
47
+ not a person. Two of them change **shape** as well as owner: the seams, the `to-tickets` quiz, and § When the code turns out to be right are decided by the
40
48
  coordinator and written to the ledger, one row each; and whatever the mandate lists as `parked` still stops,
41
- reported for the owner rather than decided. One thing changes **shape** rather than owner: a mandate is one
49
+ reported for the owner rather than decided. The engines are invoked exactly as above, mandate or not. One thing changes **shape** rather than owner: a mandate is one
42
50
  unit of work and reaches the active development branch (`policy.development_branch`, default `main`) through **one PR**, so Step 4 commits the ticket to the run branch instead of
43
51
  opening a PR per ticket, and Step 5 splits: the coordinator pushes the run branch at every spec close, but
44
52
  **the cloud run happens once, at `wdi-autopilot` § Finish** — every intermediate push starts nothing, and
@@ -224,7 +232,7 @@ is not.
224
232
 
225
233
  ### Step 2 — build
226
234
 
227
- - The owner runs `/implement`, and it MUST be given the ticket and the three brief rules above.
235
+ - This skill invokes `implement` (as § All six engines says), and it MUST be given the ticket and the three brief rules above.
228
236
  - It commits to the current branch and **never pushes**. That is its own behaviour and it is what we want; the
229
237
  coordinator is the hand that pushes.
230
238
  - **`/implement` calls `/code-review` itself, and that call does NOT satisfy Step 3.** It is the builder
@@ -385,8 +393,9 @@ only thing `V19` checked.
385
393
  - Amending what a ticket `satisfies` to make a must-fix go away
386
394
  - A ticket that slices one layer instead of cutting through all of them, outside a wide refactor
387
395
  - Running a wide refactor's batches in parallel
388
- - Claiming this skill invoked `to-spec`, `to-tickets`, or `implement` — it cannot; the owner runs them, or under
389
- a mandate a builder reads and follows them, and the ledger says so
396
+ - Paraphrasing `to-spec`, `to-tickets`, or `implement` from memory, or summarising one into a brief, and
397
+ calling that the engine — on a host with no skill tool the engine is its whole `SKILL.md`, read from the repo
398
+ - Stopping because the host has no `Skill` tool — that host loads skills by reading them, and so does this skill
390
399
  - A builder editing `.what/`, `.how/`, or an `applied` `DEC-` to make its code fit
391
400
  - Fixing a failing test without knowing why it failed
392
401
  - Opening a PR with an unresolved must-fix, or before the ticket-closing checklist is answered
@@ -1,15 +1,17 @@
1
1
  ---
2
2
  name: wdi-daily-autopilot
3
- description: Compose and launch the autonomous daily loop routine (default 10m interval) with self code-review and peer-review runners resolved from local configuration. Invoke as `/wdi-daily-autopilot [self-review] [peer] [interval] [--skip-peer-review|--no-review]` (`[self-review]` alias `[in-session]`).
3
+ description: Compose and launch the autonomous daily loop routine (default 10m interval, on the host's own scheduler; once where the host has none) with self code-review and peer-review runners resolved from local configuration. Invoke as `/wdi-daily-autopilot [self-review] [peer] [interval] [--skip-peer-review|--no-review]` (`[self-review]` alias `[in-session]`).
4
4
  disable-model-invocation: true
5
5
  ---
6
6
 
7
7
  # WDI Daily Autopilot Launch
8
8
 
9
+ > **Typed by the owner, or not at all.** Run this skill only when the person typed `wdi-daily-autopilot` — `/wdi-daily-autopilot` or this host's own syntax for it — in the turn that is running. Reached any other way (a description that looked relevant, another skill, a subagent), stop and name it instead. Hosts that can hold a skill to manual-only already do; on the others, this line is the lock.
10
+
9
11
  Composes the autonomous daily engineering routine, verifies or initiates the owner-accepted mandate
10
12
  required by `wdi-autopilot`, resolves coordinator self code-review and independent peer-review dispatch
11
- from local configuration or agent rules, and launches the execution via `/loop <interval>` (default
12
- `10m`).
13
+ from local configuration or agent rules, and launches the execution on the host's own scheduler (default
14
+ `10m`) — or, on a host that has none, runs one iteration now.
13
15
 
14
16
  `/wdi-daily-autopilot [self-review] [peer] [interval] [--skip-peer-review|--no-review]`:
15
17
  - `[self-review]` — coordinator self code-review pass model (`default` or explicit model slug; alias `[in-session]`).
@@ -53,9 +55,10 @@ Inspect the repository for `.control/custom-dispatch.yaml` (if not found in the
53
55
  Guardrail: coordinator direct implementation MUST NOT eliminate independent peer review when any component the mandate touches has `risk_accepted: low`. There `low` is the hardest review: `wdi-build` Step 3 requires a two-reviewer panel of agents that are not the builder (`delivery-flow-guide.md`). The coordinator MUST NOT honour a peer-review bypass (`roles.reviewer: none`, `review_policy.peer_review: false`, `--skip-peer-review`, or `--no-review`) when any touched component has `risk_accepted: low`: stop and report which components block it (fail-closed). When every touched component is `medium` or `high`, the bypass is allowed, and the choice MUST be recorded in the mandate text (step 4) and in the ledger.
54
56
  - Resolve runner dispatch by `type:` for reviewer and deep analyst:
55
57
  - `auto`: Evaluates whether the runner's target model is reachable in-session from the active
56
- session profile (per the caller's global agent collaboration rules). Dispatches in-session via `Agent`
57
- if reachable; falls back to shell-out using `command` if unreachable in-session.
58
- - `in-session`: Dispatches strictly via in-session `Agent` subagent.
58
+ session profile (per the caller's global agent collaboration rules). Dispatches through this host's
59
+ own read-only subagent tooling if reachable; falls back to shell-out using `command` if unreachable in-session.
60
+ - `in-session`: Dispatches strictly through this host's own subagent tooling (read-only). A host with
61
+ none cannot satisfy it — stop and report (fail-closed).
59
62
  - `shell-out`: Executes the external shell-out `command` (single-string command). If `command` is absent
60
63
  or empty, stop and report immediately (fail-closed).
61
64
  - **If `.control/custom-dispatch.yaml` does not exist**:
@@ -123,17 +126,25 @@ self-review and self-verification without external peer dispatch.
123
126
 
124
127
  ## 5. Launch
125
128
 
126
- Invoke the `loop` skill with `<resolved interval> /wdi-autopilot <composed text from step 4>`. This
127
- starts the loop execution.
129
+ Read this host's `loop:` from `hosts:` in `.control/wdi-method.yaml` (the entry whose `id` is the host
130
+ running this session) and launch the way `wdi-autopilot` § Starting the loop says:
131
+
132
+ - **`kind: command` or `kind: scheduler`** — start the host's own scheduler with `<resolved interval>` and
133
+ the prompt `/wdi-autopilot <composed text from step 4>` (the host's own invocation syntax, `invoke:` in
134
+ the same entry, replaces `/wdi-autopilot` where it differs).
135
+ - **`none`** (or the host is not in `hosts:`) — do not look for a substitute: no shell loop, no OS
136
+ scheduler, no second agent. Run **one** iteration of `wdi-autopilot` now, in this turn, with the composed
137
+ text. The mandate the owner already accepted (step 3) is the go-ahead; nothing more is asked.
128
138
 
129
139
  ## 6. Verify Immediate Execution
130
140
 
131
- Before finishing, verify that `/wdi-autopilot` was invoked in this same turn for the first iteration
132
- rather than remaining idle until the first cron interval tick. If it did not run immediately, invoke
133
- `/wdi-autopilot` now to start the first iteration.
141
+ Before finishing, verify that `wdi-autopilot` ran its first iteration in this same turn rather than
142
+ waiting for the first scheduled tick. If it did not, run it now.
134
143
 
135
144
  ## 7. Report and Stop
136
145
 
137
146
  Report the resolved configuration (in-session mechanism, peer review status, active mandate ID, and
138
- loop interval), confirm that the loop is active, and stop. MUST NOT intervene in or micromanage
139
- subsequent loop iterations.
147
+ loop interval — or `once: this host has no scheduler`), and stop. Where a schedule is running, MUST NOT
148
+ intervene in or micromanage subsequent iterations. Where it ran once, the report ends with the one line
149
+ the owner needs: invoke this skill again to run the next iteration — the mandate, ledger, and run branch
150
+ carry over.