@snipcodeit/mgw 0.2.2 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/commands/run.md CHANGED
@@ -48,1560 +48,36 @@ State: .mgw/active/ (if triaged already)
48
48
 
49
49
  <process>
50
50
 
51
- <step name="validate_and_load">
52
- **Validate input and load state:**
51
+ <!-- ═══════════════════════════════════════════════════════════ -->
52
+ <!-- Stage 1: TRIAGE -->
53
+ <!-- Validate input, load/create state, preflight comment -->
54
+ <!-- check, post work-starting comment -->
55
+ <!-- ═══════════════════════════════════════════════════════════ -->
53
56
 
54
- Store repo root and default branch (used throughout):
55
- ```bash
56
- REPO_ROOT=$(git rev-parse --show-toplevel)
57
- DEFAULT=$(gh repo view --json defaultBranchRef -q .defaultBranchRef.name)
58
- ```
57
+ @~/.claude/commands/mgw/run/triage.md
59
58
 
60
- Parse $ARGUMENTS for issue number and flags. If issue number missing:
61
- ```
62
- AskUserQuestion(
63
- header: "Issue Number Required",
64
- question: "Which issue number do you want to run the pipeline for?",
65
- followUp: null
66
- )
67
- ```
59
+ <!-- ═══════════════════════════════════════════════════════════ -->
60
+ <!-- Stage 2: WORKTREE -->
61
+ <!-- Create isolated worktree, set up branch, apply labels -->
62
+ <!-- ═══════════════════════════════════════════════════════════ -->
68
63
 
69
- Extract flags from $ARGUMENTS:
70
- ```bash
71
- RETRY_FLAG=false
72
- for ARG in $ARGUMENTS; do
73
- case "$ARG" in
74
- --retry) RETRY_FLAG=true ;;
75
- esac
76
- done
77
- ```
64
+ @~/.claude/commands/mgw/run/worktree.md
78
65
 
79
- Check for existing state: `${REPO_ROOT}/.mgw/active/${ISSUE_NUMBER}-*.json`
66
+ <!-- ═══════════════════════════════════════════════════════════ -->
67
+ <!-- Stage 3: EXECUTE -->
68
+ <!-- Run GSD pipeline (quick or milestone), handle retries, -->
69
+ <!-- post execution update or failure comment -->
70
+ <!-- ═══════════════════════════════════════════════════════════ -->
80
71
 
81
- If no state file exists → issue not triaged yet. Run triage inline:
82
- - Inform user: "Issue #${ISSUE_NUMBER} hasn't been triaged. Running triage first."
83
- - Execute the mgw:issue triage flow (steps from issue.md) inline.
84
- - After triage, reload state file.
72
+ @~/.claude/commands/mgw/run/execute.md
85
73
 
86
- If state file exists → load it. **Run migrateProjectState() to ensure retry fields exist:**
87
- ```bash
88
- node -e "
89
- const { migrateProjectState } = require('./lib/state.cjs');
90
- migrateProjectState();
91
- " 2>/dev/null || true
92
- ```
74
+ <!-- ═══════════════════════════════════════════════════════════ -->
75
+ <!-- Stage 4: PR-CREATE -->
76
+ <!-- Create PR from artifacts, clean up worktree, post -->
77
+ <!-- completion comment, prompt sync -->
78
+ <!-- ═══════════════════════════════════════════════════════════ -->
93
79
 
