@opengsd/gsd-core 1.7.0-rc.6 → 1.8.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.
Files changed (195) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.opencode/plugins/gsd-core.js +14 -0
  4. package/README.md +2 -0
  5. package/agents/gsd-debug-session-manager.md +42 -4
  6. package/agents/gsd-debugger.md +87 -29
  7. package/agents/gsd-executor.md +31 -3
  8. package/agents/gsd-planner.md +29 -36
  9. package/agents/gsd-security-auditor.md +13 -15
  10. package/agents/gsd-verifier.md +2 -2
  11. package/bin/install.js +1157 -84
  12. package/commands/gsd/ai-integration-phase.md +1 -1
  13. package/commands/gsd/mempalace-capture.md +31 -1
  14. package/commands/gsd/new-milestone.md +1 -1
  15. package/commands/gsd/plan-phase.md +5 -3
  16. package/commands/gsd/plan-review-convergence.md +3 -2
  17. package/commands/gsd/surface.md +6 -6
  18. package/gsd-core/bin/gsd-tools.cjs +1866 -2434
  19. package/gsd-core/bin/lib/adapter-imperative.cjs +8 -1
  20. package/gsd-core/bin/lib/agent-command-router.cjs +20 -5
  21. package/gsd-core/bin/lib/api-coverage.cjs +341 -49
  22. package/gsd-core/bin/lib/audit.cjs +7 -6
  23. package/gsd-core/bin/lib/broken-windows.cjs +716 -0
  24. package/gsd-core/bin/lib/capability-command-router.cjs +733 -0
  25. package/gsd-core/bin/lib/capability-registry.cjs +157 -88
  26. package/gsd-core/bin/lib/capability-writer.cjs +6 -1
  27. package/gsd-core/bin/lib/check-command-router.cjs +129 -26
  28. package/gsd-core/bin/lib/claude-orchestration-command-router.cjs +115 -27
  29. package/gsd-core/bin/lib/claude-orchestration.cjs +84 -9
  30. package/gsd-core/bin/lib/clock.cjs +19 -0
  31. package/gsd-core/bin/lib/command-aliases.cjs +14 -0
  32. package/gsd-core/bin/lib/commands.cjs +129 -13
  33. package/gsd-core/bin/lib/config-loader.cjs +20 -4
  34. package/gsd-core/bin/lib/config.cjs +81 -18
  35. package/gsd-core/bin/lib/core-utils.cjs +14 -3
  36. package/gsd-core/bin/lib/decisions.cjs +32 -8
  37. package/gsd-core/bin/lib/docs.cjs +6 -0
  38. package/gsd-core/bin/lib/drift.cjs +4 -4
  39. package/gsd-core/bin/lib/external-descriptor-trust.cjs +14 -2
  40. package/gsd-core/bin/lib/frontmatter.cjs +22 -0
  41. package/gsd-core/bin/lib/gap-checker.cjs +17 -2
  42. package/gsd-core/bin/lib/gsd2-import.cjs +2 -1
  43. package/gsd-core/bin/lib/init.cjs +138 -60
  44. package/gsd-core/bin/lib/install-engine.cjs +301 -25
  45. package/gsd-core/bin/lib/install-profiles.cjs +239 -1
  46. package/gsd-core/bin/lib/installer-migration-authoring.cjs +2 -1
  47. package/gsd-core/bin/lib/installer-migrations/005-opencode-baseline-commands-dir.cjs +146 -0
  48. package/gsd-core/bin/lib/installer-migrations/006-pi-extension-cjs-to-js.cjs +91 -0
  49. package/gsd-core/bin/lib/installer-migrations.cjs +45 -6
  50. package/gsd-core/bin/lib/markdown-sectionizer.cjs +449 -0
  51. package/gsd-core/bin/lib/markdown-table.cjs +698 -0
  52. package/gsd-core/bin/lib/milestone.cjs +463 -43
  53. package/gsd-core/bin/lib/model-catalog.cjs +19 -4
  54. package/gsd-core/bin/lib/model-resolver.cjs +189 -7
  55. package/gsd-core/bin/lib/onboard-projection.cjs +11 -8
  56. package/gsd-core/bin/lib/phase-command-router.cjs +50 -2
  57. package/gsd-core/bin/lib/phase-id.cjs +26 -4
  58. package/gsd-core/bin/lib/phase-lifecycle.cjs +62 -36
  59. package/gsd-core/bin/lib/phase-locator.cjs +23 -2
  60. package/gsd-core/bin/lib/phase.cjs +636 -72
  61. package/gsd-core/bin/lib/plan-scan.cjs +73 -2
  62. package/gsd-core/bin/lib/roadmap-parser.cjs +225 -17
  63. package/gsd-core/bin/lib/roadmap.cjs +113 -52
  64. package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +14 -7
  65. package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +3 -2
  66. package/gsd-core/bin/lib/runtime-artifact-layout.cjs +24 -9
  67. package/gsd-core/bin/lib/runtime-hooks-surface.cjs +41 -17
  68. package/gsd-core/bin/lib/schema-detect.cjs +2 -1
  69. package/gsd-core/bin/lib/security.cjs +1 -1
  70. package/gsd-core/bin/lib/shell-command-projection.cjs +61 -25
  71. package/gsd-core/bin/lib/smart-entry.cjs +73 -7
  72. package/gsd-core/bin/lib/state-document.cjs +7 -4
  73. package/gsd-core/bin/lib/state-transition.cjs +122 -46
  74. package/gsd-core/bin/lib/state.cjs +456 -137
  75. package/gsd-core/bin/lib/surface.cjs +53 -11
  76. package/gsd-core/bin/lib/template.cjs +2 -1
  77. package/gsd-core/bin/lib/uat.cjs +474 -13
  78. package/gsd-core/bin/lib/ui-safety-gate.cjs +23 -1
  79. package/gsd-core/bin/lib/validate.cjs +12 -8
  80. package/gsd-core/bin/lib/verification.cjs +112 -17
  81. package/gsd-core/bin/lib/verify.cjs +224 -25
  82. package/gsd-core/bin/lib/workstream.cjs +3 -2
  83. package/gsd-core/bin/lib/worktree-safety.cjs +1 -1
  84. package/gsd-core/bin/lib/write-set.cjs +38 -0
  85. package/gsd-core/bin/shared/config-schema.manifest.json +5 -2
  86. package/gsd-core/references/api-coverage.md +37 -7
  87. package/gsd-core/references/checkpoints.md +13 -1
  88. package/gsd-core/references/common-bug-patterns.md +13 -0
  89. package/gsd-core/references/debugger-bug-taxonomy.md +111 -0
  90. package/gsd-core/references/debugger-fix-acceptance.md +157 -0
  91. package/gsd-core/references/debugger-philosophy.md +1 -0
  92. package/gsd-core/references/debugger-prevention.md +98 -0
  93. package/gsd-core/references/debugger-rca-branching.md +98 -0
  94. package/gsd-core/references/debugger-repro-hardening.md +130 -0
  95. package/gsd-core/references/debugger-sbfl.md +110 -0
  96. package/gsd-core/references/debugger-semantic-recall.md +81 -0
  97. package/gsd-core/references/execute-phase-quota-recovery.md +55 -0
  98. package/gsd-core/references/execute-phase-requirement-revert.md +8 -0
  99. package/gsd-core/references/execute-phase-response-language.md +7 -0
  100. package/gsd-core/references/planner-antipatterns.md +6 -0
  101. package/gsd-core/references/planner-mvp-mode.md +12 -13
  102. package/gsd-core/references/planner-preconditions.md +156 -0
  103. package/gsd-core/references/planner-reversibility.md +132 -0
  104. package/gsd-core/references/reviewer-instances.md +9 -7
  105. package/gsd-core/references/skeleton-template.md +1 -1
  106. package/gsd-core/references/thinking-models-planning.md +3 -1
  107. package/gsd-core/templates/DEBUG.md +5 -3
  108. package/gsd-core/workflows/add-phase.md +2 -0
  109. package/gsd-core/workflows/add-tests.md +4 -2
  110. package/gsd-core/workflows/add-todo.md +32 -1
  111. package/gsd-core/workflows/ai-integration-phase.md +4 -2
  112. package/gsd-core/workflows/audit-fix.md +2 -2
  113. package/gsd-core/workflows/check-todos.md +3 -1
  114. package/gsd-core/workflows/cleanup.md +7 -1
  115. package/gsd-core/workflows/code-review.md +17 -5
  116. package/gsd-core/workflows/complete-milestone.md +3 -0
  117. package/gsd-core/workflows/debug.md +27 -5
  118. package/gsd-core/workflows/diagnose-issues.md +1 -1
  119. package/gsd-core/workflows/discovery-phase.md +7 -0
  120. package/gsd-core/workflows/discuss-phase/templates/context.md +16 -2
  121. package/gsd-core/workflows/discuss-phase-assumptions.md +3 -0
  122. package/gsd-core/workflows/do.md +7 -1
  123. package/gsd-core/workflows/docs-update.md +1 -0
  124. package/gsd-core/workflows/eval-review.md +3 -0
  125. package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +4 -4
  126. package/gsd-core/workflows/execute-phase/steps/regression-gate.md +2 -2
  127. package/gsd-core/workflows/execute-phase.md +30 -37
  128. package/gsd-core/workflows/execute-plan.md +15 -4
  129. package/gsd-core/workflows/fast.md +8 -22
  130. package/gsd-core/workflows/graduation.md +3 -0
  131. package/gsd-core/workflows/health.md +7 -1
  132. package/gsd-core/workflows/help/modes/full.md +6 -2
  133. package/gsd-core/workflows/import.md +8 -2
  134. package/gsd-core/workflows/inbox.md +7 -0
  135. package/gsd-core/workflows/ingest-docs.md +15 -10
  136. package/gsd-core/workflows/manager.md +3 -1
  137. package/gsd-core/workflows/map-codebase.md +4 -4
  138. package/gsd-core/workflows/mvp-phase.md +3 -0
  139. package/gsd-core/workflows/new-milestone.md +69 -21
  140. package/gsd-core/workflows/new-project.md +17 -15
  141. package/gsd-core/workflows/new-workspace.md +3 -1
  142. package/gsd-core/workflows/onboard.md +3 -0
  143. package/gsd-core/workflows/plan-phase.md +14 -5
  144. package/gsd-core/workflows/plan-review-convergence.md +48 -3
  145. package/gsd-core/workflows/plant-seed.md +3 -0
  146. package/gsd-core/workflows/profile-user.md +7 -1
  147. package/gsd-core/workflows/progress.md +33 -5
  148. package/gsd-core/workflows/quick.md +21 -7
  149. package/gsd-core/workflows/remove-workspace.md +3 -0
  150. package/gsd-core/workflows/review.md +123 -68
  151. package/gsd-core/workflows/scan.md +1 -1
  152. package/gsd-core/workflows/secure-phase.md +4 -1
  153. package/gsd-core/workflows/settings-integrations.md +3 -0
  154. package/gsd-core/workflows/settings.md +3 -0
  155. package/gsd-core/workflows/ship.md +58 -5
  156. package/gsd-core/workflows/sketch.md +3 -0
  157. package/gsd-core/workflows/smart-entry.md +3 -0
  158. package/gsd-core/workflows/spec-phase.md +1 -1
  159. package/gsd-core/workflows/spike.md +7 -1
  160. package/gsd-core/workflows/transition.md +1 -1
  161. package/gsd-core/workflows/ui-phase.md +3 -1
  162. package/gsd-core/workflows/ui-review.md +3 -0
  163. package/gsd-core/workflows/undo.md +7 -0
  164. package/gsd-core/workflows/update.md +2 -0
  165. package/gsd-core/workflows/validate-phase.md +3 -0
  166. package/gsd-core/workflows/verify-phase.md +2 -2
  167. package/gsd-core/workflows/verify-work.md +7 -3
  168. package/hooks/dist/gsd-context-monitor.js +27 -9
  169. package/hooks/dist/gsd-statusline.js +252 -17
  170. package/hooks/gsd-context-monitor.js +27 -9
  171. package/hooks/gsd-statusline.js +252 -17
  172. package/package.json +8 -4
  173. package/pi/gsd.cjs +8 -2
  174. package/scripts/changeset/lint.cjs +1 -0
  175. package/scripts/changeset/parse.cjs +26 -0
  176. package/scripts/check-glossary-refs.cjs +220 -0
  177. package/scripts/ci-rebase-check.cjs +48 -4
  178. package/scripts/ci-test-scope.cjs +39 -1
  179. package/scripts/gen-adr-index.cjs +526 -0
  180. package/scripts/gen-golden-install-parity-zcode.cjs +35 -45
  181. package/scripts/gen-install-tree-fixtures.cjs +75 -0
  182. package/scripts/gen-test-timings.cjs +201 -0
  183. package/scripts/lint-allow-test-rule-refs.allowlist.json +0 -1
  184. package/scripts/lint-portable-timeout.cjs +140 -0
  185. package/scripts/lint-table-schema-drift.cjs +157 -0
  186. package/scripts/lint-test-file-count.allowlist.json +1 -0
  187. package/scripts/release-tarball-smoke.cjs +18 -11
  188. package/scripts/run-tests.cjs +420 -58
  189. package/skills/gsd-ai-integration-phase/SKILL.md +1 -1
  190. package/skills/gsd-mempalace-capture/SKILL.md +31 -1
  191. package/skills/gsd-new-milestone/SKILL.md +1 -1
  192. package/skills/gsd-plan-phase/SKILL.md +5 -3
  193. package/skills/gsd-plan-review-convergence/SKILL.md +3 -2
  194. package/skills/gsd-surface/SKILL.md +6 -6
  195. package/vscode/package.json +1 -1
