@mhd-ghaith-abtah/flow 0.7.2-beta.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 (53) hide show
  1. package/CHANGELOG.md +87 -0
  2. package/LICENSE +21 -0
  3. package/README.md +162 -0
  4. package/adapters/e2e/_interface.md +42 -0
  5. package/adapters/e2e/none.md +15 -0
  6. package/adapters/e2e/playwright-mcp.md +86 -0
  7. package/adapters/issue-tracker/_interface.md +46 -0
  8. package/adapters/issue-tracker/github-issues.md +103 -0
  9. package/adapters/issue-tracker/linear.md +65 -0
  10. package/adapters/issue-tracker/none.md +26 -0
  11. package/adapters/pr/_interface.md +29 -0
  12. package/adapters/pr/github.md +61 -0
  13. package/adapters/pr/none.md +32 -0
  14. package/adapters/verify/_interface.md +26 -0
  15. package/adapters/verify/custom.md +27 -0
  16. package/adapters/verify/make.md +30 -0
  17. package/adapters/verify/pnpm.md +27 -0
  18. package/bin/flow.js +129 -0
  19. package/catalog.yaml +364 -0
  20. package/docs/adapters.md +99 -0
  21. package/docs/migrate-from-bmad.md +95 -0
  22. package/docs/profiles.md +81 -0
  23. package/docs/quickstart.md +82 -0
  24. package/lib/catalog.js +164 -0
  25. package/lib/commands/add.js +147 -0
  26. package/lib/commands/doctor.js +392 -0
  27. package/lib/commands/init.js +86 -0
  28. package/lib/commands/install.js +181 -0
  29. package/lib/commands/plan.js +108 -0
  30. package/lib/commands/remove.js +87 -0
  31. package/lib/commands/uninstall.js +157 -0
  32. package/lib/repo-root.js +53 -0
  33. package/package.json +62 -0
  34. package/schemas/catalog.schema.json +155 -0
  35. package/schemas/flow-config.schema.json +85 -0
  36. package/schemas/install-state.schema.json +79 -0
  37. package/skills/flow-doctor/SKILL.md +15 -0
  38. package/skills/flow-doctor/workflow.md +157 -0
  39. package/skills/flow-init/SKILL.md +10 -0
  40. package/skills/flow-init/workflow.md +420 -0
  41. package/skills/flow-sprint/SKILL.md +10 -0
  42. package/skills/flow-sprint/workflow.md +394 -0
  43. package/skills/flow-story/SKILL.md +12 -0
  44. package/skills/flow-story/workflow.md +531 -0
  45. package/templates/claude-md-section.md.tmpl +55 -0
  46. package/templates/flow-readme.md.tmpl +34 -0
  47. package/templates/flow.config.yaml.tmpl +94 -0
  48. package/templates/pr.md.tmpl +40 -0
  49. package/templates/retro.md.tmpl +58 -0
  50. package/templates/sprint.yaml.tmpl +18 -0
  51. package/templates/story.md.tmpl +35 -0
  52. package/tools/fix-caveman-shrink.sh +68 -0
  53. package/tools/lint-changelog.js +98 -0
