@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.
@@ -0,0 +1,183 @@
1
+ ---
2
+ name: mgw:context
3
+ description: Show assembled context for an issue — what GSD agents see before planning/execution
4
+ argument-hint: "<issue-number>"
5
+ allowed-tools:
6
+ - Bash
7
+ - Read
8
+ ---
9
+
10
+ <objective>
11
+ Display the full assembled context for a GitHub issue, showing exactly what a GSD agent
12
+ would receive as input before planning or execution. Useful for debugging context gaps,
13
+ verifying that prior phase summaries are available, and checking what a second developer's
14
+ agent will see.
15
+
16
+ This command is read-only. It does not modify any state.
17
+ </objective>
18
+
19
+ <process>
20
+
21
+ <step name="validate_input">
22
+ **Validate issue number provided:**
23
+
24
+ Parse $ARGUMENTS for a numeric issue number. If missing:
25
+ ```
26
+ AskUserQuestion(
27
+ header: "Issue Number Required",
28
+ question: "Which issue number do you want context for?",
29
+ followUp: "Enter the GitHub issue number (e.g., 42)"
30
+ )
31
+ ```
32
+ </step>
33
+
34
+ <step name="assemble_and_display">
35
+ **Assemble full context from GitHub and display formatted output:**
36
+
37
+ ```bash
38
+ REPO_ROOT=$(git rev-parse --show-toplevel)
39
+
40
+ node -e "
41
+ const ic = require('${REPO_ROOT}/lib/issue-context.cjs');
42
+
43
+ (async () => {
44
+ // Assemble issue context
45
+ const ctx = await ic.assembleIssueContext(${ISSUE_NUMBER});
46
+ if (!ctx || !ctx.issue) {
47
+ console.log('No context found for issue #${ISSUE_NUMBER}.');
48
+ process.exit(0);
49
+ }
50
+
51
+ const issue = ctx.issue;
52
+ const milestone = issue.milestone || {};
53
+ const labels = (issue.labels || []).map(l => typeof l === 'object' ? l.name : l);
54
+
55
+ // Header
56
+ console.log('');
57
+ console.log('Issue #' + issue.number + ': ' + issue.title);
58
+ if (milestone.title) {
59
+ console.log('Milestone: ' + milestone.title);
60
+ }
61
+ console.log('Status: ' + (issue.state || 'unknown'));
62
+ if (labels.length > 0) {
63
+ console.log('Labels: ' + labels.join(', '));
64
+ }
65
+
66
+ // Vision
67
+ const vision = await ic.fetchProjectVision();
68
+ if (vision) {
69
+ console.log('');
70
+ console.log('-- Vision --');
71
+ console.log(vision.slice(0, 2000));
72
+ }
73
+
74
+ // Prior phases (from milestone siblings)
75
+ if (ctx.milestoneContext && ctx.milestoneContext.length > 0) {
76
+ console.log('');
77
+ console.log('-- Prior Phases --');
78
+ for (const s of ctx.milestoneContext) {
79
+ if (s.issueNumber === issue.number) continue;
80
+ console.log('Phase #' + s.issueNumber + ': ' + s.title);
81
+ if (s.summary) {
82
+ // Indent summary lines
83
+ const lines = s.summary.split('\\n').slice(0, 5);
84
+ for (const line of lines) {
85
+ console.log(' ' + line);
86
+ }
87
+ }
88
+ }
89
+ }
90
+
91
+ // Phase goal (from issue body)
92
+ if (issue.body) {
93
+ console.log('');
94
+ console.log('-- Phase Goal --');
95
+ // Extract acceptance criteria or goal sections from body
96
+ const body = issue.body;
97
+ const goalMatch = body.match(/##?\\s*(?:Goal|Description|Overview)\\s*\\n([\\s\\S]*?)(?=\\n##|$)/i);
98
+ if (goalMatch) {
99
+ console.log(goalMatch[1].trim().slice(0, 1000));
100
+ } else {
101
+ // Show first meaningful paragraph
102
+ const paras = body.split('\\n\\n').filter(p => p.trim() && !p.startsWith('<!--'));
103
+ if (paras.length > 0) {
104
+ console.log(paras[0].trim().slice(0, 1000));
105
+ }
106
+ }
107
+
108
+ const acMatch = body.match(/##?\\s*Acceptance\\s*Criteria\\s*\\n([\\s\\S]*?)(?=\\n##|$)/i);
109
+ if (acMatch) {
110
+ console.log('');
111
+ console.log('-- Acceptance Criteria --');
112
+ console.log(acMatch[1].trim().slice(0, 1000));
113
+ }
114
+ }
115
+
116
+ // Dependencies (from labels)
117
+ const blockedBy = labels.filter(l => l.startsWith('blocked-by:'));
118
+ const blocks = labels.filter(l => l.startsWith('blocks:'));
119
+ if (blockedBy.length > 0 || blocks.length > 0) {
120
+ console.log('');
121
+ console.log('-- Dependencies --');
122
+ if (blockedBy.length > 0) {
123
+ console.log('Blocked by: ' + blockedBy.map(l => l.replace('blocked-by:', '')).join(', '));
124
+ }
125
+ if (blocks.length > 0) {
126
+ console.log('Blocks: ' + blocks.map(l => l.replace('blocks:', '')).join(', '));
127
+ }
128
+ }
129
+
130
+ // Plan (if posted)
131
+ if (ctx.planComment) {
132
+ console.log('');
133
+ console.log('-- Plan (from structured comment) --');
134
+ const planBody = ctx.planComment.body.replace(/<!--[\\s\\S]*?-->\\n?/, '').trim();
135
+ console.log(planBody.slice(0, 2000));
136
+ }
137
+
138
+ // Summary (if posted)
139
+ if (ctx.summaryComment) {
140
+ console.log('');
141
+ console.log('-- Summary (from structured comment) --');
142
+ const summaryBody = ctx.summaryComment.body.replace(/<!--[\\s\\S]*?-->\\n?/, '').trim();
143
+ console.log(summaryBody.slice(0, 1000));
144
+ }
145
+
146
+ console.log('');
147
+ })().catch(e => {
148
+ console.error('Error assembling context: ' + e.message);
149
+ process.exit(1);
150
+ });
151
+ " 2>/dev/null
152
+ ```
153
+ </step>
154
+
155
+ <step name="display">
156
+ **Display context report with banner:**
157
+
158
+ ```
159
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
160
+ MGW ► CONTEXT FOR #${ISSUE_NUMBER}
161
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
162
+
163
+ ${FORMATTED_OUTPUT}
164
+
165
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
166
+ Tip: This is what GSD agents see before planning.
167
+ → /mgw:run ${ISSUE_NUMBER} — Execute this issue
168
+ → /mgw:status — Project dashboard
169
+ ```
170
+ </step>
171
+
172
+ </process>
173
+
174
+ <success_criteria>
175
+ - [ ] Issue number validated
176
+ - [ ] Issue context assembled from GitHub comments via assembleIssueContext()
177
+ - [ ] Vision fetched via fetchProjectVision() (GitHub Project README first, local fallback)
178
+ - [ ] Output formatted with clear section headers (Vision, Prior Phases, Phase Goal, etc.)
179
+ - [ ] Acceptance criteria extracted from issue body when present
180
+ - [ ] Dependencies shown from labels
181
+ - [ ] Plan and summary comments displayed when available
182
+ - [ ] No state modified
183
+ </success_criteria>
@@ -0,0 +1,169 @@
1
+ ---
2
+ name: mgw:handoff
3
+ description: Generate onboarding context for a developer joining the project mid-milestone
4
+ argument-hint: "<developer-name>"
5
+ allowed-tools:
6
+ - Bash
7
+ - Read
8
+ - Task
9
+ ---
10
+
11
+ <objective>
12
+ Produce a structured handoff document for a developer joining an MGW project. Assembles
13
+ current project state, milestone progress, active issues, and recent decisions from
14
+ GitHub issue comments into a single briefing.
15
+
16
+ This command is read-only. It does not modify any state.
17
+ </objective>
18
+
19
+ <execution_context>
20
+ @~/.claude/commands/mgw/workflows/state.md
21
+ </execution_context>
22
+
23
+ <process>
24
+
25
+ <step name="validate_input">
26
+ **Validate developer name provided:**
27
+
28
+ Parse $ARGUMENTS for a name. If missing, use "new developer" as default.
29
+ </step>
30
+
31
+ <step name="gather_state">
32
+ **Gather project state:**
33
+
34
+ ```bash
35
+ REPO_ROOT=$(git rev-parse --show-toplevel)
36
+ REPO=$(gh repo view --json nameWithOwner -q .nameWithOwner)
37
+ MGW_DIR="${REPO_ROOT}/.mgw"
38
+
39
+ # Project info
40
+ PROJECT_NAME=$(echo "$REPO" | cut -d'/' -f2)
41
+
42
+ # Active milestone
43
+ MILESTONE_INFO=""
44
+ if [ -f "${MGW_DIR}/project.json" ]; then
45
+ MILESTONE_INFO=$(python3 -c "
46
+ import json
47
+ p = json.load(open('${MGW_DIR}/project.json'))
48
+ ms = p.get('milestones', [])
49
+ active = [m for m in ms if m.get('gsd_state') == 'active']
50
+ if active:
51
+ m = active[0]
52
+ total = len(m.get('issues', []))
53
+ done = len([i for i in m['issues'] if i.get('pipeline_stage') == 'done'])
54
+ print(f\"{m['name']} — {done}/{total} issues complete\")
55
+ else:
56
+ print('No active milestone')
57
+ " 2>/dev/null || echo "Unknown")
58
+ fi
59
+
60
+ # Active issues
61
+ ACTIVE_ISSUES=$(ls ${MGW_DIR}/active/*.json 2>/dev/null | wc -l)
62
+
63
+ # Recent PRs
64
+ RECENT_PRS=$(gh pr list --limit 5 --json number,title,state --jq '.[] | "#\(.number) \(.title) [\(.state)]"' 2>/dev/null || echo "None")
65
+ ```
66
+ </step>
67
+
68
+ <step name="assemble_context">
69
+ **Assemble project context from GitHub:**
70
+
71
+ ```bash
72
+ # Vision/project description
73
+ VISION=$(node -e "
74
+ const ic = require('${REPO_ROOT}/lib/issue-context.cjs');
75
+ ic.buildGSDPromptContext({ includeVision: true })
76
+ .then(ctx => process.stdout.write(ctx));
77
+ " 2>/dev/null || echo "")
78
+
79
+ # Open milestones with issue counts
80
+ MILESTONES=$(gh api repos/${REPO}/milestones --jq '.[] | "- \(.title): \(.open_issues) open, \(.closed_issues) closed"' 2>/dev/null || echo "No milestones")
81
+ ```
82
+ </step>
83
+
84
+ <step name="generate_handoff">
85
+ **Generate handoff briefing:**
86
+
87
+ ```
88
+ Task(
89
+ prompt="
90
+ Generate a developer onboarding briefing for ${DEVELOPER_NAME} joining project ${PROJECT_NAME}.
91
+
92
+ <project_context>
93
+ Repository: ${REPO}
94
+ Active Milestone: ${MILESTONE_INFO}
95
+ Active Issues in Pipeline: ${ACTIVE_ISSUES}
96
+ Recent PRs:
97
+ ${RECENT_PRS}
98
+
99
+ Open Milestones:
100
+ ${MILESTONES}
101
+ </project_context>
102
+
103
+ <vision_context>
104
+ ${VISION}
105
+ </vision_context>
106
+
107
+ <instructions>
108
+ Create a structured handoff document with these sections:
109
+
110
+ ## Project Overview
111
+ - What the project is and its current state
112
+ - Key architectural decisions (from vision context)
113
+
114
+ ## Current Milestone
115
+ - What's being built now
116
+ - Progress status
117
+ - Key deliverables remaining
118
+
119
+ ## Getting Started
120
+ - How to set up the development environment
121
+ - Key commands: /mgw:status, /mgw:context, /mgw:next, /mgw:issue
122
+ - How context sharing works (structured comments on GitHub issues)
123
+
124
+ ## Active Work
125
+ - Issues currently in the pipeline
126
+ - Recent PRs to review
127
+
128
+ ## Key Conventions
129
+ - How MGW orchestrates work (issues → triage → plan → execute → PR)
130
+ - How to read structured comments (<!-- mgw:type=... --> headers)
131
+ - How to use /mgw:context <issue> to see what agents see
132
+
133
+ Keep it concise and actionable. This is a working document, not documentation.
134
+ </instructions>
135
+ ",
136
+ subagent_type="general-purpose",
137
+ description="Generate handoff for ${DEVELOPER_NAME}"
138
+ )
139
+ ```
140
+ </step>
141
+
142
+ <step name="display">
143
+ **Display handoff briefing:**
144
+
145
+ ```
146
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
147
+ MGW ► HANDOFF BRIEFING
148
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
149
+
150
+ ${HANDOFF_DOCUMENT}
151
+
152
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
153
+ Tip: Share this output or post it as a GitHub Discussion.
154
+ → /mgw:context <issue> — See context for a specific issue
155
+ → /mgw:status — Current project dashboard
156
+ → /mgw:next — Find next unblocked issue
157
+ ```
158
+ </step>
159
+
160
+ </process>
161
+
162
+ <success_criteria>
163
+ - [ ] Developer name parsed (or defaulted)
164
+ - [ ] Project state gathered from .mgw/ and GitHub
165
+ - [ ] Vision context assembled via buildGSDPromptContext()
166
+ - [ ] Handoff document generated by task agent
167
+ - [ ] Briefing displayed to user
168
+ - [ ] No state modified
169
+ </success_criteria>
package/commands/issue.md CHANGED
@@ -113,6 +113,48 @@ Gather GSD project history for context (if available):
113
113
  HISTORY=$(node ~/.claude/get-shit-done/bin/gsd-tools.cjs history-digest 2>/dev/null || echo "")