@@ -119,10 +119,20 @@ Collect phase artifacts for the review prompt:
119
119
  ```bash
120
120
  INIT=$(gsd_run query init.phase-op "${PHASE_ARG}")
121
121
  if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
122
+
123
+ # #2358: ONE run-scoped temp dir (portable via ${TMPDIR:-/tmp}) so overlapping
124
+ # runs never collide or read each other's stale files.
125
+ RUN_DIR=$(mktemp -d "${TMPDIR:-/tmp}/gsd-review-XXXXXX")
126
+ echo "RUN_DIR=$RUN_DIR"
122
127
  ```
123
128
 
124
129
  Read from init: `phase_dir`, `phase_number`, `padded_phase`.
125
130
 
131
+ Capture `RUN_DIR` above (created ONCE) and thread it into every `{run_dir}`
132
+ placeholder and `$RUN_DIR`/`${RUN_DIR}` reference within a bash block. Do NOT
133
+ re-run `mktemp -d` later — every block must resolve to this same directory, or
134
+ `build_prompt`'s writes and `invoke_reviewers`' reads split.
135
+
126
136
  Then read:
127
137
  1. `.planning/PROJECT.md` (first 80 lines — project context)
128
138
  2. Phase section from `.planning/ROADMAP.md`
@@ -189,40 +199,42 @@ Focus on:
189
199
  Output your review in markdown format.
190
200
  ```
191
201
 
192
- Write to a temp file: `/tmp/gsd-review-prompt-{phase}.md`
202
+ Write to a temp file: `{run_dir}/gsd-review-prompt.md`
193
203
 
194
204
  Also write individual section files so the budget tool can re-trim per reviewer:
195
205
 
196
206
  ```bash
207
+ RUN_DIR="{run_dir}" # from gather_context
208
+
197
209
  # Write individual section files for per-reviewer budget trimming
198
210
  # These are always written so reviewers with a budget can invoke prompt-budget
199
- cp "$INSTRUCTIONS_BLOCK_FILE" "/tmp/gsd-review-${PHASE}-instructions.md"
200
- cp "$ROADMAP_SECTION_FILE" "/tmp/gsd-review-${PHASE}-roadmap.md"
211
+ cp "$INSTRUCTIONS_BLOCK_FILE" "${RUN_DIR}/gsd-review-instructions.md"
212
+ cp "$ROADMAP_SECTION_FILE" "${RUN_DIR}/gsd-review-roadmap.md"
201
213
 
202
214
  # Plan files: copy each PLAN.md to a predictable numbered path
203
215
  PLAN_INDEX=0