@@ -0,0 +1,394 @@
1
+ # flow-sprint Workflow
2
+
3
+ **Output style — Caveman mandate.** All user-facing output from this workflow MUST be Caveman-mode: fragments OK, drop articles / filler / pleasantries / hedging, keep code & commit & security text normal. Status, prompts, errors, tables — all terse.
4
+
5
+ **Goal:** maintain sprint state in `docs/flow/sprint.yaml`. Stories are the unit of work; epics group them; status flows backlog → doing → review → done. Every status change also invokes the active issue-tracker adapter to keep external state in sync.
6
+
7
+ **Schema invariants** (validated on every write):
8
+ - `stories[].id` matches `^E\d+-S?\d{1,3}[a-z]?$`. Accepted forms:
9
+ - Flow native — `E1-001`, `E1-002`, … (zero-padded three-digit)
10
+ - BMad-style — `E1-S1`, `E2-S10`, `E3-S9b`, … (kept when migrated from `bmad-create-story` output to preserve continuity)
11
+ - Both forms can coexist in the same sprint.yaml. `flow-sprint add` continues whichever form the epic already uses.
12
+ - `stories[].status` in `[backlog, doing, review, done, cancelled]`
13
+ - `stories[].kind` in `[code, offline]`, default `code` when omitted.
14
+ - `code` — runs the full per-story loop (branch → plan → implement → review → verify → e2e → docs → commit → PR).
15
+ - `offline` — meatspace tasks (address resolution, photoshoot, copywriting, manual data work). `next` skips by default; `done` is a one-shot flip with no branch / PR / verify checks.
16
+ - Exactly zero or one story may be in `doing` at any time (enforce one-story-at-a-time per dev unless `mode: team`)
17
+
18
+ ---
19
+
20
+ <workflow>
21
+
22
+ <step n="1" goal="Parse subcommand and arguments">
23
+ <action>Parse argv:
24
+ - First positional = subcommand
25
+ - Remaining args interpreted per subcommand
26
+ </action>
27
+
28
+ <action>Resolve paths from `flow.config.yaml`:
29
+ - `{{sprint_file}}` = config.sprint_file (default `docs/flow/sprint.yaml`)
30
+ - `{{stories_dir}}` = config.stories_dir (default `docs/flow/stories`)
31
+ - `{{deferred_file}}` = config.deferred_file (default `docs/flow/deferred.md`)
32
+ - `{{archive_dir}}` = `docs/flow/archive`
33
+ - `{{retros_dir}}` = `docs/flow/retros`
34
+ - `{{issue_tracker_adapter}}` = config.adapters.issue_tracker (e.g. "github-issues")
35
+ - `{{pr_adapter}}` = config.adapters.pr
36
+ - `{{mode}}` = config.mode
37
+ </action>
38
+
39
+ <action>If `flow.config.yaml` is missing, HALT with "Flow not installed in this project — run /flow-init first."</action>
40
+
41
+ <action>Load `{{sprint}}` = parsed `{{sprint_file}}`.</action>
42
+ </step>
43
+
44
+ <step n="2" goal="Dispatch subcommand">
45
+
46
+ <check if="subcommand == 'init'">
47
+ <action>Write a minimal sprint.yaml + create dirs. Same effect as flow-init's project scaffold step but standalone. Useful for bootstrapping a fresh sprint after a retro.</action>
48
+ </check>
49
+
50
+ <check if="subcommand == 'add-epic'">
51
+ <action>Parse: `<epic-id> "<title>"` — e.g. `add-epic E1 "Foundation"`.</action>
52
+ <action>Validate epic-id format (`^E\d+$`).</action>
53
+ <action>Refuse if epic-id already exists in `{{sprint}}.epics`.</action>
54
+ <action>Append `{ id, title, status: backlog }` to `{{sprint}}.epics`.</action>
55
+ <action>Write sprint.yaml.</action>
56
+ <output>✓ Added epic {{epic_id}}.</output>
57
+ </check>
58
+
59
+ <check if="subcommand == 'add'">
60
+ <action>Parse: `"<title>" --epic <E?> [--tags t1,t2] [--why "..."] [--issue auto|skip]`.</action>
61
+
62
+ <action>If `--epic` omitted, ask which epic (numbered list from {{sprint}}.epics).</action>
63
+
64
+ <check if="--why not provided">
65
+ <ask>Brief why? (one sentence)</ask>
66
+ </check>
67
+ <check if="ACs not provided in args">
68
+ <ask>Acceptance criteria? One per line. Empty line to finish.</ask>
69
+ </check>
70
+
71
+ <action>Compute the next story id for this epic — **detect format from existing stories first** (issue #26 — loosened to support non-BMad/non-Flow formats):
72
+ 1. Collect existing stories in this epic: `{{epic_stories}}` = stories where `epic == {{epic_id}}`.
73
+ 2. Determine `{{id_format}}` by matching the FIRST entry's id against the regex set in priority order:
74
+ - `^E\d+-S\d+[a-z]?$` → `bmad` (e.g. `E1-S1`, `E3-S9b`)
75
+ - `^E\d+-\d{3}$` → `flow-native` (e.g. `E1-001`)
76
+ - `^[A-Z][A-Z0-9]*-\d+$` → `tracker-style` (e.g. `PLA-42`, `ENG-100` — Linear / Jira style)
77
+ - `^[a-z][a-z0-9-]*$` → `kebab` (e.g. `setup-auth`, `migrate-db-v2`)
78
+ - `^.+$` (any non-empty) → `custom` — Flow won't auto-generate; ASKs the user for the next id (suggests `<FIRST.id>_<n>`)
79
+ - Empty → HALT with "Empty story-id in epic {{epic_id}}. Fix sprint.yaml manually."
80
+ - If `{{epic_stories}}` is empty: use `flow.config.yaml > sprint.default_id_format` (default `bmad` post-migration, `flow-native` for greenfield, override via `--id-format=<format>`).
81
+ 3. Compute next numeric: `{{next_num}}` = max(parsed numeric part of each existing id) + 1; start at 1 for empty epics. `kebab` + `custom` skip this.
82
+ 4. Render `{{story_id}}` per format:
83
+ - `bmad` → `E{{epic_num}}-S{{next_num}}` (no zero-padding; e.g. `E1-S11`)
84
+ - `flow-native` → `E{{epic_num}}-{{next_num.toString().padStart(3, '0')}}` (e.g. `E1-011`)
85
+ - `tracker-style` → `{{prefix}}-{{next_num}}` (prefix parsed from FIRST.id; reuses tracker team-key)
86
+ - `kebab` → ASK user (no sensible auto-form for free-form kebab ids; suggest `--id=<value>` flag)
87
+ - `custom` → ASK user; default suggestion `{{FIRST.id}}_{{next_num}}`
88
+ </action>
89
+
90
+ <action>Generate filename: `{{stories_dir}}/{{story_id}}-{{slug(title)}}.md`.</action>
91
+
92
+ <action>Render the story file from `templates/story.md.tmpl` with title, epic, tags, why, ACs.</action>
93
+
94
+ <check if="{{issue_tracker_adapter}} != 'none' AND --issue != 'skip'">
95
+ <action>Load adapter: `~/.claude/skills/flow-story/adapters/issue-tracker/{{issue_tracker_adapter}}.md`. Follow its `create_issue` operation with title + body. Capture returned `{issue_id, url}`.</action>
96
+ <action>Update story file frontmatter: add `Issue: {{issue_id}}` line.</action>
97
+ </check>
98
+
99
+ <action>Append to `{{sprint}}.stories`:
100
+ ```yaml
101
+ - id: {{story_id}}
102
+ title: "{{title}}"
103
+ epic: {{epic_id}}
104
+ issue: "{{issue_id or null}}"
105
+ status: backlog
106
+ tags: {{tags}}
107
+ file: {{relative path to story md}}
108
+ ```
109
+ </action>
110
+
111
+ <action>Write sprint.yaml.</action>
112
+ <output>✓ Added {{story_id}} — {{title}}
113
+ File: {{file}}
114
+ Issue: {{issue_id or "(none)"}}
115
+ Run `/flow-sprint next` to start work.
116
+ </output>
117
+ </check>
118
+
119
+ <check if="subcommand == 'next'">
120
+ <action>Parse optional flags from args: `--epic <id>` (scope picker to one epic), `--include-offline` (don't skip stories where `kind == offline`), `--kind <code|offline>` (force pick by kind).</action>
121
+
122
+ <action>Build the candidate set:
123
+ 1. Start from `{{sprint}}.stories` where `status == 'backlog'` (preserve YAML order).
124
+ 2. If `--epic` given, filter to that epic.
125
+ 3. **Filter out offline stories by default:** drop entries where `kind == 'offline'` UNLESS `--include-offline` or `--kind offline` was passed.
126
+ 4. → `{{candidates}}`.
127
+ </action>
128
+
129
+ <check if="{{candidates}} is empty">
130
+ <action>Check whether there ARE offline stories that were filtered out. If yes, surface them as a hint.</action>
131
+ <output>📭 No code stories in backlog{{epic_scope_suffix}}.
132
+
133
+ {{ if filtered_offline > 0: }}{{filtered_offline}} offline-tagged story(ies) skipped. Run with `--include-offline` to pick one, or:
134
+ - `/flow-sprint next --include-offline` — include offline stories in the candidate pool
135
+ - `/flow-sprint done <id> --kind offline` — close an offline story directly (no branch, no PR)
136
+ - `/flow-sprint add "<title>" --epic E? --tags ...` — add a new story
137
+ {{ else: }}Add a story with `/flow-sprint add` or run `/flow-sprint status` to see what's left.{{ /if }}
138
+ </output>
139
+ <action>End turn.</action>
140
+ </check>
141
+
142
+ <action>Pick the first entry in `{{candidates}}` → `{{story}}`.</action>
143
+
144
+ <check if="any story has status == 'doing'">
145
+ <output>⚠ Another story is already in 'doing': {{that_story.id}}. Finish or pause it first.</output>
146
+ <ask>Continue anyway and put {{story.id}} alongside? [y/N] (only safe in team mode)</ask>
147
+ </check>
148
+
149
+ <action>Flip `{{story}}.status` to `doing`. Set `{{story}}.started_at` = today (ISO).</action>
150
+
151
+ <check if="{{story.kind}} == 'offline'">
152
+ <action>**Offline branch:** do NOT create a git branch. Skip the issue-tracker `transition_to_doing` call (offline stories typically have no linked issue). Write sprint.yaml. Emit:</action>
153
+ <output>📌 Started {{story.id}} — {{story.title}} *(kind: offline)*
154
+
155
+ No branch created — this is meatspace work.
156
+ When you've completed the task IRL, close it out:
157
+ `/flow-sprint done {{story.id}}`
158
+ </output>
159
+ <action>End turn — flow-story has nothing to do for offline stories.</action>
160
+ </check>
161
+
162
+ <action>**Code branch (default):** Create + checkout `git checkout -b flow/{{story.id}}-{{slug(title)}}` (or `{{issue_id}}-...` if present and adapter prefers that format).</action>
163
+
164
+ <action>Invoke issue-tracker adapter `transition_to_doing({{story.issue}})` if `{{issue_id}}` exists.</action>
165
+
166
+ <action>Write sprint.yaml.</action>
167
+
168
+ <output>📌 Started {{story.id}} — {{story.title}}
169
+
170
+ Branch: {{branch_name}}
171
+ Story: {{story.file}}
172
+ Issue: {{story.issue or "(none)"}}
173
+
174
+ Next: `/flow-story` to drive implementation.
175
+ </output>
176
+ </check>
177
+
178
+ <check if="subcommand == 'status'">
179
+ <action>Group stories by epic. For each epic, show:
180
+ - Epic header + progress count
181
+ - Each story: status icon, id, title, issue (if any)
182
+ </action>
183
+
184
+ <action>Show open PRs (if `{{pr_adapter}}` != none): query GH for PRs matching `flow/*` branches.</action>
185
+ <action>Show open deferred-work count (count non-resolved lines in `{{deferred_file}}`).</action>
186
+
187
+ <action>**Midpoint check.** Compute `{{progress_pct}}` = done / (total - cancelled). Read `{{midpoint_threshold}}` from flow.config.yaml > sprint.midpoint_threshold (default 0.5). Read `{{midpoint_review_offered}}` from sprint.yaml > metadata.midpoint_review_offered (default false).</action>
188
+
189
+ <check if="{{progress_pct}} >= {{midpoint_threshold}} AND NOT {{midpoint_review_offered}}">
190
+ <output>🎯 Midpoint reached ({{done}}/{{total}} = {{progress_pct}}%). Worth a scope check?
191
+
192
+ Open scope is a leading indicator of slip. A 5-min review now can save a lot at the back end.
193
+
194
+ Run: `/flow-sprint scope-review` (or `--report-only` for just the report, no prompts).
195
+ </output>
196
+ <action>Set `sprint.yaml > metadata.midpoint_review_offered = true` so this prompt doesn't repeat.</action>
197
+ </check>
198
+
199
+ <output>📊 Sprint status
200
+
201
+ {{ for each epic: }}
202
+ Epic {{epic.id}} — {{epic.title}} ({{done}}/{{total}}) {{ ✓ if done==total }}
203
+ {{ for each story: }}
204
+ {{status_icon}} {{story.id}} {{story.title}}{{ + " · " + issue if any}}
205
+
206
+ Open PRs: {{count}}
207
+ Open deferred: {{count}}
208
+ </output>
209
+ </check>
210
+
211
+ <check if="subcommand == 'done'">
212
+ <action>Parse: `<story-id>` [+ optional flags `--note "..."`, `--force`]. Look up story in {{sprint}}.</action>
213
+
214
+ <check if="{{story.kind}} == 'offline'">
215
+ <action>**Offline shortcut path** — no branch / PR / verify gates apply.
216
+ 1. Validate current status in `[backlog, doing]` (allow done-without-doing for backfilled offline work; halt only if already `done` or `cancelled`).
217
+ 2. Flip `{{story}}.status` → `done`. Set `{{story}}.completed_at` = today.
218
+ 3. If `--note` provided, append it to `{{story}}.notes` (one-line resolution summary, e.g. `"Office at Dubai Silicon Oasis, Building XYZ, Floor 3"`).
219
+ 4. Invoke issue-tracker adapter `transition_to_done({{story.issue}})` only if `{{story.issue}}` exists (typically offline stories have none).
220
+ 5. If story file exists, move to archive; else skip.
221
+ 6. Write sprint.yaml.
222
+ 7. Skip the `git checkout main && pull && branch -d` block — no branch was created.
223
+ </action>
224
+ <output>✓ {{story.id}} done *(offline)*
225
+ {{ if note: }}Note: {{note}}{{ /if }}
226
+ </output>
227
+ <action>Continue to epic-complete check at bottom of this subcommand, then end turn.</action>
228
+ </check>
229
+
230
+ <action>**Code path (default):**</action>
231
+ <action>Validate current status is `review` (or `doing` if user passes `--force`).</action>
232
+
233
+ <check if="story has issue AND {{pr_adapter}} != 'none'">
234
+ <action>Verify PR is merged via adapter `verify_merged(issue_id)`. If not merged, HALT with "PR not merged yet — merge first, then re-run."</action>
235
+ </check>
236
+
237
+ <action>Flip `{{story}}.status` to `done`. Set `{{story}}.completed_at` = today.</action>
238
+ <action>Invoke issue-tracker adapter `transition_to_done({{story.issue}})` to close the external issue.</action>
239
+
240
+ <action>Move story file: `{{story.file}}` → `{{archive_dir}}/{{basename}}`. Update `{{story}}.file` to the new path.</action>
241
+
242
+ <action>`git fetch --prune && git checkout main && git pull --ff-only && git branch -d flow/{{story.id}}-*`.</action>
243
+
244
+ <action>Write sprint.yaml.</action>
245
+
246
+ <action>Check epic completion: if all stories in this epic have status == 'done', set epic.status = done and emit a hint to run `/flow-sprint retro {{epic.id}}`.</action>
247
+
248
+ <output>✓ {{story.id}} done. Archived to {{archive_dir}}.
249
+ {{ if epic complete: }} 🎉 Epic {{epic.id}} complete — run `/flow-sprint retro {{epic.id}}`.
250
+ </output>
251
+ </check>
252
+
253
+ <check if="subcommand == 'deferred'">
254
+ <action>Read `{{deferred_file}}`. Parse lines (one entry per line, format: `- [<status>] <one-liner> · <source>`).</action>
255
+ <output>Deferred items ({{open_count}} open):
256
+ {{ list with line numbers + status }}
257
+ Add new: append to {{deferred_file}}. Mark resolved: change `[ ]` → `[x]`.
258
+ </output>
259
+ </check>
260
+
261
+ <check if="subcommand == 'retro'">
262
+ <action>Parse: `<epic-id>` (default: most recently completed epic).</action>
263
+ <action>Validate epic exists and has at least one done story.</action>
264
+
265
+ <action>Gather inputs:
266
+ - All story files in `{{archive_dir}}` matching this epic
267
+ - `git log --oneline main` filtered to commits in this epic's date range (between first story's started_at and last story's completed_at)
268
+ - Open deferred items tagged for this epic
269
+ </action>
270
+
271
+ <action>Render `{{retros_dir}}/{{epic.id}}-retro.md` from `templates/retro.md.tmpl`. Pre-fill: shipped count, cycle time avg, deferred carry-forward. Leave "What worked / What didn't / Carry into next epic" sections for the user to edit.</action>
272
+
273
+ <output>✓ Retro draft written to {{retros_dir}}/{{epic.id}}-retro.md.
274
+ Edit, commit, push.
275
+ </output>
276
+ </check>
277
+
278
+ <check if="subcommand == 'import-bmad'">
279
+ <action>Same migration logic as flow-init step 11. Useful if user skipped migration at install time.</action>
280
+ </check>
281
+
282
+ <check if="subcommand == 'scope-review'">
283
+ <action>Parse optional flags: `--apply` (interactively apply suggestions), `--report-only` (write report, no prompts), `--threshold <pct>` (override 0.5 default for what counts as "midpoint"), `--include-prd` (also read PRD/architecture from reference_docs).</action>
284
+
285
+ <action>Gather inputs for the audit agent:
286
+ 1. sprint.yaml — full epic + story list with status
287
+ 2. All story files under `{{stories_dir}}` AND `{{archive_dir}}` (recent + done)
288
+ 3. `{{deferred_file}}` — accumulated friction signals
289
+ 4. `{{retros_dir}}/*.md` — completed-epic retros
290
+ 5. Reference docs from `flow.config.yaml > reference_docs` — only if `--include-prd` (e.g. PRD, architecture, epics-stories.md from BMad)
291
+ 6. Recent git history: `git log --oneline -50 main` for done-context
292
+ </action>
293
+
294
+ <action>Spawn a background agent (Agent tool, run_in_background: true) with:
295
+ - `subagent_type`: `general-purpose` (no specialized scope-audit agent in v0; could add later)
296
+ - `description`: "Scope review of {{project_name}}"
297
+ - `prompt`: a self-contained brief listing all inputs above and asking the agent to return a structured markdown report:
298
+
299
+ ```
300
+ # Scope Review — {{project_name}} — {{date}}
301
+
302
+ ## Progress snapshot
303
+ - {{done}}/{{total}} stories done ({{pct}}%)
304
+ - {{N}} stories in backlog / doing / review
305
+ - Time since first story: {{days}}
306
+ - Deferred items open: {{open_count}}
307
+
308
+ ## Proposed merges (overlapping stories)
309
+ For each: source story-ids, suggested merged id + title, rationale (1 line)
310
+
311
+ ## Proposed drops (no longer relevant / duplicates)
312
+ For each: story-id, rationale referencing PRD or deferred ledger or retro
313
+
314
+ ## Proposed splits (stories that grew too big)
315
+ For each: story-id, proposed split into N new stories
316
+
317
+ ## Proposed adds (gaps not covered)
318
+ For each: epic, suggested new story-id + title, rationale
319
+
320
+ ## Epics worth reconsidering
321
+ Either consolidate / drop / split entire epics. Include rationale.
322
+
323
+ ## Risks of NOT trimming
324
+ One paragraph on what happens if scope stays as-is.
325
+ ```
326
+
327
+ Output ONLY the report. No preamble, no closing remarks.
328
+ </action>
329
+
330
+ <action>While the agent runs (in background), continue:
331
+ 1. Ensure `{{retros_dir}}/../scope-reviews/` exists (mkdir).
332
+ 2. Reserve filename `docs/flow/scope-reviews/{{YYYY-MM-DD}}.md`.
333
+ </action>
334
+
335
+ <action>When the agent returns (notification): write its report to the reserved filename.</action>
336
+
337
+ <output>📋 Scope review report → docs/flow/scope-reviews/{{YYYY-MM-DD}}.md ({{N}} merges, {{M}} drops, {{K}} adds, {{L}} splits proposed).</output>
338
+
339
+ <check if="--apply OR (default behavior, NOT --report-only)">
340
+ <ask>Review suggestions interactively? [Y/n/later]</ask>
341
+ <check if="user picks Y">
342
+ <action>For each suggestion in the report (merge, drop, split, add) in that order:
343
+ 1. Show the suggestion + rationale.
344
+ 2. Ask `[a]pply / [s]kip / [m]odify / [q]uit`.
345
+ 3. If apply: mutate sprint.yaml accordingly. For merges, combine stories under one id, archive the absorbed ones with a "merged into <X>" note. For drops, set status to `cancelled` with a `cancelled_reason`. For splits, replace one entry with N new entries. For adds, append new entries with status `backlog`.
346
+ 4. If modify: collect user's edits to the proposed change, then apply.
347
+ </action>
348
+ <action>After all suggestions processed: write sprint.yaml, record `metadata.last_scope_review.applied_at` = today + summary counts.</action>
349
+ </check>
350
+ <check if="user picks later">
351
+ <action>Record `metadata.last_scope_review.report_pending` = true + filename. To apply later, re-run `/flow-sprint scope-review` — it skips the audit-agent phase when a recent report exists for today and goes straight to the interactive walkthrough. (A dedicated `--apply-from <path>` flag is tracked as E5-009 for a future release; for now the same-day re-run path is the supported workflow.)</action>
352
+ </check>
353
+ </check>
354
+
355
+ <action>Record in sprint.yaml `metadata.scope_reviews[]`: {date, suggested_counts, applied_counts, report_path}.</action>
356
+ </check>
357
+
358
+ <check if="subcommand not recognized">
359
+ <output>Unknown subcommand: {{subcommand}}.
360
+ Try: init | add-epic | add | next | status | done | deferred | retro | import-bmad
361
+ </output>
362
+ </check>
363
+ </step>
364
+
365
+ </workflow>
366
+
367
+ ---
368
+
369
+ ## sprint.yaml schema (canonical)
370
+
371
+ ```yaml
372
+ version: 1
373
+ project: <name>
374
+ generated: <ISO date>
375
+ last_updated: <ISO timestamp>
376
+
377
+ epics:
378
+ - id: E1
379
+ title: "Foundation"
380
+ status: backlog | in-progress | done
381
+
382
+ stories:
383
+ - id: E1-001 # ^E\d+-\d{3}$
384
+ title: "Tokens + base layout"
385
+ epic: E1
386
+ issue: "#42" | "PLA-15" | null
387
+ status: backlog | doing | review | done | cancelled
388
+ tags: [ui, foundation]
389
+ file: docs/flow/stories/E1-001-tokens-base-layout.md
390
+ started_at: 2026-05-18 # only when status >= doing
391
+ completed_at: 2026-05-19 # only when status == done
392
+ ```
393
+
394
+ Comments are preserved on write. Unknown top-level keys are preserved (forward-compat).
@@ -0,0 +1,12 @@
1
+ ---
2
+ name: flow-story
3
+ description: 'Per-story orchestrator. Auto-detects phase (plan / implement / review / verify / e2e / docs / commit / pr / merge-done) from sprint.yaml + git branch + commits + PR state, then invokes the right ECC primitive (/plan, /prp-implement, /code-review, /update-docs, /prp-commit, /prp-pr) or active adapter, and chains to the next phase. Auto-scaffolds a minimal story-file stub from sprint.yaml + conventions when missing. Accepts no args (continues active story) or a story id. Use when the user runs /flow-story or /flow-story <id>.'
4
+ argument-hint: '[<story-id>] [--advise-only] [--auto] [--auto-merge] [--skip-plan] [--strict-plan] [--no-verify] [--no-e2e] [--no-tests] [--no-review] [--hard-review]'
5
+ version: 0.6.1
6
+ ---
7
+
8
+ Follow the instructions in ./workflow.md.
9
+
10
+ **Execution model (v0.3+):** the workflow defaults to **execute mode** — each phase invokes the next ECC primitive or adapter and chains to the following phase. Hard halts (plan's CONFIRM, CRITICAL findings, verify failure, e2e failure, PR open) are unconditional. The pre-commit confirm is the only soft halt that `--auto` can skip.
11
+
12
+ Pass `--advise-only` to revert to the pre-v0.3 behavior where each phase prints the next command and ends the turn.