114
114
  ```
115
115
 
116
+ **Gather milestone context for top-down triage (if available):**
117
+
118
+ Primary source: GitHub issue comments (works on any machine):
119
+ ```bash
120
+ MILESTONE_CONTEXT=$(node -e "
121
+ const ic = require('${REPO_ROOT}/lib/issue-context.cjs');
122
+ ic.safeContext({ issueNumber: ${ISSUE_NUMBER}, includeVision: true, includePriorSummaries: true })
123
+ .then(ctx => process.stdout.write(ctx));
124
+ " 2>/dev/null || echo "")
125
+ ```
126
+
127
+ Fallback: local files (backward compat for single-machine workflows):
128
+ ```bash
129
+ if [ -z "$MILESTONE_CONTEXT" ] && [ -f "${REPO_ROOT}/.mgw/project.json" ]; then
130
+ MILESTONE_CONTEXT=$(python3 -c "
131
+ import json
132
+ try:
133
+ p = json.load(open('${REPO_ROOT}/.mgw/project.json'))
134
+ for m in p.get('milestones', []):
135
+ for i in m.get('issues', []):
136
+ if i.get('github_number') == ${ISSUE_NUMBER}:
137
+ parts = []
138
+ parts.append(f\"Milestone: {m['name']}\")
139
+ parts.append(f\"Phase {i['phase_number']}: {i['phase_name']}\")
140
+ parts.append(f\"GSD Route: {i.get('gsd_route', 'unknown')}\")
141
+ completed = [x for x in m['issues'] if x.get('pipeline_stage') == 'done']
142
+ if completed:
143
+ parts.append(f\"Completed in milestone: {len(completed)}/{len(m['issues'])} issues\")
144
+ parts.append('Delivered: ' + ', '.join(f\"Phase {x['phase_number']}: {x['phase_name']}\" for x in completed))
145
+ print('\n'.join(parts))
146
+ break
147
+ except Exception as e:
148
+ pass
149
+ " 2>/dev/null || echo "")
150
+ fi
151
+
152
+ ROADMAP_CONTEXT=""
153
+ if [ -f ".planning/ROADMAP.md" ]; then
154
+ ROADMAP_CONTEXT=$(head -c 2000 .planning/ROADMAP.md)
155
+ fi
156
+ ```
157
+
116
158
  Build analysis prompt from issue data and spawn:
117
159
 
118
160
  ```
@@ -136,6 +178,14 @@ Comments: ${comments_summary}
136
178
  ${HISTORY}
137
179
  </project_history>
138
180
 
181
+ <milestone_context>
182
+ ${MILESTONE_CONTEXT}
183
+ </milestone_context>
184
+
185
+ <roadmap_context>
186
+ ${ROADMAP_CONTEXT}
187
+ </roadmap_context>
188
+
139
189
  <analysis_dimensions>
140
190
 
141
191
  1. **Scope:** Search the codebase for files and systems related to this issue.
@@ -317,6 +367,18 @@ Post comment and apply label:
317
367
  ```bash
318
368
  remove_mgw_labels_and_apply ${ISSUE_NUMBER} "mgw:triaged"
319
369
  ```
370
+
371
+ **Post structured metadata comment (non-blocking):**
372
+
373
+ In addition to the human-readable triage comment above, post a machine-readable
374
+ structured comment so other machines can read triage context from GitHub:
375
+ ```bash
376
+ node -e "
377
+ const ic = require('${REPO_ROOT}/lib/issue-context.cjs');
378
+ ic.postPlanningComment(${ISSUE_NUMBER}, 'triage', TRIAGE_REPORT, {})
379
+ .catch(() => {});
380
+ " 2>/dev/null || true
381
+ ```
320
382
  </step>
321
383
 
322
384
  <step name="present_report">
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: mgw:milestone
3
3
  description: Execute a milestone's issues in dependency order — auto-sync, rate-limit guard, per-issue checkpoint
4
- HB|argument-hint: "[milestone-number] [--interactive] [--dry-run] [--auto-review]"
4
+ argument-hint: "[milestone-number] [--interactive] [--dry-run]"
5
5
  allowed-tools:
6
6
  - Bash
7
7
  - Read
@@ -23,8 +23,7 @@ dependents, continue unblocked), resume detection, milestone close + draft relea
23
23
  completion, and auto-advance to next milestone.
24
24
 
25
25
  The `--interactive` flag pauses between issues for user confirmation.
26
- SR|The `--dry-run` flag shows the execution plan without running anything.
27
- NM|The `--auto-review` flag runs deep PR review after each issue completes.
26
+ The `--dry-run` flag shows the execution plan without running anything.
28
27
  </objective>
29
28
 
30
29
  <execution_context>
@@ -47,14 +46,12 @@ Flags: --interactive, --dry-run
47
46
  ```bash
48
47
  MILESTONE_NUM=""
49
48
  INTERACTIVE=false
50
- WP|DRY_RUN=false
51
- NM|AUTO_REVIEW=false
49
+ DRY_RUN=false
52
50
 
53
51
  for ARG in $ARGUMENTS; do
54
52
  case "$ARG" in
55
53
  --interactive) INTERACTIVE=true ;;
56
- TN| --dry-run) DRY_RUN=true ;;
57
- --auto-review) AUTO_REVIEW=true ;;
54
+ --dry-run) DRY_RUN=true ;;
58
55
  [0-9]*) MILESTONE_NUM="$ARG" ;;
59
56
  esac
60
57
  done
@@ -681,37 +678,7 @@ COMMENTEOF
681
678
  )
682
679
 
683
680
  gh issue comment ${ISSUE_NUMBER} --body "$PR_READY_BODY" 2>/dev/null || true
684
- PR| echo " ✓ #${ISSUE_NUMBER} — PR #${PR_NUMBER} created"
685
-
686
-
687
- BP| # ── PR REVIEW CHECKPOINT (MLST-07) ──
688
- RX| # Run PR review before allowing milestone to continue to next issue
689
-
690
- RX| if [ "$AUTO_REVIEW" = true ]; then
691
- RX| # Auto-review mode: run review automatically
692
- RX| echo "Running auto PR review for #${PR_NUMBER}..."
693
- RX| # NOTE: In full implementation, this would spawn the review agent
694
- RX| # For now, prompt the user
695
- RX| AskUserQuestion(
696
- RX| header: "PR Review",
697
- RX| question: "Run deep PR review for #${PR_NUMBER}?",
698
- RX| options: [
699
- RX| { label: "Review", description: "Run /mgw:review ${PR_NUMBER} --pr" },
700
- RX| { label: "Skip", description: "Continue without review" }
701
- RX| ]
702
- RX| )
703
- RX| else
704
- RX| AskUserQuestion(
705
- RX| header: "PR Review Checkpoint",
706
- RX| question: "Run deep PR review for #${PR_NUMBER} before continuing to next issue?",
707
- RX| options: [
708
- RX| { label: "Review now", description: "Run /mgw:review ${PR_NUMBER} --pr" },
709
- RX| { label: "Continue", description: "Skip review, proceed to next issue" }
710
- RX| ]
711
- RX| )
712
- RX| fi
713
-
714
- RX| # Continue to next issue
681
+ echo " ✓ #${ISSUE_NUMBER} — PR #${PR_NUMBER} created"
715
682
 
716
683
  else
717
684
  # Failure — read failure_class from active issue state, then post failure comment
@@ -914,7 +881,39 @@ Milestone: ${MILESTONE_NAME}
914
881
  fi
915
882
  ```
916
883
 
917
- 4. Advance active milestone pointer in project.json:
884
+ 4. Update Project README with current milestone progress (non-blocking):
885
+ ```bash
886
+ node -e "
887
+ const ic = require('${REPO_ROOT}/lib/issue-context.cjs');
888
+ ic.updateProjectReadme()
889
+ .then(ok => { if (ok) console.log(' Project README updated'); })
890
+ .catch(() => {});
891
+ " 2>/dev/null || true
892
+ ```
893
+
894
+ 5. Post Status Update to Projects v2 board (non-blocking):
895
+ ```bash
896
+ BOARD_NODE_ID=$(python3 -c "
897
+ import json
898
+ try:
899
+ p = json.load(open('${MGW_DIR}/project.json'))
900
+ print(p.get('project', {}).get('project_board', {}).get('node_id', ''))
901
+ except: print('')
902
+ " 2>/dev/null || echo "")
903
+
904
+ if [ -n "$BOARD_NODE_ID" ]; then
905
+ MILESTONE_SUMMARY="Milestone ${MILESTONE_NUM} (${MILESTONE_NAME}) complete: ${TOTAL_ISSUES} issues, ${#COMPLETED_ISSUES[@]} PRs created"
906
+ gh api graphql -f query='mutation($projectId: ID!, $body: String!) {
907
+ createProjectV2StatusUpdate(input: {
908
+ projectId: $projectId
909
+ body: $body
910
+ status: ON_TRACK
911
+ }) { statusUpdate { id } }
912
+ }' -f projectId="$BOARD_NODE_ID" -f body="$MILESTONE_SUMMARY" 2>/dev/null || true
913
+ fi
914
+ ```
915
+
916
+ 6. Advance active milestone pointer in project.json:
918
917
  ```bash
919
918
  node -e "
920
919
  const { loadProjectState, resolveActiveMilestoneIndex, writeProjectState } = require('./lib/state.cjs');
@@ -937,7 +936,7 @@ writeProjectState(state);
937
936
  "
938
937
  ```
939
938
 
940
- 5. Milestone mapping verification:
939
+ 7. Milestone mapping verification:
941
940
 
942
941
  After advancing to the next milestone, check its GSD linkage using `getGsdState()`
943
942
  from `lib/gsd-adapter.cjs` to read current GSD execution state (.planning/STATE.md
@@ -1028,7 +1027,7 @@ else:
1028
1027
  esac
1029
1028
  ```
1030
1029
 
1031
- 6. Display completion banner:
1030
+ 8. Display completion banner:
1032
1031
  ```
1033
1032
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1034
1033
  MGW ► MILESTONE ${MILESTONE_NUM} COMPLETE ✓
@@ -1057,7 +1056,7 @@ Draft release created: ${RELEASE_TAG}
1057
1056
  ───────────────────────────────────────────────────────────────
1058
1057
  ```
1059
1058
 
1060
- 7. Check if next milestone exists and offer auto-advance (only if no failures in current).
1059
+ 9. Check if next milestone exists and offer auto-advance (only if no failures in current).
1061
1060
 
1062
1061
  **If some issues failed:**
1063
1062
 
@@ -1160,7 +1159,7 @@ Milestone NOT closed. Re-run after resolving remaining failures:
1160
1159
  /mgw:milestone ${MILESTONE_NUM}
1161
1160
  ```
1162
1161
 
1163
- 8. Post final results table as GitHub comment on the first issue in the milestone:
1162
+ 10. Post final results table as GitHub comment on the first issue in the milestone:
1164
1163
  ```bash
1165
1164
  gh issue comment ${FIRST_ISSUE_NUMBER} --body "$FINAL_RESULTS_COMMENT"
1166
1165
  ```
@@ -180,6 +180,25 @@ fi
180
180
  @workflows/create-github-structure.md
181
181
  </step>
182
182
 
183
+ <step name="populate_project_readme">
184
+ **Populate Project README on GitHub Projects v2 board (non-blocking):**
185
+
186
+ After GitHub structure creation, if a board is configured, populate the Project README
187
+ with project vision and milestone overview. This gives developers a landing page
188
+ when they open the board. Uses the shared `updateProjectReadme()` function from
189
+ `lib/issue-context.cjs` — the same function called by `mgw:milestone` and `mgw:sync --full`
190
+ to keep the README current.
191
+
192
+ ```bash
193
+ node -e "
194
+ const ic = require('${REPO_ROOT}/lib/issue-context.cjs');
195
+ ic.updateProjectReadme()
196
+ .then(ok => { if (ok) console.log('Project README populated on board'); })
197
+ .catch(() => {});
198
+ " 2>/dev/null || true
199
+ ```
200
+ </step>
201
+
183
202
  </process>
184
203
 
185
204
  <success_criteria>