@ikunin/sprintpilot 1.0.3 → 1.0.5
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/_Sprintpilot/Sprintpilot.md +17 -1
- package/_Sprintpilot/manifest.yaml +1 -1
- package/_Sprintpilot/modules/autopilot/config.yaml +18 -0
- package/_Sprintpilot/skills/sprint-autopilot-on/workflow.md +166 -426
- package/_Sprintpilot/skills/sprintpilot-update/workflow.md +2 -1
- package/_Sprintpilot/templates/epic-retrospective.md +24 -0
- package/_Sprintpilot/templates/sprint-report.txt +60 -0
- package/lib/commands/install.js +247 -3
- package/lib/prompts.js +22 -0
- package/lib/substitute.js +1 -1
- package/package.json +4 -1
|
@@ -8,23 +8,19 @@ You do NOT hardcode the workflow sequence. After each completed skill, read its
|
|
|
8
8
|
|
|
9
9
|
**Git integration** is additive. If `_Sprintpilot/manifest.yaml` doesn't exist or `git.enabled: false`, all git operations are silently skipped and this workflow behaves identically to the stock autopilot.
|
|
10
10
|
|
|
11
|
-
### Shell portability
|
|
11
|
+
### Shell portability
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
The executing shell may be bash, zsh, PowerShell, or cmd — translate bash idioms as needed:
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
| Bash | PowerShell |
|
|
16
|
+
|---|---|
|
|
17
|
+
| `A && B` | `A; if ($LASTEXITCODE -eq 0) { B }` |
|
|
18
|
+
| `A \|\| true` | `A; $LASTEXITCODE = 0` |
|
|
19
|
+
| `2>/dev/null` | `2>$null` |
|
|
20
|
+
| `rm -rf <dir>` | `Remove-Item -Recurse -Force <dir>` |
|
|
21
|
+
| `if [ -f X ]; then ... fi` | `if (Test-Path -PathType Leaf X) { ... }` |
|
|
16
22
|
|
|
17
|
-
|
|
18
|
-
|---|---|---|
|
|
19
|
-
| `A && B` | `A; if ($LASTEXITCODE -eq 0) { B }` (or separate commands, guarding B manually) | Run B only if A succeeded |
|
|
20
|
-
| `A \|\| true` | `A; $LASTEXITCODE = 0` (or `try { A } catch {}` for cmdlets) | Run A, ignore failures |
|
|
21
|
-
| `2>/dev/null` | `2>$null` | Suppress stderr |
|
|
22
|
-
| `rm -rf <dir>` | `Remove-Item -Recurse -Force <dir>` | Recursive delete |
|
|
23
|
-
| `if [ -f X ]; then ... fi` | `if (Test-Path -PathType Leaf X) { ... }` | File-exists check (regular file, not dir) |
|
|
24
|
-
|
|
25
|
-
**Safer:** when in doubt, use the cross-platform Node helpers under `_Sprintpilot/scripts/`. For ad-hoc file ops, invoke Node inline: `node -e "require('fs').rmSync('<path>', {recursive: true, force: true})"`.
|
|
26
|
-
|
|
27
|
-
If a step below uses `&&` to chain "run B only on A's success", and you cannot express that in one line, **run the commands separately and STOP if any step fails** — do not proceed past a failed step.
|
|
23
|
+
For cross-platform file ops prefer the Node helpers under `_Sprintpilot/scripts/`, or inline: `node -e "require('fs').rmSync('<path>', {recursive: true, force: true})"`. When a step chains commands with `&&` and you cannot express it in one line, run them separately and STOP on any failure.
|
|
28
24
|
|
|
29
25
|
---
|
|
30
26
|
|
|
@@ -75,55 +71,20 @@ For everything else: decide, document briefly, continue.
|
|
|
75
71
|
|
|
76
72
|
## DECISION LOGGING
|
|
77
73
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
### When to log
|
|
81
|
-
|
|
82
|
-
Log a decision whenever you:
|
|
83
|
-
- Choose an architecture pattern, data structure, or design approach (`architecture`)
|
|
84
|
-
- Select a test strategy or skip a test category (`test-strategy`)
|
|
85
|
-
- Add, remove, or substitute a dependency (`dependency`)
|
|
86
|
-
- Dismiss a code review finding (`review-triage`)
|
|
87
|
-
- Accept and apply a code review finding (`review-accept`)
|
|
88
|
-
- Recover from a HALT condition (`halt-recovery`)
|
|
89
|
-
- Implement something not explicitly in the story spec (`scope`)
|
|
90
|
-
- Apply a workaround for a tool limitation or false positive (`workaround`)
|
|
74
|
+
Log every non-trivial decision to `{decision_log_file}` (skip routine actions — running tests, staging files, creating branches). Create the file on first decision; update `last_updated` on every append.
|
|
91
75
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
Initialize `{decision_log_file}` on first decision (if it does not exist):
|
|
76
|
+
**Categories:** `architecture`, `test-strategy`, `dependency`, `review-triage` (dismissed finding), `review-accept` (applied fix), `halt-recovery`, `scope` (outside story spec), `workaround`.
|
|
77
|
+
**Impact:** `low` (reversible/cosmetic), `medium` (affects one component), `high` (cross-cutting or deviates from spec).
|
|
78
|
+
**Phase format:** `{skill}:{sub_phase}` — e.g. `dev-story:RED`, `code-review:triage`, `autopilot:routing`.
|
|
97
79
|
|
|
80
|
+
**File schema:**
|
|
98
81
|
```yaml
|
|
99
|
-
generated: {
|
|
100
|
-
last_updated: {
|
|
101
|
-
|
|
102
|
-
|
|
82
|
+
generated: {date}
|
|
83
|
+
last_updated: {datetime}
|
|
84
|
+
decisions:
|
|
85
|
+
- { id, timestamp, story, phase, category, decision, rationale, impact }
|
|
103
86
|
```
|
|
104
87
|
|
|
105
|
-
Append each decision as a new entry:
|
|
106
|
-
|
|
107
|
-
```yaml
|
|
108
|
-
- id: {auto_increment}
|
|
109
|
-
timestamp: "{current_datetime_iso8601}"
|
|
110
|
-
story: "{current_story or sprint-level}"
|
|
111
|
-
phase: "{skill}:{sub_phase}"
|
|
112
|
-
category: {architecture|test-strategy|dependency|review-triage|review-accept|halt-recovery|scope|workaround}
|
|
113
|
-
decision: "{what was decided — one line}"
|
|
114
|
-
rationale: "{why — one line}"
|
|
115
|
-
impact: {low|medium|high}
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
**Phase format:** `dev-story:RED`, `dev-story:GREEN`, `code-review:triage`, `code-review:patch`, `autopilot:init`, `autopilot:routing`, etc.
|
|
119
|
-
|
|
120
|
-
**Impact levels:**
|
|
121
|
-
- `low` — easily reversible, cosmetic, or standard practice
|
|
122
|
-
- `medium` — affects behavior but contained to one story/component
|
|
123
|
-
- `high` — cross-cutting, hard to reverse, or deviates from spec
|
|
124
|
-
|
|
125
|
-
Always update `last_updated` when appending.
|
|
126
|
-
|
|
127
88
|
---
|
|
128
89
|
|
|
129
90
|
## SKILL AUTOMATABLE REFERENCE
|
|
@@ -138,6 +99,7 @@ All BMAD skills are fully automatable (auto-continue past menus, derive decision
|
|
|
138
99
|
| `bmad-create-ux-design` | Automatable if PRD exists; BLOCKER if no PRD |
|
|
139
100
|
| `bmad-party-mode` | Skip — inherently interactive |
|
|
140
101
|
| `bmad-brainstorming` | Skip — inherently interactive |
|
|
102
|
+
| `bmad-retrospective` | Under autopilot, handled per `autopilot.retrospective_mode`: `auto` (default — inline artifact, no external skill call), `stop` (pause so user runs `/bmad-retrospective` interactively, then resumes autopilot), or `skip` (not recommended). The external skill is NOT invoked from autopilot because it enters a multi-persona discussion loop under some CLIs. |
|
|
141
103
|
|
|
142
104
|
---
|
|
143
105
|
|
|
@@ -155,6 +117,8 @@ Resolve:
|
|
|
155
117
|
- `project_root` = absolute path of current working directory (store for later use)
|
|
156
118
|
- `session_story_limit` is loaded below from `modules/autopilot/config.yaml` (default: 3)
|
|
157
119
|
|
|
120
|
+
**`{state_file}` schema** (referenced as `STATE_FIELDS` below): `last_updated`, `current_story`, `current_bmad_step`, `completed_skill`, `next_skill`, `session_stories_done`, `stories_remaining`, `git_enabled`, `platform`, `in_worktree`, `pr_base`. Always update `last_updated` on every write.
|
|
121
|
+
|
|
158
122
|
### Git integration bootstrap
|
|
159
123
|
|
|
160
124
|
<action>Check if `{project-root}/_Sprintpilot/manifest.yaml` exists</action>
|
|
@@ -173,13 +137,15 @@ Resolve:
|
|
|
173
137
|
</action>
|
|
174
138
|
<action>Read `{project-root}/_Sprintpilot/modules/autopilot/config.yaml` (if present) and set:
|
|
175
139
|
- `{{session_story_limit}}` from `autopilot.session_story_limit` (default: 3). A value of 0 disables the limit (run until sprint complete).
|
|
176
|
-
|
|
140
|
+
- `{{retrospective_mode}}` from `autopilot.retrospective_mode` (default: `auto`). Valid values: `auto` | `stop` | `skip`. Any unknown value falls back to `auto`.
|
|
141
|
+
If the file or either key is missing, fall back to the defaults above.
|
|
177
142
|
</action>
|
|
178
143
|
</check>
|
|
179
144
|
|
|
180
145
|
<check if="manifest does NOT exist">
|
|
181
146
|
<action>Set `{{git_enabled}}` = false</action>
|
|
182
147
|
<action>Set `{{session_story_limit}}` = 3</action>
|
|
148
|
+
<action>Set `{{retrospective_mode}}` = `auto`</action>
|
|
183
149
|
<action>Log: "No _Sprintpilot/manifest.yaml found — running stock autopilot (no git)"</action>
|
|
184
150
|
</check>
|
|
185
151
|
|
|
@@ -197,6 +163,17 @@ Resolve:
|
|
|
197
163
|
<action>STOP</action>
|
|
198
164
|
</check>
|
|
199
165
|
|
|
166
|
+
<action>**Check for `origin` remote** — run: `git remote get-url origin`
|
|
167
|
+
If the command fails (exit code != 0), no `origin` remote is configured. Set `{{has_origin}}` = false.
|
|
168
|
+
Otherwise set `{{has_origin}}` = true.
|
|
169
|
+
</action>
|
|
170
|
+
<check if="{{has_origin}} is false">
|
|
171
|
+
<action>Log: "WARN: no `origin` remote configured — running in local-only mode. Remote operations (fetch, push, PR, branch reconciliation) will be skipped. Add a remote later with: `git remote add origin <url>`"</action>
|
|
172
|
+
<action>Set `{{push_auto}}` = false</action>
|
|
173
|
+
<action>Set `{{create_pr}}` = false</action>
|
|
174
|
+
<action>Set `{{platform}}` = "git_only"</action>
|
|
175
|
+
</check>
|
|
176
|
+
|
|
200
177
|
<action>**Lock file** — run: `node {{project_root}}/_Sprintpilot/scripts/lock.js acquire`
|
|
201
178
|
Output will be one of:
|
|
202
179
|
- `ACQUIRED:<session-id>` → proceed
|
|
@@ -232,7 +209,8 @@ Resolve:
|
|
|
232
209
|
</action>
|
|
233
210
|
|
|
234
211
|
<action>**Branch reconciliation** — detect pushed-but-unmerged story branches.
|
|
235
|
-
|
|
212
|
+
Skip this entire section if `{{has_origin}}` is false (no remote → nothing to reconcile).
|
|
213
|
+
Run as separate commands — **if `git fetch origin` fails (no remote/network/auth), STOP branch reconciliation and log a warning; do not operate on stale local refs**:
|
|
236
214
|
1. `git fetch origin`
|
|
237
215
|
2. `git branch -r --list "origin/{{branch_prefix}}*"`
|
|
238
216
|
For each remote branch:
|
|
@@ -315,26 +293,27 @@ Resolve:
|
|
|
315
293
|
- Advance to next non-done story
|
|
316
294
|
- Update `{state_file}` with reconciled values
|
|
317
295
|
</action>
|
|
296
|
+
|
|
297
|
+
<!-- Resume from a `retrospective_mode: stop` pause. -->
|
|
298
|
+
<check if="{state_file}.paused_at is epic-complete-awaiting-retrospective">
|
|
299
|
+
<action>Set `{{paused_epic_id}}` from `{state_file}.paused_epic_id`. Check if epic `{{paused_epic_id}}` is `done` in `{status_file}` OR an artifact exists at `{implementation_artifacts}/retrospectives/epic-{{paused_epic_id}}-*.md`.</action>
|
|
300
|
+
<check if="epic is done OR retrospective artifact exists">
|
|
301
|
+
<action>Clear `paused_at`, `paused_epic_id`, `next_action` from `{state_file}`. Log: "Epic {{paused_epic_id}} retrospective detected — resuming autopilot".</action>
|
|
302
|
+
</check>
|
|
303
|
+
<check if="epic is NOT done AND no retrospective artifact">
|
|
304
|
+
<action>Report: "Autopilot still paused — epic {{paused_epic_id}} retrospective not yet done. Run `/bmad-retrospective` interactively, then re-run `/sprint-autopilot-on`. (To bypass: set `retrospective_mode` to `auto` or `skip` in `_Sprintpilot/modules/autopilot/config.yaml`.)" Then STOP.</action>
|
|
305
|
+
</check>
|
|
306
|
+
</check>
|
|
307
|
+
|
|
318
308
|
<goto step="2">Jump to execution loop with reconciled state</goto>
|
|
319
309
|
</check>
|
|
320
310
|
|
|
321
311
|
<check if="state_file does NOT exist">
|
|
322
|
-
<action>Check if `{status_file}` exists
|
|
323
|
-
|
|
324
|
-
<check if="{{git_enabled}} AND status_file did not exist
|
|
325
|
-
<action>Run `git fetch origin`
|
|
326
|
-
<action>Initialize `{git_status_file}` with git_integration
|
|
327
|
-
```yaml
|
|
328
|
-
# Sprintpilot — Git Status
|
|
329
|
-
git_integration:
|
|
330
|
-
enabled: true
|
|
331
|
-
base_branch: {git.base_branch from config}
|
|
332
|
-
platform: {{platform}}
|
|
333
|
-
|
|
334
|
-
stories:
|
|
335
|
-
```
|
|
336
|
-
Note: this is the addon's own file — NEVER write git fields to sprint-status.yaml.
|
|
337
|
-
</action>
|
|
312
|
+
<action>Check if `{status_file}` exists. If NOT, do NOT jump to `bmad-sprint-planning` (Phase 4 skill, requires Phase 1–3 artifacts). Invoke `bmad-help` — "No sprint-status.yaml found. What is the current phase and which skill should run first?" — and set `{{next_skill}}` from its response. Expected routing: no PRD → `bmad-create-prd` (BLOCKER); PRD → `bmad-create-architecture`; architecture → `bmad-create-epics-and-stories`; epics → `bmad-sprint-planning`.</action>
|
|
313
|
+
|
|
314
|
+
<check if="{{git_enabled}} AND status_file did not exist AND {{next_skill}} is bmad-sprint-planning (planning just completed earlier in this flow)">
|
|
315
|
+
<action>Run `git fetch origin` — warn + skip on failure (no remote/auth/network), do not abort bootstrap.</action>
|
|
316
|
+
<action>Initialize `{git_status_file}` (addon-owned — NEVER write git fields to sprint-status.yaml) with: `git_integration: { enabled: true, base_branch: <from config>, platform: {{platform}} }` and empty `stories:`.</action>
|
|
338
317
|
</check>
|
|
339
318
|
|
|
340
319
|
<action>Read `{status_file}` — find all stories not yet `done`</action>
|
|
@@ -345,21 +324,7 @@ Resolve:
|
|
|
345
324
|
- `{{session_stories_done}}` = 0
|
|
346
325
|
</action>
|
|
347
326
|
<action>Create master task: "Sprintpilot — Full Sprint Execution" → `in_progress`</action>
|
|
348
|
-
<action>Write initial `{state_file}
|
|
349
|
-
```yaml
|
|
350
|
-
last_updated: {current_datetime}
|
|
351
|
-
current_story: null
|
|
352
|
-
current_bmad_step: null
|
|
353
|
-
completed_skill: bmad-help
|
|
354
|
-
next_skill: {{next_skill}}
|
|
355
|
-
session_stories_done: 0
|
|
356
|
-
stories_remaining: [list from sprint-status]
|
|
357
|
-
git_enabled: {{git_enabled}}
|
|
358
|
-
platform: {{platform}}
|
|
359
|
-
in_worktree: false
|
|
360
|
-
pr_base: {{base_branch}}
|
|
361
|
-
```
|
|
362
|
-
</action>
|
|
327
|
+
<action>Write initial `{state_file}` with STATE_FIELDS: `current_story = null`, `current_bmad_step = null`, `completed_skill = bmad-help`, `session_stories_done = 0`, `stories_remaining = [from sprint-status]`, `in_worktree = false`, `pr_base = {{base_branch}}`.</action>
|
|
363
328
|
<action>Report to user:
|
|
364
329
|
```
|
|
365
330
|
Sprintpilot ON
|
|
@@ -369,6 +334,7 @@ Resolve:
|
|
|
369
334
|
Git integration: {{git_enabled}}
|
|
370
335
|
Platform: {{platform}}
|
|
371
336
|
Session limit: {{session_story_limit}} stories, then checkpoint + new session
|
|
337
|
+
Retrospective mode: {{retrospective_mode}}
|
|
372
338
|
|
|
373
339
|
Beginning autonomous execution. I will only stop for true blockers or session checkpoints.
|
|
374
340
|
```
|
|
@@ -451,90 +417,33 @@ Resolve:
|
|
|
451
417
|
|
|
452
418
|
<!-- GIT: Enter worktree before dev-story -->
|
|
453
419
|
<check if="{{git_enabled}} AND {{next_skill}} is bmad-dev-story">
|
|
454
|
-
<action>**Sanitize branch name
|
|
455
|
-
`node {{project_root}}/_Sprintpilot/scripts/sanitize-branch.js "{{current_story}}" --prefix "{{branch_prefix}}" --max-length 60`
|
|
456
|
-
Output: sanitized name (without prefix). Set `{{branch_name}}` = output.
|
|
457
|
-
Full branch ref will be `{{branch_prefix}}{{branch_name}}`.
|
|
458
|
-
</action>
|
|
459
|
-
|
|
460
|
-
<action>**Check if branch already registered** in `{status_file}` for this story.
|
|
461
|
-
If yes AND worktree already exists → skip creation (idempotent).
|
|
462
|
-
If yes AND no worktree → recovery mode (see health check).
|
|
463
|
-
If no → proceed with creation.
|
|
464
|
-
</action>
|
|
420
|
+
<action>**Sanitize branch name**: `node {{project_root}}/_Sprintpilot/scripts/sanitize-branch.js "{{current_story}}" --prefix "{{branch_prefix}}" --max-length 60`. Set `{{branch_name}}` = output. Full ref: `{{branch_prefix}}{{branch_name}}`.</action>
|
|
465
421
|
|
|
466
|
-
<action>**
|
|
467
|
-
Run: `git fetch origin`
|
|
422
|
+
<action>**Idempotency check** — if branch is already registered in `{status_file}` for this story AND its worktree exists, skip creation. If registered without worktree → recovery mode (see health check). Otherwise proceed.</action>
|
|
468
423
|
|
|
469
|
-
|
|
470
|
-
- Read `{git_status_file}` for earlier stories in the same epic
|
|
471
|
-
- Find the latest story branch where `push_status` = "pushed" AND `pr_url` is a valid URL
|
|
472
|
-
- Check if that branch has been merged to `{{base_branch}}`: `git merge-base --is-ancestor origin/{{branch_prefix}}<prev-branch> origin/{{base_branch}}`
|
|
424
|
+
<action>**Pick branch point.** If `{{has_origin}}` is true: `git fetch origin` (warn + continue on failure). If `{{has_origin}}` is false: skip fetch, use local refs.
|
|
473
425
|
|
|
474
|
-
|
|
475
|
-
-
|
|
476
|
-
-
|
|
477
|
-
- Log: "Branching from {{branch_prefix}}<prev-branch> (PR pending merge)"
|
|
478
|
-
Otherwise:
|
|
479
|
-
- Branch from base: `git checkout origin/{{base_branch}}`
|
|
480
|
-
- Set `{{pr_base}}` = `{{base_branch}}`
|
|
426
|
+
Read `{git_status_file}` for earlier stories in this epic; find the latest with `push_status = "pushed"` AND a valid `pr_url`; check if merged to base: `git merge-base --is-ancestor origin/{{branch_prefix}}<prev-branch> origin/{{base_branch}}`.
|
|
427
|
+
- If unmerged previous story exists (requires `{{has_origin}}`): `git checkout origin/{{branch_prefix}}<prev-branch>`, set `{{pr_base}}` = `{{branch_prefix}}<prev-branch>`.
|
|
428
|
+
- Otherwise: `git checkout origin/{{base_branch}}` (or local `{{base_branch}}` if no origin), set `{{pr_base}}` = `{{base_branch}}`.
|
|
481
429
|
|
|
482
|
-
|
|
430
|
+
Detached HEAD is fine — `git worktree add` below creates a new branch from HEAD.
|
|
483
431
|
</action>
|
|
484
432
|
|
|
485
|
-
<action>**Create worktree
|
|
486
|
-
```
|
|
487
|
-
git worktree add "{{project_root}}/.worktrees/{{current_story}}" -b "{{branch_prefix}}{{branch_name}}" 2>&1
|
|
488
|
-
```
|
|
489
|
-
This creates `.worktrees/{{current_story}}/` with a new branch `{{branch_prefix}}{{branch_name}}` from HEAD.
|
|
490
|
-
|
|
491
|
-
If worktree add fails (branch already exists):
|
|
492
|
-
```
|
|
493
|
-
git worktree add "{{project_root}}/.worktrees/{{current_story}}" "{{branch_prefix}}{{branch_name}}" 2>&1
|
|
494
|
-
```
|
|
433
|
+
<action>**Create worktree.** Try: `git worktree add "{{project_root}}/.worktrees/{{current_story}}" -b "{{branch_prefix}}{{branch_name}}" 2>&1`. If it fails because the branch already exists, retry without `-b`: `git worktree add "{{project_root}}/.worktrees/{{current_story}}" "{{branch_prefix}}{{branch_name}}" 2>&1`.
|
|
495
434
|
|
|
496
|
-
|
|
497
|
-
- Log: "WARN: git worktree add failed — continuing without worktree isolation"
|
|
498
|
-
- Set `{{in_worktree}}` = false
|
|
499
|
-
- Create branch manually: `git checkout -b {{branch_prefix}}{{branch_name}}`
|
|
500
|
-
If checkout also fails (branch already exists): `git checkout {{branch_prefix}}{{branch_name}}`
|
|
501
|
-
If both fail: HALT — "Could not create or switch to branch {{branch_prefix}}{{branch_name}}"
|
|
502
|
-
- Continue with the skill invocation in PROJECT_ROOT (no isolation)
|
|
503
|
-
- Git operations (commit, push, PR) still work on the branch
|
|
435
|
+
If both fail (disk/permissions): log "WARN: worktree add failed — continuing without isolation", set `{{in_worktree}}` = false, and fall back to branch-only mode: `git checkout -b {{branch_prefix}}{{branch_name}}` (retry without `-b` if branch exists). HALT only if the checkout also fails. Git push/PR still work on the branch.
|
|
504
436
|
</action>
|
|
505
437
|
|
|
506
438
|
<check if="worktree add succeeded">
|
|
507
|
-
<action
|
|
508
|
-
`
|
|
509
|
-
All subsequent file operations and commands MUST use this directory.
|
|
510
|
-
Set `{{worktree_path}}` = `{{project_root}}/.worktrees/{{current_story}}`
|
|
511
|
-
</action>
|
|
512
|
-
|
|
513
|
-
<action>**Init submodules** if needed.
|
|
514
|
-
First check for `.gitmodules` (use your file-exists tool, or `node -e "process.exit(require('fs').existsSync('.gitmodules')?0:1)"`). If not present, skip this step.
|
|
515
|
-
If present, run `git submodule update --init --recursive` (give it ~30 seconds). If the command fails or hangs, warn "Submodule init failed (may need auth). Continuing without." and proceed.
|
|
516
|
-
</action>
|
|
517
|
-
|
|
439
|
+
<action>`cd {{project_root}}/.worktrees/{{current_story}}`. All subsequent commands run from here. Set `{{worktree_path}}` = this path.</action>
|
|
440
|
+
<action>**Init submodules** if `.gitmodules` exists (check with your file-exists tool or `node -e "process.exit(require('fs').existsSync('.gitmodules')?0:1)"`). Run `git submodule update --init --recursive` (~30s). On failure/hang: warn "Submodule init failed (may need auth). Continuing." and proceed.</action>
|
|
518
441
|
<action>Set `{{in_worktree}}` = true</action>
|
|
519
442
|
</check>
|
|
520
|
-
<action>Update `{state_file}` (write to worktree copy since
|
|
443
|
+
<action>Update `{state_file}` (write to the worktree copy since cwd is now the worktree)</action>
|
|
521
444
|
</check>
|
|
522
445
|
|
|
523
|
-
<action>Update `{state_file}
|
|
524
|
-
```yaml
|
|
525
|
-
last_updated: {current_datetime}
|
|
526
|
-
current_story: {{current_story}}
|
|
527
|
-
current_bmad_step: executing
|
|
528
|
-
completed_skill: {previous skill}
|
|
529
|
-
next_skill: {{next_skill}}
|
|
530
|
-
session_stories_done: {{session_stories_done}}
|
|
531
|
-
stories_remaining: {{stories_remaining}}
|
|
532
|
-
git_enabled: {{git_enabled}}
|
|
533
|
-
platform: {{platform}}
|
|
534
|
-
in_worktree: {{in_worktree}}
|
|
535
|
-
pr_base: {{pr_base}}
|
|
536
|
-
```
|
|
537
|
-
</action>
|
|
446
|
+
<action>Update `{state_file}` with STATE_FIELDS (set `current_bmad_step = executing`, `completed_skill = <previous skill>`).</action>
|
|
538
447
|
|
|
539
448
|
<!-- Autopilot menu handling rules apply — see AUTOPILOT RULES section above -->
|
|
540
449
|
|
|
@@ -586,8 +495,12 @@ pr_base: {{pr_base}}
|
|
|
586
495
|
<goto step="7">Mark story done</goto>
|
|
587
496
|
</check>
|
|
588
497
|
|
|
589
|
-
<check if="{{completed_skill}}
|
|
590
|
-
<action>Log: "Epic retrospective
|
|
498
|
+
<check if="{{completed_skill}} is retrospective-auto">
|
|
499
|
+
<action>Log: "Epic retrospective generated inline by autopilot — sprint-status.yaml updated"</action>
|
|
500
|
+
</check>
|
|
501
|
+
|
|
502
|
+
<check if="{{completed_skill}} is retrospective-skip">
|
|
503
|
+
<action>Log: "Epic retrospective skipped per config — sprint-status.yaml updated inline"</action>
|
|
591
504
|
</check>
|
|
592
505
|
|
|
593
506
|
<check if="{{completed_skill}} was bmad-create-epics-and-stories">
|
|
@@ -601,7 +514,8 @@ pr_base: {{pr_base}}
|
|
|
601
514
|
</check>
|
|
602
515
|
|
|
603
516
|
<check if="{{completed_skill}} was bmad-sprint-planning AND {{git_enabled}}">
|
|
604
|
-
<action>
|
|
517
|
+
<action>If `{{has_origin}}` is true, run `git fetch origin` (log a warning on failure and continue — do not abort).
|
|
518
|
+
If `{{has_origin}}` is false, skip the fetch.</action>
|
|
605
519
|
<action>Initialize `{git_status_file}` if it doesn't exist (with git_integration block)</action>
|
|
606
520
|
</check>
|
|
607
521
|
|
|
@@ -617,22 +531,10 @@ pr_base: {{pr_base}}
|
|
|
617
531
|
</action>
|
|
618
532
|
</check>
|
|
619
533
|
|
|
620
|
-
<!-- GIT: Commit planning artifacts to main after planning skills -->
|
|
621
534
|
<check if="{{git_enabled}} AND {{completed_skill}} is a planning skill (bmad-create-prd, bmad-create-architecture, bmad-create-ux-design, bmad-create-epics-and-stories, bmad-sprint-planning, bmad-check-implementation-readiness, bmad-create-story)">
|
|
622
|
-
<action>**Commit planning artifacts to main
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
git add _bmad-output/planning-artifacts/ _bmad-output/implementation-artifacts/ _bmad-output/stories/
|
|
626
|
-
```
|
|
627
|
-
Check if there's anything staged; if yes, commit:
|
|
628
|
-
```
|
|
629
|
-
git diff --cached --quiet
|
|
630
|
-
```
|
|
631
|
-
If that exits non-zero (there are staged changes), run: `git commit -m "docs: {{completed_skill}} artifacts"`
|
|
632
|
-
Then push (log a warning if push fails; do not halt autopilot):
|
|
633
|
-
```
|
|
634
|
-
git push origin {{base_branch}}
|
|
635
|
-
```
|
|
535
|
+
<action>**Commit planning artifacts to main.**
|
|
536
|
+
1. `git add _bmad-output/planning-artifacts/ _bmad-output/implementation-artifacts/ _bmad-output/stories/` (ignore missing-path errors)
|
|
537
|
+
2. If `git diff --cached --quiet` exits non-zero: `git commit -m "docs: {{completed_skill}} artifacts"` then `git push origin {{base_branch}}` (warn on push failure, do not halt).
|
|
636
538
|
</action>
|
|
637
539
|
</check>
|
|
638
540
|
|
|
@@ -643,32 +545,17 @@ pr_base: {{pr_base}}
|
|
|
643
545
|
|
|
644
546
|
<step n="5" goal="Determine next skill — from skill output first, bmad-help as fallback">
|
|
645
547
|
|
|
646
|
-
<action>Read the output of `{{completed_skill}}
|
|
647
|
-
|
|
648
|
-
<check if="output contains 'Next Steps', 'What to do next', 'Run next', or equivalent">
|
|
649
|
-
<action>Extract `{{next_skill}}` from that section</action>
|
|
650
|
-
<action>Log: "Next step from skill output: {{next_skill}}"</action>
|
|
651
|
-
</check>
|
|
548
|
+
<action>Read the output of `{{completed_skill}}`. If it contains "Next Steps", "What to do next", "Run next", or equivalent, extract `{{next_skill}}` from that section. Otherwise invoke `bmad-help` — "{{completed_skill}} just finished. What is the next required workflow step?" — and extract `{{next_skill}}` from its response. Log the source ("skill output" vs "bmad-help fallback").</action>
|
|
652
549
|
|
|
653
|
-
<check if="
|
|
654
|
-
<action
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
<action>Set `{{current_story}}` = first undone story from `{status_file}`</action>
|
|
663
|
-
<action>Determine `{{next_skill}}` based on that story's current status and BMAD step:
|
|
664
|
-
- If story has no story file yet → `bmad-create-story`
|
|
665
|
-
- If story file exists but status is `ready-for-dev` → `bmad-check-implementation-readiness`
|
|
666
|
-
- If story is `in-progress` and `current_bmad_step` is before `code-review` (i.e. RED or GREEN phase) → `bmad-dev-story`
|
|
667
|
-
- If story is `in-progress` and `current_bmad_step` is `code-review` or later → `bmad-code-review`
|
|
668
|
-
- Otherwise → invoke `bmad-help` for precise determination
|
|
669
|
-
</action>
|
|
670
|
-
<action>Log: "next_skill was empty but undone stories remain — resolved to {{next_skill}} for {{current_story}}"</action>
|
|
671
|
-
</check>
|
|
550
|
+
<check if="{{next_skill}} is null, empty, or signals completion">
|
|
551
|
+
<action>**Verify against source of truth** — re-read `{status_file}`. If undone stories exist, set `{{current_story}}` = first one and determine `{{next_skill}}`:
|
|
552
|
+
- No story file → `bmad-create-story`
|
|
553
|
+
- Story file + status `ready-for-dev` → `bmad-check-implementation-readiness`
|
|
554
|
+
- Status `in-progress` and `current_bmad_step` before `code-review` → `bmad-dev-story`
|
|
555
|
+
- Status `in-progress` and `current_bmad_step` ≥ `code-review` → `bmad-code-review`
|
|
556
|
+
- Else → invoke `bmad-help` for precise determination
|
|
557
|
+
Log: "next_skill was empty but undone stories remain — resolved to {{next_skill}} for {{current_story}}".
|
|
558
|
+
</action>
|
|
672
559
|
<check if="all stories in status_file are done">
|
|
673
560
|
<goto step="10">Sprint complete</goto>
|
|
674
561
|
</check>
|
|
@@ -779,37 +666,15 @@ Instruct: "Re-verify code review for story {{current_story}} — all patch findi
|
|
|
779
666
|
</action>
|
|
780
667
|
|
|
781
668
|
<check if="{{create_pr}} is false OR {{platform}} is git_only OR {{pr_url}} is null or SKIPPED">
|
|
782
|
-
<action>**Merge story branch to main
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
git
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
If succeeds:
|
|
789
|
-
- `git push origin {{base_branch}}`
|
|
790
|
-
- Set `{{merge_status}}` = "merged"
|
|
791
|
-
If fails (conflict):
|
|
792
|
-
- `git merge --abort`
|
|
793
|
-
- `git fetch origin`
|
|
794
|
-
- `git checkout -B {{base_branch}} origin/{{base_branch}}`
|
|
795
|
-
- Retry merge once: `git merge {{branch_prefix}}{{branch_name}} --no-edit`
|
|
796
|
-
- If retry succeeds: push, set `{{merge_status}}` = "merged"
|
|
797
|
-
- If retry fails: set `{{merge_status}}` = "failed"
|
|
798
|
-
Log: "WARN: merge failed for {{current_story}} — will retry on next boot"
|
|
799
|
-
|
|
800
|
-
If `{{merge_status}}` == "failed":
|
|
801
|
-
Log warning but do NOT halt. The branch is pushed and preserved.
|
|
802
|
-
Boot reconciliation (INITIALIZATION branch reconciliation) will retry on next session.
|
|
803
|
-
|
|
804
|
-
Note: `{{merge_status}}` is persisted by the full sync-status.js call later in this step (via `--merge-status`). Do NOT call sync-status.js separately here — it does full block replacement and would destroy other fields.
|
|
669
|
+
<action>**Merge story branch to main.** If `{{has_origin}}` is false (local-only), substitute `origin/{{base_branch}}` → `{{base_branch}}` and skip all `git push origin` / `git fetch origin` calls below.
|
|
670
|
+
1. `git checkout -B {{base_branch}} origin/{{base_branch}}` then `git merge {{branch_prefix}}{{branch_name}} --no-edit`.
|
|
671
|
+
2. On success: `git push origin {{base_branch}}`, set `{{merge_status}}` = "merged".
|
|
672
|
+
3. On conflict: `git merge --abort`, `git fetch origin`, re-checkout base, retry merge once. On retry success: push + merged. On retry failure: `{{merge_status}}` = "failed", log warning, continue — the branch is preserved and boot reconciliation retries next session.
|
|
673
|
+
|
|
674
|
+
`{{merge_status}}` is persisted by the sync-status.js call later in this step (via `--merge-status`). Do NOT call sync-status.js here — it does full block replacement and would destroy other fields.
|
|
805
675
|
</action>
|
|
806
676
|
<check if="{{cleanup_on_merge}} is true">
|
|
807
|
-
<action>**Cleanup worktree**
|
|
808
|
-
```
|
|
809
|
-
git worktree remove .worktrees/{{current_story}} --force
|
|
810
|
-
git worktree prune
|
|
811
|
-
```
|
|
812
|
-
</action>
|
|
677
|
+
<action>**Cleanup worktree** (ignore failures — may already be gone): `git worktree remove .worktrees/{{current_story}} --force` then `git worktree prune`</action>
|
|
813
678
|
</check>
|
|
814
679
|
</check>
|
|
815
680
|
<check if="{{pr_url}} is a valid URL (not null, not SKIPPED)">
|
|
@@ -818,29 +683,11 @@ Instruct: "Re-verify code review for story {{current_story}} — all patch findi
|
|
|
818
683
|
<action>Log: "Story {{current_story}} pushed — PR awaiting review: {{pr_url}}"</action>
|
|
819
684
|
</check>
|
|
820
685
|
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
git
|
|
825
|
-
|
|
826
|
-
</action>
|
|
827
|
-
|
|
828
|
-
<action>**Write git status** to addon's own file (NEVER modify sprint-status.yaml) — runs AFTER checkout to base branch so the file persists in the working tree for the commit below:
|
|
829
|
-
`node {{project_root}}/_Sprintpilot/scripts/sync-status.js --story "{{current_story}}" --git-status-file "{{project_root}}/_bmad-output/implementation-artifacts/git-status.yaml" --branch "{{branch_prefix}}{{branch_name}}" --commit "{{story_commit}}" --patch-commits "{{patch_commits_csv}}" --push-status "{{push_status}}" --merge-status "{{merge_status}}" --pr-url "{{pr_url}}" --lint-result "{{lint_result}}" --worktree "{{project_root}}/.worktrees/{{current_story}}" --platform "{{platform}}" --base-branch "{{base_branch}}"`
|
|
830
|
-
This writes to `git-status.yaml` (addon-owned). Sprint-status.yaml is BMAD-owned — updated by BMAD skills only.
|
|
831
|
-
</action>
|
|
832
|
-
|
|
833
|
-
<action>**Stage and commit artifacts** — explicitly include git-status.yaml and decision-log.yaml. Ignore errors from the `git add` (any listed path may not yet exist):
|
|
834
|
-
```
|
|
835
|
-
git add _bmad-output/implementation-artifacts/sprint-status.yaml _bmad-output/implementation-artifacts/git-status.yaml _bmad-output/implementation-artifacts/autopilot-state.yaml _bmad-output/implementation-artifacts/decision-log.yaml _bmad-output/stories/ _bmad-output/planning-artifacts/
|
|
836
|
-
```
|
|
837
|
-
Check if anything is staged: `git diff --cached --quiet`. If that exits non-zero, commit:
|
|
838
|
-
`git commit -m "docs: story {{current_story}} done — {{test_count}} tests{{#if pr_url}}, PR: {{pr_url}}{{/if}}"`
|
|
839
|
-
Then push (log a warning if push fails; do not halt autopilot):
|
|
840
|
-
```
|
|
841
|
-
git push origin {{base_branch}}
|
|
842
|
-
```
|
|
843
|
-
This ensures sprint-status.yaml, git-status.yaml, story files, and any updated artifacts are on main even when story code is on a PR branch.
|
|
686
|
+
<action>**Commit story artifacts to main** — keeps main in sync even when story code is on a PR branch.
|
|
687
|
+
1. `git checkout -B {{base_branch}} origin/{{base_branch}}`
|
|
688
|
+
2. Write git-status.yaml (addon-owned — never touch sprint-status.yaml): `node {{project_root}}/_Sprintpilot/scripts/sync-status.js --story "{{current_story}}" --git-status-file "{{project_root}}/_bmad-output/implementation-artifacts/git-status.yaml" --branch "{{branch_prefix}}{{branch_name}}" --commit "{{story_commit}}" --patch-commits "{{patch_commits_csv}}" --push-status "{{push_status}}" --merge-status "{{merge_status}}" --pr-url "{{pr_url}}" --lint-result "{{lint_result}}" --worktree "{{project_root}}/.worktrees/{{current_story}}" --platform "{{platform}}" --base-branch "{{base_branch}}"`
|
|
689
|
+
3. Stage artifacts (ignore errors for missing paths): `git add _bmad-output/implementation-artifacts/sprint-status.yaml _bmad-output/implementation-artifacts/git-status.yaml _bmad-output/implementation-artifacts/autopilot-state.yaml _bmad-output/implementation-artifacts/decision-log.yaml _bmad-output/stories/ _bmad-output/planning-artifacts/`
|
|
690
|
+
4. If `git diff --cached --quiet` exits non-zero: `git commit -m "docs: story {{current_story}} done — {{test_count}} tests{{#if pr_url}}, PR: {{pr_url}}{{/if}}"` then `git push origin {{base_branch}}` (warn on push failure, do not halt).
|
|
844
691
|
</action>
|
|
845
692
|
</check>
|
|
846
693
|
|
|
@@ -858,36 +705,37 @@ Instruct: "Re-verify code review for story {{current_story}} — all patch findi
|
|
|
858
705
|
|
|
859
706
|
<action>Check if ALL stories in this epic are `done`</action>
|
|
860
707
|
<check if="epic complete">
|
|
861
|
-
<action>
|
|
862
|
-
<action>
|
|
863
|
-
|
|
864
|
-
|
|
708
|
+
<action>Resolve `{{epic_id}}` (e.g. "1") and `{{epic_title}}` from `{status_file}` for the current epic</action>
|
|
709
|
+
<action>Create task "[epic {{epic_id}}] retrospective" → `in_progress`</action>
|
|
710
|
+
|
|
711
|
+
<!-- Retrospective: driven by `autopilot.retrospective_mode`. The external
|
|
712
|
+
`bmad-retrospective` skill is NEVER invoked from autopilot (multi-persona
|
|
713
|
+
discussion loop under some CLIs). -->
|
|
714
|
+
|
|
715
|
+
<check if="{{retrospective_mode}} is auto">
|
|
716
|
+
<action>Collect from `{status_file}` for epic `{{epic_id}}`: done stories `{ story-key, title, test_pass_count, patch_count }`, epic title, dates if present.</action>
|
|
717
|
+
<action>Collect decision-log entries for epic `{{epic_id}}` (match `story` prefix `{{epic_id}}-` or `phase: autopilot:*` tagged to this epic). Identify open risks / carry-over notes from any story `notes`/`risks` fields or `workaround` decisions for this epic.</action>
|
|
718
|
+
<action>Ensure `{implementation_artifacts}/retrospectives/` exists. Read template `{{project_root}}/_Sprintpilot/templates/epic-retrospective.md`, fill mustache placeholders, write to `{implementation_artifacts}/retrospectives/epic-{{epic_id}}-retrospective.md`.</action>
|
|
719
|
+
<action>Update `{status_file}`: `epics.{{epic_id}}.status = done`, `.retrospective_path = <file>`, `.completed_at = {current_date}`.</action>
|
|
720
|
+
<action>Append decision-log entry: `{ category: workaround, decision: "retrospective generated inline", rationale: "retrospective_mode=auto", impact: low, phase: autopilot:retrospective, story: "epic-{{epic_id}}" }`.</action>
|
|
721
|
+
<action>Mark retrospective task → `completed`. Set `{{completed_skill}}` = `retrospective-auto`.</action>
|
|
722
|
+
</check>
|
|
865
723
|
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
<action
|
|
869
|
-
<action>Report:
|
|
870
|
-
|
|
871
|
-
Epic complete — PR/MR summary:
|
|
872
|
-
{{#each epic_stories}}
|
|
873
|
-
- {{story-key}}: {{pr_url}}
|
|
874
|
-
{{/each}}
|
|
724
|
+
<check if="{{retrospective_mode}} is stop">
|
|
725
|
+
<action>Update `{state_file}`: `paused_at = epic-complete-awaiting-retrospective`, `paused_epic_id = {{epic_id}}`, `next_action = "run /bmad-retrospective interactively for epic {{epic_id}}, then re-run /sprint-autopilot-on"`.</action>
|
|
726
|
+
<action>Append decision-log entry: `{ category: workaround, decision: "paused for interactive retrospective", rationale: "retrospective_mode=stop", impact: low, phase: autopilot:retrospective, story: "epic-{{epic_id}}" }`. Mark retrospective task → `completed`.</action>
|
|
727
|
+
<action>Report: "Autopilot paused — epic {{epic_id}} complete, retrospective handed off. Run `/bmad-retrospective` interactively for epic {{epic_id}}, then re-run `/sprint-autopilot-on`. State saved to: {state_file}." Then STOP.</action>
|
|
728
|
+
</check>
|
|
875
729
|
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
730
|
+
<check if="{{retrospective_mode}} is skip">
|
|
731
|
+
<action>Update `{status_file}`: `epics.{{epic_id}}.status = done`, `.retrospective_path = null`, `.retrospective_skipped = true`, `.completed_at = {current_date}`.</action>
|
|
732
|
+
<action>Append decision-log entry: `{ category: workaround, decision: "retrospective skipped", rationale: "retrospective_mode=skip (NOT RECOMMENDED)", impact: medium, phase: autopilot:retrospective, story: "epic-{{epic_id}}" }`. Mark retrospective task → `completed`. Set `{{completed_skill}}` = `retrospective-skip`.</action>
|
|
733
|
+
</check>
|
|
734
|
+
|
|
735
|
+
<check if="{{git_enabled}}">
|
|
736
|
+
<action>**Epic PR summary** — list all epic PR/MR URLs from `{status_file}` and report as "Epic complete — PR/MR summary: [list]. Ready to merge — review PRs and confirm when ready."</action>
|
|
879
737
|
<check if="{{cleanup_on_merge}} is true">
|
|
880
|
-
<action>**Cleanup worktrees** for completed stories:
|
|
881
|
-
For each story in this epic:
|
|
882
|
-
1. Check if worktree at `.worktrees/{{story-key}}` exists
|
|
883
|
-
2. Check if clean: `git -C .worktrees/{{story-key}} status --porcelain`
|
|
884
|
-
3. If clean → `git worktree remove .worktrees/{{story-key}}` + `git worktree prune`
|
|
885
|
-
Update `{git_status_file}` for this story: `worktree_cleaned: true`
|
|
886
|
-
4. If dirty → warn user, skip cleanup
|
|
887
|
-
</action>
|
|
888
|
-
</check>
|
|
889
|
-
<check if="{{cleanup_on_merge}} is false">
|
|
890
|
-
<action>Log: "Worktree cleanup skipped (git.worktree.cleanup_on_merge = false)"</action>
|
|
738
|
+
<action>**Cleanup worktrees** for completed stories. For each: if `.worktrees/{{story-key}}` exists, check cleanliness via `git -C .worktrees/{{story-key}} status --porcelain`. If clean → `git worktree remove` + `git worktree prune` and set `worktree_cleaned: true` in `{git_status_file}`. If dirty → warn and skip.</action>
|
|
891
739
|
</check>
|
|
892
740
|
</check>
|
|
893
741
|
</check>
|
|
@@ -904,21 +752,7 @@ Instruct: "Re-verify code review for story {{current_story}} — all patch findi
|
|
|
904
752
|
|
|
905
753
|
<step n="8" goal="Save state and continue">
|
|
906
754
|
|
|
907
|
-
<action>Update `{state_file}
|
|
908
|
-
```yaml
|
|
909
|
-
last_updated: {current_datetime}
|
|
910
|
-
current_story: {{current_story}}
|
|
911
|
-
current_bmad_step: {{current_bmad_step}}
|
|
912
|
-
completed_skill: {{completed_skill}}
|
|
913
|
-
next_skill: {{next_skill}}
|
|
914
|
-
session_stories_done: {{session_stories_done}}
|
|
915
|
-
stories_remaining: {{stories_remaining}}
|
|
916
|
-
git_enabled: {{git_enabled}}
|
|
917
|
-
platform: {{platform}}
|
|
918
|
-
in_worktree: {{in_worktree}}
|
|
919
|
-
pr_base: {{pr_base}}
|
|
920
|
-
```
|
|
921
|
-
</action>
|
|
755
|
+
<action>Update `{state_file}` with STATE_FIELDS.</action>
|
|
922
756
|
|
|
923
757
|
<goto step="2">Continue execution loop</goto>
|
|
924
758
|
|
|
@@ -953,21 +787,7 @@ pr_base: {{pr_base}}
|
|
|
953
787
|
</action>
|
|
954
788
|
</check>
|
|
955
789
|
|
|
956
|
-
<action>Update `{state_file}
|
|
957
|
-
```yaml
|
|
958
|
-
last_updated: {current_datetime}
|
|
959
|
-
current_story: {{current_story}}
|
|
960
|
-
current_bmad_step: {{current_bmad_step}}
|
|
961
|
-
completed_skill: {{completed_skill}}
|
|
962
|
-
next_skill: {{next_skill}}
|
|
963
|
-
session_stories_done: {{session_stories_done}}
|
|
964
|
-
stories_remaining: {{stories_remaining}}
|
|
965
|
-
git_enabled: {{git_enabled}}
|
|
966
|
-
platform: {{platform}}
|
|
967
|
-
in_worktree: {{in_worktree}}
|
|
968
|
-
pr_base: {{pr_base}}
|
|
969
|
-
```
|
|
970
|
-
</action>
|
|
790
|
+
<action>Update `{state_file}` with STATE_FIELDS.</action>
|
|
971
791
|
|
|
972
792
|
<action>Read `{decision_log_file}` — count medium/high decisions from this session's stories</action>
|
|
973
793
|
|
|
@@ -1017,133 +837,53 @@ No work will be repeated.
|
|
|
1017
837
|
<action>Run full test suite — report `N/N passed`</action>
|
|
1018
838
|
|
|
1019
839
|
<!-- Generate project documentation after sprint completion -->
|
|
1020
|
-
<action>**
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
<
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
`
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
- All completed stories grouped by epic, with their story titles
|
|
1045
|
-
- Total story count, total epic count
|
|
1046
|
-
- Final test count
|
|
1047
|
-
- If git_enabled: all PR/MR URLs, patch counts, dismissed findings per story
|
|
840
|
+
<action>**Resolve stack** — set `{{stack}}` = `{ name, install_cmd, run_cmd, test_cmd }` using the first successful source:
|
|
841
|
+
|
|
842
|
+
1. **`project-context.md`** (glob `**/project-context.md`, canonical `{output_folder}/project-context.md`) — extract from "Technology Stack & Versions" and any install/run/test subsections.
|
|
843
|
+
2. **`architecture.md`** (`{planning_artifacts}/architecture.md`) — extract from "Tech Stack" / "Runtime" / "Build & Deploy" / "Commands" sections.
|
|
844
|
+
3. **Manifest heuristics** — map manifest file → stack → idiomatic commands:
|
|
845
|
+
|
|
846
|
+
| Manifest | Stack | install / run / test |
|
|
847
|
+
|---|---|---|
|
|
848
|
+
| `package.json` | Node/JS/TS | `<pm> install` / `<pm> run start\|dev\|serve` (or `node <bin>`) / `<pm> test` — `<pm>` = `pnpm`/`yarn`/`bun`/`npm` by lockfile |
|
|
849
|
+
| `pyproject.toml`, `requirements.txt`, `setup.py` | Python | `pip install -r requirements.txt` (or `-e .`) / Django `python manage.py runserver` → Flask → FastAPI `uvicorn app:app` → `python main.py`/`app.py` / `pytest` |
|
|
850
|
+
| `go.mod` | Go | `go mod download` / `go run .` (or `./cmd/<name>`) / `go test ./...` |
|
|
851
|
+
| `Cargo.toml` | Rust | `cargo build` / `cargo run` (or `--bin <name>`) / `cargo test` |
|
|
852
|
+
| `pom.xml` | Java/Kotlin (Maven) | `mvn install` / `mvn spring-boot:run` or `mvn exec:java` / `mvn test` |
|
|
853
|
+
| `build.gradle(.kts)` | Java/Kotlin (Gradle) | `./gradlew build` / `./gradlew bootRun` or `run` / `./gradlew test` |
|
|
854
|
+
| `Gemfile` | Ruby | `bundle install` / `rails server` or `bundle exec ruby <entry>` / `bundle exec rspec` |
|
|
855
|
+
| `*.csproj`/`*.sln` | .NET | `dotnet restore` / `dotnet run` (or `--project`) / `dotnet test` |
|
|
856
|
+
| `composer.json` | PHP | `composer install` / `php artisan serve` (Laravel) or `php -S localhost:8000 -t public` / `vendor/bin/phpunit` |
|
|
857
|
+
| `mix.exs` | Elixir | `mix deps.get` / `mix phx.server` or `mix run --no-halt` / `mix test` |
|
|
858
|
+
| (none of the above) | Explicit launcher | `./run.sh`/`./run_gui.sh`/`./start.sh`, `make run\|start\|dev`, `docker compose up`, `docker build` + `docker run` |
|
|
859
|
+
|
|
860
|
+
4. **No match** — all fields `null`. Downstream omits the line; never guess.
|
|
861
|
+
|
|
862
|
+
Set `{{launch_cmd}}` = `{{stack.run_cmd}}`.
|
|
863
|
+
If `{{stack}}` came from (3) and `project-context.md` exists without stack info, log: "Consider running `bmad-generate-project-context` to capture stack commands."
|
|
1048
864
|
</action>
|
|
1049
865
|
|
|
1050
|
-
<action
|
|
1051
|
-
- All decisions with impact `medium` or `high`
|
|
1052
|
-
- Count of `review-accept` entries (patches applied)
|
|
1053
|
-
- Count of `review-triage` entries (findings dismissed)
|
|
1054
|
-
- Total review rounds (count of code-review invocations)
|
|
1055
|
-
- Per-story summary: patches applied and findings dismissed
|
|
1056
|
-
</action>
|
|
866
|
+
<action>**Generate documentation** — invoke `bmad-document-project`. If unavailable or it fails, write a minimal README using `{{stack}}`: project name + description (from brief/PRD); install/run/test lines for each non-null `{{stack.*_cmd}}` (omit lines where null); architecture overview if `architecture.md` exists.</action>
|
|
1057
867
|
|
|
1058
|
-
<action>Find the app launch command by checking (in order):
|
|
1059
|
-
1. `run_gui.sh` or `run.sh` in the project root
|
|
1060
|
-
2. `main.py` in the project root
|
|
1061
|
-
3. Check `pyproject.toml`, `package.json`, or `setup.py` for scripts
|
|
1062
|
-
Record as `{{launch_cmd}}`
|
|
1063
|
-
</action>
|
|
1064
|
-
|
|
1065
|
-
<!-- GIT: Final worktree cleanup — safety net for any worktrees not cleaned during epic completion -->
|
|
1066
868
|
<check if="{{git_enabled}}">
|
|
1067
|
-
<action>**
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
Then: `git worktree prune`
|
|
869
|
+
<action>**Commit final artifacts + docs to main.**
|
|
870
|
+
1. `git checkout -B {{base_branch}} origin/{{base_branch}}`
|
|
871
|
+
2. `git add _bmad-output/ README.md docs/` (ignore missing-path errors)
|
|
872
|
+
3. If `git diff --cached --quiet` exits non-zero: `git commit -m "docs: project documentation and final artifacts"` then `git push origin {{base_branch}}` (warn on push failure).
|
|
1072
873
|
</action>
|
|
1073
874
|
</check>
|
|
1074
875
|
|
|
1075
|
-
|
|
876
|
+
<action>**Collect report data** from `{status_file}` (stories grouped by epic with titles, totals, final test count; PR/MR URLs, patch/dismissed counts per story if git_enabled) and `{decision_log_file}` (medium/high-impact decisions; counts of `review-accept`, `review-triage`, code-review rounds; per-story patches-applied / findings-dismissed).</action>
|
|
877
|
+
|
|
1076
878
|
<check if="{{git_enabled}}">
|
|
879
|
+
<action>**Cleanup remaining worktrees** (safety net): `git worktree list --porcelain` → for each non-main worktree: `git worktree remove <path> --force` then `git worktree prune` (log + continue on failure).</action>
|
|
1077
880
|
<action>Release lock: `node {{project_root}}/_Sprintpilot/scripts/lock.js release`</action>
|
|
1078
881
|
</check>
|
|
1079
882
|
|
|
1080
883
|
<action>Delete `{state_file}` — sprint complete</action>
|
|
1081
884
|
<action>Mark master task "Sprintpilot — Full Sprint Execution" → `completed`</action>
|
|
1082
885
|
|
|
1083
|
-
<action>
|
|
1084
|
-
```
|
|
1085
|
-
╔═══════════════════════════════════════════════════════════════╗
|
|
1086
|
-
║ BMAD AUTOPILOT — REPORT ║
|
|
1087
|
-
╚═══════════════════════════════════════════════════════════════╝
|
|
1088
|
-
|
|
1089
|
-
SUMMARY
|
|
1090
|
-
Stories completed : {{done_count}}/{{total_stories}}
|
|
1091
|
-
Epics completed : {{done_epics}}/{{total_epics}}
|
|
1092
|
-
Total tests : {{N}}/{{N}} passed
|
|
1093
|
-
{{#if git_enabled}}
|
|
1094
|
-
Platform : {{platform}}
|
|
1095
|
-
{{/if}}
|
|
1096
|
-
|
|
1097
|
-
STORIES
|
|
1098
|
-
{{#each epic}}
|
|
1099
|
-
Epic {{epic_number}}: {{epic_title}}
|
|
1100
|
-
{{#each stories}}
|
|
1101
|
-
✓ {{story-key}} — {{test_count}} tests{{#if pr_url}} PR: {{pr_url}}{{/if}}
|
|
1102
|
-
{{/each}}
|
|
1103
|
-
{{/each}}
|
|
1104
|
-
{{#if remaining_stories}}
|
|
1105
|
-
Not started:
|
|
1106
|
-
{{#each remaining_stories}}
|
|
1107
|
-
· {{story-key}}
|
|
1108
|
-
{{/each}}
|
|
1109
|
-
{{/if}}
|
|
1110
|
-
|
|
1111
|
-
DECISIONS REQUIRING REVIEW (high/medium impact)
|
|
1112
|
-
{{#each medium_high_decisions}}
|
|
1113
|
-
#{{id}} [{{impact}}] {{story}} / {{phase}}
|
|
1114
|
-
{{decision}}
|
|
1115
|
-
→ {{rationale}}
|
|
1116
|
-
{{/each}}
|
|
1117
|
-
{{#if no_medium_high_decisions}}
|
|
1118
|
-
None — all decisions were low-impact.
|
|
1119
|
-
{{/if}}
|
|
1120
|
-
|
|
1121
|
-
Full log: {decision_log_file}
|
|
1122
|
-
|
|
1123
|
-
REVIEW FINDINGS APPLIED
|
|
1124
|
-
Patches applied : {{total_patches}}
|
|
1125
|
-
Findings dismissed : {{total_dismissed}}
|
|
1126
|
-
Review rounds : {{total_review_rounds}}
|
|
1127
|
-
|
|
1128
|
-
CODE REVIEW SUMMARY (per story)
|
|
1129
|
-
{{#each completed_stories}}
|
|
1130
|
-
{{story-key}} : {{patches_applied}} patches applied, {{findings_dismissed}} dismissed
|
|
1131
|
-
{{/each}}
|
|
1132
|
-
|
|
1133
|
-
WHAT TO DO NEXT
|
|
1134
|
-
1. Review decisions marked medium/high above
|
|
1135
|
-
{{#if has_pr_urls}}
|
|
1136
|
-
2. Merge open PRs: {{pr_urls_list}}
|
|
1137
|
-
{{/if}}
|
|
1138
|
-
{{#if launch_cmd}}
|
|
1139
|
-
{{next_number}}. Run the app: {{launch_cmd}}
|
|
1140
|
-
{{/if}}
|
|
1141
|
-
{{next_number}}. Manual smoke test checklist:
|
|
1142
|
-
{{#each completed_stories}}
|
|
1143
|
-
· [{{story-key}}] {{smoke_test_suggestion}}
|
|
1144
|
-
{{/each}}
|
|
1145
|
-
```
|
|
1146
|
-
</action>
|
|
886
|
+
<action>Read template `{{project_root}}/_Sprintpilot/templates/sprint-report.txt`, fill mustache placeholders with the collected data, and print the result verbatim as the final message.</action>
|
|
1147
887
|
|
|
1148
888
|
</step>
|
|
1149
889
|
|