@opengsd/gsd-core 1.2.0 → 1.3.0-rc.1

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.
Files changed (92) hide show
  1. package/README.ja-JP.md +6 -5
  2. package/README.ko-KR.md +6 -5
  3. package/README.md +10 -45
  4. package/README.pt-BR.md +5 -4
  5. package/README.zh-CN.md +6 -5
  6. package/agents/gsd-ai-researcher.md +1 -1
  7. package/agents/gsd-debug-session-manager.md +1 -1
  8. package/agents/gsd-doc-writer.md +7 -6
  9. package/agents/gsd-domain-researcher.md +1 -1
  10. package/agents/gsd-eval-planner.md +1 -1
  11. package/agents/gsd-phase-researcher.md +1 -1
  12. package/agents/gsd-ui-researcher.md +1 -1
  13. package/agents/gsd-verifier.md +1 -1
  14. package/assets/gsd-logo-2000-transparent.png +0 -0
  15. package/assets/gsd-logo-2000-transparent.svg +17 -0
  16. package/assets/gsd-logo-2000.png +0 -0
  17. package/assets/gsd-logo-2000.svg +21 -0
  18. package/assets/terminal.svg +68 -0
  19. package/bin/install.js +86 -44
  20. package/commands/gsd/review.md +2 -1
  21. package/get-shit-done/bin/gsd-tools.cjs +37 -1
  22. package/get-shit-done/bin/lib/command-aliases.cjs +16 -0
  23. package/get-shit-done/bin/lib/commands.cjs +109 -5
  24. package/get-shit-done/bin/lib/config-types.cjs +19 -0
  25. package/get-shit-done/bin/lib/core.cjs +455 -63
  26. package/get-shit-done/bin/lib/gap-checker.cjs +56 -7
  27. package/get-shit-done/bin/lib/installer-migration-report.cjs +1 -0
  28. package/get-shit-done/bin/lib/milestone.cjs +59 -1
  29. package/get-shit-done/bin/lib/model-catalog.cjs +17 -0
  30. package/get-shit-done/bin/lib/phase-lifecycle.cjs +0 -1
  31. package/get-shit-done/bin/lib/review-reviewer-selection.cjs +1 -0
  32. package/get-shit-done/bin/lib/roadmap-command-router.cjs +134 -0
  33. package/get-shit-done/bin/lib/roadmap-upgrade.cjs +569 -0
  34. package/get-shit-done/bin/lib/roadmap.cjs +6 -5
  35. package/get-shit-done/bin/lib/semver-compare.cjs +34 -27
  36. package/get-shit-done/bin/lib/shell-command-projection.cjs +35 -0
  37. package/get-shit-done/bin/lib/state-document.cjs +0 -4
  38. package/get-shit-done/bin/lib/state.cjs +41 -6
  39. package/get-shit-done/bin/lib/ui-safety-gate.cjs +111 -0
  40. package/get-shit-done/bin/lib/validate.cjs +43 -17
  41. package/get-shit-done/bin/lib/verify.cjs +107 -4
  42. package/get-shit-done/bin/shared/config-defaults.manifest.json +1 -0
  43. package/get-shit-done/bin/shared/config-schema.manifest.json +12 -1
  44. package/get-shit-done/bin/shared/model-catalog.json +27 -0
  45. package/get-shit-done/references/checkpoints.md +1 -1
  46. package/get-shit-done/references/planner-human-verify-mode.md +1 -1
  47. package/get-shit-done/references/ui-brand.md +4 -2
  48. package/get-shit-done/workflows/audit-fix.md +1 -1
  49. package/get-shit-done/workflows/audit-milestone.md +2 -0
  50. package/get-shit-done/workflows/autonomous.md +7 -5
  51. package/get-shit-done/workflows/cleanup.md +43 -3
  52. package/get-shit-done/workflows/code-review-fix.md +3 -3
  53. package/get-shit-done/workflows/code-review.md +2 -0
  54. package/get-shit-done/workflows/debug.md +6 -1
  55. package/get-shit-done/workflows/diagnose-issues.md +2 -0
  56. package/get-shit-done/workflows/discuss-phase/modes/advisor.md +1 -1
  57. package/get-shit-done/workflows/discuss-phase-assumptions.md +2 -2
  58. package/get-shit-done/workflows/docs-update.md +18 -4
  59. package/get-shit-done/workflows/eval-review.md +1 -1
  60. package/get-shit-done/workflows/execute-phase/steps/codebase-drift-gate.md +1 -1
  61. package/get-shit-done/workflows/execute-phase.md +21 -11
  62. package/get-shit-done/workflows/execute-plan.md +1 -1
  63. package/get-shit-done/workflows/explore.md +2 -0
  64. package/get-shit-done/workflows/help/modes/default.md +3 -3
  65. package/get-shit-done/workflows/help/modes/full.md +5 -5
  66. package/get-shit-done/workflows/import.md +2 -0
  67. package/get-shit-done/workflows/ingest-docs.md +2 -2
  68. package/get-shit-done/workflows/manager.md +2 -2
  69. package/get-shit-done/workflows/map-codebase.md +2 -0
  70. package/get-shit-done/workflows/new-milestone.md +2 -2
  71. package/get-shit-done/workflows/new-project.md +2 -2
  72. package/get-shit-done/workflows/plan-phase.md +16 -15
  73. package/get-shit-done/workflows/plan-review-convergence.md +3 -3
  74. package/get-shit-done/workflows/quick.md +5 -3
  75. package/get-shit-done/workflows/review.md +109 -1
  76. package/get-shit-done/workflows/scan.md +2 -0
  77. package/get-shit-done/workflows/secure-phase.md +2 -0
  78. package/get-shit-done/workflows/settings-advanced.md +195 -5
  79. package/get-shit-done/workflows/settings.md +15 -1
  80. package/get-shit-done/workflows/ui-phase.md +2 -2
  81. package/get-shit-done/workflows/ui-review.md +1 -1
  82. package/get-shit-done/workflows/validate-phase.md +2 -0
  83. package/get-shit-done/workflows/verify-work.md +2 -2
  84. package/hooks/dist/gsd-worktree-path-guard.js +169 -0
  85. package/hooks/gsd-worktree-path-guard.js +169 -0
  86. package/hooks/managed-hooks-registry.cjs +1 -0
  87. package/package.json +9 -6
  88. package/scripts/build-hooks.js +1 -0
  89. package/scripts/ci-test-scope.cjs +10 -0
  90. package/scripts/run-tests.cjs +25 -1
  91. package/scripts/lint-shared-module-handsync.cjs +0 -388
  92. package/scripts/shared-module-handsync-allowlist.json +0 -183
