flow-cc 0.1.1 → 0.3.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/CHANGELOG.md ADDED
@@ -0,0 +1,63 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [0.3.0] - 2026-02-11
9
+
10
+ ### Added
11
+ - `/flow:setup` command — replaces `/flow:init` for project scaffolding only. Adds overwrite protection (stops if project already initialized).
12
+ - `/flow:milestone` command — extracted from `/flow:init` for milestone transitions. Adds guard for pending phases before archiving.
13
+ - Codebase scan exclusions in `/flow:spec` — explicitly excludes `node_modules/`, `.git/`, `dist/`, `build/`, `.next/`, `__pycache__/`, `*.min.js`, `*.map`, `*.lock`. Uses targeted glob patterns instead of bare `**/*`.
14
+ - Minimum viable PRD check in `/flow:spec` — validates at least 3 user stories, 1 phase, and 1 verification command before finalizing.
15
+ - Agent timeout + progress indicators in `/flow:go` — prints wave spawn/completion status, checks stuck agents after 10 minutes.
16
+ - Max retry limit (3 attempts) for verification in `/flow:go` — stops after 3 failures with user options instead of looping forever.
17
+ - Wave failure handling in `/flow:go` — detects all-failed vs partial-failed waves, asks user how to proceed.
18
+
19
+ ### Changed
20
+ - `/flow:init` split into `/flow:setup` (project scaffolding) and `/flow:milestone` (milestone transitions)
21
+ - Skill count: 9 skills (was 8 — setup replaces init, milestone is new)
22
+ - All cross-references updated: intro, done, status, go, task, README, install.js, DESIGN.md, templates
23
+
24
+ ### Removed
25
+ - `/flow:init` command — replaced by `/flow:setup` and `/flow:milestone`
26
+
27
+ ## [0.2.0] - 2026-02-11
28
+
29
+ ### Added
30
+ - `CHANGELOG.md` in Keep a Changelog format
31
+ - `CONTRIBUTING.md` with skill file format docs and testing expectations
32
+ - Example lesson in `templates/lessons.md.template` showing PATTERN/CAUSE/FIX/RULE format
33
+ - Node.js version check (requires >= 18) with clear error message
34
+ - Write permission check before install starts
35
+ - Rollback on install failure — tracks created files and cleans up
36
+ - Post-install verification — checks key files exist after copy
37
+ - `--verify` flag for install health check without modifying anything
38
+ - `engines` field in package.json (`node >= 18`)
39
+ - Error logging for hooks — writes to `~/.claude/hooks/flow-error.log` (capped at 50KB)
40
+ - Context size limits in `/flow:spec` — caps codebase scan at 50 files, focused mode for 500+ file repos
41
+
42
+ ### Fixed
43
+ - `.gitignore` now has proper Node.js entries (was just `nul`)
44
+ - `/flow:done` archive step now creates `.planning/archive/` if missing and skips gracefully when no `.planning/` exists
45
+ - `/flow:update` now shows changelog for the new version before confirming update
46
+
47
+ ## [0.1.1] - 2025-05-01
48
+
49
+ ### Changed
50
+ - Updated package.json metadata (description, keywords, repository links)
51
+ - Polished README with badges and install instructions
52
+ - Added MIT license file
53
+
54
+ ## [0.1.0] - 2025-05-01
55
+
56
+ ### Added
57
+ - Initial release of Flow plugin for Claude Code
58
+ - 8 skills: init, spec, go, done, status, task, intro, update
59
+ - 2 hooks: statusline display, background update checker
60
+ - 4 templates: CLAUDE.md, STATE.md, ROADMAP.md, lessons.md
61
+ - One-command installer via `npx flow-cc`
62
+ - Automatic statusLine configuration
63
+ - Uninstall support via `npx flow-cc --uninstall`
@@ -0,0 +1,59 @@
1
+ # Contributing to Flow
2
+
3
+ Thanks for your interest in contributing! Flow is a structured workflow system for Claude Code, and contributions are welcome.
4
+
5
+ ## Reporting Bugs
6
+
7
+ Open an issue at [github.com/troyhoffman-oss/flow-plugin/issues](https://github.com/troyhoffman-oss/flow-plugin/issues) with:
8
+
9
+ - Steps to reproduce
10
+ - Expected vs. actual behavior
11
+ - Your OS and Node.js version
12
+ - Claude Code version (if relevant)
13
+
14
+ ## Suggesting Features
15
+
16
+ Open an issue with the `enhancement` label. Describe:
17
+
18
+ - The problem you're trying to solve
19
+ - Your proposed solution
20
+ - Any alternatives you've considered
21
+
22
+ ## Submitting Pull Requests
23
+
24
+ 1. Fork the repo and create a branch from `master`
25
+ 2. Make your changes
26
+ 3. Test the installer: `node bin/install.js` from the repo root
27
+ 4. Verify skills load in Claude Code (run `/flow:intro`)
28
+ 5. Open a PR with a clear description of what changed and why
29
+
30
+ ### Skill File Format
31
+
32
+ Skills live in `skills/` as Markdown files with YAML frontmatter:
33
+
34
+ ```markdown
35
+ ---
36
+ name: flow:example
37
+ description: One-line description
38
+ user_invocable: true
39
+ ---
40
+
41
+ # /flow:example — Title
42
+
43
+ Instructions for Claude Code to follow when this skill is invoked.
44
+ ```
45
+
46
+ ### Testing Expectations
47
+
48
+ - Run `node bin/install.js` and verify all files land in `~/.claude/`
49
+ - Run `node bin/install.js --uninstall` and verify clean removal
50
+ - Run `node bin/install.js --verify` to check install health
51
+ - Test on both Windows and macOS/Linux if possible
52
+
53
+ ## Architecture
54
+
55
+ See [DESIGN.md](DESIGN.md) for architecture decisions and system design.
56
+
57
+ ## Code of Conduct
58
+
59
+ Be kind, constructive, and respectful. We're all here to build better tools.
package/README.md CHANGED
@@ -35,7 +35,8 @@ Flow fixes this by giving Claude Code a **memory system and execution framework*
35
35
  | Command | What it does |
36
36
  |---|---|
37
37
  | `/flow:intro` | Walkthrough of the system — **start here** |
38
- | `/flow:init` | Initialize a project with `.planning/` scaffolding, CLAUDE.md, templates |
38
+ | `/flow:setup` | Set up a new project with `.planning/` scaffolding, CLAUDE.md, templates |
39
+ | `/flow:milestone` | Archive completed milestone and start a new one |
39
40
  | `/flow:spec` | Spec interview that produces an executable PRD with phased execution plan |
40
41
  | `/flow:go` | Execute the next phase from the PRD using wave-based agent teams |
41
42
  | `/flow:task` | Bug fixes, cleanup, small features — no PRD needed |
@@ -46,16 +47,18 @@ Flow fixes this by giving Claude Code a **memory system and execution framework*
46
47
  ## How It Works
47
48
 
48
49
  ```
49
- /flow:init → /flow:spec → /flow:go (repeat per phase) → /flow:done
50
-
51
- handoff prompt for next session
50
+ /flow:setup → /flow:spec → /flow:go (repeat per phase) → /flow:done
51
+
52
+ handoff prompt for next session
53
+
54
+ /flow:milestone → next cycle
52
55
 
53
56
  /flow:task ← standalone path for bug fixes and small features
54
57
  ```
55
58
 
56
59
  **The lifecycle in practice:**
57
60
 
58
- 1. **`/flow:init`** — Creates `.planning/` directory, CLAUDE.md, STATE.md, ROADMAP.md, lessons.md
61
+ 1. **`/flow:setup`** — Creates `.planning/` directory, CLAUDE.md, STATE.md, ROADMAP.md, lessons.md
59
62
  2. **`/flow:spec`** — Interviews you about the milestone. Produces a PRD with wave-based phases, acceptance criteria, and agent-team structure
60
63
  3. **`/flow:go`** — Reads the PRD, spawns parallel agent teams per wave, builds, verifies, commits
61
64
  4. **`/flow:done`** — Updates all planning docs, captures lessons, generates a one-line handoff prompt so the next session starts instantly
@@ -66,7 +69,8 @@ Flow fixes this by giving Claude Code a **memory system and execution framework*
66
69
  ```
67
70
  ~/.claude/
68
71
  ├── commands/flow/
69
- │ ├── flow-init.md # 8 skill files
72
+ │ ├── flow-setup.md # 9 skill files
73
+ │ ├── flow-milestone.md
70
74
  │ ├── flow-spec.md
71
75
  │ ├── flow-go.md
72
76
  │ ├── flow-task.md
@@ -88,7 +92,7 @@ Flow fixes this by giving Claude Code a **memory system and execution framework*
88
92
 
89
93
  ## Project Structure
90
94
 
91
- Every Flow project gets this structure via `/flow:init`:
95
+ Every Flow project gets this structure via `/flow:setup`:
92
96
 
93
97
  ```
94
98
  your-project/
@@ -121,6 +125,12 @@ Flow uses the same `.planning/` directory structure as [GSD](https://github.com/
121
125
 
122
126
  [Claude Code](https://docs.anthropic.com/en/docs/claude-code) CLI with skills support.
123
127
 
128
+ ## Links
129
+
130
+ - [Changelog](CHANGELOG.md) — what changed in each version
131
+ - [Contributing](CONTRIBUTING.md) — how to report bugs, suggest features, submit PRs
132
+ - [Design](DESIGN.md) — architecture decisions and system design
133
+
124
134
  ## License
125
135
 
126
136
  MIT
package/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.1
1
+ 0.3.0
package/bin/install.js CHANGED
@@ -1,11 +1,18 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node
2
2
  // Flow plugin installer for Claude Code
3
- // Usage: npx flow-cc [--uninstall]
3
+ // Usage: npx flow-cc [--uninstall] [--verify]
4
4
 
5
5
  const fs = require('fs');
6
6
  const path = require('path');
7
7
  const os = require('os');
8
8
 
9
+ // ---------- Node.js version check ----------
10
+ const nodeMajor = parseInt(process.versions.node.split('.')[0], 10);
11
+ if (nodeMajor < 18) {
12
+ console.error('Flow requires Node.js 18 or later. You have ' + process.version);
13
+ process.exit(1);
14
+ }
15
+
9
16
  const homeDir = os.homedir();
10
17
  const claudeDir = path.join(homeDir, '.claude');
11
18
  const commandsDir = path.join(claudeDir, 'commands', 'flow');
@@ -21,6 +28,93 @@ const templatesDir = path.join(pkgRoot, 'templates');
21
28
  const versionFile = path.join(pkgRoot, 'VERSION');
22
29
 
23
30
  const uninstall = process.argv.includes('--uninstall') || process.argv.includes('-u');
31
+ const verify = process.argv.includes('--verify') || process.argv.includes('-v');
32
+
33
+ // ---------- Verify ----------
34
+ if (verify) {
35
+ console.log('Flow install health check:\n');
36
+
37
+ let passed = 0;
38
+ const total = 5;
39
+
40
+ // 1. Skills installed
41
+ try {
42
+ const files = fs.existsSync(commandsDir)
43
+ ? fs.readdirSync(commandsDir).filter(f => f.endsWith('.md'))
44
+ : [];
45
+ if (files.length > 0) {
46
+ console.log(` \u2713 Skills installed (${files.length} files)`);
47
+ passed++;
48
+ } else {
49
+ console.log(' \u2717 Skills not installed (0 .md files in commands/flow/)');
50
+ }
51
+ } catch (e) {
52
+ console.log(' \u2717 Skills not installed (cannot read commands/flow/)');
53
+ }
54
+
55
+ // 2. Hooks installed
56
+ try {
57
+ const hookFiles = ['flow-check-update.js', 'flow-statusline.js'];
58
+ const found = hookFiles.filter(h => fs.existsSync(path.join(hooksDir, h)));
59
+ if (found.length === 2) {
60
+ console.log(' \u2713 Hooks installed (2 files)');
61
+ passed++;
62
+ } else {
63
+ console.log(` \u2717 Hooks incomplete (${found.length}/2 files)`);
64
+ }
65
+ } catch (e) {
66
+ console.log(' \u2717 Hooks not installed');
67
+ }
68
+
69
+ // 3. VERSION file
70
+ try {
71
+ const vPath = path.join(commandsDir, 'VERSION');
72
+ if (fs.existsSync(vPath)) {
73
+ const ver = fs.readFileSync(vPath, 'utf8').trim();
74
+ console.log(` \u2713 VERSION file present (${ver})`);
75
+ passed++;
76
+ } else {
77
+ console.log(' \u2717 VERSION file missing');
78
+ }
79
+ } catch (e) {
80
+ console.log(' \u2717 VERSION file missing');
81
+ }
82
+
83
+ // 4. Templates installed
84
+ try {
85
+ const tDir = path.join(commandsDir, 'templates');
86
+ const files = fs.existsSync(tDir) ? fs.readdirSync(tDir) : [];
87
+ if (files.length > 0) {
88
+ console.log(` \u2713 Templates installed (${files.length} files)`);
89
+ passed++;
90
+ } else {
91
+ console.log(' \u2717 Templates not installed (0 files)');
92
+ }
93
+ } catch (e) {
94
+ console.log(' \u2717 Templates not installed');
95
+ }
96
+
97
+ // 5. StatusLine configured
98
+ try {
99
+ if (fs.existsSync(settingsPath)) {
100
+ const settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
101
+ if (settings.statusLine && typeof settings.statusLine.command === 'string' &&
102
+ settings.statusLine.command.includes('flow-statusline')) {
103
+ console.log(' \u2713 StatusLine configured');
104
+ passed++;
105
+ } else {
106
+ console.log(' \u2717 StatusLine not configured');
107
+ }
108
+ } else {
109
+ console.log(' \u2717 StatusLine not configured (no settings.json)');
110
+ }
111
+ } catch (e) {
112
+ console.log(' \u2717 StatusLine not configured');
113
+ }
114
+
115
+ console.log(`\nResult: ${passed}/${total} checks passed`);
116
+ process.exit(passed === total ? 0 : 1);
117
+ }
24
118
 
25
119
  // ---------- Uninstall ----------
26
120
  if (uninstall) {
@@ -60,7 +154,7 @@ if (uninstall) {
60
154
  console.log(' Removed statusLine from ~/.claude/settings.json');
61
155
  }
62
156
  } catch (e) {
63
- // settings.json parse error leave it alone
157
+ // settings.json parse error -- leave it alone
64
158
  }
65
159
  }
66
160
 
@@ -71,79 +165,176 @@ if (uninstall) {
71
165
  // ---------- Install ----------
72
166
  console.log('Installing Flow plugin...\n');
73
167
 
74
- // 1. Create directories
75
- for (const dir of [commandsDir, hooksDir, cacheDir]) {
76
- fs.mkdirSync(dir, { recursive: true });
168
+ // ---------- Write permission check ----------
169
+ const permTestDir = fs.existsSync(claudeDir) ? claudeDir : path.dirname(claudeDir);
170
+ const permTestFile = path.join(permTestDir, '.flow-perm-test-' + process.pid);
171
+ try {
172
+ fs.writeFileSync(permTestFile, 'test');
173
+ fs.unlinkSync(permTestFile);
174
+ } catch (e) {
175
+ console.error('Cannot write to ' + claudeDir + ' \u2014 check permissions.');
176
+ process.exit(1);
77
177
  }
78
178
 
79
- // 2. Copy skills: skills/flow-*.md → commands/flow/*.md (strip "flow-" prefix)
80
- const skillFiles = fs.readdirSync(skillsDir).filter(f => f.startsWith('flow-') && f.endsWith('.md'));
81
- for (const file of skillFiles) {
82
- const dest = file.replace(/^flow-/, '');
83
- fs.copyFileSync(path.join(skillsDir, file), path.join(commandsDir, dest));
179
+ // ---------- Rollback tracking ----------
180
+ const created = []; // paths created during install (files and dirs we created fresh)
181
+
182
+ function trackFile(filePath) {
183
+ created.push({ type: 'file', path: filePath });
84
184
  }
85
- console.log(` Installed ${skillFiles.length} skills → ~/.claude/commands/flow/`);
86
185
 
87
- // 3. Copy hooks
88
- const hookFiles = ['flow-check-update.js', 'flow-statusline.js'];
89
- for (const hook of hookFiles) {
90
- const src = path.join(srcHooksDir, hook);
91
- if (fs.existsSync(src)) {
92
- fs.copyFileSync(src, path.join(hooksDir, hook));
186
+ function trackDir(dirPath) {
187
+ // Only track if we actually created it (didn't exist before)
188
+ if (!fs.existsSync(dirPath)) {
189
+ created.push({ type: 'dir', path: dirPath });
93
190
  }
94
191
  }
95
- console.log(' Installed hooks → ~/.claude/hooks/');
96
192
 
97
- // 4. Copy VERSION
98
- fs.copyFileSync(versionFile, path.join(commandsDir, 'VERSION'));
99
- console.log(' Installed VERSION ~/.claude/commands/flow/VERSION');
100
-
101
- // 5. Copy templates
102
- const destTemplatesDir = path.join(commandsDir, 'templates');
103
- fs.mkdirSync(destTemplatesDir, { recursive: true });
104
- if (fs.existsSync(templatesDir)) {
105
- const templateFiles = fs.readdirSync(templatesDir);
106
- for (const file of templateFiles) {
107
- fs.copyFileSync(path.join(templatesDir, file), path.join(destTemplatesDir, file));
193
+ function rollback() {
194
+ console.error('\nRolling back partial install...');
195
+ for (let i = created.length - 1; i >= 0; i--) {
196
+ const item = created[i];
197
+ try {
198
+ if (item.type === 'file' && fs.existsSync(item.path)) {
199
+ fs.unlinkSync(item.path);
200
+ } else if (item.type === 'dir' && fs.existsSync(item.path)) {
201
+ fs.rmSync(item.path, { recursive: true });
202
+ }
203
+ } catch (e) {
204
+ // Best-effort cleanup
205
+ }
108
206
  }
109
- console.log(` Installed ${templateFiles.length} templates → ~/.claude/commands/flow/templates/`);
207
+ console.error('Rollback complete.');
110
208
  }
111
209
 
112
- // 6. Merge statusLine into settings.json
113
- let settings = {};
114
- if (fs.existsSync(settingsPath)) {
115
- try {
116
- settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
117
- } catch (e) {
118
- // Corrupted settings — start fresh but warn
119
- console.log(' Warning: could not parse existing settings.json, preserving as backup');
120
- fs.copyFileSync(settingsPath, settingsPath + '.bak');
210
+ try {
211
+ // 1. Create directories
212
+ for (const dir of [commandsDir, hooksDir, cacheDir]) {
213
+ trackDir(dir);
214
+ fs.mkdirSync(dir, { recursive: true });
121
215
  }
122
- }
123
- settings.statusLine = {
124
- type: 'command',
125
- command: `node "${path.join(hooksDir, 'flow-statusline.js')}"`
126
- };
127
- fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n');
128
- console.log(' Configured statusLine in ~/.claude/settings.json');
129
-
130
- // 7. Write .source breadcrumb (for dev/setup.sh compat)
131
- fs.writeFileSync(path.join(commandsDir, '.source'), pkgRoot + '\n');
132
-
133
- // Done
134
- const version = fs.readFileSync(versionFile, 'utf8').trim();
135
- console.log(`
216
+
217
+ // 2. Copy skills: skills/flow-*.md -> commands/flow/*.md (strip "flow-" prefix)
218
+ const skillFiles = fs.readdirSync(skillsDir).filter(f => f.startsWith('flow-') && f.endsWith('.md'));
219
+ for (const file of skillFiles) {
220
+ const dest = file.replace(/^flow-/, '');
221
+ const destPath = path.join(commandsDir, dest);
222
+ fs.copyFileSync(path.join(skillsDir, file), destPath);
223
+ trackFile(destPath);
224
+ }
225
+ console.log(` Installed ${skillFiles.length} skills \u2192 ~/.claude/commands/flow/`);
226
+
227
+ // 3. Copy hooks
228
+ const hookFiles = ['flow-check-update.js', 'flow-statusline.js'];
229
+ for (const hook of hookFiles) {
230
+ const src = path.join(srcHooksDir, hook);
231
+ if (fs.existsSync(src)) {
232
+ const destPath = path.join(hooksDir, hook);
233
+ fs.copyFileSync(src, destPath);
234
+ trackFile(destPath);
235
+ }
236
+ }
237
+ console.log(' Installed hooks \u2192 ~/.claude/hooks/');
238
+
239
+ // 4. Copy VERSION
240
+ const versionDest = path.join(commandsDir, 'VERSION');
241
+ fs.copyFileSync(versionFile, versionDest);
242
+ trackFile(versionDest);
243
+ console.log(' Installed VERSION \u2192 ~/.claude/commands/flow/VERSION');
244
+
245
+ // 5. Copy templates
246
+ const destTemplatesDir = path.join(commandsDir, 'templates');
247
+ trackDir(destTemplatesDir);
248
+ fs.mkdirSync(destTemplatesDir, { recursive: true });
249
+ if (fs.existsSync(templatesDir)) {
250
+ const templateFiles = fs.readdirSync(templatesDir);
251
+ for (const file of templateFiles) {
252
+ const destPath = path.join(destTemplatesDir, file);
253
+ fs.copyFileSync(path.join(templatesDir, file), destPath);
254
+ trackFile(destPath);
255
+ }
256
+ console.log(` Installed ${templateFiles.length} templates \u2192 ~/.claude/commands/flow/templates/`);
257
+ }
258
+
259
+ // 6. Merge statusLine into settings.json
260
+ let settings = {};
261
+ if (fs.existsSync(settingsPath)) {
262
+ try {
263
+ settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
264
+ } catch (e) {
265
+ // Corrupted settings -- start fresh but warn
266
+ console.log(' Warning: could not parse existing settings.json, preserving as backup');
267
+ fs.copyFileSync(settingsPath, settingsPath + '.bak');
268
+ }
269
+ }
270
+ settings.statusLine = {
271
+ type: 'command',
272
+ command: `node "${path.join(hooksDir, 'flow-statusline.js')}"`
273
+ };
274
+ fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n');
275
+ trackFile(settingsPath);
276
+ console.log(' Configured statusLine in ~/.claude/settings.json');
277
+
278
+ // 7. Write .source breadcrumb (for dev/setup.sh compat)
279
+ const sourcePath = path.join(commandsDir, '.source');
280
+ fs.writeFileSync(sourcePath, pkgRoot + '\n');
281
+ trackFile(sourcePath);
282
+
283
+ // ---------- Post-install verification ----------
284
+ let warnings = 0;
285
+
286
+ // Check: at least 1 file in commandsDir
287
+ const installedSkills = fs.readdirSync(commandsDir).filter(f => f.endsWith('.md'));
288
+ if (installedSkills.length === 0) {
289
+ console.log(' Warning: no skill files found in commands/flow/');
290
+ warnings++;
291
+ }
292
+
293
+ // Check: both hook files
294
+ const installedHooks = hookFiles.filter(h => fs.existsSync(path.join(hooksDir, h)));
295
+ if (installedHooks.length < 2) {
296
+ console.log(` Warning: only ${installedHooks.length}/2 hook files installed`);
297
+ warnings++;
298
+ }
299
+
300
+ // Check: VERSION file
301
+ if (!fs.existsSync(path.join(commandsDir, 'VERSION'))) {
302
+ console.log(' Warning: VERSION file not found after install');
303
+ warnings++;
304
+ }
305
+
306
+ // Check: templates directory with at least 1 file
307
+ const tplDir = path.join(commandsDir, 'templates');
308
+ const tplFiles = fs.existsSync(tplDir) ? fs.readdirSync(tplDir) : [];
309
+ if (tplFiles.length === 0) {
310
+ console.log(' Warning: no template files found after install');
311
+ warnings++;
312
+ }
313
+
314
+ if (warnings > 0) {
315
+ console.log(` (${warnings} verification warning${warnings > 1 ? 's' : ''} — install may be incomplete)`);
316
+ }
317
+
318
+ // Done
319
+ const version = fs.readFileSync(versionFile, 'utf8').trim();
320
+ console.log(`
136
321
  Flow v${version} installed successfully!
137
322
 
138
323
  Commands available:
139
- /flow:intro Learn the Flow workflow
140
- /flow:init — Start a new project or milestone
141
- /flow:spec — Spec interview executable PRD
142
- /flow:go — Execute next phase with agent teams
143
- /flow:done — Session-end documentation
144
- /flow:status — Quick orientation
145
- /flow:task — Lightweight task execution
146
- /flow:update — Update Flow to latest version
324
+ /flow:intro \u2014 Learn the Flow workflow
325
+ /flow:setup \u2014 Set up a new project
326
+ /flow:milestone \u2014 Start a new milestone
327
+ /flow:spec \u2014 Spec interview \u2192 executable PRD
328
+ /flow:go \u2014 Execute next phase with agent teams
329
+ /flow:done \u2014 Session-end documentation
330
+ /flow:status \u2014 Quick orientation
331
+ /flow:task \u2014 Lightweight task execution
332
+ /flow:update \u2014 Update Flow to latest version
147
333
 
148
334
  Get started: run /flow:intro in any Claude Code session.
149
335
  `);
336
+ } catch (err) {
337
+ rollback();
338
+ console.error('\nInstall failed: ' + err.message);
339
+ process.exit(1);
340
+ }
@@ -11,43 +11,90 @@ const homeDir = os.homedir();
11
11
  const cacheDir = path.join(homeDir, '.claude', 'cache');
12
12
  const cacheFile = path.join(cacheDir, 'flow-update-check.json');
13
13
  const versionFile = path.join(homeDir, '.claude', 'commands', 'flow', 'VERSION');
14
+ const errorLog = path.join(homeDir, '.claude', 'hooks', 'flow-error.log');
14
15
 
15
- // Ensure cache directory exists
16
- if (!fs.existsSync(cacheDir)) {
17
- fs.mkdirSync(cacheDir, { recursive: true });
16
+ function logError(context, err) {
17
+ try {
18
+ const line = `[${new Date().toISOString()}] flow-check-update: ${context}: ${err.message || err}\n`;
19
+ // Cap log at 50KB — truncate oldest entries
20
+ if (fs.existsSync(errorLog)) {
21
+ const stat = fs.statSync(errorLog);
22
+ if (stat.size > 50 * 1024) {
23
+ const content = fs.readFileSync(errorLog, 'utf8');
24
+ const lines = content.split('\n');
25
+ fs.writeFileSync(errorLog, lines.slice(Math.floor(lines.length / 2)).join('\n'));
26
+ }
27
+ }
28
+ fs.appendFileSync(errorLog, line);
29
+ } catch (_) {
30
+ // Logging must never throw
31
+ }
18
32
  }
19
33
 
20
- // Run check in background (spawn detached process, windowsHide prevents console flash)
21
- const child = spawn(process.execPath, ['-e', `
22
- const fs = require('fs');
23
- const { execSync } = require('child_process');
34
+ try {
35
+ // Ensure cache directory exists
36
+ if (!fs.existsSync(cacheDir)) {
37
+ fs.mkdirSync(cacheDir, { recursive: true });
38
+ }
24
39
 
25
- const cacheFile = ${JSON.stringify(cacheFile)};
26
- const versionFile = ${JSON.stringify(versionFile)};
40
+ // Run check in background (spawn detached process, windowsHide prevents console flash)
41
+ const child = spawn(process.execPath, ['-e', `
42
+ const fs = require('fs');
43
+ const { execSync } = require('child_process');
27
44
 
28
- let installed = '0.0.0';
29
- try {
30
- if (fs.existsSync(versionFile)) {
31
- installed = fs.readFileSync(versionFile, 'utf8').trim();
45
+ const cacheFile = ${JSON.stringify(cacheFile)};
46
+ const versionFile = ${JSON.stringify(versionFile)};
47
+ const errorLog = ${JSON.stringify(errorLog)};
48
+
49
+ function logError(context, err) {
50
+ try {
51
+ const line = '[' + new Date().toISOString() + '] flow-check-update(child): ' + context + ': ' + (err.message || err) + '\\n';
52
+ if (fs.existsSync(errorLog)) {
53
+ const stat = fs.statSync(errorLog);
54
+ if (stat.size > 50 * 1024) {
55
+ const content = fs.readFileSync(errorLog, 'utf8');
56
+ const lines = content.split('\\n');
57
+ fs.writeFileSync(errorLog, lines.slice(Math.floor(lines.length / 2)).join('\\n'));
58
+ }
59
+ }
60
+ fs.appendFileSync(errorLog, line);
61
+ } catch (_) {}
32
62
  }
33
- } catch (e) {}
34
63
 
35
- let latest = null;
36
- try {
37
- latest = execSync('npm view flow-cc version', { encoding: 'utf8', timeout: 10000, windowsHide: true }).trim();
38
- } catch (e) {}
39
-
40
- const result = {
41
- update_available: latest && installed !== latest,
42
- installed,
43
- latest: latest || 'unknown',
44
- checked: Math.floor(Date.now() / 1000)
45
- };
46
-
47
- fs.writeFileSync(cacheFile, JSON.stringify(result));
48
- `], {
49
- stdio: 'ignore',
50
- windowsHide: true
51
- });
52
-
53
- child.unref();
64
+ try {
65
+ let installed = '0.0.0';
66
+ try {
67
+ if (fs.existsSync(versionFile)) {
68
+ installed = fs.readFileSync(versionFile, 'utf8').trim();
69
+ }
70
+ } catch (e) {
71
+ logError('read-version', e);
72
+ }
73
+
74
+ let latest = null;
75
+ try {
76
+ latest = execSync('npm view flow-cc version', { encoding: 'utf8', timeout: 10000, windowsHide: true }).trim();
77
+ } catch (e) {
78
+ logError('npm-view', e);
79
+ }
80
+
81
+ const result = {
82
+ update_available: latest && installed !== latest,
83
+ installed,
84
+ latest: latest || 'unknown',
85
+ checked: Math.floor(Date.now() / 1000)
86
+ };
87
+
88
+ fs.writeFileSync(cacheFile, JSON.stringify(result));
89
+ } catch (e) {
90
+ logError('main', e);
91
+ }
92
+ `], {
93
+ stdio: 'ignore',
94
+ windowsHide: true
95
+ });
96
+
97
+ child.unref();
98
+ } catch (e) {
99
+ logError('spawn', e);
100
+ }
@@ -7,6 +7,25 @@ const path = require('path');
7
7
  const os = require('os');
8
8
 
9
9
  const homeDir = os.homedir();
10
+ const errorLog = path.join(homeDir, '.claude', 'hooks', 'flow-error.log');
11
+
12
+ function logError(context, err) {
13
+ try {
14
+ const line = `[${new Date().toISOString()}] flow-statusline: ${context}: ${err.message || err}\n`;
15
+ // Cap log at 50KB — truncate oldest entries
16
+ if (fs.existsSync(errorLog)) {
17
+ const stat = fs.statSync(errorLog);
18
+ if (stat.size > 50 * 1024) {
19
+ const content = fs.readFileSync(errorLog, 'utf8');
20
+ const lines = content.split('\n');
21
+ fs.writeFileSync(errorLog, lines.slice(Math.floor(lines.length / 2)).join('\n'));
22
+ }
23
+ }
24
+ fs.appendFileSync(errorLog, line);
25
+ } catch (_) {
26
+ // Logging must never throw
27
+ }
28
+ }
10
29
 
11
30
  // Read JSON from stdin (Claude Code statusline protocol)
12
31
  let input = '';
@@ -56,9 +75,13 @@ process.stdin.on('end', () => {
56
75
  const todos = JSON.parse(fs.readFileSync(path.join(todosDir, files[0].name), 'utf8'));
57
76
  const inProgress = todos.find(t => t.status === 'in_progress');
58
77
  if (inProgress) task = inProgress.activeForm || '';
59
- } catch (e) {}
78
+ } catch (e) {
79
+ logError('parse-todos', e);
80
+ }
60
81
  }
61
- } catch (e) {}
82
+ } catch (e) {
83
+ logError('read-todos', e);
84
+ }
62
85
  }
63
86
 
64
87
  // --- Flow update notification ---
@@ -78,6 +101,7 @@ process.stdin.on('end', () => {
78
101
  shouldCheck = true;
79
102
  }
80
103
  } catch (e) {
104
+ logError('parse-cache', e);
81
105
  shouldCheck = true;
82
106
  }
83
107
  } else {
@@ -96,7 +120,9 @@ process.stdin.on('end', () => {
96
120
  });
97
121
  child.unref();
98
122
  }
99
- } catch (e) {}
123
+ } catch (e) {
124
+ logError('spawn-update-check', e);
125
+ }
100
126
  }
101
127
 
102
128
  // --- Output ---
@@ -107,6 +133,7 @@ process.stdin.on('end', () => {
107
133
  process.stdout.write(`${flowUpdate}\x1b[2m${model}\x1b[0m \u2502 \x1b[2m${dirname}\x1b[0m${ctx}`);
108
134
  }
109
135
  } catch (e) {
136
+ logError('main', e);
110
137
  // Silent fail — statusline must never crash
111
138
  }
112
139
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flow-cc",
3
- "version": "0.1.1",
3
+ "version": "0.3.0",
4
4
  "description": "Structured workflow system for Claude Code — spec interviews, agent-team execution, session handoffs, compounding knowledge",
5
5
  "author": "Troy Hoffman",
6
6
  "license": "MIT",
@@ -25,11 +25,16 @@
25
25
  "bin": {
26
26
  "flow-cc": "bin/install.js"
27
27
  },
28
+ "engines": {
29
+ "node": ">=18"
30
+ },
28
31
  "files": [
29
32
  "bin",
30
33
  "skills",
31
34
  "hooks",
32
35
  "templates",
33
- "VERSION"
36
+ "VERSION",
37
+ "CHANGELOG.md",
38
+ "CONTRIBUTING.md"
34
39
  ]
35
40
  }
@@ -65,6 +65,8 @@ Structure:
65
65
  - Mark completed phases with completion date
66
66
  - Ensure pending phases have enough detail that the next session can start with a one-line prompt
67
67
  - **Archive check:** If the current milestone is fully complete:
68
+ - If `.planning/` does not exist, skip archiving entirely — there's nothing to archive
69
+ - Create `.planning/archive/` if it doesn't already exist (use `mkdir -p` or equivalent)
68
70
  - Move milestone phase details to `.planning/archive/milestones-vX.md`
69
71
  - Keep only the summary row in the ROADMAP milestone table
70
72
  - Move `PRD.md` to `.planning/archive/PRD-vX.md`
@@ -98,7 +100,7 @@ Determine the next action and generate a copyable handoff prompt:
98
100
  ```
99
101
  - If milestone is complete:
100
102
  ```
101
- Milestone [name] complete. Run /flow:init to start the next milestone.
103
+ Milestone [name] complete. Run /flow:milestone to start the next milestone.
102
104
  ```
103
105
 
104
106
  Print the handoff prompt in a fenced code block so the user can copy it.
package/skills/flow-go.md CHANGED
@@ -32,7 +32,7 @@ Run these checks before executing. If any fail, stop and tell the user what to d
32
32
  - Verification commands
33
33
  - If missing: "PRD phase section is too vague. Add wave structure + file lists, or run `/flow:spec`."
34
34
  3. **Branch check:** Verify you're on the correct feature branch (from PRD header). If not, warn the user.
35
- 4. **All phases done?** If no pending phases remain: "All phases complete! Run `/flow:done` to wrap up, or `/flow:init` for the next milestone."
35
+ 4. **All phases done?** If no pending phases remain: "All phases complete! Run `/flow:done` to wrap up, or `/flow:milestone` for the next milestone."
36
36
 
37
37
  ## Step 3 — Staleness Check
38
38
 
@@ -82,22 +82,54 @@ so agents have it in their context without needing to search.]
82
82
 
83
83
  - Use TeamCreate or Task tool to spawn all agents in the wave simultaneously
84
84
  - Each agent runs with `mode: "bypassPermissions"` for autonomous execution
85
- - Wait for all agents in the wave to complete before moving to the next wave
85
+ - Print: **"Wave N: Spawned X agents [agent-1-task], [agent-2-task], ..."**
86
+ - As each agent completes, print: **"Wave N: agent-name completed (X/Y)"**
87
+ - Set a reasonable timeout for each agent. If an agent hasn't completed after 10 minutes, check on it. If it's stuck, stop it and note the failure.
88
+ - Wait for all agents in the wave to complete (or timeout) before moving to the next wave
86
89
 
87
- ### 4c. Between Waves
90
+ ### 4c. Wave Failure Handling
88
91
 
89
- After each wave completes:
92
+ After a wave completes, check results:
93
+
94
+ **If ALL agents in a wave failed:**
95
+ - Print: **"Wave N failed — all X agents errored."**
96
+ - Show error summaries from each agent
97
+ - Use AskUserQuestion: "Wave N failed completely. How to proceed?"
98
+ - "Retry this wave"
99
+ - "Skip to next wave"
100
+ - "Abort phase"
101
+
102
+ **If SOME agents failed but others succeeded:**
103
+ - Print: **"Wave N: X/Y agents succeeded, Z failed."**
104
+ - Show failed agent error summaries
105
+ - Use AskUserQuestion: "Some agents failed. How to proceed?"
106
+ - "Retry failed agents"
107
+ - "Continue without them"
108
+ - "Abort phase"
109
+
110
+ When a wave completes successfully (all agents or user chose to continue), print: **"Wave N complete. Proceeding to Wave N+1."**
111
+
112
+ ### 4d. Between Waves
113
+
114
+ After each wave completes (and failure handling is resolved):
90
115
  1. Run verification commands from CLAUDE.md (e.g., `npx tsc --noEmit`, `npx biome check`)
91
116
  2. Check for integration issues between agents' output
92
117
  3. Fix any issues before proceeding to the next wave
93
118
  4. If verification fails and you can fix it quickly (< 2 minutes of work), fix it. Otherwise, stop and report.
94
119
 
95
- ### 4d. Final Verification
120
+ ### 4e. Final Verification
96
121
 
97
122
  After ALL waves complete:
98
123
  1. Run full verification suite
99
124
  2. Check all acceptance criteria for this phase's user stories
100
- 3. If anything fails, fix it or report to the user
125
+ 3. If verification fails, attempt to fix (max **3 attempts**):
126
+ - After attempt 1 fails: Print **"Verification failed. Attempting fix (1/3)..."**
127
+ - After attempt 2 fails: Print **"Verification failed. Attempting fix (2/3)..."**
128
+ - After attempt 3 fails: Print **"Verification failed after 3 attempts. STOP."** Print the errors and use AskUserQuestion:
129
+ - "Skip verification and continue"
130
+ - "Fix manually and retry"
131
+ - "Abort this phase"
132
+ - Do NOT loop further beyond 3 attempts.
101
133
 
102
134
  ## Step 5 — Commit
103
135
 
@@ -14,28 +14,35 @@ Print this:
14
14
 
15
15
  ## Flow — Your Workflow System
16
16
 
17
- Flow is 5 commands that turn your specs into shipped code through agent teams. Each command feeds the next.
17
+ Flow is 6 commands that turn your specs into shipped code through agent teams. Each command feeds the next.
18
18
 
19
19
  ### The Lifecycle
20
20
 
21
21
  ```
22
- /flow:init → /flow:spec → /flow:go (repeat) → /flow:done
22
+ /flow:setup → /flow:spec → /flow:go (repeat) → /flow:done
23
23
 
24
24
  handoff prompt for next session
25
+
26
+ /flow:milestone → next cycle
25
27
 
26
28
  /flow:task ← standalone path for bug fixes, cleanup, small features (no PRD needed)
27
29
  ```
28
30
 
29
31
  ### Command by Command
30
32
 
31
- **`/flow:init`** — Run once per project (or once per new milestone)
32
- - New project: asks you 4-5 questions (what is it, tech stack, verify commands, first milestone)
33
+ **`/flow:setup`** — Run once per project
34
+ - Asks you 4-5 questions (what is it, tech stack, verify commands, first milestone)
33
35
  - Creates the scaffolding: `CLAUDE.md`, `.planning/STATE.md`, `.planning/ROADMAP.md`, `tasks/lessons.md`
34
- - Existing project: archives the old milestone + PRD, sets up the next one
36
+ - If project already set up, tells you to use `/flow:milestone` or `/flow:spec` instead
37
+
38
+ **`/flow:milestone`** — Run when starting a new milestone
39
+ - Archives the completed milestone + PRD
40
+ - Sets up fresh planning docs for the next milestone
41
+ - Guards against archiving milestones with incomplete phases
35
42
 
36
43
  **`/flow:task`** — Run anytime for small work
37
44
  - Bug fixes, cleanup, one-off features — anything that doesn't need a full PRD
38
- - Works standalone without `/flow:init` — lowest friction entry to Flow
45
+ - Works standalone without `/flow:setup` — lowest friction entry to Flow
39
46
  - Executes, verifies, commits, and logs to STATE.md (if it exists)
40
47
  - Scope guard recommends `/flow:spec` if the task grows beyond 5 files or 3 layers
41
48
 
@@ -80,7 +87,7 @@ Flow is 5 commands that turn your specs into shipped code through agent teams. E
80
87
  ### Starting a Brand New Project
81
88
 
82
89
  ```
83
- 1. /flow:init ← scaffolds everything
90
+ 1. /flow:setup ← scaffolds everything
84
91
  2. /flow:spec ← interview → PRD
85
92
  3. /flow:go ← phase 1
86
93
  4. /flow:done ← wrap up
@@ -0,0 +1,67 @@
1
+ ---
2
+ name: flow:milestone
3
+ description: Archive completed milestone and start a new one
4
+ user_invocable: true
5
+ ---
6
+
7
+ # /flow:milestone — Start New Milestone
8
+
9
+ You are executing the `/flow:milestone` skill. This archives the current milestone and sets up a new one.
10
+
11
+ ## Guard: Project Must Exist
12
+
13
+ Check if `.planning/STATE.md` exists:
14
+ - **If it does NOT exist** → Print: "No project found. Run `/flow:setup` first." and **STOP.**
15
+ - **If it exists** → Continue.
16
+
17
+ ## Step 1: Read Context
18
+
19
+ Read `.planning/STATE.md` and `.planning/ROADMAP.md` to understand:
20
+ - What milestone just completed (or is completing)
21
+ - What version number to use next
22
+ - Current state of the project
23
+
24
+ ## Step 2: Check for Pending Phases
25
+
26
+ Parse ROADMAP.md for the current milestone's phases:
27
+ - If any phases have status "Pending" or "In Progress" (not complete):
28
+ - Print: "Warning: The current milestone has incomplete phases:"
29
+ - List the pending/in-progress phases
30
+ - Use AskUserQuestion: "Archive this milestone anyway?" with options:
31
+ - "Yes — archive and move on"
32
+ - "No — finish current phases first"
33
+ - If the user says No → Print: "Run `/flow:go` to continue the current milestone." and **STOP.**
34
+
35
+ ## Step 3: Ask Milestone Question
36
+
37
+ Use AskUserQuestion:
38
+ - "What's the goal of this new milestone?" (free text)
39
+ - "What should it be called?" (free text, or suggest a name based on context)
40
+
41
+ ## Step 4: Archive Completed Milestone
42
+
43
+ 1. Read current ROADMAP.md phase details for the completed milestone
44
+ 2. Write them to `.planning/archive/milestones-vX.md` (where X is the completed version)
45
+ 3. If `PRD.md` exists, move it to `.planning/archive/PRD-vX.md` (read it, write to archive, delete original)
46
+ 4. In ROADMAP.md, replace the completed milestone's phase details with just the summary row (mark as "Complete")
47
+
48
+ ## Step 5: Update Planning Docs
49
+
50
+ **ROADMAP.md:**
51
+ - Add new milestone row to the table
52
+ - Add new milestone section with goal and "Run `/flow:spec` to define phases"
53
+
54
+ **STATE.md:**
55
+ - Replace with fresh state for the new milestone
56
+ - Reset phase progress table
57
+ - Note the milestone transition in "What Was Built"
58
+
59
+ ## Step 6: Print Completion Message
60
+
61
+ ```
62
+ Milestone [name] (v[X]) initialized.
63
+ - Archived: previous milestone details + PRD
64
+ - Updated: ROADMAP.md, STATE.md
65
+
66
+ Run `/flow:spec` to build the PRD for this milestone.
67
+ ```
@@ -1,24 +1,22 @@
1
1
  ---
2
- name: flow:init
3
- description: Initialize a new project or start a new milestone with planning scaffolding
2
+ name: flow:setup
3
+ description: Set up a new project with Flow planning scaffolding
4
4
  user_invocable: true
5
5
  ---
6
6
 
7
- # /flow:initInitialize Project or Milestone
7
+ # /flow:setupSet Up New Project
8
8
 
9
- You are executing the `/flow:init` skill. This sets up the planning scaffolding for a new project or a new milestone within an existing project.
9
+ You are executing the `/flow:setup` skill. This sets up the planning scaffolding for a new project.
10
10
 
11
- ## Mode Detection
11
+ ## Guard: Already Initialized
12
12
 
13
- Check if `.planning/STATE.md` exists:
14
- - **If it does NOT exist** New Project Mode
15
- - **If it exists** → New Milestone Mode
13
+ Check if `.planning/STATE.md` already exists:
14
+ - **If it exists** Print: "This project is already set up. Run `/flow:milestone` to start a new milestone, or `/flow:spec` to spec the current one." and **STOP. Do not overwrite.**
15
+ - **If it does NOT exist** → Continue with setup below.
16
16
 
17
17
  ---
18
18
 
19
- ## New Project Mode
20
-
21
- ### Step 1: Ask Setup Questions
19
+ ## Step 1: Ask Setup Questions
22
20
 
23
21
  Use AskUserQuestion to gather project info. Ask these questions (you may combine into 2-3 AskUserQuestion calls):
24
22
 
@@ -47,7 +45,7 @@ Use AskUserQuestion to gather project info. Ask these questions (you may combine
47
45
  - "Yes — scan and catalog existing code"
48
46
  - "No — greenfield project"
49
47
 
50
- ### Step 2: Brownfield Scan (if requested)
48
+ ## Step 2: Brownfield Scan (if requested)
51
49
 
52
50
  If the user said yes to scanning:
53
51
  1. Use Glob to find key directories: `src/`, `app/`, `lib/`, `components/`, `api/`, `pages/`, `utils/`, `types/`
@@ -55,7 +53,7 @@ If the user said yes to scanning:
55
53
  3. Build a brief catalog of what exists (key components, patterns, data layer)
56
54
  4. Include this in the CLAUDE.md Quick Context section
57
55
 
58
- ### Step 3: Create Project Files
56
+ ## Step 3: Create Project Files
59
57
 
60
58
  Create these 5 files (create directories as needed):
61
59
 
@@ -76,7 +74,7 @@ Create these 5 files (create directories as needed):
76
74
  | — | Run `/flow:spec` to define phases | — |
77
75
 
78
76
  ## What Was Built (This Session)
79
- - Project initialized with `/flow:init`
77
+ - Project initialized with `/flow:setup`
80
78
  - Created: CLAUDE.md, STATE.md, ROADMAP.md, tasks/lessons.md
81
79
 
82
80
  ## Key Decisions
@@ -159,7 +157,7 @@ Format: PATTERN → CAUSE → FIX → RULE
159
157
 
160
158
  **`.planning/archive/`** — Create this empty directory (use `mkdir -p` via Bash).
161
159
 
162
- ### Step 4: Print Completion Message
160
+ ## Step 4: Print Completion Message
163
161
 
164
162
  ```
165
163
  Project initialized:
@@ -171,48 +169,3 @@ Project initialized:
171
169
 
172
170
  Run `/flow:spec` to plan your first milestone.
173
171
  ```
174
-
175
- ---
176
-
177
- ## New Milestone Mode
178
-
179
- ### Step 1: Read Context
180
-
181
- Read `.planning/STATE.md` and `.planning/ROADMAP.md` to understand:
182
- - What milestone just completed (or is completing)
183
- - What version number to use next
184
- - Current state of the project
185
-
186
- ### Step 2: Ask Milestone Question
187
-
188
- Use AskUserQuestion:
189
- - "What's the goal of this new milestone?" (free text)
190
- - "What should it be called?" (free text, or suggest a name based on context)
191
-
192
- ### Step 3: Archive Completed Milestone
193
-
194
- 1. Read current ROADMAP.md phase details for the completed milestone
195
- 2. Write them to `.planning/archive/milestones-vX.md` (where X is the completed version)
196
- 3. If `PRD.md` exists, move it to `.planning/archive/PRD-vX.md` (read it, write to archive, delete original)
197
- 4. In ROADMAP.md, replace the completed milestone's phase details with just the summary row (mark as "Complete")
198
-
199
- ### Step 4: Update Planning Docs
200
-
201
- **ROADMAP.md:**
202
- - Add new milestone row to the table
203
- - Add new milestone section with goal and "Run `/flow:spec` to define phases"
204
-
205
- **STATE.md:**
206
- - Replace with fresh state for the new milestone
207
- - Reset phase progress table
208
- - Note the milestone transition in "What Was Built"
209
-
210
- ### Step 5: Print Completion Message
211
-
212
- ```
213
- Milestone [name] (v[X]) initialized.
214
- - Archived: previous milestone details + PRD
215
- - Updated: ROADMAP.md, STATE.md
216
-
217
- Run `/flow:spec` to build the PRD for this milestone.
218
- ```
@@ -16,8 +16,10 @@ You are executing the `/flow:spec` skill. This is the KEYSTONE skill of the flow
16
16
  2. Read `CLAUDE.md` — understand project rules and tech stack
17
17
  3. Read `PRD.md` if it exists — check for existing spec to build on
18
18
  4. **Codebase scan** (brownfield projects):
19
- - Use Glob to find: components, pages/routes, API endpoints, types, utilities, config files, database models
20
- - Use Grep for: export patterns, route definitions, key function signatures
19
+ - **Exclusions:** NEVER scan these directories/files: `node_modules/`, `.git/`, `dist/`, `build/`, `.next/`, `__pycache__/`, `*.min.js`, `*.map`, `*.lock`. Use Glob with patterns like `src/**/*`, `app/**/*`, `lib/**/*` never use bare `**/*` which includes generated files.
20
+ - **Size check first:** Use Glob with `src/**/*`, `app/**/*`, `lib/**/*`, `components/**/*` (excluding the above) to estimate relevant file count. If > 500 files, switch to focused mode (see below).
21
+ - **Standard mode (≤ 500 files):** Use Glob to find components, pages/routes, API endpoints, types, utilities, config files, database models. Use Grep for export patterns, route definitions, key function signatures. **Cap at 50 files sampled** — prioritize entry points, config, and type definitions.
22
+ - **Focused mode (> 500 files):** Scan ONLY: package.json/config files, entry points (index.ts, main.ts, app.ts), route definitions, database schema/models, and type definition files. Skip component trees, test files, and generated code entirely.
21
23
  - Build internal summary: "Here's what exists that we can reuse"
22
24
  5. Print a brief context summary to the user: "Here's what I found in the codebase: [key components, patterns, data layer]. Starting the spec interview."
23
25
 
@@ -113,6 +115,20 @@ Cover these areas thoroughly. There are no "rounds" — move fluidly between are
113
115
 
114
116
  ## Phase 3 — PRD Generation
115
117
 
118
+ ### Minimum Viable PRD Check
119
+
120
+ Before generating the final PRD, validate:
121
+ - At least **3 user stories** with acceptance criteria have been discussed
122
+ - At least **1 implementation phase** has been defined
123
+ - At least **1 verification command** has been specified
124
+
125
+ If any check fails, print what's missing and use AskUserQuestion:
126
+ - "The PRD is thin — [missing items]. Want to continue the interview to flesh it out, or finalize as-is?"
127
+ - "Continue interview" — return to Phase 2 and probe the missing areas
128
+ - "Finalize as-is" — proceed with what we have
129
+
130
+ ### Write PRD
131
+
116
132
  Write `PRD.md` to the project root with this EXACT structure:
117
133
 
118
134
  ```markdown
@@ -17,7 +17,7 @@ Read ALL of the following in parallel:
17
17
  - Count lessons in `tasks/lessons.md` (if exists)
18
18
 
19
19
  IF both STATE.md AND ROADMAP.md are missing:
20
- - Print: "No flow project found. Run `/flow:init` to set up, or `/flow:task` for a quick standalone fix."
20
+ - Print: "No flow project found. Run `/flow:setup` to set up, or `/flow:task` for a quick standalone fix."
21
21
  - STOP here.
22
22
 
23
23
  IF only one file exists, continue with what's available.
@@ -47,7 +47,7 @@ Use this explicit decision tree:
47
47
 
48
48
  **IF all phases are complete:**
49
49
  → Primary: `/flow:done` to finalize this milestone
50
- → Then: `/flow:init` to start the next milestone
50
+ → Then: `/flow:milestone` to start the next milestone
51
51
  → Alt: `/flow:task` for quick fixes or cleanup (no PRD needed)
52
52
 
53
53
  **IF no phases exist in ROADMAP (milestone defined but not planned):**
@@ -65,7 +65,7 @@ Lessons: [N] rules
65
65
  [routing recommendations from Step 3]
66
66
  ```
67
67
 
68
- Adapt the block based on available information. If STATE.md is missing, omit "Last session". If ROADMAP.md is missing, omit phase counts and say "Run /flow:init to set up tracking."
68
+ Adapt the block based on available information. If STATE.md is missing, omit "Last session". If ROADMAP.md is missing, omit phase counts and say "Run /flow:setup to set up tracking."
69
69
 
70
70
  ## Step 5 — No File Writes
71
71
 
@@ -11,7 +11,7 @@ You are executing the `/flow:task` skill. This is for small, focused work — bu
11
11
  RULES:
12
12
  - NO AGENT TEAMS. NO PRD. Single execution context.
13
13
  - Exception: ONE Task agent for an isolated subtask to prevent context bloat.
14
- - This skill MUST work without `/flow:init`. Missing planning files are fine.
14
+ - This skill MUST work without `/flow:setup`. Missing planning files are fine.
15
15
 
16
16
  ## Step 1 — Context Load
17
17
 
@@ -46,14 +46,23 @@ If installed version equals latest version, print this and stop:
46
46
  Flow is up to date (v<version>)
47
47
  ```
48
48
 
49
- ## Step 4: Confirm update
49
+ ## Step 4: Show what's new
50
50
 
51
- Print the available update and ask the user to confirm:
51
+ Fetch the CHANGELOG.md from the Flow repo to show the user what changed:
52
+
53
+ 1. Run: `npx -y -p flow-cc@<latest> node -e "const fs=require('fs'),p=require('path');try{console.log(fs.readFileSync(p.join(require.resolve('flow-cc/package.json'),'..','CHANGELOG.md'),'utf8'))}catch(e){console.log('CHANGELOG not available')}"`
54
+ 2. Parse the output and extract only the section for `v<latest>` (from the `## [<latest>]` heading to the next `## [` heading or end of file)
55
+ 3. Print:
52
56
 
53
57
  ```
54
58
  Update available: v<installed> → v<latest>
59
+
60
+ Here's what's new in v<latest>:
61
+ <extracted changelog section>
55
62
  ```
56
63
 
64
+ If the CHANGELOG fetch fails, just print the version line without the changelog section. Don't let a missing changelog block the update.
65
+
57
66
  Wait for user confirmation before proceeding.
58
67
 
59
68
  ## Step 5: Run update
@@ -13,7 +13,7 @@
13
13
  | — | Run `/flow:spec` to define phases | — |
14
14
 
15
15
  ## What Was Built (This Session)
16
- - Project initialized with `/flow:init`
16
+ - Project initialized with `/flow:setup`
17
17
  - Created: CLAUDE.md, STATE.md, ROADMAP.md, tasks/lessons.md
18
18
 
19
19
  ## Key Decisions
@@ -5,6 +5,16 @@ Format: PATTERN → CAUSE → FIX → RULE
5
5
  ## Execution Patterns
6
6
  <!-- Lessons about workflow, delegation, verification -->
7
7
 
8
+ <!-- EXAMPLE (replace with real lessons as you work):
9
+
10
+ ### Agent context overflow on large files
11
+ - **PATTERN:** Spawned agent tried to read a 2000-line file and ran out of context before finishing its task
12
+ - **CAUSE:** Agent prompt didn't specify which lines/functions to read — it read the whole file
13
+ - **FIX:** Added explicit line ranges and function names to the agent prompt
14
+ - **RULE:** Always tell agents exactly which functions/sections to read. Never say "read file.ts" — say "read file.ts lines 50-120 (the handleSubmit function)"
15
+
16
+ END EXAMPLE -->
17
+
8
18
  ## Domain Knowledge
9
19
  <!-- Lessons about business logic, data models, user behavior -->
10
20