@baldurpan/create-ai-workflow 0.2.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.
Files changed (116) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +165 -0
  3. package/dist/agents-block.js +70 -0
  4. package/dist/bin.js +14 -0
  5. package/dist/check/markdown.js +47 -0
  6. package/dist/check/parse.js +113 -0
  7. package/dist/check/rules.js +245 -0
  8. package/dist/cli.js +109 -0
  9. package/dist/commands/check.js +41 -0
  10. package/dist/commands/install.js +76 -0
  11. package/dist/commands/standards-add.js +145 -0
  12. package/dist/commands/update.js +214 -0
  13. package/dist/layout.js +115 -0
  14. package/dist/log.js +20 -0
  15. package/dist/manifest.js +53 -0
  16. package/dist/paths.js +41 -0
  17. package/package.json +37 -0
  18. package/templates/blocks/agents-block.md +30 -0
  19. package/templates/claude/agents/planner.agent.md +60 -0
  20. package/templates/claude/agents/reviewer.agent.md +77 -0
  21. package/templates/context/README.md +81 -0
  22. package/templates/context/plan-template.md +69 -0
  23. package/templates/context/plan-template.notes.md +55 -0
  24. package/templates/context/roles/coder.md +76 -0
  25. package/templates/context/workflow.md +143 -0
  26. package/templates/skills/feature-close/SKILL.md +102 -0
  27. package/templates/skills/feature-implement/SKILL.md +142 -0
  28. package/templates/skills/feature-plan/SKILL.md +138 -0
  29. package/templates/skills/feature-status/SKILL.md +86 -0
  30. package/templates/skills/onboard/SKILL.md +122 -0
  31. package/templates/skills/orchestrate/SKILL.md +92 -0
  32. package/templates/skills/roadmap/SKILL.md +97 -0
  33. package/templates/standards/.source +8 -0
  34. package/templates/standards/README.md +104 -0
  35. package/templates/standards/architecture/api-design.md +212 -0
  36. package/templates/standards/architecture/dependency-boundaries.md +104 -0
  37. package/templates/standards/architecture/feature-driven.md +102 -0
  38. package/templates/standards/architecture/folder-structure.md +108 -0
  39. package/templates/standards/architecture/monorepos.md +107 -0
  40. package/templates/standards/architecture/refactoring.md +97 -0
  41. package/templates/standards/architecture/shared-code.md +81 -0
  42. package/templates/standards/docs/PHP-SPEC.md +1195 -0
  43. package/templates/standards/docs/SPEC.md +540 -0
  44. package/templates/standards/examples/bad/data-fetching.tsx +52 -0
  45. package/templates/standards/examples/bad/derived-state.tsx +60 -0
  46. package/templates/standards/examples/bad/feature-component.tsx +80 -0
  47. package/templates/standards/examples/bad/prop-drilling.tsx +70 -0
  48. package/templates/standards/examples/good/data-fetching.tsx +53 -0
  49. package/templates/standards/examples/good/derived-state.tsx +52 -0
  50. package/templates/standards/examples/good/feature-component.tsx +141 -0
  51. package/templates/standards/examples/good/invoice.schema.ts +20 -0
  52. package/templates/standards/examples/good/prop-drilling.tsx +83 -0
  53. package/templates/standards/philosophy/ai-agent-behavior.md +93 -0
  54. package/templates/standards/philosophy/core-principles.md +49 -0
  55. package/templates/standards/philosophy/incremental-abstraction.md +56 -0
  56. package/templates/standards/philosophy/maintainability.md +66 -0
  57. package/templates/standards/philosophy/readability.md +87 -0
  58. package/templates/standards/php/README.md +62 -0
  59. package/templates/standards/php/anti-patterns.md +259 -0
  60. package/templates/standards/php/architecture.md +241 -0
  61. package/templates/standards/php/frameworks.md +197 -0
  62. package/templates/standards/php/rules.md +205 -0
  63. package/templates/standards/php/security.md +190 -0
  64. package/templates/standards/php/testing.md +139 -0
  65. package/templates/standards/php/tooling.md +245 -0
  66. package/templates/standards/react/accessibility.md +130 -0
  67. package/templates/standards/react/anti-patterns.md +187 -0
  68. package/templates/standards/react/component-design.md +139 -0
  69. package/templates/standards/react/error-boundaries.md +195 -0
  70. package/templates/standards/react/forms.md +147 -0
  71. package/templates/standards/react/hooks.md +88 -0
  72. package/templates/standards/react/memoization.md +87 -0
  73. package/templates/standards/react/state-management.md +123 -0
  74. package/templates/standards/react/testing.md +118 -0
  75. package/templates/standards/react/use-effect.md +110 -0
  76. package/templates/standards/security/api-security.md +136 -0
  77. package/templates/standards/security/auth.md +112 -0
  78. package/templates/standards/security/secrets.md +105 -0
  79. package/templates/standards/security/validation.md +89 -0
  80. package/templates/standards/templates/.editorconfig +16 -0
  81. package/templates/standards/templates/.nvmrc +1 -0
  82. package/templates/standards/templates/AGENTS.md +46 -0
  83. package/templates/standards/templates/CLAUDE.md +3 -0
  84. package/templates/standards/templates/_dot_gitignore +50 -0
  85. package/templates/standards/templates/biome.json +53 -0
  86. package/templates/standards/templates/eslint.config.js +61 -0
  87. package/templates/standards/templates/project-readme.md +76 -0
  88. package/templates/standards/templates/pull-request-template.md +46 -0
  89. package/templates/standards/templates/tsconfig.json +35 -0
  90. package/templates/standards/tooling/biome.md +92 -0
  91. package/templates/standards/tooling/ci.md +128 -0
  92. package/templates/standards/tooling/dates.md +194 -0
  93. package/templates/standards/tooling/dependencies.md +90 -0
  94. package/templates/standards/tooling/nx.md +113 -0
  95. package/templates/standards/tooling/observability.md +183 -0
  96. package/templates/standards/tooling/prisma.md +152 -0
  97. package/templates/standards/tooling/shadcn.md +115 -0
  98. package/templates/standards/tooling/tailwind.md +135 -0
  99. package/templates/standards/tooling/tanstack-query.md +214 -0
  100. package/templates/standards/tooling/tanstack-router.md +365 -0
  101. package/templates/standards/tooling/tanstack.md +31 -0
  102. package/templates/standards/tooling/vite.md +135 -0
  103. package/templates/standards/typescript/anti-patterns.md +107 -0
  104. package/templates/standards/typescript/error-handling.md +216 -0
  105. package/templates/standards/typescript/naming.md +78 -0
  106. package/templates/standards/typescript/rules.md +159 -0
  107. package/templates/standards/typescript/tsconfig/base.json +32 -0
  108. package/templates/standards/typescript/tsconfig/nextjs.json +12 -0
  109. package/templates/standards/typescript/tsconfig/react.json +9 -0
  110. package/templates/standards/typescript/validation.md +104 -0
  111. package/templates/stubs/executors.md +49 -0
  112. package/templates/stubs/findings.md +40 -0
  113. package/templates/stubs/history.md +13 -0
  114. package/templates/stubs/roadmap.md +29 -0
  115. package/templates/stubs/stack.md +35 -0
  116. package/templates/stubs/verify.md +48 -0