204
216
  for PLAN_FILE in "${PHASE_DIR}"/*-PLAN.md; do
205
217
  PADDED_IDX=$(printf '%02d' "$PLAN_INDEX")
206
- cp "$PLAN_FILE" "/tmp/gsd-review-${PHASE}-plan-${PADDED_IDX}.md"
218
+ cp "$PLAN_FILE" "${RUN_DIR}/gsd-review-plan-${PADDED_IDX}.md"
207
219
  PLAN_INDEX=$((PLAN_INDEX + 1))
208
220
  done
209
221
 
210
222
  # Optional section files (only if content was included in the combined prompt)
211
223
  if [ -f ".planning/PROJECT.md" ]; then
212
- cp .planning/PROJECT.md "/tmp/gsd-review-${PHASE}-project.md"
224
+ cp .planning/PROJECT.md "${RUN_DIR}/gsd-review-project.md"
213
225
  fi
214
226
  if ls "${PHASE_DIR}/"*"-CONTEXT.md" >/dev/null 2>&1; then
215
- cat "${PHASE_DIR}/"*"-CONTEXT.md" > "/tmp/gsd-review-${PHASE}-context.md"
227
+ cat "${PHASE_DIR}/"*"-CONTEXT.md" > "${RUN_DIR}/gsd-review-context.md"
216
228
  fi
217
229
  if ls "${PHASE_DIR}/"*"-RESEARCH.md" >/dev/null 2>&1; then
218
- cat "${PHASE_DIR}/"*"-RESEARCH.md" > "/tmp/gsd-review-${PHASE}-research.md"
230
+ cat "${PHASE_DIR}/"*"-RESEARCH.md" > "${RUN_DIR}/gsd-review-research.md"
219
231
  fi
220
232
  if [ -f ".planning/REQUIREMENTS.md" ]; then
221
- cp .planning/REQUIREMENTS.md "/tmp/gsd-review-${PHASE}-requirements.md"
233
+ cp .planning/REQUIREMENTS.md "${RUN_DIR}/gsd-review-requirements.md"
222
234
  fi
223
235
  ```
224
236
 
225
- Note: The variable names above (`INSTRUCTIONS_BLOCK_FILE`, `ROADMAP_SECTION_FILE`, `PHASE_DIR`, `PHASE`) reference the variables already established during prompt assembly. In practice the AI implementing this step writes the instruction and roadmap blocks to temp files while assembling the combined prompt, then copies those same temp files to the per-reviewer section paths. If the assembled prompt was built inline (string concatenation rather than file-by-file), write each section to the corresponding path after writing the combined file.
237
+ Note: `INSTRUCTIONS_BLOCK_FILE`, `ROADMAP_SECTION_FILE`, and `PHASE_DIR` come from prompt assembly; `RUN_DIR` is the run-scoped dir from `gather_context` (#2358) re-assigned from `{run_dir}` above. Copy the temp files written during prompt assembly to these section paths (or write each section here if the prompt was built inline).
226
238
  </step>
227
239
 
228
240
  <step name="invoke_reviewers">
@@ -255,21 +267,23 @@ shell-interpolated). Exact invocation in `gsd-core/references/reviewer-instances
255
267
 
256
268
  For each selected CLI, invoke in sequence (not parallel — avoid rate limits):
257
269
 
270
+ **Timeout guidance (#2194):** prompt-fed source-grounded reviews are slow — measured ~570s for Codex at `xhigh` effort and ~525s for headless Claude on a large plan set. Each of the Gemini / Claude / Codex blocks below MUST be invoked with a high Bash `timeout:` — at least `900000` (15 min), and `1200000` (20 min) for Codex `xhigh` or headless Claude — so a lane is not killed mid-review. On Claude Code, raise the host cap via `BASH_MAX_TIMEOUT_MS` if a review can exceed it. A silent empty output after a long run is a **timeout kill, not a crash** — the Codex `0xc0000142` misdiagnosis persisted because the empty-output branches below cannot distinguish the two; treat an empty result on a slow lane as a dropped lane and re-run with more time rather than diagnosing a CLI/sandbox failure. A cross-AI review that silently drops a lane is blind in one eye.
271
+
258
272
  **Gemini:**
259
273
  ```bash
260
274
  if [ -n "$GEMINI_MODEL" ] && [ "$GEMINI_MODEL" != "null" ]; then
261
- cat /tmp/gsd-review-prompt-{phase}.md | gemini -m "$GEMINI_MODEL" -p - 2>/dev/null > /tmp/gsd-review-gemini-{phase}.md
275
+ cat {run_dir}/gsd-review-prompt.md | gemini -m "$GEMINI_MODEL" -p - 2>/dev/null > {run_dir}/gsd-review-gemini.md
262
276
  else
263
- cat /tmp/gsd-review-prompt-{phase}.md | gemini -p - 2>/dev/null > /tmp/gsd-review-gemini-{phase}.md
277
+ cat {run_dir}/gsd-review-prompt.md | gemini -p - 2>/dev/null > {run_dir}/gsd-review-gemini.md
264
278
  fi
265
279
  ```
266
280
 
267
281
  **Claude (separate session):**
268
282
  ```bash
269
283
  if [ -n "$CLAUDE_MODEL" ] && [ "$CLAUDE_MODEL" != "null" ]; then
270
- cat /tmp/gsd-review-prompt-{phase}.md | claude --model "$CLAUDE_MODEL" -p - 2>/dev/null > /tmp/gsd-review-claude-{phase}.md
284
+ cat {run_dir}/gsd-review-prompt.md | claude --model "$CLAUDE_MODEL" -p - 2>/dev/null > {run_dir}/gsd-review-claude.md
271
285
  else
272
- cat /tmp/gsd-review-prompt-{phase}.md | claude -p - 2>/dev/null > /tmp/gsd-review-claude-{phase}.md
286
+ cat {run_dir}/gsd-review-prompt.md | claude -p - 2>/dev/null > {run_dir}/gsd-review-claude.md
273
287
  fi
274
288
  ```
275
289
 
@@ -284,13 +298,13 @@ fi
284
298
  # stdout redirect would append that noise to a non-empty file — slipping past the
285
299
  # `[ ! -s … ]` empty-output guard as a silently polluted review.
286
300
  if [ -n "$CODEX_MODEL" ] && [ "$CODEX_MODEL" != "null" ]; then
287
- cat /tmp/gsd-review-prompt-{phase}.md | codex exec --ephemeral $CODEX_BYPASS_FLAG --model "$CODEX_MODEL" --skip-git-repo-check -o /tmp/gsd-review-codex-{phase}.md - 2>/tmp/gsd-review-codex-{phase}.err >/dev/null
301
+ cat {run_dir}/gsd-review-prompt.md | codex exec --ephemeral $CODEX_BYPASS_FLAG --model "$CODEX_MODEL" --skip-git-repo-check -o {run_dir}/gsd-review-codex.md - 2>{run_dir}/gsd-review-codex.err >/dev/null
288
302
  else
289
- cat /tmp/gsd-review-prompt-{phase}.md | codex exec --ephemeral $CODEX_BYPASS_FLAG --skip-git-repo-check -o /tmp/gsd-review-codex-{phase}.md - 2>/tmp/gsd-review-codex-{phase}.err >/dev/null
303
+ cat {run_dir}/gsd-review-prompt.md | codex exec --ephemeral $CODEX_BYPASS_FLAG --skip-git-repo-check -o {run_dir}/gsd-review-codex.md - 2>{run_dir}/gsd-review-codex.err >/dev/null
290
304
  fi
291
- if [ ! -s /tmp/gsd-review-codex-{phase}.md ]; then
292
- echo "Codex review failed or returned empty output. stderr:" > /tmp/gsd-review-codex-{phase}.md
293
- cat /tmp/gsd-review-codex-{phase}.err >> /tmp/gsd-review-codex-{phase}.md
305
+ if [ ! -s {run_dir}/gsd-review-codex.md ]; then
306
+ echo "Codex review failed or returned empty output. stderr:" > {run_dir}/gsd-review-codex.md
307
+ cat {run_dir}/gsd-review-codex.err >> {run_dir}/gsd-review-codex.md
294
308
  fi
295
309
  ```
296
310
 
@@ -299,7 +313,7 @@ fi
299
313
  Note: CodeRabbit reviews the current git diff/working tree — it does not accept a prompt or model flag. It may take up to 5 minutes. Use `timeout: 360000` on the Bash tool call. The source-grounding requirement in the build_prompt Review Instructions applies only to the prompt-fed reviewers above; CodeRabbit is a diff-only reviewer and never receives it. Treat its output as a diff observation, not a grounded plan-level verdict.
300
314
 
301
315
  ```bash
302
- coderabbit review --prompt-only 2>/dev/null > /tmp/gsd-review-coderabbit-{phase}.md
316
+ coderabbit review --prompt-only 2>/dev/null > {run_dir}/gsd-review-coderabbit.md
303
317
  ```
304
318
 
305
319
  **OpenCode (via GitHub Copilot):**
@@ -331,30 +345,30 @@ if [ -n "$OPENCODE_MODEL" ] && [ "$OPENCODE_MODEL" != "null" ]; then
331
345
  else
332
346
  set --
333
347
  fi
334
- cat /tmp/gsd-review-prompt-{phase}.md | opencode run "$@" --format json - 2>/tmp/gsd-review-opencode-{phase}.err > /tmp/gsd-review-opencode-{phase}.json
335
- # Reconstruct the review from the assistant text parts. Capture into a variable and
336
- # test its CONTENT (not the output file's size): an empty extraction still prints a
337
- # trailing newline, which would fool a `[ -s file ]` check into skipping the stub.
338
- OPENCODE_REVIEW=$(jq -rs '[.[] | select(.type=="text") | .part.text // empty] | join("\n")' /tmp/gsd-review-opencode-{phase}.json 2>/dev/null)
348
+ cat {run_dir}/gsd-review-prompt.md | opencode run "$@" --format json - 2>{run_dir}/gsd-review-opencode.err > {run_dir}/gsd-review-opencode.json
349
+ # Reconstruct the review from the assistant text parts into a variable and test
350
+ # its CONTENT, not the file size: an empty extraction still prints a trailing
351
+ # newline that would fool a `[ -s file ]` check into skipping the stub.
352
+ OPENCODE_REVIEW=$(jq -rs '[.[] | select(.type=="text") | .part.text // empty] | join("\n")' {run_dir}/gsd-review-opencode.json 2>/dev/null)
339
353
  if [ -n "$OPENCODE_REVIEW" ]; then
340
- printf '%s\n' "$OPENCODE_REVIEW" > /tmp/gsd-review-opencode-{phase}.md
354
+ printf '%s\n' "$OPENCODE_REVIEW" > {run_dir}/gsd-review-opencode.md
341
355
  else
342
- # No assistant text (agent emitted no final message, or stdout was not valid JSON events).
356
+ # No assistant text (no final message, or stdout was not valid JSON):
343
357
  {
344
358
  echo "OpenCode review returned no assistant text (#1936: agent ended its turn with no final message)."
345
- OPENCODE_DIAG=$(jq -rs '[.[] | select(.type=="step_finish")] | last | "stop reason=\(.part.reason // "?"), output tokens=\(.part.tokens.output // "?")"' /tmp/gsd-review-opencode-{phase}.json 2>/dev/null)
359
+ OPENCODE_DIAG=$(jq -rs '[.[] | select(.type=="step_finish")] | last | "stop reason=\(.part.reason // "?"), output tokens=\(.part.tokens.output // "?")"' {run_dir}/gsd-review-opencode.json 2>/dev/null)
346
360
  [ -n "$OPENCODE_DIAG" ] && echo "Diagnostic: $OPENCODE_DIAG"
347
361
  echo "stderr:"
348
- cat /tmp/gsd-review-opencode-{phase}.err
349
- } > /tmp/gsd-review-opencode-{phase}.md
362
+ cat {run_dir}/gsd-review-opencode.err
363
+ } > {run_dir}/gsd-review-opencode.md
350
364
  fi
351
365
  ```
352
366
 
353
367
  **Qwen Code:**
354
368
  ```bash
355
- cat /tmp/gsd-review-prompt-{phase}.md | qwen - 2>/dev/null > /tmp/gsd-review-qwen-{phase}.md
356
- if [ ! -s /tmp/gsd-review-qwen-{phase}.md ]; then
357
- echo "Qwen review failed or returned empty output." > /tmp/gsd-review-qwen-{phase}.md
369
+ cat {run_dir}/gsd-review-prompt.md | qwen - 2>/dev/null > {run_dir}/gsd-review-qwen.md
370
+ if [ ! -s {run_dir}/gsd-review-qwen.md ]; then
371
+ echo "Qwen review failed or returned empty output." > {run_dir}/gsd-review-qwen.md
358
372
  fi
359
373
  ```
360
374
 
@@ -364,11 +378,16 @@ fi
364
378
  # prompt as an ARGUMENT, not stdin. A full review prompt can exceed the OS argument limit, so
365
379
  # reference the prompt file by path rather than inlining it. Capture stderr so a failure is
366
380
  # diagnosable instead of a silent empty result.
367
- CURSOR_PROMPT_ARG="Read the file at /tmp/gsd-review-prompt-{phase}.md in full and carry out the review request it contains. Output only the resulting markdown review. Do not edit any files."
368
- cursor-agent -p --mode ask --trust --output-format text "$CURSOR_PROMPT_ARG" 2>/tmp/gsd-review-cursor-{phase}.err > /tmp/gsd-review-cursor-{phase}.md
369
- if [ ! -s /tmp/gsd-review-cursor-{phase}.md ]; then
370
- echo "Cursor review failed or returned empty output. stderr:" > /tmp/gsd-review-cursor-{phase}.md
371
- cat /tmp/gsd-review-cursor-{phase}.err >> /tmp/gsd-review-cursor-{phase}.md
381
+ # #2176: same absolute-root anchor as the Antigravity block — cursor-agent runs
382
+ # in the repo cwd, but repo-relative references in the assembled prompt still
383
+ # need an explicit root to resolve against. rev-parse (not bare pwd) so the
384
+ # anchor is correct even when /gsd:review is invoked from a repo subdirectory.
385
+ _CURSOR_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
386
+ CURSOR_PROMPT_ARG="Read the file at {run_dir}/gsd-review-prompt.md in full and carry out the review request it contains. The repository under review is at $_CURSOR_ROOT — resolve every relative file path in the review request against that absolute root. Output only the resulting markdown review. Do not edit any files."
387
+ cursor-agent -p --mode ask --trust --output-format text "$CURSOR_PROMPT_ARG" 2>{run_dir}/gsd-review-cursor.err > {run_dir}/gsd-review-cursor.md
388
+ if [ ! -s {run_dir}/gsd-review-cursor.md ]; then
389
+ echo "Cursor review failed or returned empty output. stderr:" > {run_dir}/gsd-review-cursor.md
390
+ cat {run_dir}/gsd-review-cursor.err >> {run_dir}/gsd-review-cursor.md
372
391
  fi
373
392
  ```
374
393
 
@@ -456,7 +475,19 @@ if [ -n "$AGY_MODEL" ] && [ "$AGY_MODEL" != "null" ]; then
456
475
  else
457
476
  set --
458
477
  fi
459
- _AGY_PROMPT="Read the file at /tmp/gsd-review-prompt-{phase}.md in full and carry out the review request it contains. Output only the resulting markdown review. Do not edit any files."
478
+ # #2176: grant the reviewer the repo under review. Without --add-dir, agy's
479
+ # permission context never receives the cwd repo — the agent anchors on its own
480
+ # ~/.gemini/antigravity-cli/scratch dir and reviews the plan text in isolation
481
+ # (the exact failure the Review Instructions forbid). Capability-probed like the
482
+ # Codex bypass flag so an older agy without --add-dir still runs; the prompt
483
+ # anchor below keeps absolute-path reads possible on that fallback.
484
+ if agy --help 2>/dev/null | grep -q -- '--add-dir'; then
485
+ set -- "$@" --add-dir "$_AGY_WS"
486
+ fi
487
+ # #2176: anchor the prompt to the absolute repo root so repo-relative references
488
+ # in the assembled review prompt resolve even on the no---add-dir fallback, and
489
+ # require an explicit self-report if the reviewer still cannot read the repo.
490
+ _AGY_PROMPT="Read the file at {run_dir}/gsd-review-prompt.md in full and carry out the review request it contains. The repository under review is at $_AGY_WS — resolve every relative file path in the review request against that absolute root and verify claims against those files. If you cannot read files under $_AGY_WS, begin your output with the exact line REVIEWED-WITHOUT-REPO-ACCESS before the review. Output only the resulting markdown review. Do not edit any files."
460
491
  # Capability-probe an external wall-clock killer (GNU coreutils `timeout` or the
461
492
  # macOS Homebrew `gtimeout`). Stock macOS ships NEITHER — a bare `timeout …` would
462
493
  # fail with rc 127 ("command not found") and silently lose the reviewer, so fall
@@ -466,20 +497,20 @@ _AGY_PROMPT="Read the file at /tmp/gsd-review-prompt-{phase}.md in full and carr
466
497
  # healthy run. Mirrors the probe in scripts/base64-scan.sh.
467
498
  _AGY_KILLER="$(command -v timeout 2>/dev/null || command -v gtimeout 2>/dev/null || true)"
468
499
  if [ -n "$_AGY_KILLER" ]; then
469
- "$_AGY_KILLER" 600 agy --print-timeout 540s "$@" -p "$_AGY_PROMPT" </dev/null 2>/dev/null > /tmp/gsd-review-antigravity-{phase}.md
500
+ "$_AGY_KILLER" 600 agy --print-timeout 540s "$@" -p "$_AGY_PROMPT" </dev/null 2>/dev/null > {run_dir}/gsd-review-antigravity.md
470
501
  else
471
- agy --print-timeout 540s "$@" -p "$_AGY_PROMPT" </dev/null 2>/dev/null > /tmp/gsd-review-antigravity-{phase}.md
502
+ agy --print-timeout 540s "$@" -p "$_AGY_PROMPT" </dev/null 2>/dev/null > {run_dir}/gsd-review-antigravity.md
472
503
  fi
473
504
  _AGY_RC=$?
474
505
  if [ "$_AGY_RC" -ne 0 ]; then
475
- : > /tmp/gsd-review-antigravity-{phase}.md
506
+ : > {run_dir}/gsd-review-antigravity.md
476
507
  fi
477
508
 
478
509
  # Step 2 — transcript fallback: catches Windows agy -p stdout bug (and any future stdout-silent edge cases).
479
510
  # Reads only lines appended AFTER the pre-flight watermark. If agy failed before writing a new response,
480
511
  # _AGY_RESULT is empty and Step 3 fires — no stale content can leak through.
481
512
  # Undocumented paths, verified agy 1.0.0–1.0.2. See maintainer note above if these break.
482
- if [ ! -s /tmp/gsd-review-antigravity-{phase}.md ]; then
513
+ if [ ! -s {run_dir}/gsd-review-antigravity.md ]; then
483
514
  if [ -f "$_AGY_CACHE" ]; then
484
515
  _AGY_CONV=$(jq -r --arg ws "$_AGY_WS" '
485
516
  .[$ws] //
@@ -497,7 +528,7 @@ if [ ! -s /tmp/gsd-review-antigravity-{phase}.md ]; then
497
528
  _AGY_RESULT=$(tail -n +"$((_AGY_SKIP + 1))" "$_AGY_TX" 2>/dev/null | \
498
529
  jq -r 'select(.source=="MODEL" and .status=="DONE" and .type=="PLANNER_RESPONSE") | .content' \
499
530
  2>/dev/null | tail -1)
500
- [ -n "$_AGY_RESULT" ] && echo "$_AGY_RESULT" > /tmp/gsd-review-antigravity-{phase}.md
531
+ [ -n "$_AGY_RESULT" ] && echo "$_AGY_RESULT" > {run_dir}/gsd-review-antigravity.md
501
532
  fi
502
533
  fi
503
534
  fi
@@ -505,7 +536,7 @@ fi
505
536
 
506
537
  # Step 3 — final guard: both approaches yielded nothing (auth error, first-run setup,
507
538
  # path schema changed, 404'd pinned model, pre-session stall, etc.)
508
- if [ ! -s /tmp/gsd-review-antigravity-{phase}.md ]; then
539
+ if [ ! -s {run_dir}/gsd-review-antigravity.md ]; then
509
540
  {
510
541
  echo "Antigravity review failed or returned empty output."
511
542
  # #2073 mode 2: a pinned model that 404s exits 0 with empty stdout AND an empty
@@ -521,7 +552,27 @@ if [ ! -s /tmp/gsd-review-antigravity-{phase}.md ]; then
521
552
  fi
522
553
  # #2073 mode 3: pre-session stall tell — no new conversation dir appeared.
523
554
  echo "If no agy run started, that is the pre-session-stall case: check whether a new ~/.gemini/antigravity-cli/brain/<conv-id>/ dir appeared within ~30s of launch."
524
- } > /tmp/gsd-review-antigravity-{phase}.md
555
+ } > {run_dir}/gsd-review-antigravity.md
556
+ fi
557
+
558
+ # #2176: blind-review marker. Two tells that the reviewer ran without repo
559
+ # access: the prompt's mandated REVIEWED-WITHOUT-REPO-ACCESS self-report in the
560
+ # first lines of output, or the agent DECLARING the scratch dir as its
561
+ # workspace. Both patterns are anchored — the self-report to the head of the
562
+ # file, the scratch tell to a workspace-declaration phrasing — so a grounded
563
+ # review that merely QUOTES these strings (e.g. reviewing this very file) is
564
+ # never mis-stamped. Stamp a machine-readable marker so the Consensus Summary
565
+ # down-weights the review instead of counting an ungrounded verdict at full
566
+ # weight. (Temp file + mv, no in-place sed — BSD/GNU safe.)
567
+ if [ -s {run_dir}/gsd-review-antigravity.md ] && \
568
+ { head -5 {run_dir}/gsd-review-antigravity.md | grep -q 'REVIEWED-WITHOUT-REPO-ACCESS' || \
569
+ grep -qiE '(workspace|working) (directory|dir).{0,40}antigravity-cli/scratch' {run_dir}/gsd-review-antigravity.md; }; then
570
+ {
571
+ echo "> [reviewed-without-repo-access] This reviewer ran without visibility into the repo under review — down-weight its verdict in the Consensus Summary."
572
+ echo ""
573
+ cat {run_dir}/gsd-review-antigravity.md
574
+ } > {run_dir}/gsd-review-antigravity.md.tmp && \
575
+ mv {run_dir}/gsd-review-antigravity.md.tmp {run_dir}/gsd-review-antigravity.md
525
576
  fi
526
577
  ```
527
578
 
@@ -542,22 +593,22 @@ prepare_trimmed_prompt_for_reviewer() {
542
593
  [ "$REVIEWER_BUDGET" = "0" ] && return 0
543
594
 
544
595
  PLAN_FILE_ARGS=""
545
- for p in /tmp/gsd-review-{phase}-plan-*.md; do
596
+ for p in {run_dir}/gsd-review-plan-*.md; do
546
597
  [ -f "$p" ] && PLAN_FILE_ARGS="$PLAN_FILE_ARGS --plan-file $p"
547
598
  done
548
599
  PROJECT_ARG=""
549
- [ -f "/tmp/gsd-review-{phase}-project.md" ] && PROJECT_ARG="--project-file /tmp/gsd-review-{phase}-project.md"
600
+ [ -f "{run_dir}/gsd-review-project.md" ] && PROJECT_ARG="--project-file {run_dir}/gsd-review-project.md"
550
601
  CONTEXT_ARG=""
551
- [ -f "/tmp/gsd-review-{phase}-context.md" ] && CONTEXT_ARG="--context-file /tmp/gsd-review-{phase}-context.md"
602
+ [ -f "{run_dir}/gsd-review-context.md" ] && CONTEXT_ARG="--context-file {run_dir}/gsd-review-context.md"
552
603
  RESEARCH_ARG=""
553
- [ -f "/tmp/gsd-review-{phase}-research.md" ] && RESEARCH_ARG="--research-file /tmp/gsd-review-{phase}-research.md"
604
+ [ -f "{run_dir}/gsd-review-research.md" ] && RESEARCH_ARG="--research-file {run_dir}/gsd-review-research.md"
554
605
  REQUIREMENTS_ARG=""
555
- [ -f "/tmp/gsd-review-{phase}-requirements.md" ] && REQUIREMENTS_ARG="--requirements-file /tmp/gsd-review-{phase}-requirements.md"
606
+ [ -f "{run_dir}/gsd-review-requirements.md" ] && REQUIREMENTS_ARG="--requirements-file {run_dir}/gsd-review-requirements.md"
556
607
 
557
608
  gsd_run query prompt-budget \
558
609
  --budget "$REVIEWER_BUDGET" \
559
- --instructions-file "/tmp/gsd-review-{phase}-instructions.md" \
560
- --roadmap-file "/tmp/gsd-review-{phase}-roadmap.md" \
610
+ --instructions-file "{run_dir}/gsd-review-instructions.md" \
611
+ --roadmap-file "{run_dir}/gsd-review-roadmap.md" \
561
612
  $PLAN_FILE_ARGS $PROJECT_ARG $CONTEXT_ARG $RESEARCH_ARG $REQUIREMENTS_ARG \
562
613
  --output-prompt "$OUTPUT_PROMPT" \
563
614
  --output-metadata "$OUTPUT_META"
@@ -571,11 +622,11 @@ if [ -z "$OLLAMA_REVIEWER_BUDGET" ] || [ "$OLLAMA_REVIEWER_BUDGET" = "null" ]; t
571
622
  fi
572
623
 
573
624
  # Apply budget trim for Ollama if a budget is configured
574
- OLLAMA_PROMPT_FILE="/tmp/gsd-review-prompt-{phase}.md"
625
+ OLLAMA_PROMPT_FILE="{run_dir}/gsd-review-prompt.md"
575
626
  OLLAMA_SKIP=0
576
627
  if [ -n "$OLLAMA_REVIEWER_BUDGET" ] && [ "$OLLAMA_REVIEWER_BUDGET" != "null" ] && [ "$OLLAMA_REVIEWER_BUDGET" != "0" ]; then
577
- OLLAMA_TRIMMED_PROMPT="/tmp/gsd-review-prompt-{phase}-ollama.md"
578
- OLLAMA_TRIM_META="/tmp/gsd-review-prompt-{phase}-ollama.metadata.json"
628
+ OLLAMA_TRIMMED_PROMPT="{run_dir}/gsd-review-prompt-ollama.md"
629
+ OLLAMA_TRIM_META="{run_dir}/gsd-review-prompt-ollama.metadata.json"
579
630
  prepare_trimmed_prompt_for_reviewer "ollama" "$OLLAMA_REVIEWER_BUDGET" "$OLLAMA_TRIMMED_PROMPT" "$OLLAMA_TRIM_META"
580
631
  OLLAMA_EXIT=$?
581
632
  if [ $OLLAMA_EXIT -ne 0 ]; then
@@ -603,9 +654,9 @@ jq -n --rawfile content "$OLLAMA_PROMPT_FILE" \
603
654
  curl -s --max-time 120 -X POST "${OLLAMA_HOST}/v1/chat/completions" \
604
655
  -H "Content-Type: application/json" -d @- 2>/dev/null | \
605
656
  jq -r '.choices[0].message.content // "Ollama review failed or returned empty output."' \
606
- > /tmp/gsd-review-ollama-{phase}.md
607
- if [ ! -s /tmp/gsd-review-ollama-{phase}.md ]; then
608
- echo "Ollama review failed or returned empty output." > /tmp/gsd-review-ollama-{phase}.md
657
+ > {run_dir}/gsd-review-ollama.md
658
+ if [ ! -s {run_dir}/gsd-review-ollama.md ]; then
659
+ echo "Ollama review failed or returned empty output." > {run_dir}/gsd-review-ollama.md
609
660
  fi
610
661
  fi
611
662
  ```
@@ -619,11 +670,11 @@ if [ -z "$LM_STUDIO_REVIEWER_BUDGET" ] || [ "$LM_STUDIO_REVIEWER_BUDGET" = "null
619
670
  fi
620
671
 
621
672
  # Apply budget trim for LM Studio if a budget is configured
622
- LM_STUDIO_PROMPT_FILE="/tmp/gsd-review-prompt-{phase}.md"
673
+ LM_STUDIO_PROMPT_FILE="{run_dir}/gsd-review-prompt.md"
623
674
  LM_STUDIO_SKIP=0
624
675
  if [ -n "$LM_STUDIO_REVIEWER_BUDGET" ] && [ "$LM_STUDIO_REVIEWER_BUDGET" != "null" ] && [ "$LM_STUDIO_REVIEWER_BUDGET" != "0" ]; then
625
- LM_STUDIO_TRIMMED_PROMPT="/tmp/gsd-review-prompt-{phase}-lm_studio.md"
626
- LM_STUDIO_TRIM_META="/tmp/gsd-review-prompt-{phase}-lm_studio.metadata.json"
676
+ LM_STUDIO_TRIMMED_PROMPT="{run_dir}/gsd-review-prompt-lm_studio.md"
677
+ LM_STUDIO_TRIM_META="{run_dir}/gsd-review-prompt-lm_studio.metadata.json"
627
678
  prepare_trimmed_prompt_for_reviewer "lm_studio" "$LM_STUDIO_REVIEWER_BUDGET" "$LM_STUDIO_TRIMMED_PROMPT" "$LM_STUDIO_TRIM_META"
628
679
  LM_STUDIO_EXIT=$?
629
680
  if [ $LM_STUDIO_EXIT -ne 0 ]; then
@@ -656,7 +707,7 @@ if [ -n "$LM_STUDIO_ACTUAL_MODEL" ] && [ "$LM_STUDIO_ACTUAL_MODEL" != "null" ] &
656
707
  fi
657
708
  LM_STUDIO_CONTENT=$(echo "$LM_STUDIO_RESPONSE" | jq -r '.choices[0].message.content // ""' 2>/dev/null || echo "")
658
709
  if [ -n "$LM_STUDIO_CONTENT" ]; then
659
- echo "$LM_STUDIO_CONTENT" > /tmp/gsd-review-lm_studio-{phase}.md
710
+ echo "$LM_STUDIO_CONTENT" > {run_dir}/gsd-review-lm_studio.md
660
711
  else
661
712
  echo "Warning: LM Studio returned empty content — skipping review." >&2
662
713
  fi
@@ -672,11 +723,11 @@ if [ -z "$LLAMA_CPP_REVIEWER_BUDGET" ] || [ "$LLAMA_CPP_REVIEWER_BUDGET" = "null
672
723
  fi
673
724
 
674
725
  # Apply budget trim for llama.cpp if a budget is configured
675
- LLAMA_CPP_PROMPT_FILE="/tmp/gsd-review-prompt-{phase}.md"
726
+ LLAMA_CPP_PROMPT_FILE="{run_dir}/gsd-review-prompt.md"
676
727
  LLAMA_CPP_SKIP=0
677
728
  if [ -n "$LLAMA_CPP_REVIEWER_BUDGET" ] && [ "$LLAMA_CPP_REVIEWER_BUDGET" != "null" ] && [ "$LLAMA_CPP_REVIEWER_BUDGET" != "0" ]; then
678
- LLAMA_CPP_TRIMMED_PROMPT="/tmp/gsd-review-prompt-{phase}-llama_cpp.md"
679
- LLAMA_CPP_TRIM_META="/tmp/gsd-review-prompt-{phase}-llama_cpp.metadata.json"
729
+ LLAMA_CPP_TRIMMED_PROMPT="{run_dir}/gsd-review-prompt-llama_cpp.md"
730
+ LLAMA_CPP_TRIM_META="{run_dir}/gsd-review-prompt-llama_cpp.metadata.json"
680
731
  prepare_trimmed_prompt_for_reviewer "llama_cpp" "$LLAMA_CPP_REVIEWER_BUDGET" "$LLAMA_CPP_TRIMMED_PROMPT" "$LLAMA_CPP_TRIM_META"
681
732
  LLAMA_CPP_EXIT=$?
682
733
  if [ $LLAMA_CPP_EXIT -ne 0 ]; then
@@ -705,7 +756,7 @@ LLAMA_CPP_CONTENT=$(jq -n --rawfile content "$LLAMA_CPP_PROMPT_FILE" \
705
756
  -H "Content-Type: application/json" -d @- 2>/dev/null | \
706
757
  jq -r '.choices[0].message.content // ""' 2>/dev/null || echo "")
707
758
  if [ -n "$LLAMA_CPP_CONTENT" ]; then
708
- echo "$LLAMA_CPP_CONTENT" > /tmp/gsd-review-llama_cpp-{phase}.md
759
+ echo "$LLAMA_CPP_CONTENT" > {run_dir}/gsd-review-llama_cpp.md
709
760
  else
710
761
  echo "Warning: llama.cpp returned empty content — skipping review." >&2
711
762
  fi
@@ -835,7 +886,7 @@ trimmed_reviewers: # only present if at least one reviewer was trimmed
835
886
 
836
887
  ## Consensus Summary
837
888
 
838
- {synthesize common concerns across all reviewers. CodeRabbit is a diff-only reviewer (it never received the source-grounding prompt), so do not weight its verdict as a grounded plan review — fold in its diff findings, but base plan-level consensus on the prompt-fed reviewers.}
889
+ {synthesize common concerns across all reviewers. CodeRabbit is a diff-only reviewer (it never received the source-grounding prompt), so do not weight its verdict as a grounded plan review — fold in its diff findings, but base plan-level consensus on the prompt-fed reviewers. A reviewer output carrying the `[reviewed-without-repo-access]` marker (or beginning with `REVIEWED-WITHOUT-REPO-ACCESS`) ran without repo access (#2176) — treat it the same way: note its concerns, but do not count its verdict at full consensus weight.}
839
890
 
840
891
  ### Agreed Strengths
841
892
  {strengths mentioned by 2+ reviewers}
@@ -872,7 +923,11 @@ To incorporate feedback into planning:
872
923
  /gsd:plan-phase {N} --reviews
873
924
  ```
874
925
 
875
- Clean up temp files.
926
+ Clean up — remove the run's temp directory now that REVIEWS.md is committed:
927
+
928
+ ```bash
929
+ rm -rf "{run_dir}"
930
+ ```
876
931
  </step>
877
932
 
878
933
  </process>
@@ -76,7 +76,7 @@ Print: `◆ Spawning scanner... (runs in a subagent — no output until it retur
76
76
 
77
77
  ```
78
78
  Agent(
79
- prompt="Scan this codebase with focus: {focus}. Write results to .planning/codebase/. Produce only: {document_list}",
79
+ prompt="Scan this codebase with focus: {focus}. Write results to {codebase_dir}/. Produce only: {document_list}",
80
80
  subagent_type="gsd-codebase-mapper",
81
81
  model="{resolved_model}"
82
82
  )
@@ -17,11 +17,14 @@ Valid GSD subagent types (use exact names — do not fall back to 'general-purpo
17
17
 
18
18
  ```bash
19
19
  _GSD_SHIM_NAME="gsd-tools.cjs"; _GSD_RUNTIME_ROOT="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"; GSD_TOOLS="${_GSD_RUNTIME_ROOT}/gsd-core/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${_GSD_RUNTIME_ROOT}/.claude/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${_GSD_RUNTIME_ROOT}/.claude/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${_GSD_RUNTIME_ROOT}/.codex/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${_GSD_RUNTIME_ROOT}/.codex/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif command -v gsd-tools >/dev/null 2>&1; then GSD_TOOLS="$(command -v gsd-tools)"; gsd_run() { "$GSD_TOOLS" "$@"; }; elif [ -f "${CLAUDE_CONFIG_DIR:-$HOME/.claude}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${CLAUDE_CONFIG_DIR:-$HOME/.claude}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${HERMES_HOME:-$HOME/.hermes}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${HERMES_HOME:-$HOME/.hermes}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${CURSOR_CONFIG_DIR:-$HOME/.cursor}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${CURSOR_CONFIG_DIR:-$HOME/.cursor}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${CODEX_HOME:-$HOME/.codex}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${CODEX_HOME:-$HOME/.codex}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${GEMINI_CONFIG_DIR:-$HOME/.gemini}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${GEMINI_CONFIG_DIR:-$HOME/.gemini}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${COPILOT_CONFIG_DIR:-$HOME/.copilot}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${COPILOT_CONFIG_DIR:-$HOME/.copilot}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${WINDSURF_CONFIG_DIR:-$HOME/.codeium/windsurf}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${WINDSURF_CONFIG_DIR:-$HOME/.codeium/windsurf}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${AUGMENT_CONFIG_DIR:-$HOME/.augment}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${AUGMENT_CONFIG_DIR:-$HOME/.augment}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${TRAE_CONFIG_DIR:-$HOME/.trae}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${TRAE_CONFIG_DIR:-$HOME/.trae}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${QWEN_CONFIG_DIR:-$HOME/.qwen}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${QWEN_CONFIG_DIR:-$HOME/.qwen}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${CODEBUDDY_CONFIG_DIR:-$HOME/.codebuddy}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${CODEBUDDY_CONFIG_DIR:-$HOME/.codebuddy}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${CLINE_CONFIG_DIR:-$HOME/.cline}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${CLINE_CONFIG_DIR:-$HOME/.cline}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${GROK_AGENTS_HOME:-$HOME/.agents}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${GROK_AGENTS_HOME:-$HOME/.agents}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${ANTIGRAVITY_CONFIG_DIR:-$HOME/.gemini/antigravity}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${ANTIGRAVITY_CONFIG_DIR:-$HOME/.gemini/antigravity}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${KILO_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/kilo}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${KILO_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/kilo}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/gsd-core@latest --claude --local" >&2; exit 1; fi; if [ -n "${CLAUDE_ENV_FILE:-}" ] && [ -n "${GSD_TOOLS:-}" ]; then printf "export PATH='%s':\"\$PATH\"\n" "${GSD_TOOLS%/*}" >> "$CLAUDE_ENV_FILE" 2>/dev/null || true; fi
20
+ RESPONSE_LANGUAGE=$(gsd_run query config-get response_language --default "" 2>/dev/null || echo "")
20
21
  INIT=$(gsd_run query init.phase-op "${PHASE_ARG}")
21
22
  if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
22
23
  AGENT_SKILLS_AUDITOR=$(gsd_run query agent-skills gsd-security-auditor)
23
24
  ```
24
25
 
26
+ **If `response_language` is set:** All user-facing questions, prompts, and explanations in this workflow MUST be presented in `{response_language}`. Technical terms, code, file paths, and subagent prompts stay in English — only user-facing output is translated.
27
+
25
28
  Parse: `phase_dir`, `phase_number`, `phase_name`, `phase_slug`, `padded_phase`.
26
29
 
27
30
  ```bash
@@ -108,7 +111,7 @@ Agent(
108
111
  "<files_to_read>{PLAN, SUMMARY, impl files, SECURITY.md}</files_to_read>" +
109
112
  "<threat_register>{threat register}</threat_register>" +
110
113
  "<config>asvs_level: {SECURITY_ASVS}, block_on: {SECURITY_BLOCK_ON}</config>" +
111
- "<constraints>Never modify implementation files. Verify mitigations exist — do not scan for new threats. Escalate implementation gaps.</constraints>" +
114
+ "<constraints>Never modify implementation files. Verify mitigations exist — do not scan for new threats. Escalate implementation gaps. Return a structured verdict only — do NOT write SECURITY.md (the orchestrator owns the file write).</constraints>" +
112
115
  "${AGENT_SKILLS_AUDITOR}",
113
116
  subagent_type="gsd-security-auditor",
114
117
  model="{AUDITOR_MODEL}",
@@ -43,6 +43,7 @@ Ensure config exists and resolve the active config path (flat vs workstream, #22
43
43
 
44
44
  ```bash
45
45
  _GSD_SHIM_NAME="gsd-tools.cjs"; _GSD_RUNTIME_ROOT="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"; GSD_TOOLS="${_GSD_RUNTIME_ROOT}/gsd-core/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${_GSD_RUNTIME_ROOT}/.claude/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${_GSD_RUNTIME_ROOT}/.claude/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${_GSD_RUNTIME_ROOT}/.codex/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${_GSD_RUNTIME_ROOT}/.codex/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif command -v gsd-tools >/dev/null 2>&1; then GSD_TOOLS="$(command -v gsd-tools)"; gsd_run() { "$GSD_TOOLS" "$@"; }; elif [ -f "${CLAUDE_CONFIG_DIR:-$HOME/.claude}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${CLAUDE_CONFIG_DIR:-$HOME/.claude}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${HERMES_HOME:-$HOME/.hermes}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${HERMES_HOME:-$HOME/.hermes}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${CURSOR_CONFIG_DIR:-$HOME/.cursor}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${CURSOR_CONFIG_DIR:-$HOME/.cursor}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${CODEX_HOME:-$HOME/.codex}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${CODEX_HOME:-$HOME/.codex}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${GEMINI_CONFIG_DIR:-$HOME/.gemini}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${GEMINI_CONFIG_DIR:-$HOME/.gemini}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${COPILOT_CONFIG_DIR:-$HOME/.copilot}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${COPILOT_CONFIG_DIR:-$HOME/.copilot}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${WINDSURF_CONFIG_DIR:-$HOME/.codeium/windsurf}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${WINDSURF_CONFIG_DIR:-$HOME/.codeium/windsurf}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${AUGMENT_CONFIG_DIR:-$HOME/.augment}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${AUGMENT_CONFIG_DIR:-$HOME/.augment}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${TRAE_CONFIG_DIR:-$HOME/.trae}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${TRAE_CONFIG_DIR:-$HOME/.trae}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${QWEN_CONFIG_DIR:-$HOME/.qwen}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${QWEN_CONFIG_DIR:-$HOME/.qwen}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${CODEBUDDY_CONFIG_DIR:-$HOME/.codebuddy}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${CODEBUDDY_CONFIG_DIR:-$HOME/.codebuddy}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${CLINE_CONFIG_DIR:-$HOME/.cline}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${CLINE_CONFIG_DIR:-$HOME/.cline}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${GROK_AGENTS_HOME:-$HOME/.agents}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${GROK_AGENTS_HOME:-$HOME/.agents}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${ANTIGRAVITY_CONFIG_DIR:-$HOME/.gemini/antigravity}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${ANTIGRAVITY_CONFIG_DIR:-$HOME/.gemini/antigravity}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${KILO_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/kilo}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${KILO_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/kilo}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/gsd-core@latest --claude --local" >&2; exit 1; fi; if [ -n "${CLAUDE_ENV_FILE:-}" ] && [ -n "${GSD_TOOLS:-}" ]; then printf "export PATH='%s':\"\$PATH\"\n" "${GSD_TOOLS%/*}" >> "$CLAUDE_ENV_FILE" 2>/dev/null || true; fi
46
+ RESPONSE_LANGUAGE=$(gsd_run query config-get response_language --default "" 2>/dev/null || echo "")
46
47
  gsd_run query config-ensure-section
47
48
  if [[ -z "${GSD_CONFIG_PATH:-}" ]]; then
48
49
  if [[ -f .planning/active-workstream ]]; then
@@ -54,6 +55,8 @@ if [[ -z "${GSD_CONFIG_PATH:-}" ]]; then
54
55
  fi
55
56
  ```
56
57
 
58
+ **If `response_language` is set:** All user-facing questions, prompts, and explanations in this workflow MUST be presented in `{response_language}`. Technical terms, code, file paths, and subagent prompts stay in English — only user-facing output is translated.
59
+
57
60
  Store `$GSD_CONFIG_PATH`. Every subsequent read/write uses it.
58
61
  </step>
59
62
 
@@ -13,6 +13,7 @@ Ensure config exists and load current state:
13
13
 
14
14
  ```bash
15
15
  _GSD_SHIM_NAME="gsd-tools.cjs"; _GSD_RUNTIME_ROOT="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"; GSD_TOOLS="${_GSD_RUNTIME_ROOT}/gsd-core/bin/${_GSD_SHIM_NAME}"; if [ -f "$GSD_TOOLS" ]; then gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${_GSD_RUNTIME_ROOT}/.claude/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${_GSD_RUNTIME_ROOT}/.claude/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${_GSD_RUNTIME_ROOT}/.codex/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${_GSD_RUNTIME_ROOT}/.codex/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif command -v gsd-tools >/dev/null 2>&1; then GSD_TOOLS="$(command -v gsd-tools)"; gsd_run() { "$GSD_TOOLS" "$@"; }; elif [ -f "${CLAUDE_CONFIG_DIR:-$HOME/.claude}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${CLAUDE_CONFIG_DIR:-$HOME/.claude}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${HERMES_HOME:-$HOME/.hermes}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${HERMES_HOME:-$HOME/.hermes}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${CURSOR_CONFIG_DIR:-$HOME/.cursor}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${CURSOR_CONFIG_DIR:-$HOME/.cursor}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${CODEX_HOME:-$HOME/.codex}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${CODEX_HOME:-$HOME/.codex}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${GEMINI_CONFIG_DIR:-$HOME/.gemini}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${GEMINI_CONFIG_DIR:-$HOME/.gemini}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${COPILOT_CONFIG_DIR:-$HOME/.copilot}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${COPILOT_CONFIG_DIR:-$HOME/.copilot}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${WINDSURF_CONFIG_DIR:-$HOME/.codeium/windsurf}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${WINDSURF_CONFIG_DIR:-$HOME/.codeium/windsurf}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${AUGMENT_CONFIG_DIR:-$HOME/.augment}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${AUGMENT_CONFIG_DIR:-$HOME/.augment}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${TRAE_CONFIG_DIR:-$HOME/.trae}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${TRAE_CONFIG_DIR:-$HOME/.trae}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${QWEN_CONFIG_DIR:-$HOME/.qwen}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${QWEN_CONFIG_DIR:-$HOME/.qwen}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${CODEBUDDY_CONFIG_DIR:-$HOME/.codebuddy}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${CODEBUDDY_CONFIG_DIR:-$HOME/.codebuddy}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${CLINE_CONFIG_DIR:-$HOME/.cline}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${CLINE_CONFIG_DIR:-$HOME/.cline}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${GROK_AGENTS_HOME:-$HOME/.agents}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${GROK_AGENTS_HOME:-$HOME/.agents}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${ANTIGRAVITY_CONFIG_DIR:-$HOME/.gemini/antigravity}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${ANTIGRAVITY_CONFIG_DIR:-$HOME/.gemini/antigravity}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; elif [ -f "${KILO_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/kilo}/gsd-core/bin/${_GSD_SHIM_NAME}" ]; then GSD_TOOLS="${KILO_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/kilo}/gsd-core/bin/${_GSD_SHIM_NAME}"; gsd_run() { node "$GSD_TOOLS" "$@"; }; else echo "ERROR: gsd-tools.cjs not found at $GSD_TOOLS and gsd-tools is not on PATH. Run: npx -y @opengsd/gsd-core@latest --claude --local" >&2; exit 1; fi; if [ -n "${CLAUDE_ENV_FILE:-}" ] && [ -n "${GSD_TOOLS:-}" ]; then printf "export PATH='%s':\"\$PATH\"\n" "${GSD_TOOLS%/*}" >> "$CLAUDE_ENV_FILE" 2>/dev/null || true; fi
16
+ RESPONSE_LANGUAGE=$(gsd_run query config-get response_language --default "" 2>/dev/null || echo "")
16
17
  gsd_run query config-ensure-section
17
18
  INIT=$(gsd_run query state.load)
18
19
  if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
@@ -27,6 +28,8 @@ if [[ -z "${GSD_CONFIG_PATH:-}" ]]; then
27
28
  fi
28
29
  ```
29
30
 
31
+ **If `response_language` is set:** All user-facing questions, prompts, and explanations in this workflow MUST be presented in `{response_language}`. Technical terms, code, file paths, and subagent prompts stay in English — only user-facing output is translated.
32
+
30
33
  Creates `config.json` (at the resolved path) with defaults if missing. `INIT` still holds `state.load` output for any step that needs STATE fields.
31
34
  Store `$GSD_CONFIG_PATH` — all subsequent reads and writes use this path, not a hardcoded `.planning/config.json`, so active-workstream installs target the correct file (#2282).
32
35
  </step>