@ikunin/sprintpilot 2.2.31 → 2.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.
Files changed (34) hide show
  1. package/README.md +232 -413
  2. package/_Sprintpilot/Sprintpilot.md +76 -6
  3. package/_Sprintpilot/bin/autopilot.js +734 -68
  4. package/_Sprintpilot/lib/orchestrator/action-ledger.js +208 -0
  5. package/_Sprintpilot/lib/orchestrator/adapt.js +93 -15
  6. package/_Sprintpilot/lib/orchestrator/profile-rules.js +7 -16
  7. package/_Sprintpilot/lib/orchestrator/sprint-plan.js +488 -0
  8. package/_Sprintpilot/lib/orchestrator/state-store.js +9 -5
  9. package/_Sprintpilot/lib/orchestrator/user-command-applier.js +78 -0
  10. package/_Sprintpilot/lib/orchestrator/user-commands.js +114 -0
  11. package/_Sprintpilot/lib/orchestrator/verify.js +10 -17
  12. package/_Sprintpilot/manifest.yaml +4 -1
  13. package/_Sprintpilot/modules/autopilot/profiles/_base.yaml +18 -4
  14. package/_Sprintpilot/modules/git/config.yaml +15 -9
  15. package/_Sprintpilot/modules/ma/config.yaml +29 -27
  16. package/_Sprintpilot/scripts/dispatch-layer.js +12 -15
  17. package/_Sprintpilot/scripts/infer-dependencies.js +706 -254
  18. package/_Sprintpilot/scripts/log-timing.js +6 -10
  19. package/_Sprintpilot/scripts/merge-shards.js +21 -23
  20. package/_Sprintpilot/scripts/post-green-gates.js +3 -1
  21. package/_Sprintpilot/scripts/resolve-dag.js +452 -280
  22. package/_Sprintpilot/scripts/sprint-plan.js +1068 -0
  23. package/_Sprintpilot/scripts/state-shard.js +13 -5
  24. package/_Sprintpilot/scripts/summarize-timings.js +2 -3
  25. package/_Sprintpilot/skills/sprint-autopilot-on/SKILL.md +30 -2
  26. package/_Sprintpilot/skills/sprint-autopilot-on/workflow.orchestrator.md +36 -10
  27. package/_Sprintpilot/skills/sprintpilot-dependency-graph/SKILL.md +63 -0
  28. package/_Sprintpilot/skills/sprintpilot-dependency-graph/workflow.md +227 -0
  29. package/_Sprintpilot/skills/sprintpilot-plan-sprint/SKILL.md +67 -0
  30. package/_Sprintpilot/skills/sprintpilot-plan-sprint/workflow.md +435 -0
  31. package/_Sprintpilot/skills/sprintpilot-sprint-progress/SKILL.md +53 -0
  32. package/_Sprintpilot/skills/sprintpilot-sprint-progress/workflow.md +169 -0
  33. package/lib/commands/install.js +186 -10
  34. package/package.json +1 -1
