@baldurpan/create-ai-workflow 0.5.1 → 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.1",
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).
@@ -63,10 +63,22 @@ differently-shaped one nearby is a decoy that gets read by mistake.
63
63
 
64
64
  **Done when:** <a condition checkable against the repo>
65
65
 
66
- ## 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
67
79
 
68
80
  <How to prove the feature works, beyond `context/verify.md` passing.>
69
81
 
70
- ## 8. Open questions
82
+ ## 9. Open questions
71
83
 
72
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.**
@@ -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
@@ -84,6 +85,12 @@ under either answer in [`context/git.md`](../../../context/git.md). Never commit
84
85
 
85
86
  Read the phase's §6.2 sub-section: its scope, its **Files:**, and what `done` means for it.
86
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
+
87
94
  Delegate to a coder per [`context/executors.md`](../../../context/executors.md) if one is configured;
88
95
  otherwise implement in-host. The coder's system prompt is
89
96
  [`context/roles/coder.md`](../../../context/roles/coder.md).
@@ -137,7 +144,8 @@ blocked by definition), then escalate to the user with the current state and the
137
144
 
138
145
  The row is part of the same change as the work — never a separate step afterwards:
139
146
 
140
- - **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.
141
149
  - **Some landed** → stays `in progress`, Note rewritten to name exactly what remains.
142
150
  - **A gate hit its cap, or something external blocks it** → `blocked`, with the blocker in the Note.
143
151
 
@@ -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