@baldurpan/create-ai-workflow 0.5.0 → 0.6.0

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 CHANGED
@@ -40,7 +40,7 @@ starting point — nothing has to be looked up first.
40
40
  | `/feature-close` | retires a feature: a `history.md` row, a `git mv` into `archive/`, and a reviewed reference sweep |
41
41
  | `/orchestrate` | one ad-hoc, commit-sized change through the same gates — no entry, no ledger |
42
42
  | `/prototype` | a throwaway HTML/CSS mockup under `prototypes/`, to settle a layout question before a plan commits to it — no gates, no application code |
43
- | `/onboard` | fills in your own stubs, adopting what the repo already documented and running each verification command before writing it down |
43
+ | `/onboard` | fills in your own stubs, adopting what the repo already documented, indexing where it documents itself, and running each verification command before writing it down |
44
44
 
45
45
  ## What makes it different
46
46
 
@@ -63,6 +63,13 @@ the agent does — and every command that lands code reads it before closing out
63
63
  commits*: a tool installed into a repository it knows nothing about does not get to write that
64
64
  repository's history unasked. Branches, pushes and pull requests are outside the workflow entirely.
65
65
 
66
+ **Documentation is part of the change.** A plan starts by finding where the project explains itself —
67
+ `context/stack.md` holds that index, `/onboard` fills it by sweeping the tree and asking what is published
68
+ elsewhere — and every plan carries a §7 naming what the feature makes untrue there. Each row is assigned to
69
+ a phase, and its path goes on that phase's `Files:` line, so the README lands with the rename rather than
70
+ after it. Docs are the one output with no gate behind them: nothing fails when a page keeps describing a
71
+ flag that no longer exists.
72
+
66
73
  **A finding outlives the session that found it.** A reviewer `FAIL` or a capped gate is written to
67
74
  `context/findings.md` *before* the loopback, so it survives the conversation ending. An open `P0`/`P1`
68
75
  blocks its phase from being marked `done` and blocks `/feature-close`.
@@ -109,6 +116,22 @@ npx @baldurpan/create-ai-workflow update --force # back up edited files (.ba
109
116
  | missing | restores |
110
117
  | not in the manifest | nothing — it cannot reach it |
111
118
 
119
+ **Run `/onboard` after an update.** That last row is the whole reason: a new version's tool-owned files can
120
+ expect something of a project-owned one — a section of `context/stack.md` that every plan now reads, a
121
+ `context/git.md` older than the file itself — and the updater is forbidden to write either. So it ends by
122
+ naming each gap and stops:
123
+
124
+ ```
125
+ Next
126
+ ! context/stack.md has no "Documentation" section — this version's stub has one
127
+ ! context/git.md is missing — a stub is project-owned, so update cannot write one
128
+ Run /onboard in your agent. It is re-runnable, and it is the only thing that
129
+ reaches these files — the commands above now read them.
130
+ ```
131
+
132
+ It is a note, not a failure — the exit code is the conflict count's to set. A tool that failed an update
133
+ over the shape of a file it may not touch would be calling someone else's business its own breakage.
134
+
112
135
  ## Standards
113
136
 
114
137
  `context/standards/` ships a vendored default, and `context/standards/README.md` holds a
@@ -6,6 +6,13 @@
6
6
  export function stripComments(text) {
7
7
  return text.replace(/<!--[\s\S]*?-->/g, (match) => match.replace(/[^\n]/g, ' '));
8
8
  }