@@ -0,0 +1,435 @@
1
+ # Sprintpilot — Sprint Plan Generation
2
+
3
+ ## Purpose
4
+
5
+ Build (or refresh) `_bmad-output/implementation-artifacts/sprint-plan.yaml`
6
+ — the authoritative sprint plan that drives autopilot story selection,
7
+ DAG-aware reordering, and external-tracker integration. Infers per-epic
8
+ + cross-epic dependencies via piped LLM envelopes (validated server-side
9
+ by `infer-dependencies.js`), lets the user curate which stories belong
10
+ in the active plan, and persists everything atomically.
11
+
12
+ ## Prerequisites
13
+
14
+ | Artifact | Path | Required |
15
+ |---|---|---|
16
+ | BMad sprint-status | `_bmad-output/implementation-artifacts/sprint-status.yaml` | yes |
17
+ | BMad epics | `_bmad-output/planning-artifacts/epics.md` | yes |
18
+ | BMad architecture | `_bmad-output/planning-artifacts/architecture.md` | yes |
19
+
20
+ If any required prerequisite is missing, halt with a `user_prompt`
21
+ naming the missing file and the BMad skill that produces it
22
+ (`bmad-sprint-planning`, `bmad-create-epics-and-stories`,
23
+ `bmad-create-architecture`). Do NOT attempt the workflow without them.
24
+
25
+ ## Outputs
26
+
27
+ | File | Location | Purpose |
28
+ |------|----------|---------|
29
+ | `sprint-plan.yaml` | `_bmad-output/implementation-artifacts/` | Authoritative plan (read by autopilot + resolve-dag) |
30
+ | `sprint-plan-dag.mmd` | `_bmad-output/implementation-artifacts/` | Rendered mermaid DAG (refreshed on every plan write) |
31
+ | Archived legacy | `.archive/dependencies.yaml.migrated` | If a pre-v2.3.0 `_Sprintpilot/sprints/dependencies.yaml` existed |
32
+
33
+ ## Conventions used below
34
+
35
+ - `<root>` = the project root passed via `--project-root` (or `cwd`).
36
+ - All scripts live under `_Sprintpilot/scripts/` — invoke via `node <path>`.
37
+ - LLM envelopes are JSON; you produce them, the script validates them.
38
+ - On any 3-iteration validation failure (per-epic OR cross-epic), the
39
+ skill writes `_bmad-output/implementation-artifacts/sprint-plan.yaml.partial`
40
+ with the last attempted envelope + errors header, writes the sentinel
41
+ `.sprint-plan-validation-failed`, and halts with a `user_prompt`
42
+ asking the user to inspect the partial.
43
+
44
+ ---
45
+
46
+ ## Step 1 — Load Inputs
47
+
48
+ <action>Verify the three required artifacts exist:
49
+ - `_bmad-output/implementation-artifacts/sprint-status.yaml`
50
+ - `_bmad-output/planning-artifacts/epics.md`
51
+ - `_bmad-output/planning-artifacts/architecture.md`
52
+
53
+ If any is missing, halt with a `user_prompt` naming what's missing.</action>
54
+
55
+ <action>Read each into memory. Parse epics.md for the list of epic IDs.
56
+ Parse sprint-status.yaml for the list of story keys under
57
+ `development_status:` (or `stories:` for the alternate shape).</action>
58
+
59
+ <action>Read the existing plan if present:
60
+ ```
61
+ node _Sprintpilot/scripts/sprint-plan.js read --project-root <root>
62
+ ```
63
+ Note: `exists: true/false` + the full plan body when present. Used by
64
+ Step 3 to compute staleness and decide which epics need re-inference.</action>
65
+
66
+ ---
67
+
68
+ ## Step 2 — Migrate Legacy Dependencies (One-Shot)
69
+
70
+ <action>Check whether a pre-v2.3.0 sidecar exists at
71
+ `_Sprintpilot/sprints/dependencies.yaml`. If it does AND `sprint-plan.yaml`
72
+ is absent OR has an empty `dependencies.stories` block, run the
73
+ one-shot migration:
74
+ ```
75
+ node _Sprintpilot/scripts/infer-dependencies.js migrate --project-root <root>
76
+ ```
77
+ The migrate command imports the legacy `stories:` + `overrides:` blocks
78
+ into the new plan, drops the legacy `epics:` block with a warning,
79
+ and moves the old file to `.archive/dependencies.yaml.migrated`.
80
+
81
+ If `migrated: false` and `reason: 'no_legacy_file'` — proceed silently.
82
+ If `migrated: false` for any other reason — surface the message in a
83
+ `user_prompt` and ask whether to continue with a fresh plan.</action>
84
+
85
+ ---
86
+
87
+ ## Step 3 — Staleness Check
88
+
89
+ <action>Compute which epics need re-inference. The cheap way is to
90
+ ask the orchestrator helper:
91
+ ```
92
+ node -e "
93
+ const m = require('./_Sprintpilot/lib/orchestrator/sprint-plan.js');
94
+ console.log(JSON.stringify(m.planStaleness({projectRoot: process.cwd()})));
95
+ "
96
+ ```
97
+ Returns `{ stale: bool, reason, missing_keys?, removed_keys? }`.
98
+
99
+ Decision matrix:
100
+
101
+ | stale | reason | action |
102
+ |---|---|---|
103
+ | false | — | Skip Step 4 entirely (plan is fresh). Go to Step 5 unless invoked via /sprintpilot-plan-sprint with a "rebuild from scratch" intent. |
104
+ | true | `missing` | Run Step 4 for EVERY epic in epics.md. |
105
+ | true | `migration_needed` | Step 2 should have handled this — re-check; if still missing, run Step 4 for every epic. |
106
+ | true | `added_stories` | Run Step 4 only for the epics whose stories appear in `missing_keys`. |
107
+ | true | `removed_stories` | Run Step 4 for the epics affected (a missing story means the per-epic graph for that epic is stale). |
108
+ | true | `corrupt` | Halt with a `user_prompt` showing the corruption error + offering archive+regenerate. |
109
+
110
+ For hand-authored plans (no AUTO-INFERRED marker AND user-direct invocation
111
+ of /sprintpilot-plan-sprint without explicit "rebuild" intent), confirm
112
+ with a `user_prompt` before regenerating: "An existing plan has hand
113
+ edits in the `dependencies` block. Proceed with regeneration (loses the
114
+ edits) or skip per-epic inference and just refresh DAG render?"</action>
115
+
116
+ ---
117
+
118
+ ## Step 4 — Per-Epic Inference
119
+
120
+ <action>For each epic that needs (re-)inference, run a tight loop:
121
+
122
+ 1. Generate the prompt:
123
+ ```
124
+ node _Sprintpilot/scripts/infer-dependencies.js scaffold-prompt --epic <id> --project-root <root>
125
+ ```
126
+ Stdout is the literal prompt — feed it back to yourself in chat as
127
+ the "next user message" to infer the dependencies. Read the four
128
+ files the prompt names; do not improvise based on memory.
129
+
130
+ 2. Produce a JSON envelope of the EXACT shape:
131
+ ```json
132
+ {
133
+ "version": 1,
134
+ "epic": "<id>",
135
+ "dependencies": { "<story-key>": ["<dep-key>", ...] },
136
+ "rationale": { "<story-key>": "1 sentence quoting the AC/file/architecture line" }
137
+ }
138
+ ```
139
+ Stories with NO inbound deps are omitted from `dependencies`. Every
140
+ listed key needs a non-empty rationale. Cross-epic edges go through
141
+ Step 5 — don't put them here.
142
+
143
+ 3. Validate via dry-run:
144
+ ```
145
+ echo '<envelope>' | node _Sprintpilot/scripts/infer-dependencies.js dry-run --epic <id> --project-root <root>
146
+ ```
147
+ On `valid: true`, proceed. On `valid: false`, the response carries
148
+ an `errors[]` array — fix the envelope and retry. Max 3 iterations
149
+ per epic. On 3rd failure, save the partial + sentinel and halt
150
+ (see "Conventions" above).
151
+
152
+ 4. Commit the envelope:
153
+ ```
154
+ echo '<envelope>' | node _Sprintpilot/scripts/infer-dependencies.js write --epic <id> --project-root <root>
155
+ ```
156
+ `wrote: true, edges_inferred, edges_added, edges_removed` confirms
157
+ success. The script writes into `plan.dependencies.stories.*` while
158
+ preserving entries for other epics and the `overrides:` block.</action>
159
+
160
+ ---
161
+
162
+ ## Step 5 — Cross-Epic Detection
163
+
164
+ <action>Now that per-epic edges are in place, ask the LLM whether
165
+ any edges cross epic boundaries:
166
+
167
+ 1. Generate the cross-epic prompt:
168
+ ```
169
+ node _Sprintpilot/scripts/infer-dependencies.js scaffold-prompt --cross-epic --project-root <root>
170
+ ```
171
+
172
+ 2. Produce a JSON envelope:
173
+ ```json
174
+ {
175
+ "version": 1,
176
+ "cross_epic_deps": [
177
+ { "from_story": "<key>", "to_story": "<key>", "rationale": "<≤200 chars>" }
178
+ ]
179
+ }
180
+ ```
181
+ `from_story` depends on `to_story`. Both keys must belong to
182
+ DIFFERENT epics. If no cross-epic deps detected, send
183
+ `cross_epic_deps: []`.
184
+
185
+ 3. Validate via dry-run:
186
+ ```
187
+ echo '<envelope>' | node _Sprintpilot/scripts/infer-dependencies.js dry-run --cross-epic --project-root <root>
188
+ ```
189
+ Validator checks: keys exist in sprint-status, from/to epics differ,
190
+ rationale present (≤200 chars), no duplicate of per-epic edges,
191
+ no cycle in the combined graph. Max 3 iterations.
192
+
193
+ 4. Present each surviving edge to the user with its rationale:
194
+ ```
195
+ Cross-epic edge detected:
196
+ 2-1-foo depends on 1-3-add-auth
197
+ Rationale: needs auth context from 1-3 before integration
198
+ [a] accept [r] reject [s] skip remaining edges
199
+ ```
200
+ Accept-all, reject-all, or per-edge. Rejected edges drop out;
201
+ accepted edges go through to write.
202
+
203
+ 5. Commit accepted edges:
204
+ ```
205
+ echo '<accepted envelope>' | node _Sprintpilot/scripts/infer-dependencies.js write-cross-epic --project-root <root>
206
+ ```</action>
207
+
208
+ ---
209
+
210
+ ## Step 6 — Issue Tracker Setup (Optional)
211
+
212
+ <action>Ask the user (single user_prompt):
213
+ > "Do you want to link stories to an external issue tracker
214
+ > (Jira / Linear / GitHub / GitLab)? [y/N]"
215
+
216
+ On `n` or skip — proceed to Step 7 without writing the `issue_tracker:`
217
+ block.
218
+
219
+ On `y` — collect:
220
+ - `provider`: one of `jira`, `linear`, `github`, `gitlab`
221
+ - `base_url`: full URL prefix (e.g., `https://co.atlassian.net`)
222
+ - `project_key`: the tracker's project key (e.g., `PROJ` for Jira)
223
+
224
+ Then call the sprint-plan primitive. Currently the simplest path is
225
+ to read the plan, set `plan.issue_tracker = { provider, base_url, project_key }`,
226
+ and write the whole plan back via `node _Sprintpilot/scripts/sprint-plan.js write`
227
+ (piping the modified plan to stdin). The script validates schema and writes
228
+ atomically.</action>
229
+
230
+ ---
231
+
232
+ ## Step 7 — Issue ID Capture (Optional)
233
+
234
+ <action>Ask the user (single user_prompt):
235
+ > "Capture external issue IDs for each epic/story? [Y]es / [n]o
236
+ > / [s]kip remaining for this epic / [p]attern (sequential IDs)"
237
+
238
+ On `n` — proceed to Step 8 without setting any `issue_id` fields.
239
+
240
+ On `Y` — loop through epics and stories. For each entity:
241
+ > "Issue ID for epic 1 (or skip)?"
242
+ > "Issue ID for story 1-3-add-auth (or skip)?"
243
+
244
+ `p` mode prompts once for a prefix (e.g., `PROJ-`) + starting number;
245
+ the skill assigns sequential IDs (`PROJ-100`, `PROJ-101`, …).
246
+
247
+ **Validation rules** — `setIssueId` rejects these inputs (re-prompt if
248
+ they appear; don't retry the same value):
249
+ - Any of: `[ ] < > | ; & \n \r` or ASCII control characters
250
+ - Any Unicode RTL/LTR override marks (`‪`–`‮`, `⁦`–`⁩`)
251
+ - Length > 200 chars
252
+
253
+ Legitimate tracker IDs from Jira (`PROJ-101`), Linear (`LIN-42`),
254
+ GitHub (`org/repo#123`), and GitLab don't contain any of these. If a
255
+ user enters something like `PROJ;101` or pastes a URL with embedded
256
+ brackets, the validator throws — show the error and ask for a clean
257
+ ID. Don't loop on the same broken input.
258
+
259
+ For each captured ID, update the plan via read → mutate → write. The
260
+ relevant primitive is `setIssueId(entity_key, issue_id, { projectRoot })`
261
+ in `sprint-plan.js`; from this skill the simplest path is to bulk-edit
262
+ the plan in memory and write it once at the end of the loop.
263
+
264
+ Bulk skip options ensure this step doesn't become tedious on sprints
265
+ with many stories.</action>
266
+
267
+ ---
268
+
269
+ ## Step 8 — Finalize Dependencies in Plan
270
+
271
+ <action>By this point Steps 4 + 5 have written `plan.dependencies.stories`
272
+ and `plan.cross_epic_deps`. Step 6/7 may have edited `issue_tracker`
273
+ and per-entity `issue_id`. Re-read the plan once to confirm:
274
+ ```
275
+ node _Sprintpilot/scripts/sprint-plan.js read --project-root <root>
276
+ ```
277
+ The plan should validate cleanly. If `exists: true, error: ...` →
278
+ something went wrong; halt with the error.</action>
279
+
280
+ ---
281
+
282
+ ## Step 9 — Build the Sprint-Wide DAG
283
+
284
+ <action>Compute the topological layering for presentation:
285
+ ```
286
+ node _Sprintpilot/scripts/resolve-dag.js graph --project-root <root>
287
+ ```
288
+ Returns `{ nodes, edges, layers, width, cycle }`. If `cycle.length > 0`,
289
+ the combined intra + cross-epic graph has a cycle (validator should
290
+ have caught this earlier; if reached, halt with the offending nodes
291
+ and ask the user to remove the bad edge).</action>
292
+
293
+ ---
294
+
295
+ ## Step 10 — Present the DAG
296
+
297
+ <action>Render a text-mode topological tree to the user:
298
+ ```
299
+ Layer 1 (parallel-eligible width: <N>):
300
+ - 1-1-bootstrap
301
+ - 2-1-foo ← cross-epic upstream of 1-3
302
+ Layer 2:
303
+ - 1-2-models
304
+ Layer 3:
305
+ - 1-3-add-auth (depends on: 1-1, 1-2, 2-1)
306
+ ...
307
+ ```
308
+
309
+ Highlight cross-epic edges with `←` or `cross-epic →` annotations.
310
+ Show summary stats: total stories, total epics, max layer width
311
+ (indicates parallel potential for v2.4.0), count of missing issue IDs.</action>
312
+
313
+ <action>Also write the mermaid DAG file for visual review:
314
+ ```
315
+ node _Sprintpilot/scripts/resolve-dag.js render --format mermaid --project-root <root>
316
+ ```
317
+ Report the path to the user:
318
+ > "DAG rendered to `_bmad-output/implementation-artifacts/sprint-plan-dag.mmd`
319
+ > — preview in any markdown viewer (GitHub, VS Code with Mermaid Preview, etc.)."</action>
320
+
321
+ ---
322
+
323
+ ## Step 11 — Curation
324
+
325
+ <action>Ask the user which stories belong in this sprint plan:
326
+ > "Which stories do you want to run in this sprint?
327
+ > Default: ALL non-done stories.
328
+ > [Enter] accept default [e] edit selection [a:KEY] add [r:KEY] remove"
329
+
330
+ `Default: ALL non-done` means every story in sprint-status whose
331
+ status is not `done`. Excluded stories carry `plan_status: excluded`
332
+ in the plan — they remain visible in the file for context (e.g., as
333
+ upstreams of included stories) but are NOT picked by the queue resolver.</action>
334
+
335
+ <action>On `e` (edit), present a numbered list with `[x]` for included
336
+ and `[ ]` for excluded; the user toggles entries by number.</action>
337
+
338
+ ---
339
+
340
+ ## Step 12 — Validate Selection
341
+
342
+ <action>For each story marked included, every transitive upstream
343
+ (intra-epic AND cross-epic) must be either ALSO included OR already
344
+ done in sprint-status. Compute via the orchestrator helper:
345
+ ```
346
+ node -e "
347
+ const m = require('./_Sprintpilot/lib/orchestrator/sprint-plan.js');
348
+ const plan = require('./_Sprintpilot/scripts/sprint-plan.js').read({projectRoot: process.cwd()});
349
+ const proposed = [/* user-selected keys */];
350
+ console.log(JSON.stringify(m.validateOrdering(proposed, plan, {projectRoot: process.cwd()})));
351
+ "
352
+ ```
353
+ Returns `{ valid, violations: [{story, upstream, suggestion}] }`.
354
+
355
+ On `valid: false`, present each violation:
356
+ > "Story `1-3-add-auth` (included) depends on `1-1-bootstrap` which is
357
+ > not in the plan and not done. Options:
358
+ > [a] add `1-1-bootstrap` to the plan
359
+ > [r] remove `1-3-add-auth` from the plan
360
+ > [x] exclude `1-3-add-auth` (keeps it visible but won't run)"
361
+
362
+ Loop until `valid: true`. Excluded stories carry `plan_status: excluded`
363
+ and the validator treats them as terminal.</action>
364
+
365
+ ---
366
+
367
+ ## Step 13 — Write Plan
368
+
369
+ <action>Build the final plan object in memory:
370
+ - `schema_version: 1`
371
+ - `source: 'skill' | 'auto' | 'cli'` (use `auto` when invoked via
372
+ `template_slots.auto: true`, `skill` otherwise)
373
+ - `plan_id`: keep existing if re-running; generate fresh on first
374
+ curation
375
+ - `epics: []` — per-epic metadata captured in Step 1 (id, title)
376
+ - `stories: []` — per-story entries with `key`, `epic`, `title`,
377
+ `plan_status` (`pending` for included, `excluded` for excluded),
378
+ `issue_id` (from Step 7), `priority` (1-indexed in topological order),
379
+ `upstream` (denormalized from `plan.dependencies.stories.<key>.depends_on`),
380
+ `cross_epic_upstream` (denormalized from `plan.cross_epic_deps`),
381
+ `added_by: 'skill'`, `added_at`
382
+ - `dependencies`, `cross_epic_deps`, `overrides`, `notes` — preserved
383
+ from Steps 4-7
384
+ - `status.last_run_outcome: 'success'`, `status.last_run_at: <now>`,
385
+ `status.last_error: null`
386
+
387
+ Pipe to write:
388
+ ```
389
+ echo '<plan-json>' | node _Sprintpilot/scripts/sprint-plan.js write --project-root <root>
390
+ ```
391
+ The script validates schema, stamps `generated`, and atomically writes
392
+ via tmp+rename.</action>
393
+
394
+ <action>Re-render the DAG to reflect any curation changes:
395
+ ```
396
+ node _Sprintpilot/scripts/resolve-dag.js render --format mermaid --project-root <root>
397
+ ```</action>
398
+
399
+ ---
400
+
401
+ ## Step 14 — Report
402
+
403
+ <action>Summarize what was written:
404
+ > "Sprint plan written to
405
+ > `_bmad-output/implementation-artifacts/sprint-plan.yaml`.
406
+ >
407
+ > - **N** stories planned (M epics)
408
+ > - **X** cross-epic edges
409
+ > - **Y** stories excluded (kept for context)
410
+ > - **Z** stories without issue IDs
411
+ >
412
+ > First 5 in execution order:
413
+ > 1. 1-1-bootstrap
414
+ > 2. 1-2-models
415
+ > 3. ...
416
+ >
417
+ > Run `/sprint-autopilot-on` to begin execution, or
418
+ > `/sprintpilot-plan-sprint` again to refine."</action>
419
+
420
+ <action>If invoked via `template_slots.auto: true` or `replan: true`,
421
+ keep the summary shorter (1-2 sentences) and return cleanly so the
422
+ autopilot session resumes; do not block on confirmation.</action>
423
+
424
+ ---
425
+
426
+ ## Failure modes
427
+
428
+ | Symptom | Recovery |
429
+ |---|---|
430
+ | Prerequisite artifact missing | Halt with `user_prompt` naming the missing file + the BMad skill that produces it. |
431
+ | 3 consecutive validation failures (per-epic OR cross-epic) | Save `sprint-plan.yaml.partial` + `.sprint-plan-validation-failed` sentinel; halt asking the user to inspect. |
432
+ | Cycle in combined intra+cross graph | Halt with the offending nodes; ask the user to remove or re-rationalize the bad edge. |
433
+ | Plan write fails (disk full, permission) | The atomic tmp+rename is all-or-nothing — no torn state. Halt with the error message. |
434
+ | `sprint-plan.yaml` corrupt on entry to Step 3 | Offer archive+regenerate via `user_prompt`. |
435
+ | Skill invoked but `sprint-status.yaml` is empty | No stories to plan; halt and ask the user to run `bmad-sprint-planning` first. |
@@ -0,0 +1,53 @@
1
+ ---
2
+ name: sprintpilot-sprint-progress
3
+ description: 'Synthesize current sprint execution progress with LLM-layered judgment. Reads sprint-plan.yaml, sprint-status.yaml, and the autopilot ledger via `autopilot progress`; highlights stalls, repeated verify failures, retry loops, and stuck phases; suggests the next action (continue, narrow to a specific story, reorder, replan, abort). Use when you want a quick health check between autopilot sessions without scrolling through the raw ledger.'
4
+ ---
5
+
6
+ ## STOP — read this entire file before doing anything
7
+
8
+ This skill is a **read-only diagnostic**. It does not change sprint-plan.yaml,
9
+ sprint-status.yaml, or any persisted autopilot state. The goal is to produce
10
+ a concise human-readable summary of where execution stands and what (if
11
+ anything) the user should do about it.
12
+
13
+ Follow **`./workflow.md`** verbatim. The three steps it lists are:
14
+
15
+ 1. Collect the structured snapshot via `autopilot progress --json`.
16
+ 2. Pull recent ledger entries for halt / verify / step context.
17
+ 3. Synthesize a brief progress report with LLM judgment + one
18
+ recommended next action.
19
+
20
+ ### Never improvise
21
+
22
+ - **No file writes.** This skill is observational. If the user wants to
23
+ reorder, add stories, mark something skipped, or replan — point them
24
+ at the appropriate user_input command or `/sprintpilot-plan-sprint`.
25
+ Don't try to fix things from this skill.
26
+ - **No state interpretation beyond what's in the ledger.** Don't
27
+ speculate about why a verify failed — just report what the ledger
28
+ says and recommend the user look at the relevant file.
29
+ - **No long-form output by default.** Default mode is ≤15 lines. If
30
+ the user asks for more detail, narrow to a story and read its
31
+ recent step events.
32
+
33
+ ### When to invoke
34
+
35
+ - Between autopilot sessions to check whether anything halted that
36
+ needs intervention.
37
+ - When you (the LLM) just finished a long batch of stories and want
38
+ to know if anything's stuck before suggesting next moves.
39
+ - When the user asks "how's the sprint going?" / "where are we?" /
40
+ "is autopilot stuck?".
41
+
42
+ ### When NOT to invoke
43
+
44
+ - For machine-readable output: call
45
+ `node _Sprintpilot/bin/autopilot.js progress --json` directly. This
46
+ skill adds LLM synthesis on top — pure JSON consumers don't need it.
47
+ - For full sprint reports: that's `bmad-sprint-status` (BMad-native,
48
+ reads sprint-status.yaml only).
49
+ - For build / deploy / CI status: not this skill's domain.
50
+
51
+ ---
52
+
53
+ Follow the instructions in ./workflow.md.
@@ -0,0 +1,169 @@
1
+ # Sprintpilot — Sprint Progress Check
2
+
3
+ ## Purpose
4
+
5
+ Produce a concise health check of the current sprint's autopilot
6
+ execution. Reads the structured progress snapshot, recent halts /
7
+ verify failures, and step-level events; layers brief judgment on top
8
+ to highlight what (if anything) needs attention.
9
+
10
+ ## Outputs
11
+
12
+ - A ≤15-line human-readable summary printed to chat.
13
+ - A single recommended next action (or "nothing to do — autopilot is
14
+ healthy / idle").
15
+
16
+ No file writes. No state mutations.
17
+
18
+ ## Conventions
19
+
20
+ - `<root>` = project root (where `_bmad-output/` lives).
21
+ - All shell-outs use `node` (no global install assumed).
22
+ - On any error (no plan, missing ledger, etc.), degrade gracefully —
23
+ print what you DO know and skip the parts you don't. The user gets
24
+ a partial answer rather than a halt.
25
+
26
+ ---
27
+
28
+ ## Step 1 — Collect the Structured Snapshot
29
+
30
+ <action>Run the progress CLI in JSON mode:
31
+ ```
32
+ node _Sprintpilot/bin/autopilot.js progress --project-root <root> --json
33
+ ```
34
+ Parse the response. Key fields:
35
+ - `plan_present` — false → project running in sprint-status order; the
36
+ rest of the analysis is naturally lighter.
37
+ - `plan_id`
38
+ - `current_story` / `current_step`
39
+ - `sprint_progress` — `{ total, done, pending, skipped, excluded, source }`
40
+ - `recent_events` — last 3 `story_step_*` ledger entries.
41
+
42
+ Don't fail if the command exits non-zero (e.g., missing project root).
43
+ Capture stderr and treat as "unknown progress" — proceed with Step 2
44
+ which still produces useful output.</action>
45
+
46
+ ---
47
+
48
+ ## Step 2 — Pull Recent Halt / Verify Context
49
+
50
+ <action>Read the tail of the ledger to identify any unresolved
51
+ halts, verify rejections, or repeated step-failure loops. Inline node
52
+ is the lightest path:
53
+
54
+ ```
55
+ node -e "
56
+ const l = require('./_Sprintpilot/lib/orchestrator/action-ledger.js');
57
+ const entries = l.read({projectRoot: process.cwd()}, {limit: 40});
58
+ const interesting = entries.filter(e =>
59
+ e.kind === 'halt' ||
60
+ e.kind === 'verify_rejected' ||
61
+ e.kind === 'plan_exhausted' ||
62
+ e.kind === 'plan_reorder_rejected' ||
63
+ e.kind === 'auto_derive_emitted' ||
64
+ e.kind === 'plan_migrated'
65
+ );
66
+ process.stdout.write(JSON.stringify(interesting));
67
+ "
68
+ ```
69
+
70
+ Look for:
71
+ - **`halt` with reason in {`autopilot_lock_held`, `worktree_orphans_detected`,
72
+ `plan_exhausted`, `user_pause`, `user_replan_sprint`, `user_abort_sprint`}**
73
+ — autopilot is stopped and needs user attention.
74
+ - **`verify_rejected` with `consecutive >= 3`** — autopilot is stuck in
75
+ a retry loop; the LLM may need to re-read the failing artifact.
76
+ - **`plan_reorder_rejected`** — a recent reorder violated the DAG;
77
+ the user has unresolved input pending.
78
+ - **Repeated `story_step_started` for the same story+phase without
79
+ matching `story_step_completed`** — phase entered but never finished;
80
+ could indicate a wedged session.
81
+
82
+ Don't fail if the ledger is empty (greenfield project, never run).
83
+ Just note "no execution history yet" and proceed.</action>
84
+
85
+ ---
86
+
87
+ ## Step 3 — Synthesize the Report
88
+
89
+ <action>Render a single brief block to chat following this template
90
+ (omit any line that doesn't apply):
91
+
92
+ ```
93
+ Sprint progress
94
+ Plan: <plan_id> — <done>/<total> done (<pending> pending,
95
+ <skipped> skipped, <excluded> excluded)
96
+ Bar: [===== ] <pct>%
97
+ Tracker: <linked>/<total> stories linked to <provider> (<project_key>) ← only when issue_tracker set
98
+ Current: <story_key> [<issue_id>] (step: <phase>) OR "idle"
99
+ ↑ issue_id bracket only when set on this story
100
+ Recent: <kind> <story> [<issue_id>] / <phase> (<elapsed>s ago)
101
+ <kind> <story> [<issue_id>] / <phase> (<elapsed>s ago)
102
+
103
+ Health: <one of: HEALTHY | STALLED | NEEDS-INPUT | EXHAUSTED | NO-PLAN>
104
+ Reason: <one short sentence>
105
+ Suggest: <one concrete next action OR "continue running">
106
+ ```
107
+
108
+ The `autopilot progress --json` response carries the lookup data:
109
+ - `current_issue_id` — the issue_id of the currently-running story (or null).
110
+ - `issue_tracking` — `{provider, project_key, base_url, total, linked, coverage}`
111
+ when an issue_tracker is configured; null otherwise (omit the Tracker
112
+ line entirely when null — don't surface zeros as noise).
113
+ - Each `recent_events[]` entry carries an `issue_id` field (or null).
114
+
115
+ Always include the `[<issue_id>]` bracket when the field is non-null;
116
+ omit it when null. Don't write "[no issue]" or similar — silence
117
+ communicates "not tracked" cleanly.
118
+
119
+ **Health classification:**
120
+
121
+ | Signal | Health | Suggest |
122
+ |---|---|---|
123
+ | `plan_present=false` AND no halts in last 40 | NO-PLAN | "Continue in sprint-status order, or run /sprintpilot-plan-sprint to enable dependency-aware ordering." |
124
+ | Most-recent halt is `plan_exhausted` | EXHAUSTED | "Run /sprintpilot-plan-sprint to add more stories, or `autopilot start --no-auto-plan` to continue in sprint-status order." |
125
+ | Most-recent halt is `user_pause` | NEEDS-INPUT | "Resume with `autopilot start`." |
126
+ | Most-recent halt is `user_replan_sprint` | NEEDS-INPUT | "Next `autopilot start` will invoke /sprintpilot-plan-sprint." |
127
+ | `verify_rejected` with `consecutive >= 3` in last 5 entries | STALLED | "Inspect the failing artifact named in `verify_result.issues`; consider `user_input { kind: 'force_continue' }` only if you've manually resolved the issue." |
128
+ | `plan_reorder_rejected` more recent than any subsequent reorder_queue | NEEDS-INPUT | "Reorder violations exist; revise the order to respect the DAG before sending another reorder_queue." |
129
+ | No halts, current_story present, current_step is a valid phase | HEALTHY | "Continue running; nothing requires attention." |
130
+ | No halts, no current_story, sprint_progress.pending > 0 | HEALTHY | "Run `autopilot start` to pick up the next pending story." |
131
+ | No halts, no current_story, sprint_progress.pending == 0 | HEALTHY | "Sprint complete; consider running the bmad-retrospective skill if not already done." |
132
+
133
+ Default to HEALTHY when classification is ambiguous — don't manufacture
134
+ alarm.</action>
135
+
136
+ <action>If the user invoked the skill with a story name argument
137
+ (e.g., `/sprintpilot-sprint-progress 1-3-add-auth`), also call:
138
+ ```
139
+ node _Sprintpilot/bin/autopilot.js progress --project-root <root> --story <story-key> --json
140
+ ```
141
+ And append a one-block "Story detail" section showing that story's
142
+ plan entry. When `issue_id` is non-null, prominently display it on its
143
+ own line (it's the primary cross-reference back to the user's issue
144
+ tracker):
145
+
146
+ ```
147
+ Story: <story_key>
148
+ Issue: <issue_id> ← omit line when null
149
+ Epic: <epic>
150
+ Plan status: <plan_status>
151
+ BMad status: <bmad_status>
152
+ Priority: <priority>
153
+ Current step: <current_step> ← omit when not running
154
+ Completed: <completed_at> ← omit when not done
155
+ ```
156
+
157
+ Do not repeat the full sprint summary in this mode — just the focused
158
+ story block.</action>
159
+
160
+ ---
161
+
162
+ ## Failure modes
163
+
164
+ | Symptom | Recovery |
165
+ |---|---|
166
+ | `autopilot progress` exits non-zero (missing project root, etc.) | Capture stderr; print "Progress CLI unavailable: <stderr first line>"; still attempt Step 2. |
167
+ | Ledger file missing | Print "No execution history yet — sprint hasn't started"; skip Step 2 analysis; suggest `autopilot start`. |
168
+ | Plan file corrupt | Print "sprint-plan.yaml unreadable (run `node _Sprintpilot/scripts/sprint-plan.js read --project-root .` to inspect)"; do NOT auto-archive — that's user's call. |
169
+ | Recent ledger has 0 entries | Note "Ledger is empty — autopilot hasn't run yet or was reset"; skip halt analysis. |