@snipcodeit/mgw 0.1.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/LICENSE +21 -0
- package/README.md +517 -0
- package/bin/mgw-install.cjs +81 -0
- package/commands/ask.md +416 -0
- package/commands/assign.md +333 -0
- package/commands/board.md +1679 -0
- package/commands/help.md +119 -0
- package/commands/init.md +250 -0
- package/commands/issue.md +469 -0
- package/commands/issues.md +109 -0
- package/commands/link.md +122 -0
- package/commands/milestone.md +952 -0
- package/commands/next.md +375 -0
- package/commands/pr.md +277 -0
- package/commands/project.md +1801 -0
- package/commands/review.md +260 -0
- package/commands/roadmap.md +489 -0
- package/commands/run.md +1282 -0
- package/commands/status.md +526 -0
- package/commands/sync.md +243 -0
- package/commands/update.md +282 -0
- package/commands/workflows/board-sync.md +404 -0
- package/commands/workflows/github.md +385 -0
- package/commands/workflows/gsd.md +377 -0
- package/commands/workflows/state.md +412 -0
- package/commands/workflows/validation.md +144 -0
- package/dist/bin/mgw.cjs +291 -0
- package/dist/claude-Vp9qvImH.cjs +466 -0
- package/dist/lib/index.cjs +395 -0
- package/package.json +51 -0
- package/templates/schema.json +164 -0
- package/templates/vision-brief-schema.json +98 -0
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
<purpose>
|
|
2
|
+
Shared state management for MGW commands. Handles .mgw/ directory initialization,
|
|
3
|
+
issue state read/write, cross-ref management, and staleness detection against GitHub.
|
|
4
|
+
Every command that touches .mgw/ state references this file.
|
|
5
|
+
</purpose>
|
|
6
|
+
|
|
7
|
+
## Directory Structure
|
|
8
|
+
|
|
9
|
+
`.mgw/` lives at repo root, is gitignored, and is local-only per developer.
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
.mgw/
|
|
13
|
+
config.json # User prefs (github username, default filters)
|
|
14
|
+
active/ # In-progress issue pipelines
|
|
15
|
+
<number>-<slug>.json
|
|
16
|
+
completed/ # Archived after PR merged/issue closed
|
|
17
|
+
cross-refs.json # Bidirectional issue/PR/branch links
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## validate_and_load
|
|
21
|
+
|
|
22
|
+
Single entry point for state initialization. Every command that touches .mgw/ calls
|
|
23
|
+
this pattern at startup. It ensures directory structure, gitignore entries, cross-refs,
|
|
24
|
+
and runs a lightweight staleness check.
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
REPO_ROOT=$(git rev-parse --show-toplevel)
|
|
28
|
+
MGW_DIR="${REPO_ROOT}/.mgw"
|
|
29
|
+
|
|
30
|
+
# 1. Ensure directory structure
|
|
31
|
+
mkdir -p "${MGW_DIR}/active" "${MGW_DIR}/completed"
|
|
32
|
+
|
|
33
|
+
# 2. Ensure gitignore entries
|
|
34
|
+
for ENTRY in ".mgw/" ".worktrees/"; do
|
|
35
|
+
if ! grep -q "^\\${ENTRY}\$" "${REPO_ROOT}/.gitignore" 2>/dev/null; then
|
|
36
|
+
echo "${ENTRY}" >> "${REPO_ROOT}/.gitignore"
|
|
37
|
+
fi
|
|
38
|
+
done
|
|
39
|
+
|
|
40
|
+
# 3. Initialize cross-refs if missing
|
|
41
|
+
if [ ! -f "${MGW_DIR}/cross-refs.json" ]; then
|
|
42
|
+
echo '{"links":[]}' > "${MGW_DIR}/cross-refs.json"
|
|
43
|
+
fi
|
|
44
|
+
|
|
45
|
+
# 4. Migrate project.json schema (idempotent — adds new fields without overwriting)
|
|
46
|
+
# This ensures all commands see gsd_milestone_id, gsd_state, active_gsd_milestone, etc.
|
|
47
|
+
# Non-blocking: if migration fails for any reason, continue silently.
|
|
48
|
+
if [ -f "${MGW_DIR}/project.json" ]; then
|
|
49
|
+
node -e "
|
|
50
|
+
const { migrateProjectState } = require('./lib/state.cjs');
|
|
51
|
+
try { migrateProjectState(); } catch(e) { /* non-blocking */ }
|
|
52
|
+
" 2>/dev/null || true
|
|
53
|
+
fi
|
|
54
|
+
|
|
55
|
+
# 5. Run staleness check (see Staleness Detection below)
|
|
56
|
+
# Only if active issues exist — skip for commands that don't need it (e.g., init, help)
|
|
57
|
+
if ls "${MGW_DIR}/active/"*.json 1>/dev/null 2>&1; then
|
|
58
|
+
check_staleness "${MGW_DIR}"
|
|
59
|
+
fi
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Staleness Detection
|
|
63
|
+
|
|
64
|
+
Lightweight check comparing GitHub `updatedAt` timestamps with local state file
|
|
65
|
+
modification times. Runs on every MGW command that touches state. Non-blocking:
|
|
66
|
+
if the check fails (network error, API limit), log a warning and continue.
|
|
67
|
+
|
|
68
|
+
### Per-Issue Check
|
|
69
|
+
For commands that operate on a specific issue:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
# Non-blocking: if check fails, continue with warning
|
|
73
|
+
check_issue_staleness() {
|
|
74
|
+
local ISSUE_NUMBER="$1"
|
|
75
|
+
local STATE_FILE="$2"
|
|
76
|
+
|
|
77
|
+
# Get GitHub's last update timestamp
|
|
78
|
+
GH_UPDATED=$(gh issue view "$ISSUE_NUMBER" --json updatedAt -q .updatedAt 2>/dev/null)
|
|
79
|
+
if [ -z "$GH_UPDATED" ]; then
|
|
80
|
+
return 0 # Can't check — don't block
|
|
81
|
+
fi
|
|
82
|
+
|
|
83
|
+
# Compare with local state file modification time
|
|
84
|
+
LOCAL_MTIME=$(stat -c %Y "$STATE_FILE" 2>/dev/null || echo "0")
|
|
85
|
+
GH_EPOCH=$(date -d "$GH_UPDATED" +%s 2>/dev/null || echo "0")
|
|
86
|
+
|
|
87
|
+
if [ "$GH_EPOCH" -gt "$LOCAL_MTIME" ]; then
|
|
88
|
+
echo "MGW: Stale state detected for #${ISSUE_NUMBER} — auto-syncing..."
|
|
89
|
+
# Re-fetch issue data and update local state
|
|
90
|
+
FRESH_DATA=$(gh issue view "$ISSUE_NUMBER" --json number,title,body,labels,assignees,state,comments,url,milestone 2>/dev/null)
|
|
91
|
+
if [ -n "$FRESH_DATA" ]; then
|
|
92
|
+
# Update the issue section of the state file (preserve pipeline_stage, triage, etc.)
|
|
93
|
+
# Implementation: read state JSON, update .issue fields, write back
|
|
94
|
+
touch "$STATE_FILE" # Update mtime to prevent re-triggering
|
|
95
|
+
fi
|
|
96
|
+
return 1 # Stale — caller can react
|
|
97
|
+
fi
|
|
98
|
+
return 0 # Fresh
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Batch Check (Milestone-Level)
|
|
103
|
+
For commands that check across all active issues in a single API call:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
# Single GraphQL call for all open issues — use for milestone operations
|
|
107
|
+
check_batch_staleness() {
|
|
108
|
+
local MGW_DIR="$1"
|
|
109
|
+
|
|
110
|
+
OWNER=$(gh repo view --json owner -q .owner.login 2>/dev/null)
|
|
111
|
+
REPO=$(gh repo view --json name -q .name 2>/dev/null)
|
|
112
|
+
|
|
113
|
+
if [ -z "$OWNER" ] || [ -z "$REPO" ]; then
|
|
114
|
+
return 0 # Can't check — don't block
|
|
115
|
+
fi
|
|
116
|
+
|
|
117
|
+
ISSUES_JSON=$(gh api graphql -f query='
|
|
118
|
+
query($owner: String!, $repo: String!) {
|
|
119
|
+
repository(owner: $owner, name: $repo) {
|
|
120
|
+
issues(first: 50, states: OPEN) {
|
|
121
|
+
nodes { number updatedAt }
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
' -f owner="$OWNER" -f repo="$REPO" --jq '.data.repository.issues.nodes' 2>/dev/null)
|
|
126
|
+
|
|
127
|
+
if [ -z "$ISSUES_JSON" ]; then
|
|
128
|
+
return 0 # Can't check — don't block
|
|
129
|
+
fi
|
|
130
|
+
|
|
131
|
+
# Compare each issue's updatedAt with local state file mtime
|
|
132
|
+
# Flag any stale issues for sync
|
|
133
|
+
echo "$ISSUES_JSON"
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Staleness Behavior
|
|
138
|
+
- When stale state is detected: **auto-sync with notice** — sync automatically, print one line telling the user it happened, do not block
|
|
139
|
+
- When the check fails (network, API limit, error): **continue silently** — never let staleness detection prevent command execution
|
|
140
|
+
- Scope: covers **both milestone-level and issue-level state**
|
|
141
|
+
|
|
142
|
+
## Comment Tracking
|
|
143
|
+
|
|
144
|
+
Comment tracking detects new comments posted on an issue between triage and execution.
|
|
145
|
+
The `triage.last_comment_count` and `triage.last_comment_at` fields are populated during
|
|
146
|
+
triage (issue.md) and checked before GSD execution begins (run.md).
|
|
147
|
+
|
|
148
|
+
### Comment Tracking Fields
|
|
149
|
+
|
|
150
|
+
| Field | Type | Set By | Description |
|
|
151
|
+
|-------|------|--------|-------------|
|
|
152
|
+
| `triage.last_comment_count` | number | issue.md | Total comment count at triage time |
|
|
153
|
+
| `triage.last_comment_at` | string\|null | issue.md | ISO timestamp of most recent comment at triage time |
|
|
154
|
+
|
|
155
|
+
### Pre-Flight Comment Check
|
|
156
|
+
|
|
157
|
+
Before GSD execution starts, run.md compares current comment count against the stored
|
|
158
|
+
count. If new comments are detected, they are classified before proceeding:
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
# Fetch current comment state from GitHub
|
|
162
|
+
CURRENT_COMMENTS=$(gh issue view $ISSUE_NUMBER --json comments --jq '.comments | length')
|
|
163
|
+
STORED_COMMENTS="${triage.last_comment_count}"
|
|
164
|
+
|
|
165
|
+
if [ "$CURRENT_COMMENTS" -gt "$STORED_COMMENTS" ]; then
|
|
166
|
+
# New comments detected — fetch and classify
|
|
167
|
+
NEW_COMMENT_BODIES=$(gh issue view $ISSUE_NUMBER --json comments \
|
|
168
|
+
--jq "[.comments[-$(($CURRENT_COMMENTS - $STORED_COMMENTS)):]] | .[].body")
|
|
169
|
+
fi
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Comment Classification
|
|
173
|
+
|
|
174
|
+
New comments are classified by a general-purpose agent into one of three categories:
|
|
175
|
+
|
|
176
|
+
| Classification | Meaning | Pipeline Action |
|
|
177
|
+
|---------------|---------|-----------------|
|
|
178
|
+
| **material** | Changes scope, requirements, or acceptance criteria | Flag for re-triage — update state, re-run triage analysis |
|
|
179
|
+
| **informational** | Status update, +1, question, acknowledgment | Log and continue — no pipeline impact |
|
|
180
|
+
| **blocking** | Explicit "don't work on this yet", "hold", "wait" | Pause pipeline — set pipeline_stage to "blocked" |
|
|
181
|
+
|
|
182
|
+
The classification agent receives the new comment bodies and the issue context, and returns
|
|
183
|
+
a JSON result:
|
|
184
|
+
|
|
185
|
+
```json
|
|
186
|
+
{
|
|
187
|
+
"classification": "material|informational|blocking",
|
|
188
|
+
"reasoning": "Brief explanation",
|
|
189
|
+
"new_requirements": ["list of new requirements if material"],
|
|
190
|
+
"blocking_reason": "reason if blocking"
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Comment Delta in Drift Detection
|
|
195
|
+
|
|
196
|
+
sync.md includes comment delta as a drift signal. If the current comment count differs
|
|
197
|
+
from `triage.last_comment_count`, the issue is flagged as having unreviewed comments
|
|
198
|
+
in the sync report.
|
|
199
|
+
|
|
200
|
+
## Issue State Schema
|
|
201
|
+
|
|
202
|
+
File: `.mgw/active/<number>-<slug>.json`
|
|
203
|
+
|
|
204
|
+
```json
|
|
205
|
+
{
|
|
206
|
+
"issue": {
|
|
207
|
+
"number": 42,
|
|
208
|
+
"title": "Short title",
|
|
209
|
+
"url": "https://github.com/owner/repo/issues/42",
|
|
210
|
+
"labels": ["bug"],
|
|
211
|
+
"assignee": "username"
|
|
212
|
+
},
|
|
213
|
+
"triage": {
|
|
214
|
+
"scope": { "files": 0, "systems": [] },
|
|
215
|
+
"validity": "pending|confirmed|invalid",
|
|
216
|
+
"security_notes": "",
|
|
217
|
+
"conflicts": [],
|
|
218
|
+
"last_comment_count": 0,
|
|
219
|
+
"last_comment_at": null,
|
|
220
|
+
"gate_result": {
|
|
221
|
+
"status": "passed|blocked",
|
|
222
|
+
"blockers": [],
|
|
223
|
+
"warnings": [],
|
|
224
|
+
"missing_fields": []
|
|
225
|
+
}
|
|
226
|
+
},
|
|
227
|
+
"gsd_route": null,
|
|
228
|
+
"gsd_artifacts": { "type": null, "path": null },
|
|
229
|
+
"pipeline_stage": "new|triaged|needs-info|needs-security-review|discussing|approved|planning|diagnosing|executing|verifying|pr-created|done|failed|blocked",
|
|
230
|
+
"comments_posted": [],
|
|
231
|
+
"linked_pr": null,
|
|
232
|
+
"linked_issues": [],
|
|
233
|
+
"linked_branches": []
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
## Stage Flow Diagram
|
|
238
|
+
|
|
239
|
+
```
|
|
240
|
+
new --> triaged (triage passes all gates)
|
|
241
|
+
new --> needs-info (validity=invalid OR insufficient detail)
|
|
242
|
+
new --> needs-security-review (security=high)
|
|
243
|
+
|
|
244
|
+
needs-info --> triaged (re-triage after info provided)
|
|
245
|
+
needs-security-review --> triaged (re-triage after security ack)
|
|
246
|
+
|
|
247
|
+
triaged --> discussing (new-milestone route, large scope)
|
|
248
|
+
triaged --> approved (discussion complete, ready for execution)
|
|
249
|
+
triaged --> planning (direct route, skip discussion)
|
|
250
|
+
triaged --> diagnosing (gsd:diagnose-issues route)
|
|
251
|
+
|
|
252
|
+
discussing --> approved (stakeholder approval)
|
|
253
|
+
approved --> planning
|
|
254
|
+
|
|
255
|
+
planning --> executing
|
|
256
|
+
diagnosing --> planning (root cause found, proceeding to fix)
|
|
257
|
+
diagnosing --> blocked (investigation inconclusive)
|
|
258
|
+
executing --> verifying
|
|
259
|
+
verifying --> pr-created
|
|
260
|
+
pr-created --> done
|
|
261
|
+
|
|
262
|
+
Any stage --> blocked (blocking comment detected)
|
|
263
|
+
blocked --> triaged (re-triage after blocker resolved)
|
|
264
|
+
Any stage --> failed (unrecoverable error)
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
## Slug Generation
|
|
268
|
+
|
|
269
|
+
Use gsd-tools for consistent slug generation:
|
|
270
|
+
```bash
|
|
271
|
+
SLUG=$(node ~/.claude/get-shit-done/bin/gsd-tools.cjs generate-slug "${issue_title}" --raw)
|
|
272
|
+
SLUG="${SLUG:0:40}" # gsd-tools doesn't truncate; MGW enforces 40-char limit
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
## Timestamps
|
|
276
|
+
|
|
277
|
+
Use gsd-tools for ISO timestamp generation:
|
|
278
|
+
```bash
|
|
279
|
+
TIMESTAMP=$(node ~/.claude/get-shit-done/bin/gsd-tools.cjs current-timestamp --raw)
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
## Cross-Refs Schema
|
|
283
|
+
|
|
284
|
+
File: `.mgw/cross-refs.json`
|
|
285
|
+
|
|
286
|
+
```json
|
|
287
|
+
{
|
|
288
|
+
"links": [
|
|
289
|
+
{ "a": "issue:42", "b": "issue:43", "type": "related", "created": "2026-02-24T10:00:00Z" },
|
|
290
|
+
{ "a": "issue:42", "b": "pr:15", "type": "implements", "created": "2026-02-24T12:00:00Z" },
|
|
291
|
+
{ "a": "issue:42", "b": "branch:fix/auth-42", "type": "tracks", "created": "2026-02-24T10:00:00Z" }
|
|
292
|
+
]
|
|
293
|
+
}
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
### Link Types
|
|
297
|
+
| a | b | type |
|
|
298
|
+
|---|---|------|
|
|
299
|
+
| issue | issue | related |
|
|
300
|
+
| issue | pr | implements |
|
|
301
|
+
| issue | branch | tracks |
|
|
302
|
+
| pr | branch | tracks |
|
|
303
|
+
|
|
304
|
+
## Project State (project.json)
|
|
305
|
+
|
|
306
|
+
File: `.mgw/project.json` — Created by `/mgw:project`, read/updated by `/mgw:milestone` and `/mgw:next`.
|
|
307
|
+
|
|
308
|
+
### Read Project State
|
|
309
|
+
```bash
|
|
310
|
+
MGW_DIR="${REPO_ROOT}/.mgw"
|
|
311
|
+
PROJECT_JSON=$(cat "${MGW_DIR}/project.json" 2>/dev/null)
|
|
312
|
+
if [ -z "$PROJECT_JSON" ]; then
|
|
313
|
+
echo "No project initialized. Run /mgw:project first."
|
|
314
|
+
exit 1
|
|
315
|
+
fi
|
|
316
|
+
|
|
317
|
+
# Resolve active milestone index — supports both new schema (active_gsd_milestone string)
|
|
318
|
+
# and legacy schema (current_milestone 1-indexed integer).
|
|
319
|
+
ACTIVE_IDX=$(node -e "
|
|
320
|
+
const { loadProjectState, resolveActiveMilestoneIndex } = require('./lib/state.cjs');
|
|
321
|
+
const state = loadProjectState();
|
|
322
|
+
console.log(resolveActiveMilestoneIndex(state));
|
|
323
|
+
")
|
|
324
|
+
CURRENT_MILESTONE=$((ACTIVE_IDX + 1)) # 1-indexed for display/legacy compat
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
### Read Milestone Issues
|
|
328
|
+
```bash
|
|
329
|
+
MILESTONE_ISSUES=$(node -e "
|
|
330
|
+
const { loadProjectState, resolveActiveMilestoneIndex } = require('./lib/state.cjs');
|
|
331
|
+
const state = loadProjectState();
|
|
332
|
+
const idx = resolveActiveMilestoneIndex(state);
|
|
333
|
+
if (idx < 0) { console.error('No active milestone'); process.exit(1); }
|
|
334
|
+
console.log(JSON.stringify(state.milestones[idx].issues || [], null, 2));
|
|
335
|
+
")
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
### Update Issue Pipeline Stage
|
|
339
|
+
Used after each `/mgw:run` completion to checkpoint progress.
|
|
340
|
+
```bash
|
|
341
|
+
node -e "
|
|
342
|
+
const { loadProjectState, resolveActiveMilestoneIndex, writeProjectState } = require('./lib/state.cjs');
|
|
343
|
+
const state = loadProjectState();
|
|
344
|
+
const idx = resolveActiveMilestoneIndex(state);
|
|
345
|
+
if (idx < 0) { console.error('No active milestone'); process.exit(1); }
|
|
346
|
+
const issue = (state.milestones[idx].issues || []).find(i => i.github_number === ${ISSUE_NUMBER});
|
|
347
|
+
if (issue) { issue.pipeline_stage = '${NEW_STAGE}'; }
|
|
348
|
+
writeProjectState(state);
|
|
349
|
+
"
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
Valid stages: `new`, `triaged`, `planning`, `diagnosing`, `executing`, `verifying`, `pr-created`, `done`, `failed`, `blocked`.
|
|
353
|
+
|
|
354
|
+
### Advance Current Milestone
|
|
355
|
+
Used after milestone completion to move pointer to next milestone.
|
|
356
|
+
```bash
|
|
357
|
+
node -e "
|
|
358
|
+
const { loadProjectState, resolveActiveMilestoneIndex, writeProjectState } = require('./lib/state.cjs');
|
|
359
|
+
const state = loadProjectState();
|
|
360
|
+
const currentIdx = resolveActiveMilestoneIndex(state);
|
|
361
|
+
const next = (state.milestones || [])[currentIdx + 1];
|
|
362
|
+
if (next) {
|
|
363
|
+
state.active_gsd_milestone = next.gsd_milestone_id || null;
|
|
364
|
+
if (!state.active_gsd_milestone) {
|
|
365
|
+
state.current_milestone = currentIdx + 2; // legacy fallback
|
|
366
|
+
}
|
|
367
|
+
} else {
|
|
368
|
+
state.active_gsd_milestone = null;
|
|
369
|
+
state.current_milestone = currentIdx + 2; // past end, signals completion
|
|
370
|
+
}
|
|
371
|
+
writeProjectState(state);
|
|
372
|
+
"
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
Only advance if ALL issues in current milestone completed successfully.
|
|
376
|
+
|
|
377
|
+
### Phase Map Usage
|
|
378
|
+
|
|
379
|
+
The `phase_map` in project.json maps GSD phase numbers to their metadata. This is the
|
|
380
|
+
bridge between MGW's issue tracking and GSD's phase-based execution:
|
|
381
|
+
|
|
382
|
+
```json
|
|
383
|
+
{
|
|
384
|
+
"phase_map": {
|
|
385
|
+
"1": {"milestone_index": 0, "gsd_route": "plan-phase", "name": "Core Data Models"},
|
|
386
|
+
"2": {"milestone_index": 0, "gsd_route": "plan-phase", "name": "API Endpoints"},
|
|
387
|
+
"3": {"milestone_index": 1, "gsd_route": "plan-phase", "name": "Frontend Components"}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
Each issue in project.json has a `phase_number` field that indexes into this map.
|
|
393
|
+
When `/mgw:run` picks up an issue, it reads the `phase_number` to determine which
|
|
394
|
+
GSD phase directory (`.planning/phases/{NN}-{slug}/`) to operate in.
|
|
395
|
+
|
|
396
|
+
Issues created outside of `/mgw:project` (e.g., manually filed bugs) will not have
|
|
397
|
+
a `phase_number`. In this case, `/mgw:run` falls back to the quick pipeline.
|
|
398
|
+
|
|
399
|
+
## Consumers
|
|
400
|
+
|
|
401
|
+
| Pattern | Referenced By |
|
|
402
|
+
|---------|-------------|
|
|
403
|
+
| validate_and_load | init.md, issue.md, run.md, update.md, link.md, pr.md, sync.md, milestone.md, ask.md |
|
|
404
|
+
| Per-issue staleness | run.md, issue.md, update.md |
|
|
405
|
+
| Batch staleness | sync.md (full reconciliation), milestone.md |
|
|
406
|
+
| Comment tracking | issue.md (populate), run.md (pre-flight check), sync.md (drift detection) |
|
|
407
|
+
| Issue state schema | issue.md, run.md, update.md, sync.md |
|
|
408
|
+
| Cross-refs schema | link.md, run.md, pr.md, sync.md |
|
|
409
|
+
| Slug generation | issue.md, run.md |
|
|
410
|
+
| Project state | milestone.md, next.md, ask.md |
|
|
411
|
+
| Gate result schema | issue.md (populate), run.md (validate) |
|
|
412
|
+
| Board status sync | board-sync.md (utility), issue.md (triage transitions), run.md (pipeline transitions) |
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
<purpose>
|
|
2
|
+
Delegation boundary rule for MGW commands. Provides a mechanical check and review
|
|
3
|
+
checklist to enforce that MGW orchestrates but never codes. Any developer reviewing
|
|
4
|
+
or writing an MGW command can apply this rule to get a clear yes/no answer.
|
|
5
|
+
</purpose>
|
|
6
|
+
|
|
7
|
+
## The Delegation Boundary Rule
|
|
8
|
+
|
|
9
|
+
**MGW orchestrates. MGW never codes.**
|
|
10
|
+
|
|
11
|
+
MGW's job is to connect GitHub issues to GSD's execution engine and manage the
|
|
12
|
+
pipeline state between them. MGW reads state, writes state, talks to GitHub, and
|
|
13
|
+
spawns agents. It never reads application code, writes application code, or makes
|
|
14
|
+
implementation decisions.
|
|
15
|
+
|
|
16
|
+
## Mechanical Check
|
|
17
|
+
|
|
18
|
+
For any logic in an MGW command, ask:
|
|
19
|
+
|
|
20
|
+
> "If GSD improved this tomorrow, would MGW automatically benefit?"
|
|
21
|
+
|
|
22
|
+
- **YES** -- Logic is correctly delegated. It lives in a Task() agent or in GSD itself, and MGW references the result.
|
|
23
|
+
- **NO** -- Logic is misplaced in MGW. It should be moved into a Task() agent that MGW spawns.
|
|
24
|
+
|
|
25
|
+
### Examples
|
|
26
|
+
|
|
27
|
+
| Logic | Answer | Reasoning |
|
|
28
|
+
|-------|--------|-----------|
|
|
29
|
+
| "Fetch issue from GitHub" | N/A | This is GitHub API, not GSD. MGW may do this directly. |
|
|
30
|
+
| "Analyze which files are affected" | YES | GSD's executor reads code. If GSD got better at analysis, MGW benefits because it spawns an analysis agent. |
|
|
31
|
+
| "Parse the issue body for triage" | NO (violation) | If MGW inlines body parsing, GSD improvements don't help. Spawn a triage agent instead. |
|
|
32
|
+
| "Spawn a planner agent" | YES | The planner is a GSD agent. Improvements flow through. |
|
|
33
|
+
| "Write .mgw/active/42-fix.json" | N/A | State management is MGW's domain, not GSD's. |
|
|
34
|
+
|
|
35
|
+
## What MGW May Do Directly (Allowlist)
|
|
36
|
+
|
|
37
|
+
These operations are within MGW's boundary:
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
- Read/write .mgw/ state files (JSON)
|
|
41
|
+
- Read/write GitHub metadata (via gh CLI — patterns in workflows/github.md)
|
|
42
|
+
- Parse command arguments ($ARGUMENTS)
|
|
43
|
+
- Display user-facing output (banners, tables, prompts, reports)
|
|
44
|
+
- Spawn Task() agents (via templates in workflows/gsd.md)
|
|
45
|
+
- Call gsd-tools.cjs for utilities (slugs, timestamps, model resolution)
|
|
46
|
+
- Initialize state (via validate_and_load in workflows/state.md)
|
|
47
|
+
- Manage worktrees (git worktree add/remove)
|
|
48
|
+
- Check/set git branches (git checkout, git push)
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## What MGW Must NEVER Do Directly (Denylist)
|
|
52
|
+
|
|
53
|
+
These operations cross the delegation boundary:
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
- Read application source code (even for "quick" scope analysis)
|
|
57
|
+
- Write application source code
|
|
58
|
+
- Make architecture or implementation decisions
|
|
59
|
+
- Analyze code for scope, security, or conflicts
|
|
60
|
+
- Generate PR descriptions from code analysis (not from GSD artifacts)
|
|
61
|
+
- Choose libraries or implementation patterns
|
|
62
|
+
- Run application tests or interpret test results
|
|
63
|
+
- Any operation that requires understanding the project's implementation
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**If you find yourself needing to do something on the denylist:** Spawn an agent for it.
|
|
67
|
+
|
|
68
|
+
## Review Checklist
|
|
69
|
+
|
|
70
|
+
For each block of logic in an MGW command, check:
|
|
71
|
+
|
|
72
|
+
- [ ] Does it read/write .mgw/ state? -- **ALLOWED**
|
|
73
|
+
- [ ] Does it call gh CLI? -- **ALLOWED** (should match a pattern in workflows/github.md)
|
|
74
|
+
- [ ] Does it spawn a Task()? -- **ALLOWED** (must match template in workflows/gsd.md, must include CLAUDE.md injection)
|
|
75
|
+
- [ ] Does it call gsd-tools.cjs? -- **ALLOWED**
|
|
76
|
+
- [ ] Does it display output to the user? -- **ALLOWED**
|
|
77
|
+
- [ ] Does it manage git worktrees/branches? -- **ALLOWED**
|
|
78
|
+
- [ ] Does it parse $ARGUMENTS? -- **ALLOWED**
|
|
79
|
+
- [ ] Does it read application code? -- **VIOLATION** — spawn an analysis agent
|
|
80
|
+
- [ ] Does it write application code? -- **VIOLATION** — spawn an executor agent
|
|
81
|
+
- [ ] Does it make implementation decisions? -- **VIOLATION** — spawn a planner agent
|
|
82
|
+
- [ ] Does it analyze code for scope/security? -- **VIOLATION** — spawn a triage agent
|
|
83
|
+
- [ ] Does it generate content from code analysis? -- **VIOLATION** — spawn a content agent
|
|
84
|
+
|
|
85
|
+
## Applying the Rule: Concrete Example
|
|
86
|
+
|
|
87
|
+
**Before (issue.md inline analysis — VIOLATION):**
|
|
88
|
+
```
|
|
89
|
+
# BAD: MGW reading code directly
|
|
90
|
+
Search the codebase for files related to "${issue_title}"
|
|
91
|
+
grep -r "auth" src/
|
|
92
|
+
# Then MGW decides: "3 files affected, medium scope"
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**After (issue.md delegated analysis — CORRECT):**
|
|
96
|
+
```
|
|
97
|
+
# GOOD: MGW spawns an agent that reads code
|
|
98
|
+
Task(
|
|
99
|
+
prompt="
|
|
100
|
+
<files_to_read>
|
|
101
|
+
- ./CLAUDE.md (Project instructions)
|
|
102
|
+
- .agents/skills/ (Project skills)
|
|
103
|
+
</files_to_read>
|
|
104
|
+
|
|
105
|
+
Analyze GitHub issue #${ISSUE_NUMBER} against this codebase.
|
|
106
|
+
Search for affected files and systems.
|
|
107
|
+
Return: scope (files, systems, size), validity, security, conflicts.
|
|
108
|
+
",
|
|
109
|
+
subagent_type="general-purpose",
|
|
110
|
+
description="Triage issue #${ISSUE_NUMBER}"
|
|
111
|
+
)
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
The agent reads code and returns structured results. MGW reads the structured results,
|
|
115
|
+
writes them to .mgw/active/, and presents them to the user. MGW never touched the code.
|
|
116
|
+
|
|
117
|
+
## When In Doubt
|
|
118
|
+
|
|
119
|
+
If you're unsure whether a piece of logic belongs in MGW or in an agent:
|
|
120
|
+
|
|
121
|
+
1. Apply the mechanical check: "If GSD improved this, would MGW benefit?"
|
|
122
|
+
2. Check if it's on the allowlist (state, GitHub, display, spawn, utilities)
|
|
123
|
+
3. If neither gives a clear answer, default to **spawning an agent**
|
|
124
|
+
|
|
125
|
+
Over-delegation (spawning agents for trivial work) wastes tokens but doesn't break anything.
|
|
126
|
+
Under-delegation (MGW reading code) violates the architecture and creates maintenance debt.
|
|
127
|
+
|
|
128
|
+
## Consumers
|
|
129
|
+
|
|
130
|
+
This rule applies to ALL MGW commands:
|
|
131
|
+
|
|
132
|
+
| Command | Key Boundary Points |
|
|
133
|
+
|---------|-------------------|
|
|
134
|
+
| run.md | Spawns planner, executor, verifier, comment classifier — never reads code |
|
|
135
|
+
| issue.md | Spawns analysis agent — never analyzes code itself |
|
|
136
|
+
| review.md | Spawns comment classification agent — reads comments, not code |
|
|
137
|
+
| pr.md | Spawns PR body builder — never reads code for description |
|
|
138
|
+
| ask.md | Spawns classification agent — never analyzes code itself |
|
|
139
|
+
| sync.md | Reads state + GitHub API only — never reads code |
|
|
140
|
+
| update.md | Reads state only — posts comments |
|
|
141
|
+
| link.md | Reads/writes cross-refs only |
|
|
142
|
+
| init.md | Creates structure + GitHub labels only |
|
|
143
|
+
| issues.md | Reads GitHub API only |
|
|
144
|
+
| help.md | Display only |
|