@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.
- package/README.ja-JP.md +6 -5
- package/README.ko-KR.md +6 -5
- package/README.md +10 -45
- package/README.pt-BR.md +5 -4
- package/README.zh-CN.md +6 -5
- package/agents/gsd-ai-researcher.md +1 -1
- package/agents/gsd-debug-session-manager.md +1 -1
- package/agents/gsd-doc-writer.md +7 -6
- package/agents/gsd-domain-researcher.md +1 -1
- package/agents/gsd-eval-planner.md +1 -1
- package/agents/gsd-phase-researcher.md +1 -1
- package/agents/gsd-ui-researcher.md +1 -1
- package/agents/gsd-verifier.md +1 -1
- package/assets/gsd-logo-2000-transparent.png +0 -0
- package/assets/gsd-logo-2000-transparent.svg +17 -0
- package/assets/gsd-logo-2000.png +0 -0
- package/assets/gsd-logo-2000.svg +21 -0
- package/assets/terminal.svg +68 -0
- package/bin/install.js +86 -44
- package/commands/gsd/review.md +2 -1
- package/get-shit-done/bin/gsd-tools.cjs +37 -1
- package/get-shit-done/bin/lib/command-aliases.cjs +16 -0
- package/get-shit-done/bin/lib/commands.cjs +109 -5
- package/get-shit-done/bin/lib/config-types.cjs +19 -0
- package/get-shit-done/bin/lib/core.cjs +455 -63
- package/get-shit-done/bin/lib/gap-checker.cjs +56 -7
- package/get-shit-done/bin/lib/installer-migration-report.cjs +1 -0
- package/get-shit-done/bin/lib/milestone.cjs +59 -1
- package/get-shit-done/bin/lib/model-catalog.cjs +17 -0
- package/get-shit-done/bin/lib/phase-lifecycle.cjs +0 -1
- package/get-shit-done/bin/lib/review-reviewer-selection.cjs +1 -0
- package/get-shit-done/bin/lib/roadmap-command-router.cjs +134 -0
- package/get-shit-done/bin/lib/roadmap-upgrade.cjs +569 -0
- package/get-shit-done/bin/lib/roadmap.cjs +6 -5
- package/get-shit-done/bin/lib/semver-compare.cjs +34 -27
- package/get-shit-done/bin/lib/shell-command-projection.cjs +35 -0
- package/get-shit-done/bin/lib/state-document.cjs +0 -4
- package/get-shit-done/bin/lib/state.cjs +41 -6
- package/get-shit-done/bin/lib/ui-safety-gate.cjs +111 -0
- package/get-shit-done/bin/lib/validate.cjs +43 -17
- package/get-shit-done/bin/lib/verify.cjs +107 -4
- package/get-shit-done/bin/shared/config-defaults.manifest.json +1 -0
- package/get-shit-done/bin/shared/config-schema.manifest.json +12 -1
- package/get-shit-done/bin/shared/model-catalog.json +27 -0
- package/get-shit-done/references/checkpoints.md +1 -1
- package/get-shit-done/references/planner-human-verify-mode.md +1 -1
- package/get-shit-done/references/ui-brand.md +4 -2
- package/get-shit-done/workflows/audit-fix.md +1 -1
- package/get-shit-done/workflows/audit-milestone.md +2 -0
- package/get-shit-done/workflows/autonomous.md +7 -5
- package/get-shit-done/workflows/cleanup.md +43 -3
- package/get-shit-done/workflows/code-review-fix.md +3 -3
- package/get-shit-done/workflows/code-review.md +2 -0
- package/get-shit-done/workflows/debug.md +6 -1
- package/get-shit-done/workflows/diagnose-issues.md +2 -0
- package/get-shit-done/workflows/discuss-phase/modes/advisor.md +1 -1
- package/get-shit-done/workflows/discuss-phase-assumptions.md +2 -2
- package/get-shit-done/workflows/docs-update.md +18 -4
- package/get-shit-done/workflows/eval-review.md +1 -1
- package/get-shit-done/workflows/execute-phase/steps/codebase-drift-gate.md +1 -1
- package/get-shit-done/workflows/execute-phase.md +21 -11
- package/get-shit-done/workflows/execute-plan.md +1 -1
- package/get-shit-done/workflows/explore.md +2 -0
- package/get-shit-done/workflows/help/modes/default.md +3 -3
- package/get-shit-done/workflows/help/modes/full.md +5 -5
- package/get-shit-done/workflows/import.md +2 -0
- package/get-shit-done/workflows/ingest-docs.md +2 -2
- package/get-shit-done/workflows/manager.md +2 -2
- package/get-shit-done/workflows/map-codebase.md +2 -0
- package/get-shit-done/workflows/new-milestone.md +2 -2
- package/get-shit-done/workflows/new-project.md +2 -2
- package/get-shit-done/workflows/plan-phase.md +16 -15
- package/get-shit-done/workflows/plan-review-convergence.md +3 -3
- package/get-shit-done/workflows/quick.md +5 -3
- package/get-shit-done/workflows/review.md +109 -1
- package/get-shit-done/workflows/scan.md +2 -0
- package/get-shit-done/workflows/secure-phase.md +2 -0
- package/get-shit-done/workflows/settings-advanced.md +195 -5
- package/get-shit-done/workflows/settings.md +15 -1
- package/get-shit-done/workflows/ui-phase.md +2 -2
- package/get-shit-done/workflows/ui-review.md +1 -1
- package/get-shit-done/workflows/validate-phase.md +2 -0
- package/get-shit-done/workflows/verify-work.md +2 -2
- package/hooks/dist/gsd-worktree-path-guard.js +169 -0
- package/hooks/gsd-worktree-path-guard.js +169 -0
- package/hooks/managed-hooks-registry.cjs +1 -0
- package/package.json +9 -6
- package/scripts/build-hooks.js +1 -0
- package/scripts/ci-test-scope.cjs +10 -0
- package/scripts/run-tests.cjs +25 -1
- package/scripts/lint-shared-module-handsync.cjs +0 -388
- package/scripts/shared-module-handsync-allowlist.json +0 -183
|
@@ -98,7 +98,7 @@ Display startup banner:
|
|
|
98
98
|
|
|
99
99
|
**If `has_plans` is false:**
|
|
100
100
|
|
|
101
|
-
Display: `◆ No plans found — spawning initial planning agent
|
|
101
|
+
Display: `◆ No plans found — spawning initial planning agent... (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze)`
|
|
102
102
|
|
|
103
103
|
```text
|
|
104
104
|
Agent(
|
|
@@ -134,7 +134,7 @@ prev_high_count = Infinity
|
|
|
134
134
|
|
|
135
135
|
Increment `cycle`.
|
|
136
136
|
|
|
137
|
-
Display: `◆ Cycle {cycle}/{MAX_CYCLES} — spawning review agent
|
|
137
|
+
Display: `◆ Cycle {cycle}/{MAX_CYCLES} — spawning review agent... (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze)`
|
|
138
138
|
|
|
139
139
|
```text
|
|
140
140
|
Agent(
|
|
@@ -308,7 +308,7 @@ Exit workflow.
|
|
|
308
308
|
|
|
309
309
|
Update `prev_high_count = HIGH_COUNT`.
|
|
310
310
|
|
|
311
|
-
Display: `◆ Spawning replan agent with review feedback
|
|
311
|
+
Display: `◆ Spawning replan agent with review feedback... (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze)`
|
|
312
312
|
|
|
313
313
|
```text
|
|
314
314
|
Agent(
|
|
@@ -392,7 +392,7 @@ Display banner:
|
|
|
392
392
|
GSD ► RESEARCHING QUICK TASK
|
|
393
393
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
394
394
|
|
|
395
|
-
◆ Investigating approaches for: ${DESCRIPTION}
|
|
395
|
+
◆ Investigating approaches for: ${DESCRIPTION} (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze)
|
|
396
396
|
```
|
|
397
397
|
|
|
398
398
|
Spawn a single focused researcher (not 4 parallel researchers like full phases — quick tasks need targeted research, not broad domain surveys):
|
|
@@ -455,6 +455,8 @@ If research file not found, warn but continue: "Research agent did not produce o
|
|
|
455
455
|
|
|
456
456
|
**If NOT `$VALIDATE_MODE`:** Use standard `quick` mode.
|
|
457
457
|
|
|
458
|
+
Display: `◆ Spawning planner... (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze)`
|
|
459
|
+
|
|
458
460
|
```
|
|
459
461
|
Agent(
|
|
460
462
|
prompt="
|
|
@@ -518,7 +520,7 @@ Display banner:
|
|
|
518
520
|
GSD ► CHECKING PLAN
|
|
519
521
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
520
522
|
|
|
521
|
-
◆ Spawning plan checker...
|
|
523
|
+
◆ Spawning plan checker... (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze)
|
|
522
524
|
```
|
|
523
525
|
|
|
524
526
|
Checker prompt:
|
|
@@ -855,7 +857,7 @@ Display banner:
|
|
|
855
857
|
GSD ► VERIFYING RESULTS
|
|
856
858
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
857
859
|
|
|
858
|
-
◆ Spawning verifier...
|
|
860
|
+
◆ Spawning verifier... (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze)
|
|
859
861
|
```
|
|
860
862
|
|
|
861
863
|
```
|
|
@@ -23,6 +23,7 @@ command -v coderabbit >/dev/null 2>&1 && echo "coderabbit:available" || echo "co
|
|
|
23
23
|
command -v opencode >/dev/null 2>&1 && echo "opencode:available" || echo "opencode:missing"
|
|
24
24
|
command -v qwen >/dev/null 2>&1 && echo "qwen:available" || echo "qwen:missing"
|
|
25
25
|
command -v cursor >/dev/null 2>&1 && echo "cursor:available" || echo "cursor:missing"
|
|
26
|
+
command -v agy >/dev/null 2>&1 && echo "antigravity:available" || echo "antigravity:missing"
|
|
26
27
|
|
|
27
28
|
# Check local model servers (OpenAI-compatible HTTP API — no CLI binary required)
|
|
28
29
|
OLLAMA_HOST=$(gsd_run query config-get review.ollama_host 2>/dev/null | jq -r '.' 2>/dev/null || echo "")
|
|
@@ -46,6 +47,7 @@ Parse flags from `$ARGUMENTS`:
|
|
|
46
47
|
- `--opencode` → include OpenCode
|
|
47
48
|
- `--qwen` → include Qwen Code
|
|
48
49
|
- `--cursor` → include Cursor
|
|
50
|
+
- `--agy` or `--antigravity` → include Antigravity CLI
|
|
49
51
|
- `--ollama` → include Ollama (local server, OpenAI-compatible)
|
|
50
52
|
- `--lm-studio` → include LM Studio (local server, OpenAI-compatible)
|
|
51
53
|
- `--llama-cpp` → include llama.cpp (local server, OpenAI-compatible)
|
|
@@ -73,6 +75,7 @@ No external AI CLIs found. Install at least one:
|
|
|
73
75
|
- opencode: https://opencode.ai (leverages GitHub Copilot subscription models)
|
|
74
76
|
- qwen: https://github.com/nicepkg/qwen-code (Alibaba Qwen models)
|
|
75
77
|
- cursor: https://cursor.com (Cursor IDE agent mode)
|
|
78
|
+
- agy: curl -fsSL https://antigravity.google/cli/install.sh | bash (Antigravity CLI — free with Google credentials)
|
|
76
79
|
|
|
77
80
|
Then run /gsd:review again.
|
|
78
81
|
```
|
|
@@ -218,6 +221,8 @@ GEMINI_MODEL=$(gsd_run query config-get review.models.gemini 2>/dev/null | jq -r
|
|
|
218
221
|
CLAUDE_MODEL=$(gsd_run query config-get review.models.claude 2>/dev/null | jq -r '.' 2>/dev/null || true)
|
|
219
222
|
CODEX_MODEL=$(gsd_run query config-get review.models.codex 2>/dev/null | jq -r '.' 2>/dev/null || true)
|
|
220
223
|
OPENCODE_MODEL=$(gsd_run query config-get review.models.opencode 2>/dev/null | jq -r '.' 2>/dev/null || true)
|
|
224
|
+
# review.models.agy is reserved for future model-pinning support; agy selects its model internally
|
|
225
|
+
AGY_MODEL=$(gsd_run query config-get review.models.agy 2>/dev/null | jq -r '.' 2>/dev/null || true)
|
|
221
226
|
```
|
|
222
227
|
|
|
223
228
|
For each selected CLI, invoke in sequence (not parallel — avoid rate limits):
|
|
@@ -285,6 +290,103 @@ if [ ! -s /tmp/gsd-review-cursor-{phase}.md ]; then
|
|
|
285
290
|
fi
|
|
286
291
|
```
|
|
287
292
|
|
|
293
|
+
**Antigravity CLI:**
|
|
294
|
+
|
|
295
|
+
**Maintainer note — why this block has three layers (last updated against agy 1.0.2):**
|
|
296
|
+
|
|
297
|
+
`agy -p` (the `--print` non-interactive flag) works correctly on macOS and Linux: it sends the
|
|
298
|
+
prompt, receives the model response, and writes it to stdout. On **native Windows** it silently
|
|
299
|
+
produces no stdout output despite the API call succeeding — a bug in `text_drip.go`'s non-TTY
|
|
300
|
+
flush path, tracked at https://github.com/google-antigravity/antigravity-cli/issues/27466 and
|
|
301
|
+
still open as of agy 1.0.2.
|
|
302
|
+
|
|
303
|
+
Regardless of platform, `agy` always persists the full exchange to a transcript file on disk.
|
|
304
|
+
The transcript fallback (Step 2 below) reads that file directly, giving Windows users full review
|
|
305
|
+
coverage without any extra tooling. This pattern was first documented by the community MCP bridge
|
|
306
|
+
at https://github.com/SinanTufekci/Claude-Code-Antigravity-CLI-MCP-Server — we inline the same
|
|
307
|
+
logic here in pure bash/jq so no additional dependency is required.
|
|
308
|
+
|
|
309
|
+
**Stale-response guard (why the pre-flight watermark matters):**
|
|
310
|
+
Without a watermark, the fallback would read the last `PLANNER_RESPONSE` entry in the transcript
|
|
311
|
+
regardless of when it was written — including entries from a previous invocation in the same
|
|
312
|
+
workspace. To prevent that, we record the transcript's line count *before* calling `agy -p`. In
|
|
313
|
+
the fallback, we only read lines appended after that count. If no new lines were written (agy
|
|
314
|
+
failed before producing a response), `_AGY_RESULT` is empty and Step 3 fires — never stale. If
|
|
315
|
+
the conv-id changed (agy started a fresh session), all lines in the new file are new and we use
|
|
316
|
+
skip=0.
|
|
317
|
+
|
|
318
|
+
**If the upstream stdout bug is fixed** (check the issue above): Step 2 silently becomes
|
|
319
|
+
unreachable; stdout is non-empty and Step 1 handles it. No code change needed.
|
|
320
|
+
|
|
321
|
+
**If the transcript paths change** in a future `agy` release: Step 2 silently becomes a no-op
|
|
322
|
+
and Step 3 fires with a clear error message in REVIEWS.md. No silent corruption. To debug:
|
|
323
|
+
- `~/.gemini/antigravity-cli/cache/last_conversations.json` — workspace → conv-id map
|
|
324
|
+
- `~/.gemini/antigravity-cli/brain/<id>/.system_generated/logs/transcript.jsonl`
|
|
325
|
+
Filter: `source=="MODEL"`, `status=="DONE"`, `type=="PLANNER_RESPONSE"`, take the last match's `content` field.
|
|
326
|
+
|
|
327
|
+
Invocation specifics (verified agy 1.0.0, macOS arm64 and Linux amd64):
|
|
328
|
+
- `-p` takes the prompt as a **flag value** — `echo X | agy -p` errors with "flag needs an argument: -p"
|
|
329
|
+
- `--print-timeout` defaults to 5m, aligning with this workflow's global timeout
|
|
330
|
+
- No `-m` / `--model` flag — agy selects the model internally
|
|
331
|
+
|
|
332
|
+
```bash
|
|
333
|
+
# Pre-flight: snapshot the transcript watermark before invoking agy.
|
|
334
|
+
# Must run BEFORE agy -p — this is what prevents the fallback from reading a stale prior response.
|
|
335
|
+
_AGY_WS=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
|
|
336
|
+
_AGY_CACHE="$HOME/.gemini/antigravity-cli/cache/last_conversations.json"
|
|
337
|
+
_AGY_MARK_CONV=""
|
|
338
|
+
_AGY_MARK_LINES=0
|
|
339
|
+
if [ -f "$_AGY_CACHE" ]; then
|
|
340
|
+
_AGY_MARK_CONV=$(jq -r --arg ws "$_AGY_WS" '
|
|
341
|
+
.[$ws] //
|
|
342
|
+
(to_entries
|
|
343
|
+
| map(select(.key | ascii_downcase == ($ws | ascii_downcase)))
|
|
344
|
+
| first | .value) //
|
|
345
|
+
empty
|
|
346
|
+
' "$_AGY_CACHE" 2>/dev/null)
|
|
347
|
+
if [ -n "$_AGY_MARK_CONV" ] && [ "$_AGY_MARK_CONV" != "null" ]; then
|
|
348
|
+
_AGY_MARK_TX="$HOME/.gemini/antigravity-cli/brain/${_AGY_MARK_CONV}/.system_generated/logs/transcript.jsonl"
|
|
349
|
+
[ -f "$_AGY_MARK_TX" ] && _AGY_MARK_LINES=$(wc -l < "$_AGY_MARK_TX" | tr -d ' ')
|
|
350
|
+
fi
|
|
351
|
+
fi
|
|
352
|
+
|
|
353
|
+
# Step 1 — primary invocation: stdout works on macOS, Linux, and WSL
|
|
354
|
+
agy -p "$(cat /tmp/gsd-review-prompt-{phase}.md)" 2>/dev/null > /tmp/gsd-review-antigravity-{phase}.md
|
|
355
|
+
|
|
356
|
+
# Step 2 — transcript fallback: catches Windows agy -p stdout bug (and any future stdout-silent edge cases).
|
|
357
|
+
# Reads only lines appended AFTER the pre-flight watermark. If agy failed before writing a new response,
|
|
358
|
+
# _AGY_RESULT is empty and Step 3 fires — no stale content can leak through.
|
|
359
|
+
# Undocumented paths, verified agy 1.0.0–1.0.2. See maintainer note above if these break.
|
|
360
|
+
if [ ! -s /tmp/gsd-review-antigravity-{phase}.md ]; then
|
|
361
|
+
if [ -f "$_AGY_CACHE" ]; then
|
|
362
|
+
_AGY_CONV=$(jq -r --arg ws "$_AGY_WS" '
|
|
363
|
+
.[$ws] //
|
|
364
|
+
(to_entries
|
|
365
|
+
| map(select(.key | ascii_downcase == ($ws | ascii_downcase)))
|
|
366
|
+
| first | .value) //
|
|
367
|
+
empty
|
|
368
|
+
' "$_AGY_CACHE" 2>/dev/null)
|
|
369
|
+
if [ -n "$_AGY_CONV" ] && [ "$_AGY_CONV" != "null" ]; then
|
|
370
|
+
_AGY_TX="$HOME/.gemini/antigravity-cli/brain/${_AGY_CONV}/.system_generated/logs/transcript.jsonl"
|
|
371
|
+
if [ -f "$_AGY_TX" ]; then
|
|
372
|
+
# If conv-id changed, agy started a new session — all lines are new, skip 0.
|
|
373
|
+
# If same conv-id, only read lines beyond the watermark.
|
|
374
|
+
[ "$_AGY_CONV" = "$_AGY_MARK_CONV" ] && _AGY_SKIP=$_AGY_MARK_LINES || _AGY_SKIP=0
|
|
375
|
+
_AGY_RESULT=$(tail -n +"$((_AGY_SKIP + 1))" "$_AGY_TX" 2>/dev/null | \
|
|
376
|
+
jq -r 'select(.source=="MODEL" and .status=="DONE" and .type=="PLANNER_RESPONSE") | .content' \
|
|
377
|
+
2>/dev/null | tail -1)
|
|
378
|
+
[ -n "$_AGY_RESULT" ] && echo "$_AGY_RESULT" > /tmp/gsd-review-antigravity-{phase}.md
|
|
379
|
+
fi
|
|
380
|
+
fi
|
|
381
|
+
fi
|
|
382
|
+
fi
|
|
383
|
+
|
|
384
|
+
# Step 3 — final guard: both approaches yielded nothing (auth error, first-run setup, path schema changed, etc.)
|
|
385
|
+
if [ ! -s /tmp/gsd-review-antigravity-{phase}.md ]; then
|
|
386
|
+
echo "Antigravity review failed or returned empty output." > /tmp/gsd-review-antigravity-{phase}.md
|
|
387
|
+
fi
|
|
388
|
+
```
|
|
389
|
+
|
|
288
390
|
**Ollama (local, OpenAI-compatible):**
|
|
289
391
|
|
|
290
392
|
Read host and model from config. All three local backends share the same `/v1/chat/completions` endpoint — only host and model differ. Use `jq --rawfile` to safely encode the multi-line prompt as JSON without shell-escaping issues.
|
|
@@ -493,7 +595,7 @@ After all reviewers complete, collect trim metadata files written during the run
|
|
|
493
595
|
```markdown
|
|
494
596
|
---
|
|
495
597
|
phase: {N}
|
|
496
|
-
reviewers: [gemini, claude, codex, coderabbit, opencode, qwen, cursor, ollama, lm_studio, llama_cpp] # populate at runtime with only the reviewers actually invoked
|
|
598
|
+
reviewers: [gemini, claude, codex, coderabbit, opencode, qwen, cursor, antigravity, ollama, lm_studio, llama_cpp] # populate at runtime with only the reviewers actually invoked
|
|
497
599
|
reviewed_at: {ISO timestamp}
|
|
498
600
|
plans_reviewed: [{list of PLAN.md files}]
|
|
499
601
|
trimmed_reviewers: # only present if at least one reviewer was trimmed
|
|
@@ -552,6 +654,12 @@ trimmed_reviewers: # only present if at least one reviewer was trimmed
|
|
|
552
654
|
|
|
553
655
|
---
|
|
554
656
|
|
|
657
|
+
## Antigravity Review
|
|
658
|
+
|
|
659
|
+
{antigravity review content}
|
|
660
|
+
|
|
661
|
+
---
|
|
662
|
+
|
|
555
663
|
## Ollama Review
|
|
556
664
|
|
|
557
665
|
{ollama review content}
|
|
@@ -72,6 +72,8 @@ mkdir -p .planning/codebase
|
|
|
72
72
|
|
|
73
73
|
Spawn a single `gsd-codebase-mapper` agent with the selected focus area:
|
|
74
74
|
|
|
75
|
+
Print: `◆ Spawning scanner... (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze)`
|
|
76
|
+
|
|
75
77
|
```
|
|
76
78
|
Agent(
|
|
77
79
|
prompt="Scan this codebase with focus: {focus}. Write results to .planning/codebase/. Produce only: {document_list}",
|
|
@@ -93,6 +93,8 @@ Call AskUserQuestion with threat table and options:
|
|
|
93
93
|
- `register_authored_at_plan_time: true` — **Verify mitigations exist** — do not scan for new threats. The register is complete; verify each threat's mitigation is present in the implementation.
|
|
94
94
|
- `register_authored_at_plan_time: false` (retroactive-STRIDE mode) — **Retroactive-STRIDE: build a STRIDE register from implementation files first, then verify mitigations.** The phase was authored before formal threat modelling; the auditor must construct the register from scratch before verifying.
|
|
95
95
|
|
|
96
|
+
Print: `◆ Spawning security auditor... (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze)`
|
|
97
|
+
|
|
96
98
|
```
|
|
97
99
|
Agent(
|
|
98
100
|
prompt="Read ~/.claude/agents/gsd-security-auditor.md for instructions.\n\n" +
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
<purpose>
|
|
2
2
|
Interactive configuration of GSD power-user knobs — plan bounce, node repair, subagent timeouts,
|
|
3
3
|
inline plan threshold, cross-AI execution, base branch, branch templates, response language,
|
|
4
|
-
context window, gitignored search, graphify build timeout,
|
|
4
|
+
context window, gitignored search, graphify build timeout, runtime model tier overrides, and
|
|
5
|
+
model policy configuration (provider + budget → canonical tier mapping, or manual model ID
|
|
6
|
+
assignment per cost tier).
|
|
5
7
|
|
|
6
8
|
This is a companion to `/gsd:settings` — the common-case prompt there covers model profile,
|
|
7
9
|
research/plan_check/verifier toggles, branching strategy, UI/AI phase gates, and worktree
|
|
8
10
|
isolation. This advanced command covers everything else that is user-settable, grouped into
|
|
9
|
-
|
|
11
|
+
eight sections so each prompt batch stays cognitively scoped. Every answer pre-selects the
|
|
10
12
|
current value; numeric-input answers that are non-numeric are rejected and re-prompted.
|
|
11
13
|
</purpose>
|
|
12
14
|
|
|
@@ -81,6 +83,13 @@ Runtime Model Tiers:
|
|
|
81
83
|
- `model_profile_overrides.<runtime>.sonnet` (default: built-in for the runtime, or absent)
|
|
82
84
|
- `model_profile_overrides.<runtime>.haiku` (default: built-in for the runtime, or absent)
|
|
83
85
|
|
|
86
|
+
Model Policy:
|
|
87
|
+
- `model_policy.provider` (default: `null` — known values: anthropic, openai, google, qwen)
|
|
88
|
+
- `model_policy.budget` (default: `null` — known values: high, medium, low)
|
|
89
|
+
- `model_policy.high` (default: `null` — model ID for the high-cost tier; used by generic provider path)
|
|
90
|
+
- `model_policy.medium` (default: `null` — model ID for the medium-cost tier; used by generic provider path)
|
|
91
|
+
- `model_policy.low` (default: `null` — model ID for the low-cost tier; used by generic provider path)
|
|
92
|
+
|
|
84
93
|
Each field's **current value is pre-selected** in the prompt rendering below. When the
|
|
85
94
|
current value is absent from the config, render the documented default as the pre-selected
|
|
86
95
|
option so the user sees what the effective value is.
|
|
@@ -500,7 +509,7 @@ gsd_run query config-set model_profile_overrides.gemini.haiku null
|
|
|
500
509
|
|
|
501
510
|
Conceptual shape after merge (unchanged top-level keys like `model_profile`,
|
|
502
511
|
`granularity`, `mode`, `brave_search`, `agent_skills.*`, `hooks.context_warnings`, and
|
|
503
|
-
anything not listed in Sections 1–
|
|
512
|
+
anything not listed in Sections 1–8 MUST survive the update):
|
|
504
513
|
|
|
505
514
|
```json
|
|
506
515
|
{
|
|
@@ -542,6 +551,14 @@ anything not listed in Sections 1–7 MUST survive the update):
|
|
|
542
551
|
"sonnet": <new|existing|null>,
|
|
543
552
|
"haiku": <new|existing|null>
|
|
544
553
|
}
|
|
554
|
+
},
|
|
555
|
+
"model_policy": {
|
|
556
|
+
...existing_model_policy,
|
|
557
|
+
"provider": <new|existing|null>,
|
|
558
|
+
"budget": <new|existing|null>,
|
|
559
|
+
"high": <new|existing|null>,
|
|
560
|
+
"medium": <new|existing|null>,
|
|
561
|
+
"low": <new|existing|null>
|
|
545
562
|
}
|
|
546
563
|
}
|
|
547
564
|
```
|
|
@@ -551,6 +568,170 @@ route each write through `gsd-tools.cjs query config-set` so sibling preservatio
|
|
|
551
568
|
the central setter.
|
|
552
569
|
</step>
|
|
553
570
|
|
|
571
|
+
### Section 8 — Model Policy
|
|
572
|
+
|
|
573
|
+
This section configures the `model_policy` key in `.planning/config.json`. Model policy
|
|
574
|
+
defines which AI models GSD uses at each cost tier (low / medium / high), independently
|
|
575
|
+
of the `runtime` and `model_profile` selections above. Two paths are offered:
|
|
576
|
+
|
|
577
|
+
- **Known provider:** choose a provider and a budget level; GSD materializes the canonical
|
|
578
|
+
tier mapping for that provider.
|
|
579
|
+
- **Generic provider:** enter low / medium / high model IDs manually.
|
|
580
|
+
|
|
581
|
+
**Step A — Read and display the current model policy:**
|
|
582
|
+
|
|
583
|
+
```bash
|
|
584
|
+
cat "$GSD_CONFIG_PATH" | python3 -c "import sys,json; c=json.load(sys.stdin); mp=c.get('model_policy',{}); print(json.dumps(mp,indent=2))" 2>/dev/null || echo "{}"
|
|
585
|
+
```
|
|
586
|
+
|
|
587
|
+
Display the current values (or "(unset)" for any absent field) before asking:
|
|
588
|
+
|
|
589
|
+
```text
|
|
590
|
+
Current model_policy:
|
|
591
|
+
provider : <value or "(unset)">
|
|
592
|
+
budget : <value or "(unset)">
|
|
593
|
+
low : <value or "(unset)">
|
|
594
|
+
medium : <value or "(unset)">
|
|
595
|
+
high : <value or "(unset)">
|
|
596
|
+
```
|
|
597
|
+
|
|
598
|
+
**Step B — Choose configuration path:**
|
|
599
|
+
|
|
600
|
+
```text
|
|
601
|
+
AskUserQuestion([
|
|
602
|
+
{
|
|
603
|
+
question: "How do you want to configure the model policy?",
|
|
604
|
+
header: "Model Policy",
|
|
605
|
+
multiSelect: false,
|
|
606
|
+
options: [
|
|
607
|
+
{ label: "Known provider", description: "Choose a provider (Claude / OpenAI / Gemini / Qwen) and a budget level — GSD writes the canonical tier mapping automatically." },
|
|
608
|
+
{ label: "Generic provider", description: "Enter low / medium / high model IDs manually for any provider or custom deployment." },
|
|
609
|
+
{ label: "Keep current", description: "Leave model_policy unchanged." }
|
|
610
|
+
]
|
|
611
|
+
}
|
|
612
|
+
])
|
|
613
|
+
```
|
|
614
|
+
|
|
615
|
+
**If "Keep current" is selected:** skip Steps C–E and move on to the confirm step.
|
|
616
|
+
|
|
617
|
+
**Step C — Known-provider path:**
|
|
618
|
+
|
|
619
|
+
```text
|
|
620
|
+
AskUserQuestion([
|
|
621
|
+
{
|
|
622
|
+
question: "Which provider?",
|
|
623
|
+
header: "Provider",
|
|
624
|
+
multiSelect: false,
|
|
625
|
+
options: [
|
|
626
|
+
{ label: "anthropic", description: "claude-opus-4-8 / claude-sonnet-4-6 / claude-haiku-4-5 (Anthropic / Claude)" },
|
|
627
|
+
{ label: "openai", description: "gpt-5.5 / gpt-5.3-codex / gpt-5.4-mini (OpenAI / Codex)" },
|
|
628
|
+
{ label: "google", description: "gemini-3-pro / gemini-3-flash / gemini-2.5-flash-lite (Google Gemini)" },
|
|
629
|
+
{ label: "qwen", description: "qwen3-max-2026-01-23 / qwen3-coder-plus / qwen3-coder-next (Qwen)" }
|
|
630
|
+
]
|
|
631
|
+
}
|
|
632
|
+
])
|
|
633
|
+
```
|
|
634
|
+
|
|
635
|
+
After the user picks a provider, ask:
|
|
636
|
+
|
|
637
|
+
```text
|
|
638
|
+
AskUserQuestion([
|
|
639
|
+
{
|
|
640
|
+
question: "Which budget level?",
|
|
641
|
+
header: "Budget",
|
|
642
|
+
multiSelect: false,
|
|
643
|
+
options: [
|
|
644
|
+
{ label: "high", description: "All tiers use the highest-quality model for the chosen provider. Highest cost." },
|
|
645
|
+
{ label: "medium", description: "High tier → top model; medium → mid model; low → cheapest model. Best cost/quality ratio." },
|
|
646
|
+
{ label: "low", description: "All tiers use the cheapest model for the chosen provider. Lowest cost." }
|
|
647
|
+
]
|
|
648
|
+
}
|
|
649
|
+
])
|
|
650
|
+
```
|
|
651
|
+
|
|
652
|
+
Canonical tier mappings by provider and budget:
|
|
653
|
+
|
|
654
|
+
| Provider | Budget | high | medium | low |
|
|
655
|
+
|-----------|--------|----------------------------|----------------------------|----------------------------|
|
|
656
|
+
| anthropic | high | claude-opus-4-8 | claude-opus-4-8 | claude-opus-4-8 |
|
|
657
|
+
| anthropic | medium | claude-opus-4-8 | claude-sonnet-4-6 | claude-haiku-4-5 |
|
|
658
|
+
| anthropic | low | claude-haiku-4-5 | claude-haiku-4-5 | claude-haiku-4-5 |
|
|
659
|
+
| openai | high | gpt-5.5 | gpt-5.5 | gpt-5.5 |
|
|
660
|
+
| openai | medium | gpt-5.5 | gpt-5.3-codex | gpt-5.4-mini |
|
|
661
|
+
| openai | low | gpt-5.4-mini | gpt-5.4-mini | gpt-5.4-mini |
|
|
662
|
+
| google | high | gemini-3-pro | gemini-3-pro | gemini-3-pro |
|
|
663
|
+
| google | medium | gemini-3-pro | gemini-3-flash | gemini-2.5-flash-lite |
|
|
664
|
+
| google | low | gemini-2.5-flash-lite | gemini-2.5-flash-lite | gemini-2.5-flash-lite |
|
|
665
|
+
| qwen | high | qwen3-max-2026-01-23 | qwen3-max-2026-01-23 | qwen3-max-2026-01-23 |
|
|
666
|
+
| qwen | medium | qwen3-max-2026-01-23 | qwen3-coder-plus | qwen3-coder-next |
|
|
667
|
+
| qwen | low | qwen3-coder-next | qwen3-coder-next | qwen3-coder-next |
|
|
668
|
+
|
|
669
|
+
Look up the selected (provider, budget) row and proceed to Step E to write those values.
|
|
670
|
+
|
|
671
|
+
**Step D — Generic-provider path:**
|
|
672
|
+
|
|
673
|
+
Prompt the user to enter each model ID as a free-text input. An empty input means "keep
|
|
674
|
+
the current value for that tier." Validate that non-empty inputs are non-blank strings
|
|
675
|
+
(no whitespace-only values); if validation fails, re-prompt that single field.
|
|
676
|
+
|
|
677
|
+
```text
|
|
678
|
+
AskUserQuestion([
|
|
679
|
+
{
|
|
680
|
+
question: "Model ID for the HIGH-cost tier? (most capable model — used for heavy reasoning tasks)",
|
|
681
|
+
header: "High-tier model",
|
|
682
|
+
multiSelect: false,
|
|
683
|
+
options: [
|
|
684
|
+
{ label: "Keep current", description: "Leave unchanged (current: <model_policy.high or '(unset)'>)." },
|
|
685
|
+
{ label: "Enter model ID", description: "Type the exact model identifier. Non-blank string required." }
|
|
686
|
+
]
|
|
687
|
+
},
|
|
688
|
+
{
|
|
689
|
+
question: "Model ID for the MEDIUM-cost tier? (balanced model — used for most agents)",
|
|
690
|
+
header: "Medium-tier model",
|
|
691
|
+
multiSelect: false,
|
|
692
|
+
options: [
|
|
693
|
+
{ label: "Keep current", description: "Leave unchanged (current: <model_policy.medium or '(unset)'>)." },
|
|
694
|
+
{ label: "Enter model ID", description: "Type the exact model identifier." }
|
|
695
|
+
]
|
|
696
|
+
},
|
|
697
|
+
{
|
|
698
|
+
question: "Model ID for the LOW-cost tier? (cheapest model — used for lightweight/fast tasks)",
|
|
699
|
+
header: "Low-tier model",
|
|
700
|
+
multiSelect: false,
|
|
701
|
+
options: [
|
|
702
|
+
{ label: "Keep current", description: "Leave unchanged (current: <model_policy.low or '(unset)'>)." },
|
|
703
|
+
{ label: "Enter model ID", description: "Type the exact model identifier." }
|
|
704
|
+
]
|
|
705
|
+
}
|
|
706
|
+
])
|
|
707
|
+
```
|
|
708
|
+
|
|
709
|
+
Set `provider = "custom"` and `budget = null` when writing the generic-provider result.
|
|
710
|
+
Proceed to Step E.
|
|
711
|
+
|
|
712
|
+
**Step E — Write model_policy to config:**
|
|
713
|
+
|
|
714
|
+
```bash
|
|
715
|
+
# Known-provider path — write all four keys atomically:
|
|
716
|
+
gsd_run query config-set model_policy.provider "<provider>" # e.g., anthropic / openai / google / qwen
|
|
717
|
+
gsd_run query config-set model_policy.budget "<budget>" # high / medium / low
|
|
718
|
+
gsd_run query config-set model_policy.high "<high-id>"
|
|
719
|
+
gsd_run query config-set model_policy.medium "<medium-id>"
|
|
720
|
+
gsd_run query config-set model_policy.low "<low-id>"
|
|
721
|
+
|
|
722
|
+
# Generic-provider path — write only tiers the user changed ("Keep current" skipped):
|
|
723
|
+
gsd_run query config-set model_policy.provider "custom"
|
|
724
|
+
gsd_run query config-set model_policy.budget null
|
|
725
|
+
# Per-tier writes for each non-"Keep current" answer:
|
|
726
|
+
gsd_run query config-set model_policy.high "<high-id>" # omit if user chose "Keep current"
|
|
727
|
+
gsd_run query config-set model_policy.medium "<medium-id>" # omit if user chose "Keep current"
|
|
728
|
+
gsd_run query config-set model_policy.low "<low-id>" # omit if user chose "Keep current"
|
|
729
|
+
```
|
|
730
|
+
|
|
731
|
+
Never write a tier the user explicitly chose to keep; the existing value must survive.
|
|
732
|
+
|
|
733
|
+
</step>
|
|
734
|
+
|
|
554
735
|
<step name="confirm">
|
|
555
736
|
Display:
|
|
556
737
|
|
|
@@ -594,6 +775,11 @@ Display:
|
|
|
594
775
|
| fast_mode.routing_tier_defaults.standard | {true/false} |
|
|
595
776
|
| fast_mode.routing_tier_defaults.heavy | {true/false} |
|
|
596
777
|
| fast_mode.agent_overrides.<agent-id> | {true/false} |
|
|
778
|
+
| model_policy.provider | {anthropic/openai/google/qwen/custom/null} |
|
|
779
|
+
| model_policy.budget | {high/medium/low/null} |
|
|
780
|
+
| model_policy.high | {model-id/null} |
|
|
781
|
+
| model_policy.medium | {model-id/null} |
|
|
782
|
+
| model_policy.low | {model-id/null} |
|
|
597
783
|
|
|
598
784
|
These settings apply to future /gsd:plan-phase, /gsd:execute-phase, /gsd:discuss-phase,
|
|
599
785
|
and /gsd:ship runs.
|
|
@@ -607,7 +793,7 @@ UI/AI phase gates), use /gsd:settings.
|
|
|
607
793
|
|
|
608
794
|
<success_criteria>
|
|
609
795
|
- [ ] Current config read from resolved `$GSD_CONFIG_PATH`
|
|
610
|
-
- [ ]
|
|
796
|
+
- [ ] Eight sections rendered (Planning, Execution, Discussion, Cross-AI, Git, Runtime/Output, Runtime Model Tiers, Model Policy)
|
|
611
797
|
- [ ] Every field pre-selected to its current value (or documented default if absent)
|
|
612
798
|
- [ ] Numeric inputs validated — non-numeric rejected and re-prompted
|
|
613
799
|
- [ ] Branch-template inputs validated — non-default must contain a placeholder
|
|
@@ -616,5 +802,9 @@ UI/AI phase gates), use /gsd:settings.
|
|
|
616
802
|
- [ ] Section 7 shows current runtime and built-in tier table
|
|
617
803
|
- [ ] Group B runtimes display "(no built-in default — your runtime handles model selection)"
|
|
618
804
|
- [ ] Override set/clear/keep paths all work correctly for each tier
|
|
619
|
-
- [ ]
|
|
805
|
+
- [ ] Section 8 (Model Policy) offers three top-level choices: Known provider, Generic provider, Keep current
|
|
806
|
+
- [ ] Known-provider path: provider + budget → canonical tier mapping written to model_policy.{provider,budget,high,medium,low}
|
|
807
|
+
- [ ] Generic-provider path: per-tier manual model IDs; "Keep current" tiers are never written; provider=custom budget=null
|
|
808
|
+
- [ ] model_policy written under the model_policy key in config.json, never as a top-level flat key
|
|
809
|
+
- [ ] Confirmation table rendered listing all fields including model_policy.{provider,budget,high,medium,low}
|
|
620
810
|
</success_criteria>
|
|
@@ -57,6 +57,11 @@ Parse current values (default to `true` if not present):
|
|
|
57
57
|
- `model_profile` — which model each agent uses (default: `balanced`)
|
|
58
58
|
- `git.branching_strategy` — branching approach (default: `"none"`)
|
|
59
59
|
- `workflow.use_worktrees` — whether parallel executor agents run in worktree isolation (default: `true`)
|
|
60
|
+
- `model_policy.provider` — provider slug for model policy (default: `null`; known values: anthropic, openai, google, qwen; set via /gsd:config --advanced)
|
|
61
|
+
- `model_policy.budget` — budget level for model policy (default: `null`; known values: high, medium, low; set via /gsd:config --advanced)
|
|
62
|
+
- `model_policy.high` — model ID for high-cost tier (default: `null`; set via /gsd:config --advanced)
|
|
63
|
+
- `model_policy.medium` — model ID for medium-cost tier (default: `null`; set via /gsd:config --advanced)
|
|
64
|
+
- `model_policy.low` — model ID for low-cost tier (default: `null`; set via /gsd:config --advanced)
|
|
60
65
|
</step>
|
|
61
66
|
|
|
62
67
|
<step name="present_settings">
|
|
@@ -423,6 +428,15 @@ Merge new settings into existing config.json:
|
|
|
423
428
|
"hooks": {
|
|
424
429
|
"context_warnings": true/false,
|
|
425
430
|
"workflow_guard": true/false
|
|
431
|
+
},
|
|
432
|
+
"model_policy": {
|
|
433
|
+
// Read-only in this flow — written only by /gsd:config --advanced (Section 8).
|
|
434
|
+
// Listed here so safe-merge never clobbers an existing model_policy object.
|
|
435
|
+
"provider": <existing|null>,
|
|
436
|
+
"budget": <existing|null>,
|
|
437
|
+
"high": <existing|null>,
|
|
438
|
+
"medium": <existing|null>,
|
|
439
|
+
"low": <existing|null>
|
|
426
440
|
}
|
|
427
441
|
}
|
|
428
442
|
```
|
|
@@ -537,7 +551,7 @@ Quick commands:
|
|
|
537
551
|
- /gsd:plan-phase --research — force research
|
|
538
552
|
- /gsd:plan-phase --skip-research — skip research
|
|
539
553
|
- /gsd:plan-phase --skip-verify — skip plan check
|
|
540
|
-
- /gsd:config --advanced — power-user tuning (plan bounce, timeouts, branch templates, cross-AI, context window)
|
|
554
|
+
- /gsd:config --advanced — power-user tuning (plan bounce, timeouts, branch templates, cross-AI, context window, model policy)
|
|
541
555
|
```
|
|
542
556
|
</step>
|
|
543
557
|
|
|
@@ -118,7 +118,7 @@ Display:
|
|
|
118
118
|
GSD ► UI DESIGN CONTRACT — PHASE {N}
|
|
119
119
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
120
120
|
|
|
121
|
-
◆ Spawning UI researcher...
|
|
121
|
+
◆ Spawning UI researcher... (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze)
|
|
122
122
|
```
|
|
123
123
|
|
|
124
124
|
Build prompt:
|
|
@@ -183,7 +183,7 @@ Display:
|
|
|
183
183
|
GSD ► VERIFYING UI-SPEC
|
|
184
184
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
185
185
|
|
|
186
|
-
◆ Spawning UI checker...
|
|
186
|
+
◆ Spawning UI checker... (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze)
|
|
187
187
|
```
|
|
188
188
|
|
|
189
189
|
Build prompt:
|
|
@@ -93,6 +93,8 @@ Call AskUserQuestion with gap table and options:
|
|
|
93
93
|
|
|
94
94
|
## 5. Spawn gsd-nyquist-auditor
|
|
95
95
|
|
|
96
|
+
Print: `◆ Spawning nyquist auditor... (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze)`
|
|
97
|
+
|
|
96
98
|
```
|
|
97
99
|
Agent(
|
|
98
100
|
prompt="Read ~/.claude/agents/gsd-nyquist-auditor.md for instructions.\n\n" +
|
|
@@ -552,7 +552,7 @@ Display:
|
|
|
552
552
|
GSD ► PLANNING FIXES
|
|
553
553
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
554
554
|
|
|
555
|
-
◆ Spawning planner for gap closure...
|
|
555
|
+
◆ Spawning planner for gap closure... (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze)
|
|
556
556
|
```
|
|
557
557
|
|
|
558
558
|
Spawn gsd-planner in --gaps mode:
|
|
@@ -602,7 +602,7 @@ Display:
|
|
|
602
602
|
GSD ► VERIFYING FIX PLANS
|
|
603
603
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
604
604
|
|
|
605
|
-
◆ Spawning plan checker...
|
|
605
|
+
◆ Spawning plan checker... (runs in a subagent — no output until it returns, ~1–5 min; expected, not a freeze)
|
|
606
606
|
```
|
|
607
607
|
|
|
608
608
|
Initialize: `iteration_count = 1`
|