package/dist/layout.js ADDED
@@ -0,0 +1,115 @@
1
+ import path from 'node:path';
2
+ import { readFileSync } from 'node:fs';
3
+ import { templatesDir, toPosix, walk } from "./paths.js";
4
+ /**
5
+ * Both trees ship. The hosts read disjoint directories — Codex finds `.agents/skills/` and never looks
6
+ * at `.claude/skills/` (§1.2) — so a repository worked on by more than one agent needs both, and a
7
+ * repository worked on by one pays a directory it never opens. Neither tree is ever hand-edited, which
8
+ * is what keeps the duplication structural rather than a drift risk (§5.1).
9
+ */
10
+ export const DEFAULT_ADAPTERS = ['claude', 'agents'];
11
+ /** Where each adapter's host looks for project-local skills. */
12
+ export const ADAPTER_SKILL_DIRS = {
13
+ claude: '.claude/skills',
14
+ agents: '.agents/skills',
15
+ };
16
+ export function isAdapter(value) {
17
+ return value === 'claude' || value === 'agents';
18
+ }
19
+ /** The manifest key for the delimited block inside AGENTS.md. Not a file — a region of one. */
20
+ export const AGENTS_BLOCK_KEY = 'AGENTS.md#ai-workflow';
21
+ export const CONTEXT_DIR = 'context';
22
+ export const MANIFEST_PATH = 'context/.state/manifest.json';
23
+ export const STANDARDS_PREFIX = 'context/standards/';
24
+ export const SKILL_NAMES = [
25
+ 'roadmap',
26
+ 'feature-plan',
27
+ 'feature-implement',
28
+ 'feature-status',
29
+ 'feature-close',
30
+ 'orchestrate',
31
+ 'onboard',
32
+ ];
33
+ /**
34
+ * A skill body is shared verbatim between adapter trees. `disable-model-invocation: true` is the only
35
+ * difference the Claude Code copy carries, and it is injected here rather than written into the template,
36
+ * so a second tree can reuse the same body untouched.
37
+ */
38
+ export function claudeSkillTransform(text) {
39
+ const match = /^---\n([\s\S]*?)\n---\n/.exec(text);
40
+ if (!match)
41
+ throw new Error('skill template has no frontmatter block');
42
+ const frontmatter = match[1];
43
+ if (/^disable-model-invocation:/m.test(frontmatter))
44
+ return text;
45
+ const patched = `---\n${frontmatter}\ndisable-model-invocation: true\n---\n`;
46
+ return patched + text.slice(match[0].length);
47
+ }
48
+ /**
49
+ * npm refuses to publish a file named `.gitignore`, so the vendored standards carry theirs as
50
+ * `_dot_gitignore` and it is restored here. Without this the installed tree would quietly differ from the
51
+ * ref `standards/.source` claims it came from.
52
+ */
53
+ export function undotted(posix) {
54
+ return posix.replace(/(^|\/)_dot_/, '$1.');
55
+ }
56
+ /** Every tool-owned file, in the order it should be written and reported. */
57
+ export function managedFiles(adapters) {
58
+ const files = [
59
+ { source: 'context/README.md', dest: 'context/README.md' },
60
+ { source: 'context/workflow.md', dest: 'context/workflow.md' },
61
+ { source: 'context/plan-template.md', dest: 'context/plan-template.md' },
62
+ { source: 'context/plan-template.notes.md', dest: 'context/plan-template.notes.md' },
63
+ { source: 'context/roles/coder.md', dest: 'context/roles/coder.md' },
64
+ ];
65
+ for (const rel of walk(path.join(templatesDir, 'standards'))) {
66
+ const posix = toPosix(rel);
67
+ files.push({ source: `standards/${posix}`, dest: `${STANDARDS_PREFIX}${undotted(posix)}` });
68
+ }
69
+ if (adapters.includes('claude')) {
70
+ for (const name of SKILL_NAMES) {
71
+ files.push({
72
+ source: `skills/${name}/SKILL.md`,
73
+ dest: `${ADAPTER_SKILL_DIRS.claude}/${name}/SKILL.md`,
74
+ transform: claudeSkillTransform,
75
+ });
76
+ }
77
+ for (const rel of walk(path.join(templatesDir, 'claude', 'agents'))) {
78
+ const posix = toPosix(rel);
79
+ files.push({ source: `claude/agents/${posix}`, dest: `.claude/agents/${posix}` });
80
+ }
81
+ }
82
+ // The same seven bodies, verbatim. No transform: `disable-model-invocation` is Claude Code's key and
83
+ // means nothing here, and there is no subagent tree to go with it — the skills already write
84
+ // delegation as optional.
85
+ if (adapters.includes('agents')) {
86
+ for (const name of SKILL_NAMES) {
87
+ files.push({
88
+ source: `skills/${name}/SKILL.md`,
89
+ dest: `${ADAPTER_SKILL_DIRS.agents}/${name}/SKILL.md`,
90
+ });
91
+ }
92
+ }
93
+ return files;
94
+ }
95
+ /** Project-owned files. Written once, at install, and never reachable by `update`. */
96
+ export const STUBS = [
97
+ { source: 'stubs/stack.md', dest: 'context/stack.md' },
98
+ { source: 'stubs/verify.md', dest: 'context/verify.md' },
99
+ { source: 'stubs/executors.md', dest: 'context/executors.md' },
100
+ { source: 'stubs/roadmap.md', dest: 'context/roadmap.md' },
101
+ { source: 'stubs/history.md', dest: 'context/history.md' },
102
+ { source: 'stubs/findings.md', dest: 'context/findings.md' },
103
+ ];
104
+ export const STUB_DIRS = ['context/drafts', 'context/plans', 'context/archive'];
105
+ export function readTemplate(source) {
106
+ return readFileSync(path.join(templatesDir, source), 'utf8');
107
+ }
108
+ /** The rendered content of a managed file — the template with its transform applied. */
109
+ export function renderManaged(file) {
110
+ const text = readTemplate(file.source);
111
+ return file.transform ? file.transform(text) : text;
112
+ }
113
+ export function agentsBlockBody() {
114
+ return readTemplate('blocks/agents-block.md').trim();
115
+ }
package/dist/log.js ADDED
@@ -0,0 +1,20 @@
1
+ const useColour = process.stdout.isTTY && !process.env.NO_COLOR;
2
+ const wrap = (code) => (s) => (useColour ? `\x1b[${code}m${s}\x1b[0m` : s);
3
+ export const bold = wrap('1');
4
+ export const dim = wrap('2');
5
+ export const red = wrap('31');
6
+ export const green = wrap('32');
7
+ export const yellow = wrap('33');
8
+ export const cyan = wrap('36');
9
+ export function info(message = '') {
10
+ process.stdout.write(`${message}\n`);
11
+ }
12
+ export function warn(message) {
13
+ process.stdout.write(`${yellow('!')} ${message}\n`);
14
+ }
15
+ export function fail(message) {
16
+ process.stderr.write(`${red('error')} ${message}\n`);
17
+ }
18
+ /** An error whose message is meant for the user — printed without a stack trace. */
19
+ export class UserError extends Error {
20
+ }
@@ -0,0 +1,53 @@
1
+ import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
2
+ import path from 'node:path';
3
+ import { MANIFEST_PATH, isAdapter } from "./layout.js";
4
+ import { UserError } from "./log.js";
5
+ import { exists } from "./paths.js";
6
+ export const SCHEMA_VERSION = 1;
7
+ export function manifestPath(root) {
8
+ return path.join(root, MANIFEST_PATH);
9
+ }
10
+ export function hasManifest(root) {
11
+ return exists(manifestPath(root));
12
+ }
13
+ export function readManifest(root) {
14
+ const file = manifestPath(root);
15
+ if (!exists(file)) {
16
+ throw new UserError(`no manifest at ${MANIFEST_PATH} — this repository has no ai-workflow install to update.\n` +
17
+ ' Run `npx @baldurpan/create-ai-workflow` to install one.');
18
+ }
19
+ let parsed;
20
+ try {
21
+ parsed = JSON.parse(readFileSync(file, 'utf8'));
22
+ }
23
+ catch (error) {
24
+ throw new UserError(`${MANIFEST_PATH} is not valid JSON: ${error.message}`);
25
+ }
26
+ const manifest = parsed;
27
+ if (manifest.schemaVersion !== SCHEMA_VERSION) {
28
+ throw new UserError(`${MANIFEST_PATH} has schemaVersion ${String(manifest.schemaVersion)}; this tool writes ${SCHEMA_VERSION}.`);
29
+ }
30
+ if (!manifest.managedFiles || typeof manifest.managedFiles !== 'object') {
31
+ throw new UserError(`${MANIFEST_PATH} has no managedFiles map.`);
32
+ }
33
+ // An adapter this version does not know is dropped rather than carried: `managedFiles` still lists
34
+ // whatever it wrote, so `update` reports those files as no longer shipped instead of losing them.
35
+ const adapters = (manifest.adapters ?? []).filter(isAdapter);
36
+ return {
37
+ schemaVersion: SCHEMA_VERSION,
38
+ version: manifest.version ?? '0.0.0',
39
+ adapters: adapters.length ? adapters : ['claude'],
40
+ managedFiles: manifest.managedFiles,
41
+ };
42
+ }
43
+ export function writeManifest(root, manifest) {
44
+ const file = manifestPath(root);
45
+ mkdirSync(path.dirname(file), { recursive: true });
46
+ const ordered = {
47
+ schemaVersion: manifest.schemaVersion,
48
+ version: manifest.version,
49
+ adapters: manifest.adapters,
50
+ managedFiles: Object.fromEntries(Object.entries(manifest.managedFiles).sort(([a], [b]) => (a < b ? -1 : 1))),
51
+ };
52
+ writeFileSync(file, `${JSON.stringify(ordered, null, 2)}\n`, 'utf8');
53
+ }
package/dist/paths.js ADDED
@@ -0,0 +1,41 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { readdirSync, readFileSync, statSync } from 'node:fs';
3
+ import path from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
5
+ /** Root of the published package — the directory holding `templates/`. */
6
+ export const packageRoot = path.resolve(fileURLToPath(import.meta.url), '..', '..');
7
+ export const templatesDir = path.join(packageRoot, 'templates');
8
+ export function packageVersion() {
9
+ const pkg = JSON.parse(readFileSync(path.join(packageRoot, 'package.json'), 'utf8'));
10
+ return pkg.version;
11
+ }
12
+ /** sha256 of a buffer or string, hex. Line endings are normalised so a CRLF checkout is not a conflict. */
13
+ export function hash(content) {
14
+ const text = typeof content === 'string' ? content : content.toString('utf8');
15
+ return createHash('sha256').update(text.replace(/\r\n/g, '\n'), 'utf8').digest('hex');
16
+ }
17
+ /** Every file under `dir`, as paths relative to `dir`, sorted. Follows no symlinks. */
18
+ export function walk(dir, base = dir) {
19
+ const out = [];
20
+ for (const entry of readdirSync(dir, { withFileTypes: true })) {
21
+ const full = path.join(dir, entry.name);
22
+ if (entry.isDirectory())
23
+ out.push(...walk(full, base));
24
+ else if (entry.isFile())
25
+ out.push(path.relative(base, full));
26
+ }
27
+ return out.sort();
28
+ }
29
+ export function exists(p) {
30
+ try {
31
+ statSync(p);
32
+ return true;
33
+ }
34
+ catch {
35
+ return false;
36
+ }
37
+ }
38
+ /** Always forward slashes — manifest keys are portable across platforms. */
39
+ export function toPosix(p) {
40
+ return p.split(path.sep).join('/');
41
+ }
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "@baldurpan/create-ai-workflow",
3
+ "version": "0.2.0",
4
+ "description": "Overlay a tiered planning workflow — roadmap, plans, phase ledgers, verification gates — onto an existing repository, for coding agents.",
5
+ "keywords": ["ai", "agents", "claude-code", "workflow", "planning", "AGENTS.md"],
6
+ "license": "MIT",
7
+ "author": "Baldur Páll Hólmgeirsson",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/baldurpan/ai-workflow.git"
11
+ },
12
+ "homepage": "https://github.com/baldurpan/ai-workflow#readme",
13
+ "bugs": {
14
+ "url": "https://github.com/baldurpan/ai-workflow/issues"
15
+ },
16
+ "type": "module",
17
+ "bin": {
18
+ "create-ai-workflow": "dist/bin.js"
19
+ },
20
+ "files": ["dist", "templates", "README.md", "LICENSE"],
21
+ "publishConfig": {
22
+ "access": "public"
23
+ },
24
+ "engines": {
25
+ "node": ">=20.10.0"
26
+ },
27
+ "scripts": {
28
+ "build": "tsc",
29
+ "prepublishOnly": "npm run build && npm test",
30
+ "test": "node --test \"test/*.test.ts\"",
31
+ "check": "tsc --noEmit"
32
+ },
33
+ "devDependencies": {
34
+ "@types/node": "^22.10.0",
35
+ "typescript": "^5.9.2"
36
+ }
37
+ }
@@ -0,0 +1,30 @@
1
+ ## Planning workflow
2
+
3
+ Planning artifacts live in [`context/`](context/README.md). Read
4
+ [`context/workflow.md`](context/workflow.md) before using any command below — it holds the tier model and
5
+ the standing rules, and every command cites it rather than restating it.
6
+
7
+ | Command | Does |
8
+ |---|---|
9
+ | `/roadmap` | prints the Tier-1 backlog, or appends one `pending` entry to it |
10
+ | `/feature-plan` | turns a backlog entry into `context/plans/<NAME>-PLAN.md` and **stops** — it never implements |
11
+ | `/feature-implement` | activates a planned feature and runs its phases, through both gates |
12
+ | `/feature-status` | read-only "where do things stand". **Never a prerequisite** for anything |
13
+ | `/feature-close` | retires a finished or abandoned feature into `context/archive/` |
14
+ | `/orchestrate` | one ad-hoc, gated, commit-sized change — no roadmap entry, no ledger |
15
+ | `/onboard` | fills in this project's own stubs: `verify.md`, `executors.md`, `stack.md` |
16
+
17
+ | Read | For |
18
+ |---|---|
19
+ | [`context/stack.md`](context/stack.md) | runtime, layout, conventions |
20
+ | [`context/standards/README.md`](context/standards/README.md) | engineering standards — load per its conditional table |
21
+ | [`context/verify.md`](context/verify.md) | the real lint / typecheck / build / test commands — the only file that names one |
22
+
23
+ **Phase status lives in the active plan's status ledger and nowhere else.** Work the lowest-numbered phase
24
+ that is not `done` and whose `Depends on` are all `done`; state which you picked before starting; update
25
+ the row in the same commit as the work. **If the ledger disagrees with the repo, stop and say so.**
26
+
27
+ **An open `P0` or `P1` in [`context/findings.md`](context/findings.md) blocks its phase from being `done`.**
28
+
29
+ **Require evidence, not assertion.** A claim about what a file contains needs the file read, not recalled —
30
+ yours as much as a subagent's.
@@ -0,0 +1,60 @@
1
+ ---
2
+ name: planner
3
+ description: Researches the codebase and the relevant documentation and drafts a plan. Use when a plan is needed before implementing a feature or fixing a complex issue. Does not write code.
4
+ model: inherit
5
+ tools: Read, Grep, Glob, Bash, WebFetch, WebSearch
6
+ ---
7
+
8
+ # Planner
9
+
10
+ You research and draft. You do **not** write code, and you do not edit files.
11
+
12
+ ## Research
13
+
14
+ You do your own research — a subagent cannot dispatch further subagents. Use `Read`, `Grep` and `Glob` for
15
+ the codebase, a documentation MCP server if one is configured, and `WebFetch` / `WebSearch` for anything it
16
+ does not cover. `Bash` is for read-only inspection (`git log`, `ls`, `--version`) — never for writing.
17
+
18
+ Do not assume a library's current API from memory. Verify it, and cite what you confirmed.
19
+
20
+ ## The output contract comes from the brief
21
+
22
+ **Your brief names the required output shape. It overrides everything below.** When it names a template's
23
+ section list, that section list *is* your output — in that order, with the ledger's exact column set. A
24
+ plan document and a per-phase work item are different artifacts, and producing the wrong one wastes the
25
+ run.
26
+
27
+ The default shape below applies only when the brief names none.
28
+
29
+ ## Workflow
30
+
31
+ 1. **Load the standards.** Read `context/standards/README.md` and load the files its conditional-loading
32
+ table points at for this task. Your checklist items must reference specific rules from those files, not
33
+ generic principles.
34
+ 2. **Read the project.** `context/stack.md` for what this repo is; `context/verify.md` for how it proves
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.
39
+
40
+ ## Default output shape
41
+
42
+ **Summary** — one paragraph on the change and its intent.
43
+
44
+ **Steps** — ordered. Each one: what needs to happen, the explicit file paths it creates or modifies, the
45
+ testable acceptance criteria, and the review checklist items (naming the specific standards that apply).
46
+
47
+ **Edge cases** — the cross-cutting ones not tied to a single step.
48
+
49
+ **Open questions** — anything you could not resolve. Mark them clearly.
50
+
51
+ ## Rules
52
+
53
+ - **Cite a file path or command output for every claim about the current codebase.** An assertion about
54
+ what a file contains needs the file read, not recalled.
55
+ - **Anything you could not verify is an open question, not an assertion.** An honest gap is worth more than
56
+ an invented decision.
57
+ - Acceptance criteria must be **testable** — say what passes and what fails, not "should work well".
58
+ - Review checklist items must name **specific standards**, not "follow best practices".
59
+ - **Name no verification command.** `context/verify.md` is the only file in this project that does. Point
60
+ at it.
@@ -0,0 +1,77 @@
1
+ ---
2
+ name: reviewer
3
+ description: Reviews a completed implementation against the plan's review checklist and the project's engineering standards, returning a verdict with severities and cited evidence. Use as the review gate after verification passes.
4
+ model: inherit
5
+ tools: Read, Grep, Glob, Bash
6
+ ---
7
+
8
+ # Reviewer
9
+
10
+ You review a completed implementation. You are an **evidence-gatherer first and a judge second**.
11
+
12
+ You are called after verification has passed. You receive the implementation output, the plan's review
13
+ checklist, and the verification result — for context, not for re-running.
14
+
15
+ Your verdict gates completion:
16
+
17
+ - **PASS**, or **PASS WITH NOTES** the caller accepts → the work is complete.
18
+ - **FAIL** → the caller writes a finding and loops back. Cap: two loops.
19
+
20
+ ## Do these in order
21
+
22
+ ### 1. Gather evidence, before forming any opinion
23
+
24
+ - For every file in the brief's file list: if its content is inlined in the prompt, treat that as the
25
+ source of truth. Otherwise `Read` it. Do this **before** writing a summary, before forming a verdict.
26
+ - For every "missing X" claim you are considering: run `grep -n "<pattern>" <file>`. The empty output is
27
+ your evidence. Cite the search you ran.
28
+ - For every standards rule you cite: open the file and quote the rule verbatim. Load them per the
29
+ conditional table in `context/standards/README.md`.
30
+ - Read the diff: `git diff` for uncommitted work, `git diff <base>...HEAD` against a base branch.
31
+
32
+ **You may not cite a line, quote code, or reference a file you have not opened.** If you find yourself
33
+ writing "line 42 says X", verify that line 42 says X. If you cannot, write
34
+ `NOT VERIFIED: I do not have access to <file>:42`.
35
+
36
+ ### 2. Walk the checklist
37
+
38
+ For every item in the plan's review checklist, write a verdict, using only the evidence from step 1.
39
+
40
+ ### 3. Form blocking findings
41
+
42
+ A finding is **blocking** only if all three hold:
43
+
44
+ 1. It corresponds to a specific review checklist item, or violates a standard the plan referenced.
45
+ 2. You have a verbatim quote from the actual file as evidence — line number and content.
46
+ 3. The fix is specific and actionable in one targeted edit.
47
+
48
+ If you cannot satisfy all three, it is a **non-blocking note**, not a blocking finding.
49
+
50
+ ### 4. Write the verdict
51
+
52
+ ```
53
+ Verdict: PASS | PASS WITH NOTES | FAIL (severity: P0 | P1 | P2 | P3)
54
+
55
+ Evidence gathered
56
+ - <file>:<line> — <verbatim quote>
57
+ - <the grep you ran, and its output>
58
+
59
+ Checklist
60
+ - <item> — <verdict, with the evidence that supports it>
61
+
62
+ Blocking findings (each with a severity, the file, and the specific fix)
63
+ Non-blocking notes
64
+ ```
65
+
66
+ Every blocking finding carries a `P0`–`P3` severity, and the verdict carries the highest of them.
67
+ `P0` breaks production or data. `P1` blocks a phase or a gate. `P2` is a real defect that does not block.
68
+ `P3` is a note worth not losing.
69
+
70
+ ## Rules
71
+
72
+ - **Never invent evidence.** These rules exist because past reviews have.
73
+ - **Do not re-run verification.** It already ran; you are reading the code.
74
+ - **Do not fix anything.** You review; the coder fixes.
75
+ - **Name no verification command.** `context/verify.md` is the only file in this project that does.
76
+ - Scope is the change, not the repository. You are judging what landed, not everything that was already
77
+ there.
@@ -0,0 +1,81 @@
1
+ # context/
2
+
3
+ Everything an agent needs to work on this project, in one agent-neutral place. Nothing here is specific to
4
+ any one coding agent — `AGENTS.md` at the repo root is the entry point that points here.
5
+
6
+ ## The one rule that outranks the others
7
+
8
+ **No document states its own status.** There is no `**Status:**` header anywhere under `context/`. Every
9
+ status has exactly one home:
10
+
11
+ | To know | Read |
12
+ |---|---|
13
+ | whether a feature is being worked | the `pending` / `active` marker in its [`roadmap.md`](roadmap.md) heading |
14
+ | whether a feature has a plan | whether its **Doc** field points into [`plans/`](plans/) |
15
+ | where a phase stands | that plan's own status ledger |
16
+ | what a retired feature's outcome was | its [`history.md`](history.md) row |
17
+
18
+ A header that claims a status is a copy nobody remembers to update. The two facts "is it being worked" and
19
+ "does it have a plan" are orthogonal, which is why they live in two different places and neither can go
20
+ stale against the other.
21
+
22
+ Nothing here is cached, parsed by a script, or generated. There is no build step in the planning loop and no
23
+ generated "current state" file — hand-editing a ledger row changes every command's answer immediately.
24
+
25
+ ## What the tool installs
26
+
27
+ | File | Holds | Owner |
28
+ |---|---|---|
29
+ | `README.md` | this file | tool |
30
+ | [`workflow.md`](workflow.md) | the tier model, the commands, the standing invariants | tool |
31
+ | [`plan-template.md`](plan-template.md) | the bare skeleton every Tier-2 plan is copied from | tool |
32
+ | [`plan-template.notes.md`](plan-template.notes.md) | what goes in each section of that skeleton | tool |
33
+ | [`roles/coder.md`](roles/coder.md) | the coder system prompt — names no commands | tool |
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 |
36
+ | [`verify.md`](verify.md) | this project's real lint / typecheck / build / test commands | project |
37
+ | [`executors.md`](executors.md) | how this project dispatches a coder and a reviewer | project |
38
+ | [`roadmap.md`](roadmap.md) | Tier 1 — the backlog. `pending` and `active` entries only | project |
39
+ | [`history.md`](history.md) | index of retired features, newest last | project |
40
+ | [`findings.md`](findings.md) | open findings that gate a phase from being marked `done` | project |
41
+ | [`drafts/`](drafts/) | notes and source material for ideas not yet planned — no ledger | project |
42
+ | [`plans/`](plans/) | Tier 2 — documents with an executable phase ledger | project |
43
+ | [`archive/`](archive/) | retired plans, moved here by `/feature-close` | project |
44
+
45
+ `*` `standards/` is tool-owned only while it is the bundled default and unmodified. Swap it with
46
+ `standards add <git-url>`, or edit it, and it becomes yours — it drops out of the manifest and updates
47
+ stop reaching it.
48
+
49
+ A document moves once per tier transition, and **which directory it sits in tells you what it is**:
50
+
51
+ ```
52
+ drafts/ ──/feature-plan──▶ plans/ ──/feature-close──▶ archive/
53
+ notes a phase ledger retired
54
+ ```
55
+
56
+ `plans/` means "has an executable ledger" and nothing more — it does not imply the feature is being worked.
57
+ If a document is ever misfiled, the roadmap's link to it breaks loudly rather than lying quietly.
58
+
59
+ ## Ownership
60
+
61
+ This directory mixes tool-supplied content with project state. The boundary is enforced by a data structure,
62
+ not by a rule someone has to remember: `context/.state/manifest.json` lists every tool-owned file with its
63
+ hash, `update` walks that manifest, and a project-owned file is not in it — so no code path reaches it.
64
+
65
+ | Tool-owned — replaced on `update` | Project-owned — unreachable by the updater |
66
+ |---|---|
67
+ | `README.md`, `workflow.md`, `plan-template*.md`, `roles/` | `stack.md`, `verify.md`, `executors.md` |
68
+ | the skill and agent trees, the `AGENTS.md` block | `roadmap.md`, `history.md`, `findings.md` |
69
+ | `standards/` while it is ours and unmodified | `drafts/`, `plans/`, `archive/`, `CLAUDE.md` |
70
+
71
+ `update` prints both columns when it runs. A visible boundary beats a documented one.
72
+
73
+ **Anything else you add under `context/` is yours forever**, by the same property — `context/decisions.md`,
74
+ `context/glossary.md`, `context/ops-notes.md` all survive by default, with no feature required to protect
75
+ them. Index your own additions in [`stack.md`](stack.md), not here: this file is replaced on every update,
76
+ so a line you add to it is a line you lose.
77
+
78
+ ## What does not belong here
79
+
80
+ Planning artifacts live in `context/`, wherever else your docs live. Product specs, API references and
81
+ anything else written for humans or library consumers stay where this project already keeps them.
@@ -0,0 +1,69 @@
1
+ # <Feature> Plan
2
+
3
+ Written <YYYY-MM-DD>. <One line on what this is.> The `<name>` entry in
4
+ [`../roadmap.md`](../roadmap.md) is where this feature's status lives.
5
+
6
+ **Phase status lives in §6.1 of this document, and nowhere else.**
7
+
8
+ ---
9
+
10
+ ## 1. Why
11
+
12
+ <The problem, with evidence.>
13
+
14
+ ## 2. Constraints
15
+
16
+ <What the solution may not do.>
17
+
18
+ ## 3. Decisions
19
+
20
+ **D1.** <Decision.> Rejected: <alternative>, because <why>.
21
+
22
+ ## 4. Design
23
+
24
+ <How it works.>
25
+
26
+ ## 5. Risks
27
+
28
+ <What could go wrong, how it would show up, and the response.>
29
+
30
+ ## 6. Phases
31
+
32
+ ### 6.1 Status ledger
33
+
34
+ | # | Phase | Status | Depends on | Note |
35
+ |---|---|---|---|---|
36
+ | 1 | <name> | not started | — | |
37
+ | 2 | <name> | not started | 1 | |
38
+
39
+ Status is one of `not started`, `in progress`, `blocked`, `done`. `done` only when committed and verified,
40
+ and whoever finishes a phase updates the row in the same commit.
41
+
42
+ **Exactly one table in this document has these columns.** Do not add a second phase table — a
43
+ differently-shaped one nearby is a decoy that gets read by mistake.
44
+
45
+ ### 6.2 The phases
46
+
47
+ #### Phase 1 — <name>
48
+
49
+ **Files:** <every path this phase creates or modifies>
50
+
51
+ **Scope:** <what it does>
52
+
53
+ **Done when:** <a condition checkable against the repo>
54
+
55
+ #### Phase 2 — <name>
56
+
57
+ **Files:** <every path this phase creates or modifies>
58
+
59
+ **Scope:** <what it does>
60
+
61
+ **Done when:** <a condition checkable against the repo>
62
+
63
+ ## 7. Verification
64
+
65
+ <How to prove the feature works, beyond `context/verify.md` passing.>
66
+
67
+ ## 8. Open questions
68
+
69
+ - <Anything the plan could not settle. An honest gap is worth more than an invented decision.>
@@ -0,0 +1,55 @@
1
+ # Filling in a Tier-2 plan
2
+
3
+ [`plan-template.md`](plan-template.md) is the skeleton. `/feature-plan` copies it **verbatim** into
4
+ `context/plans/<NAME>-PLAN.md` and then fills it in — there is no fenced block to extract and no italic
5
+ guidance to strip, because all of that is here instead.
6
+
7
+ Sections may be added. The ones in the template may not be dropped or reordered, and the ledger's column
8
+ set is fixed — `check` compares every plan's ledger against the template's.
9
+
10
+ ## What goes in each section
11
+
12
+ **§1 Why** — the problem, with evidence. Measurements, failing cases, user-visible symptoms; not "it would
13
+ be nice if". A reader who disagrees with this section should not read further, and a reader who agrees
14
+ should not need convincing again later.
15
+
16
+ **§2 Constraints** — what the solution may not do. Runtime limits, compatibility promises, things already
17
+ decided elsewhere that this must respect. Link to [`stack.md`](stack.md) rather than restating it.
18
+
19
+ **§3 Decisions** — numbered `D1`, `D2`, … so later sections and source comments can cite them by number.
20
+ Each one: the decision, the alternative rejected, and why. This is the section that stops a question being
21
+ re-litigated in three months.
22
+
23
+ **§4 Design** — how it works. Sub-sections as the shape of the work demands. Cite file paths for anything
24
+ that already exists.
25
+
26
+ **§5 Risks** — what could go wrong, how it would show up, and what the response is. "Unknown" is an
27
+ acceptable response; silence is not.
28
+
29
+ **§6.1 Status ledger** — one row per phase, `not started` in a newly written plan. Every row needs a real
30
+ `Depends on` value (`—` for none): the phase-selection rule *is* "lowest-numbered phase that is not `done`
31
+ and whose `Depends on` are all `done`", so a missing column silently degrades it.
32
+
33
+ **§6.2 The phases** — one sub-section per ledger row. **The `Files:` line is required, not advisory.** It
34
+ is what turns `/feature-status`'s reconciliation from a judgement call into a check: without it, "does the
35
+ repo match the ledger" has no answer. A phase is a **commit-sized unit of work with a checkable outcome**,
36
+ not a category of activity — "grammar plus container support for the new token" is a phase; "testing" is
37
+ not.
38
+
39
+ **§7 Verification** — how to prove the feature works, beyond [`verify.md`](verify.md) passing. Commands to
40
+ run by hand, files to eyeball, numbers to compare against §1's measurements. Anything that belongs to the
41
+ project's standing verification stack goes in `verify.md` instead, not here.
42
+
43
+ **§8 Open questions** — what the plan could not settle. Do not paper over them.
44
+
45
+ ## Standing rules
46
+
47
+ - **The document never states its own status.** No `**Status:**` header, ever. Feature status lives in
48
+ [`roadmap.md`](roadmap.md), phase status in §6.1, retired outcomes in [`history.md`](history.md) — one
49
+ place each. `check` fails a plan that grows one.
50
+ - **`/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.
52
+ - **Cite by §-number, not by line number.** Source comments cite plan sections; line numbers rot on the
53
+ first edit, and a §-number survives the move into `archive/`.
54
+ - **Never mark a phase `done` in a plan that has not been executed.** Every phase in a new plan is
55
+ `not started`.