94
- Check pipeline_stage:
95
- - "triaged" → proceed to GSD execution
96
- - "planning" / "executing" → resume from where we left off
97
- - "blocked" → "Pipeline for #${ISSUE_NUMBER} is blocked by a stakeholder comment. Review the issue comments, resolve the blocker, then re-run."
98
- - "pr-created" / "done" → "Pipeline already completed for #${ISSUE_NUMBER}. Run /mgw:sync to reconcile."
99
- - "failed" → Check for --retry flag:
100
- - If --retry NOT present:
101
- ```
102
- Pipeline for #${ISSUE_NUMBER} has failed (failure class: ${last_failure_class || "unknown"}).
103
- dead_letter: ${dead_letter}
104
-
105
- To retry: /mgw:run ${ISSUE_NUMBER} --retry
106
- To inspect: /mgw:issue ${ISSUE_NUMBER}
107
- ```
108
- STOP.
109
- - If --retry present and dead_letter === true:
110
- ```bash
111
- # Clear dead_letter and reset retry state via resetRetryState()
112
- node -e "
113
- const { loadActiveIssue } = require('./lib/state.cjs');
114
- const { resetRetryState } = require('./lib/retry.cjs');
115
- const fs = require('fs'), path = require('path');
116
- const activeDir = path.join(process.cwd(), '.mgw', 'active');
117
- const files = fs.readdirSync(activeDir);
118
- const file = files.find(f => f.startsWith('${ISSUE_NUMBER}-') && f.endsWith('.json'));
119
- if (!file) { console.error('No state file for #${ISSUE_NUMBER}'); process.exit(1); }
120
- const filePath = path.join(activeDir, file);
121
- const state = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
122
- const reset = resetRetryState(state);
123
- reset.pipeline_stage = 'triaged';
124
- fs.writeFileSync(filePath, JSON.stringify(reset, null, 2));
125
- console.log('Retry state cleared for #${ISSUE_NUMBER}');
126
- "
127
- # Remove pipeline-failed label
128
- gh issue edit ${ISSUE_NUMBER} --remove-label "pipeline-failed" 2>/dev/null || true
129
- ```
130
- Log: "MGW: dead_letter cleared for #${ISSUE_NUMBER} via --retry flag. Re-queuing."
131
- Continue pipeline (treat as triaged).
132
- - If --retry present and dead_letter !== true (manual retry of non-dead-lettered failure):
133
- ```bash
134
- node -e "
135
- const { resetRetryState } = require('./lib/retry.cjs');
136
- const fs = require('fs'), path = require('path');
137
- const activeDir = path.join(process.cwd(), '.mgw', 'active');
138
- const files = fs.readdirSync(activeDir);
139
- const file = files.find(f => f.startsWith('${ISSUE_NUMBER}-') && f.endsWith('.json'));
140
- if (!file) { console.error('No state file'); process.exit(1); }
141
- const filePath = path.join(activeDir, file);
142
- const state = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
143
- const reset = resetRetryState(state);
144
- reset.pipeline_stage = 'triaged';
145
- fs.writeFileSync(filePath, JSON.stringify(reset, null, 2));
146
- console.log('Retry state reset for #${ISSUE_NUMBER}');
147
- "
148
- gh issue edit ${ISSUE_NUMBER} --remove-label "pipeline-failed" 2>/dev/null || true
149
- ```
150
- Continue pipeline.
151
- - "needs-info" → Check for --force flag in $ARGUMENTS:
152
- If --force NOT present:
153
- ```
154
- Pipeline for #${ISSUE_NUMBER} is blocked by triage gate (needs-info).
155
- The issue requires more detail before execution can begin.
156
-
157
- To override: /mgw:run ${ISSUE_NUMBER} --force
158
- To review: /mgw:issue ${ISSUE_NUMBER} (re-triage after updating the issue)
159
- ```
160
- STOP.
161
- If --force present:
162
- Log warning: "MGW: WARNING — Overriding needs-info gate for #${ISSUE_NUMBER}. Proceeding with --force."
163
- Update state: pipeline_stage = "triaged", add override_log entry.
164
- Continue pipeline.
165
- - "needs-security-review" → Check for --security-ack flag in $ARGUMENTS:
166
- If --security-ack NOT present:
167
- ```
168
- Pipeline for #${ISSUE_NUMBER} requires security review.
169
- This issue was flagged as high security risk during triage.
170
-
171
- To acknowledge and proceed: /mgw:run ${ISSUE_NUMBER} --security-ack
172
- To review: /mgw:issue ${ISSUE_NUMBER} (re-triage)
173
- ```
174
- STOP.
175
- If --security-ack present:
176
- Log warning: "MGW: WARNING — Acknowledging security risk for #${ISSUE_NUMBER}. Proceeding with --security-ack."
177
- Update state: pipeline_stage = "triaged", add override_log entry.
178
- Continue pipeline.
179
-
180
- **Route selection via gsd-adapter (runs after loading issue state):**
181
-
182
- Use `selectGsdRoute()` from `lib/gsd-adapter.cjs` to determine the GSD execution
183
- path. This centralizes the routing decision so it is auditable and consistent
184
- across all pipeline commands:
185
-
186
- ```bash
187
- GSD_ROUTE=$(node -e "
188
- const { selectGsdRoute } = require('./lib/gsd-adapter.cjs');
189
- const issue = $(cat ${REPO_ROOT}/.mgw/active/${STATE_FILE});
190
- const { loadProjectState } = require('./lib/state.cjs');
191
- const projectState = loadProjectState() || {};
192
- const route = selectGsdRoute(issue, projectState);
193
- console.log(route);
194
- ")
195
- # GSD_ROUTE is one of: quick | plan-phase | diagnose | execute-only | verify-only
196
- ```
197
-
198
- **Cross-milestone detection (runs after loading issue state):**
199
-
200
- Check if this issue belongs to a non-active GSD milestone:
201
-
202
- ```bash
203
- CROSS_MILESTONE_WARN=$(node -e "
204
- const { loadProjectState, resolveActiveMilestoneIndex } = require('./lib/state.cjs');
205
- const state = loadProjectState();
206
- if (!state) { console.log('none'); process.exit(0); }
207
-
208
- const activeGsdId = state.active_gsd_milestone;
209
-
210
- // Find this issue's milestone in project.json
211
- const issueNum = ${ISSUE_NUMBER};
212
- let issueMilestone = null;
213
- for (const m of (state.milestones || [])) {
214
- if ((m.issues || []).some(i => i.github_number === issueNum)) {
215
- issueMilestone = m;
216
- break;
217
- }
218
- }
219
-
220
- if (!issueMilestone) { console.log('none'); process.exit(0); }
221
-
222
- const issueGsdId = issueMilestone.gsd_milestone_id;
223
-
224
- // No active_gsd_milestone set (legacy schema): no warning
225
- if (!activeGsdId) { console.log('none'); process.exit(0); }
226
-
227
- // Issue is in the active milestone: no warning
228
- if (issueGsdId === activeGsdId) { console.log('none'); process.exit(0); }
229
-
230
- // Issue is in a different milestone
231
- const gsdRoute = '${GSD_ROUTE}';
232
- if (gsdRoute === 'quick' || gsdRoute === 'gsd:quick') {
233
- console.log('isolation:' + issueMilestone.name + ':' + (issueGsdId || 'unlinked'));
234
- } else {
235
- console.log('warn:' + issueMilestone.name + ':' + (issueGsdId || 'unlinked') + ':' + activeGsdId);
236
- }
237
- ")
238
-
239
- case "$CROSS_MILESTONE_WARN" in
240
- none)
241
- # No cross-milestone issue — proceed normally
242
- ;;
243
- isolation:*)
244
- MILESTONE_NAME=$(echo "$CROSS_MILESTONE_WARN" | cut -d':' -f2)
245
- GSD_ID=$(echo "$CROSS_MILESTONE_WARN" | cut -d':' -f3)
246
-
247
- # Re-validate route against live GitHub labels (project.json may be stale from triage time)
248
- LIVE_LABELS=$(gh issue view ${ISSUE_NUMBER} --json labels --jq '[.labels[].name] | join(",")' 2>/dev/null || echo "")
249
- QUICK_CONFIRMED=false
250
- if echo "$LIVE_LABELS" | grep -qiE "gsd-route:quick|gsd:quick|quick"; then
251
- QUICK_CONFIRMED=true
252
- fi
253
-
254
- if [ "$QUICK_CONFIRMED" = "true" ]; then
255
- echo ""
256
- echo "NOTE: Issue #${ISSUE_NUMBER} belongs to milestone '${MILESTONE_NAME}' (GSD: ${GSD_ID})"
257
- echo " Confirmed gsd:quick via live labels — running in isolation."
258
- echo ""
259
- else
260
- # Route mismatch: project.json says quick but labels don't confirm it
261
- echo ""
262
- echo "⚠️ Route mismatch for cross-milestone issue #${ISSUE_NUMBER}:"
263
- echo " project.json route: quick (set at triage time)"
264
- echo " Live GitHub labels: ${LIVE_LABELS:-none}"
265
- echo " Labels do not confirm gsd:quick — treating as plan-phase (requires milestone context)."
266
- echo ""
267
- echo "Options:"
268
- echo " 1) Switch active milestone to '${GSD_ID}' and continue"
269
- echo " 2) Re-triage this issue (/mgw:issue ${ISSUE_NUMBER}) to update its route"
270
- echo " 3) Abort"
271
- echo ""
272
- read -p "Choice [1/2/3]: " ROUTE_MISMATCH_CHOICE
273
- case "$ROUTE_MISMATCH_CHOICE" in
274
- 1)
275
- node -e "
276
- const { loadProjectState, writeProjectState } = require('./lib/state.cjs');
277
- const state = loadProjectState();
278
- state.active_gsd_milestone = '${GSD_ID}';
279
- writeProjectState(state);
280
- console.log('Switched active_gsd_milestone to: ${GSD_ID}');
281
- "
282
- # Validate ROADMAP.md matches (same check as option 1 in warn case)
283
- ROADMAP_VALID=$(python3 -c "
284
- import os
285
- if not os.path.exists('.planning/ROADMAP.md'):
286
- print('missing')
287
- else:
288
- with open('.planning/ROADMAP.md') as f:
289
- content = f.read()
290
- print('match' if '${GSD_ID}' in content else 'mismatch')
291
- " 2>/dev/null || echo "missing")
292
- if [ "$ROADMAP_VALID" != "match" ]; then
293
- node -e "
294
- const { loadProjectState, writeProjectState } = require('./lib/state.cjs');
295
- const state = loadProjectState();
296
- state.active_gsd_milestone = '$(echo "$CROSS_MILESTONE_WARN" | cut -d':' -f4)';
297
- writeProjectState(state);
298
- " 2>/dev/null || true
299
- echo "Switch rolled back — ROADMAP.md does not match '${GSD_ID}'."
300
- echo "Run /gsd:new-milestone to update ROADMAP.md first."
301
- exit 0
302
- fi
303
- ;;
304
- 2)
305
- echo "Re-triage with: /mgw:issue ${ISSUE_NUMBER}"
306
- exit 0
307
- ;;
308
- *)
309
- echo "Aborted."
310
- exit 0
311
- ;;
312
- esac
313
- fi
314
- ;;
315
- warn:*)
316
- ISSUE_MILESTONE=$(echo "$CROSS_MILESTONE_WARN" | cut -d':' -f2)
317
- ISSUE_GSD=$(echo "$CROSS_MILESTONE_WARN" | cut -d':' -f3)
318
- ACTIVE_GSD=$(echo "$CROSS_MILESTONE_WARN" | cut -d':' -f4)
319
- echo ""
320
- echo "⚠️ Cross-milestone issue detected:"
321
- echo " Issue #${ISSUE_NUMBER} belongs to: '${ISSUE_MILESTONE}' (GSD: ${ISSUE_GSD})"
322
- echo " Active GSD milestone: ${ACTIVE_GSD}"
323
- echo ""
324
- echo "This issue requires plan-phase work that depends on ROADMAP.md context."
325
- echo "Running it against the wrong active milestone may produce incorrect plans."
326
- echo ""
327
- echo "Options:"
328
- echo " 1) Switch active milestone to '${ISSUE_GSD}' and continue"
329
- echo " 2) Continue anyway (not recommended)"
330
- echo " 3) Abort — run /gsd:new-milestone to set up the correct milestone first"
331
- echo ""
332
- read -p "Choice [1/2/3]: " MILESTONE_CHOICE
333
- case "$MILESTONE_CHOICE" in
334
- 1)
335
- node -e "
336
- const { loadProjectState, writeProjectState } = require('./lib/state.cjs');
337
- const state = loadProjectState();
338
- state.active_gsd_milestone = '${ISSUE_GSD}';
339
- writeProjectState(state);
340
- console.log('Switched active_gsd_milestone to: ${ISSUE_GSD}');
341
- "
342
- # Validate ROADMAP.md matches the new active milestone
343
- ROADMAP_VALID=$(python3 -c "
344
- import os
345
- if not os.path.exists('.planning/ROADMAP.md'):
346
- print('missing')
347
- else:
348
- with open('.planning/ROADMAP.md') as f:
349
- content = f.read()
350
- print('match' if '${ISSUE_GSD}' in content else 'mismatch')
351
- " 2>/dev/null || echo "missing")
352
- if [ "$ROADMAP_VALID" = "match" ]; then
353
- echo "Active milestone updated. ROADMAP.md confirmed for '${ISSUE_GSD}'."
354
- else
355
- # Roll back — ROADMAP.md doesn't match
356
- node -e "
357
- const { loadProjectState, writeProjectState } = require('./lib/state.cjs');
358
- const state = loadProjectState();
359
- state.active_gsd_milestone = '${ACTIVE_GSD}';
360
- writeProjectState(state);
361
- " 2>/dev/null || true
362
- echo "Switch rolled back — ROADMAP.md does not match '${ISSUE_GSD}'."
363
- echo "Run /gsd:new-milestone to update ROADMAP.md first."
364
- exit 0
365
- fi
366
- ;;
367
- 2)
368
- echo "Proceeding with cross-milestone issue (may affect plan quality)."
369
- ;;
370
- *)
371
- echo "Aborted. Run /gsd:new-milestone then /mgw:project to align milestones."
372
- exit 0
373
- ;;
374
- esac
375
- ;;
376
- esac
377
- ```
378
- </step>
379
-
380
- <step name="create_worktree">
381
- **Create isolated worktree for issue work:**
382
-
383
- Derive branch and worktree path:
384
- ```bash
385
- BRANCH_NAME="issue/${ISSUE_NUMBER}-${slug}"
386
- WORKTREE_DIR="${REPO_ROOT}/.worktrees/${BRANCH_NAME}"
387
- ```
388
-
389
- Ensure .worktrees/ is gitignored:
390
- ```bash
391
- mkdir -p "$(dirname "${WORKTREE_DIR}")"
392
- if ! git check-ignore -q .worktrees 2>/dev/null; then
393
- echo ".worktrees/" >> "${REPO_ROOT}/.gitignore"
394
- fi
395
- ```
396
-
397
- Create worktree with feature branch:
398
- ```bash
399
- # If worktree already exists (resume in same session), skip creation
400
- if [ -d "${WORKTREE_DIR}" ]; then
401
- echo "Worktree exists, reusing"
402
- # If branch already exists (resume from prior session)
403
- elif git show-ref --verify --quiet "refs/heads/${BRANCH_NAME}"; then
404
- git worktree add "${WORKTREE_DIR}" "${BRANCH_NAME}"
405
- # New branch (first run)
406
- else
407
- git worktree add "${WORKTREE_DIR}" -b "${BRANCH_NAME}"
408
- fi
409
- ```
410
-
411
- **Switch working directory to worktree:**
412
- ```bash
413
- cd "${WORKTREE_DIR}"
414
- ```
415
-
416
- Update state (at `${REPO_ROOT}/.mgw/active/`): add branch to linked_branches.
417
- Add cross-ref (at `${REPO_ROOT}/.mgw/cross-refs.json`): issue → branch.
418
-
419
- **Apply in-progress label:**
420
- ```bash
421
- remove_mgw_labels_and_apply ${ISSUE_NUMBER} "mgw:in-progress"
422
- ```
423
-
424
- **PATH CONVENTION for remaining steps:**
425
- - File operations, git commands, and agent work use **relative paths** (CWD = worktree)
426
- - `.mgw/` state operations use **absolute paths**: `${REPO_ROOT}/.mgw/`
427
- (`.mgw/` is gitignored — it only exists in the main repo, not the worktree)
428
- </step>
429
-
430
- <step name="preflight_comment_check">
431
- **Pre-flight comment check — detect new comments since triage:**
432
-
433
- Before GSD execution begins, check if new comments have been posted on the issue
434
- since triage. This prevents executing against a stale plan when stakeholders have
435
- posted material changes, blockers, or scope updates.
436
-
437
- ```bash
438
- # Fetch current comment count from GitHub
439
- CURRENT_COMMENTS=$(gh issue view $ISSUE_NUMBER --json comments --jq '.comments | length' 2>/dev/null || echo "0")
440
- STORED_COMMENTS="${triage.last_comment_count}" # From state file
441
-
442
- # If stored count is missing (pre-comment-tracking state), skip check
443
- if [ -z "$STORED_COMMENTS" ] || [ "$STORED_COMMENTS" = "null" ] || [ "$STORED_COMMENTS" = "0" ]; then
444
- STORED_COMMENTS=0
445
- fi
446
- ```
447
-
448
- If new comments detected (`CURRENT_COMMENTS > STORED_COMMENTS`):
449
-
450
- 1. **Fetch new comment bodies:**
451
- ```bash
452
- NEW_COUNT=$(($CURRENT_COMMENTS - $STORED_COMMENTS))
453
- NEW_COMMENTS=$(gh issue view $ISSUE_NUMBER --json comments \
454
- --jq "[.comments[-${NEW_COUNT}:]] | .[] | {author: .author.login, body: .body, createdAt: .createdAt}" 2>/dev/null)
455
- ```
456
-
457
- 2. **Spawn classification agent:**
458
- ```
459
- Task(
460
- prompt="
461
- <files_to_read>
462
- - ./CLAUDE.md (Project instructions — if exists, follow all guidelines)
463
- </files_to_read>
464
-
465
- Classify new comments on GitHub issue #${ISSUE_NUMBER}.
466
-
467
- <issue_context>
468
- Title: ${issue_title}
469
- Current pipeline stage: ${pipeline_stage}
470
- GSD Route: ${gsd_route}
471
- Triage scope: ${triage.scope}
472
- </issue_context>
473
-
474
- <new_comments>
475
- ${NEW_COMMENTS}
476
- </new_comments>
477
-
478
- <classification_rules>
479
- Classify each comment (and the overall batch) into ONE of:
480
-
481
- - **material** — Comment changes scope, requirements, acceptance criteria, or design.
482
- Examples: 'Actually we also need to handle X', 'Changed the requirement to Y',
483
- 'Don't forget about edge case Z'.
484
-
485
- - **informational** — Status update, acknowledgment, question that doesn't change scope, +1.
486
- Examples: 'Looks good', 'Thanks for picking this up', 'What's the ETA?', '+1'.
487
-
488
- - **blocking** — Explicit instruction to stop or wait. Must contain clear hold language.
489
- Examples: 'Don't work on this yet', 'Hold off', 'Blocked by external dependency',
490
- 'Wait for design review'.
491
-
492
- If ANY comment in the batch is blocking, overall classification is blocking.
493
- If ANY comment is material (and none blocking), overall classification is material.
494
- Otherwise, informational.
495
- </classification_rules>
496
-
497
- <output_format>
498
- Return ONLY valid JSON:
499
- {
500
- \"classification\": \"material|informational|blocking\",
501
- \"reasoning\": \"Brief explanation of why this classification was chosen\",
502
- \"new_requirements\": [\"list of new requirements if material, empty array otherwise\"],
503
- \"blocking_reason\": \"reason if blocking, empty string otherwise\"
504
- }
505
- </output_format>
506
- ",
507
- subagent_type="general-purpose",
508
- description="Classify comments on #${ISSUE_NUMBER}"
509
- )
510
- ```
511
-
512
- 3. **React based on classification:**
513
-
514
- | Classification | Action |
515
- |---------------|--------|
516
- | **informational** | Log: "MGW: ${NEW_COUNT} new comment(s) reviewed — informational, continuing." Update `triage.last_comment_count` in state file. Continue pipeline. |
517
- | **material** | Log: "MGW: Material comment(s) detected — scope may have changed." Update state: add new_requirements to triage context. Update `triage.last_comment_count`. Re-read issue body for updated requirements. Continue with enriched context (pass new_requirements to planner). Check for security keywords in material comments (see below). |
518
- | **blocking** | Log: "MGW: Blocking comment detected — pipeline paused." Update state: `pipeline_stage = "blocked"`. Apply mgw:blocked label. Post comment on issue: `> **MGW** . \`pipeline-blocked\` . Blocked by stakeholder comment. Reason: ${blocking_reason}`. Stop pipeline execution. |
519
-
520
- **Security keyword check for material comments:**
521
- ```bash
522
- SECURITY_KEYWORDS="security|vulnerability|CVE|exploit|injection|XSS|CSRF|auth bypass"
523
- if echo "$NEW_COMMENTS" | grep -qiE "$SECURITY_KEYWORDS"; then
524
- # Add warning to gate_result and prompt user
525
- echo "MGW: Security-related comment detected. Re-triage recommended."
526
- # Prompt: "Security-related comment detected. Re-triage recommended. Continue or re-triage?"
527
- fi
528
- ```
529
-
530
- **When blocking comment detected — apply label:**
531
- ```bash
532
- remove_mgw_labels_and_apply ${ISSUE_NUMBER} "mgw:blocked"
533
- ```
534
-
535
- If no new comments detected, continue normally.
536
- </step>
537
-
538
- <step name="post_triage_update">
539
- **Post work-starting comment on issue:**
540
-
541
- Note: The triage gate evaluation and triage-complete/triage-blocked comment are now
542
- posted IMMEDIATELY during /mgw:issue. This step posts a separate work-starting
543
- notification when pipeline execution actually begins in run.md.
544
-
545
- Gather enrichment data from triage state:
546
- ```bash
547
- SCOPE_SIZE="${triage.scope.size}" # small|medium|large
548
- FILE_COUNT="${triage.scope.file_count}"
549
- SYSTEM_LIST="${triage.scope.systems}"
550
- FILE_LIST="${triage.scope.files}"
551
- CONFLICTS="${triage.conflicts}"
552
- ROUTE_REASONING="${triage.route_reasoning}"
553
- TIMESTAMP=$(node -e "try{process.stdout.write(require('./lib/gsd-adapter.cjs').getTimestamp())}catch(e){process.stdout.write(new Date().toISOString().replace(/\\.\\d{3}Z$/,'Z'))}")
554
-
555
- # Load milestone/phase context from project.json if available
556
- MILESTONE_CONTEXT=""
557
- if [ -f "${REPO_ROOT}/.mgw/project.json" ]; then
558
- MILESTONE_CONTEXT=$(node -e "
559
- const { loadProjectState, resolveActiveMilestoneIndex } = require('./lib/state.cjs');
560
- const state = loadProjectState();
561
- if (!state) process.exit(0);
562
- // Search all milestones for the issue (not just active) to handle cross-milestone lookups
563
- for (const m of (state.milestones || [])) {
564
- for (const i of (m.issues || [])) {
565
- if (i.github_number === ${ISSUE_NUMBER}) {
566
- console.log('Milestone: ' + m.name + ' | Phase ' + i.phase_number + ': ' + i.phase_name);
567
- process.exit(0);
568
- }
569
- }
570
- }
571
- " 2>/dev/null || echo "")
572
- fi
573
- ```
574
-
575
- Post the work-starting comment directly (no sub-agent — guarantees it happens):
576
-
577
- ```bash
578
- WORK_STARTING_BODY=$(cat <<COMMENTEOF
579
- > **MGW** · \`work-starting\` · ${TIMESTAMP}
580
- > ${MILESTONE_CONTEXT}
581
-
582
- ### Work Starting
583
-
584
- | | |
585
- |---|---|
586
- | **Route** | \`${gsd_route}\` — ${ROUTE_REASONING} |
587
- | **Scope** | ${SCOPE_SIZE} — ${FILE_COUNT} files across ${SYSTEM_LIST} |
588
- | **Conflicts** | ${CONFLICTS} |
589
-
590
- Work begins on branch \`${BRANCH_NAME}\`.
591
-
592
- <details>
593
- <summary>Affected Files</summary>
594
-
595
- ${FILE_LIST as bullet points}
596
-
597
- </details>
598
- COMMENTEOF
599
- )
600
-
601
- gh issue comment ${ISSUE_NUMBER} --body "$WORK_STARTING_BODY" 2>/dev/null || true
602
- ```
603
-
604
- Log comment in state file (at `${REPO_ROOT}/.mgw/active/`).
605
- </step>
606
-
607
- <step name="execute_gsd_quick">
608
- **Execute GSD pipeline (quick / quick --full route):**
609
-
610
- Only run this step if gsd_route is "gsd:quick" or "gsd:quick --full".
611
-
612
- **Retry loop initialization:**
613
- ```bash
614
- # Load retry state from .mgw/active/ state file
615
- RETRY_COUNT=$(node -e "
616
- const { loadActiveIssue } = require('./lib/state.cjs');
617
- const state = loadActiveIssue(${ISSUE_NUMBER});
618
- console.log((state && typeof state.retry_count === 'number') ? state.retry_count : 0);
619
- " 2>/dev/null || echo "0")
620
- EXECUTION_SUCCEEDED=false
621
- ```
622
-
623
- **Begin retry loop** — wraps the GSD quick execution (steps 1–11 below) with transient-failure retry:
624
-
625
- ```
626
- RETRY_LOOP:
627
- while canRetry(issue_state) AND NOT EXECUTION_SUCCEEDED:
628
- ```
629
-
630
- Update pipeline_stage to "executing" in state file (at `${REPO_ROOT}/.mgw/active/`).
631
-
632
- Determine flags:
633
- - "gsd:quick" → $QUICK_FLAGS = ""
634
- - "gsd:quick --full" → $QUICK_FLAGS = "--full"
635
-
636
- Read the issue description to use as the GSD task description (full body, capped at 5000 chars for pathological issues):
637
- ```
638
- $TASK_DESCRIPTION = "Issue #${ISSUE_NUMBER}: ${issue_title}\n\n${issue_body}" # full body, max 5000 chars
639
- ```
640
-
641
- Execute the GSD quick workflow. Read and follow the quick workflow steps:
642
-
643
- 1. **Init:** `node ~/.claude/get-shit-done/bin/gsd-tools.cjs init quick "$DESCRIPTION"`
644
- Parse JSON for: planner_model, executor_model, checker_model, verifier_model, next_num, slug, date, quick_dir, task_dir.
645
-
646
- **Handle missing .planning/:** Check `roadmap_exists` from init output. If false, do NOT
647
- create GSD state files — .planning/ is owned by GSD. Only create the quick task
648
- directory (GSD agents need it to store plans/summaries):
649
- ```bash
650
- if [ "$roadmap_exists" = "false" ]; then
651
- echo "NOTE: No .planning/ directory found. GSD manages its own state files."
652
- echo " To create a ROADMAP.md, run /gsd:new-milestone after this pipeline."
653
- mkdir -p .planning/quick
654
- fi
655
- ```
656
- MGW never writes config.json, ROADMAP.md, or STATE.md — those are GSD-owned files.
657
-
658
- 2. **Create task directory:**
659
- ```bash
660
- QUICK_DIR=".planning/quick/${next_num}-${slug}"
661
- mkdir -p "$QUICK_DIR"
662
- ```
663
-
664
- 3. **Spawn planner (task agent):**
665
- ```
666
- Task(
667
- prompt="
668
- <planning_context>
669
-
670
- **Mode:** ${FULL_MODE ? 'quick-full' : 'quick'}
671
- **Directory:** ${QUICK_DIR}
672
- **Description:** ${TASK_DESCRIPTION}
673
-
674
- <triage_context>
675
- Scope: ${triage.scope.files} files across systems: ${triage.scope.systems}
676
- Validity: ${triage.validity}
677
- Security: ${triage.security_notes}
678
- Conflicts: ${triage.conflicts}
679
- GSD Route: ${gsd_route}
680
- </triage_context>
681
-
682
- <issue_comments>
683
- ${recent_comments}
684
- </issue_comments>
685
-
686
- <files_to_read>
687
- - ./CLAUDE.md (Project instructions — if exists, follow all guidelines)
688
- - .agents/skills/ (Project skills — if dir exists, list skills, read SKILL.md for each, follow relevant rules)
689
- </files_to_read>
690
-
691
- </planning_context>
692
-
693
- <constraints>
694
- - Create a SINGLE plan with 1-3 focused tasks
695
- - Quick tasks should be atomic and self-contained
696
- - No research phase
697
- ${FULL_MODE ? '- Target ~40% context usage (structured for verification)' : '- Target ~30% context usage (simple, focused)'}
698
- ${FULL_MODE ? '- MUST generate must_haves in plan frontmatter (truths, artifacts, key_links)' : ''}
699
- ${FULL_MODE ? '- Each task MUST have files, action, verify, done fields' : ''}
700
- </constraints>
701
-
702
- <output>
703
- Write plan to: ${QUICK_DIR}/${next_num}-PLAN.md
704
- Return: ## PLANNING COMPLETE with plan path
705
- </output>
706
- ",
707
- subagent_type="gsd-planner",
708
- model="{planner_model}",
709
- description="Plan: ${issue_title}"
710
- )
711
- ```
712
-
713
- 4. **Verify plan exists** at `${QUICK_DIR}/${next_num}-PLAN.md`
714
-
715
- 5. **Pre-flight plan structure check (gsd-tools):**
716
- ```bash
717
- PLAN_CHECK=$(node ~/.claude/get-shit-done/bin/gsd-tools.cjs verify plan-structure "${QUICK_DIR}/${next_num}-PLAN.md")
718
- ```
719
- Parse the JSON result. If structural issues found, include them in the plan-checker prompt below so it has concrete problems to evaluate rather than searching from scratch.
720
-
721
- 6. **(If --full) Spawn plan-checker, handle revision loop (max 2 iterations):**
722
- ```
723
- Task(
724
- prompt="
725
- <files_to_read>
726
- - ./CLAUDE.md (Project instructions — if exists, follow all guidelines)
727
- - .agents/skills/ (Project skills — if dir exists, list skills, read SKILL.md for each, follow relevant rules)
728
- - ${QUICK_DIR}/${next_num}-PLAN.md (Plan to verify)
729
- </files_to_read>
730
-
731
- <verification_context>
732
- **Mode:** quick-full
733
- **Task Description:** ${TASK_DESCRIPTION}
734
-
735
- <structural_preflight>
736
- ${PLAN_CHECK}
737
- </structural_preflight>
738
-
739
- **Scope:** This is a quick task, not a full phase. Skip checks that require a ROADMAP phase goal. If structural_preflight flagged issues, prioritize evaluating those.
740
- </verification_context>
741
-
742
- <check_dimensions>
743
- - Requirement coverage: Does the plan address the task description?
744
- - Task completeness: Do tasks have files, action, verify, done fields?
745
- - Key links: Are referenced files real?
746
- - Scope sanity: Is this appropriately sized for a quick task (1-3 tasks)?
747
- - must_haves derivation: Are must_haves traceable to the task description?
748
-
749
- Skip: context compliance (no CONTEXT.md), cross-plan deps (single plan), ROADMAP alignment
750
- </check_dimensions>
751
-
752
- <expected_output>
753
- - ## VERIFICATION PASSED — all checks pass
754
- - ## ISSUES FOUND — structured issue list
755
- </expected_output>
756
- ",
757
- subagent_type="gsd-plan-checker",
758
- model="{checker_model}",
759
- description="Check quick plan: ${issue_title}"
760
- )
761
- ```
762
-
763
- If issues found and iteration < 2: spawn planner revision, then re-check.
764
- If iteration >= 2: offer force proceed or abort.
765
-
766
- 7. **Spawn executor (task agent):**
767
- ```
768
- Task(
769
- prompt="
770
- <files_to_read>
771
- - ./CLAUDE.md (Project instructions — if exists, follow all guidelines)
772
- - .agents/skills/ (Project skills — if dir exists, list skills, read SKILL.md for each, follow relevant rules)
773
- - ${QUICK_DIR}/${next_num}-PLAN.md (Plan)
774
- </files_to_read>
775
-
776
- Execute quick task ${next_num}.
777
-
778
- <constraints>
779
- - Execute all tasks in the plan
780
- - Commit each task atomically
781
- - Create summary at: ${QUICK_DIR}/${next_num}-SUMMARY.md
782
- - Do NOT update ROADMAP.md or STATE.md (GSD owns .planning/ files)
783
- </constraints>
784
- ",
785
- subagent_type="gsd-executor",
786
- model="{executor_model}",
787
- description="Execute: ${issue_title}"
788
- )
789
- ```
790
-
791
- 8. **Verify summary (gsd-tools):**
792
- ```bash
793
- VERIFY_RESULT=$(node ~/.claude/get-shit-done/bin/gsd-tools.cjs verify-summary "${QUICK_DIR}/${next_num}-SUMMARY.md")
794
- ```
795
- Parse JSON result. Use `passed` field for go/no-go. Checks summary existence, files created, and commits.
796
-
797
- 9. **(If --full) Spawn verifier:**
798
- ```
799
- Task(
800
- prompt="
801
- <files_to_read>
802
- - ./CLAUDE.md (Project instructions — if exists, follow all guidelines)
803
- - .agents/skills/ (Project skills — if dir exists, list skills, read SKILL.md for each, follow relevant rules)
804
- - ${QUICK_DIR}/${next_num}-PLAN.md (Plan)
805
- </files_to_read>
806
-
807
- Verify quick task goal achievement.
808
- Task directory: ${QUICK_DIR}
809
- Task goal: ${TASK_DESCRIPTION}
810
-
811
- Check must_haves against actual codebase. Create VERIFICATION.md at ${QUICK_DIR}/${next_num}-VERIFICATION.md.",
812
- subagent_type="gsd-verifier",
813
- model="{verifier_model}",
814
- description="Verify: ${issue_title}"
815
- )
816
- ```
817
-
818
- 10. **Post-execution artifact verification (non-blocking):**
819
- ```bash
820
- ARTIFACT_CHECK=$(node ~/.claude/get-shit-done/bin/gsd-tools.cjs verify artifacts "${QUICK_DIR}/${next_num}-PLAN.md" 2>/dev/null || echo '{"passed":true}')
821
- KEYLINK_CHECK=$(node ~/.claude/get-shit-done/bin/gsd-tools.cjs verify key-links "${QUICK_DIR}/${next_num}-PLAN.md" 2>/dev/null || echo '{"passed":true}')
822
- ```
823
- Non-blocking: if either check flags issues, include them in the PR description as warnings. Do not halt the pipeline.
824
-
825
- 11. **Commit artifacts:**
826
- ```bash
827
- node ~/.claude/get-shit-done/bin/gsd-tools.cjs commit "docs(quick-${next_num}): ${issue_title}" --files ${file_list}
828
- ```
829
-
830
- Update state (at `${REPO_ROOT}/.mgw/active/`): gsd_artifacts.path = $QUICK_DIR, pipeline_stage = "verifying".
831
-
832
- **Retry loop — on execution failure:**
833
-
834
- If any step above fails (executor or verifier agent returns error, summary missing, etc.), capture the error and apply retry logic:
835
-
836
- ```bash
837
- # On failure — classify and decide whether to retry
838
- FAILURE_CLASS=$(node -e "
839
- const { classifyFailure, canRetry, incrementRetry, getBackoffMs } = require('./lib/retry.cjs');
840
- const { loadActiveIssue } = require('./lib/state.cjs');
841
- const fs = require('fs'), path = require('path');
842
-
843
- const activeDir = path.join(process.cwd(), '.mgw', 'active');
844
- const files = fs.readdirSync(activeDir);
845
- const file = files.find(f => f.startsWith('${ISSUE_NUMBER}-') && f.endsWith('.json'));
846
- const filePath = path.join(activeDir, file);
847
- let issueState = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
848
-
849
- // Classify the failure from the error context
850
- const error = { message: '${EXECUTION_ERROR_MESSAGE}' };
851
- const result = classifyFailure(error);
852
- console.error('Failure classified as: ' + result.class + ' — ' + result.reason);
853
-
854
- // Persist failure class to state
855
- issueState.last_failure_class = result.class;
856
-
857
- if (result.class === 'transient' && canRetry(issueState)) {
858
- const backoff = getBackoffMs(issueState.retry_count || 0);
859
- issueState = incrementRetry(issueState);
860
- fs.writeFileSync(filePath, JSON.stringify(issueState, null, 2));
861
- // Output: backoff ms so shell can sleep
862
- console.log('retry:' + backoff + ':' + result.class);
863
- } else {
864
- // Permanent failure or retries exhausted — dead-letter
865
- issueState.dead_letter = true;
866
- fs.writeFileSync(filePath, JSON.stringify(issueState, null, 2));
867
- console.log('dead_letter:' + result.class);
868
- }
869
- ")
870
-
871
- case "$FAILURE_CLASS" in
872
- retry:*)
873
- BACKOFF_MS=$(echo "$FAILURE_CLASS" | cut -d':' -f2)
874
- BACKOFF_SEC=$(( (BACKOFF_MS + 999) / 1000 ))
875
- echo "MGW: Transient failure detected — retrying in ${BACKOFF_SEC}s (retry ${RETRY_COUNT})..."
876
- sleep "$BACKOFF_SEC"
877
- RETRY_COUNT=$((RETRY_COUNT + 1))
878
- # Loop back to retry
879
- ;;
880
- dead_letter:*)
881
- FAILURE_CLASS_NAME=$(echo "$FAILURE_CLASS" | cut -d':' -f2)
882
- EXECUTION_SUCCEEDED=false
883
- # Break out of retry loop — handled in post_execution_update
884
- break
885
- ;;
886
- esac
887
- ```
888
-
889
- On successful execution (EXECUTION_SUCCEEDED=true): break out of retry loop, clear last_failure_class:
890
- ```bash
891
- node -e "
892
- const fs = require('fs'), path = require('path');
893
- const activeDir = path.join(process.cwd(), '.mgw', 'active');
894
- const files = fs.readdirSync(activeDir);
895
- const file = files.find(f => f.startsWith('${ISSUE_NUMBER}-') && f.endsWith('.json'));
896
- const filePath = path.join(activeDir, file);
897
- const state = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
898
- state.last_failure_class = null;
899
- fs.writeFileSync(filePath, JSON.stringify(state, null, 2));
900
- " 2>/dev/null || true
901
- ```
902
- </step>
903
-
904
- <step name="execute_gsd_milestone">
905
- **Execute GSD pipeline (new-milestone route):**
906
-
907
- Only run this step if gsd_route is "gsd:new-milestone".
908
-
909
- **Retry loop initialization** (same pattern as execute_gsd_quick):
910
- ```bash
911
- RETRY_COUNT=$(node -e "
912
- const { loadActiveIssue } = require('./lib/state.cjs');
913
- const state = loadActiveIssue(${ISSUE_NUMBER});
914
- console.log((state && typeof state.retry_count === 'number') ? state.retry_count : 0);
915
- " 2>/dev/null || echo "0")
916
- EXECUTION_SUCCEEDED=false
917
- ```
918
-
919
- **Begin retry loop** — wraps the phase-execution loop (steps 2b–2e below) with transient-failure retry. Step 2 (milestone roadmap creation) is NOT wrapped in the retry loop — roadmap creation failures are always treated as permanent (require human intervention).
920
-
921
- This is the most complex path. The orchestrator needs to:
922
-
923
- **Resolve models for milestone agents:**
924
- ```bash
925
- PLANNER_MODEL=$(node -e "process.stdout.write(require('./lib/gsd-adapter.cjs').resolveModel('gsd-planner'))")
926
- EXECUTOR_MODEL=$(node -e "process.stdout.write(require('./lib/gsd-adapter.cjs').resolveModel('gsd-executor'))")
927
- VERIFIER_MODEL=$(node -e "process.stdout.write(require('./lib/gsd-adapter.cjs').resolveModel('gsd-verifier'))")
928
- ```
929
-
930
- 1. **Discussion phase trigger for large-scope issues:**
931
-
932
- If the issue was triaged with large scope and `gsd_route == "gsd:new-milestone"`, post
933
- a scope proposal comment and set the discussing stage before proceeding to phase execution:
934
-
935
- ```bash
936
- DISCUSS_TIMESTAMP=$(node -e "try{process.stdout.write(require('./lib/gsd-adapter.cjs').getTimestamp())}catch(e){process.stdout.write(new Date().toISOString().replace(/\\.\\d{3}Z$/,'Z'))}")
937
-
938
- # Build scope breakdown from triage data
939
- SCOPE_SIZE="${triage.scope.size}"
940
- SCOPE_BREAKDOWN="${triage.scope.files formatted as table rows}"
941
- PHASE_COUNT="TBD (determined by roadmapper)"
942
-
943
- # Post scope proposal comment using template from github.md
944
- # Use Scope Proposal Comment template from @~/.claude/commands/mgw/workflows/github.md
945
- ```
946
-
947
- Set pipeline_stage to "discussing" and apply "mgw:discussing" label:
948
- ```bash
949
- remove_mgw_labels_and_apply ${ISSUE_NUMBER} "mgw:discussing"
950
- ```
951
-
952
- Present to user:
953
- ```
954
- AskUserQuestion(
955
- header: "Scope Proposal Posted",
956
- question: "A scope proposal has been posted to GitHub. Proceed with autonomous roadmap creation, or wait for stakeholder feedback?",
957
- options: [
958
- { label: "Proceed", description: "Continue with roadmap creation now" },
959
- { label: "Wait", description: "Pipeline paused until stakeholder approves scope" }
960
- ]
961
- )
962
- ```
963
-
964
- If wait: stop here. User will re-run /mgw:run after scope is approved.
965
- If proceed: apply "mgw:approved" label and continue.
966
-
967
- 2. **Create milestone:** Use `gsd-tools init new-milestone` to gather context, then attempt autonomous roadmap creation from issue data:
968
-
969
- ```bash
970
- MILESTONE_INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.cjs init new-milestone 2>/dev/null)
971
- ```
972
-
973
- Extract requirements from structured issue template fields (BLUF, What's Needed, What's Involved) if present.
974
-
975
- If issue body contains sufficient detail (has clear requirements/scope):
976
- - Spawn roadmapper agent with issue-derived requirements
977
- - After roadmap generation, present to user for confirmation checkpoint:
978
- ```
979
- AskUserQuestion(
980
- header: "Milestone Roadmap Generated",
981
- question: "Review the generated ROADMAP.md. Proceed with execution, revise, or switch to interactive mode?",
982
- followUp: "Enter: proceed, revise, or interactive"
983
- )
984
- ```
985
-
986
- If issue body lacks sufficient detail (no clear structure or too vague):
987
- - Fall back to interactive mode:
988
- ```
989
- The new-milestone route requires more detail than the issue provides.
990
- Please run: /gsd:new-milestone
991
-
992
- After the milestone is created, run /mgw:run ${ISSUE_NUMBER} again to
993
- continue the pipeline through execution.
994
- ```
995
-
996
- Update pipeline_stage to "planning" (at `${REPO_ROOT}/.mgw/active/`).
997
-
998
- 2. **If resuming with pipeline_stage = "planning" and ROADMAP.md exists:**
999
- Discover phases from ROADMAP and run the full per-phase GSD lifecycle:
1000
-
1001
- ```bash
1002
- ROADMAP_ANALYSIS=$(node ~/.claude/get-shit-done/bin/gsd-tools.cjs roadmap analyze)
1003
- # Parse ROADMAP_ANALYSIS JSON for list of phases:
1004
- # Each phase has: phase_number, phase_name, phase_slug
1005
- PHASE_LIST=$(echo "$ROADMAP_ANALYSIS" | python3 -c "
1006
- import json, sys
1007
- data = json.load(sys.stdin)
1008
- for p in data.get('phases', []):
1009
- print(f\"{p['number']}|{p['name']}|{p.get('slug', '')}\")
1010
- ")
1011
- ```
1012
-
1013
- For each phase in order:
1014
-
1015
- **a. Scaffold phase directory, then init:**
1016
-
1017
- `init plan-phase` requires the phase directory to exist before it can locate it.
1018
- Use `scaffold phase-dir` first (which creates the directory from ROADMAP data),
1019
- then call `init plan-phase` to get planner/checker model assignments.
1020
-
1021
- ```bash
1022
- # Generate slug from phase name (lowercase, hyphens, no special chars)
1023
- PHASE_SLUG=$(echo "${PHASE_NAME}" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/--*/-/g' | sed 's/^-//;s/-$//')
1024
-
1025
- # Scaffold creates the directory and returns the path
1026
- SCAFFOLD=$(node ~/.claude/get-shit-done/bin/gsd-tools.cjs scaffold phase-dir --phase "${PHASE_NUMBER}" --name "${PHASE_SLUG}")
1027
- phase_dir=$(echo "$SCAFFOLD" | python3 -c "import json,sys; print(json.load(sys.stdin)['directory'])")
1028
-
1029
- # Now init plan-phase can find the directory for model resolution
1030
- PHASE_INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.cjs init plan-phase "${PHASE_NUMBER}")
1031
- # Parse PHASE_INIT JSON for: planner_model, checker_model
1032
- ```
1033
-
1034
- **b. Spawn planner agent (gsd:plan-phase):**
1035
- ```
1036
- Task(
1037
- prompt="
1038
- <files_to_read>
1039
- - ./CLAUDE.md (Project instructions -- if exists, follow all guidelines)
1040
- - .agents/skills/ (Project skills -- if dir exists, list skills, read SKILL.md for each, follow relevant rules)
1041
- - .planning/ROADMAP.md (Phase definitions and requirements)
1042
- - .planning/STATE.md (If exists -- project state)
1043
- </files_to_read>
1044
-
1045
- You are the GSD planner. Plan phase ${PHASE_NUMBER}: ${PHASE_NAME}.
1046
-
1047
- Read and follow the plan-phase workflow:
1048
- @~/.claude/get-shit-done/workflows/plan-phase.md
1049
-
1050
- Phase directory: ${phase_dir}
1051
- Phase number: ${PHASE_NUMBER}
1052
-
1053
- Create PLAN.md file(s) in the phase directory. Each plan must have:
1054
- - Frontmatter with phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, must_haves
1055
- - Objective, context, tasks, verification, success criteria, output sections
1056
- - Each task with files, action, verify, done fields
1057
-
1058
- Commit the plan files when done.
1059
- ",
1060
- subagent_type="gsd-planner",
1061
- model="${PLANNER_MODEL}",
1062
- description="Plan phase ${PHASE_NUMBER}: ${PHASE_NAME}"
1063
- )
1064
- ```
1065
-
1066
- **c. Verify plans exist:**
1067
- ```bash
1068
- PLAN_COUNT=$(ls ${phase_dir}/*-PLAN.md 2>/dev/null | wc -l)
1069
- if [ "$PLAN_COUNT" -eq 0 ]; then
1070
- echo "ERROR: No plans created for phase ${PHASE_NUMBER}. Skipping phase execution."
1071
- # Post error comment and continue to next phase
1072
- gh issue comment ${ISSUE_NUMBER} --body "> **MGW** \`phase-error\` Phase ${PHASE_NUMBER} planning produced no plans. Skipping." 2>/dev/null || true
1073
- continue
1074
- fi
1075
- ```
1076
-
1077
- **d. Init execute-phase and spawn executor agent (gsd:execute-phase):**
1078
- ```bash
1079
- EXEC_INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.cjs init execute-phase "${PHASE_NUMBER}")
1080
- # Parse EXEC_INIT JSON for: executor_model, verifier_model, phase_dir, plans, incomplete_plans, plan_count
1081
- ```
1082
- ```
1083
- Task(
1084
- prompt="
1085
- <files_to_read>
1086
- - ./CLAUDE.md (Project instructions -- if exists, follow all guidelines)
1087
- - .agents/skills/ (Project skills -- if dir exists, list skills, read SKILL.md for each, follow relevant rules)
1088
- - ${phase_dir}/*-PLAN.md (Plans to execute)
1089
- </files_to_read>
1090
-
1091
- You are the GSD executor. Execute all plans for phase ${PHASE_NUMBER}: ${PHASE_NAME}.
1092
-
1093
- Read and follow the execute-phase workflow:
1094
- @~/.claude/get-shit-done/workflows/execute-phase.md
1095
-
1096
- Phase: ${PHASE_NUMBER}
1097
- Phase directory: ${phase_dir}
1098
-
1099
- Execute each plan's tasks in wave order. For each plan:
1100
- 1. Execute all tasks
1101
- 2. Commit each task atomically
1102
- 3. Create SUMMARY.md in the phase directory
1103
-
1104
- Do NOT update ROADMAP.md or STATE.md directly -- those are managed by GSD tools.
1105
- ",
1106
- subagent_type="gsd-executor",
1107
- model="${EXECUTOR_MODEL}",
1108
- description="Execute phase ${PHASE_NUMBER}: ${PHASE_NAME}"
1109
- )
1110
- ```
1111
-
1112
- **e. Spawn verifier agent (gsd:verify-phase):**
1113
- ```
1114
- Task(
1115
- prompt="
1116
- <files_to_read>
1117
- - ./CLAUDE.md (Project instructions -- if exists, follow all guidelines)
1118
- - .agents/skills/ (Project skills -- if dir exists, list skills, read SKILL.md for each, follow relevant rules)
1119
- - ${phase_dir}/*-PLAN.md (Plans with must_haves)
1120
- - ${phase_dir}/*-SUMMARY.md (Execution summaries)
1121
- </files_to_read>
1122
-
1123
- Verify phase ${PHASE_NUMBER}: ${PHASE_NAME} goal achievement.
1124
-
1125
- Read and follow the verify-phase workflow:
1126
- @~/.claude/get-shit-done/workflows/verify-phase.md
1127
-
1128
- Phase: ${PHASE_NUMBER}
1129
- Phase directory: ${phase_dir}
1130
-
1131
- Check must_haves from plan frontmatter against actual codebase.
1132
- Create VERIFICATION.md in the phase directory.
1133
- ",
1134
- subagent_type="gsd-verifier",
1135
- model="${VERIFIER_MODEL}",
1136
- description="Verify phase ${PHASE_NUMBER}: ${PHASE_NAME}"
1137
- )
1138
- ```
1139
-
1140
- **f. Post phase-complete comment directly (no sub-agent):**
1141
- ```bash
1142
- PHASE_TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
1143
- VERIFICATION_STATUS=$(grep -m1 "^## " "${phase_dir}/"*-VERIFICATION.md 2>/dev/null | head -1 || echo "Verification complete")
1144
- PHASE_BODY=$(cat <<COMMENTEOF
1145
- > **MGW** · \`phase-complete\` · ${PHASE_TIMESTAMP}
1146
- > ${MILESTONE_CONTEXT}
1147
-
1148
- ### Phase ${PHASE_NUMBER} Complete — ${PHASE_NAME}
1149
-
1150
- Execution complete. See ${phase_dir} for plans, summaries, and verification.
1151
-
1152
- **Verification:** ${VERIFICATION_STATUS}
1153
- COMMENTEOF
1154
- )
1155
- gh issue comment ${ISSUE_NUMBER} --body "$PHASE_BODY" 2>/dev/null || true
1156
- ```
1157
-
1158
- **Retry loop — on phase execution failure** (apply same pattern as execute_gsd_quick):
1159
-
1160
- If a phase's executor or verifier fails, capture the error and apply retry logic via `classifyFailure()`, `canRetry()`, `incrementRetry()`, and `getBackoffMs()` from `lib/retry.cjs`. Only the failing phase is retried (restart from step 2b for that phase). If the failure is transient and `canRetry()` is true: sleep backoff, call `incrementRetry()`, loop. If permanent or retries exhausted: set `dead_letter = true`, set `last_failure_class`, break the retry loop.
1161
-
1162
- On successful completion of all phases: clear `last_failure_class`, set `EXECUTION_SUCCEEDED=true`.
1163
-
1164
- After ALL phases complete → update pipeline_stage to "verifying" (at `${REPO_ROOT}/.mgw/active/`).
1165
- </step>
1166
-
1167
- <step name="post_execution_update">
1168
- **Post execution-complete comment on issue (or failure comment if dead_letter):**
1169
-
1170
- Read `dead_letter` and `last_failure_class` from current issue state:
1171
- ```bash
1172
- DEAD_LETTER=$(node -e "
1173
- const { loadActiveIssue } = require('./lib/state.cjs');
1174
- const state = loadActiveIssue(${ISSUE_NUMBER});
1175
- console.log(state && state.dead_letter === true ? 'true' : 'false');
1176
- " 2>/dev/null || echo "false")
1177
-
1178
- LAST_FAILURE_CLASS=$(node -e "
1179
- const { loadActiveIssue } = require('./lib/state.cjs');
1180
- const state = loadActiveIssue(${ISSUE_NUMBER});
1181
- console.log((state && state.last_failure_class) ? state.last_failure_class : 'unknown');
1182
- " 2>/dev/null || echo "unknown")
1183
- ```
1184
-
1185
- **If dead_letter === true — post failure comment and halt:**
1186
- ```bash
1187
- if [ "$DEAD_LETTER" = "true" ]; then
1188
- FAIL_TIMESTAMP=$(node ~/.claude/get-shit-done/bin/gsd-tools.cjs current-timestamp --raw 2>/dev/null || date -u +"%Y-%m-%dT%H:%M:%SZ")
1189
- RETRY_COUNT_CURRENT=$(node -e "
1190
- const { loadActiveIssue } = require('./lib/state.cjs');
1191
- const state = loadActiveIssue(${ISSUE_NUMBER});
1192
- console.log((state && typeof state.retry_count === 'number') ? state.retry_count : 0);
1193
- " 2>/dev/null || echo "0")
1194
-
1195
- FAIL_BODY=$(cat <<COMMENTEOF
1196
- > **MGW** · \`pipeline-failed\` · ${FAIL_TIMESTAMP}
1197
- > ${MILESTONE_CONTEXT}
1198
-
1199
- ### Pipeline Failed
1200
-
1201
- Issue #${ISSUE_NUMBER} — ${issue_title}
1202
-
1203
- | | |
1204
- |---|---|
1205
- | **Failure class** | \`${LAST_FAILURE_CLASS}\` |
1206
- | **Retries attempted** | ${RETRY_COUNT_CURRENT} of 3 |
1207
- | **Status** | Dead-lettered — requires human intervention |
1208
-
1209
- **Failure class meaning:**
1210
- - \`transient\` — retry exhausted (rate limit, network, or overload)
1211
- - \`permanent\` — unrecoverable (auth, missing deps, bad config)
1212
- - \`needs-info\` — issue is ambiguous or incomplete
1213
-
1214
- **To retry after resolving root cause:**
1215
- \`\`\`
1216
- /mgw:run ${ISSUE_NUMBER} --retry
1217
- \`\`\`
1218
- COMMENTEOF
1219
- )
1220
-
1221
- gh issue comment ${ISSUE_NUMBER} --body "$FAIL_BODY" 2>/dev/null || true
1222
- gh issue edit ${ISSUE_NUMBER} --add-label "pipeline-failed" 2>/dev/null || true
1223
- gh label create "pipeline-failed" --description "Pipeline execution failed" --color "d73a4a" --force 2>/dev/null || true
1224
-
1225
- # Update pipeline_stage to failed
1226
- node -e "
1227
- const fs = require('fs'), path = require('path');
1228
- const activeDir = path.join(process.cwd(), '.mgw', 'active');
1229
- const files = fs.readdirSync(activeDir);
1230
- const file = files.find(f => f.startsWith('${ISSUE_NUMBER}-') && f.endsWith('.json'));
1231
- const filePath = path.join(activeDir, file);
1232
- const state = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
1233
- state.pipeline_stage = 'failed';
1234
- fs.writeFileSync(filePath, JSON.stringify(state, null, 2));
1235
- " 2>/dev/null || true
1236
-
1237
- echo "MGW: Pipeline dead-lettered for #${ISSUE_NUMBER} (class: ${LAST_FAILURE_CLASS}). Use --retry after fixing root cause."
1238
- exit 1
1239
- fi
1240
- ```
1241
-
1242
- **Otherwise — post execution-complete comment:**
1243
-
1244
- After GSD execution completes successfully, post a structured update before creating the PR:
1245
-
1246
- ```bash
1247
- COMMIT_COUNT=$(git rev-list ${DEFAULT_BRANCH}..HEAD --count 2>/dev/null || echo "0")
1248
- TEST_STATUS=$(npm test 2>&1 >/dev/null && echo "passing" || echo "failing")
1249
- FILE_CHANGES=$(git diff --stat ${DEFAULT_BRANCH}..HEAD 2>/dev/null | tail -1)
1250
- EXEC_TIMESTAMP=$(node -e "try{process.stdout.write(require('./lib/gsd-adapter.cjs').getTimestamp())}catch(e){process.stdout.write(new Date().toISOString().replace(/\\.\\d{3}Z$/,'Z'))}")
1251
- ```
1252
-
1253
- Post the execution-complete comment directly (no sub-agent — guarantees it happens):
1254
-
1255
- ```bash
1256
- EXEC_BODY=$(cat <<COMMENTEOF
1257
- > **MGW** · \`execution-complete\` · ${EXEC_TIMESTAMP}
1258
- > ${MILESTONE_CONTEXT}
1259
-
1260
- ### Execution Complete
1261
-
1262
- ${COMMIT_COUNT} atomic commit(s) on branch \`${BRANCH_NAME}\`.
1263
-
1264
- **Changes:** ${FILE_CHANGES}
1265
-
1266
- **Tests:** ${TEST_STATUS}
1267
-
1268
- Preparing pull request.
1269
- COMMENTEOF
1270
- )
1271
-
1272
- gh issue comment ${ISSUE_NUMBER} --body "$EXEC_BODY" 2>/dev/null || true
1273
- ```
1274
-
1275
- Update pipeline_stage to "pr-pending" (at `${REPO_ROOT}/.mgw/active/`).
1276
- </step>
1277
-
1278
- <step name="create_pr">
1279
- **Create PR (task agent):**
1280
-
1281
- After GSD execution completes (any route):
1282
-
1283
- Push branch and gather artifacts:
1284
- ```bash
1285
- git push -u origin ${BRANCH_NAME}
1286
-
1287
- # Structured summary data via gsd-tools (returns JSON with one_liner, key_files, tech_added, patterns, decisions)
1288
- SUMMARY_DATA=$(node ~/.claude/get-shit-done/bin/gsd-tools.cjs summary-extract "${gsd_artifacts_path}/*SUMMARY*" 2>/dev/null || echo '{}')
1289
- # Also keep raw summary for full context
1290
- SUMMARY=$(cat ${gsd_artifacts_path}/*SUMMARY* 2>/dev/null)
1291
- VERIFICATION=$(cat ${gsd_artifacts_path}/*VERIFICATION* 2>/dev/null)
1292
- COMMITS=$(git log ${DEFAULT_BRANCH}..HEAD --oneline)
1293
- CROSS_REFS=$(cat ${REPO_ROOT}/.mgw/cross-refs.json 2>/dev/null)
1294
- # Progress table for PR details section
1295
- PROGRESS_TABLE=$(node ~/.claude/get-shit-done/bin/gsd-tools.cjs progress table --raw 2>/dev/null || echo "")
1296
-
1297
- # Milestone/phase context for PR body
1298
- MILESTONE_TITLE=""
1299
- PHASE_INFO=""
1300
- DEPENDENCY_CHAIN=""
1301
- PROJECT_BOARD_URL=""
1302
- if [ -f "${REPO_ROOT}/.mgw/project.json" ]; then
1303
- MILESTONE_TITLE=$(python3 -c "
1304
- import json
1305
- p = json.load(open('${REPO_ROOT}/.mgw/project.json'))
1306
- for m in p['milestones']:
1307
- for i in m.get('issues', []):
1308
- if i.get('github_number') == ${ISSUE_NUMBER}:
1309
- print(m['name'])
1310
- break
1311
- " 2>/dev/null || echo "")
1312
-
1313
- PHASE_INFO=$(python3 -c "
1314
- import json
1315
- p = json.load(open('${REPO_ROOT}/.mgw/project.json'))
1316
- total_phases = sum(len(m.get('issues', [])) for m in p['milestones'])
1317
- for m in p['milestones']:
1318
- for i in m.get('issues', []):
1319
- if i.get('github_number') == ${ISSUE_NUMBER}:
1320
- total_in_milestone = len(m.get('issues', []))
1321
- idx = [x['github_number'] for x in m['issues']].index(${ISSUE_NUMBER}) + 1
1322
- print(f\"Phase {i['phase_number']}: {i['phase_name']} (issue {idx}/{total_in_milestone} in milestone)\")
1323
- break
1324
- " 2>/dev/null || echo "")
1325
-
1326
- DEPENDENCY_CHAIN=$(python3 -c "
1327
- import json
1328
- p = json.load(open('${REPO_ROOT}/.mgw/project.json'))
1329
- refs = json.load(open('${REPO_ROOT}/.mgw/cross-refs.json'))
1330
- blockers = [l['b'].split(':')[1] for l in refs.get('links', [])
1331
- if l.get('type') == 'blocked-by' and l['a'] == 'issue:${ISSUE_NUMBER}']
1332
- blocks = [l['a'].split(':')[1] for l in refs.get('links', [])
1333
- if l.get('type') == 'blocked-by' and l['b'] == 'issue:${ISSUE_NUMBER}']
1334
- parts = []
1335
- if blockers: parts.append('Blocked by: ' + ', '.join(f'#{b}' for b in blockers))
1336
- if blocks: parts.append('Unblocks: ' + ', '.join(f'#{b}' for b in blocks))
1337
- print(' | '.join(parts) if parts else 'No dependencies')
1338
- " 2>/dev/null || echo "")
1339
-
1340
- PROJECT_BOARD_URL=$(python3 -c "
1341
- import json
1342
- p = json.load(open('${REPO_ROOT}/.mgw/project.json'))
1343
- print(p.get('project', {}).get('project_board', {}).get('url', ''))
1344
- " 2>/dev/null || echo "")
1345
- fi
1346
- ```
1347
-
1348
- Read issue state for context.
1349
-
1350
- ```
1351
- Task(
1352
- prompt="
1353
- <files_to_read>
1354
- - ./CLAUDE.md (Project instructions — if exists, follow all guidelines)
1355
- - .agents/skills/ (Project skills — if dir exists, list skills, read SKILL.md for each, follow relevant rules)
1356
- </files_to_read>
1357
-
1358
- Create a GitHub PR for issue #${ISSUE_NUMBER}.
1359
-
1360
- <issue>
1361
- Title: ${issue_title}
1362
- Body: ${issue_body}
1363
- </issue>
1364
-
1365
- <milestone_context>
1366
- Milestone: ${MILESTONE_TITLE}
1367
- Phase: ${PHASE_INFO}
1368
- Dependencies: ${DEPENDENCY_CHAIN}
1369
- Board: ${PROJECT_BOARD_URL}
1370
- </milestone_context>
1371
-
1372
- <summary_structured>
1373
- ${SUMMARY_DATA}
1374
- </summary_structured>
1375
-
1376
- <summary_raw>
1377
- ${SUMMARY}
1378
- </summary_raw>
1379
-
1380
- <verification>
1381
- ${VERIFICATION}
1382
- </verification>
1383
-
1384
- <artifact_warnings>
1385
- ${ARTIFACT_CHECK}
1386
- ${KEYLINK_CHECK}
1387
- </artifact_warnings>
1388
-
1389
- <commits>
1390
- ${COMMITS}
1391
- </commits>
1392
-
1393
- <cross_refs>
1394
- ${CROSS_REFS}
1395
- </cross_refs>
1396
-
1397
- <instructions>
1398
- 1. Build PR title: short, prefixed with fix:/feat:/refactor: based on issue labels. Under 70 characters.
1399
-
1400
- 2. Build PR body using this EXACT structure (fill in from data above):
1401
-
1402
- ## Summary
1403
- - 2-4 bullets of what was built and why (use one_liner from summary_structured if available)
1404
-
1405
- Closes #${ISSUE_NUMBER}
1406
-
1407
- ## Milestone Context
1408
- - **Milestone:** ${MILESTONE_TITLE}
1409
- - **Phase:** ${PHASE_INFO}
1410
- - **Dependencies:** ${DEPENDENCY_CHAIN}
1411
- (Skip this section entirely if MILESTONE_TITLE is empty)
1412
-
1413
- ## Changes
1414
- - File-level changes grouped by module (use key_files from summary_structured)
1415
-
1416
- ## Test Plan
1417
- - Verification checklist from VERIFICATION artifact
1418
-
1419
- ## Cross-References
1420
- - ${CROSS_REFS entries as bullet points}
1421
- (Skip if no cross-refs)
1422
-
1423
- <details>
1424
- <summary>GSD Progress</summary>
1425
-
1426
- ${PROGRESS_TABLE}
1427
- </details>
1428
- (Skip if PROGRESS_TABLE is empty)
1429
-
1430
- 3. Create PR: gh pr create --title '<title>' --base '${DEFAULT_BRANCH}' --head '${BRANCH_NAME}' --body '<body>'
1431
- 4. Post testing procedures as separate PR comment: gh pr comment <pr_number> --body '<testing>'
1432
- 5. Return: PR number, PR URL
1433
- </instructions>
1434
- ",
1435
- subagent_type="general-purpose",
1436
- description="Create PR for #${ISSUE_NUMBER}"
1437
- )
1438
- ```
1439
-
1440
- Parse PR number and URL from agent response.
1441
-
1442
- Update state (at `${REPO_ROOT}/.mgw/active/`):
1443
- - linked_pr = PR number
1444
- - pipeline_stage = "pr-created"
1445
-
1446
- Add cross-ref (at `${REPO_ROOT}/.mgw/cross-refs.json`): issue → PR.
1447
- SJ|</step>
1448
-
1449
- KV|<step name="pr_review_checkpoint">
1450
- VR|**PR Review Checkpoint (MLST-07):**
1451
-
1452
- NP|Before considering this issue complete, run PR deep review to ensure quality.
1453
- This prevents advancing with a subpar PR.
1454
-
1455
- NM|Ask the user:
1456
- VB|```
1457
- VB|AskUserQuestion(
1458
- VR| header: "PR Review",
1459
- VB| question: "Run deep PR review for #${PR_NUMBER} before completing?",
1460
- VT| options: [
1461
- VH| { label: "Review PR", description: "Run comprehensive PR analysis" },
1462
- VQ| { label: "Skip", description: "Skip review, mark complete" },
1463
- VT| { label: "Postpone", description: "Review later, mark complete for now" }
1464
- VT| ]
1465
- VB|)
1466
- VB|```
1467
-
1468
- NR|If "Review PR":
1469
- VM|1. Run mgw:review in PR mode: `/mgw:review ${PR_NUMBER} --pr`
1470
- RM|2. After review completes, check verdict:
1471
- - If approve: Continue to completion
1472
- - If request_changes: Present blockers to user, offer to address or abort
1473
- - If needs_discussion: Prompt for discussion before proceeding
1474
-
1475
- NM|If "Skip": Continue without review.
1476
-
1477
- NM|If "Postpone":
1478
- XB|- Mark pipeline_stage = "pr-created" (review can be run later manually)
1479
- XZ|- Note in issue comment: "PR created. Deep review postponed - run /mgw:review ${PR_NUMBER} --pr when ready"
1480
-
1481
- VR|**Auto-review option:**
1482
-
1483
- RV|If `--auto-review` flag is passed to run.md, skip the prompt and run review automatically.
1484
- Parse the flag:
1485
- VB|```bash
1486
- QX|AUTO_REVIEW=false
1487
- VT|for ARG in $ARGUMENTS; do
1488
- VM| case "$ARG" in
1489
- --auto-review) AUTO_REVIEW=true ;;
1490
- esac
1491
- VT|done
1492
-
1493
- QK|if [ "$AUTO_REVIEW" = true ]; then
1494
- # Run review automatically
1495
- /mgw:review ${PR_NUMBER} --pr
1496
- VT|fi
1497
- VB|```
1498
-
1499
- <step name="cleanup_and_complete">
1500
- **Clean up worktree, post completion, and prompt sync:**
1501
-
1502
- Return to main repo and remove worktree (branch persists for PR):
1503
- ```bash
1504
- cd "${REPO_ROOT}"
1505
- git worktree remove "${WORKTREE_DIR}" 2>/dev/null
1506
- rmdir "${REPO_ROOT}/.worktrees/issue" 2>/dev/null
1507
- rmdir "${REPO_ROOT}/.worktrees" 2>/dev/null
1508
- ```
1509
-
1510
- Clear MGW labels at completion:
1511
- ```bash
1512
- # Pass empty string — removes all mgw: labels without applying a new one
1513
- remove_mgw_labels_and_apply ${ISSUE_NUMBER} ""
1514
- ```
1515
-
1516
- Post-completion label reconciliation:
1517
- ```bash
1518
- # Post-completion label reconciliation — verify no stray MGW labels remain
1519
- LIVE_LABELS=$(gh issue view ${ISSUE_NUMBER} --json labels --jq '[.labels[].name]' 2>/dev/null || echo "[]")
1520
- STRAY_MGW=$(echo "$LIVE_LABELS" | python3 -c "
1521
- import json, sys
1522
- labels = json.load(sys.stdin)
1523
- stray = [l for l in labels if l.startswith('mgw:')]
1524
- print('\n'.join(stray))
1525
- " 2>/dev/null || echo "")
1526
-
1527
- if [ -n "$STRAY_MGW" ]; then
1528
- echo "MGW WARNING: unexpected MGW labels still on issue after completion: $STRAY_MGW" >&2
1529
- fi
1530
-
1531
- # Sync live labels back to .mgw/active state file
1532
- LIVE_LABELS_LIST=$(gh issue view ${ISSUE_NUMBER} --json labels --jq '[.labels[].name]' 2>/dev/null || echo "[]")
1533
- # Update labels field in ${REPO_ROOT}/.mgw/active/${STATE_FILE} using python3 json patch:
1534
- python3 -c "
1535
- import json, sys
1536
- path = sys.argv[1]
1537
- live = json.loads(sys.argv[2])
1538
- with open(path) as f: state = json.load(f)
1539
- state['labels'] = live
1540
- with open(path, 'w') as f: json.dump(state, f, indent=2)
1541
- " "${REPO_ROOT}/.mgw/active/${STATE_FILE}" "$LIVE_LABELS_LIST" 2>/dev/null || true
1542
- ```
1543
-
1544
- Extract one-liner summary for concise comment:
1545
- ```bash
1546
- ONE_LINER=$(node ~/.claude/get-shit-done/bin/gsd-tools.cjs summary-extract "${gsd_artifacts_path}/*SUMMARY*" --fields one_liner --raw 2>/dev/null || echo "")
1547
- ```
1548
-
1549
- Post structured PR-ready comment directly (no sub-agent — guarantees it happens):
1550
-
1551
- ```bash
1552
- DONE_TIMESTAMP=$(node -e "try{process.stdout.write(require('./lib/gsd-adapter.cjs').getTimestamp())}catch(e){process.stdout.write(new Date().toISOString().replace(/\\.\\d{3}Z$/,'Z'))}")
1553
-
1554
- PR_READY_BODY=$(cat <<COMMENTEOF
1555
- > **MGW** · \`pr-ready\` · ${DONE_TIMESTAMP}
1556
- > ${MILESTONE_CONTEXT}
1557
-
1558
- ### PR Ready
1559
-
1560
- **PR #${PR_NUMBER}** — ${PR_URL}
1561
-
1562
- ${ONE_LINER}
1563
-
1564
- Testing procedures posted on the PR.
1565
- This issue will auto-close when the PR is merged.
1566
-
1567
- <details>
1568
- <summary>Pipeline Summary</summary>
1569
-
1570
- | Stage | Status |
1571
- |-------|--------|
1572
- | Triage | ✓ |
1573
- | Planning | ✓ |
1574
- | Execution | ✓ |
1575
- | PR Creation | ✓ |
1576
-
1577
- </details>
1578
- COMMENTEOF
1579
- )
1580
-
1581
- gh issue comment ${ISSUE_NUMBER} --body "$PR_READY_BODY" 2>/dev/null || true
1582
- ```
1583
-
1584
- Update pipeline_stage to "done" (at `${REPO_ROOT}/.mgw/active/`).
1585
-
1586
- Report to user:
1587
- ```
1588
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1589
- MGW ► PIPELINE COMPLETE
1590
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1591
-
1592
- Issue: #${ISSUE_NUMBER} — ${issue_title}
1593
- Route: ${gsd_route}
1594
- PR: #${PR_NUMBER} — ${PR_URL}
1595
- Branch: ${BRANCH_NAME} (worktree cleaned up)
1596
-
1597
- Status comments posted. PR includes testing procedures.
1598
- Issue will auto-close on merge.
1599
-
1600
- Next:
1601
- → Review the PR, then merge
1602
- → After merge: /mgw:sync to archive state and clean up branches
1603
- ```
1604
- </step>
80
+ @~/.claude/commands/mgw/run/pr-create.md
1605
81
 
1606
82
  </process>
1607
83