create-rigel 0.1.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 (240) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +156 -0
  3. package/cli.js +122 -0
  4. package/package.json +47 -0
  5. package/templates/express/.claude/CLAUDE.md +114 -0
  6. package/templates/express/.claude/agents/arch-validator.md +85 -0
  7. package/templates/express/.claude/agents/db-optimizer.md +72 -0
  8. package/templates/express/.claude/agents/doc-gardener.md +67 -0
  9. package/templates/express/.claude/agents/garbage-collector.md +94 -0
  10. package/templates/express/.claude/agents/gate-checker.md +176 -0
  11. package/templates/express/.claude/agents/reviewer.md +84 -0
  12. package/templates/express/.claude/agents/security-auditor.md +82 -0
  13. package/templates/express/.claude/hooks/post-write.sh +93 -0
  14. package/templates/express/.claude/rules/api.md +149 -0
  15. package/templates/express/.claude/rules/architecture.md +78 -0
  16. package/templates/express/.claude/rules/database.md +104 -0
  17. package/templates/express/.claude/rules/jobs.md +81 -0
  18. package/templates/express/.claude/rules/security.md +92 -0
  19. package/templates/express/.claude/rules/testing.md +97 -0
  20. package/templates/express/.claude/settings.json +35 -0
  21. package/templates/express/.claude/skills/00-infra-setup/SKILL.md +479 -0
  22. package/templates/express/.claude/skills/01-write-roadmap/SKILL.md +72 -0
  23. package/templates/express/.claude/skills/02-write-spec/SKILL.md +119 -0
  24. package/templates/express/.claude/skills/03-write-plan/SKILL.md +124 -0
  25. package/templates/express/.claude/skills/04-build-layer/SKILL.md +216 -0
  26. package/templates/express/.claude/skills/05-validate-layer/SKILL.md +43 -0
  27. package/templates/express/.claude/skills/06-push-layer/SKILL.md +59 -0
  28. package/templates/express/.claude/skills/07-layer-check/SKILL.md +62 -0
  29. package/templates/express/.claude/skills/08-garbage-collect/SKILL.md +86 -0
  30. package/templates/express/.claude/skills/09-doc-garden/SKILL.md +64 -0
  31. package/templates/express/.claude/skills/10-db-optimize/SKILL.md +96 -0
  32. package/templates/express/.claude/skills/11-load-test/SKILL.md +77 -0
  33. package/templates/express/.dockerignore +43 -0
  34. package/templates/express/.env.example +42 -0
  35. package/templates/express/.github/CODEOWNERS +22 -0
  36. package/templates/express/.github/dependabot.yml +48 -0
  37. package/templates/express/.github/pull_request_template.md +58 -0
  38. package/templates/express/.github/workflows/ci.yml +278 -0
  39. package/templates/express/.github/workflows/load-test.yml +41 -0
  40. package/templates/express/.gitleaks.toml +18 -0
  41. package/templates/express/.lintstagedrc.json +3 -0
  42. package/templates/express/.nvmrc +1 -0
  43. package/templates/express/.prettierrc +8 -0
  44. package/templates/express/.sequelizerc +8 -0
  45. package/templates/express/AGENTS.md +94 -0
  46. package/templates/express/ARCHITECTURE.md +161 -0
  47. package/templates/express/Dockerfile +40 -0
  48. package/templates/express/Makefile +79 -0
  49. package/templates/express/QUICKSTART.md +131 -0
  50. package/templates/express/docker-compose.yml +114 -0
  51. package/templates/express/docs/PLANS.md +111 -0
  52. package/templates/express/docs/QUALITY_SCORE.md +66 -0
  53. package/templates/express/docs/design-docs/core-beliefs.md +89 -0
  54. package/templates/express/docs/design-docs/decisions/ADR-000-infrastructure.md +70 -0
  55. package/templates/express/docs/design-docs/decisions/ADR-001-observability.md +82 -0
  56. package/templates/express/docs/design-docs/decisions/index.md +23 -0
  57. package/templates/express/docs/design-docs/index.md +11 -0
  58. package/templates/express/docs/design-docs/observability.md +194 -0
  59. package/templates/express/docs/design-docs/team-workflow.md +64 -0
  60. package/templates/express/docs/exec-plans/active/.gitkeep +0 -0
  61. package/templates/express/docs/exec-plans/completed/.gitkeep +0 -0
  62. package/templates/express/docs/exec-plans/tech-debt-tracker.md +31 -0
  63. package/templates/express/docs/generated/.gitkeep +0 -0
  64. package/templates/express/docs/product-specs/ROADMAP.md +49 -0
  65. package/templates/express/docs/product-specs/draft/.gitkeep +0 -0
  66. package/templates/express/docs/product-specs/index.md +21 -0
  67. package/templates/express/docs/product-specs/ready/.gitkeep +0 -0
  68. package/templates/express/eslint.config.mjs +94 -0
  69. package/templates/express/gitignore +36 -0
  70. package/templates/express/infra/monitoring/alloy/config.alloy +59 -0
  71. package/templates/express/jest.config.ts +61 -0
  72. package/templates/express/package.json +45 -0
  73. package/templates/express/scripts/openapi.export.ts +77 -0
  74. package/templates/express/tests/architecture/isolation.test.ts +51 -0
  75. package/templates/express/tests/architecture/layers.test.ts +83 -0
  76. package/templates/express/tests/integration/health.test.ts +40 -0
  77. package/templates/express/tests/integration/isolation.test.template.ts +88 -0
  78. package/templates/express/tests/load/smoke.js +46 -0
  79. package/templates/express/tests/load/soak.js +45 -0
  80. package/templates/express/tests/load/stress.js +44 -0
  81. package/templates/express/tests/unit/utils/response.util.test.ts +53 -0
  82. package/templates/express/tsconfig.build.json +8 -0
  83. package/templates/express/tsconfig.json +20 -0
  84. package/templates/fastapi/.claude/CLAUDE.md +122 -0
  85. package/templates/fastapi/.claude/agents/arch-validator.md +64 -0
  86. package/templates/fastapi/.claude/agents/db-optimizer.md +59 -0
  87. package/templates/fastapi/.claude/agents/doc-gardener.md +55 -0
  88. package/templates/fastapi/.claude/agents/garbage-collector.md +74 -0
  89. package/templates/fastapi/.claude/agents/gate-checker.md +133 -0
  90. package/templates/fastapi/.claude/agents/reviewer.md +74 -0
  91. package/templates/fastapi/.claude/agents/security-auditor.md +69 -0
  92. package/templates/fastapi/.claude/hooks/post-write.sh +65 -0
  93. package/templates/fastapi/.claude/rules/api.md +119 -0
  94. package/templates/fastapi/.claude/rules/architecture.md +84 -0
  95. package/templates/fastapi/.claude/rules/database.md +153 -0
  96. package/templates/fastapi/.claude/rules/jobs.md +85 -0
  97. package/templates/fastapi/.claude/rules/security.md +102 -0
  98. package/templates/fastapi/.claude/rules/testing.md +207 -0
  99. package/templates/fastapi/.claude/settings.json +50 -0
  100. package/templates/fastapi/.claude/skills/00-infra-setup/SKILL.md +311 -0
  101. package/templates/fastapi/.claude/skills/01-write-roadmap/SKILL.md +61 -0
  102. package/templates/fastapi/.claude/skills/02-write-spec/SKILL.md +82 -0
  103. package/templates/fastapi/.claude/skills/03-write-plan/SKILL.md +83 -0
  104. package/templates/fastapi/.claude/skills/04-build-layer/SKILL.md +170 -0
  105. package/templates/fastapi/.claude/skills/05-validate-layer/SKILL.md +20 -0
  106. package/templates/fastapi/.claude/skills/06-push-layer/SKILL.md +31 -0
  107. package/templates/fastapi/.claude/skills/07-layer-check/SKILL.md +51 -0
  108. package/templates/fastapi/.claude/skills/08-garbage-collect/SKILL.md +47 -0
  109. package/templates/fastapi/.claude/skills/09-doc-garden/SKILL.md +9 -0
  110. package/templates/fastapi/.claude/skills/10-db-optimize/SKILL.md +53 -0
  111. package/templates/fastapi/.claude/skills/11-load-test/SKILL.md +81 -0
  112. package/templates/fastapi/.dockerignore +30 -0
  113. package/templates/fastapi/.github/dependabot.yml +24 -0
  114. package/templates/fastapi/AGENTS.md +87 -0
  115. package/templates/fastapi/ARCHITECTURE.md +141 -0
  116. package/templates/fastapi/Makefile +42 -0
  117. package/templates/fastapi/README.md +179 -0
  118. package/templates/fastapi/docs/PLANS.md +26 -0
  119. package/templates/fastapi/docs/QUALITY_SCORE.md +26 -0
  120. package/templates/fastapi/docs/design-docs/core-beliefs.md +46 -0
  121. package/templates/fastapi/docs/design-docs/decisions/ADR-000-infrastructure.md +79 -0
  122. package/templates/fastapi/docs/design-docs/decisions/index.md +7 -0
  123. package/templates/fastapi/docs/design-docs/index.md +9 -0
  124. package/templates/fastapi/docs/exec-plans/active/.gitkeep +0 -0
  125. package/templates/fastapi/docs/exec-plans/completed/.gitkeep +0 -0
  126. package/templates/fastapi/docs/exec-plans/tech-debt-tracker.md +19 -0
  127. package/templates/fastapi/docs/generated/.gitkeep +0 -0
  128. package/templates/fastapi/docs/product-specs/ROADMAP.md +49 -0
  129. package/templates/fastapi/docs/product-specs/draft/.gitkeep +0 -0
  130. package/templates/fastapi/docs/product-specs/index.md +18 -0
  131. package/templates/fastapi/docs/product-specs/ready/.gitkeep +0 -0
  132. package/templates/fastapi/gitignore +46 -0
  133. package/templates/fastapi/scripts/gate.sh +68 -0
  134. package/templates/nestjs/.claude/CLAUDE.md +121 -0
  135. package/templates/nestjs/.claude/agents/db-optimizer.md +51 -0
  136. package/templates/nestjs/.claude/agents/doc-gardener.md +45 -0
  137. package/templates/nestjs/.claude/agents/garbage-collector.md +50 -0
  138. package/templates/nestjs/.claude/agents/gate-checker.md +127 -0
  139. package/templates/nestjs/.claude/agents/reviewer.md +68 -0
  140. package/templates/nestjs/.claude/agents/security-auditor.md +72 -0
  141. package/templates/nestjs/.claude/hooks/post-write.sh +91 -0
  142. package/templates/nestjs/.claude/rules/api.md +87 -0
  143. package/templates/nestjs/.claude/rules/architecture.md +104 -0
  144. package/templates/nestjs/.claude/rules/database.md +111 -0
  145. package/templates/nestjs/.claude/rules/security.md +110 -0
  146. package/templates/nestjs/.claude/rules/testing.md +145 -0
  147. package/templates/nestjs/.claude/settings.json +33 -0
  148. package/templates/nestjs/.claude/skills/00-infra-setup/SKILL.md +222 -0
  149. package/templates/nestjs/.claude/skills/01-write-spec/SKILL.md +25 -0
  150. package/templates/nestjs/.claude/skills/02-write-plan/SKILL.md +18 -0
  151. package/templates/nestjs/.claude/skills/03-build-layer/SKILL.md +242 -0
  152. package/templates/nestjs/.claude/skills/04-validate-layer/SKILL.md +4 -0
  153. package/templates/nestjs/.claude/skills/05-push-layer/SKILL.md +6 -0
  154. package/templates/nestjs/.claude/skills/06-layer-check/SKILL.md +12 -0
  155. package/templates/nestjs/.claude/skills/07-garbage-collect/SKILL.md +2 -0
  156. package/templates/nestjs/.claude/skills/08-doc-garden/SKILL.md +4 -0
  157. package/templates/nestjs/.claude/skills/09-api-sync/SKILL.md +36 -0
  158. package/templates/nestjs/.claude/skills/10-load-test/SKILL.md +29 -0
  159. package/templates/nestjs/.env.example +11 -0
  160. package/templates/nestjs/AGENTS.md +88 -0
  161. package/templates/nestjs/ARCHITECTURE.md +192 -0
  162. package/templates/nestjs/docs/PLANS.md +22 -0
  163. package/templates/nestjs/docs/QUALITY_SCORE.md +27 -0
  164. package/templates/nestjs/docs/design-docs/core-beliefs.md +18 -0
  165. package/templates/nestjs/docs/design-docs/decisions/ADR-000-infrastructure.md +58 -0
  166. package/templates/nestjs/docs/design-docs/decisions/index.md +7 -0
  167. package/templates/nestjs/docs/design-docs/index.md +7 -0
  168. package/templates/nestjs/docs/exec-plans/active/.gitkeep +0 -0
  169. package/templates/nestjs/docs/exec-plans/completed/.gitkeep +0 -0
  170. package/templates/nestjs/docs/exec-plans/tech-debt-tracker.md +16 -0
  171. package/templates/nestjs/docs/generated/.gitkeep +0 -0
  172. package/templates/nestjs/docs/product-specs/draft/.gitkeep +0 -0
  173. package/templates/nestjs/docs/product-specs/index.md +7 -0
  174. package/templates/nestjs/docs/product-specs/ready/.gitkeep +0 -0
  175. package/templates/nestjs/gitignore +8 -0
  176. package/templates/nextjs/.claude/CLAUDE.md +139 -0
  177. package/templates/nextjs/.claude/agents/arch-validator.md +66 -0
  178. package/templates/nextjs/.claude/agents/contract-checker.md +78 -0
  179. package/templates/nextjs/.claude/agents/doc-gardener.md +52 -0
  180. package/templates/nextjs/.claude/agents/garbage-collector.md +61 -0
  181. package/templates/nextjs/.claude/agents/gate-checker.md +129 -0
  182. package/templates/nextjs/.claude/agents/perf-auditor.md +109 -0
  183. package/templates/nextjs/.claude/agents/reviewer.md +79 -0
  184. package/templates/nextjs/.claude/agents/security-auditor.md +50 -0
  185. package/templates/nextjs/.claude/hooks/post-write.sh +121 -0
  186. package/templates/nextjs/.claude/rules/api-contract.md +166 -0
  187. package/templates/nextjs/.claude/rules/architecture.md +99 -0
  188. package/templates/nextjs/.claude/rules/components.md +122 -0
  189. package/templates/nextjs/.claude/rules/security.md +122 -0
  190. package/templates/nextjs/.claude/rules/testing.md +187 -0
  191. package/templates/nextjs/.claude/scripts/infra-setup.sh +550 -0
  192. package/templates/nextjs/.claude/settings.json +33 -0
  193. package/templates/nextjs/.claude/skills/00-infra-setup/SKILL.md +471 -0
  194. package/templates/nextjs/.claude/skills/01-write-roadmap/SKILL.md +77 -0
  195. package/templates/nextjs/.claude/skills/02-write-spec/SKILL.md +78 -0
  196. package/templates/nextjs/.claude/skills/03-write-plan/SKILL.md +91 -0
  197. package/templates/nextjs/.claude/skills/04-build-layer/SKILL.md +141 -0
  198. package/templates/nextjs/.claude/skills/05-validate-layer/SKILL.md +13 -0
  199. package/templates/nextjs/.claude/skills/06-push-layer/SKILL.md +20 -0
  200. package/templates/nextjs/.claude/skills/07-layer-check/SKILL.md +28 -0
  201. package/templates/nextjs/.claude/skills/08-garbage-collect/SKILL.md +14 -0
  202. package/templates/nextjs/.claude/skills/09-doc-garden/SKILL.md +12 -0
  203. package/templates/nextjs/.claude/skills/10-api-sync/SKILL.md +50 -0
  204. package/templates/nextjs/.claude/skills/11-perf-budget/SKILL.md +51 -0
  205. package/templates/nextjs/.dockerignore +25 -0
  206. package/templates/nextjs/.gitattributes +10 -0
  207. package/templates/nextjs/.github/CODEOWNERS +24 -0
  208. package/templates/nextjs/.github/dependabot.yml +31 -0
  209. package/templates/nextjs/.github/pull_request_template.md +59 -0
  210. package/templates/nextjs/.github/workflows/ci.yml +143 -0
  211. package/templates/nextjs/.github/workflows/lighthouse.yml +54 -0
  212. package/templates/nextjs/.github/workflows/load-test.yml +54 -0
  213. package/templates/nextjs/.husky/pre-commit +1 -0
  214. package/templates/nextjs/.lintstagedrc.json +4 -0
  215. package/templates/nextjs/.mcp.json +8 -0
  216. package/templates/nextjs/.prettierignore +13 -0
  217. package/templates/nextjs/.prettierrc +9 -0
  218. package/templates/nextjs/AGENTS.md +88 -0
  219. package/templates/nextjs/ARCHITECTURE.md +165 -0
  220. package/templates/nextjs/Dockerfile +38 -0
  221. package/templates/nextjs/Makefile +50 -0
  222. package/templates/nextjs/QUICKSTART.md +128 -0
  223. package/templates/nextjs/docs/PLANS.md +23 -0
  224. package/templates/nextjs/docs/QUALITY_SCORE.md +27 -0
  225. package/templates/nextjs/docs/design-docs/core-beliefs.md +43 -0
  226. package/templates/nextjs/docs/design-docs/decisions/ADR-000-infrastructure.md +72 -0
  227. package/templates/nextjs/docs/design-docs/decisions/index.md +7 -0
  228. package/templates/nextjs/docs/design-docs/index.md +7 -0
  229. package/templates/nextjs/docs/design-docs/team-workflow.md +66 -0
  230. package/templates/nextjs/docs/exec-plans/active/.gitkeep +0 -0
  231. package/templates/nextjs/docs/exec-plans/completed/.gitkeep +0 -0
  232. package/templates/nextjs/docs/exec-plans/tech-debt-tracker.md +19 -0
  233. package/templates/nextjs/docs/generated/.gitkeep +0 -0
  234. package/templates/nextjs/docs/product-specs/ROADMAP.md +59 -0
  235. package/templates/nextjs/docs/product-specs/draft/.gitkeep +0 -0
  236. package/templates/nextjs/docs/product-specs/index.md +18 -0
  237. package/templates/nextjs/docs/product-specs/ready/.gitkeep +0 -0
  238. package/templates/nextjs/eslint.config.mjs +150 -0
  239. package/templates/nextjs/gitignore +35 -0
  240. package/templates/nextjs/lighthouserc.js +37 -0