9
+ /**
10
+ * Blank out fenced code blocks, preserving line count. A `##` inside a fence is an illustration — the
11
+ * stubs sketch a directory layout in one — not a heading of the document.
12
+ */
13
+ export function stripFences(text) {
14
+ return text.replace(/^```[\s\S]*?^```/gm, (match) => match.replace(/[^\n]/g, ' '));
15
+ }
9
16
  function splitCells(line) {
10
17
  return line
11
18
  .trim()
package/dist/cli.js CHANGED
@@ -10,7 +10,8 @@ const USAGE = `${bold('create-ai-workflow')} — overlay a tiered planning workf
10
10
  ${bold('Usage')}
11
11
  npx @baldurpan/create-ai-workflow install into this repository
12
12
  npm create @baldurpan/ai-workflow the same thing, shorter
13
- npx @baldurpan/create-ai-workflow update replace the tool-owned files with this version
13
+ npx @baldurpan/create-ai-workflow update replace the tool-owned files with this version,
14
+ and name what only ${cyan('/onboard')} can fill
14
15
  npx @baldurpan/create-ai-workflow standards add <url> swap context/standards/ for a git repository
15
16
  npx @baldurpan/create-ai-workflow check report structural breakage; never writes
16
17
 
@@ -2,9 +2,10 @@ import { copyFileSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'no
2
2
  import path from 'node:path';
3
3
  import { apply as applyBlock, BlockConflictError, inspect } from "../agents-block.js";
4
4
  import { AGENTS_BLOCK_KEY, DEFAULT_ADAPTERS, STANDARDS_PREFIX, agentsBlockBody, managedFiles, renderManaged, } from "../layout.js";
5
- import { bold, cyan, dim, green, info, red, UserError, warn, yellow } from "../log.js";
5
+ import { bold, cyan, dim, green, info, red, UserError, yellow } from "../log.js";
6
6
  import { readManifest, writeManifest } from "../manifest.js";
7
7
  import { exists, hash, packageVersion } from "../paths.js";
8
+ import { stubGaps } from "../stubs.js";
8
9
  const LABEL = {
9
10
  replace: green('update '),
10
11
  restore: green('restore'),
@@ -138,9 +139,11 @@ export function update(root, options) {
138
139
  info();
139
140
  info(`${yellow('!')} the bundled standards moved: ${dim(installedRef.slice(0, 8))} → ${dim(bundledRef.slice(0, 8))}`);
140
141
  }
142
+ const gaps = stubGaps(root);
141
143
  if (options.dryRun) {
142
144
  info();
143
145
  info(dim('--dry-run: nothing was written.'));
146
+ reportStubGaps(gaps);
144
147
  return conflicts.length > 0 && !options.force ? 1 : 0;
145
148
  }
146
149
  if (conflicts.length > 0 && !options.force) {
@@ -201,8 +204,30 @@ export function update(root, options) {
201
204
  writeManifest(root, manifest);
202
205
  info();
203
206
  info(`${green('done')} ${written} file${written === 1 ? '' : 's'} written. Review the diff — nothing was committed.`);
207
+ reportStubGaps(gaps);
204
208
  return 0;
205
209
  }
210
+ /**
211
+ * What this version's stubs expect and the install does not have. Printed last, because it is the only
212
+ * part of an update that needs a person: everything above it has already happened, and nothing here can.
213
+ *
214
+ * This is a note, never an error — the exit code is the conflict count's to set. A tool that fails an
215
+ * update over the shape of a file it is forbidden to touch would be reporting someone else's business as
216
+ * its own breakage.
217
+ */
218
+ function reportStubGaps(gaps) {
219
+ if (gaps.length === 0)
220
+ return;
221
+ info();
222
+ info(bold('Next'));
223
+ for (const gap of gaps) {
224
+ info(gap.section === undefined
225
+ ? ` ${yellow('!')} ${gap.dest} ${dim('is missing — a stub is project-owned, so update cannot write one')}`
226
+ : ` ${yellow('!')} ${gap.dest} ${dim(`has no "${gap.section}" section — this version's stub has one`)}`);
227
+ }
228
+ info(` Run ${cyan('/onboard')} in your agent. ${dim('It is re-runnable, and it is the only thing that')}`);
229
+ info(` ${dim('reaches these files — the commands above now read them.')}`);
230
+ }
206
231
  function describeBad(state) {
207
232
  return state.kind === 'duplicate'
208
233
  ? `${state.count} ai-workflow blocks in AGENTS.md — delete the extra one`
package/dist/layout.js CHANGED
@@ -93,15 +93,22 @@ export function managedFiles(adapters) {
93
93
  }
94
94
  return files;
95
95
  }
96
- /** Project-owned files. Written once, at install, and never reachable by `update`. */
96
+ /**
97
+ * Project-owned files. Written once, at install, and never reachable by `update`.
98
+ *
99
+ * `onboard` marks the four whose content a person supplies, through `/onboard`. The other three are
100
+ * written by the workflow as it runs — a roadmap entry, a history row, a finding — so a question about
101
+ * their shape is `check`'s, and pointing at `/onboard` for one of them would name a command that does not
102
+ * touch it.
103
+ */
97
104
  export const STUBS = [
98
- { source: 'stubs/stack.md', dest: 'context/stack.md' },
99
- { source: 'stubs/verify.md', dest: 'context/verify.md' },
100
- { source: 'stubs/executors.md', dest: 'context/executors.md' },
101
- { source: 'stubs/git.md', dest: 'context/git.md' },
102
- { source: 'stubs/roadmap.md', dest: 'context/roadmap.md' },
103
- { source: 'stubs/history.md', dest: 'context/history.md' },
104
- { source: 'stubs/findings.md', dest: 'context/findings.md' },
105
+ { source: 'stubs/stack.md', dest: 'context/stack.md', onboard: true },
106
+ { source: 'stubs/verify.md', dest: 'context/verify.md', onboard: true },
107
+ { source: 'stubs/executors.md', dest: 'context/executors.md', onboard: true },
108
+ { source: 'stubs/git.md', dest: 'context/git.md', onboard: true },
109
+ { source: 'stubs/roadmap.md', dest: 'context/roadmap.md', onboard: false },
110
+ { source: 'stubs/history.md', dest: 'context/history.md', onboard: false },
111
+ { source: 'stubs/findings.md', dest: 'context/findings.md', onboard: false },
105
112
  ];
106
113
  export const STUB_DIRS = ['context/drafts', 'context/plans', 'context/archive'];
107
114
  export function readTemplate(source) {
package/dist/stubs.js ADDED
@@ -0,0 +1,51 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import path from 'node:path';
3
+ import { stripComments, stripFences } from "./check/markdown.js";
4
+ import { readTemplate, STUBS } from "./layout.js";
5
+ import { exists } from "./paths.js";
6
+ /**
7
+ * The `##` headings of a markdown document, in order.
8
+ *
9
+ * Fenced blocks and HTML comments are blanked first: the stubs ship their examples commented out and
10
+ * `stack.md` carries a fenced layout sketch, and a heading inside either is an illustration rather than a
11
+ * section of the document.
12
+ */
13
+ export function sections(text) {
14
+ return [...stripComments(stripFences(text)).matchAll(/^## +(.+?)\s*$/gm)].map((m) => m[1]);
15
+ }
16
+ /** Backticks, case and run-together whitespace are formatting, not identity. */
17
+ function normalise(heading) {
18
+ return heading.replace(/`/g, '').replace(/\s+/g, ' ').trim().toLowerCase();
19
+ }
20
+ /**
21
+ * What this version's stubs expect that the install does not have — a stub file that is missing outright,
22
+ * or one whose sections this version has added to.
23
+ *
24
+ * `update` reports this and writes nothing. Stubs are project-owned and deliberately absent from the
25
+ * manifest, so nothing here can reach them; `/onboard` is the only thing that fills one, and until it runs
26
+ * a command can be pointed at a section of a file that does not have it.
27
+ *
28
+ * **Only the stubs `/onboard` fills are examined.** `roadmap.md`, `history.md` and `findings.md` are
29
+ * written by the workflow rather than by a person, so their shape is `check`'s question — and a report
30
+ * that named `/onboard` for a file that command never opens would be sending someone somewhere useless.
31
+ *
32
+ * A section the user deleted on purpose and one this version added look identical from here, and both are
33
+ * reported. Telling them apart would mean recording stub state in the manifest, which is the one place the
34
+ * design keeps free of project-owned files — and the fix is the same either way.
35
+ */
36
+ export function stubGaps(root) {
37
+ const gaps = [];
38
+ for (const stub of STUBS.filter((s) => s.onboard)) {
39
+ const full = path.join(root, stub.dest);
40
+ if (!exists(full)) {
41
+ gaps.push({ dest: stub.dest });
42
+ continue;
43
+ }
44
+ const have = new Set(sections(readFileSync(full, 'utf8')).map(normalise));
45
+ for (const section of sections(readTemplate(stub.source))) {
46
+ if (!have.has(normalise(section)))
47
+ gaps.push({ dest: stub.dest, section });
48
+ }
49
+ }
50
+ return gaps;
51
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@baldurpan/create-ai-workflow",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "Overlay a tiered planning workflow — roadmap, plans, phase ledgers, verification gates — onto an existing repository, for coding agents.",
5
5
  "keywords": [
6
6
  "ai",
@@ -17,7 +17,7 @@ the standing rules, and every command cites it rather than restating it.
17
17
 
18
18
  | Read | For |
19
19
  |---|---|
20
- | [`context/stack.md`](context/stack.md) | runtime, layout, conventions |
20
+ | [`context/stack.md`](context/stack.md) | runtime, layout, conventions, and where this project documents itself |
21
21
  | [`context/standards/README.md`](context/standards/README.md) | engineering standards — load per its conditional table |
22
22
  | [`context/verify.md`](context/verify.md) | the real lint / typecheck / build / test commands — the only file that names one |
23
23
  | [`context/git.md`](context/git.md) | who commits, and at what granularity — read it before closing out any change |
@@ -31,5 +31,8 @@ the working tree and the user commits it.
31
31
 
32
32
  **An open `P0` or `P1` in [`context/findings.md`](context/findings.md) blocks its phase from being `done`.**
33
33
 
34
+ **Documentation is part of the change.** Whatever a change makes untrue in this project's own docs is fixed
35
+ by the phase that makes it untrue, not by a follow-up.
36
+
34
37
  **Require evidence, not assertion.** A claim about what a file contains needs the file read, not recalled —
35
38
  yours as much as a subagent's.
@@ -33,9 +33,13 @@ The default shape below applies only when the brief names none.
33
33
  generic principles.
34
34
  2. **Read the project.** `context/stack.md` for what this repo is; `context/verify.md` for how it proves
35
35
  itself. Search the codebase and find the patterns that already exist.
36
- 3. **Verify externals.** Check documentation for every library and API involved. Cite what you confirmed.
37
- 4. **Consider.** Edge cases, error states, and implicit requirements the request did not mention.
38
- 5. **Draft.** Say *what* needs to happen, not *how* to code it.
36
+ 3. **Find the documentation.** `context/stack.md`'s Documentation section says where this project explains
37
+ itself. If it is empty, sweep for it — READMEs, `docs/`, a docs site in the tree, an API reference, a
38
+ changelog, help text in the code. Report what the change would make untrue there, per surface. An empty
39
+ index is not evidence that there are none.
40
+ 4. **Verify externals.** Check documentation for every library and API involved. Cite what you confirmed.
41
+ 5. **Consider.** Edge cases, error states, and implicit requirements the request did not mention.
42
+ 6. **Draft.** Say *what* needs to happen, not *how* to code it.
39
43
 
40
44
  ## Default output shape
41
45
 
@@ -32,7 +32,7 @@ generated "current state" file — hand-editing a ledger row changes every comma
32
32
  | [`plan-template.notes.md`](plan-template.notes.md) | what goes in each section of that skeleton | tool |
33
33
  | [`roles/coder.md`](roles/coder.md) | the coder system prompt — names no commands | tool |
34
34
  | [`standards/`](standards/README.md) | engineering standards, loaded per that README's conditional table | tool* |
35
- | [`stack.md`](stack.md) | this project's runtime, layout, conventions, and an index of your own files | project |
35
+ | [`stack.md`](stack.md) | this project's runtime, layout, conventions, where it documents itself, and an index of your own files | project |
36
36
  | [`verify.md`](verify.md) | this project's real lint / typecheck / build / test commands | project |
37
37
  | [`executors.md`](executors.md) | how this project dispatches a coder and a reviewer | project |
38
38
  | [`git.md`](git.md) | who commits the work an agent produces, and at what granularity | project |
@@ -71,6 +71,11 @@ hash, `update` walks that manifest, and a project-owned file is not in it — so
71
71
 
72
72
  `update` prints both columns when it runs. A visible boundary beats a documented one.
73
73
 
74
+ The boundary has a cost, and `update` prints that too: a new version's tool-owned files can expect
75
+ something of a project-owned one — a section of [`stack.md`](stack.md), a `git.md` that predates the
76
+ file — and nothing in the updater may write it. So it names each gap under **Next** and stops there.
77
+ Closing them is `/onboard`, which is re-runnable for exactly this reason.
78
+
74
79
  **Anything else you add under `context/` is yours forever**, by the same property — `context/decisions.md`,
75
80
  `context/glossary.md`, `context/ops-notes.md` all survive by default, with no feature required to protect
76
81
  them. Index your own additions in [`stack.md`](stack.md), not here: this file is replaced on every update,
@@ -80,3 +85,7 @@ so a line you add to it is a line you lose.
80
85
 
81
86
  Planning artifacts live in `context/`, wherever else your docs live. Product specs, API references and
82
87
  anything else written for humans or library consumers stay where this project already keeps them.
88
+
89
+ They are not out of scope for being elsewhere, though. [`stack.md`](stack.md)'s Documentation section
90
+ indexes where "elsewhere" is, so a plan can name what a feature makes untrue there and a phase can carry
91
+ the fix — the standing rule is in [`workflow.md`](workflow.md).
@@ -36,9 +36,11 @@ Written <YYYY-MM-DD>. <One line on what this is.> The `<name>` entry in
36
36
  | 1 | <name> | not started | — | |
37
37
  | 2 | <name> | not started | 1 | |
38
38
 
39
- Status is one of `not started`, `in progress`, `blocked`, `done`. `done` only when the scope landed and both
40
- gates passed, and whoever finishes a phase updates the row as part of the same change as the work — who
41
- commits that change is [`../git.md`](../git.md)'s answer, not this table's.
39
+ Status is one of `not started`, `in progress`, `blocked`, `done`. A row goes to `in progress` when work on
40
+ the phase starts, before any code, so an interrupted run leaves a ledger that says what was underway. `done`
41
+ only when the scope landed and both gates passed, and whoever finishes a phase updates the row as part of
42
+ the same change as the work — who commits that change is [`../git.md`](../git.md)'s answer, not this
43
+ table's.
42
44
 
43
45
  **Exactly one table in this document has these columns.** Do not add a second phase table — a
44
46
  differently-shaped one nearby is a decoy that gets read by mistake.
@@ -61,10 +63,22 @@ differently-shaped one nearby is a decoy that gets read by mistake.
61
63
 
62
64
  **Done when:** <a condition checkable against the repo>
63
65
 
64
- ## 7. Verification
66
+ ## 7. Documentation
67
+
68
+ <What this feature makes untrue in the project's own documentation. Start from the Documentation index in
69
+ [`../stack.md`](../stack.md), and from the repository itself if that index is empty.>
70
+
71
+ | Surface | What changes | Phase |
72
+ |---|---|---|
73
+ | <path, or the URL of a docs site> | <what it claims now that this makes wrong, or what it will not say yet> | <n> |
74
+
75
+ <If nothing changes, name the surfaces you checked and why none of them describe this. An empty section
76
+ reads as "not checked", and nothing downstream can tell those apart.>
77
+
78
+ ## 8. Verification
65
79
 
66
80
  <How to prove the feature works, beyond `context/verify.md` passing.>
67
81
 
68
- ## 8. Open questions
82
+ ## 9. Open questions
69
83
 
70
84
  - <Anything the plan could not settle. An honest gap is worth more than an invented decision.>
@@ -36,11 +36,19 @@ repo match the ledger" has no answer. A phase is a **commit-sized unit of work w
36
36
  not a category of activity — "grammar plus container support for the new token" is a phase; "testing" is
37
37
  not.
38
38
 
39
- **§7 Verification** — how to prove the feature works, beyond [`verify.md`](verify.md) passing. Commands to
39
+ **§7 Documentation** — every place this project explains itself that the feature makes wrong, out of date
40
+ or incomplete. The surfaces come from [`stack.md`](stack.md)'s Documentation index, and from a sweep of the
41
+ repository when that index is empty — an index nobody filled in is not evidence that there are no docs.
42
+ **Each row names the phase that carries it, and that phase's `Files:` line names the same path.** A
43
+ documentation row with no phase is a follow-up nobody does. If the feature genuinely changes nothing, the
44
+ section says which surfaces were checked and why: *"no surface describes this"* is an answer, and it is
45
+ distinguishable from silence only when it is written down.
46
+
47
+ **§8 Verification** — how to prove the feature works, beyond [`verify.md`](verify.md) passing. Commands to
40
48
  run by hand, files to eyeball, numbers to compare against §1's measurements. Anything that belongs to the
41
49
  project's standing verification stack goes in `verify.md` instead, not here.
42
50
 
43
- **§8 Open questions** — what the plan could not settle. Do not paper over them.
51
+ **§9 Open questions** — what the plan could not settle. Do not paper over them.
44
52
 
45
53
  ## Standing rules
46
54
 
@@ -48,7 +56,8 @@ project's standing verification stack goes in `verify.md` instead, not here.
48
56
  [`roadmap.md`](roadmap.md), phase status in §6.1, retired outcomes in [`history.md`](history.md) — one
49
57
  place each. `check` fails a plan that grows one.
50
58
  - **`/feature-plan` produces a reviewable skeleton plus open questions**, not a finished plan of record.
51
- §1, §3 and §6.1 are the sections research can usefully draft. §4 and §5 usually arrive as open questions.
59
+ §1, §3, §6.1 and §7 are the sections research can usefully draft §7 in particular is a search, not a
60
+ judgement call. §4 and §5 usually arrive as open questions.
52
61
  - **Cite by §-number, not by line number.** Source comments cite plan sections; line numbers rot on the
53
62
  first edit, and a §-number survives the move into `archive/`.
54
63
  - **Never mark a phase `done` in a plan that has not been executed.** Every phase in a new plan is
@@ -96,6 +96,20 @@ policy, resolves by committing on its own every phase. That is a call about some
96
96
  it is a written answer rather than an inference. Branching and pushing are outside it: nothing here creates
97
97
  a branch, pushes, or opens a pull request under either answer.
98
98
 
99
+ ### Documentation is part of the change
100
+
101
+ > **Find where this project documents itself before planning — the Documentation index in
102
+ > [`stack.md`](stack.md), and the repository itself when that index is missing or empty. Whatever a change
103
+ > makes untrue there is fixed by the phase that makes it untrue, not by a follow-up.**
104
+
105
+ Documentation is the one output with no gate behind it. Nothing fails when a README goes on describing a
106
+ flag that was renamed, so the drift is invisible until someone follows the old instructions and it is not
107
+ invisible to them. `/feature-plan` writes the affected surfaces into the plan's §7, each assigned to a
108
+ phase, and that phase's **Files:** line carries the path like anything else it touches.
109
+
110
+ *"Nothing here describes this feature"* is a legitimate answer, and it names the surfaces that were
111
+ checked. Saying nothing is not that answer.
112
+
99
113
  ### Never transcribe a credential
100
114
 
101
115
  > **A DSN, token or key is described and pointed at the secret store, never copied into a tracked file.**
@@ -125,10 +139,16 @@ To pick the next phase: take the **lowest-numbered phase that is not `done` and
125
139
  are all `done`.** State which one you picked before starting. If it is already `in progress`, read its Note
126
140
  and resume — do not restart it.
127
141
 
142
+ **A phase's row is written twice.** It opens to `in progress` when the work starts, before any code, and
143
+ closes to `done`, `in progress` or `blocked` when the phase ends. The opening write is what makes an
144
+ interruption survivable: a run that dies mid-phase leaves a tree with half the work in it, and the row is
145
+ the only thing that can say so.
146
+
128
147
  `done` means the phase's scope landed and both gates passed — **a verdict about the gates, not about git.**
129
148
  Whoever finishes a phase updates its row **as part of the same change as the work**: one commit where the
130
- agent commits, one working tree handed over where the user does. A row updated separately is a row that
131
- disagrees with the repository in between.
149
+ agent commits, one working tree handed over where the user does. A closing row updated separately is a row
150
+ that disagrees with the repository in between. The opening write is not a change of its own — it is left in
151
+ the tree and lands with the work it describes.
132
152
 
133
153
  If the ledger's claim disagrees with the repo — a phase marked `done` whose files do not exist, or the
134
154
  reverse — **stop and say so.** Never silently re-do or skip a phase on a stale ledger. A `done` row whose
@@ -38,7 +38,8 @@ detailed it looks.
38
38
  This is the step that used to be structural: `/feature-plan` stopped and you typed a second command. It is
39
39
  explicit here now, or it is lost.
40
40
 
41
- 1. **Surface the plan's §8 Open questions and require an acknowledgement.** Do not proceed on silence.
41
+ 1. **Surface the plan's Open questions section and require an acknowledgement.** Do not proceed on
42
+ silence. Cite it by name — a plan written against an earlier template numbers its sections differently.
42
43
  2. **Re-check that the files the plan cites still exist.** A plan drafted a month ago against a
43
44
  since-changed tree is a state that can now exist and could not before. Name anything that has moved.
44
45
  3. **Check the one-active-feature rule** in [`context/workflow.md`](../../../context/workflow.md). If
@@ -65,10 +66,31 @@ If the ledger's claim contradicts the repo — a phase marked `done` whose **Fil
65
66
  plainly in the tree under a phase marked `not started` — **say so and stop.** Never silently re-do or skip
66
67
  a phase on a stale ledger.
67
68
 
68
- ## 6. Do the work
69
+ ## 6. Open the ledger row
70
+
71
+ Set the phase's Status to `in progress` and write a Note naming what is underway — **before any code.**
72
+
73
+ This row is what a *later* session reads. A phase interrupted here — context exhausted, session closed, run
74
+ cancelled — leaves a working tree with half a phase in it. A row still reading `not started` sends the next
75
+ run into step 5's disagreement stop, or into redoing work that is already there.
76
+
77
+ One token and one Note, in the row that is already there — do not move the entry, restructure the table, or
78
+ write a summary anywhere else. If the row is already `in progress` because you are resuming it, leave it
79
+ alone; step 11 rewrites the Note.
80
+
81
+ **This write is not a change of its own.** Leave it in the working tree — it lands with the phase's work
82
+ under either answer in [`context/git.md`](../../../context/git.md). Never commit it on its own.
83
+
84
+ ## 7. Do the work
69
85
 
70
86
  Read the phase's §6.2 sub-section: its scope, its **Files:**, and what `done` means for it.
71
87
 
88
+ **The plan's Documentation rows assigned to this phase are part of this phase**, not a follow-up — their
89
+ paths are on the same **Files:** line as the code. Per the standing rule in
90
+ [`context/workflow.md`](../../../context/workflow.md), whatever this phase makes untrue is fixed by this
91
+ phase. If the work turned out differently from the plan and made something *else* untrue — a README the
92
+ plan never listed — fix that too and say so; the sweep happened before the code existed.
93
+
72
94
  Delegate to a coder per [`context/executors.md`](../../../context/executors.md) if one is configured;
73
95
  otherwise implement in-host. The coder's system prompt is
74
96
  [`context/roles/coder.md`](../../../context/roles/coder.md).
@@ -79,7 +101,7 @@ this repository can open them, and a brief that inlines them is a brief that goe
79
101
 
80
102
  Describe **what** needs to happen, never **how** to code it. Scope each delegated task to specific files.
81
103
 
82
- ## 7. Gate 1 — verification
104
+ ## 8. Gate 1 — verification
83
105
 
84
106
  Per the gate contract in [`context/workflow.md`](../../../context/workflow.md): read
85
107
  [`context/verify.md`](../../../context/verify.md) and run its sections in order — Lint → Typecheck → Build →
@@ -89,9 +111,9 @@ Test.
89
111
  so, never faked. Exit 0 is the verdict regardless of summary text. If `verify.md` does not exist or has no
90
112
  filled-in section, stop and say so. Docs-only changes run Lint plus a read of the diff.
91
113
 
92
- A failure is the verdict — go to step 9 with the failing output verbatim as the feedback.
114
+ A failure is the verdict — go to step 10 with the failing output verbatim as the feedback.
93
115
 
94
- ## 8. Gate 2 — review
116
+ ## 9. Gate 2 — review
95
117
 
96
118
  Dispatch per [`context/executors.md`](../../../context/executors.md). With no independent reviewer
97
119
  configured, review the diff yourself against the plan's review expectations and the standards — weaker, and
@@ -100,13 +122,13 @@ configured, review the diff yourself against the plan's review expectations and
100
122
  Require concrete evidence — file paths, command output — for every verdict, and a `P0`–`P3` severity on
101
123
  every blocking finding.
102
124
 
103
- - `PASS` or `PASS WITH NOTES` → the phase's work is done; go to step 10.
104
- - `FAIL` → **write it to [`context/findings.md`](../../../context/findings.md) first, then** go to step 9.
125
+ - `PASS` or `PASS WITH NOTES` → the phase's work is done; go to step 11.
126
+ - `FAIL` → **write it to [`context/findings.md`](../../../context/findings.md) first, then** go to step 10.
105
127
 
106
128
  **Write the finding before the loopback, not after it.** A verdict that lives only in this session's
107
129
  transcript evaporates when the conversation ends — including a `P0` the cap never got to.
108
130
 
109
- ## 9. Loopback
131
+ ## 10. Loopback
110
132
 
111
133
  Cap: **two loops per gate, per phase.**
112
134
 
@@ -118,11 +140,12 @@ At the cap: **write a finding** (`P1` for a Gate 1 cap-out — a phase whose ver
118
140
  blocked by definition), then escalate to the user with the current state and the last feedback.
119
141
  **Escalating is not a substitute for recording.**
120
142
 
121
- ## 10. Close out the ledger row
143
+ ## 11. Close out the ledger row
122
144
 
123
145
  The row is part of the same change as the work — never a separate step afterwards:
124
146
 
125
- - **All of the phase's scope landed and both gates passed** → `done`.
147
+ - **All of the phase's scope landed and both gates passed** → `done`. Its documentation rows are part of
148
+ that scope: a phase whose doc update has not landed has not landed.
126
149
  - **Some landed** → stays `in progress`, Note rewritten to name exactly what remains.
127
150
  - **A gate hit its cap, or something external blocks it** → `blocked`, with the blocker in the Note.
128
151
 
@@ -131,7 +154,7 @@ open `P0` or `P1` is tied to this phase**; leave it `in progress` and name the f
131
154
 
132
155
  `done` is a verdict about the gates, not about git. Whether the change is committed at all is the next step.
133
156
 
134
- ## 11. Land it — read [`context/git.md`](../../../context/git.md)
157
+ ## 12. Land it — read [`context/git.md`](../../../context/git.md)
135
158
 
136
159
  **Do not commit until you have read that file, and do not commit at all unless it says the agent does.**
137
160
  It is the only place this project's answer lives, the same way `verify.md` is the only place its commands
@@ -142,7 +165,7 @@ once, and name `/onboard`.
142
165
  and stop. Do not stage-and-commit "to be helpful", and do not push or branch under either answer.
143
166
  - **The agent commits** → the code and the ledger row in one commit, at the granularity that file names.
144
167
 
145
- ## 12. Report
168
+ ## 13. Report
146
169
 
147
170
  - What changed, and which files — and whether it is committed or waiting in the tree.
148
171
  - Gate 1 output, and Gate 2's verdict.
@@ -98,6 +98,13 @@ planner's own default shape:
98
98
  acceptance-criteria — a per-phase artifact, not a plan — and you will throw it away.
99
99
  - Pointers to `context/stack.md`, `context/standards/README.md` (load per its conditional table) and
100
100
  `context/verify.md`. Cite the paths; do not paste the files in. Anything reading this repo can open them.
101
+ - **Where this project documents itself, and what this feature makes untrue there.** Start from the
102
+ Documentation section of `context/stack.md`. **If that section is empty, missing, or names less than the
103
+ tree plainly holds, sweep for it** — the root `README`, a `README` in each package, `docs/`, a docs site
104
+ or landing page in the repository, an API reference or OpenAPI document, a changelog, help text and
105
+ format comments that live in the code. Ask the user about anything hosted elsewhere: a wiki, a docs site
106
+ built from another repo, a published reference. **An index nobody filled in is not evidence that there
107
+ are no docs**, and a plan that assumes it is ships the drift.
101
108
  - **Cite file paths and command output for every claim about the current codebase.** Anything unverified is
102
109
  an open question, not an assertion.
103
110
  - Phases are **commit-sized units with checkable outcomes**, each with a real `Depends on` value and a
@@ -111,7 +118,11 @@ Fill in the template's shape. Then:
111
118
  - Date it and point its header at the roadmap entry.
112
119
  - **No `**Status:**` header.** Feature status lives in `roadmap.md`, phase status in the ledger. A document
113
120
  that claims its own status is a copy that goes stale.
114
- - Fill in **§8 Open questions** honestly. An honest gap is worth more than an invented decision.
121
+ - Fill in **§7 Documentation** from what the sweep found: one row per surface the feature changes, each
122
+ assigned to the phase that carries it, **and that phase's `Files:` line names the same path.** A
123
+ documentation row with no phase is a follow-up nobody does. If nothing changes, say which surfaces you
124
+ checked and why none of them describe this — that is an answer, and leaving the section blank is not.
125
+ - Fill in **§9 Open questions** honestly. An honest gap is worth more than an invented decision.
115
126
  - Every phase is `not started`.
116
127
 
117
128
  ### 6. Update the roadmap entry
@@ -129,7 +140,8 @@ own; discarding it over a marker would undo the point of the split.
129
140
 
130
141
  ### 7. Report and stop
131
142
 
132
- State the document path, the phase count, and the open questions. Then say plainly that **what you produced
143
+ State the document path, the phase count, the documentation surfaces §7 commits to updating, and the open
144
+ questions. Then say plainly that **what you produced
133
145
  is a reviewable skeleton plus open questions, not a finished plan of record** — the value is the structure
134
146
  and the research. Name the next step: the user reviews and edits the plan, and `/feature-implement` runs it
135
147
  once they are satisfied.
@@ -9,6 +9,11 @@ Fills the project-owned stubs the installer deliberately left empty, and folds w
9
9
  already documented into them. **Re-runnable** — run it again after the stack changes, and it re-proposes
10
10
  against what is there now.
11
11
 
12
+ **Run it after an `update`, too.** The updater replaces tool-owned files only; the stubs are project-owned
13
+ and it cannot reach them, so a section a new version's stub gained arrives only through this command. The
14
+ update prints the gaps it found under **Next** — every one of them is this command's work. Until it runs,
15
+ a command can be pointed at a section of a file that does not have it.
16
+
12
17
  **Asking is not guessing.** The installer could have detected a test command and written it in; that is
13
18
  exactly how a file ends up naming a command that has never run. This command asks, and where it can, it
14
19
  *checks*.
@@ -22,7 +27,7 @@ Read [`context/workflow.md`](../../../context/workflow.md) for the tier model.
22
27
  | [`context/verify.md`](../../../context/verify.md) | the real Lint / Typecheck / Build / Test commands — **only ones that exited 0** |
23
28
  | [`context/executors.md`](../../../context/executors.md) | how this project dispatches a coder and a reviewer |
24
29
  | [`context/git.md`](../../../context/git.md) | who commits the work, and at what granularity |
25
- | [`context/stack.md`](../../../context/stack.md) | runtime, layout, conventions |
30
+ | [`context/stack.md`](../../../context/stack.md) | runtime, layout, conventions, and the index of where this project documents itself |
26
31
  | [`AGENTS.md`](../../../AGENTS.md) | pruned, on confirmation, of what moved into those four. The region between the `ai-workflow` markers is never touched |
27
32
 
28
33
  Show every proposed edit before writing it, and **do not commit.** The user reviews and commits.
@@ -45,6 +50,7 @@ Break what you read into claims — a paragraph, a table row, a bullet — and p
45
50
  | A claim about | Goes to |
46
51
  |---|---|
47
52
  | what the project is, its layout, its conventions | `context/stack.md` |
53
+ | where the project's own documentation lives, or how it is published | `context/stack.md`, its Documentation section |
48
54
  | a lint, typecheck, build or test command | a **candidate** for `context/verify.md` — Step 6 still has to run it |
49
55
  | how a coder or a reviewer is dispatched | `context/executors.md` |
50
56
  | a rule about who commits, or when work is committed | `context/git.md` |
@@ -69,6 +75,11 @@ old file is a candidate like any other and still has to run.
69
75
 
70
76
  On a re-run, a claim its destination file already states is already adopted. Say so in a line and move on.
71
77
 
78
+ **If an `update` named a missing section** — `context/stack.md` with no Documentation section, a stub that
79
+ is not there at all — add the heading in the shipped stub's order, then fill it through the step below that
80
+ owns it. Do not rewrite what is already there to match a newer stub: the section is the part that is new,
81
+ not the prose someone wrote about their own project.
82
+
72
83
  ## Step 2 — Coder dispatch
73
84
 
74
85
  Ask whether implementation runs **in-host** or is **offloaded** to an external coder CLI.
@@ -183,6 +194,23 @@ Start from what Step 1 routed here, show it back as a draft, and ask only for th
183
194
  that earns its keep; the rest is discoverable. Inherited prose is usually strongest here and weakest at
184
195
  describing layout, which drifts.
185
196
 
197
+ Then fill in the **Documentation** section, which is the one every later plan reads:
198
+
199
+ 1. **Sweep the repository.** The root `README`, a `README` in every package, `docs/`, a docs site or
200
+ landing page built from this repo, an API reference or OpenAPI document, a changelog, a `man` page or
201
+ `--help` text that lives in the code, a comment that is the only description of a file format.
202
+ 2. **Ask what is published elsewhere** — a wiki, a hosted docs site built from another repository, a
203
+ support centre, a public API reference. Nothing in the tree can reveal those, and they are the surfaces
204
+ that rot longest without anyone noticing.
205
+ 3. **Ask which of them are actually maintained.** A directory nobody has touched in two years is worth
206
+ recording as exactly that; a plan can then say so instead of proposing an update to a dead file.
207
+ 4. **Write "none" if there is none.** An empty section reads as "nobody checked", and `/feature-plan`
208
+ cannot tell those apart — it sweeps the tree itself when the section is empty, which finds files but
209
+ never finds the docs site nobody mentioned.
210
+
211
+ Say what this is for: every plan's §7 starts from this list, and whatever a feature makes untrue there is
212
+ fixed by the phase that makes it untrue.
213
+
186
214
  Point out that anything else added under `context/` should be indexed in `stack.md`, not in
187
215
  `context/README.md`, which is tool-owned and replaced on update.
188
216
 
@@ -45,6 +45,11 @@ A refusal here is the workflow working.
45
45
 
46
46
  Read `context/stack.md` and load `context/standards/README.md` per its conditional table.
47
47
 
48
+ **Check that file's Documentation section, and the tree if it is empty.** If this change makes something
49
+ there wrong — a README, a docs page, a changelog, help text in the code — the fix is part of this change,
50
+ per the standing rule in [`context/workflow.md`](../../../context/workflow.md). A one-shot change is where
51
+ that gets skipped most, because there is no plan holding the row.
52
+
48
53
  Delegate to a coder per [`context/executors.md`](../../../context/executors.md) if one is configured;
49
54
  otherwise implement in-host. The coder's system prompt is
50
55
  [`context/roles/coder.md`](../../../context/roles/coder.md). The brief **cites paths, it does not paste
@@ -25,6 +25,19 @@ What this project is, and what an agent has to know before touching it. Run `/on
25
25
  things deliberately kept separate, where local secrets live, what must never be run against
26
26
  production. -->
27
27
 
28
+ ## Documentation
29
+
30
+ <!-- Every place this project explains itself, one line each: the path or URL, who reads it, and what kind
31
+ of change has to reach it. READMEs at the root and in each package, docs/, a docs site or landing page,
32
+ an API reference or OpenAPI document, a changelog, a wiki, help text that lives in the code, comments
33
+ that are the only description of a format.
34
+
35
+ Say which ones are actually maintained — a directory nobody has updated in two years is worth writing
36
+ down as that, rather than leaving the next reader to discover it.
37
+
38
+ If this project documents itself nowhere, write "none". An empty section reads as "nobody checked",
39
+ and a plan cannot tell those two apart. -->
40
+
28
41
  ## Also in `context/`
29
42
 
30
43
  <!-- Index anything you add under context/ here — decisions.md, glossary.md, ops-notes.md. Not in