@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 +24 -1
- package/dist/check/markdown.js +7 -0
- package/dist/cli.js +2 -1
- package/dist/commands/update.js +26 -1
- package/dist/layout.js +15 -8
- package/dist/stubs.js +51 -0
- package/package.json +1 -1
- package/templates/blocks/agents-block.md +4 -1
- package/templates/claude/agents/planner.agent.md +7 -3
- package/templates/context/README.md +10 -1
- package/templates/context/plan-template.md +19 -5
- package/templates/context/plan-template.notes.md +12 -3
- package/templates/context/workflow.md +22 -2
- package/templates/skills/feature-implement/SKILL.md +35 -12
- package/templates/skills/feature-plan/SKILL.md +14 -2
- package/templates/skills/onboard/SKILL.md +29 -1
- package/templates/skills/orchestrate/SKILL.md +5 -0
- package/templates/stubs/stack.md +13 -0
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
|
package/dist/check/markdown.js
CHANGED
|
@@ -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
|
|
package/dist/commands/update.js
CHANGED
|
@@ -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,
|
|
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
|
-
/**
|
|
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.
|
|
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. **
|
|
37
|
-
|
|
38
|
-
|
|
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`.
|
|
40
|
-
|
|
41
|
-
|
|
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.
|
|
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
|
-
##
|
|
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
|
|
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
|
-
**§
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
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
|
-
##
|
|
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
|
|
114
|
+
A failure is the verdict — go to step 10 with the failing output verbatim as the feedback.
|
|
93
115
|
|
|
94
|
-
##
|
|
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
|
|
104
|
-
- `FAIL` → **write it to [`context/findings.md`](../../../context/findings.md) first, then** go to step
|
|
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
|
-
##
|
|
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
|
-
##
|
|
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
|
-
##
|
|
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
|
-
##
|
|
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 **§
|
|
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,
|
|
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
|
package/templates/stubs/stack.md
CHANGED
|
@@ -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
|