@@ -0,0 +1,471 @@
1
+ # /infra-setup — Phase 0 Infrastructure Setup
2
+
3
+ > **Verified:** 2026-06-18 · **Staleness threshold:** 60 days
4
+ > **Sources:** create-next-app (https://nextjs.org/docs/app/api-reference/cli/create-next-app) ·
5
+ > shadcn/ui (https://ui.shadcn.com/docs/cli) · TanStack Query (https://tanstack.com/query) ·
6
+ > ESLint flat config (https://eslint.org/docs/latest/use/configure/configuration-files)
7
+ > If older than the threshold, fetch current docs via `ctx7` (resolve library → fetch docs),
8
+ > or via `WebFetch`/`WebSearch` if ctx7 is unavailable, **before** following the commands.
9
+
10
+ Triggered by: `/infra-setup`
11
+ Run ONCE. Check if `package.json` exists first — if yes, abort (already set up).
12
+
13
+ ---
14
+
15
+ ## How to run this skill (two phases)
16
+
17
+ **Phase A — scaffold the Next.js app (Step 1 below).** `create-next-app` refuses to run
18
+ in a non-empty directory, and this harness ships files (`.claude/`, `.github/`, `docs/`,
19
+ configs…) that it treats as conflicts. So Step 1 **parks the harness files aside**, runs
20
+ the plain `npx create-next-app@latest .` into the now-empty root, then **restores** them.
21
+ Run this block directly — it cannot be a script, because any script under `.claude/`
22
+ would be parked away mid-run.
23
+
24
+ **Phase B — deterministic setup (Steps 2–4 + scripts + husky).** Once the app exists,
25
+ run the checked-in script — identical every time:
26
+
27
+ ```bash
28
+ bash .claude/scripts/infra-setup.sh
29
+ ```
30
+
31
+ Then **you** author the harness glue (Step 5) and config edits (Steps 6–8), which need
32
+ judgement and cannot be scripted. The Steps below document what runs (so they can be
33
+ audited/updated when the Verified date is stale) and what you must hand-author.
34
+
35
+ > If a command fails on a tool version change, fix it, re-run, and bump the `Verified:`
36
+ > date above — do not silently hand-run divergent commands.
37
+
38
+ ---
39
+
40
+ ## Cardinal Scaffolding Rule
41
+
42
+ **Never hand-write boilerplate the CLI can generate.**
43
+ `create-next-app` and `npx shadcn` own the app shell, root layout, base pages, and UI
44
+ components. Dependencies install at their **latest LTS** — no version pins (bare
45
+ `npm install <pkg>`). Hand-authoring is restricted to **harness glue with no generator**
46
+ (see Step 5). If a generator exists for an artifact, run it and edit its output rather
47
+ than writing the file from scratch.
48
+
49
+ ---
50
+
51
+ ## Step 1 — Create Next.js App (park → scaffold → restore)
52
+
53
+ Run this block **directly** (not via a script — `.claude/` gets parked). It moves the
54
+ harness files aside, runs the plain `create-next-app` in the empty root, then restores
55
+ the harness on top of the generated app (our files win on the one overlap, `.gitignore`).
56
+
57
+ ```bash
58
+ # Abort if already set up
59
+ [ -f package.json ] && { echo "package.json exists — infra already run. Aborting."; exit 1; }
60
+
61
+ # 1. Park every harness file create-next-app would treat as a conflict.
62
+ # CRITICAL: park to a dir OUTSIDE the project. create-next-app refuses to run if the
63
+ # cwd contains ANYTHING except a known-safe allowlist (.git is fine) — a `.harness-hold`
64
+ # SUBDIR would itself be flagged as a conflict and abort the scaffold. So park to an
65
+ # external temp dir, leaving only .git behind.
66
+ # eslint.config.mjs is parked too — we restore OUR version on top so it wins over
67
+ # the one create-next-app generates (it carries the layer-boundary rules).
68
+ HOLD=$(mktemp -d)
69
+ for f in .claude .github .husky docs \
70
+ .prettierrc .prettierignore .lintstagedrc.json .gitattributes .gitignore .mcp.json \
71
+ eslint.config.mjs Dockerfile .dockerignore Makefile \
72
+ lighthouserc.js AGENTS.md ARCHITECTURE.md QUICKSTART.md; do
73
+ [ -e "$f" ] && mv "$f" "$HOLD"/
74
+ done
75
+
76
+ # 2. Scaffold into the now-empty root (plain, non-interactive)
77
+ npx create-next-app@latest . \
78
+ --typescript --tailwind --eslint --app --src-dir \
79
+ --import-alias "@/*" --turbopack --use-npm --yes
80
+
81
+ # 3. Restore the harness on top (clobber: our .gitignore/configs win over generated)
82
+ cp -a "$HOLD"/. ./
83
+ rm -rf "$HOLD"
84
+ ```
85
+
86
+ > If `create-next-app` lists a NEW conflicting file not in the park list above, add it to
87
+ > the `for f in …` list and re-run. `.git` is never parked (create-next-app tolerates it).
88
+
89
+ ## Step 2 — Install All Dependencies
90
+ > Steps 2–4 + package.json scripts + husky are performed by `bash .claude/scripts/infra-setup.sh`.
91
+ > The detail below documents what that script runs.
92
+ ```bash
93
+ # Server state + API contract
94
+ npm install @tanstack/react-query @tanstack/react-query-devtools
95
+ npm install openapi-fetch
96
+ npm install -D openapi-typescript
97
+
98
+ # Client state
99
+ npm install zustand
100
+
101
+ # Forms + validation
102
+ npm install react-hook-form @hookform/resolvers zod
103
+
104
+ # shadcn/ui CLI
105
+ npm install -D shadcn
106
+
107
+ # Testing
108
+ npm install -D vitest @vitejs/plugin-react jsdom
109
+ npm install -D @testing-library/react @testing-library/user-event @testing-library/jest-dom
110
+ npm install -D msw playwright @playwright/test
111
+ npm install -D @vitest/coverage-v8
112
+
113
+ # Performance
114
+ npm install -D @next/bundle-analyzer
115
+
116
+ # Linting (the committed eslint.config.mjs uses Next's native flat config — no FlatCompat)
117
+ npm install -D @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint-plugin-import
118
+ ```
119
+
120
+ ## Step 3 — Initialise shadcn/ui
121
+ ```bash
122
+ npx shadcn init
123
+ # Select: Default style, CSS variables for colors
124
+ # This creates components.json and src/components/ui/
125
+ ```
126
+
127
+ Add base components:
128
+ ```bash
129
+ npx shadcn add button input label form card dialog toast badge skeleton
130
+ ```
131
+
132
+ ## Step 4 — Directory Structure
133
+ ```bash
134
+ mkdir -p \
135
+ src/types \
136
+ src/lib \
137
+ src/hooks \
138
+ src/store \
139
+ src/features \
140
+ src/components/shared \
141
+ src/utils \
142
+ tests/unit/{hooks,features,components,utils} \
143
+ tests/e2e \
144
+ tests/visual \
145
+ tests/architecture \
146
+ tests/mocks \
147
+ docs/{product-specs/{draft,ready},exec-plans/{active,completed},design-docs/decisions,generated}
148
+ ```
149
+
150
+ ## Step 5 — Create Harness Glue (only files with no CLI generator)
151
+
152
+ Per the Cardinal Scaffolding Rule, Claude authors **only** the files below — none of
153
+ these can be produced by `create-next-app` or `npx shadcn`. The root layout, base
154
+ page, and all UI components come from the generators (Step 1 + Step 3); do **not**
155
+ re-create them. Auth/dashboard route groups and their pages are **feature-build
156
+ concerns**, not Phase 0 — they are created later by `/build-layer`, not here.
157
+
158
+ ### src/lib/env.ts
159
+ Zod-validated NEXT_PUBLIC_* env vars. `process.env` ONLY here.
160
+ Schema includes: `NEXT_PUBLIC_API_URL`.
161
+ On invalid: `console.error` + `throw new Error` (not process.exit — browser context).
162
+
163
+ ### src/lib/api-client.ts
164
+ openapi-fetch `createClient<paths>` instance.
165
+ Auth middleware reads token from React context.
166
+ Base URL from `env.NEXT_PUBLIC_API_URL`.
167
+ Import type `paths` from `@/types/api.generated` (will exist after /api-sync).
168
+ **REQUIRED: pass a lazy `fetch`** so MSW can intercept in tests — openapi-fetch binds
169
+ `globalThis.fetch` at client-creation time (before MSW patches it in `beforeAll`), so a
170
+ client created at import time would capture the un-patched fetch and every hook test
171
+ would hit the real network (flaky `ECONNREFUSED`). Wrap it:
172
+ ```typescript
173
+ export const apiClient = createClient<paths>({
174
+ baseUrl: env.NEXT_PUBLIC_API_URL,
175
+ fetch: (...args) => globalThis.fetch(...args), // lazy — lets MSW intercept in tests
176
+ })
177
+ ```
178
+
179
+ ### src/lib/constants.ts
180
+ App-wide constants. No process.env.
181
+
182
+ ### Script-written glue (do NOT hand-author — `infra-setup.sh` Step 7 writes these)
183
+ - `src/lib/logger.ts` — zero-dep structured JSON logger (the only sanctioned logging path)
184
+ - `src/lib/api-error.ts` — `toApiError`/`ApiError` (normalises the canonical error envelope)
185
+ - `src/instrumentation.ts` — Next.js boot/observability seam
186
+ - `src/app/global-error.tsx` — root error boundary that reports via the logger
187
+ - `.env.example`, the per-layer `vitest.config.ts`, `playwright.config.ts`, `tests/setup.ts`,
188
+ `tests/architecture/layers.test.ts`, `tests/e2e/isolation.spec.ts` (+ `helpers/auth.ts`),
189
+ and `tests/load/{smoke,stress,soak}.js`
190
+
191
+ ### src/utils/cn.util.ts
192
+ `clsx` + `tailwind-merge` class merger. 100% tested.
193
+ (Note: `npx shadcn init` may also generate a `cn` helper in `src/lib/utils.ts` —
194
+ if so, re-export from there instead of duplicating.)
195
+
196
+ ### src/utils/format-date.util.ts
197
+ Date formatting helpers. 100% tested.
198
+
199
+ ### src/utils/parse-error.util.ts
200
+ Safely extract error message from unknown. 100% tested.
201
+
202
+ ### src/store/ui-store.ts
203
+ Zustand store for UI-only state: `sidebarOpen`, `activeModal`.
204
+
205
+ ### src/types/domain.types.ts
206
+ Placeholder — frontend-only types added here as features are built.
207
+
208
+ ### src/types/api.generated.ts
209
+ Placeholder with comment: `// READ ONLY — regenerate with: npm run api:sync`
210
+ Actual content generated by /api-sync after OpenAPI spec is available.
211
+
212
+ ### tests/mocks/server.ts + tests/mocks/handlers.ts
213
+ MSW server setup for Vitest.
214
+
215
+ ### tests/utils/create-wrapper.tsx
216
+ React QueryClient wrapper for renderHook tests.
217
+
218
+ ### tests/architecture/layers.test.ts — WRITTEN BY THE SCRIPT (do not hand-author)
219
+ Dependency-free import-graph structural tests (Node `fs` only). **`.claude/scripts/infra-setup.sh`
220
+ (Step 6) writes this file**, so the gate is deterministic, not improvised — the gate
221
+ (`tests/architecture/`) and CI both depend on this exact file. Shown here for reference:
222
+
223
+ ```typescript
224
+ import { describe, it, expect } from 'vitest'
225
+ import { readdirSync, readFileSync, statSync, existsSync } from 'node:fs'
226
+ import { join } from 'node:path'
227
+
228
+ // Layer import rules. A layer must NOT import from any of its "forbidden" layers.
229
+ // Aliases are matched as `@/<layer>` and bare `app/` imports.
230
+ const RULES: Record<string, string[]> = {
231
+ 'src/types': ['@/lib', '@/hooks', '@/features', '@/store', '@/components'],
232
+ 'src/lib': ['@/hooks', '@/features', '@/components'],
233
+ 'src/store': ['@/hooks', '@/features', '@/components'],
234
+ 'src/hooks': ['@/features', '@/components'],
235
+ 'src/features': ['app/'],
236
+ }
237
+
238
+ function walk(dir: string): string[] {
239
+ if (!existsSync(dir)) return []
240
+ return readdirSync(dir).flatMap((name) => {
241
+ const full = join(dir, name)
242
+ if (statSync(full).isDirectory()) return walk(full)
243
+ return /\.(ts|tsx)$/.test(full) && !full.endsWith('.d.ts') ? [full] : []
244
+ })
245
+ }
246
+
247
+ const IMPORT_RE = /(?:import|from)\s+['"]([^'"]+)['"]/g
248
+
249
+ function importsOf(file: string): string[] {
250
+ const src = readFileSync(file, 'utf8')
251
+ const out: string[] = []
252
+ for (const m of src.matchAll(IMPORT_RE)) out.push(m[1])
253
+ return out
254
+ }
255
+
256
+ describe('layer import rules', () => {
257
+ for (const [layer, forbidden] of Object.entries(RULES)) {
258
+ it(`${layer} does not import from ${forbidden.join(', ')}`, () => {
259
+ const violations: string[] = []
260
+ for (const file of walk(layer)) {
261
+ for (const imp of importsOf(file)) {
262
+ const hit = forbidden.some((f) => {
263
+ const base = f.endsWith('/') ? f.slice(0, -1) : f
264
+ return imp === base || imp.startsWith(base + '/')
265
+ })
266
+ if (hit) violations.push(`${file} → ${imp}`)
267
+ }
268
+ }
269
+ expect(violations, violations.join('\n')).toHaveLength(0)
270
+ })
271
+ }
272
+ })
273
+
274
+ describe('app pages contain no business logic', () => {
275
+ it('page.tsx files import features, not hooks directly', () => {
276
+ const pages = walk('app').filter((f) => f.endsWith('page.tsx'))
277
+ const violations = pages.filter((f) =>
278
+ importsOf(f).some((imp) => imp.startsWith('@/hooks')),
279
+ )
280
+ expect(violations, violations.join('\n')).toHaveLength(0)
281
+ })
282
+ })
283
+ ```
284
+
285
+ ### src/components/providers.tsx
286
+ `'use client'` Providers component: QueryClientProvider (+ devtools), toast provider.
287
+ This holds the client-side context that the generated root layout cannot.
288
+
289
+ ### Wire providers into the generated layout (edit, not rewrite)
290
+ `app/layout.tsx` is generated by `create-next-app`. **Edit** it to wrap `{children}`
291
+ in `<Providers>` from `src/components/providers.tsx`. Keep the generated font setup and
292
+ metadata; do not rewrite the file from scratch.
293
+
294
+ ## Step 6 — Config Files
295
+
296
+ `create-next-app` already generated `next.config.ts` and `tsconfig.json`. **Edit**
297
+ `next.config.ts` to add the settings below — do not recreate it.
298
+
299
+ `vitest.config.ts`, `playwright.config.ts`, and `tests/setup.ts` are **written by
300
+ `.claude/scripts/infra-setup.sh` (Step 5)** — do not author them by hand. The
301
+ `vitest.config.ts` it writes carries the **per-layer coverage thresholds** (utils 100 ·
302
+ hooks 80 · features 70 · components 70) that match `.claude/rules/testing.md`; they are
303
+ real, machine-enforced gates, not prose. Shown below for reference.
304
+
305
+ `eslint.config.mjs` is **committed by the harness** and restored on top of the generated
306
+ one (Step 1 park-and-restore) — it carries the layer-import boundaries. Do not hand-edit
307
+ boundaries into the generated file; edit the committed `eslint.config.mjs` instead.
308
+
309
+ ### next.config.ts (base is SCRIPT-WRITTEN; you only add version-gated extras)
310
+ `infra-setup.sh` (Step 5) overwrites the generated `next.config.ts` with a base that has
311
+ `output: 'standalone'` (required by the Dockerfile) + security headers. **Only** add
312
+ `reactCompiler`/`typedRoutes` here if you've confirmed the installed Next version supports
313
+ them (they're version-sensitive — `reactCompiler` may need `babel-plugin-react-compiler`,
314
+ and `typedRoutes` moved out of `experimental`). Full reference shape:
315
+ ```typescript
316
+ import type { NextConfig } from 'next'
317
+ const nextConfig: NextConfig = {
318
+ output: 'standalone', // minimal server bundle for the Docker runner stage (script writes this)
319
+ reactCompiler: true, // OPTIONAL — only if the installed Next version supports it
320
+ experimental: {
321
+ typedRoutes: true, // OPTIONAL — note: top-level `typedRoutes` in newer Next
322
+ },
323
+ // Security headers
324
+ async headers() {
325
+ return [{
326
+ source: '/(.*)',
327
+ headers: [
328
+ { key: 'X-Frame-Options', value: 'DENY' },
329
+ { key: 'X-Content-Type-Options', value: 'nosniff' },
330
+ { key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' },
331
+ { key: 'Permissions-Policy', value: 'camera=(), microphone=(), geolocation=()' },
332
+ ],
333
+ }]
334
+ },
335
+ }
336
+ export default nextConfig
337
+ ```
338
+
339
+ ### vitest.config.ts
340
+ ```typescript
341
+ import { defineConfig } from 'vitest/config'
342
+ import react from '@vitejs/plugin-react'
343
+ import path from 'path'
344
+
345
+ export default defineConfig({
346
+ plugins: [react()],
347
+ test: {
348
+ environment: 'jsdom',
349
+ globals: true,
350
+ setupFiles: ['./tests/setup.ts'],
351
+ coverage: {
352
+ provider: 'v8',
353
+ include: ['src/**/*.{ts,tsx}'],
354
+ exclude: ['src/types/api.generated.ts', 'src/components/ui/**'],
355
+ thresholds: { lines: 70, functions: 70, branches: 65 },
356
+ },
357
+ },
358
+ resolve: { alias: { '@': path.resolve(__dirname, './src') } },
359
+ })
360
+ ```
361
+
362
+ ### playwright.config.ts
363
+ ```typescript
364
+ import { defineConfig, devices } from '@playwright/test'
365
+ export default defineConfig({
366
+ testDir: './tests/e2e',
367
+ fullyParallel: true,
368
+ forbidOnly: !!process.env.CI,
369
+ retries: process.env.CI ? 2 : 0,
370
+ use: {
371
+ baseURL: 'http://localhost:3000',
372
+ trace: 'on-first-retry',
373
+ },
374
+ projects: [{ name: 'chromium', use: { ...devices['Desktop Chrome'] } }],
375
+ webServer: {
376
+ command: 'npm run dev',
377
+ url: 'http://localhost:3000',
378
+ reuseExistingServer: !process.env.CI,
379
+ },
380
+ })
381
+ ```
382
+
383
+ ### tests/setup.ts
384
+ ```typescript
385
+ import '@testing-library/jest-dom/vitest'
386
+ import { beforeAll, afterAll, afterEach } from 'vitest'
387
+ import { server } from './mocks/server'
388
+ beforeAll(() => server.listen({ onUnhandledRequest: 'warn' }))
389
+ afterEach(() => server.resetHandlers())
390
+ afterAll(() => server.close())
391
+ ```
392
+
393
+ ### package.json scripts (the script in `.claude/scripts/infra-setup.sh` adds these)
394
+ `dev` / `build` / `start` keep create-next-app's values; the harness adds the rest.
395
+ Note `lint` uses **`eslint .`** (flat config), NOT the deprecated `next lint`, and `gate`
396
+ is the single command `/push-layer` and `/validate-layer` run.
397
+ ```json
398
+ {
399
+ "scripts": {
400
+ "dev": "next dev",
401
+ "build": "next build",
402
+ "start": "next start",
403
+ "api:sync": "openapi-typescript openapi.json -o src/types/api.generated.ts",
404
+ "test": "vitest",
405
+ "test:ui": "vitest --ui",
406
+ "test:coverage": "vitest run --coverage",
407
+ "test:e2e": "playwright test",
408
+ "test:visual": "playwright test tests/visual/",
409
+ "typecheck": "tsc --noEmit",
410
+ "lint": "eslint .",
411
+ "lint:fix": "eslint . --fix",
412
+ "format": "prettier --write .",
413
+ "format:check": "prettier --check .",
414
+ "gate": "npm run typecheck && npm run lint && npm run format:check && npm run test:coverage",
415
+ "analyze": "ANALYZE=true next build",
416
+ "prepare": "husky"
417
+ }
418
+ }
419
+ ```
420
+
421
+ ### Committed dev-experience tooling (already in the template — no authoring needed)
422
+ These files ship with the template; the script installs their deps and activates husky:
423
+ - `.prettierrc` + `.prettierignore` — Prettier (with `prettier-plugin-tailwindcss`)
424
+ - `.lintstagedrc.json` + `.husky/pre-commit` — pre-commit runs `lint-staged`
425
+ (eslint --fix + prettier on staged files)
426
+ - `.github/workflows/ci.yml` — typecheck · lint · format · test · build on PR
427
+ - `.github/workflows/lighthouse.yml` + `lighthouserc.js` — Core Web Vitals budget
428
+ - `docs/design-docs/team-workflow.md` — branch protection + review policy
429
+
430
+ ### .env.example
431
+ ```
432
+ NEXT_PUBLIC_API_URL=http://localhost:8000
433
+ ```
434
+
435
+ ## Step 7 — ESLint Config (committed `eslint.config.mjs` — nothing to author)
436
+ The harness ships `eslint.config.mjs` (restored over the generated one in Step 1). It
437
+ already enforces, mechanically:
438
+ - `no-restricted-syntax` blocking `process.env` outside `src/lib/` and direct `fetch()`
439
+ outside the hooks layer
440
+ - `no-restricted-imports` enforcing the full layer-import matrix (and "no `@/hooks` in
441
+ pages")
442
+ - `no-console` at warning level
443
+ - `eslint-config-prettier` LAST so Prettier owns formatting
444
+ To change a boundary, edit the committed `eslint.config.mjs` — do NOT add rules to a
445
+ generated file that the next scaffold would overwrite.
446
+
447
+ ## Step 8 — Write ADR-000
448
+ `docs/design-docs/decisions/ADR-000-infrastructure.md`
449
+ Document stack choices: Next.js, openapi-typescript, TanStack Query, Zustand, Vitest.
450
+
451
+ ## Gate Check
452
+ ```bash
453
+ npm run gate # typecheck + lint (flat config) + format:check + test:coverage (incl. tests/architecture/)
454
+ ```
455
+
456
+ ## Commit
457
+ ```bash
458
+ git add -A
459
+ git commit -m "chore(infra): phase 0 infrastructure setup
460
+
461
+ - Next.js + React + TypeScript strict (latest LTS, no version pins)
462
+ - TanStack Query + openapi-fetch (API contract layer)
463
+ - Zustand (UI state)
464
+ - shadcn/ui + Tailwind CSS
465
+ - Vitest + Playwright + MSW
466
+ - Security headers in next.config.ts
467
+ - React Compiler enabled
468
+ - Architecture structural tests
469
+ - ADR-000: infrastructure decisions"
470
+ git push origin main
471
+ ```
@@ -0,0 +1,77 @@
1
+ # /write-roadmap — Decompose a Product Frontend into an Ordered Spec Roadmap
2
+
3
+ Triggered by: `/write-roadmap` (optional arg: path to the product brief; else ask the human)
4
+
5
+ This is the altitude ABOVE specs. A real product frontend is many screens/flows across several
6
+ feature areas and personas — this skill plans that SET, ordered by dependency, and picks a
7
+ walking-skeleton first slice. It writes ONLY `docs/product-specs/ROADMAP.md`; it NEVER writes
8
+ spec files (that is `/write-spec`'s job, which owns spec numbering).
9
+
10
+ **Two inputs:** the same product **brief** the backend used, and the backend **`openapi.json`**
11
+ (the real contract). The brief says *what/for whom/which personas*; the OpenAPI says *what is
12
+ actually buildable*. The frontend roadmap is NOT a mirror of the backend roadmap — it
13
+ re-decomposes the product along **frontend axes** (screens, flows, personas, real-time).
14
+
15
+ ## Step 1 — Gather Brief + Contract
16
+ Read the product brief (arg path, or ask the human to paste it). Confirm the backend contract is
17
+ present:
18
+ ```bash
19
+ ls openapi.json src/types/api.generated.ts 2>/dev/null
20
+ ```
21
+ If `openapi.json` exists but `api.generated.ts` doesn't (or may be stale), tell the human to run
22
+ `/api-sync` first so the roadmap can reference real endpoints. Do not proceed without a brief.
23
+
24
+ ## Step 2 — Check for an Existing Roadmap (refresh, don't clobber)
25
+ ```bash
26
+ ls docs/product-specs/ROADMAP.md 2>/dev/null && echo "EXISTS — refresh: keep created specs"
27
+ ls docs/product-specs/{draft,ready}/ 2>/dev/null | grep "SPEC-" | sort
28
+ ```
29
+ If a roadmap exists you are REFRESHING: preserve every row that already has a real Spec ID and
30
+ its Status; only add/reorder `NOT_STARTED` rows. Never renumber a created spec.
31
+
32
+ ## Step 3 — Identify Feature Areas & Personas
33
+ From the brief + the OpenAPI tags, group the UI into a SMALL set of **feature areas** (screen
34
+ clusters), and note the **personas** (e.g. agent, supervisor, admin) — different personas are
35
+ often different surfaces over the same API. Two truths that make this NOT a 1:1 map of endpoints:
36
+ - One screen composes MANY endpoints (a dashboard pulls several domains + a live feed).
37
+ - Many endpoints have NO UI (machine-to-machine: ingestion, orchestration, internal jobs).
38
+ So the OpenAPI is the *contract*, not the roadmap — you decide the screens.
39
+
40
+ ## Step 4 — Order Specs by Dependency + Map to Backend
41
+ Break each feature area into shippable frontend specs (one coherent screen/flow each). For every
42
+ spec record: name, feature area, the **backend SPEC/domain it `Implements`** (consumes), and which
43
+ *frontend* specs it depends on. Honor the unforgiving frontend order:
44
+ - **App shell + auth + role routing + design-system primitives come first** — everything depends on them.
45
+ - A **shared real-time client** (WebSocket/Socket.IO) is a dependency of every live screen — build it once, early.
46
+ - A frontend spec is only *buildable* when its `Implements` backend spec is **SHIPPED** — order accordingly.
47
+ Order the whole list topologically. Keep each spec small enough to become ONE execution plan.
48
+
49
+ ## Step 5 — Pick the Walking-Skeleton First Slice
50
+ Choose the single thinnest spec that exercises the whole stack end-to-end — typically **login +
51
+ app shell + one auth-gated route that fetches via the generated client through a TanStack Query
52
+ hook and renders** (for a real-time product, also open the WS and render one live event). It must
53
+ depend on nothing. Mark exactly one spec as the skeleton. Build it first to prove routing + auth +
54
+ openapi-fetch + TanStack Query (+ the WS client) all wire up before any feature screen.
55
+
56
+ ## Step 6 — Write / Refresh the Roadmap
57
+ Save to `docs/product-specs/ROADMAP.md` using the template in that file's header (self-documenting).
58
+ Fill: Feature Areas & Personas, the dependency-ordered Spec Roadmap table (with the `Implements`
59
+ column), and the Build Sequence Rationale.
60
+ - New specs get Spec ID `—` and Status `NOT_STARTED`.
61
+ - On refresh, keep existing Spec IDs/Statuses untouched; never renumber a created spec.
62
+ - Set the **Walking skeleton** header to the chosen first slice.
63
+
64
+ ## Step 7 — Tell the Human
65
+ ```
66
+ Roadmap written: docs/product-specs/ROADMAP.md
67
+ {N} frontend specs across {M} feature areas / {P} personas, dependency-ordered.
68
+ Walking skeleton (build first): {skeleton spec name}
69
+
70
+ Review the roadmap. When the order looks right:
71
+ 1. Run /api-sync (ensure api.generated.ts matches the backend).
72
+ 2. Run /write-spec — it reads ROADMAP.md and authors the next NOT_STARTED spec whose
73
+ `Implements` backend spec is SHIPPED (starting with the walking skeleton).
74
+ 3. /write-plan → /build-layer down the list as backend capabilities ship.
75
+
76
+ /write-roadmap does NOT write spec files. It only plans the set.
77
+ ```
@@ -0,0 +1,78 @@
1
+ # /write-spec — Write a Product Spec
2
+
3
+ Triggered by: `/write-spec`
4
+
5
+ ## Step 1 — Consult the Roadmap (if present)
6
+ ```bash
7
+ ls docs/product-specs/ROADMAP.md 2>/dev/null
8
+ ```
9
+ If it exists, read it. Pick the first row with Status `NOT_STARTED` — the **walking skeleton**
10
+ if nothing is built yet, otherwise the next dependency-unblocked row **whose `Implements`
11
+ (backend SPEC) is SHIPPED** (don't build UI for an endpoint the backend hasn't shipped). Use
12
+ that row's Name, Feature Area, Implements, and Depends-On to pre-fill the spec. If no roadmap
13
+ exists, proceed ad hoc (a single standalone spec).
14
+
15
+ ## Step 2 — Get Next Spec Number
16
+ ```bash
17
+ ls docs/product-specs/{draft,ready}/ 2>/dev/null | grep "SPEC-" | sort | tail -1
18
+ ```
19
+ (`ROADMAP.md` is CAPS, so this `grep SPEC-` is unaffected.)
20
+
21
+ ## Step 3 — Write the Spec
22
+ Save to: `docs/product-specs/draft/SPEC-XXX-{slug}.md`
23
+
24
+ ```markdown
25
+ # SPEC-XXX — {Feature Name}
26
+
27
+ **Status:** DRAFT
28
+ **Created:** YYYY-MM-DD
29
+ **Plan:** —
30
+ **Feature area:** — <!-- from ROADMAP.md row, if roadmap-driven -->
31
+ **Implements (backend SPEC):** — <!-- backend spec/domain this UI consumes -->
32
+ **Depends on:** — <!-- other frontend specs, from ROADMAP.md -->
33
+
34
+ ---
35
+
36
+ ## Problem Statement
37
+
38
+ ## What We're Building
39
+
40
+ ## Screens / Views
41
+ | Screen | Route | Description |
42
+ |---|---|---|
43
+
44
+ ## User Flows
45
+ {numbered steps for each key flow}
46
+
47
+ ## API Endpoints Used
48
+ {list endpoints from the backend this feature consumes}
49
+ {These determine what will be in the hooks layer}
50
+
51
+ ## Business Rules (Frontend)
52
+ {Validation rules, state machine UI, conditional rendering}
53
+
54
+ ## Non-Functional Requirements
55
+ {Performance targets, accessibility requirements, responsive breakpoints}
56
+
57
+ ## Out of Scope (v1)
58
+
59
+ ## Acceptance Criteria
60
+ - [ ] {testable, specific}
61
+ ```
62
+
63
+ ## Step 4 — Update Index + Roadmap
64
+ Add to `docs/product-specs/index.md`: `| SPEC-XXX | {Name} | DRAFT | — | YYYY-MM-DD |`
65
+ If this spec came from a `ROADMAP.md` row, flip that row: `Spec ID: — → SPEC-XXX` and
66
+ `Status: NOT_STARTED → DRAFT` (mirrors how `/write-plan` updates the spec + index together).
67
+
68
+ ## Step 5 — Tell the Human
69
+ ```
70
+ Spec written: docs/product-specs/draft/SPEC-XXX-{slug}.md
71
+
72
+ Review it. When satisfied:
73
+ 1. Move to: docs/product-specs/ready/SPEC-XXX-{slug}.md
74
+ 2. Change Status: DRAFT → READY
75
+ 3. Run /write-plan
76
+
77
+ Claude will not create a plan until the spec is in ready/.
78
+ ```