@@ -38,6 +38,7 @@ Checkpoints requiring user input:
3838@~ /.claude/commands/mgw/workflows/github.md
3939@~ /.claude/commands/mgw/workflows/gsd.md
4040@~ /.claude/commands/mgw/workflows/validation.md
41+ @~ /.claude/commands/mgw/workflows/board-sync.md
4142</execution_context>
4243
4344<context >
@@ -57,6 +58,66 @@ REPO_ROOT=$(git rev-parse --show-toplevel)
5758DEFAULT=$( gh repo view --json defaultBranchRef -q .defaultBranchRef.name)
5859```
5960
61+ Define the board sync utility (non-blocking — see board-sync.md for full reference):
62+ ``` bash
63+ update_board_status () {
64+ local ISSUE_NUMBER=" $1 "
65+ local NEW_STAGE=" $2 "
66+ if [ -z " $ISSUE_NUMBER " ] || [ -z " $NEW_STAGE " ]; then return 0; fi
67+ BOARD_NODE_ID=$( python3 -c "
68+ import json,sys,os
69+ try:
70+ p=json.load(open('${REPO_ROOT} /.mgw/project.json'))
71+ print(p.get('project',{}).get('project_board',{}).get('node_id',''))
72+ except: print('')
73+ " 2> /dev/null || echo " " )
74+ if [ -z " $BOARD_NODE_ID " ]; then return 0; fi
75+ ITEM_ID=$( python3 -c "
76+ import json,sys
77+ try:
78+ p=json.load(open('${REPO_ROOT} /.mgw/project.json'))
79+ for m in p.get('milestones',[]):
80+ for i in m.get('issues',[]):
81+ if i.get('github_number')==${ISSUE_NUMBER} :
82+ print(i.get('board_item_id','')); sys.exit(0)
83+ print('')
84+ except: print('')
85+ " 2> /dev/null || echo " " )
86+ if [ -z " $ITEM_ID " ]; then return 0; fi
87+ FIELD_ID=$( python3 -c "
88+ import json,sys,os
89+ try:
90+ s='${REPO_ROOT} /.mgw/board-schema.json'
91+ if os.path.exists(s):
92+ print(json.load(open(s)).get('fields',{}).get('status',{}).get('field_id',''))
93+ else:
94+ p=json.load(open('${REPO_ROOT} /.mgw/project.json'))
95+ print(p.get('project',{}).get('project_board',{}).get('fields',{}).get('status',{}).get('field_id',''))
96+ except: print('')
97+ " 2> /dev/null || echo " " )
98+ if [ -z " $FIELD_ID " ]; then return 0; fi
99+ OPTION_ID=$( python3 -c "
100+ import json,sys,os
101+ try:
102+ stage='${NEW_STAGE} '
103+ s='${REPO_ROOT} /.mgw/board-schema.json'
104+ if os.path.exists(s):
105+ print(json.load(open(s)).get('fields',{}).get('status',{}).get('options',{}).get(stage,''))
106+ else:
107+ p=json.load(open('${REPO_ROOT} /.mgw/project.json'))
108+ print(p.get('project',{}).get('project_board',{}).get('fields',{}).get('status',{}).get('options',{}).get(stage,''))
109+ except: print('')
110+ " 2> /dev/null || echo " " )
111+ if [ -z " $OPTION_ID " ]; then return 0; fi
112+ gh api graphql -f query='
113+ mutation($projectId:ID!,$itemId:ID!,$fieldId:ID!,$optionId:String!){
114+ updateProjectV2ItemFieldValue(input:{projectId:$projectId,itemId:$itemId,fieldId:$fieldId,value:{singleSelectOptionId:$optionId}}){projectV2Item{id}}
115+ }
116+ ' -f projectId=" $BOARD_NODE_ID " -f itemId=" $ITEM_ID " \
117+ -f fieldId=" $FIELD_ID " -f optionId=" $OPTION_ID " 2> /dev/null || true
118+ }
119+ ```
120+
60121Parse $ARGUMENTS for issue number. If missing:
61122```
62123AskUserQuestion(
@@ -248,7 +309,7 @@ Return ONLY valid JSON:
248309| ---------------| --------|
249310| ** informational** | Log: "MGW: ${NEW_COUNT} new comment(s) reviewed — informational, continuing." Update ` triage.last_comment_count ` in state file. Continue pipeline. |
250311| ** 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). |
251- | ** 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. |
312+ | ** blocking** | Log: "MGW: Blocking comment detected — pipeline paused." Update state: ` pipeline_stage = "blocked" ` . Apply mgw: blocked label. Call ` update_board_status $ISSUE_NUMBER "blocked" ` (non-blocking). Post comment on issue: ` > **MGW** . \ ` pipeline-blocked\` . Blocked by stakeholder comment. Reason: ${blocking_reason}`. Stop pipeline execution. |
252313
253314** Security keyword check for material comments:**
254315``` bash
@@ -339,6 +400,9 @@ Log comment in state file (at `${REPO_ROOT}/.mgw/active/`).
339400Only run this step if gsd_route is "gsd: quick " or "gsd: quick --full".
340401
341402Update pipeline_stage to "executing" in state file (at ` ${REPO_ROOT}/.mgw/active/ ` ).
403+ ``` bash
404+ update_board_status $ISSUE_NUMBER " executing" # non-blocking board sync
405+ ```
342406
343407Determine flags:
344408- "gsd: quick " → $QUICK_FLAGS = ""
@@ -539,6 +603,9 @@ node ~/.claude/get-shit-done/bin/gsd-tools.cjs commit "docs(quick-${next_num}):
539603```
540604
541605Update state (at ` ${REPO_ROOT}/.mgw/active/ ` ): gsd_artifacts.path = $QUICK_DIR, pipeline_stage = "verifying".
606+ ``` bash
607+ update_board_status $ISSUE_NUMBER " verifying" # non-blocking board sync
608+ ```
542609</step >
543610
544611<step name =" execute_gsd_milestone " >
@@ -576,6 +643,7 @@ Set pipeline_stage to "discussing" and apply "mgw:discussing" label:
576643``` bash
577644gh issue edit ${ISSUE_NUMBER} --remove-label " mgw:in-progress" 2> /dev/null
578645gh issue edit ${ISSUE_NUMBER} --add-label " mgw:discussing" 2> /dev/null
646+ update_board_status $ISSUE_NUMBER " discussing" # non-blocking board sync
579647```
580648
581649Present to user:
@@ -623,6 +691,9 @@ If proceed: apply "mgw:approved" label and continue.
623691 ```
624692
625693 Update pipeline_stage to "planning" (at `${REPO_ROOT}/.mgw/active/`).
694+ ```bash
695+ update_board_status $ISSUE_NUMBER "planning" # non-blocking board sync
696+ ```
626697
6276982 . ** If resuming with pipeline_stage = "planning" and ROADMAP.md exists:**
628699 Discover phases from ROADMAP and run the full per-phase GSD lifecycle:
@@ -785,6 +856,9 @@ COMMENTEOF
785856 ```
786857
787858 After ALL phases complete → update pipeline_stage to "verifying" (at ` ${REPO_ROOT}/.mgw/active/ ` ).
859+ ``` bash
860+ update_board_status $ISSUE_NUMBER " verifying" # non-blocking board sync
861+ ```
788862</step >
789863
790864<step name =" post_execution_update " >
@@ -822,6 +896,9 @@ gh issue comment ${ISSUE_NUMBER} --body "$EXEC_BODY" 2>/dev/null || true
822896```
823897
824898Update pipeline_stage to "pr-pending" (at ` ${REPO_ROOT}/.mgw/active/ ` ).
899+ ``` bash
900+ update_board_status $ISSUE_NUMBER " pr-created" # non-blocking board sync (pr-pending maps to pr-created on board)
901+ ```
825902</step >
826903
827904<step name =" create_pr " >
@@ -992,6 +1069,10 @@ Update state (at `${REPO_ROOT}/.mgw/active/`):
9921069- linked_pr = PR number
9931070- pipeline_stage = "pr-created"
9941071
1072+ ``` bash
1073+ update_board_status $ISSUE_NUMBER " pr-created" # non-blocking board sync
1074+ ```
1075+
9951076Add cross-ref (at ` ${REPO_ROOT}/.mgw/cross-refs.json ` ): issue → PR.
9961077</step >
9971078
@@ -1052,6 +1133,9 @@ gh issue comment ${ISSUE_NUMBER} --body "$PR_READY_BODY" 2>/dev/null || true
10521133```
10531134
10541135Update pipeline_stage to "done" (at ` ${REPO_ROOT}/.mgw/active/ ` ).
1136+ ``` bash
1137+ update_board_status $ISSUE_NUMBER " done" # non-blocking board sync
1138+ ```
10551139
10561140Report to user:
10571141```
@@ -1092,5 +1176,7 @@ Next:
10921176- [ ] Worktree cleaned up, user returned to main workspace
10931177- [ ] mgw: in-progress label removed at completion
10941178- [ ] State file updated through all pipeline stages
1179+ - [ ] Board Status field synced at each pipeline_stage transition (non-blocking)
1180+ - [ ] Board sync failures never block pipeline execution
10951181- [ ] User prompted to run /mgw: sync after merge
10961182</success_criteria>
0 commit comments