@@ -284,11 +284,11 @@ Check if this phase has frontend indicators and whether a UI-SPEC already exists
284
284
  PHASE_SECTION=$(gsd_run query roadmap.get-phase ${PHASE_NUM} 2>/dev/null)
285
285
  # Shell-free word-boundary gate (#3718): Node.js helper — no locale env-var dependency.
286
286
  # Reads via stdin to avoid OS ARG_MAX limits on large phase text.
287
- # Path anchored to repo root; falls back to CWD if git is unavailable
288
- # Exit codes mirror grep: 0 = UI tokens found, 1 = not found.
289
- GSD_REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || echo ".")
290
- printf '%s' "$PHASE_SECTION" | node "${GSD_REPO_ROOT}/bin/lib/ui-safety-gate.cjs" > /dev/null 2>&1
291
- HAS_UI=$?
287
+ # Resolve the helper against the GSD install dir via RUNTIME_DIR (#448) — NOT the consuming
288
+ # project's git root — falling back to git toplevel / $HOME/.claude. Exit codes mirror grep (0=UI,1=none).
289
+ _GSD_RT="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"
290
+ UI_GATE_JS=$(for _c in "$_GSD_RT/get-shit-done/bin/lib/ui-safety-gate.cjs" "$_GSD_RT/bin/lib/ui-safety-gate.cjs" "$_GSD_RT/.claude/bin/lib/ui-safety-gate.cjs" "$HOME/.claude/get-shit-done/bin/lib/ui-safety-gate.cjs" "$HOME/.claude/bin/lib/ui-safety-gate.cjs"; do [ -f "$_c" ] && { echo "$_c"; break; }; done)
291
+ if [ -n "$UI_GATE_JS" ]; then printf '%s' "$PHASE_SECTION" | node "$UI_GATE_JS" >/dev/null 2>&1; HAS_UI=$?; else echo "WARN: ui-safety-gate.cjs not found via RUNTIME_DIR/\$HOME (#448) — assuming UI present" >&2; HAS_UI=0; fi
292
292
  UI_SPEC_FILE=$(ls "${PHASE_DIR}"/*-UI-SPEC.md 2>/dev/null | head -1)
293
293
  ```
294
294
 
@@ -324,6 +324,8 @@ UI_SPEC_FILE=$(ls "${PHASE_DIR}"/*-UI-SPEC.md 2>/dev/null | head -1)
324
324
 
325
325
  **If `INTERACTIVE` is set:** Dispatch plan as a background agent to keep the main context lean. While plan runs, the workflow can immediately start discussing the next phase (see step 4).
326
326
 
327
+ Print: `◆ Spawning background planner for phase ${PHASE_NUM}... (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze)`
328
+
327
329
  ```
328
330
  Agent(
329
331
  description="Plan phase ${PHASE_NUM}: ${PHASE_NAME}",
@@ -85,17 +85,38 @@ These phase directories will be archived:
85
85
  Destination: .planning/milestones/v{X.Z}-phases/
86
86
  ```
87
87
 
88
- If no phase directories remain to archive (all already moved or deleted):
88
+ **Stale local branches (upstream gone):**
89
+
90
+ First, update remote-tracking refs so the candidate list matches the execution list exactly:
91
+
92
+ ```bash
93
+ git fetch --prune 2>/dev/null || true
94
+ ```
95
+
96
+ Then enumerate candidates (protected branch names are excluded even if their upstream is gone):
97
+
98
+ ```bash
99
+ git branch -vv | awk '/: gone\]/ { if ($1 !~ /^\*$|^main$|^next$|^trunk$|^develop$/) print $1 }'
100
+ ```
101
+
102
+ Show each branch name. If none, show:
103
+
104
+ ```
105
+ No stale local branches detected.
106
+ ```
107
+
108
+ If no phase directories remain to archive (all already moved or deleted) AND no stale branches exist:
89
109
 
90
110
  ```
91
111
  No phase directories found to archive. Phases may have been removed or archived previously.
112
+ No stale local branches detected either.
92
113
  ```
93
114
 
94
115
  Stop here.
95
116
 
96
117
 
97
118
  **Text mode (`workflow.text_mode: true` in config or `--text` flag):** Set `TEXT_MODE=true` if `--text` is present in `$ARGUMENTS` OR `text_mode` from init JSON is `true`. When TEXT_MODE is active, replace every `AskUserQuestion` call with a plain-text numbered list and ask the user to type their choice number. This is required for non-Claude runtimes (OpenAI Codex, Gemini CLI, etc.) where `AskUserQuestion` is not available.
98
- AskUserQuestion: "Proceed with archiving?" with options: "Yes — archive listed phases" | "Cancel"
119
+ AskUserQuestion: "Proceed with archiving and pruning?" with options: "Yes — archive phases and prune stale branches" | "Cancel"
99
120
 
100
121
  If "Cancel": Stop.
101
122
 
@@ -119,6 +140,22 @@ Repeat for all milestones in the cleanup set.
119
140
 
120
141
  </step>
121
142
 
143
+ <step name="prune_local_branches">
144
+
145
+ After phase archival, prune local branches whose upstream has been deleted. Use the same filter as the dry-run so the execution list matches exactly what the user confirmed:
146
+
147
+ ```bash
148
+ git branch -vv | awk '/: gone\]/ { if ($1 !~ /^\*$|^main$|^next$|^trunk$|^develop$/) print $1 }' | xargs -r git branch -D
149
+ ```
150
+
151
+ Notes:
152
+ - `git fetch --prune` already ran in `show_dry_run` — the tracking refs are current and this step enumerates from the same state the user confirmed.
153
+ - `!~ /^\*$/` skips the currently checked-out branch (prefixed with `* ` in `git branch -vv` output, so `$1` yields `*`).
154
+ - `!~ /^main$|^next$|^trunk$|^develop$/` excludes protected branch names even if their upstream is gone — matches the dry-run exclusion exactly.
155
+ - `xargs -r` prevents `git branch -D` from running with no arguments when no stale branches exist.
156
+
157
+ </step>
158
+
122
159
  <step name="commit">
123
160
 
124
161
  Commit the changes:
@@ -137,6 +174,8 @@ Archived:
137
174
  {For each milestone}
138
175
  - v{X.Y}: {N} phase directories → .planning/milestones/v{X.Y}-phases/
139
176
 
177
+ Pruned: {N} local branches whose upstream is gone.
178
+
140
179
  .planning/phases/ cleaned up.
141
180
  ```
142
181
 
@@ -148,8 +187,9 @@ Archived:
148
187
 
149
188
  - [ ] All completed milestones without existing phase archives identified
150
189
  - [ ] Phase membership determined from archived ROADMAP snapshots
151
- - [ ] Dry-run summary shown and user confirmed
190
+ - [ ] Dry-run summary shown and user confirmed (covers both archival and pruning)
152
191
  - [ ] Phase directories moved to `.planning/milestones/v{X.Y}-phases/`
192
+ - [ ] Stale local branches pruned (branches whose upstream is gone)
153
193
  - [ ] Changes committed
154
194
 
155
195
  </success_criteria>
@@ -179,7 +179,7 @@ If REVIEW.md contains a `files_reviewed_list` frontmatter field, use that as the
179
179
  </step>
180
180
 
181
181
  <step name="spawn_fixer">
182
- Spawn the gsd-code-fixer agent with config:
182
+ Spawn the gsd-code-fixer agent with config (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze):
183
183
 
184
184
  ```bash
185
185
  # Build config for agent
@@ -271,7 +271,7 @@ if [ "$AUTO_MODE" = "true" ]; then
271
271
  done
272
272
  fi
273
273
 
274
- # Spawn gsd-code-reviewer agent to re-review
274
+ # Spawn gsd-code-reviewer agent to re-review (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze)
275
275
  # (This overwrites REVIEW_PATH with latest review state)
276
276
  Agent(subagent_type="gsd-code-reviewer", prompt="
277
277
  <config>
@@ -304,7 +304,7 @@ Do NOT commit the output — the orchestrator handles that.
304
304
  break
305
305
  fi
306
306
 
307
- # Still has issues — spawn fixer again
307
+ # Still has issues — spawn fixer again (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze)
308
308
  echo "Issues remain. Applying fixes for iteration ${ITERATION}..."
309
309
 
310
310
  Agent(subagent_type="gsd-code-fixer", prompt="
@@ -441,6 +441,8 @@ fi
441
441
 
442
442
  Spawn the gsd-code-reviewer agent:
443
443
 
444
+ Print: `◆ Spawning code reviewer... (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze)`
445
+
444
446
  ```
445
447
  Agent(subagent_type="gsd-code-reviewer", prompt="
446
448
  <files_to_read>
@@ -101,7 +101,7 @@ Eliminated: {count}
101
101
 
102
102
  Surface to user. Then delegate directly to the session manager (skip Steps 2 and 3 — pass `symptoms_prefilled: true` and set the slug from SLUG variable). The existing file IS the context.
103
103
 
104
- Print before spawning:
104
+ Print before spawning (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze):
105
105
  ```
106
106
  [debug] Session: .planning/debug/{SLUG}.md
107
107
  [debug] Status: {status}
@@ -190,6 +190,11 @@ Create `.planning/debug/{slug}.md` with initial state using the Write tool (neve
190
190
 
191
191
  After initial context setup, spawn the session manager to handle the full checkpoint/continuation loop. The session manager handles specialist_hint dispatch internally: when gsd-debugger returns ROOT CAUSE FOUND it extracts the specialist_hint field and invokes the matching skill (e.g. typescript-expert, swift-concurrency) before offering fix options.
192
192
 
193
+ Print before spawning (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze):
194
+ ```
195
+ [debug] Delegating loop to session manager...
196
+ ```
197
+
193
198
  ```
194
199
  Agent(
195
200
  prompt="""
@@ -96,6 +96,8 @@ EXPECTED_BASE=$(git rev-parse HEAD)
96
96
 
97
97
  For each gap, fill the debug-subagent-prompt template and spawn:
98
98
 
99
+ Print: `◆ Spawning diagnostics agent... (each runs in a subagent — no output until they return, ~1–5 min; expected, not a freeze)`
100
+
99
101
  ```
100
102
  Agent(
101
103
  prompt=filled_debug_subagent_prompt + "\n\n<worktree_branch_check>\nFIRST ACTION: assert this is a disposable worktree branch before any repair. Run:\n```bash\nHEAD_REF=$(git symbolic-ref --quiet HEAD || echo \"DETACHED\")\nACTUAL_BRANCH=$(git rev-parse --abbrev-ref HEAD)\nif [ \"$HEAD_REF\" = \"DETACHED\" ] || echo \"$ACTUAL_BRANCH\" | grep -Eq '^(main|master|develop|trunk|release/.*)$'; then\n echo \"FATAL: diagnose worktree HEAD on '$ACTUAL_BRANCH'; refusing reset --hard on a protected branch.\" >&2\n exit 1\nfi\nif ! echo \"$ACTUAL_BRANCH\" | grep -Eq '^worktree-agent-[A-Za-z0-9._/-]+$'; then\n echo \"FATAL: diagnose worktree HEAD '$ACTUAL_BRANCH' is not in the worktree-agent-* namespace; refusing reset --hard.\" >&2\n exit 1\nfi\nACTUAL_BASE=$(git merge-base HEAD {EXPECTED_BASE})\nif [ \"$ACTUAL_BASE\" != \"{EXPECTED_BASE}\" ]; then\n git reset --hard {EXPECTED_BASE}\n [ \"$(git rev-parse HEAD)\" != \"{EXPECTED_BASE}\" ] && { echo \"ERROR: Could not correct worktree base\"; exit 1; }\nfi\n```\nFixes EnterWorktree creating branches from main on all platforms while preventing protected-branch data loss.\n</worktree_branch_check>\n\n<files_to_read>\n- {phase_dir}/{phase_num}-UAT.md\n- .planning/STATE.md\n</files_to_read>\n${AGENT_SKILLS_DEBUGGER}",
@@ -86,7 +86,7 @@ This reframing applies to:
86
86
  After the user selects gray areas in `present_gray_areas`, spawn parallel
87
87
  research agents.
88
88
 
89
- 1. Display brief status: `Researching {N} areas...`
89
+ 1. Display brief status: `Researching {N} areas...` (each runs in a subagent — no output until they return, ~1–5 min; expected, not a freeze)
90
90
 
91
91
  2. For EACH user-selected gray area, spawn a `Agent()` in parallel:
92
92
 
@@ -252,7 +252,7 @@ Map to calibration tier:
252
252
 
253
253
  If no USER-PROFILE.md: calibration_tier = "standard"
254
254
 
255
- **Spawn Explore subagent:**
255
+ **Spawn Explore subagent** (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze)**:**
256
256
 
257
257
  ```
258
258
  Agent(subagent_type="gsd-assumptions-analyzer", prompt="""
@@ -310,7 +310,7 @@ Parse the subagent's response. Extract:
310
310
  <step name="external_research">
311
311
  **Skip if:** `needs_research` from deep_codebase_analysis is empty.
312
312
 
313
- If research topics were flagged, spawn a general-purpose research agent:
313
+ If research topics were flagged, spawn a general-purpose research agent (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze):
314
314
 
315
315
  ```
316
316
  Agent(subagent_type="general-purpose", prompt="""
@@ -374,7 +374,7 @@ After all decisions recorded, continue to detect_runtime_capabilities.
374
374
  <step name="dispatch_wave_1" condition="Task tool is available">
375
375
  **Read the work manifest first:** `Read .planning/tmp/docs-work-manifest.json` — use `canonical_queue` items with `wave: 1` for this step.
376
376
 
377
- Spawn 3 parallel gsd-doc-writer agents for Wave 1 docs: README, ARCHITECTURE, CONFIGURATION.
377
+ Spawn 3 parallel gsd-doc-writer agents for Wave 1 docs: README, ARCHITECTURE, CONFIGURATION (each runs in a subagent — no output until they return, ~1–5 min; expected, not a freeze).
378
378
 
379
379
  These are foundational docs with no cross-references needed, making them ideal for parallel generation.
380
380
 
@@ -831,7 +831,8 @@ Extract `canonical_queue` (items with `status: "completed"`) and `review_queue`
831
831
 
832
832
  For each doc in `canonical_queue` that was successfully written to disk:
833
833
 
834
- 1. Spawn the `gsd-doc-verifier` agent (or invoke sequentially if Task tool is unavailable) with a `<verify_assignment>` block:
834
+ 1. Print: `◆ Spawning doc verifier for {doc_path}... (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze)`
835
+ Spawn the `gsd-doc-verifier` agent (or invoke sequentially if Task tool is unavailable) with a `<verify_assignment>` block:
835
836
  ```xml
836
837
  <verify_assignment>
837
838
  doc_path: {relative path to the doc file, e.g. README.md}
@@ -849,7 +850,8 @@ This is NOT optional. Every doc in `review_queue` MUST be verified.
849
850
 
850
851
  For each doc in `review_queue` from the manifest:
851
852
 
852
- 1. Spawn the `gsd-doc-verifier` agent with the same `<verify_assignment>` block as above.
853
+ 1. Print: `◆ Spawning doc verifier for {doc_path}... (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze)`
854
+ Spawn the `gsd-doc-verifier` agent with the same `<verify_assignment>` block as above.
853
855
  2. Read the result JSON from `.planning/tmp/verify-{doc_filename}.json`.
854
856
  3. Update the manifest: set `status: "verified"` for each review_queue doc processed.
855
857
 
@@ -900,7 +902,10 @@ Correct flagged inaccuracies by re-sending failing docs to the doc-writer in fix
900
902
  **For each iteration (while iteration < MAX_FIX_ITERATIONS and there are docs with failures):**
901
903
 
902
904
  1. For each doc with `claims_failed > 0` in the latest verification_results:
903
- a. Read the current file content from disk.
905
+ a. Read the current file content from disk. Record the pre-fix line count:
906
+ ```bash
907
+ PRE_FIX_LINES=$(wc -l < "{doc_path}" 2>/dev/null || echo 0)
908
+ ```
904
909
  b. Spawn `gsd-doc-writer` agent (or invoke sequentially) with a fix assignment:
905
910
  ```xml
906
911
  <doc_assignment>
@@ -917,6 +922,15 @@ Correct flagged inaccuracies by re-sending failing docs to the doc-writer in fix
917
922
  </doc_assignment>
918
923
  ```
919
924
  c. One agent spawn per doc with failures. Do not batch multiple docs into one spawn.
925
+ d. **Post-fix truncation guard:** After the fix agent completes, check for file corruption:
926
+ ```bash
927
+ POST_FIX_LINES=$(wc -l < "{doc_path}" 2>/dev/null || echo 0)
928
+ ```
929
+ If `POST_FIX_LINES` is less than 10% of `PRE_FIX_LINES` (i.e. the file shrank by more than 90%), the fix agent corrupted the file via a full-file Write. Restore it immediately:
930
+ - Write the `existing_content` captured in step 1a back to `"{doc_path}"` using the Write tool
931
+ - Log: `WARNING: Fix agent corrupted {doc_path} ({POST_FIX_LINES} lines after fix, was {PRE_FIX_LINES}). Restored from pre-fix content. Failures for this doc require manual correction.`
932
+ - Mark this doc as `"fix-corrupted"` in the manifest; it will appear in remaining failures at the end
933
+ - Do NOT attempt to fix this doc again this iteration. It is still included in the step 2 re-verification (so its failures are counted) but no further fix agent will be dispatched for it in this iteration.
920
934
 
921
935
  2. After all fix agents complete, re-verify ALL docs (not just the ones that were fixed):
922
936
  - Re-run the same verification process as verify_docs step.
@@ -73,7 +73,7 @@ Build file list for auditor:
73
73
  ## 3. Spawn gsd-eval-auditor
74
74
 
75
75
  ```
76
- ◆ Spawning eval auditor...
76
+ ◆ Spawning eval auditor... (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze)
77
77
  ```
78
78
 
79
79
  Build prompt:
@@ -49,7 +49,7 @@ _GSD_SHIM_NAME="gsd-tools.cjs"; _GSD_RUNTIME_ROOT="${RUNTIME_DIR:-$(git rev-pars
49
49
  AGENT_SKILLS_MAPPER=$(gsd_run query agent-skills gsd-codebase-mapper)
50
50
  ```
51
51
 
52
- Then spawn `gsd-codebase-mapper` agents with the `--paths` hint:
52
+ Then spawn `gsd-codebase-mapper` agents with the `--paths` hint (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze):
53
53
 
54
54
  ```text
55
55
  Agent(
@@ -491,7 +491,7 @@ increases monotonically across waves. `{status}` is `complete` (success),
491
491
  **{Plan ID}: {Plan Name}**
492
492
  {2-3 sentences: what this builds, technical approach, why it matters}
493
493
 
494
- Spawning {count} agent(s)...
494
+ Spawning {count} agent(s)... (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze)
495
495
  ---
496
496
  ```
497
497
 
@@ -1406,11 +1406,11 @@ grep "^status:" "$PHASE_DIR"/*-VERIFICATION.md | cut -d: -f2 | tr -d ' '
1406
1406
 
1407
1407
  **Step A: Persist human verification items as UAT file.**
1408
1408
 
1409
- Create `{phase_dir}/{phase_num}-HUMAN-UAT.md` using UAT template format:
1409
+ Create `{phase_dir}/{phase_num}-UAT.md` using UAT template format:
1410
1410
 
1411
1411
  ```markdown
1412
1412
  ---
1413
- status: partial
1413
+ status: testing
1414
1414
  phase: {phase_num}-{phase_name}
1415
1415
  source: [{phase_num}-VERIFICATION.md]
1416
1416
  started: [now ISO]
@@ -1419,7 +1419,11 @@ updated: [now ISO]
1419
1419
 
1420
1420
  ## Current Test
1421
1421
 
1422
- [awaiting human testing]
1422
+ number: 1
1423
+ name: {first human_verification item description}
1424
+ expected: |
1425
+ {expected behavior from VERIFICATION.md}
1426
+ awaiting: user response
1423
1427
 
1424
1428
  ## Tests
1425
1429
 
@@ -1443,26 +1447,32 @@ blocked: 0
1443
1447
 
1444
1448
  Commit the file:
1445
1449
  ```bash
1446
- gsd_run query commit "test({phase_num}): persist human verification items as UAT" --files "{phase_dir}/{phase_num}-HUMAN-UAT.md"
1450
+ gsd_run query commit "test({phase_num}): persist human verification items as UAT" --files "{phase_dir}/{phase_num}-UAT.md"
1447
1451
  ```
1448
1452
 
1449
1453
  **Step B: Present to user:**
1450
1454
 
1451
1455
  ```
1452
- ## ✓ Phase {X}: {Name} — Human Verification Required
1456
+ ## ◷ Phase {X}: {Name} — Human Verification Needed
1453
1457
 
1454
- All automated checks passed. {N} items need human testing:
1458
+ All automated checks passed. {N} item(s) require human testing before this phase can be marked complete:
1455
1459
 
1456
1460
  {From VERIFICATION.md human_verification section}
1457
1461
 
1458
- Items saved to `{phase_num}-HUMAN-UAT.md` — they will appear in `/gsd:progress` and `/gsd:audit-uat`.
1462
+ Tests saved to `{phase_num}-UAT.md`.
1459
1463
 
1460
- "approved" → continue | Report issues → gap closure
1464
+ When ready to run the tests:
1465
+
1466
+ `/gsd:verify-work {X} ${GSD_WS}`
1467
+
1468
+ Verify-work will walk you through each item and mark the phase complete when all tests pass.
1461
1469
  ```
1462
1470
 
1463
- **If user says "approved":** Proceed to `update_roadmap`. The HUMAN-UAT.md file persists with `status: partial` and will surface in future progress checks until the user runs `/gsd:verify-work` on it.
1471
+ **Do NOT advance the phase from this branch.** Phase completion is handled by verify-work's auto-transition after UAT passes.
1472
+
1473
+ **If user acknowledges without reporting issues (including "ok", "noted", "ack", "got it", "approved", "done", "yes", "pass", or similar):** Stop. The phase remains pending. No further orchestrator action — wait for the user to run `/gsd:verify-work`.
1464
1474
 
1465
- **If user reports issues:** Proceed to gap closure as currently implemented.
1475
+ **If user reports issues now (before running verify-work):** Proceed to gap closure as currently implemented.
1466
1476
 
1467
1477
  **If gaps_found:**
1468
1478
  ```
@@ -92,7 +92,7 @@ Otherwise: Apply checkpoint-based routing below.
92
92
  | Verify-only | B (segmented) | Segments between checkpoints. After none/human-verify → SUBAGENT. After decision/human-action → MAIN |
93
93
  | Decision | C (main) | Execute entirely in main context |
94
94
 
95
- **Pattern A:** init_agent_tracking → capture `EXPECTED_BASE=$(git rev-parse HEAD)` → spawn Agent(subagent_type="gsd-executor", model=executor_model) with prompt: execute plan at [path], autonomous, all tasks + SUMMARY + commit, follow deviation/auth rules, report: plan name, tasks, SUMMARY path, commit hash → track agent_id → wait → update tracking → report. **Include `isolation="worktree"` only if `workflow.use_worktrees` is not `false`** (read via `config-get workflow.use_worktrees`). **When using `isolation="worktree"`, include a `<worktree_branch_check>` block in the prompt** instructing the executor to: (1) FIRST assert `git symbolic-ref HEAD` resolves to a per-agent branch (NOT a protected ref like `main`/`master`/`develop`/`trunk`/`release/*`) and HALT with a blocker if not — never self-recover via `git update-ref refs/heads/<protected>` (#2924); (2) only after that assertion passes, run `git merge-base HEAD {EXPECTED_BASE}` and, if the result differs from `{EXPECTED_BASE}`, hard-reset the branch with `git reset --hard {EXPECTED_BASE}` before starting work, then verify with `[ "$(git rev-parse HEAD)" != "{EXPECTED_BASE}" ] && exit 1`. The HEAD assertion (Step 1) MUST run before any reset/checkout. This corrects a known issue where `EnterWorktree` creates branches from `main` instead of the feature branch HEAD (affects all platforms — #2015) and prevents the destructive HEAD-on-master self-recovery path (#2924).
95
+ **Pattern A:** init_agent_tracking → capture `EXPECTED_BASE=$(git rev-parse HEAD)` → print `Spawning executor agent (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze)` → spawn Agent(subagent_type="gsd-executor", model=executor_model) with prompt: execute plan at [path], autonomous, all tasks + SUMMARY + commit, follow deviation/auth rules, report: plan name, tasks, SUMMARY path, commit hash → track agent_id → wait → update tracking → report. **Include `isolation="worktree"` only if `workflow.use_worktrees` is not `false`** (read via `config-get workflow.use_worktrees`). **When using `isolation="worktree"`, include a `<worktree_branch_check>` block in the prompt** instructing the executor to: (1) FIRST assert `git symbolic-ref HEAD` resolves to a per-agent branch (NOT a protected ref like `main`/`master`/`develop`/`trunk`/`release/*`) and HALT with a blocker if not — never self-recover via `git update-ref refs/heads/<protected>` (#2924); (2) only after that assertion passes, run `git merge-base HEAD {EXPECTED_BASE}` and, if the result differs from `{EXPECTED_BASE}`, hard-reset the branch with `git reset --hard {EXPECTED_BASE}` before starting work, then verify with `[ "$(git rev-parse HEAD)" != "{EXPECTED_BASE}" ] && exit 1`. The HEAD assertion (Step 1) MUST run before any reset/checkout. This corrects a known issue where `EnterWorktree` creates branches from `main` instead of the feature branch HEAD (affects all platforms — #2015) and prevents the destructive HEAD-on-master self-recovery path (#2924).
96
96
 
97
97
  **Pattern B:** Execute segment-by-segment. Autonomous segments: spawn subagent for assigned tasks only (no SUMMARY/commit). Checkpoints: main context. After all segments: aggregate, create SUMMARY, commit. See segment_execution.
98
98
 
@@ -59,6 +59,8 @@ This would take ~30 seconds and might surface useful context.
59
59
  ```
60
60
 
61
61
  If yes, spawn a research agent:
62
+
63
+ Print: `◆ Spawning explorer... (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze)`
62
64
  ```
63
65
  Agent(
64
66
  prompt="Quick research: {specific_question}. Return 3-5 key findings, no more than 200 words.",
@@ -1,11 +1,11 @@
1
1
  <purpose>
2
- One-page newcomer-oriented tour of GSD. Output ONLY the `<reference>` content below. No additions.
2
+ One-page newcomer-oriented tour of GSD Core. Output ONLY the `<reference>` content below. No additions.
3
3
  </purpose>
4
4
 
5
5
  <reference>
6
- # GSD — Get Shit Done
6
+ # GSD Core — Git. Ship. Done.
7
7
 
8
- Plan-driven development for solo agentic work with Claude Code. GSD turns a vague idea into a hierarchical plan, then executes it phase by phase with state tracking and atomic commits.
8
+ Plan-driven development for solo agentic work with Claude Code. GSD Core turns a vague idea into a hierarchical plan, then executes it phase by phase with state tracking and atomic commits.
9
9
 
10
10
  ## Start here (3 commands)
11
11
 
@@ -1,11 +1,11 @@
1
1
  <purpose>
2
- Display the complete GSD command reference. Output ONLY the reference content. Do NOT add project-specific analysis, git status, next-step suggestions, or any commentary beyond the reference.
2
+ Display the complete GSD Core command reference. Output ONLY the reference content. Do NOT add project-specific analysis, git status, next-step suggestions, or any commentary beyond the reference.
3
3
  </purpose>
4
4
 
5
5
  <reference>
6
- # GSD Command Reference
6
+ # GSD Core Command Reference
7
7
 
8
- **GSD** (Get Shit Done) creates hierarchical project plans optimized for solo agentic development with Claude Code.
8
+ **GSD Core** (Git. Ship. Done.) creates hierarchical project plans optimized for solo agentic development with Claude Code.
9
9
 
10
10
  ## Quick Start
11
11
 
@@ -418,10 +418,10 @@ Usage: `/gsd:ship 4` or `/gsd:ship 4 --draft`
418
418
 
419
419
  ---
420
420
 
421
- **`/gsd:review --phase N [--gemini] [--claude] [--codex] [--coderabbit] [--opencode] [--qwen] [--cursor] [--all]`**
421
+ **`/gsd:review --phase N [--gemini] [--claude] [--codex] [--coderabbit] [--opencode] [--qwen] [--cursor] [--agy] [--all]`**
422
422
  Cross-AI peer review — invoke external AI CLIs to independently review phase plans.
423
423
 
424
- - Detects available CLIs (gemini, claude, codex, coderabbit)
424
+ - Detects available CLIs (gemini, claude, codex, coderabbit, agy)
425
425
  - Each CLI reviews plans independently with the same structured prompt
426
426
  - CodeRabbit reviews the current git diff (not a prompt) — may take up to 5 minutes
427
427
  - Produces REVIEWS.md with per-reviewer feedback and consensus summary
@@ -197,6 +197,8 @@ Write the PLAN.md file to the target directory.
197
197
 
198
198
  Delegate validation to gsd-plan-checker:
199
199
 
200
+ Print: "Delegating to gsd-plan-checker (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze)"
201
+
200
202
  ```
201
203
  Agent({
202
204
  subagent_type: "gsd-plan-checker",
@@ -180,7 +180,7 @@ Collect the one-line confirmations from each classifier. If any classifier error
180
180
 
181
181
  <step name="synthesize">
182
182
 
183
- Spawn `gsd-doc-synthesizer` once:
183
+ Spawn `gsd-doc-synthesizer` once (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze):
184
184
 
185
185
  ```
186
186
  Agent({
@@ -247,7 +247,7 @@ Proceed to routing silently, or optionally display `GSD > No conflicts. Auto-res
247
247
 
248
248
  Audit PROJECT.md field requirements that `gsd-roadmapper` expects. For fields derivable from `.planning/intel/SYNTHESIS.md` (project scope, goals/non-goals, constraints, locked decisions), synthesize from the intel. For fields NOT derivable (project name, developer-facing success metric, target runtime), prompt via `AskUserQuestion` one at a time — minimal question set, no interrogation.
249
249
 
250
- Delegate to `gsd-roadmapper`:
250
+ Delegate to `gsd-roadmapper` (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze):
251
251
 
252
252
  ```
253
253
  Agent({
@@ -269,7 +269,7 @@ Important: You are running in the background. Do NOT use AskUserQuestion — mak
269
269
  Display:
270
270
 
271
271
  ```
272
- ◆ Spawning planner for Phase {N}: {phase_name}...
272
+ ◆ Spawning planner for Phase {N}: {phase_name}... (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze)
273
273
  ```
274
274
 
275
275
  Loop back to dashboard step.
@@ -303,7 +303,7 @@ Important: You are running in the background. Do NOT use AskUserQuestion — mak
303
303
  Display:
304
304
 
305
305
  ```
306
- ◆ Spawning executor for Phase {N}: {phase_name}...
306
+ ◆ Spawning executor for Phase {N}: {phase_name}... (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze)
307
307
  ```
308
308
 
309
309
  Loop back to dashboard step.
@@ -144,6 +144,8 @@ Use Agent tool with `subagent_type="gsd-codebase-mapper"`, `model="{mapper_model
144
144
 
145
145
  **CRITICAL:** Use the dedicated `gsd-codebase-mapper` agent, NOT `Explore` or `browser_subagent`. The mapper agent writes documents directly.
146
146
 
147
+ Print: "Spawning 4 parallel codebase mapper agents (each runs in a subagent — no output until they return, ~1–5 min; expected, not a freeze)"
148
+
147
149
  **Agent 1: Tech Focus**
148
150
 
149
151
  ```text
@@ -287,7 +287,7 @@ AskUserQuestion: "Research the domain ecosystem for new features before defining
287
287
  GSD ► RESEARCHING
288
288
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
289
289
 
290
- ◆ Spawning 4 researchers in parallel...
290
+ ◆ Spawning 4 researchers in parallel... (each runs in a subagent — no output until they return, ~1–5 min; expected, not a freeze)
291
291
  → Stack, Features, Architecture, Pitfalls
292
292
  ```
293
293
 
@@ -455,7 +455,7 @@ gsd_run query commit "docs: define milestone v[X.Y] requirements" --files .plann
455
455
  GSD ► CREATING ROADMAP
456
456
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
457
457
 
458
- ◆ Spawning roadmapper...
458
+ ◆ Spawning roadmapper... (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze)
459
459
  ```
460
460
 
461
461
  **Starting phase number:**
@@ -869,7 +869,7 @@ Check if this is greenfield or subsequent milestone:
869
869
  Display spawning indicator:
870
870
 
871
871
  ```
872
- ◆ Spawning 4 researchers in parallel...
872
+ ◆ Spawning 4 researchers in parallel... (each runs in a subagent — no output until they return, ~1–5 min; expected, not a freeze)
873
873
  → Stack research
874
874
  → Features research
875
875
  → Architecture research
@@ -1265,7 +1265,7 @@ Display stage banner:
1265
1265
  GSD ► CREATING ROADMAP
1266
1266
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1267
1267
 
1268
- ◆ Spawning roadmapper...
1268
+ ◆ Spawning roadmapper... (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze)
1269
1269
  ```
1270
1270
 
1271
1271
  **ROADMAP.md template — mode-aware emit.** When generating the initial ROADMAP.md:
@@ -99,7 +99,7 @@ The gate fires only on `Complete`. `Executed` and `Needs Review` are not gated
99
99
 
100
100
  ## 2. Parse and Normalize Arguments
101
101
 
102
- Extract from $ARGUMENTS: phase number (integer or decimal like `2.1`), flags (`--research`, `--skip-research`, `--research-phase <N>`, `--gaps`, `--skip-verify`, `--skip-ui`, `--prd <filepath>`, `--ingest <path-or-glob>`, `--ingest-format <auto|nygard|madr|narrative>`, `--reviews`, `--text`, `--bounce`, `--skip-bounce`, `--chunked`, `--mvp`, `--force` (override closed-phase gate, see §1.5)).
102
+ Extract from $ARGUMENTS: phase number (integer or decimal like `2.1`), flags (`--research`, `--skip-research`, `--research-phase <N>`, `--gaps`, `--skip-verify`, `--skip-ui`, `--prd <filepath>`, `--ingest <path-or-glob>`, `--ingest-format <auto|nygard|madr|narrative>`, `--reviews`, `--text`, `--bounce`, `--skip-bounce`, `--chunked`, `--mvp`, `--tdd`, `--force` (override closed-phase gate, see §1.5)).
103
103
 
104
104
  **`--research-phase <N>` — research-only mode (#3042 + #3044).** When this flag is present, parse `<N>` as the phase number (overrides any positional phase argument), set `RESEARCH_ONLY=true`, and treat the rest of this workflow as a research-dispatch only — the planner spawn (step 8), plan-checker, verification, gaps, bounce, and post-planning-gaps blocks all skip on `RESEARCH_ONLY`. Use this for cross-phase research, doc review before committing to a planning approach, and correction-without-replanning loops. Replaces the deleted `/gsd-research-phase` command.
105
105
 
@@ -127,10 +127,10 @@ Set `TEXT_MODE=true` if `--text` is present in $ARGUMENTS OR `text_mode` from in
127
127
  ```bash
128
128
  MVP_FLAG_ARG=""
129
129
  if [[ "$ARGUMENTS" =~ (^|[[:space:]])--mvp([[:space:]]|$) ]]; then MVP_FLAG_ARG="--cli-flag"; fi
130
+ if [[ "$ARGUMENTS" =~ (^|[[:space:]])--tdd([[:space:]]|$) ]]; then TDD_MODE=true; fi
130
131
  ```
131
132
 
132
- Defer the `phase.mvp-mode` query until `PHASE` is finalized (after explicit argument parsing/fallback phase detection + validation).
133
- The verb returns `true|false`. Full result also exposes `source` (`cli_flag` | `roadmap` | `config` | `none`) for diagnostics. The mode is **all-or-nothing per phase** (PRD decision Q1) — never selective per task.
133
+ Defer the `phase.mvp-mode` query until `PHASE` is finalized (after explicit argument parsing/fallback phase detection + validation). The verb returns `true|false`; full result also exposes `source` (`cli_flag` | `roadmap` | `config` | `none`) for diagnostics. Mode is **all-or-nothing per phase** (PRD decision Q1).
134
134
 
135
135
  **Walking Skeleton gate.** When `MVP_MODE=true` AND `phase_number == "01"` AND there are zero prior phase summaries (new project), the planner runs in **Walking Skeleton mode** (per PRD decision Q2 — new projects only). Detect with:
136
136
 
@@ -480,7 +480,7 @@ Display banner:
480
480
  GSD ► RESEARCHING PHASE {X}
481
481
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
482
482
 
483
- ◆ Spawning researcher...
483
+ ◆ Spawning researcher... (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze)
484
484
  ```
485
485
 
486
486
  ### Spawn gsd-phase-researcher
@@ -625,11 +625,11 @@ Check if phase has frontend indicators:
625
625
  PHASE_SECTION=$(gsd_run query roadmap.get-phase "${PHASE}" 2>/dev/null)
626
626
  # Shell-free word-boundary gate (#3718): Node.js helper — no locale env-var dependency.
627
627
  # Reads via stdin to avoid OS ARG_MAX limits on large phase text.
628
- # Path anchored to repo root; falls back to CWD if git is unavailable
629
- # Exit codes mirror grep: 0 = UI tokens found, 1 = not found.
630
- GSD_REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || echo ".")
631
- printf '%s' "$PHASE_SECTION" | node "${GSD_REPO_ROOT}/bin/lib/ui-safety-gate.cjs" > /dev/null 2>&1
632
- HAS_UI=$?
628
+ # Resolve the helper against the GSD install dir via RUNTIME_DIR (#448) — NOT the consuming
629
+ # project's git root — falling back to git toplevel / $HOME/.claude. Exit codes mirror grep (0=UI,1=none).
630
+ _GSD_RT="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"
631
+ UI_GATE_JS=$(for _c in "$_GSD_RT/get-shit-done/bin/lib/ui-safety-gate.cjs" "$_GSD_RT/bin/lib/ui-safety-gate.cjs" "$_GSD_RT/.claude/bin/lib/ui-safety-gate.cjs" "$HOME/.claude/get-shit-done/bin/lib/ui-safety-gate.cjs" "$HOME/.claude/bin/lib/ui-safety-gate.cjs"; do [ -f "$_c" ] && { echo "$_c"; break; }; done)
632
+ if [ -n "$UI_GATE_JS" ]; then printf '%s' "$PHASE_SECTION" | node "$UI_GATE_JS" >/dev/null 2>&1; HAS_UI=$?; else echo "WARN: ui-safety-gate.cjs not found via RUNTIME_DIR/\$HOME (#448) — assuming UI present" >&2; HAS_UI=0; fi
633
633
  ```
634
634
 
635
635
  **If `HAS_UI` is 0 (frontend indicators found):**
@@ -815,7 +815,7 @@ Display banner:
815
815
  GSD ► PATTERN MAPPING PHASE {X}
816
816
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
817
817
 
818
- ◆ Spawning pattern mapper...
818
+ ◆ Spawning pattern mapper... (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze)
819
819
  ```
820
820
 
821
821
  Pattern mapper prompt:
@@ -877,7 +877,7 @@ Display banner:
877
877
  GSD ► PLANNING PHASE {X}
878
878
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
879
879
 
880
- ◆ Spawning planner...
880
+ ◆ Spawning planner... (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze)
881
881
  ```
882
882
 
883
883
  Planner prompt:
@@ -1040,7 +1040,7 @@ fi
1040
1040
 
1041
1041
  Display:
1042
1042
  ```text
1043
- ◆ Chunked mode: spawning outline planner...
1043
+ ◆ Chunked mode: spawning outline planner... (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze)
1044
1044
  ```
1045
1045
 
1046
1046
  Spawn the planner in **outline-only** mode — it must write only the outline manifest, not any
@@ -1087,7 +1087,7 @@ For each plan entry extracted from `PLAN-OUTLINE.md`:
1087
1087
 
1088
1088
  2. Display:
1089
1089
  ```text
1090
- ◆ Chunked mode: planning {plan_id} ({k}/{N})...
1090
+ ◆ Chunked mode: planning {plan_id} ({k}/{N})... (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze)
1091
1091
  ```
1092
1092
 
1093
1093
  3. Spawn the planner in **single-plan** mode — it must write exactly one PLAN.md file:
@@ -1225,7 +1225,7 @@ Display banner:
1225
1225
  GSD ► VERIFYING PLANS
1226
1226
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1227
1227
 
1228
- ◆ Spawning plan checker...
1228
+ ◆ Spawning plan checker... (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze)
1229
1229
  ```
1230
1230
 
1231
1231
  Checker prompt:
@@ -1627,7 +1627,8 @@ one place before execution begins.
1627
1627
  ```bash
1628
1628
  POST_PLANNING_GAPS=$(gsd_run query config-get workflow.post_planning_gaps --default true 2>/dev/null || echo true)
1629
1629
  if [ "$POST_PLANNING_GAPS" = "true" ]; then
1630
- node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" gap-analysis --phase-dir "${PHASE_DIR}"
1630
+ # Scope to this phase's mapped REQ-IDs (#447); null/TBD skips the requirements comparison (CONTEXT.md decisions still reported), mirroring §13.
1631
+ node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" gap-analysis --phase-dir "${PHASE_DIR}" --phase-req-ids "$(node "$HOME/.claude/get-shit-done/bin/gsd-tools.cjs" query init.plan-phase "$PHASE" --pick phase_req_ids 2>/dev/null || echo TBD)"
1631
1632
  fi
1632
1633
  ```
1633
1634