Compare commits

...

41 Commits

Author SHA1 Message Date
Tom Boucher
42ed7cee8d refactor: deepen GSDTools query execution seams (#3085)
* refactor: deepen gsdtools query execution seams

* docs: add changeset for query seam deepening

* docs: fix changeset summary text

* fix: address coderabbit query seam findings

* test: address remaining coderabbit findings and notes

* refactor: use internal gsdtools error type import
2026-05-03 18:56:41 -04:00
Tom Boucher
5e21bf7567 Deepen query dispatch seam with Command Topology Module (#3078)
* Deepen query dispatch seam with command topology module

* Stabilize SDK parity defaults and integration test gating

* docs(architecture): record pre-project config policy and e2e gate

* refactor(query): stop injecting native adapter in CLI dispatch path

* fix(config): align workflow auto-chain typing and docs
2026-05-03 18:11:38 -04:00
Tom Boucher
9c92c32f6e refactor(query): deepen runtime context/native adapter/output seams (#3076)
* refactor(query): deepen runtime context, native adapter, and cli output seams

* chore(changeset): add fragment for query seam deepening continuation

* refactor(query): converge internal command-resolution imports on canonical seam

* refactor(query): remove dead seam wrappers and converge on canonical modules

* docs(architecture): update context and adr for query seam completion

* fix(query): preserve gsd-tools stderr in cli output and clarify static ws test scope

* test(query): cover whitespace stderr and null exitCode fallback
2026-05-03 16:31:48 -04:00
Tom Boucher
5c9f34bd31 refactor(cli): extract Query CLI Adapter Module seam (#3074)
* refactor(cli): extract query adapter seam from cli entrypoint

* test: update ws forwarding guard for query-cli-adapter seam

* fix(query): close remaining CodeRabbit findings on cli adapter

* test: address remaining CodeRabbit nitpicks on ws forwarding coverage
2026-05-03 15:57:01 -04:00
Tom Boucher
b6c401dc90 refactor(query): deepen command/dispatch seams and resolve coderabbit findings
* refactor(query): deepen command definition seam and fold fallback mapping cleanup

* refactor(query): add shared dispatch formatting module seam

* fix(query): restore QueryResult type import in dispatch deps

* test/query: align raw-output policy and definition normalization contracts

* refactor(query): deepen diagnosis, invariant report, and error taxonomy seams

* refactor(query): deepen dispatch plan, fallback bridge, policy snapshot, and hints seams

* refactor(query): deepen validation, fallback policy, capability, and result builder seams

* refactor(query): deepen resolution strategy, output classifier, observability, and policy-capability seams

* refactor(query): finalize deep strategy/classifier/observability/capability seams

* test/query: address coderabbit inline and out-of-diff dispatch nits

* fix(query): address remaining coderabbit input-validation and bridge stderr threads

* fix(query): address remaining coderabbit dispatch and strategy/output nits
2026-05-03 15:29:34 -04:00
Tom Boucher
c3f896f311 docs(contributing): codify CONTEXT + ADR contribution and testing standards 2026-05-03 14:54:14 -04:00
Tom Boucher
f104dab332 refactor(query): deepen dispatch policy seam with structured result contract (#3066)
* refactor(query): deepen dispatch policy seam with structured result contract

Closes #3065.

- unify query dispatch outcome as typed success/failure union
- include error kind/details + final exit_code in failure path
- align native and fallback paths under one dispatch policy seam
- make CLI query path consume seam result (thin adapter)
- add ADR + context term for Dispatch Policy Module

* refactor(query): strengthen dispatch seam with shared error mapper and typed details

- add query-dispatch-error-mapper module shared by native/fallback paths
- remove ad-hoc inline mapping in dispatch/fallback executors
- lock error-details schema in mapper + dispatch tests
- document structured dispatch contract in QUERY-HANDLERS.md

* fix(query): return structured fallback failure when path resolution throws

- guard resolveGsdToolsPath in cjs dispatch path
- map thrown resolution errors to fallback_failure result
- add regression test for structured failure contract
2026-05-03 14:30:27 -04:00
Tom Boucher
5975f06b6a refactor(query): extract command catalog seam for registry wiring (#3060)
* refactor(sdk): extract gsdtools transport seam with per-command policy

* refactor(query): centralize registry command catalog wiring

* refactor(query): unify command resolution seam across sdk callers

* fix(sdk): address CodeRabbit transport policy and timeout findings

* refactor(query): extract mutation event mapper seam

* refactor(query): converge mutation and transport policy data

* refactor(query): share fallback orchestration across cli and sdk

* refactor(query): split static registry catalog by domain clusters

* refactor(query): extract mutation event emission decorator seam

* refactor(query): extract alias-family handler catalog module

* refactor(query): extract cjs fallback execution adapter

* refactor(query): deepen command semantics seam

* refactor(query): extract deep dispatch seam

* refactor(query): deepen cjs fallback execution seam

* refactor(query): merge routing plan into dispatch seam

* fix(query): address CodeRabbit review findings on PR #3060

Critical: prevent double-execution race by checking timeout errors
before subprocess fallback (gsd-transport.ts).

Major: fix execRaw() to respect transport policy outputMode instead
of hardcoding 'raw' (gsd-tools.ts).

Major: add explicit 30s timeout to subprocess fallback execution
(query-fallback-executor.ts).

Major: remove raw args from stderr banner to prevent secret leakage
(query-fallback-executor.ts).

Minor: ensure native text output has trailing newline for CLI parity
(query-dispatch.ts).

Update gsd-tools.test.ts to match new execRaw() behavior.

* fix(tests): update CLI integration tests for catalog-based registration

The refactoring moved handler registration from inline registry.register()
calls to catalog-based registration (registerStaticCatalog/registerAliasCatalog).

- gsd-sdk-query-registry-integration.test.cjs: collectRegisteredNames() now
  also scans catalog files for handler names registered via the new system.
- bug-2492-context-coverage-gate.test.cjs: checks for catalog-based
  registration (DECISION_ROUTING_STATIC_CATALOG) instead of inline strings.
- bug-2524-sdk-query-ws-flag.test.cjs: checks for dispatchNative callback
  pattern instead of direct registry.dispatch() call.

* fix(query): address remaining CodeRabbit review findings

- query-command-semantics.ts: guard stats/progress rewrite so option
  tokens (e.g. --pick) are not turned into subcommands, preserving the
  top-level handler dispatch.

- query-dispatch.ts: formatOutput now skips --pick for text-format
  responses (matching CJS fallback behavior) and surfaces a proper error
  when extractField returns undefined instead of silently producing
  'undefined'.

- query-dispatch.ts: fix backwards error message — 'registered' is the
  restrictive policy that disables fallback, not enables it.

- tests/bug-2492-context-coverage-gate.test.cjs: check
  VERIFY_DECISION_STATIC_CATALOG (the correct catalog for plan-gate
  handlers) instead of DECISION_ROUTING_STATIC_CATALOG.

- tests/gsd-sdk-query-registry-integration.test.cjs: resolve catalog
  variable before loading entries so the drift guard checks each
  referenced catalog individually.

* refactor(query): deepen registry assembly module with strict invariants

- extract registry assembly into dedicated module
- split build vs mutation decoration internals
- add strict assembly invariants:
  1) no duplicate keys
  2) alias canonicals must have handlers
  3) mutation commands must be registered
  4) raw-output policy commands must be registered
- slim query index to thin re-export seam
- add focused registry assembly tests
- update drift-guard tests to target new seam

* test(query): add thin-seam coverage for query index re-exports

* fix(query): return structured native dispatch errors + tighten decisions.parse guard

- runQueryDispatch native path now catches adapter errors and returns
  QueryDispatchResult.error instead of throwing.
- preserve legacy CLI exit contract by using code=1 for native dispatch
  failures.
- strengthen bug-2492 guard: decisions.parse assertion now checks
  VERIFY_DECISION_STATIC_CATALOG OR explicit command token.
2026-05-03 13:57:32 -04:00
Tom Boucher
0f98952a3d refactor(sdk): extract GSDTools transport seam + policy (#3058)
* refactor(sdk): extract gsdtools transport seam with per-command policy

* fix(sdk): address CodeRabbit transport policy and timeout findings

* fix(sdk): harden raw transport formatting and raw-path coverage
2026-05-03 08:20:05 -04:00
Tom Boucher
eb365f7336 docs: audit and update docs/ for v1.40.0 release (#3048)
* docs(en): update FEATURES/USER-GUIDE/COMMANDS for v1.40.0 surface

- FEATURES.md: append v1.40.0 section (#122 skill consolidation, #123
  namespace meta-skills, #124 context-window guard, #125 phase-lifecycle
  status-line read-side); add to TOC.
- USER-GUIDE.md: add slash-command form (hyphen vs colon) primer and
  namespace routing primer; replace deleted slash forms in walkthroughs
  (`/gsd-add-backlog`, `/gsd-plant-seed`, `/gsd-add-phase`,
  `/gsd-set-profile`, `/gsd-list-workspaces`, etc.) with consolidated
  forms (`/gsd-capture --backlog`, `/gsd-phase --insert`,
  `/gsd-config --profile`, `/gsd-workspace --list`, etc.); fix
  `/gsd-spike-wrap-up` and `/gsd-sketch-wrap-up` to flag form.
- COMMANDS.md: clarify Command Syntax (Gemini = colon form, others =
  hyphen form); add Namespace Meta-Skills section with all six routers;
  add `--context` to /gsd-health flag table.

Refs #3047

* docs(en): refresh INVENTORY/CLI-TOOLS/STATE-MD-LIFECYCLE for v1.40.0

- INVENTORY.md: workflow-row "Invoked by" column updated to point at
  consolidated commands (`/gsd-phase` family, `/gsd-workspace --list`,
  `/gsd-config --advanced/--integrations/--profile`,
  `/gsd-sketch --wrap-up`, `/gsd-spike --wrap-up`); CLI-modules row for
  `secrets.cjs` updated to `/gsd-config --integrations`. Command count
  and namespace meta-skills section already reflect 65 shipped (= 59
  consolidated sub-skills + 6 ns-* routers).
- CLI-TOOLS.md: add `validate context` row under Validation Commands
  with the 60 %/70 % threshold envelope used by `/gsd-health --context`.
- STATE-MD-LIFECYCLE.md: flip status header from "proposed" to
  "shipped in v1.40.0" since `parseStateMd()` and `formatGsdState()`
  now read and render `active_phase`, `next_action`, `next_phases`,
  and `progress`.

`docs/AGENTS.md` audited and verified clean — `gsd-code-fixer` row
already lists the correct `/gsd-code-review --fix` spawner; no
deleted-skill references found. `docs/INVENTORY-MANIFEST.json`
audited and verified clean — already enumerates the 65 commands
(including six ns-* routers) and contains no deleted slash forms.

Refs #3047

* docs(en): cleanup ARCHITECTURE/CONFIGURATION for v1.40.0

- ARCHITECTURE.md: split Commands install-target list to call out the
  Gemini colon form (`/gsd:command-name`) vs hyphen form for every
  other runtime. Add a new subsection covering two-stage hierarchical
  routing via the six namespace meta-skills (#2792) and a paired note
  on the MCP token-budget interaction so readers see the two big
  per-turn cost levers in one place.
- CONFIGURATION.md: rewrite three references to the deleted
  `/gsd-settings-advanced` and `/gsd-settings-integrations` slash
  forms to use the consolidated `/gsd-config --advanced` /
  `/gsd-config --integrations` invocations. Add a new "STATE.md
  Frontmatter (Phase Lifecycle)" section documenting the four
  optional fields (`active_phase`, `next_action`, `next_phases`,
  `progress`) read by the v1.40 status-line, with a pointer to
  STATE-MD-LIFECYCLE.md for the full reference.

`docs/manual-update.md` audited and verified clean — already documents
`/gsd-update --reapply` (the consolidated form), no reference to the
deleted `/gsd-reapply-patches`.

Refs #3047

* docs(i18n): mirror v1.40.0 slash-command rename into ja-JP/ko-KR/zh-CN/pt-BR

Mechanical token-level renames only — every reference to a deleted
micro-skill slash form is rewritten to the consolidated form on the
matching parent skill. No prose was machine-translated; new prose
sections (slash-form primer, namespace routing primer, v1.40 feature
entries, STATE.md frontmatter) were left for human translator
follow-up.

Renames applied uniformly across all four trees:
  /gsd-add-todo, /gsd-add-note, /gsd-add-backlog,
  /gsd-plant-seed, /gsd-check-todos      → /gsd-capture[ --note|
                                            --backlog|--seed|--list]
  /gsd-add-phase, /gsd-insert-phase,
  /gsd-remove-phase, /gsd-edit-phase     → /gsd-phase[ --insert|
                                            --remove|--edit]
  /gsd-new-workspace, /gsd-list-workspaces,
  /gsd-remove-workspace                  → /gsd-workspace[ --new|
                                            --list|--remove]
  /gsd-settings-advanced,
  /gsd-settings-integrations,
  /gsd-set-profile                       → /gsd-config[ --advanced|
                                            --integrations|--profile]
  /gsd-sketch-wrap-up                    → /gsd-sketch --wrap-up
  /gsd-spike-wrap-up                     → /gsd-spike --wrap-up
  /gsd-reapply-patches                   → /gsd-update --reapply
  /gsd-code-review-fix                   → /gsd-code-review --fix
  /gsd-plan-milestone-gaps               → /gsd-audit-milestone

Refs #3047

* docs(changelog): regroup [Unreleased] under Feature/Enhancement/Fix

Replace the existing Keep-a-Changelog \`Added\` / \`Changed\` /
\`Performance\` / \`Removed\` / \`Fixed\` sub-headers in the [Unreleased]
block with the issue/PR template taxonomy:

  Added                 → Feature
  Changed / Performance → Enhancement
  Removed               → Enhancement
  Fixed                 → Fix

Order within the release: Feature → Enhancement → Fix. Every bullet
preserved verbatim — only headers and grouping changed; the awkward
inline-versioned headers (\`### Added — 1.40.0-rc.1\`,
\`### Changed — 1.40.0-rc.1\`, \`### Fixed — 1.40.0-rc.1\`) folded into
the same buckets with the \`— 1.40.0-rc.1\` suffix dropped, since the
[Unreleased] block IS 1.40.0-rc.1.

The [1.39.2] hotfix block called out in #3047's spec does not yet
exist in CHANGELOG.md (the previously released hotfix is [1.39.1]),
so this commit only regroups [Unreleased]. Older release blocks
([1.39.1] and earlier) are frozen and untouched.

Refs #3047

* docs(changeset): add fragment for v1.40.0 doc audit

Refs #3047

* docs(en): strip leading / from deleted slash-command tokens in FEATURES

REQ-CONSOLIDATE-03 and REQ-CONSOLIDATE-04 listed deleted commands by
their `/gsd-foo` form for the historical record. The docs-parity tests
in bug-3010, bug-3029-3034, and bug-3042-3044 use the regex
`/\/gsd-[a-z0-9][a-z0-9-]*/g` to scan user-facing surfaces for any
remaining mention of removed slash forms — they cannot tell prose
about a deleted command from a live recommendation.

Strip the leading slash from the bare-name references (preserve the
historical text otherwise). Tests now require a `/` prefix to match,
so `gsd-add-todo` reads identically to a human but no longer trips
the parser.

Verified locally: 65/65 tests pass across the three docs-parity
suites that were red on CI run 25270072600.

Refs #3047

* docs(en): fix CR feedback + drop literal /gsd:plan-phase from USER-GUIDE

CI: tests/bug-2543-gsd-slash-namespace.test.cjs flagged
docs/USER-GUIDE.md:35 for embedding the literal `/gsd:plan-phase`
token in the parenthetical Gemini-form example. The test scans every
.md under docs/ for `/gsd:<live-cmd>` because non-Gemini surfaces must
not advertise the colon form. Replaced the literal example with a
prose substitution rule.

CR: docs/ARCHITECTURE.md:125 — the namespace meta-skills were listed
by file-prefix (`gsd-ns-workflow`) but the invocable frontmatter `name:`
is the bare form (`gsd-workflow`). Verified against the six
`commands/gsd/ns-*.md` files. Replaced with the canonical names and
noted the file/name disagreement in-line.

CR: docs/COMMANDS.md:723 — `v1.40` aligned to canonical `v1.40.0`.

CR: docs/FEATURES.md:2679 — REQ-CTX-GUARD-02 advertised the wrong
invocation (`gsd-tools validate context`). The shipped handler is
exposed via `gsd-sdk query validate.context` and requires explicit
`--tokens-used <int>` + `--context-window <int>` flags (verified
against sdk/src/query/validate.ts:849-882 and
get-shit-done/bin/lib/validate-command-router.cjs:19-36).

CR: docs/zh-CN/README.md:533 — added `inherit` to the profile-options
parenthetical to match the canonical set (verified against
model-profiles.cjs:29 `VALID_PROFILES = […MODEL_PROFILES['gsd-planner'], 'inherit']`).

Verified locally: 74/74 tests pass across the four docs-parity suites
that were red on CI runs 25270072600 and 25270182903.

Refs #3047
2026-05-03 07:33:27 -04:00
Tom Boucher
1e6737cd8e feat(plan-phase): --research-phase flag + scrub stale slash-command refs (#3042, #3044) (#3045)
* feat(plan-phase): --research-phase flag absorbs deleted /gsd-research-phase + scrub stale refs (#3042, #3044)

#3042 (orphaned research-phase): /gsd-research-phase had a workflow file
but no slash-command stub. Rather than restore the orphan, the research-
only capability is now a flag on /gsd-plan-phase:

  /gsd-plan-phase --research-phase <N>

When set, the workflow scopes to phase N, runs the research step (Section
5 of the existing plan-phase workflow), then early-exits before the
planner/plan-checker/verifier chain.

Per RCA against the deleted standalone, the flag adds two modifiers to
fully cover the original surface (Option B from the RCA discussion):

- --view : print existing RESEARCH.md to stdout, no spawn. Cheapest mode
  for the correction-without-replanning loop the issue reporter
  explicitly called out. Errors with a clear hint if RESEARCH.md is
  missing.
- --research : reuse the existing "force re-research" semantics. In
  research-only mode this skips the existing-RESEARCH.md prompt and
  re-spawns unconditionally.
- Neither flag, RESEARCH.md exists : prompt update/view/skip. Mirrors
  the deleted standalone's existing-artifact menu (#3042 RCA).

#3044 (stale slash-command refs): scrubbed five deleted commands from
all user-facing surfaces, including English docs, 4 localized doc sets
(ja-JP, ko-KR, zh-CN, pt-BR), workflows, templates, and references.

  /gsd-check-todos          → /gsd-capture --list
  /gsd-new-workspace        → /gsd-workspace --new
  /gsd-status               → /gsd-progress
  /gsd-plan-milestone-gaps  → table rows / orphan sections removed
                              (PR #3038 only scrubbed workflows/agent;
                              missed the docs surfaces this PR covers)
  /gsd-research-phase       → /gsd-plan-phase --research-phase

Includes a fix to docs/issue-driven-orchestration.md (PR #3036)
which itself referenced /gsd-new-workspace 4 times — self-correction.

Removed:
- get-shit-done/workflows/research-phase.md (orphan, capability
  absorbed into --research-phase flag)

Tests:
- tests/bug-3042-3044-research-flag-and-stale-refs.test.cjs — 46
  structural-IR tests across both bugs:
  - argument-hint advertises --research-phase + --view
  - workflow parses --research-phase, sets RESEARCH_ONLY,
    early-exits before planner
  - --view prints RESEARCH.md without spawning
  - --research forces refresh in research-only mode
  - existing-RESEARCH.md prompt path with update/view/skip
  - workflows/research-phase.md is removed
  - 5 deleted slash-commands absent from 17 English user-facing
    surfaces + 16 localized doc surfaces (4 locales × 4 docs each)
  - replacement command tokens present where deleted ones lived

6950/6950 full suite pass. Lints clean.

Closes #3042
Closes #3044

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix: address all 8 CR findings on PR #3045

Major (3):
- get-shit-done/workflows/plan-phase.md:344 — added explicit early-exit
  guard at Section 5.1: "Skip if RESEARCH_ONLY=true". Without it, an LLM
  could fall through "use existing, skip to step 6" → planner spawn,
  violating the research-only contract. The guard makes the early-exit
  unreachable from any non-research-only branch.
- get-shit-done/references/continuation-format.md (3 examples) +
  zh-CN/.../continuation-format.md (3 examples) — pointed to
  `/gsd-plan-phase --research-phase` but docs/COMMANDS.md didn't
  document the flag. Added a full --research-phase + --view + --research
  modifier section to the /gsd-plan-phase flag table in COMMANDS.md so
  the canonical reference matches the continuation examples.

Minor (5):
- docs/FEATURES.md:1632 — `/gsd-plan-phase --research-phase` →
  `/gsd-plan-phase --research-phase <N>` (include required arg).
- get-shit-done/templates/README.md:46 — NN-VALIDATION.md producer
  reverted from `/gsd-plan-phase --research-phase` (Nyquist) to plain
  `/gsd-plan-phase` (Nyquist). VALIDATION.md is created during normal
  Nyquist flow, not research-only mode — the bulk replacement was
  wrong for that line.
- get-shit-done/workflows/help.md:89 — signature line was missing
  `--research`; added it alongside `--research-phase` and `--view`.
- tests/bug-3042-3044-...:197 — promptHasView/promptHasSkip were
  tautological (matched anywhere in 1700-line workflow). Tightened
  to a proximity check anchored on "RESEARCH.md already exists" prompt
  header within a 600-char window. Updated workflow to emit that
  literal phrase.
- tests/feat-2840-...:95 — workspace assertion used `/gsd-workspace`
  but the documented replacement is `/gsd-workspace --new`. Tightened
  to require both tokens (in 3 places: requiredCommands list, regex
  in conceptPairs, error message).

6950/6950 full suite pass. Lint clean.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-02 23:12:50 -04:00
Tom Boucher
dca12242b5 fix(install): skip Gemini local commands/gsd when global GSD present (#3037) (#3041)
* fix(install): skip Gemini local commands/gsd when global GSD present (#3037)

Reporter showed that running `npx get-shit-done-cc --gemini --global`
followed by `--gemini --local` in a project creates the same 65 GSD
command files in both Gemini scopes:
  - ~/.gemini/commands/gsd/ (user scope)
  - <project>/.gemini/commands/gsd/ (workspace scope)

Gemini conflict-detects by command name across scopes and renames every
overlapping /gsd:* command to /workspace.gsd:* and /user.gsd:*, breaking
the documented /gsd:* namespace.

Fix: in bin/install.js, when handling --gemini --local, detect whether
~/.gemini/commands/gsd/ already exists with managed-shape content. If
so, skip the local copy and print a clear three-line warning explaining
the conflict avoidance. The user-scope install already provides the
same /gsd:* commands in this project; the local copy adds zero value.

Sibling fixes (test isolation):
- tests/install-minimal-all-runtimes.test.cjs: pass HOME/USERPROFILE
  through the spawned installer's env so the developer's real
  ~/.gemini/commands/gsd/ doesn't trigger the new skip path during
  test runs that want to assert the local-install populates
  commands/gsd/.
- tests/gemini-namespacing.test.cjs: the "Gemini Install (Behavioral)"
  describe block now creates an isolated tmpHome and points
  process.env.HOME at it before calling install(false, 'gemini'),
  with proper restore in afterEach.

Test:
- tests/bug-3037-gemini-duplicate-commands.test.cjs — 4 structural
  tests:
    1. global install populates HOME/.gemini/commands/gsd
    2. local install AFTER global skips the local copy
    3. local install with NO existing global still populates locally
       (no-regression)
    4. local install when HOME has .gemini/ but no GSD-managed
       commands/gsd/ still populates locally (non-GSD-Gemini-user
       no-regression)

6909/6909 full suite pass. Lints clean.

Closes #3037

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix: address CR feedback on PR #3041 — narrower detection + USERPROFILE restore

CR findings:

1. **bin/install.js (Major)** — userScopeHasGsd used
   `fs.readdirSync(homeGeminiGsd).length > 0` which would skip the
   local install for any non-empty directory, including a user who
   hand-dropped a single override at ~/.gemini/commands/gsd/<thing>
   .toml without ever running --gemini --global. Narrowed the
   detection to require at least 3 canonical GSD command files
   (help.toml, progress.toml, new-project.toml) — a marker that
   ships in every GSD Gemini install (minimal mode included) and is
   structurally impossible to produce by accident.

2. **tests/bug-3037-...:59 (Minor)** — beforeEach overwrites
   process.env.USERPROFILE but afterEach only restores HOME, leaking
   the temp home into later tests on Windows or any code path that
   reads USERPROFILE. Added save/restore symmetric with HOME.

Plus added a 5th regression test covering the narrowed detection:
"local install when HOME has hand-dropped overrides UNDER commands/gsd/
(but no full GSD) still populates locally" — directly exercises the
edge case CR identified.

5/5 targeted tests pass. 6910/6910 full suite pass.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-02 17:44:52 -04:00
Tom Boucher
7714b5244b fix(workflows,docs): scrub stale /gsd-code-review-fix and /gsd-plan-milestone-gaps refs (#3029, #3034) (#3038)
* fix(workflows,docs): scrub stale /gsd-code-review-fix and /gsd-plan-milestone-gaps refs (#3029, #3034)

#2790 consolidated /gsd-code-review-fix into /gsd-code-review --fix and
deleted /gsd-plan-milestone-gaps in favor of inline gap planning as part
of /gsd-audit-milestone's output. The deletion was propagated through
some surfaces (#2950 covered help/do/settings/discuss-phase/etc.) but
several user-facing surfaces still emitted the old forms:

#3029 — /gsd-code-review-fix references in:
- agents/gsd-code-fixer.md (description, "Spawned by", recovery prose)
- get-shit-done/workflows/code-review.md (offer text)
- get-shit-done/workflows/execute-phase.md (offer text)
- get-shit-done/workflows/code-review-fix.md (internal retry hints)
- docs/INVENTORY.md (agent + workflow rows)
- docs/CONFIGURATION.md (workflow.code_review row)
- docs/USER-GUIDE.md (3 occurrences in walkthrough)
- docs/AGENTS.md (gsd-code-fixer agent stub)
- docs/FEATURES.md (commands list + REQ-REVIEW-04)

All replaced with /gsd-code-review --fix. Internal retry hints in the
workflow file itself updated to point at the new form. Release notes
(docs/RELEASE-*.md) and gsd-ns-review's "absorbed by" deletion note
left unchanged — historical/explanatory content.

#3034 — /gsd-plan-milestone-gaps references in:
- get-shit-done/workflows/audit-milestone.md (<offer_next> blocks for
  gaps_found and tech_debt: lines 281, 323)
- commands/gsd/complete-milestone.md (gaps_found pre-flight: lines 46, 57)

Replaced with inline closure path:
  /gsd-phase --insert <N> "Close gap: <REQ-ID> ..."
  /gsd-discuss-phase <N>
  /gsd-plan-phase <N>
  /gsd-execute-phase <N>

Plus a Nyquist-coverage hint pointing at /gsd-validate-phase /
/gsd-secure-phase for retroactive audit-chain hygiene gaps. The
gsd-ns-project SKILL.md "deleted by #2790" note is preserved
(it's the canonical pointer for future readers asking what
happened to the command).

Tests:
- tests/bug-3029-3034-stale-command-routes.test.cjs — parser-based
  assertions per fixed surface, plus a structural cross-check that
  gsd-ns-project keeps the deletion note. 15 tests, all green.
- 6905/6905 full suite passes.

Closes #3029
Closes #3034

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix: address CR feedback on PR #3038 — argument order, structural tests, agent count

CR findings on PR #3038:

1. **docs/USER-GUIDE.md (Major)** — `--fix` examples used flag-first form
   (`/gsd-code-review --fix 3`), but the supported CLI grammar is
   phase-first (`/gsd-code-review 3 --fix`). The original sed-based
   replacement preserved the position of the `gsd-code-review-fix`
   token, producing the wrong order. Fixed in USER-GUIDE.md (3
   occurrences) and the same drift in the workflow surfaces:
   - get-shit-done/workflows/code-review-fix.md (2 retry hints)
   - get-shit-done/workflows/code-review.md (offer text)
   - get-shit-done/workflows/execute-phase.md (offer text)

2. **docs/AGENTS.md (Minor)** — internal count drift: line 483 said
   "Ten additional agents" but line 725 said "12 advanced/specialized".
   Filesystem reality: 33 agents total, 21 primary, 12 specialized
   (count of `### ` stubs in the Advanced and Specialized section).
   Updated lines 3, 13, 483 to use 12/33 and added the two missing
   names (doc-classifier, doc-synthesizer) to the inline list at
   line 13.

3. **tests:94 (Major refactor suggestion)** — `.includes()` token checks
   were source-grep style. Refactored to a typed-IR pattern: extract
   the SET of slash-command tokens via regex, assert membership on the
   parsed Set instead of substring scanning the raw file text. Added
   the `allow-test-rule` comment explaining the IR-build vs
   IR-assertion split per scripts/lint-no-source-grep.cjs convention.

4. **tests:130 (Major)** — replacement-path assertion was file-wide and
   could false-pass on generic mentions of "inline" elsewhere in the
   file. Refactored: `extractOfferBlocks(content)` returns the typed
   list of `<offer_next>` and "Pre-flight" blocks where the deleted
   command previously lived, and the assertion runs against those
   blocks specifically. Now requires `/gsd-phase --insert` or
   inline-audit prose to appear in the same offer block, not just
   somewhere in the file.

15/15 targeted tests pass. 6905/6905 full suite pass. Lints clean.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-02 17:23:44 -04:00
Tom Boucher
117b3ec009 docs: add issue-driven orchestration guide (#2840) (#3036)
* docs: add issue-driven orchestration guide (#2840)

Adds docs/issue-driven-orchestration.md — a recipe for driving GSD from a
GitHub / Linear / Jira issue using existing primitives. Maps Symphony-style
orchestration concepts onto GSD commands without vendoring code, adding a
daemon, or introducing tracker integration.

Concept mapping covers:
- WORKFLOW.md → ROADMAP.md / STATE.md / phase CONTEXT.md / phase PLAN.md
- isolated agent workspace → /gsd-new-workspace --strategy worktree
- agent dispatch → /gsd-manager (interactive), /gsd-autonomous (unattended)
- per-phase steps → /gsd-discuss-phase → /gsd-plan-phase → /gsd-execute-phase
- proof-of-work → /gsd-verify-work (UAT.md persists across /clear)
- adversarial review → /gsd-review (cross-AI peer review)
- human merge gate → /gsd-ship
- follow-up capture → /gsd-note, /gsd-plant-seed, /gsd-new-milestone

End-to-end flow walks through 7 numbered steps from picking the tracker
issue to capturing follow-ups. Safety boundaries (isolated worktrees,
explicit human review, no automatic public posting, verification before
ship) and non-goals (no vendoring, no daemon, no mandatory tracker, no
gate bypass, no command-surface expansion) are spelled out explicitly so
the doc cannot drift into "let's just add one more flag".

Cross-linked from docs/README.md (Documentation Index) and
docs/USER-GUIDE.md (Table of Contents preamble).

Tests: tests/feat-2840-issue-driven-orchestration-guide.test.cjs — 9
structural-IR tests parse the guide into a typed record and assert on
flags (commandsPresent, conceptPairs, nonGoalFlags, safetyFlags,
numberedSteps). Fence-language MD040 check enforced. Cross-link
presence enforced. No raw-text assertions on prose.

6890/6890 tests pass. Lint:tests clean (allow-test-rule comment justifies
the doc-shape parser per scripts/lint-no-source-grep.cjs escape hatch).
Lint:changeset clean.

Closes #2840

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(test): guard USER-GUIDE.md existsSync before read (CR #3036)

CR Minor: cross-linked-from-USER-GUIDE.md test called fs.readFileSync
directly without first asserting fs.existsSync, asymmetric with the
README.md test above. A missing USER-GUIDE.md would throw ENOENT instead
of producing a meaningful assertion message. Mirror the null-guard
pattern.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-02 16:57:42 -04:00
Tom Boucher
95d2bc20f8 feat(hooks): opt-in SessionStart update banner for non-statusline users (#2795) (#3035)
* feat(hooks): opt-in SessionStart update banner for non-statusline users (#2795)

When a user declines (or keeps a non-GSD) statusline at install time, the
installer now offers an opt-in SessionStart banner that surfaces GSD update
availability. The banner reads the existing
~/.cache/gsd/gsd-update-check.json cache (written by
gsd-check-update-worker.js) and emits a single systemMessage line only when
update_available is true:

    GSD update available: <installed> → <latest>. Run /gsd-update.

It is silent when up-to-date and rate-limits "check failed" diagnostics to
once per 24h via a sentinel file so a corrupt cache doesn't nag every
session. Removed cleanly by `npx get-shit-done-cc --uninstall` which strips
both the script and the SessionStart entry. The banner is never offered when
GSD's statusline is being installed (statusline already surfaces update
info, so re-prompting would be noise).

Implementation:
- hooks/gsd-update-banner.js — pure functions buildBannerOutput,
  shouldSuppressFailureWarning, readCache; thin main() wires them.
- bin/install.js — handleUpdateBanner() prompt, parseUpdateBannerInput(),
  buildUpdateBannerHookEntry(), buildUpdateBannerPromptText(); chained into
  installAllRuntimes() so finalize() receives both flags. updateBannerCommand
  computed alongside the other JS-hook commands; finishInstall() registers
  the SessionStart entry only when shouldInstallBanner === true and the
  hook file is present at the target.
- Hook ships in scripts/build-hooks.js HOOKS_TO_COPY, listed in
  MANAGED_HOOKS for stale-detection in gsd-check-update-worker.js, in the
  uninstall hook-removal lists in install.js, and in the
  rewriteLegacyManagedNodeHookCommands allowlist.

Tests:
- tests/feat-2795-update-banner.test.cjs — 22 tests, structural-IR
  assertions on parsed JSON envelopes (no raw-text matching). Covers
  pure-function branches (cache present/absent, parseError, rate-limit
  suppression, missing version fields), end-to-end hook invocation against
  fixture cache states, and install.js wiring (prompt text, input parsing,
  hook entry shape).
- tests/trae-install.test.cjs — updated install() return-shape assertion to
  include updateBannerCommand: null for the no-settings runtime.
- 6881/6881 tests pass.

Docs (bundled in same commit per the bundle-docs-with-code skill):
- docs/USER-GUIDE.md — new "Surface GSD Update Notifications Without GSD's
  Statusline" task section with opt-in/opt-out instructions.
- docs/FEATURES.md — REQ-HOOK-08 added; "Update Banner" subsection under
  the Hook System feature with cache flow + removal path.
- docs/INVENTORY.md — hook count 11 → 12, new row for gsd-update-banner.js.
- docs/INVENTORY-MANIFEST.json — regenerated.

Closes #2795

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(install): gate banner prompt on actual installability (CR #3035)

CodeRabbit findings on PR #3035:

- bin/install.js (Major): continueAfterStatusline gated banner prompt on
  the raw `shouldInstallStatusline` flag from handleStatusline. But
  finishInstall later silently skips the statusline write on local
  installs unless --force-statusline is set (#2248). Two consequences:
    1. Interactive local Claude/Gemini installs got neither a statusline
       nor a banner offer.
    2. Codex/Cursor/Copilot/Windsurf/Trae/Cline-only installs (where
       every result.updateBannerCommand is null) still got prompted even
       though the choice was silently ignored.
  Fix: derive willInstallStatusline = shouldInstallStatusline &&
  (isGlobal || forceStatusline), and gate the banner prompt on a
  canInstallBanner precondition computed from results[].updateBannerCommand.
  Pass the raw shouldInstallStatusline through to finalize unchanged so
  per-runtime statusline gating in finishInstall is unaffected.

- tests/feat-2795-update-banner.test.cjs (Minor): rate-limit suppression
  test parsed r1.stdout without first asserting r1.status === 0. Other
  e2e tests in this file (lines 210, 241) do this. A non-zero exit would
  surface as a cryptic SyntaxError instead of a status assertion failure.
  Fix applied verbatim.

6881/6881 tests pass.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-02 16:33:16 -04:00
Tom Boucher
35fffe7f31 docs(out-of-scope): record #2758 agent-template-rendering decision
Closed on the technical merits: the determinism claim is theoretical (no
observed misinterpretation), token waste is small and unmeasured, and PR
#2279's orchestrator-embedding path already serves the deterministic-gating
need without a parallel templating subsystem.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-02 15:56:24 -04:00
Tom Boucher
d137ce86ec docs(out-of-scope): record #2756 temporal-context decision
Reporter did not return to clarify the actual ask after the narrowing-then-
retraction in the comment thread. Closing as wontfix per .out-of-scope/
temporal-context.md with re-open criteria spelled out.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-02 15:53:08 -04:00
Tom Boucher
8c43ba7301 docs(#3025): MCP tool schema as a context-budget concern (#3032)
* docs(#3025): MCP tool schema as a context-budget concern

Adds documentation covering the largest GSD cost lever that GSD
itself does not own: MCP tool schema injection. Every enabled MCP
server adds its schema to every turn (often 20k+ tokens for
heavyweight servers like browser/playwright, mac-tools, etc.),
which can dwarf whatever `model_profile` tuning saves.

Two doc surfaces (per the bundle-docs-with-code skill depth gradient):

1. get-shit-done/references/context-budget.md
   - New "MCP Tool Schema Cost (Harness Concern)" section.
   - Explains schemas-per-turn cost framing.
   - Names enabledMcpjsonServers / disabledMcpjsonServers and
     .claude/settings.json explicitly.
   - Pre-phase audit checklist: browser/playwright, platform-specific,
     cross-project/stale, duplicate/shadow.
   - Explicit "GSD does not manage MCP enablement — harness concern"
     statement so users don't hunt for a GSD setting.
   - Links to Anthropic Claude Code MCP docs as canonical reference.
   - Notes compounding interaction with model_profile (additive levers).

2. docs/USER-GUIDE.md
   - New task-oriented "Trim MCP servers to reduce per-turn cost"
     section above "Using Non-Claude Runtimes".
   - Same checklist condensed.
   - Cross-link to context-budget.md for the full reference.

Tests:
- tests/feat-3025-mcp-token-budget-docs.test.cjs (12 cases) parses
  both docs into typed semantic-flag records and asserts behavioral
  invariants (mentions key, includes audit, names harness, etc.)
  rather than substring-matching prose. Adheres to CONTRIBUTING.md
  no-source-grep — section can be reworded freely as long as the
  required semantics survive.
- Markdownlint pre-flight tests (MD040 fence language, MD056 table
  column count) per the bundle-docs-with-code skill so CR can't
  ratchet on prose nitpicks across multiple review rounds.

Verification:
- 12/12 pass on regression test
- 6857/6857 full suite (12 net new)
- lint-no-source-grep clean (377 test files)

Companion to #3023 (per-phase-type model map) and #3024 (dynamic
routing). Together they cover the three biggest cost levers users
ask about; this issue covers the one GSD does not own.

Closes #3025

* docs(#3025): batch 3 CR fixes — pr id, relative link, named flag

CodeRabbit on PR #3032 (3 minor — 2 inline + 1 nitpick), all in one
push per the bundle-docs-with-code skill (avoid per-round nitpick
ratchet):

1. Inline (Minor) — .changeset/mcp-token-budget-docs.md:3
   `pr: TBD` → `pr: 3032` so changeset tooling can link the entry.

2. Inline (Minor) — docs/USER-GUIDE.md:1101
   Used a hardcoded `https://github.com/.../blob/main/...` URL for the
   cross-link to `context-budget.md`. Rest of USER-GUIDE.md uses
   relative links. Switched to `../get-shit-done/references/context-
   budget.md#mcp-tool-schema-cost-harness-concern` so feature-branch
   work shows the right content and rename-resilience is preserved.

3. Nitpick — tests/feat-3025-mcp-token-budget-docs.test.cjs:234
   The cross-link assertion used an inline `/context-budget/i.test(...)`
   while every other invariant in the file lived as a named flag in
   `parseMcpBudgetSection`. Per CONTRIBUTING.md no-source-grep, added
   `crossLinksContextBudget` to the parser and asserted on
   `parsed.crossLinksContextBudget` so the cross-link rule sits next
   to its siblings.

Verification:
- 12/12 pass on regression test (no count change; refactor only)
- No source code changes, only docs + tests

* test(#3025): strip inline markdown before phrase-match (CR nitpick)

CodeRabbit caught that the `explainsHarnessNotGsd` primary regex
branch couldn't match "GSD does **not** manage" in
context-budget.md because the markdown bold markers (`**`) sit
between contiguous words. The test passed today only via the
fallback `harness (concern|setting|controlled)` branch — the
primary branch was effectively dead code.

Fix: strip inline markdown emphasis (`**`, `*`, `~~`) and inline-
code backticks before any phrase-matching in `parseMcpBudgetSection`.
All seven flag computations now run against the stripped text so
markdown formatting can't silently invalidate any invariant.

Underscores are intentionally NOT stripped — `model_profile` and
other snake_case identifiers must survive intact for the
mentionsModelProfileInteraction check to find them.

Verification: 12/12 still pass; primary branches now fire on
real markdown content rather than relying on fallbacks.

* test(#3025): guard markdownlint tests against null section (CR nitpick)

CodeRabbit caught that the MD040 and MD056 markdownlint pre-flight
tests called `section.match(...)` and `section.split('\n')`
directly on the value returned by `extractSection`, which returns
null when no matching header is found. If the MCP section is ever
removed (regression), both tests would throw `TypeError: Cannot
read properties of null` instead of producing a clean assertion
failure naming the actual problem.

The semantic tests above are protected because parseMcpBudgetSection
short-circuits to a typed-falsy record on null input. The
markdownlint tests bypassed that guard since they need raw section
text, not parsed flags. Added `assert.ok(section, ...)` preconditions
to both so a missing section produces a meaningful failure message.

No content changes; defensive programming only.

Verification: 12/12 still pass.
2026-05-02 15:24:26 -04:00
Tom Boucher
e1d661ece0 feat(#3024): dynamic routing with failure-tier escalation (#3031)
* feat(#3024): dynamic routing with failure-tier escalation

Adds a `dynamic_routing` block to .planning/config.json that lets
the resolver start agents on a cheap tier and escalate one tier up
when the orchestrator detects a soft failure (verification
inconclusive, plan-check FLAG, etc.). Solves the "pay Opus rates as
insurance" anti-pattern by making escalation observed-quality-driven.

Architecture:
- AGENT_DEFAULT_TIERS map (light/standard/heavy) — every agent in
  MODEL_PROFILES declares a default tier; tests assert coverage
  so adding a new agent without updating the map fails CI.
- nextTier(currentTier) helper — light → standard → heavy → heavy
  (heavy stays at heavy; can't go further).
- resolveModelForTier(cwd, agentType, attempt) — new resolver. The
  orchestrator tracks the attempt counter and passes 0 for the
  first spawn, 1+ on escalation. The resolver caps internally at
  max_escalations so the orchestrator can blindly bump the counter.
- Schema validation: dynamic_routing.enabled / escalate_on_failure /
  max_escalations / tier_models.<light|standard|heavy>. Unknown
  tiers and unknown sub-keys rejected at config-set time.
- SDK schema mirror updated to keep CJS/SDK in lockstep (#2653).

Resolution precedence (highest → lowest):
  1. model_overrides[<agent>]              (full IDs accepted)
  2. dynamic_routing.tier_models[<tier>]   (NEW; escalation-aware)
  3. models[<phase_type>]                  (#3023 phase-type map)
  4. model_profile                         (per-agent column)
  5. Runtime default

Backward compatibility: dynamic_routing is disabled by default
(enabled: false or block omitted). resolveModelForTier short-
circuits to resolveModelInternal in that case, so callers can
adopt unconditionally without breaking existing behavior.

This PR delivers the JS-layer infrastructure: schema + tier map +
resolver. Orchestrator adoption (workflow markdown updates that
detect soft failures and call resolveModelForTier with attempt+1)
is incremental follow-up — verifier / plan-checker / integration-
checker each adopt the protocol when ready.

Tests (23 cases, all structural-IR — no stdout grep):
- Schema invariants: AGENT_DEFAULT_TIERS coverage, VALID_AGENT_TIERS
  exact match, every assignment uses a valid tier
- nextTier helper: light→standard→heavy→heavy, null on invalid input
- Disabled mode: no block + enabled:false both no-op (back-compat)
- Enabled mode: attempt=0 returns default tier model, attempt=1
  escalates, beyond max_escalations caps, heavy agents stay heavy,
  default max_escalations=1 when omitted
- Precedence: per-agent override beats dynamic_routing,
  dynamic_routing beats phase-type models
- Validation: every settings key accepted, unknown tiers/sub-keys
  rejected, bare `dynamic_routing` rejected as config-set target

Documentation:
- get-shit-done/references/model-profiles.md — full reference section
- docs/CONFIGURATION.md — full settings table + escalation flow
- docs/USER-GUIDE.md — task-oriented "Cheap-by-default" section
- docs/FEATURES.md — config row cross-link

Verification:
- 23/23 pass on regression test
- 6843/6843 full suite (23 net new from 6820)
- lint-no-source-grep clean (376 test files)
- SDK schema mirror keeps CJS/SDK in sync per #2653 parity test

Closes #3024

* fix(#3024): honor escalate_on_failure:false + 3 CR follow-ups

CodeRabbit on PR #3031 (4 findings — 1 Major + 2 Minor + 1 Nitpick):

1. **Major (inline)** — get-shit-done/bin/lib/core.cjs:1668
   resolveModelForTier ignored dynamic_routing.escalate_on_failure.
   When the user set it to false, escalation should be disabled, but
   the resolver only checked attempt/max_escalations. An orchestrator
   that always passes attempt+1 on retry would silently escalate
   despite the user opting out.
   Fix: gate effectiveAttempt on `dr.escalate_on_failure !== false`
   so false short-circuits every attempt back to the default tier.

2. **Minor (inline)** — docs/CONFIGURATION.md:123-126
   The dynamic_routing rows in the Core Settings table had 4 cells
   instead of 5 (missing the Options column), breaking the table
   structure. Added explicit Options values for enabled / escalate_on_failure
   / max_escalations rows.

3. **Minor (outside-diff)** — references/model-profiles.md:179-195
   "Resolution Logic" sketch was pre-#3024 and didn't include
   dynamic_routing in the precedence ladder. Updated to a 6-step
   block with dynamic_routing at step 3 (between override and
   phase-type).

4. **Nitpick** — tests/feat-3024-dynamic-routing.test.cjs:189+
   Tests used `if (lightAgent) { ... }` guards that silent-pass
   when AGENT_DEFAULT_TIERS drifts. Replaced all 5 conditional
   skips with `assert.ok(lightAgent, '...')` preconditions so a
   tier-mapping change surfaces as a test failure.

Plus: 2 new regression tests for the Major fix:
- escalate_on_failure:false caps every attempt at default tier
- escalate_on_failure:true (explicit) still escalates normally

Verification:
- 25/25 pass on regression test (23 prior + 2 escalate_on_failure)
- 6845/6845 full suite (2 net new)
- lint-no-source-grep clean

* docs(#3024): align precedence + add fence language tags (CR follow-up)

CodeRabbit (3 minor):

1. docs/CONFIGURATION.md:691 — "Per-Phase-Type Models → Resolution
   precedence" was a 4-step block written pre-#3024; readers got
   contradictory rules between the per-phase-type section and the
   later dynamic_routing section. Updated to the same 5-step ladder
   with dynamic_routing at step 2, and noted that dynamic_routing
   is disabled by default so this section's behavior is unchanged
   when the kill-switch is off.

2. docs/CONFIGURATION.md:770 — escalation-flow code fence missing
   language tag (MD040). Added `text`.

3. references/model-profiles.md:184 — resolution-ladder code fence
   missing language tag (MD040). Added `text`.

No code changes; docs only. Verification: regression test still 25/25.

* docs(#3024): clarify precedence prose — five layers, not four (CR nitpick)

CodeRabbit nitpick: the "Per-Phase-Type Models → Resolution
precedence" prose said "The four layers compose..." but the ladder
above lists five (including Runtime default). Also "dynamic_routing
escalates per-attempt above all of them" misreads as suggesting
dynamic_routing wins over model_overrides — actually overrides still
win at step 1.

Reworded top-down so the precedence direction is unambiguous:
  - model_profile = base
  - models = phase-level override
  - dynamic_routing = per-attempt escalation
  - model_overrides = per-agent exception (top)
  - runtime default = fallback

No code changes; docs only.

* docs(#3024): note escalate_on_failure:false in escalation-flow diagram (CR)

CodeRabbit nitpick: the escalation-flow diagram in
docs/CONFIGURATION.md described the soft-failure → respawn →
tier_models[next_tier_up] path, but didn't surface the
`dynamic_routing.escalate_on_failure: false` kill-switch right next
to it. Users reading the flow diagram (which is the canonical place
to understand attempt behavior) wouldn't see that the kill-switch
overrides the soft-failure branch.

Added a one-paragraph note immediately after the flow listing,
before the tier-sequence example, so the kill-switch is visible
exactly where users decide whether escalation will happen.

No code changes; docs only.
2026-05-02 14:26:35 -04:00
Tom Boucher
d812c66020 feat(#3023): per-phase-type model map in .planning/config.json (#3030)
* feat(#3023): per-phase-type model map in .planning/config.json

Adds a new `models` block to .planning/config.json with six phase-type
slots (planning / discuss / research / execution / verification /
completion). Lets users express coarse tuning ("Opus for planning,
Sonnet for the rest") without learning the agent taxonomy.

Resolution precedence (highest → lowest):
  1. Per-agent `model_overrides[agent]`     (full IDs; targeted exception)
  2. Phase-type `models[phase_type]`         (NEW; tier alias)
  3. Profile table (`model_profile`)          (per-agent column)
  4. Runtime default

The three layers compose: `models` defaults a phase, `model_overrides`
carves an exception. Phase-type values are tier aliases (opus/sonnet/
haiku/inherit) so the runtime-resolution chain (#2517) stays correct
end-to-end without further branching.

Implementation:
- model-profiles.cjs: new AGENT_TO_PHASE_TYPE map + VALID_PHASE_TYPES
  set. Each agent in MODEL_PROFILES gets one phase-type assignment;
  tests assert coverage so adding a new agent without updating the
  table fails CI.
- core.cjs (resolveModelInternal): inserts phase-type tier lookup
  between per-agent override and profile-derived tier. Skips runtime
  resolution when the resolved tier is 'inherit' (was previously gated
  only on profile === 'inherit'; phase-type can now produce inherit
  independently).
- core.cjs (loadConfig): pass `parsed.models` through both code paths
  so resolveModelInternal can read it.
- config-schema.cjs + sdk/src/query/config-schema.ts: dynamic-pattern
  validator accepts only the six known phase-types; unknown slots
  rejected at config-set time.

Backward compat: configs without `models` behave exactly as today.

Tests (15 cases, all structural-IR — no stdout grep):
- Schema: AGENT_TO_PHASE_TYPE coverage, VALID_PHASE_TYPES exact match
- Resolver: phase-type alone; per-agent override beats phase-type;
  phase-type beats profile; issue's full example; "inherit"; empty
  block is no-op; no block is no-op
- Validation: each of the 6 slots accepted; unknown slot rejected;
  bare `models` (no slot) rejected

Verification:
- 15/15 pass on new regression test
- 6808/6808 full suite (5 net new), 0 fail
- lint-no-source-grep clean across 375 test files

Closes #3023

* docs(#3023): document `models` per-phase-type config in user-facing docs

Adds `models` block coverage to the three user-facing docs that ship
with each release:

1. docs/CONFIGURATION.md
   - New "Per-Phase-Type Models" section between "Per-Agent Overrides"
     and "Non-Claude Runtimes" with:
       * full example mixing models + model_overrides
       * phase-type → agent mapping table
       * resolution-precedence pseudocode
       * accepted values (tier alias only)
       * "When to use which" decision matrix
       * validation behavior + example error
   - Added `"models": {}` to the Full Schema snippet
   - Added a row for `models.<phase_type>` to the config keys table
     (next to model_profile_overrides for adjacency)

2. docs/FEATURES.md
   - Added a row for models.<phase_type> in the Configurable Settings
     table (right under model_profile)
   - Cross-link to CONFIGURATION.md for the full surface

3. docs/USER-GUIDE.md
   - New task-oriented "Tuning model cost by phase" section above
     "Using Non-Claude Runtimes" — leads with the concrete config
     and shows the override pattern (one-shot phase + targeted exception)
   - Cross-link to CONFIGURATION.md

Verification:
- 29/29 pass on config-schema-docs-parity + docs-update + new feature
  test (parity-check passes, so the config-schema entry I added in the
  feature commit is now matched by a docs row)
- 6808/6808 full suite pass
- lint-no-source-grep clean

Doc style follows the same pattern used by the existing model_profile,
model_overrides, and model_profile_overrides sections — example-led,
table-backed, cross-referenced. Each doc surfaces the feature at the
right depth (reference / settings table / task guide).

* fix(#3023): mirror phase-type tier in resolveReasoningEffortInternal (CR Major)

CodeRabbit caught a real Codex correctness bug + 3 minor docs/test issues:

1. **Major (outside-diff)** — resolveReasoningEffortInternal in core.cjs
   derived its tier exclusively from the profile table, ignoring the
   models.<phase_type> override added in #3023. Failure mode on Codex:

     Config: model_profile=balanced, models.execution=opus, agent=gsd-executor
     resolveModelInternal:           tier=opus    → gpt-5.4
     resolveReasoningEffortInternal: tier=sonnet  → reasoning_effort=medium
                                                     ↑
                                                  WRONG — should be xhigh
                                                  (opus tier on Codex)

   The runtime received a mismatched (model, effort) pair. Mirrored the
   phase-type lookup from resolveModelInternal so both functions derive
   from the same tier source. 'inherit' phase-type returns null effort
   (no runtime entry maps to 'inherit'; let runtime decide).

2. Minor — .changeset/per-phase-type-models.md `pr: TBD` → `pr: 3030`.

3. Minor (outside-diff) — model-profiles.md "Resolution Logic" section
   omitted the new phase-type tier. Updated the 4-step block to a 5-step
   block including `models[phase_type]` between override and profile,
   plus a paragraph noting that `model` and `reasoning_effort` derive
   from the same tier source.

4. Nitpick — added 2 typo-safety tests:
   - models.research = "haiku3" (typo) → falls through to profile
   - models.research = "openai/gpt-5" (full ID) → falls through to profile
   Plus 5 new reasoning_effort tests covering the Major fix:
   - exported correctly
   - phase-type override flips both model AND effort to same tier
   - inherit phase-type returns null effort
   - per-agent override still bypasses phase-type for effort
   - claude runtime ignores models.* (no effort propagation)

Verification:
- 24/24 pass on regression test (15 original + 2 typo-safety + 5 effort + 2 outside-diff related)
- 6815/6815 full suite (7 net new from 6808)
- lint-no-source-grep clean

The reasoning_effort tests are written semantically (phase-type override
must produce the SAME effort as a profile-only opus config) rather than
hard-coding tier-specific effort strings, so changes to the runtime tier
map don't break them.

* fix(#3023): phase-type override beats profile=inherit (CR Major round 2)

CodeRabbit caught another precedence inversion: when
  { model_profile: 'inherit', models: { execution: 'opus' } }
both resolvers short-circuited on `profile === 'inherit'` BEFORE the
phase-type override could be honored. Result: model returned 'inherit'
and reasoning_effort returned null — both contradicting the documented
precedence where models[phase_type] wins over model_profile.

Fix in resolveModelInternal:
- Compute tier from phase-type FIRST. If phase-type is a valid alias,
  it wins. Otherwise, fall back to profile-derived tier OR 'inherit'
  (when profile === 'inherit').
- Gate the runtime-resolution branch on `tier !== 'inherit'` (was
  `profile !== 'inherit'`) so phase-type=opus can flip runtime mapping
  on even when profile=inherit.
- Gate the inherit-return on `tier === 'inherit'` (was
  `profile === 'inherit'`).

Fix in resolveReasoningEffortInternal:
- Remove the `if (profile === 'inherit') return null;` early-return.
- Compute tier from phase-type first, fall back to profile. If
  phase-type is explicitly 'inherit' OR the resolved tier is 'inherit',
  return null (no runtime entry maps to inherit).

Tests added (5 new):
- model: phase-type wins over profile=inherit (with explicit opus, with
  haiku for one phase + planner-without-slot still inheriting)
- model: profile=inherit + no models block → all agents inherit (no
  regression on existing inherit semantics)
- model: profile=inherit + models block but agent has no slot → that
  agent inherits, agents with slots get phase-type tier
- effort: phase-type opus + profile=inherit → produces opus-tier
  effort, NOT null (the original bug)

Verification:
- 27/27 pass on regression test (24 prior + 3 model + 1 effort)
- 6820/6820 full suite (5 net new)
- lint-no-source-grep clean

The effort test reads the expected value by running a profile-only opus
config and comparing — semantic check, not hard-coded effort string. So
runtime tier map changes don't break the test.
2026-05-02 13:19:15 -04:00
Tom Boucher
c9f5b7daac fix(#3020): probe user shell PATH at install-time, not just process.env.PATH (#3028)
* fix(#3020): probe user shell PATH at install-time, not just process.env.PATH

The installer's "✓ GSD SDK ready" message was a false positive whenever
the install subprocess's process.env.PATH contained the gsd-sdk shim
but the user's later interactive shells did not. Three known sources
of mismatch on POSIX:

- ~/.local/bin: install subprocess inherits npm/npx-injected PATH;
  user's login shell may not add ~/.local/bin if .profile/.bashrc/
  .zshrc don't.
- nvm/fnm/volta: node version managers shim PATH per-shell, so
  `npm prefix -g` from inside the install subprocess can resolve to
  a different bin dir than the user's interactive shell sees.
- npm-prefix tooling: some installers inject extra PATH entries that
  vanish in fresh sessions.

Result reported on #3011 by @x0rk and @stefanoginella: install prints
✓, but every workflow invocation later fails with
"bash: gsd-sdk: command not found".

Fix:

- isGsdSdkOnPath(pathString?) — now accepts an explicit PATH string.
  Zero-arg form preserves existing behavior (reads process.env.PATH).
  Pure walk, no spawn. Lets callers verify against any PATH source.

- getUserShellPath() — new helper. Probes the user's login shell via
  `$SHELL -lc 'printf %s "$PATH"'` (POSIX). 2-second timeout so a
  misconfigured rc file can't hang the install. Returns null on
  Windows (cross-shell PATH probing requires a different strategy
  per Git Bash / PowerShell / cmd.exe — tracked separately) or when
  the probe fails; callers fall back to process.env.PATH in that case.

- installSdkIfNeeded() — after the existing isGsdSdkOnPath() check
  passes, also verify the shim is reachable from getUserShellPath()
  on POSIX. If install-PATH and user-shell-PATH disagree, downgrade
  to the actionable ⚠ diagnostic from PR #3014 (which has the shim
  location, shell-specific PATH-update commands, and an npx fallback
  note). Routing affected users into PR #3014's diagnostic is the
  point — not silently green-then-red.

Tests:
- bug-3020-install-shell-path-probe.test.cjs (10 tests, structural):
  - isGsdSdkOnPath accepts an explicit PATH (true/false on fixture
    PATH dirs with/without an executable shim)
  - zero-arg form returns a boolean
  - empty string PATH → false
  - getUserShellPath returns string-or-null
  - returns null on Windows
  - returns null when $SHELL unset on POSIX
  - cross-shell mismatch detection: install-PATH and user-PATH that
    differ produce different isGsdSdkOnPath results — the invariant
    the install-time check now exploits
- All assertions on structural records, not console output. Adheres
  to typed-IR / CONTRIBUTING.md "Prohibited: Raw Text Matching".

Verification:
- 10/10 pass on new regression test
- 6768/6768 pass on full suite (5 net-new tests)
- lint-no-source-grep clean

Windows cross-shell coverage (gsd-sdk.cmd resolves under PowerShell
but not Git Bash without a no-extension sibling) is tracked separately
— this PR is the POSIX-side fix and the Windows scaffolding (the
optional pathString arg on isGsdSdkOnPath) that a Windows fix can
build on.

Closes #3020

* fix(#3020): type-guard pathString, last-line PATH parse (CR)

CodeRabbit on PR #3028 (4 findings — 3 actionable + 1 nitpick):

1. .changeset/install-shell-path-probe.md (2 findings):
   - `pr: TBD` → `pr: 3028`
   - Doc said `echo $PATH` but impl uses `printf %s "$PATH"` (chosen
     to avoid shell-dependent echo behavior, e.g. interpreting `-n`).
     Aligned changeset prose with implementation.

2. bin/install.js:9176 — isGsdSdkOnPath(pathString) used
   `pathString !== undefined` to gate the explicit-PATH branch, but
   getUserShellPath() can return null and `null.split()` throws.
   Tightened to `typeof pathString === 'string'` so null / number /
   object inputs fall back to process.env.PATH. Added 2 regression
   tests covering the null and non-string cases.

3. bin/install.js:9232 — getUserShellPath trimmed entire stdout. A
   misconfigured rc file that prints a banner / motd / log line
   BEFORE the printf would pollute the result and incorrectly flip
   the cross-shell check to false. Take the LAST non-empty line
   (PATH itself is single-line) so noise can't hijack the probe.

4. Nitpick: the changeset PR placeholder — covered by (1).

Verification: 12/12 pass on regression test (10 original + 2 new
type-guard tests), 6770/6770 full suite, lint clean.

* docs(#3020): JSDoc references printf %s "$PATH", not echo $PATH (CR)

CodeRabbit caught two stale JSDoc references that still said
`$SHELL -lc 'echo $PATH'` while the implementation uses
`$SHELL -lc 'printf %s "$PATH"'`. echo is undesirable here because:

- POSIX echo's behavior with `-n` / backslash escapes varies across
  shells (bash builtin vs /bin/echo vs zsh) and can introduce
  trailing-newline pollution that the per-line trim now papers over.
- printf is portable and emits exactly the bytes given.

Synced both stale doc strings:
  - bin/install.js:9211 (getUserShellPath JSDoc)
  - tests/bug-3020-install-shell-path-probe.test.cjs:27 (header)

No behavior change — implementation already uses printf.
2026-05-02 11:45:39 -04:00
Tom Boucher
6df9b44297 fix(#3018): codex adapter must stop and ask, not silently default decisions (#3027)
* fix(#3018): codex adapter must stop and ask, not silently default decisions

@jon-hendry: running `\$gsd-discuss-phase 81` in Codex Default mode
proceeded toward writing CONTEXT.md / DISCUSSION-LOG.md / checkpoint
artifacts without surfacing the discussion questions to the user. The
generated Codex skill adapter explicitly told it to do that:

  Execute mode fallback:
  - When `request_user_input` is rejected (Execute mode), present a
    plain-text numbered list and pick a reasonable default.

That instruction is wrong for any workflow whose contract is to
discuss with the user (most prominently `$gsd-discuss-phase`). The
fallback now requires the agent to:

1. STOP. Present the questions as a plain-text numbered list, then
   wait for the user's reply.
2. Only proceed without a user answer when one of these is true:
   (a) invocation included --auto / --all,
   (b) user explicitly approved a default for this question, or
   (c) workflow's documented contract permits autonomous defaults.
3. Do NOT write CONTEXT.md, DISCUSSION-LOG.md, PLAN.md, or checkpoint
   files until the user has answered or one of (a)-(c) above applies.

Tests:
- bug-3018-codex-discuss-fallback.test.cjs (5 tests, structural-IR):
  parses the generated header into sections via regex,  asserts on
  the Execute-mode-fallback section's content (must contain stop/
  wait + plain-text directives, must NOT contain "pick a reasonable
  default", must name a permission path, must forbid artifact
  writing). No raw text snapshot — the assertions describe the
  behavioral invariant, so prose can be reworded without test churn.
- codex-config.test.cjs:128 still passes — section still mentions
  "Execute mode" as required.

Verification:
- 5/5 pass on new regression test
- 116/116 pass on bug-3018 + codex-config combined
- 6763/6763 pass on full suite
- lint-no-source-grep clean

Closes #3018

* test(#3018): parse fallback into typed semantic-flag record (CR)

CodeRabbit nitpick on PR #3027: the regression tests grepped the
generated header prose with regex, which is brittle and tests wording
rather than semantics. Per CONTRIBUTING.md "no-source-grep" standard.

Refactored to a structural-IR shape:

- New `parseExecuteModeFallback(section)` walks the section text once
  and returns a typed record:
    {
      ok, sectionLength,
      instructsStop,                          // STOP/HALT/WAIT directive
      presentsPlainTextQuestions,             // plain-text / numbered list
      namesPermissionPath,                    // --auto / --all / explicit approval
      forbidsWritingArtifactsBeforeAnswer,    // write-ban + named artifact class
      silentlyPicksDefaults,                  // anti-pattern guard (must be false)
    }
- Each positive invariant gets its own test asserting on the parsed
  boolean, so a failure points at the exact invariant that broke.
- A final test does a single assert.deepStrictEqual against the full
  expected contract — gives a structured diff when any flag flips.
- The artifact-write ban now requires BOTH a "do not write" intent
  AND a named artifact class (was a single broad regex), so generic
  "do not write" prose elsewhere in the section can't satisfy it.

Verification: 8/8 pass; lint-no-source-grep clean.
2026-05-02 11:45:36 -04:00
Tom Boucher
e3b64b39f8 fix(#3019): query --help reaches handler instead of short-circuiting (#3026)
* fix(#3019): query --help reaches handler instead of short-circuiting to top-level usage

The query argv parser in sdk/src/cli.ts harvested -h/--help as a global
flag and main() short-circuited dispatch when args.help was true. Net
effect: every `gsd-sdk query <anything> --help` printed top-level USAGE
instead of contextual subcommand help. There was no path for users to
discover what arguments a query subcommand accepts — they had to trigger
"required" errors by trial and error.

Two-layer fix:

1. sdk/src/cli.ts (parseCliArgsQueryPermissive)
   - Push -h / --help onto queryArgv instead of consuming them silently,
     so the registered handler / gsd-tools.cjs fallback gets to interpret
     the flag and render contextual help.
   - Only honor the global help flag when there is NO real subcommand to
     dispatch to (i.e. queryArgv contains only help flags). Preserves
     `gsd-sdk query --help` → top-level USAGE while letting
     `gsd-sdk query phase add --help` reach the handler.

2. get-shit-done/bin/gsd-tools.cjs
   - Render top-level usage on --help / -h / -? / --usage instead of
     erroring with "Unknown flag". The discovery hint in the usage text
     points users at the working method (run without args → error names
     required arguments) and references #3019 for tracking subcommand-
     level help printers.
   - --version remains rejected (no discovery use-case).

#1818 anti-hallucination invariant preserved: the destructive command
NEVER executes when --help is present. The new shape returns success:true
+ usage on stdout instead of the old success:false + error on stderr —
both satisfy "destructive command did not run", and the new shape also
restores discoverability.

Tests:
- sdk/src/cli.test.ts: 4 new vitest cases covering #3019 — query argv
  parser keeps --help with subcommand, parses -h short flag, preserves
  bare `query --help` top-level behavior, preserves --help position when
  intermixed with other query flags.
- tests/bug-3019-help-passthrough.test.cjs: 5 node:test cases on the
  fallback — bare gsd-tools (no args) errors with usage; --help renders
  usage on stdout exit 0; -h same; subcommand --help renders usage; usage
  hint mentions discovery method (without prose substring matching —
  parses into typed sections).
- tests/bug-1818-unknown-flags.test.cjs: rewritten to assert the new
  invariant ("destructive command did not run" + "usage was rendered")
  instead of the old shape ("--help is rejected with non-zero exit").
  Each destructive test seeds a sentinel artifact (phase dir, slug
  output) and asserts it survives.

Verification:
- 47/47 vitest pass on sdk/src/cli.test.ts
- 5/5 pass on tests/bug-3019-help-passthrough.test.cjs
- 8/8 pass on tests/bug-1818-unknown-flags.test.cjs (rewritten)
- 6763/6763 pass on full node:test suite
- lint-no-source-grep clean (0 violations)

Closes #3019

* fix(#3019): SDK fallback forwards plain-text help, broader usage list (CR)

CodeRabbit on PR #3026 (4 findings — 1 Major outside-diff, 2 inline,
1 nitpick):

1. **Major outside-diff** — sdk/src/cli.ts:442-454. The fallback path
   that delegates to gsd-tools.cjs called parseCliQueryJsonOutput
   (JSON.parse) on stdout. Now that gsd-tools renders plain-text usage
   on --help, JSON.parse threw "Unexpected token 'U'". Wrapped the
   parse in try/catch — on parse failure, forward the plain stdout
   verbatim so subcommand help reaches the user. Regression test:
   tests/bug-3019-help-passthrough.test.cjs spawns the built SDK and
   asserts `gsd-sdk query phase --help` exits 0, stdout contains the
   gsd-tools usage, and stderr does NOT contain a JSON-parse error.

2. .changeset/help-passthrough.md:3 — `pr: TBD` → `pr: 3026`.

3. gsd-tools.cjs:346 (TOP_LEVEL_USAGE):
   - Removed self-referencing `#3019` link (immediately stale after
     this PR merges).
   - Expanded Commands list from 17 → all 47 dispatcher cases:
     agent-skills, audit-open, audit-uat, check-commit, commit, …
     phase, phases, roadmap, milestone, validate, progress, intel,
     graphify, learnings, etc. — the bulk of the surface that was
     previously unreachable via --help discovery.

4. Nitpick: `isUsageOutput` was duplicated in bug-1818 and
   bug-3019-help-passthrough tests. Moved to tests/helpers.cjs with
   structural-comment, removed both duplicates.

Verification: 47/47 vitest pass, 14/14 regression tests pass,
6764/6764 full suite, lint clean.

* test(#3019): use t.skip() instead of bare return when SDK not built (CR)

CodeRabbit follow-up on PR #3026:

The integration test guarded against missing sdk/dist/cli.js with a
bare `return;` — node:test counts that as a passing test (0 assertions
exercised, 0 failures). On a CI checkout that hasn't run the SDK build,
the #3026 regression test silently green-lit and no signal ever
surfaced that the integration check was skipped.

Switched to `t.skip(...)` via the test context parameter so the
omission shows up in the test report. The unit-level fix
(sdk/src/cli.ts) is still covered by vitest, so the skip only affects
the end-to-end spawn-built-SDK check.

Verification: 6/6 pass when SDK is built; 5 pass + 1 skip when not.
2026-05-02 11:45:33 -04:00
Tom Boucher
8e25eb6546 fix(#3017): codex SessionStart hook uses absolute node, not bare 'node' (#3022)
* fix(#3017): codex SessionStart hook uses absolute node, not bare 'node'

PR #3002 fixed #2979 for settings.json-based managed JS hooks (Claude
Code, Gemini, Antigravity) by routing through buildHookCommand() →
resolveNodeRunner(), emitting the absolute Node binary path so hooks
resolve under GUI/minimal-PATH runtimes (/usr/bin:/bin:/usr/sbin:/sbin)
where nvm/Homebrew/Volta-installed node is not on PATH.

The Codex install path bypassed both helpers — line 7935 of bin/install.js
wrote `command = "node ${path}"` directly into config.toml. So Codex
SessionStart hook still failed with exit 127 ("node: command not found")
under the same minimal-PATH conditions PR #3002 was meant to close.

Fix:
- Add buildCodexHookBlock(targetDir, { absoluteRunner, eol }) — a pure
  helper that emits the toml hook block with the absolute runner. Returns
  null when absoluteRunner is null so the caller skips registration with
  a warning instead of writing a broken bare-node hook.
- Add rewriteLegacyCodexHookBlock(content, absoluteRunner) — mirror of
  rewriteLegacyManagedNodeHookCommands for the toml surface, so
  reinstall migrates a 1.39.x bare-node config.toml to the absolute form.
  Uses basename equality (CODEX_MANAGED_HOOK_BASENAMES set) so user-
  authored bare-node hooks are left alone.
- Replace the inline string-concat at line 7935 with a call to the new
  helper, threaded with the detected line ending so CRLF files stay CRLF.
- On the codex reinstall path, call rewriteLegacyCodexHookBlock first so
  existing bare-node entries get migrated before the new entry is added.

Tests:
- bug-3017-codex-hook-absolute-node.test.cjs (9 tests, all typed-IR):
  - buildCodexHookBlock emits absolute runner, parses to expected fields
  - returns null on missing runner (caller skips)
  - integrates with resolveNodeRunner() in the live process
  - rewriteLegacyCodexHookBlock migrates managed bare-node entries
  - leaves user-authored bare-node hooks alone (basename allowlist)
  - leaves entries with absolute runner unchanged (idempotent)
  - returns content unchanged when absoluteRunner is null
- codex-config.test.cjs e2e expectation updated to match new shape:
  parsed.hooks.SessionStart[0].hooks[0].command now equals
  '"<process.execPath>" "<hookPath>"' instead of 'node <hookPath>'.

Verification:
- 9/9 pass on the new regression test
- 179/179 pass across all codex-touching test files
- 6767/6767 pass on full suite, lint-no-source-grep clean
- Adheres to typed-IR / CONTRIBUTING.md "Prohibited: Raw Text Matching":
  parseCodexHookBlock returns a typed record; assertions are on
  structured fields (runner, hookPath, type, hasMarker), not stdout regex.

Closes #3017

* test(#3017): tighten runner assertions to exact process.execPath (CR)

CodeRabbit on PR #3022 (3 findings, 2 actionable + 1 nitpick):

1. .changeset/codex-bare-node-fix.md:3 — replace `pr: TBD` with
   `pr: 3022` so changeset metadata is traceable.

2. tests/bug-3017-codex-hook-absolute-node.test.cjs:81-146 — the test
   asserted `parsed.runner !== 'node'` and `parsed.runner.includes('/node')`,
   which would false-positive on any absolute path containing '/node'
   (e.g. /Users/x/notnode/foo). Tightened to compare against the EXACT
   absolute path supplied by the caller (after stripping toml + JSON
   escape layers via a new unescapeRunner() helper). The live-process
   integration test now compares against process.execPath exactly. The
   rewriteLegacyCodexHookBlock test also uses exact-equality.

3. Nitpick (skipped): use repository's TOML parser for parsing instead
   of bespoke regex. The hand-rolled parser is small, scoped, and
   fully tested by these structural assertions; pulling in a TOML lib
   for tests would create a circular dependency on the SUT (the
   installer's own parser). Leaving as-is.

Verification: 9/9 pass on regression test, 6767/6767 full suite, lint clean.
2026-05-02 11:45:30 -04:00
Tom Boucher
f2decefede fix(#3010): post-install message and docs use /gsd-update --reapply (#3012)
* fix(#3010): post-install message and docs use /gsd-update --reapply

PR #2824 consolidated 86 skills into ~58, removing the standalone
/gsd-reapply-patches command and folding it into a flag on /gsd-update
(/gsd-update --reapply). The 1.39.1 hotfix (#2954) updated help.md
but missed three other surfaces that still recommended the dead form:

1. bin/install.js reportLocalPatches() — runtime emitter shown after
   every install with backed-up patches. All branches updated:
   - claude/opencode/kilo/copilot: /gsd-update --reapply
   - gemini: /gsd:update --reapply
   - codex: $gsd-update --reapply
   - cursor: gsd-update --reapply (mention the skill name)

2. get-shit-done/workflows/update.md — Step 4 prose and the
   check_local_patches block both referenced /gsd-reapply-patches.
   Replaced with /gsd-update --reapply (with backticks around the
   command per CR feedback for copy/paste UX).

3. Localized docs (en/ja-JP/ko-KR/zh-CN) — 14 files across
   ARCHITECTURE.md / COMMANDS.md / FEATURES.md / INVENTORY.md /
   USER-GUIDE.md / manual-update.md still listed the removed command.

Tests:
- bug-3010-reapply-patches-references.test.cjs (4 tests): scans
  bin/install.js's reportLocalPatches body, every workflow file, and
  every doc (excluding CHANGELOG history and help.md's deprecation
  notice) for the removed command form, and verifies each runtime
  branch emits the consolidated form via captured console output.
- tests/copilot-install.test.cjs:1081-1115 — stale assertions that
  hard-coded the removed string updated to assert /gsd-update --reapply.

Verification: 115/115 pass across both files.

Co-authored-by: Patrick Clery <patrick@patrickclery.com>
Closes #3010

* test(#3010): broaden dead-command scan + tighten runtime exact-match

CodeRabbit follow-up findings on #3012:

1. Workflow + docs scans only matched "/gsd-reapply-patches", missing
   the gemini ("/gsd:reapply-patches") and codex ("$gsd-reapply-patches")
   spellings. A regression that re-introduced either form in localized
   docs would have passed silently. Extracted a DEAD_COMMAND_PATTERNS
   array + findDeadCommands() helper used by both scans, so all three
   removed forms are checked uniformly. Match output also reports which
   spellings hit, for faster diagnosis.

2. reportLocalPatches runtime test asserted output.includes('update --reapply'),
   which is too loose — a malformed prefix like '/gsd:update --reapply' on
   the claude branch would have passed. Replaced with an exact
   {runtime → expected token} map covering all 7 branches:
     claude/opencode/kilo/copilot → /gsd-update --reapply
     gemini → /gsd:update --reapply
     codex → $gsd-update --reapply
     cursor → gsd-update --reapply
   Negative assertion also runs DEAD_COMMAND_PATTERNS against output for
   every runtime, so dead forms can't slip in regardless of branch.

Verification: 4/4 pass on bug-3010-reapply-patches-references.test.cjs.

* test(#3010): add prefix-absence guard for cursor runtime (CR follow-up)

CodeRabbit (Minor): the cursor expected token "gsd-update --reapply" is
a substring of every prefixed form ("/gsd-update --reapply" for claude/
opencode/kilo/copilot, "\$gsd-update --reapply" for codex). The positive
output.includes(expectedToken) check therefore can't distinguish correct
cursor output from a regression where the installer emits a prefixed
form for cursor — both pass the substring check.

Add an explicit prefix-absence assertion for cursor that fails if any
of /, \$, or : appears immediately before "gsd-update --reapply" in
output. The gemini form ("/gsd:update --reapply") doesn't share the
substring (gsd:update vs gsd-update) so it's already caught by the
positive includes failing on cursor's expected bare token.

Verification: 4/4 pass.

---------

Co-authored-by: Patrick Clery <patrick@patrickclery.com>
2026-05-02 09:38:34 -04:00
Tom Boucher
a4e5cc7c24 fix(#3011): actionable SDK-not-on-PATH diagnostic with shim location and shell-specific commands (#3014)
* fix(#3011): actionable SDK-not-on-PATH diagnostic with shim location and shell-specific commands

The previous diagnostic was a generic 'GSD SDK files are present but
gsd-sdk is not on your PATH' message with no concrete path or
shell-specific PATH-export command. Windows users reported that they
couldn't find where the shim was written and didn't know how to add
it to PATH for each shell (PowerShell vs cmd.exe vs Git Bash vs WSL
all read PATH from different sources).

New formatSdkPathDiagnostic({ shimDir, platform, runDir }) helper
returns a typed IR:
- shimLocationLine: explicit 'Shim written to: <path>'
- actionLines: platform-specific PATH-export commands
  - Windows: 3 lines (PowerShell, cmd.exe, Git Bash with backslash->/
    translation for bash compatibility)
  - POSIX: 1 line (export PATH=...)
- npxNoteLines: 'you're running via npx ... npm install -g instead'
  when runDir is under an _npx cache segment (where the shim may be
  written to a temp dir that won't persist for the user's interactive
  shell)
- isNpx, isWin32: structured booleans for assertions

Renderer in install.js just emits each line. Tests assert on the
typed IR fields directly (no source-grep, no console-output parsing).

Tests: 12 cases across 5 suites covering Windows shell flavors
(PowerShell preserves backslashes, Git Bash translates to forward),
POSIX exports, null-shimDir fallback to npm install -g advice, npx
detection on both path-separator conventions, and IR shape contract.

Closes #3011

* fix(#3011): cmd.exe guidance uses powershell -Command, not setx

CodeRabbit flagged the cmd.exe action line as a Major Windows
correctness bug:

  setx PATH "${shimDir}; %PATH%"

Two failure modes:
1. setx silently truncates the registry value above 1024 chars,
   permanently storing the truncated PATH and breaking applications
   until restored from the registry backup or fixed manually.
2. %PATH% expands to its current literal value at the moment setx
   runs, and the result is written as REG_SZ instead of REG_EXPAND_SZ.
   Lazy references like %SystemRoot% are baked in as literals, so
   future changes to those variables stop propagating.

Replace with the same SetEnvironmentVariable call already used for
the PowerShell line, invoked through `powershell -Command` so cmd.exe
users get a safe command without us recommending two different APIs.

* fix(#3011): escape shimDir for PowerShell, bash, and POSIX export

CodeRabbit (Minor): a Windows username with a single quote (e.g.
"C:\Users\O'Neil\AppData\Roaming\npm") would interpolate raw into the
suggested commands, producing unparseable shell input the user can't
fix without understanding the bug.

Each shell context needs a different escape:

- PowerShell single-quoted strings: '' is the literal-quote escape.
  Apply to both the PowerShell line and the cmd.exe line (which
  delegates to PowerShell).

- Git Bash, where the path lives inside an outer single-quoted echo:
  '\'' (close-quote, escaped-quote, reopen-quote) embeds a literal
  single quote. The slash-conversion (\\ → /) still applies first.

- POSIX export (Linux/macOS) inside double quotes: escape \, $, ",
  and backtick so the path is copied verbatim. $PATH lives outside
  the escape and still expands at paste time.

Regression test: bug-3011-sdk-path-diagnostic.test.cjs locks in the
expected escape sequence for all three shell flavors.
2026-05-02 09:30:58 -04:00
Tom Boucher
f55069ecbf test(#2974): migrate 8 test files to typed-IR assertions (#3016)
* test(#2974): migrate 8 test files to typed-IR assertions

Replaces raw stdout/stderr substring matching with structured-field
assertions per CONTRIBUTING.md "Prohibited: Raw Text Matching on Test
Outputs". Adds shared infrastructure for typed error emission so this
pattern is the easy path going forward.

Shared infrastructure:
- core.cjs: ERROR_REASON frozen enum + setJsonErrorMode/getJsonErrorMode
- gsd-tools.cjs: --json-errors CLI flag, parsed before subcommand dispatch
- config.cjs: typed reasons at all 7 error sites
- graphify.cjs: GRAPHIFY_REASON enum + reason/timeout_ms in execGraphify result
- bin/install.js: pure buildSdkFailFastReport() IR builder + renderer
- hooks/gsd-session-state.sh, gsd-phase-boundary.sh: emit Claude Code
  hookSpecificOutput JSON envelope with typed state_present/config_mode/
  planning_modified/file_path fields (no-op when hooks.community is off)

Test migrations (all pass, 171 tests across the 8 files):
- bug-2649-sdk-fail-fast: assert on ir.reason / ir.context / ir.fix_command
- bug-2687-config-read-warning-parity: assert.equal stderr === ''
- bug-2796-arg-parsing-regression: assert on result.json.updated/.phase
- bug-2838-summary-rescue: parse rescue footer, assert mtime invariant
- bug-2943-config-get-context-window: parse JSON, assert ERROR_REASON.CONFIG_KEY_NOT_FOUND
- graphify: assert reason === GRAPHIFY_REASON.ENOENT/TIMEOUT
- hooks-opt-in: parse hookSpecificOutput, assert typed fields
- security-scan: reclassified as source-text-is-the-product (scan label
  output and CI workflow YAML ARE the deployed contract)

Verification: lint-no-source-grep clean (0 violations), full suite
6741/6741 pass.

Closes #2974

* test(#2974): address CR feedback — typed code field, robust idempotency

Two CodeRabbit findings on #3016 addressed:

1. tests/hooks-opt-in.test.cjs:355 (Minor, inline) —
   parsed.reason.includes('Conventional Commits') was still substring
   matching after the typed-IR migration. Fixed at the source: the
   gsd-validate-commit hook now emits a typed `code` field
   ('CONVENTIONAL_COMMITS_VIOLATION', 'COMMIT_SUBJECT_TOO_LONG')
   alongside the human-readable `reason`. Test asserts strictEqual
   on the code; the prose copy is no longer part of the test contract.

2. tests/bug-2838-summary-rescue-gitignored-planning.test.cjs:224-250
   (Outside-diff) — mtimeMs alone can stay unchanged on coarse-grained
   filesystems (HFS+, FAT) when two rewrites land within the same
   timestamp tick, falsely passing the idempotency assertion.
   Replaced with a full snapshot (mtimeMs, ctimeMs, size, ino, sha256
   of contents) compared via assert.deepStrictEqual — the hash
   catches any rewrite the timestamp would miss.

Verification: 30/30 pass on the two affected files; lint-no-source-grep
clean (0 violations across 368 test files).
2026-05-02 09:27:23 -04:00
Tom Boucher
de25400b70 fix(#2979): emit absolute node path in managed hooks for GUI/minimal-PATH runtimes (#3002)
* fix(#2979): emit absolute node path in managed hooks for GUI/minimal-PATH runtimes

Installer-emitted hook commands started with bare 'node' which works
under interactive shells (nvm/Homebrew/Volta on PATH) but fails in
GUI-launched runtimes that start with /usr/bin:/bin:/usr/sbin:/sbin.
Every managed JS hook (gsd-check-update, gsd-statusline, gsd-context-monitor,
gsd-prompt-guard, gsd-read-guard, gsd-read-injection-scanner,
gsd-workflow-guard) failed with /bin/sh: node: command not found —
silently disabling update checks, statusline, and security guards.

Fix: new resolveNodeRunner() helper returns process.execPath (the
absolute path of the Node binary running the installer) forward-slash-
normalized and double-quoted. Used in:
  - buildHookCommand() for global installs (.js runner)
  - local-install code paths for all 7 managed JS hooks

.sh hooks keep bare 'bash' — /bin/bash is in the POSIX standard PATH
and always resolves under minimal-PATH GUI launches.

Tests: bug-2979-hook-absolute-node.test.cjs parses emitted commands
into { runner, hookPath } records and asserts:
  - resolveNodeRunner returns quoted absolute forward-slash node path
  - .js hooks emit absolute runner (default and portableHooks modes)
  - .sh hooks still emit bare 'bash'

Closes #2979

* chore(#2979): add changeset fragment for PR #3002

* chore(#2979): add changeset fragment for PR #3002

* fix(#2979): resolveNodeRunner returns null on missing execPath; rewrite legacy bare-node managed hooks (CR feedback)

CodeRabbit on PR #3002 caught two issues:

1. resolveNodeRunner fell back to bare 'node' when process.execPath was
   empty -- recreating the exact #2979 bug. Now returns null. Callers
   (buildHookCommand and the local-install code paths) check for null
   and skip registration rather than emit a broken command.

2. The original #2979 fix only updated NEWLY registered hooks. Existing
   bare-node managed hook entries from pre-#2979 installs stayed
   broken across reinstalls. New rewriteLegacyManagedNodeHookCommands
   walks settings.hooks and rewrites any managed-hook entry that starts
   with bare 'node ' to use the absolute runner. Filename allowlist
   (gsd-check-update.js, gsd-statusline.js, gsd-context-monitor.js,
   gsd-prompt-guard.js, gsd-read-guard.js, gsd-read-injection-scanner.js,
   gsd-workflow-guard.js) ensures user-authored bare-node hooks are
   left untouched.

Tests: bug-2979-hook-absolute-node.test.cjs grows by 8 cases:
- 5 for the migration walker (rewrites managed entries, leaves quoted-
  runner entries alone, leaves user-authored entries alone, leaves .sh
  entries alone, no-ops on null runner).
- 2 for resolveNodeRunner returning null on empty execPath.
- 1 for buildHookCommand returning null when execPath unavailable.

* chore(#3002): drop direct CHANGELOG.md edit; release entry now lives in .changeset/

The changeset-fragment workflow (#2975) renders fragments into
CHANGELOG.md at release time. Direct edits to [Unreleased] on
each PR caused merge conflicts on every concurrent PR. This commit
restores CHANGELOG.md to match origin/main; the release entry for
this fix is preserved in the .changeset/*.md fragment(s) on this
branch, which the release workflow consolidates.

* fix(#2979): guard hook + statusline pushes against null commands (CR follow-up)

CodeRabbit on PR #3002 found an outside-diff issue: when
resolveNodeRunner() returns null, every dependent *Command becomes
null, but the registration sites still pushed { type: 'command',
command: null } entries onto settings.hooks. The runtime's hook
schema rejects null commands and the failure surfaces as a confusing
parse error.

Fix:
- One unified warning at the top of configureSettings when ANY JS-hook
  command resolves null (operator sees the cause once instead of per-hook).
- Each of the 6 managed JS hook registration if-clauses now guards on
  the *Command variable being truthy: && updateCheckCommand,
  && contextMonitorCommand, && promptGuardCommand, && readGuardCommand,
  && readInjectionScannerCommand, && workflowGuardCommand.
- Statusline registration adds an else-if (!statuslineCommand) clause
  with its own warn before the settings.statusLine write site.

Tests: bug-2979-hook-absolute-node.test.cjs grows by 7 cases
(6 per-hook structural assertions parsing install.js for the
`fs.existsSync(<file>) && <command>` shape, plus 1 statusline
guard-precedes-write test).

* fix(#2979): defense-in-depth validateHookFields before writeSettings (CR)

CodeRabbit on PR #3002 (post-fix-up review): replace source-grep
structural tests with behavioral assertions on the settings object.

The push-site `&& <command>` guards (commit ce696c64) prevent null
commands from being pushed in the first place. As a defense-in-depth
backstop, install.js now runs validateHookFields(settings) right
before writeSettings(); validateHookFields already filters
{type:'command', command: null} entries (line 5884), so even if my
push-site guards ever regress, no null-command entries reach disk.

Tests: replaced the 7 install.js source-grep tests with 8 truly
behavioral tests:
- validateHookFields strips null-command entries for each of the 6
  managed JS hook shapes (parameterized by event + matcher)
- validateHookFields drops the entry entirely when all its hooks are
  null-command
- validateHookFields preserves agent-type hooks while stripping
  null-command sibling hooks in the same entry

These tests exercise the actual function the production code uses,
not its source representation. They survive future refactors of the
registration call sites.

* fix(#2979): tighten managed-hook migration to basename equality (CR)

CodeRabbit on PR #3002 (post-fix-up review): the previous
`trimmed.includes(name)` matcher had a false-positive vector. A
user-authored hook whose path contained a managed filename as a
substring (e.g. /home/me/scripts/wraps-gsd-check-update.js-helper.js)
would be unconditionally rewritten with the GSD runner, replacing
the user's bare `node` with our absolute path -- silently mutating
their hook configuration.

Fix: parse the command into <runner> <script-token> with the
script-token allowed to be quoted (single or double) or bareword.
Extract the path inside quotes, take the basename (handles both
forward and backslash separators on Windows), and match against
MANAGED_HOOK_FILES via Set.has() — exact equality, not substring.

Tests: bug-2979 grows by 4 cases:
- user hook with managed-filename-as-substring is NOT rewritten
- single-quoted path: rewritten correctly
- bareword path: rewritten correctly
- Windows backslash path: basename extraction works
2026-05-02 00:40:09 -04:00
Tom Boucher
ca78b65de7 fix(#2973): /gsd-profile-user writes dev-preferences.md to skills/, not legacy commands/gsd/ (#3003)
* fix(#2973): /gsd-profile-user writes dev-preferences.md to skills/ not legacy commands/gsd/

v1.39.0's install summary claimed the legacy ~/.claude/commands/gsd/
directory had been removed in favor of skills-only architecture, but
the cmdGenerateDevPreferences writer at profile-output.cjs:781 still
defaulted to the legacy path. Every /gsd-profile-user --refresh
deterministically re-created the legacy directory.

Missed in PR #1540's migration because dev-preferences is a
runtime-generated user artifact, not a GSD-shipped command file.

Fix:
- Writer default: ~/.claude/skills/gsd-dev-preferences/SKILL.md
- profile-user.md Display message + artifact list reference new path
- New migrateLegacyDevPreferencesToSkill(targetDir, saved) installer
  helper. Called at all 5 skills-aware install branches. Copies
  preserved legacy dev-preferences.md into skills/gsd-dev-preferences/
  SKILL.md, but ONLY if no SKILL.md already exists -- never clobbers
  user-customized skill content.

Tests: bug-2973-profile-user-skills-path.test.cjs runs the writer in
a subprocess (core.cjs:output uses fs.writeSync(1, ...) which bypasses
in-process stubbing), asserts the writer's command_path field is the
skills location, the file is on disk at that path, the legacy path is
NOT created. Tests for migration helper assert it writes when no skill
exists and skips when one does.

Closes #2973

* chore(#2973): add changeset fragment for PR #3003

* fix(#2973): rephrase comment to avoid cline-install leaked-path lint

The new comment at line 780 of profile-output.cjs literally contained
the string '~/.claude/commands/gsd/' which the cline-install
leaked-path regression test (tests/cline-install.test.cjs:175)
correctly flagged.

Cline transforms .claude/skills/ -> .cline/skills/ in installed .cjs
files but does not transform .claude/commands/. The new comment talks
about the legacy 'commands/gsd' subdirectory without the ~/.claude/
prefix, so the lint passes. The path semantics are unchanged -- the
runtime construction at line 787 still uses path.join(os.homedir(),
'.claude', 'skills', ...) which the lint regex does not match.

* test(#2973): add timeout to spawnSync to prevent CI hangs (CR feedback)

CodeRabbit on PR #3003: without a timeout, a regression that hangs the
writer or dispatcher would block CI indefinitely. Added a 30s timeout
(generous for what should complete in <1s) and an explicit signal
assertion so a timeout trip surfaces as a clear test failure with
context rather than a hung worker.

* test(#2973): add allow-test-rule annotation for legitimate product-text parsing

The new var-binding lint from #2982/#2985 caught readFileSync(...).match()
and readFileSync(...).includes() calls in this test. Both are legitimate
structural assertions against the product workflow markdown, not source-grep:

- match() extracts the path from a structured Display: "..." line and
  asserts on the typed path value (same pattern as bug-2470's installer
  scanForLeakedPaths regex test).
- includes() asserts the absence of a legacy path literal.

profile-user.md IS the shipped workflow artifact, and its Display: line
IS what the user sees. Per the existing test-rigor convention, this is
the source-text-is-the-product justification category.

Annotated with allow-test-rule citing that category.

* chore(#3003): drop direct CHANGELOG.md edit; release entry now lives in .changeset/

The changeset-fragment workflow (#2975) renders fragments into
CHANGELOG.md at release time. Direct edits to [Unreleased] on
each PR caused merge conflicts on every concurrent PR. This commit
restores CHANGELOG.md to match origin/main; the release entry for
this fix is preserved in the .changeset/*.md fragment(s) on this
branch, which the release workflow consolidates.

* fix(#2973): preserve user-owned gsd-dev-preferences skill across wipe (CR)

CodeRabbit on PR #3003 caught a real bug: copyCommandsAsClaudeSkills()
wipes ALL gsd-* skill directories at the top of every install, then
reinstalls from the package source. Since gsd-dev-preferences is
user-generated (written by /gsd-profile-user --refresh) and NOT
shipped by the npm package, the wipe deletes the user's customized
SKILL.md with nothing to restore from.

Fix: USER_OWNED_SKILLS allow-list in copyCommandsAsClaudeSkills.
Snapshot files under skills/gsd-dev-preferences/ before the wipe,
restore after. Same preserve/restore pattern as PR #1924.

Tests: bug-2973 grows by 2 cases:
- user-customized SKILL.md survives the wipe
- non-user-owned gsd-* skills are still wiped (preservation is opt-in)
2026-05-02 00:29:45 -04:00
Tom Boucher
1a51ec5829 fix(#2990): gsd-code-fixer worktree attaches to a new branch, not the user-checked-out one (#3001)
* fix(#2990): gsd-code-fixer worktree attaches to a new branch, not the user-checked-out one

The agent's setup_worktree step ran 'git worktree add "$wt" "$branch"'
where $branch was the user's currently-checked-out branch in the main
repo. Git refuses to check out the same branch in two worktrees by
default, so the call failed before any review fix could be applied.

This is the next-layer failure after #2686 (foreground/background race)
and #2839 (transactional cleanup): the isolation strategy was correct
in design, blocked only by git's same-branch protection.

Fix:
- Create a new branch 'gsd-reviewfix/${padded_phase}-$$' from the
  current branch tip and attach the worktree to it via
  'git worktree add -b "$reviewfix_branch" "$wt" "$branch"'.
- Cleanup tail is now four steps:
  1. 'git -C "$main_repo" merge --ff-only "$reviewfix_branch"'
     -- captures the agent's commits on the user's branch. --ff-only
     fails loudly on divergence (concurrent commits to $branch); the
     temp branch is preserved for manual merge.
  2. 'git worktree remove "$wt" --force'.
  3. 'git -C "$main_repo" branch -D "$reviewfix_branch"' ONLY if
     ff-only succeeded.
  4. 'rm -f "$sentinel"' last (preserves #2839 transactional ordering).
- Recovery sentinel JSON now records reviewfix_branch alongside
  worktree_path so a re-run after interruption cleans both the orphan
  worktree and the orphan temp branch.

Regression test: tests/bug-2990-code-fixer-worktree-branch.test.cjs
parses the agent .md into structured 'git worktree add' invocation
records (skipping occurrences inside markdown inline-code or bash
comments -- those are citations of the OLD pattern, not executable)
and asserts the structural invariants on the new pattern.

Closes #2990

* chore(#2990): add changeset fragment for PR #3001

* chore(#2990): add changeset fragment for PR #3001

* fix(#2990): correct main_repo parsing and ff_status capture (CR feedback)

CodeRabbit on PR #3001 caught two real bugs in the cleanup tail:

1. `awk '/^worktree / { print $2 }'` truncates paths containing
   spaces. /path/with spaces/repo becomes /path/with. Replaced with
   `sub(/^worktree /, ''); print` which strips the prefix and
   preserves the full path.

2. `if ! git merge ...; then ff_status=$?` captures the exit of the
   `!` operator (always 1 on failure), not the merge command's exit
   code. Restructured to `if cmd; then ff_status=0; else ff_status=$?`
   so the else-branch captures the real merge exit code.

Tests still pass: bug-2990 structural assertions on the agent .md
content unchanged.

* fix(#2990): recovery extracts reviewfix_branch and deletes orphan branch (CR)

CodeRabbit on PR #3001 found two issues:

1. (Major) Recovery code only extracted worktree_path from the sentinel.
   If a prior run died after `git worktree remove` but before
   `git branch -D`, the orphan reviewfix branch survived forever. The
   sentinel records reviewfix_branch (line 272) and the docs claim
   recovery deletes it, but the code didn't.
   Fixed: emit BOTH worktree_path and reviewfix_branch from the parser
   (newline-separated), capture each into shell vars, and call
   `git branch -D "$prior_branch" 2>/dev/null || true` after worktree
   removal but before sentinel deletion.

2. (Quick win) The bug-2990 test used regex .test() against the raw
   markdown, which would have been satisfied by prose mentioning the
   token. Restructured to:
   - parseCleanupGitInvocations() returns ordered records with structured
     fields (verb, targetsReviewfixBranch, isMergeFfOnly, isBranchDelete)
   - assert exactly-one merge --ff-only AND exactly-one branch -D
   - assert merge precedes branch-delete in execution order
   - parse the sentinel JSON.stringify call to extract field names and
     assert reviewfix_branch is among them

   Added 2 new tests for the recovery-block invariant: parses the recovery
   node -e block and asserts it extracts parsed.reviewfix_branch alongside
   parsed.worktree_path; and asserts the recovery shell calls
   `git branch -D "$prior_branch"`.

* test(#2990): add allow-test-rule annotation for product-text parsing (CR follow-up)

The lint-tests CI catch flagged md.match() in the new structural-IR
test suite. The .match() calls extract typed fields (cleanup-tail
git invocation records, sentinel JSON field names, recovery-block
node script content) from agents/gsd-code-fixer.md — which IS the
deployed agent product. Asserting on those typed fields tests the
runtime contract, not source code internals.

source-text-is-the-product is the correct classification per the
existing convention (matches thread-session-management.test.cjs and
the others reclassified in PR #2985's CR follow-up).

* chore(#3001): drop direct CHANGELOG.md edit; release entry now lives in .changeset/

The changeset-fragment workflow (#2975) renders fragments into
CHANGELOG.md at release time. Direct edits to [Unreleased] on
each PR caused merge conflicts on every concurrent PR. This commit
restores CHANGELOG.md to match origin/main; the release entry for
this fix is preserved in the .changeset/*.md fragment(s) on this
branch, which the release workflow consolidates.
2026-05-02 00:29:43 -04:00
Tom Boucher
4277f7d7e8 fix(#2994): move verify-reapply-patches.cjs to get-shit-done/bin/ so it ships to user installs (#3000)
* fix(#2994): move verify-reapply-patches.cjs to get-shit-done/bin/ so installer ships it

scripts/verify-reapply-patches.cjs (added in #2972 to close the
verified-yes-without-checking gap from #2969) shipped in the npm tarball
but never reached user installs: bin/install.js copies get-shit-done/
recursively but does not copy the top-level scripts/ directory.

Effect: every fresh install hit `Cannot find module …/scripts/verify-reapply-patches.cjs`
on Step 5 of /gsd-reapply-patches. The whole point of moving
verification out of LLM-driven prose into a deterministic script is
undone if the script does not resolve at runtime.

Fix: move the script to get-shit-done/bin/verify-reapply-patches.cjs
(same pattern as gsd-tools.cjs and other runtime bin scripts that the
installer ships) and update reapply-patches.md Step 5 to invoke
${GSD_HOME}/get-shit-done/bin/verify-reapply-patches.cjs.

Tests:
- bug-2969 SCRIPT path updated to the new location
- New bug-2994-verify-reapply-patches-installed-path.test.cjs parses
  reapply-patches.md into structured invocation records and asserts
  every node ${GSD_HOME}/... reference lives under get-shit-done/
  (the installed tree). Catches future regressions where someone moves
  a runtime-needed script back to scripts/.

Closes #2994

* chore(#2994): add changeset fragment for PR #3000

* chore(#2994): add changeset fragment for PR #3000

* docs(#2994): update verifier-script-location comment to reflect new path (CR)

CodeRabbit on PR #3000: the parenthetical at line 278 still said the
script ships under scripts/, but this PR moved it to get-shit-done/bin/.
Updated the prose to reference the new location and the installer
target path.

* chore(#3000): drop direct CHANGELOG.md edit; release entry now lives in .changeset/

The changeset-fragment workflow (#2975) renders fragments into
CHANGELOG.md at release time. Direct edits to [Unreleased] on
each PR caused merge conflicts on every concurrent PR. This commit
restores CHANGELOG.md to match origin/main; the release entry for
this fix is preserved in the .changeset/*.md fragment(s) on this
branch, which the release workflow consolidates.
2026-05-02 00:29:34 -04:00
Tom Boucher
cde793f1f0 fix(#2992): deterministic latest-version check — package name is a constant, not LLM choice (#2993)
* fix(#2992): deterministic latest-version check — package name is a constant, not LLM choice

The /gsd-update workflow's check_latest_version step was prescribed in
LLM-driven prose: "run `npm view get-shit-done-cc version`". The
executing model could and did shortcut the prescription and invent
npm queries against name-shaped guesses — `@get-shit-done/cli`,
`get-shit-done-cli`, `gsd` — all of which 404 or, worse, return an
unrelated typosquat (the 2016 `get-shit-done` timer package). Same
architectural anti-pattern as #2969 (Hunk Verification Gate where
the LLM filled `verified: yes` without checking).

Implementation built TDD per #2992:

  get-shit-done/bin/check-latest-version.cjs
    - PACKAGE_NAME = 'get-shit-done-cc' as a module constant; not
      parameterised, not exposed for override.
    - checkLatestVersion({ spawn? }) returns
      { ok: bool, version?: string, reason: CHECK_REASON.X, detail? }
      via a frozen enum: OK / FAIL_NPM_FAILED / FAIL_INVALID_OUTPUT.
    - --json mode emits the structured record on stdout for the
      workflow to parse via jq.
    - Windows-aware: uses { shell: process.platform === 'win32' }
      since npm is npm.cmd on Windows (same lesson as #2962).
    - Stored under get-shit-done/bin/ (not top-level scripts/) because
      that path IS in the user's installed config dir; top-level
      scripts/ ships in the npm tarball but is not copied into
      ~/.claude/ at install time.

  tests/bug-2992-check-latest-version.test.cjs
    - 7 tests, all assertions on the typed CHECK_REASON enum + the
      structured record. Injectable spawn function so no real npm
      process is invoked. Covers OK, npm-non-zero, invalid-output,
      empty-output, pre-release semver, PACKAGE_NAME constant lock,
      enum-shape lock.

  get-shit-done/workflows/update.md
    - check_latest_version step rewritten to call the script via
      `node "${GSD_HOME}/get-shit-done/bin/check-latest-version.cjs"
      --json` and parse the structured response with jq. Explicit
      "Do NOT run `npm view` or `npm search` directly" guidance
      cites #2992 so future contributors understand why.

Closes #2992

* fix(#2992): trailing slash on GSD_HOME default to satisfy bare-path lint

The bug-2470 regression test scans update.md for bare `$HOME/.claude`
references (no trailing slash). The PR added one in the new
check_latest_version step. Fix: trailing slash on the default value
(`${GSD_HOME:-$HOME/.claude/}`). Bash POSIX collapses the resulting
double slash; the lint pattern's negative lookahead is now satisfied.

* fix(#2992): emit GSD_DIR from get_installed_version, use it in check_latest_version

Addresses CodeRabbit feedback: the previous `${GSD_HOME:-$HOME/.claude/}`
fallback hardcoded the Claude runtime path, which silently breaks for
non-Claude runtimes (gemini, codex, opencode, kilo).

Fix:
- get_installed_version now emits a 4th line with the resolved config
  dir ($LOCAL_DIR or $GLOBAL_DIR), captured by callers as GSD_DIR.
- check_latest_version uses $GSD_DIR/get-shit-done/bin/check-latest-version.cjs.
  Empty GSD_DIR (UNKNOWN scope) skips the version check and falls
  through to fresh-install path.

This keeps the package name deterministic (#2992) AND respects the
detected runtime, instead of assuming Claude.

* chore(#2992): add changeset fragment for PR #2993

* chore(#2992): add changeset fragment for PR #2993

* fix(#2992): consolidate LATEST_RESULT parsing inside the GSD_DIR guard

CodeRabbit on PR #2993: the previous structure separated the GSD_DIR
guard from the jq parsing, so when GSD_DIR was empty the parsing block
ran against an unset LATEST_RESULT and produced misleading 'couldn't
check for updates' diagnostics instead of clean 'no_install_detected'.

Move all field assignments inside the conditional so the skip path
seeds LATEST_OK=false, LATEST_VERSION='', LATEST_REASON='no_install_detected',
and LATEST_STATUS=0 atomically.

* fix(#2992): emit GSD_DIR in early-return; add code-block lang and spawnSync timeout (CR)

CodeRabbit on PR #2993 caught three issues:

1. (Major) The early-return path in get_installed_version (PREFERRED_CONFIG_DIR
   fast path) only echoed 3 lines, but PR #2993 changed the contract to 4
   (GSD_DIR is now line 4). Downstream check_latest_version misread valid
   installs as UNKNOWN. Added `echo "$PREFERRED_CONFIG_DIR"` before exit 0.

2. (Minor) Markdown MD040: fenced code block at line 310 was missing a
   language identifier. Added ```text.

3. (Quick win) spawnSync('npm view ...') had no timeout, so a hung network
   could block /gsd-update indefinitely. Added 15s timeout; on timeout
   spawnSync returns with signal !== null and the existing failure path
   emits FAIL_NPM_FAILED.

* fix(#3008): kill cross-process race in install-minimal:307 mid-copy test

Old shape compared listTmpStageDirs() snapshots before/after the
mid-copy throw. Under scripts/run-tests.cjs --test-concurrency=4,
tests/install-minimal-all-runtimes.test.cjs runs in a parallel
subprocess and also creates gsd-minimal-skills-* dirs in shared
os.tmpdir(). The parallel process's create/remove activity between
this test's two snapshots caused deterministic failure when timing
aligned -- presented as 'flaky' but is a real race.

CI failure data (PR #2993 run 25238555786):
  expected (before): ['gsd-minimal-skills-km1O1O']
  actual   (after):  []

Both processes behaved correctly in isolation. The test was wrong:
it observed a shared filesystem state across processes.

Fix: stub fs.mkdtempSync inside this test to record THIS call's
stage dir path. After the throw, assert fs.existsSync(stagedDir)
=== false. Direct observation of the function's own behavior; no
global tmpdir scan; no parallel-process interference.

Closes #3008

* fix(#2992): distinguish timeout from npm failure; guard empty LATEST_RESULT (CR)

CodeRabbit on PR #2993 (post-fix-up review) caught two improvements:

1. (Low value) check-latest-version.cjs:55-61 — when spawnSync times
   out, r.status is null and r.signal is set (e.g. 'SIGTERM'), but
   r.stderr is empty. Without the signal-first branch, both timeouts
   and genuine npm failures shaped as 'npm exited non-zero' in detail,
   making logs ambiguous. Added explicit signal-first branch:
   'npm timed out (signal: SIGTERM)'.

2. (Quick win) update.md:284-315 — when node is missing or the script
   doesn't exist, LATEST_RESULT is empty. Piping empty to jq parses
   without error but leaves LATEST_OK / LATEST_REASON as empty
   strings, producing the user-visible diagnostic
   'Couldn\'t check for updates (reason: , exit: N)' with a blank
   reason. Added an explicit guard that sets LATEST_REASON to
   'script_not_found_or_node_unavailable' when LATEST_RESULT is empty,
   so operators see a meaningful failure message.

Tests: bug-2992 grows by 2 cases (timeout signal detail + empty
stderr fallback).
2026-05-02 00:29:31 -04:00
Tom Boucher
ffeeb92c14 fix(#2997): mask SECRET_CONFIG_KEYS in SDK config-set/get and init responses (#2999)
* fix(#2997): mask SECRET_CONFIG_KEYS in SDK config-set/get and init responses

The CJS→TS port at sdk/src/query/config-mutation.ts:240,243 and
config-query.ts:122,128,132 dropped the masking layer that secrets.cjs
spec defines for brave_search/firecrawl/exa_search. Result: the SDK
echoed plaintext API keys into machine-readable JSON output (stdout,
transcripts, CI logs).

Adjacent leak in init.ts:673-675 / init.cjs:728-730: the init bundle
passed config.brave_search through raw, leaking the API key whenever
the user had stored one.

Fix:
- New sdk/src/query/secrets.ts ports SECRET_CONFIG_KEYS, isSecretKey,
  maskSecret, maskIfSecret. Exact CJS parity (verified by 17 tests
  in secrets.test.ts that import secrets.cjs and compare).
- config-set masks value + previousValue in response; on-disk plaintext
  intact (key stays usable).
- config-get masks read response. --default flows through unmasked
  (user's own input, not stored secret).
- init.ts/init.cjs mask string values only; booleans (availability
  flags) pass through unchanged so the typed contract is preserved.

Tests: 17 in secrets.test.ts (including CJS parity), 5 in
config-mutation.test.ts (#2997 block — covers on-disk-preserved,
previousValue masking, short-value, unset, non-secret pass-through),
4 in config-query.test.ts.

Closes #2997

* chore(#2997): add changeset fragment for PR #2999

* chore(#2997): add changeset fragment for PR #2999

* chore(#2999): drop direct CHANGELOG.md edit; release entry now lives in .changeset/

The changeset-fragment workflow (#2975) renders fragments into
CHANGELOG.md at release time. Direct edits to [Unreleased] on
each PR caused merge conflicts on every concurrent PR. This commit
restores CHANGELOG.md to match origin/main; the release entry for
this fix is preserved in the .changeset/*.md fragment(s) on this
branch, which the release workflow consolidates.
2026-05-02 00:17:45 -04:00
Tom Boucher
4e378d37d8 fix(#3008): kill cross-process race in install-minimal:307 mid-copy test (#3009)
Old shape compared listTmpStageDirs() snapshots before/after the
mid-copy throw. Under scripts/run-tests.cjs --test-concurrency=4,
tests/install-minimal-all-runtimes.test.cjs runs in a parallel
subprocess and also creates gsd-minimal-skills-* dirs in shared
os.tmpdir(). The parallel process's create/remove activity between
this test's two snapshots caused deterministic failure when timing
aligned -- presented as 'flaky' but is a real race.

CI failure data (PR #2993 run 25238555786):
  expected (before): ['gsd-minimal-skills-km1O1O']
  actual   (after):  []

Both processes behaved correctly in isolation. The test was wrong:
it observed a shared filesystem state across processes.

Fix: stub fs.mkdtempSync inside this test to record THIS call's
stage dir path. After the throw, assert fs.existsSync(stagedDir)
=== false. Direct observation of the function's own behavior; no
global tmpdir scan; no parallel-process interference.

Closes #3008
2026-05-01 22:37:48 -04:00
Tom Boucher
9f09246f3b fix(#2998): populate gsd-pristine/ from install transform pipeline so verifier has a real baseline (#3004)
* fix(#2998): populate gsd-pristine/ from install transform pipeline so verifier has a real baseline

saveLocalPatches declared a pristineDir variable and JSDoc'd 'saves
pristine copies to gsd-pristine/' but no code ever wrote there. Effect:
/gsd-reapply-patches Step 5 verifier (#2972) silently fell back to its
over-broad heuristic ('every significant backup line') -- exactly the
silent-success-on-lost-content failure mode #2969 was designed to
prevent.

Fix: new populatePristineDir({...}) helper runs copyWithPathReplacement
(the install transform pipeline) into a tmp staging dir, then copies out
only the modified-file paths into gsd-pristine/. saveLocalPatches now
accepts a pristineCtx and calls the helper when local patches are
detected. Soft-fails on transform errors (logs warning, continues with
empty pristine -- no worse than pre-fix).

Pristine reflects the about-to-install version's content, which is the
right baseline for 'what would survive without the user's modifications'.

Tests: bug-2998-pristine-dir-populated.test.cjs asserts the helper is
exported, no-ops on empty input, writes one pristine file per source-
existing path, skips ghost paths, and produces deterministic output
(byte-identical across runs -- the property pristine_hashes depends on).

Closes #2998

* chore(#2998): add changeset fragment for PR #3004

* fix(#2998): expand pristine to all manifest install roots; clear stale pristine on populate (CR)

CodeRabbit on PR #3004 caught two issues:

1. populatePristineDir only staged packageSrc/get-shit-done/ but
   manifest.files records edits under several install roots (commands/,
   agents/, hooks/, skills/, root files like .clinerules). Modified
   paths outside get-shit-done/ were silently skipped, leaving the
   verifier with no baseline for those edits. Fixed by computing the
   set of top-level dirs from the modified set and staging each one
   that exists in source. Root-level files (no slash) bypass the
   transform pipeline and are copied directly.

2. populatePristineDir did not wipe pre-existing gsd-pristine/ before
   populating. A previous run's stale pristine could survive into the
   current run's diff baseline. Now wipe before populate AND in the
   catch path so soft-failures don't leave half-populated data on disk.

Tests: bug-2998-pristine-dir-populated.test.cjs grows by 2 cases:
- agents/ paths are staged and copied (was silently skipped pre-fix)
- mixed get-shit-done/ + agents/ in same modified list both stage
2026-05-01 21:14:14 -04:00
Tom Boucher
c2ada7e799 feat(#2995): post-install path audit for workflow-invoked scripts (#2996)
* feat(#2995): post-install path audit for workflow-invoked scripts

Catches the gap class surfaced by #2994: a workflow references a script
via ${GSD_HOME}/<path> that ships in the npm tarball but is not copied
to the user's config dir at install time. Unit tests don't catch it
because they resolve the script via path.join(__dirname, '..', 'scripts',
…) — the source layout, not the deployed layout.

Implementation built TDD per #2995, vertical slices with structured-IR
assertions:

  scripts/audit-workflow-script-paths.cjs
    - Pure auditWorkflowScriptPaths({ workflowsDir, repoRoot,
      installedPrefixes }) returns { ok, findings: [{ workflow, path,
      kind }] } via the AUDIT_FINDING enum.
    - Two finding kinds: MISSING_FROM_REPO (typo / file deleted) and
      NOT_INSTALLED (#2994 class — first segment outside installed
      prefixes).
    - Tolerates ${GSD_HOME:-...} default-fallback syntax.

  tests/bug-2995-post-install-script-paths.test.cjs
    - 9 tests across 3 suites:
      • Pure-function pass and per-finding-kind detection (5 tests on
        synthetic fixtures).
      • Real workflow audit (2 tests asserting the actual repo's
        get-shit-done/workflows/ has no NEW gaps and KNOWN_GAPS stays
        consistent with audit findings).
      • Enum shape lock + extractReferences edge cases.
    - All assertions on typed AUDIT_FINDING enum / structured records;
      zero raw text matching.
    - KNOWN_GAPS is a Set keyed on `workflow|path|kind` strings;
      currently contains the #2994 entry. The companion test fails if
      a KNOWN_GAPS entry no longer matches a real finding (forces the
      allow-list to shrink as gaps fix).

The audit immediately catches #2994's gap on `reapply-patches.md`. The
allow-list contains exactly that entry; new gaps fail CI; #2994's fix
will remove the entry as part of the same PR.

Closes #2995
Refs #2994

* chore(#2995): add changeset fragment for PR #2996

* chore(#2995): add changeset fragment for PR #2996

* fix(#2995): emit both NOT_INSTALLED + MISSING_FROM_REPO; clean up fixture leak (CR)

CodeRabbit on PR #2996 found two issues:

1. (Low value) auditWorkflowScriptPaths short-circuited on NOT_INSTALLED,
   masking MISSING_FROM_REPO for the same ref. Removed the `continue` so
   both findings emit in one run; added a regression test.

2. (Low value) bug-2995 test created tmpRoot in before() but never wrote
   into it; per-fixture mkdtempSync dirs leaked. Rooted fixture repos
   under tmpRoot so the after() cleanup actually frees them.
2026-05-01 21:13:45 -04:00
Tom Boucher
55ae8e42d2 test(#2986): mutation-killer suite for config-schema.cjs (95 typed assertions) (#3005)
* test(#2986): mutation-killer suite for config-schema.cjs (95 typed assertions)

Stryker measured 4.62% mutation score on config-schema.cjs (6 killed,
124 survived). Surviving mutants documented that existing tests were
exercising paths without verifying outputs.

Adds tests/bug-2986-config-schema-mutation-killers.test.cjs (95 tests,
4 suites) targeting each surviving mutant class:

- M1/M4: parameterized isValidConfigKey(key) === true for every member
  of VALID_CONFIG_KEYS. Kills static-key-fast-path mutations
  (if (VALID_CONFIG_KEYS.has(...)) return true; -> if (false) return true;)
  because no static key matches any DYNAMIC_KEY_PATTERN by design.

- M2: representative dynamic-pattern keys (one per pattern). Each matches
  exactly one pattern. Kills .some -> .every mutation: with .every, no
  single key matches all patterns -> all dynamic keys would be rejected.

- M3: strictEqual against the literal boolean true/false (not assert.ok
  truthy checks). Kills polarity-flip mutations.

- Anchor-tightening: keys that differ from valid by one char beyond the
  documented shape (trailing dot-segment, empty agent name, non-enum tier,
  etc.). Kills regex-loosening mutations on ^, $, charset boundaries.

Tests assert on typed boolean return values from the lib's public surface.
Zero source-grep, zero raw-text matching.

* chore(#2986): add changeset fragment for PR #3005

* test(#2986): use dynamic-only rep key for features pattern (CR feedback)

CodeRabbit on PR #3005: features.thinking_partner is in the static
VALID_CONFIG_KEYS set, so the static fast-path returns true before
DYNAMIC_KEY_PATTERNS.some() is ever called. A Stryker mutant that
removed only the features entry from DYNAMIC_KEY_PATTERNS would
survive because the test only ever exercised the static path for
that key.

Replaced features.thinking_partner with features.some_dynamic_feature
which is NOT in static keys, so isValidConfigKey must reach the
dynamic path to return true. Added a per-rep invariant that asserts
each representative key is NOT a member of VALID_CONFIG_KEYS,
catching this class of mistake at test time on any future
representative-key change.
2026-05-01 21:13:25 -04:00
Tom Boucher
3657c4ea9e fix(#3006): retarget PR-template CHANGELOG checkboxes at the changeset workflow (#3007)
The three PR templates still asked contributors to tick `CHANGELOG.md
updated`, contradicting the post-#2978 rule (documented in
CONTRIBUTING.md and enforced by scripts/changeset/lint.cjs) that
`CHANGELOG.md` must not be edited directly.

Each checkbox now references `npm run changeset` with the appropriate
`--type` (Fixed/Changed/Added) and notes the `no-changelog` opt-out
label where applicable, so `gh pr create` users land in the correct
workflow by copy-paste.

Closes #3006

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-01 20:01:04 -04:00
Tom Boucher
918f987a19 feat(#2982): extend no-source-grep lint to catch var-binding readFileSync.includes() (#2985)
* feat(#2982): extend no-source-grep lint to catch var-binding readFileSync.includes()

The base lint (scripts/lint-no-source-grep.cjs) only catches
readFileSync(...).<text-method>() chained directly. The much more
common var-binding form escapes it:

  const src = fs.readFileSync(p, 'utf8');
  // 50 lines later
  if (src.includes('foo')) {}        // ← still grep, lint missed it

Scan of the test suite found ~141 files using this pattern.

Implementation built TDD per #2982 with structured-IR assertions:

  scripts/lint-no-source-grep-extras.cjs
    - detectVarBindingViolations(src) — pure detector, two passes:
      pass 1 collects vars bound from readFileSync, pass 2 finds any
      <var>.<includes|startsWith|endsWith|match|search>( on those vars.
    - detectWrappedAssertOkMatch(src) — flags
      assert.ok(<expr>.match(...)) which escapes the assert.match rule.
    - VIOLATION enum exposes stable codes for tests to assert on.

  scripts/lint-no-source-grep.cjs
    - Wires the new detectors into the existing per-file check; one
      additional violation row per file with the first 3 sample tokens.

  tests/bug-2982-lint-var-binding.test.cjs
    - 13 tests, all assertions on typed VIOLATION enum / structured
      records. Covers all 5 text-match methods, multi-var, no-bind,
      string literal (must NOT trigger), wrapped assert.ok(.match),
      and assert.match (must NOT double-flag).

Migration backlog (#2974 expanded scope):

  - 42 files annotated `// allow-test-rule: source-text-is-the-product`
    (legitimate — they read .md/.json/.yml files whose deployed text
    IS the product)
  - 3 files annotated `// allow-test-rule: pending-migration-to-typed-ir [#2974]`
    (read .cjs/.js source — clear migration debt)
  - 95 files annotated `pending-migration-to-typed-ir [#2974]` with
    `Per-file review may reclassify as source-text-is-the-product
    during migration` (mixed — manual review under #2974)

After this lands the lint reports 0 violations on main; new
violations in PRs surface immediately.

Closes #2982
Refs #2974

* test(#2982): fix truncated test name per CR

The label ended with a bare '(' from a copy-paste mishap. Now reads
'does NOT flag .matchAll(...) — matchAll is not match, so
assert.ok(.matchAll(...)) is not flagged'.

* chore(#2982): add changeset fragment for PR #2985

* chore(#2982): add changeset fragment for PR #2985
2026-05-01 19:50:10 -04:00
Tom Boucher
17a4321bf5 docs(#2989): promote v1.39.1 hotfix entries from [Unreleased] to dated section (#2991)
Both v1.39.0 (stable, tagged 2026-05-01T03:05:33Z) and v1.39.1
(hotfix, tagged 2026-05-01T21:03:54Z) shipped to npm but the
CHANGELOG `[Unreleased]` link still pointed at `v1.38.5...HEAD` and
the entries that landed in v1.39.1 were still un-promoted.

Move the five v1.39.1 hotfix entries (#2917, #2949, #2954, #2962,
#2969) into a new `## [1.39.1] - 2026-05-01` section above
`## [1.38.5]`, with a one-line intro and install snippet matching
the conventions used in earlier dated sections.

Update the `[Unreleased]` link to point at `v1.39.1...HEAD`.

Out of scope (separate cleanup):
  - Backfilling a `## [1.39.0]` section. The CHANGELOG never had one;
    this PR doesn't make that worse but also doesn't try to invent
    release-note text from commit messages.
  - The eight v1.39.1 commits without `[Unreleased]` entries
    (#2942, #2944, #2924/#2941, #2940, #2947, #2950, #2948, #2957).
    These weren't in `[Unreleased]` to begin with; faithful
    promotion only moves what was already documented.
  - Adding a `docs/RELEASE-v1.39.1.md` file. The `docs/RELEASE-*.md`
    pattern in this repo is RC-only; stable patches historically
    don't have a counterpart.

The post-v1.39.1 hardening entries (#2980, #2983, #2987 from this
session, plus #2976 which was pre-skipped from the v1.39.1
cherry-pick set after #2980 landed) remain in the new
`[Unreleased]` section — they ship in the next release.

Closes #2989
2026-05-01 18:21:09 -04:00
Tom Boucher
9d5db87249 feat(#2975): adopt changeset-fragment workflow to eliminate CHANGELOG conflicts (#2978)
* feat(#2975): adopt changeset-fragment workflow to eliminate CHANGELOG conflicts

Two PRs that both edit `### Fixed` in CHANGELOG.md always conflict on merge.
Recently bit on #2960/#2972 in the same session — fix-the-conflict-and-rebase
tax. Replace the shared-file model with per-PR fragment files that never
share lines.

Implementation built TDD per #2975, vertical slices with structured-IR
assertions throughout:

  scripts/changeset/parse.cjs       - fragment text → typed record + frozen
                                      FRAGMENT_ERROR enum (8 tests)
  scripts/changeset/render.cjs      - fragments → structured IR with
                                      Keep-a-Changelog section ordering
                                      (2 tests)
  scripts/changeset/serialize.cjs   - IR ↔ markdown round-trip pair
                                      (parse(serialize(ir)) === ir,
                                      3 tests)
  scripts/changeset/cli.cjs         - file-I/O wrapper with --json mode;
                                      reads .changeset/, folds into
                                      CHANGELOG.md, deletes consumed
                                      fragments. Idempotent. (1 test)
  scripts/changeset/lint.cjs        - pure verdict (changedFiles, labels)
                                      → { ok, reason } via LINT_REASON
                                      enum. Honors `no-changelog` label.
                                      (5 tests)
  scripts/changeset/new.cjs         - fragment scaffolder with random
                                      adjective-noun-noun filename. Tests
                                      assert via parseFragment round-trip.
                                      (3 tests)

Total: 22 tests, all assertions on typed structured fields. No regex on
text, no String#includes on file content. Lint clean across 356 test files.

Supporting:

  .changeset/README.md              - format spec + workflow docs
  .changeset/eager-hawks-rally.md   - dogfood fragment for THIS PR (will
                                      be the first thing the new release
                                      tool consumes)
  .github/workflows/changeset-required.yml
                                    - CI: every PR runs lint.cjs
  package.json                      - npm run changeset, changelog:render,
                                      lint:changeset
  CONTRIBUTING.md                   - new "CHANGELOG Entries — Drop a
                                      Fragment" section between PR
                                      Guidelines and Testing Standards

Closes #2975

* fix(#2975): address CodeRabbit findings on changeset workflow

7 valid findings (4 Major, 3 Minor); all addressed:

scripts/changeset/parse.cjs
  - Preserve fragment body verbatim. Previously body.trim() ate
    intentional leading whitespace (code blocks, etc.); now trim() is
    used only for the emptiness check, and a single trailing newline
    is stripped (the editor-added one) so well-formed fragments
    round-trip byte-for-byte. Added a regression test asserting a
    code-block-leading body is preserved.

scripts/changeset/cli.cjs
  - Validate flag values during argument parsing. parseArgs now returns
    { ok, opts | error }; rejects `--repo` etc. with no following value
    or with another flag as the value. main() surfaces the error
    message before exiting 2.
  - Handle post-write fragment-deletion failures. After CHANGELOG.md
    is written, any unlink failure is captured into a structured
    deleteFailures list with reason 'fail_fragment_delete'; cmdRender
    returns exitCode=1 with the partial-failure detail instead of
    leaving the changelog updated and fragments behind (which would
    cause double-consumption on rerun).

scripts/changeset/lint.cjs
  - Treat CHANGELOG.md as a linted user-facing path. Direct edits to
    CHANGELOG.md (the bypass route around the new workflow) now fail
    the lint with FAIL_MISSING_FRAGMENT. Added a regression test for
    that case.
  - Use cp.execFileSync instead of cp.execSync for the git diff call.
    Eliminates the shell-interpolation surface on GITHUB_BASE_REF;
    git's own arg parser remains the validator.

scripts/changeset/new.cjs
  - Atomic fragment creation. existsSync() + writeFileSync was racy
    under concurrent invocations. Now writeFileSync uses { flag: 'wx' }
    which fails EEXIST on collision; the random-name retry loop
    catches EEXIST and re-rolls. Throws explicitly after 16 attempts
    rather than silently overwriting.

.changeset/README.md
  - Add language tag `md` to the format example fence (markdownlint
    MD040).

All 25 changeset tests pass; lint clean (356 test files, 0 violations).

* fix(#2975): sanitize --type and validate flag values in new.cjs (CR fixes)

Two CR findings on scripts/changeset/new.cjs:

1. (Minor) `type` was embedded in frontmatter without sanitization. A
   newline in the value (e.g. `--type 'Fixed\ntype: Added'`) would
   corrupt the fragment. scaffoldFragment now validates `type` against
   the Keep-a-Changelog ALLOWED_TYPES set BEFORE writing — same set
   parse.cjs uses on consume. Throws with a typed error referencing
   the allowed values; tests cover the newline case + 4 other
   non-allowed values.

2. (Minor) `--repo` (and other value-taking flags) without a value
   silently set opts.repo to undefined, which produced a cryptic
   ERR_INVALID_ARG_TYPE deep inside path.join. parseArgs now mirrors
   the cli.cjs convention: returns { ok, opts | error }, validates
   that the next token exists and is not itself another flag, and
   surfaces a precise "missing value for --repo" message before exit.
   Added 3 tests: missing-trailing-value, flag-as-value, well-formed.

29 tests pass across the changeset suite (4 new regression tests).
2026-05-01 18:12:20 -04:00
443 changed files with 15945 additions and 2401 deletions

44
.changeset/README.md Normal file
View File

@@ -0,0 +1,44 @@
# Changeset Fragments
This directory holds **per-PR CHANGELOG fragments**. Every PR with user-facing changes drops one (or more) `<random-name>.md` files here describing its CHANGELOG entry. Fragments are consolidated into the top-level `CHANGELOG.md` at release time.
## Why
Two PRs that both edit the `### Fixed` block of `CHANGELOG.md` always conflict on merge — git can't pick a serialization order without human input. Two PRs that each add a fresh `.changeset/<unique-name>.md` never conflict because they don't share lines.
See [#2975](https://github.com/gsd-build/get-shit-done/issues/2975) for the full rationale.
## Adding a fragment
```bash
node scripts/changeset/new.cjs \
--type Fixed \
--pr 1234 \
--body "fix the thing — explain the user-visible change in one sentence"
```
This writes `.changeset/<adjective>-<noun>-<noun>.md` with frontmatter and a body. Three random words → concurrent PRs don't collide.
## Format
```md
---
type: Fixed
pr: 1234
---
**`/gsd-foo` no longer drops trailing slashes** — explain the user-visible change.
```
Allowed `type:` values follow [Keep a Changelog](https://keepachangelog.com/): `Added`, `Changed`, `Deprecated`, `Removed`, `Fixed`, `Security`.
## Opting out
PRs that legitimately have no user-facing impact can add the `no-changelog` label. CI honors it. When unsure, add the fragment.
## At release time
```bash
node scripts/changeset/cli.cjs render --version vX.Y.Z --date YYYY-MM-DD
```
Reads every fragment, groups bullets by `type:`, replaces `## [Unreleased]` with a new `## [vX.Y.Z] - YYYY-MM-DD` block, opens a fresh `## [Unreleased]` above, deletes consumed fragments. Idempotent.

View File

@@ -0,0 +1,5 @@
---
type: Changed
---
**Query command dispatch deepened with Command Topology Module** — query dispatch now consumes a single topology seam that resolves command tokens, binds native handler adapters, and returns structured no-match diagnosis, improving locality and reducing dispatch seam drift.

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 3058
---
**GSD transport raw-mode handling and timeout fallback hardened** — fixes undefined raw formatting edge case and adds raw-path coverage to prevent regressions.

View File

@@ -0,0 +1,8 @@
---
type: Changed
pr: 3069
---
**query command metadata now flows through a canonical Command Definition Module seam** — registry assembly, mutation semantics, and alias generation consume one Interface (`family`, `canonical`, `aliases`, `mutation`, `output_mode`, `handler_key`) to improve locality and reduce drift.
**query fallback error mapping cleanup** — the CJS fallback catch path now passes original `err` to `mapFallbackDispatchError` (follow-up to prior review feedback missed in PR #3066).

View File

@@ -0,0 +1,6 @@
---
type: Changed
pr: 3075
---
**query architecture deepening pass** — extracted Query Runtime Context, Native Dispatch Adapter, and Query CLI Output Modules so dispatch policy, runtime context policy, and CLI projection logic each live behind focused seams with higher locality and leverage.

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 2990
---
gsd-code-fixer worktree no longer fails on the same-branch checkout — the agent now creates a new gsd-reviewfix/ branch via git worktree add -b and fast-forwards the user's branch on cleanup. See #2990.

View File

@@ -0,0 +1,5 @@
---
type: Changed
pr: 2986
---
Test suite for config-schema.cjs is now mutation-resistant — 95 typed assertions kill the 124 surviving Stryker mutants from the 4.62% baseline. Tests target static-key fast path, dynamic-pattern .some semantics, polarity, and regex-anchor tightening. See #2986.

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 3008
---
**`tests/install-minimal.test.cjs:307` no longer races on shared `os.tmpdir()` under parallel CI** — the previous shape compared `listTmpStageDirs()` snapshots before and after the throw. Under `scripts/run-tests.cjs --test-concurrency=4`, `tests/install-minimal-all-runtimes.test.cjs` runs in a parallel process and creates/removes `gsd-minimal-skills-*` dirs in the shared OS tmpdir between snapshots, so `deepStrictEqual` failed deterministically when the parallel process happened to have a live stage dir during the snapshot window. Fix: stub `fs.mkdtempSync` to record THIS call's stage dir, then assert that exact path no longer exists after the throw — no global filesystem snapshot, no race. (#3008)

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 3022
---
**Codex SessionStart hook now uses absolute Node binary path** — closes the gap left after #3002. The Codex install path wrote `command = "node ${path}"` directly into config.toml, bypassing `resolveNodeRunner()`. Under GUI/minimal-PATH runtimes (`/usr/bin:/bin:/usr/sbin:/sbin`), bare `node` failed to resolve, exit 127. Now routed through new `buildCodexHookBlock()` helper. Reinstall path migrates legacy bare-node entries via new `rewriteLegacyCodexHookBlock()`. See #3017.

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: TBD
---
**Codex skill adapter no longer instructs the agent to silently default discuss-phase decisions.** When `request_user_input` was rejected (Default mode), the generated adapter said "pick a reasonable default" — so `$gsd-discuss-phase` proceeded toward writing CONTEXT.md / DISCUSSION-LOG.md / checkpoints without ever asking the user. Adapter prose now requires the agent to STOP, present plain-text questions, and wait, with explicit named exceptions (`--auto`/`--all`/explicit user approval). See #3018.

View File

@@ -0,0 +1,6 @@
---
type: Changed
pr: 3074
---
**query CLI path extracted into a dedicated Query CLI Adapter Module**`sdk/src/cli.ts` now delegates query-specific dispatch, error mapping, and output/exit handling to `sdk/src/query/query-cli-adapter.ts` for better locality and testability.

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 3012
---
**Post-install message and update.md no longer recommend the removed `/gsd-reapply-patches` command** — after PR #2824 consolidated 86 skills into ~58, `/gsd-reapply-patches` was folded into a flag (`/gsd-update --reapply`). The 1.39.1 hotfix (#2954) updated `help.md` but missed `bin/install.js`'s `reportLocalPatches` runtime emitter, `get-shit-done/workflows/update.md` Step 4, and the English + zh-CN/ja-JP/ko-KR doc set. Users hit "Unknown command" after every install with backed-up patches. All five runtime branches in `reportLocalPatches` (claude, opencode, kilo, copilot, gemini, codex, cursor) now emit the consolidated form. Regression: `tests/bug-3010-reapply-patches-references.test.cjs` scans `bin/install.js`, every workflow file, and every doc (excluding CHANGELOG history and help.md's deprecation notice) for stale recommendations. See #3010.

View File

@@ -0,0 +1,5 @@
---
type: Changed
pr: 0
---
**Documentation refreshed for v1.40.0** — full audit of `docs/` against the 1.40.0-rc.1 release surface. Updates command lists, walkthroughs, and inventory rows for the 86→59 skill consolidation (#2790), the six namespace meta-skills with two-stage routing (#2792), the `/gsd-health --context` guard, the phase-lifecycle status-line read-side (#2833), and the Gemini colon-form / non-Gemini hyphen-form slash-command split. Translations in ja-JP/ko-KR/zh-CN/pt-BR mirror the structural changes; new English prose is marked with `<!-- TODO i18n -->` for human translator follow-up. CHANGELOG.md `[Unreleased]` section regrouped under Feature/Enhancement/Fix headers.

View File

@@ -0,0 +1,5 @@
---
type: Added
pr: TBD
---
**`dynamic_routing` block in `.planning/config.json` for failure-tier escalation (#3024).** Each agent declares a default tier (`light` / `standard` / `heavy`); when `dynamic_routing.enabled: true`, the resolver picks `tier_models[default_tier]` for the first spawn and escalates one tier up on orchestrator-detected soft failure (capped by `max_escalations`). Disabled by default — fully backward compatible. Composes with `model_overrides` (higher precedence) and `models.<phase_type>` (lower) for full cost-control flexibility. Adds new resolver `resolveModelForTier(cwd, agent, attempt)` to `core.cjs` for orchestrator integration.

View File

@@ -0,0 +1,5 @@
---
type: Added
pr: 2975
---
**Changeset-fragment workflow** — eliminates CHANGELOG.md merge conflicts. Each PR drops `.changeset/<random-name>.md` with frontmatter (`type:`, `pr:`) plus a markdown body; the release-time `npm run changelog:render` consolidates fragments into `CHANGELOG.md` and deletes them. CI lint (`npm run lint:changeset`) requires a fragment on any PR touching user-facing files (`bin/`, `get-shit-done/`, `agents/`, `commands/`, `hooks/`, `sdk/src/`); contributors can opt out via the `no-changelog` label for purely internal changes. See [.changeset/README.md](.changeset/README.md) and CONTRIBUTING.md for the workflow.

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 3037
---
**Gemini local install no longer duplicates `/gsd:*` commands across user and workspace scopes** — when GSD is already installed at the user scope (`~/.gemini/commands/gsd/`) and you run `npx get-shit-done-cc --gemini --local` in a project, the installer now skips writing `commands/gsd/` to `<project>/.gemini/` and prints a one-line warning explaining why. Previously, both scopes received the same 65 command files, and Gemini's conflict detector renamed every `/gsd:*` command to `/workspace.gsd:*` and `/user.gsd:*`, breaking the documented namespace. Closes #3037.

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 2994
---
/gsd-reapply-patches Step 5 verifier now resolves at runtime — moved scripts/verify-reapply-patches.cjs to get-shit-done/bin/ which is shipped by the installer. The legacy scripts/ directory is not copied to user installs. See #2994.

View File

@@ -0,0 +1,5 @@
---
type: Changed
pr: 3060
---
**Query mutation event mapping moved to dedicated module** — preserves event payloads while improving registry locality and test surface.

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 3026
---
**`gsd-sdk query <subcommand> --help` now reaches the handler instead of returning top-level usage.** The query argv parser harvested `--help` as a global flag and `main()` short-circuited dispatch — there was no path to discover what arguments a query subcommand accepts. The parser now leaves `--help` in `queryArgv` so the handler/fallback can render contextual help. The `gsd-tools.cjs` fallback now renders top-level usage on `--help` (instead of erroring), preserving #1818's anti-hallucination invariant by NOT executing the destructive command. See #3019.

View File

@@ -0,0 +1,5 @@
---
type: Changed
pr: 3060
---
**Alias-family handler maps moved to dedicated catalog module** — keeps command keys/order while reducing createRegistry coupling and improving family-level locality.

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 3028
---
**Installer no longer prints `✓ GSD SDK ready` when the shim is unreachable from the user's runtime shells.** The previous check used `process.env.PATH` from the install subprocess, which often differs from the user's later interactive shells (POSIX `~/.local/bin` not in login shell, node-version-manager PATH shims). Added `getUserShellPath()` helper that probes `$SHELL -lc 'printf %s "$PATH"'` and `isGsdSdkOnPath(pathString?)` overload that accepts an explicit PATH; the install-time check now downgrades to the actionable `⚠` diagnostic from PR #3014 when install-PATH and user-shell-PATH disagree. Windows cross-shell support tracked separately. See #3020.

View File

@@ -0,0 +1,5 @@
---
type: Added
pr: 2840
---
**`docs/issue-driven-orchestration.md` — recipe for driving GSD from a tracker issue** — new guide that maps Symphony-style orchestration concepts (workflow, isolated agent workspace, proof-of-work, human review gate, follow-up capture) onto existing GSD primitives (`/gsd-new-workspace`, `/gsd-manager`, `/gsd-autonomous`, `/gsd-verify-work`, `/gsd-review`, `/gsd-ship`, `STATE.md`, phase artifacts). Documentation only — no new commands, no daemon, no tracker integration.

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 2994
---
/gsd-reapply-patches Step 5 verifier now resolves at runtime — moved scripts/verify-reapply-patches.cjs to get-shit-done/bin/ which is shipped by the installer. The legacy scripts/ directory is not copied to user installs. See #2994.

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 2979
---
Managed JS hooks now resolve under GUI/minimal-PATH runtimes — installer emits process.execPath (absolute, quoted, forward-slash-normalized) as the runner for every .js hook command instead of bare node. See #2979.

View File

@@ -0,0 +1,5 @@
---
type: Added
pr: 2995
---
Post-install path smoke test for workflow-invoked scripts — audits every node ${GSD_HOME}/...cjs invocation in workflows resolves at the runtime-installed path. See #2995.

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 3011
---
**Actionable diagnostic when `gsd-sdk` is not on PATH after install** — Windows users (and others on multi-shell setups) reported that the previous "GSD SDK files are present but `gsd-sdk` is not on your PATH" warning gave them no way to fix it: no path to look at, no shell-specific commands, no mention of the npx-cache caveat. New `formatSdkPathDiagnostic({ shimDir, platform, runDir })` helper returns a typed IR with the resolved shim location, platform-specific PATH-export commands (PowerShell / cmd.exe / Git Bash on Windows; `export PATH` on POSIX), and an npx-specific note when running under an `_npx` cache segment (where the shim may be written to a temp dir that won't persist). The console renderer in `bin/install.js` emits the lines from the IR; tests assert on the typed fields directly. (#3011)

View File

@@ -0,0 +1,5 @@
---
type: Added
pr: 3032
---
**Documentation: MCP tool schema as a context-budget concern (#3025).** Adds new sections to `get-shit-done/references/context-budget.md` and `docs/USER-GUIDE.md` explaining that every enabled MCP server injects its tool schema into every turn — heavyweight servers (browser/playwright, Mac-tools, Windows-tools) can cost 20k+ tokens each, often dwarfing what `model_profile` tuning saves. The toggle lives in `.claude/settings.json` (`enabledMcpjsonServers` / `disabledMcpjsonServers`) and is a Claude Code harness concern, not a GSD concern. Includes a pre-phase audit checklist (browser, platform-specific, cross-project, duplicates) and notes the multiplier interaction with `model_profile`. Companion to #3023 (per-phase-type model map) and #3024 (dynamic routing); together they cover the three biggest cost levers.

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 2997
---
SDK config-set/config-get and init responses no longer echo plaintext API keys. New sdk/src/query/secrets.ts ports SECRET_CONFIG_KEYS masking from CJS; init bundles only mask string values to preserve the boolean availability-flag contract. See #2997.

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 2992
---
/gsd-update queries wrong npm package names — moved package name into a deterministic check-latest-version.cjs script and updated the workflow to use ${GSD_DIR} from get_installed_version. See #2992.

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 3007
---
**PR templates now point at the changeset workflow** — the `Fix`, `Enhancement`, and `Feature` PR templates previously asked contributors to tick `CHANGELOG.md updated`, which contradicted the post-#2978 rule that `CHANGELOG.md` must not be edited directly. Each checkbox now references `npm run changeset` (and the `no-changelog` opt-out where applicable).

View File

@@ -0,0 +1,5 @@
---
type: Changed
pr: 3060
---
**CLI query CJS fallback execution extracted to dedicated adapter module** — preserves logs/help passthrough behavior while improving fallback locality and testability.

View File

@@ -0,0 +1,5 @@
---
type: Changed
pr: 3060
---
**Query mutation event emission now uses a dedicated decorator seam** — preserves fire-and-forget behavior while reducing registry coupling and improving testability.

View File

@@ -0,0 +1,5 @@
---
type: Added
pr: 3030
---
**`models` block in `.planning/config.json` for per-phase-type model selection (#3023).** A new resolution layer between per-agent `model_overrides` and the `model_profile` tier table. Six named slots (`planning` / `discuss` / `research` / `execution` / `verification` / `completion`) accept tier aliases (`opus` / `sonnet` / `haiku` / `inherit`). Lets you express "Opus for planning, Sonnet for the rest" in two lines without learning the agent taxonomy. Fully backward compatible — configs without `models` behave exactly as today.

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 2998
---
gsd-pristine/ is now populated by the installer when local patches are detected — saveLocalPatches calls a new populatePristineDir helper that runs the install transform pipeline into a tmp staging dir and copies modified files into pristineDir. The reapply-patches Step 5 verifier no longer falls back to its over-broad heuristic. See #2998.

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 2997
---
SDK config-set/config-get and init responses no longer echo plaintext API keys. New sdk/src/query/secrets.ts ports SECRET_CONFIG_KEYS masking from CJS; init bundles only mask string values to preserve the boolean availability-flag contract. See #2997.

View File

@@ -0,0 +1,5 @@
---
type: Added
pr: 2995
---
Post-install path smoke test for workflow-invoked scripts — audits every node ${GSD_HOME}/...cjs invocation in workflows resolves at the runtime-installed path. See #2995.

View File

@@ -0,0 +1,5 @@
---
type: Changed
pr: 3060
---
**Query fallback orchestration now shared** — CLI and SDK query dispatch now use one planning seam for native vs CJS fallback decisions with behavior parity preserved.

View File

@@ -0,0 +1,5 @@
---
type: Changed
pr: 3060
---
**Query/transport policy data now converged in shared module** — mutation and raw-output policy wiring now share one source of truth to reduce drift.

View File

@@ -0,0 +1,5 @@
---
type: Changed
pr: 3042
---
**`/gsd-research-phase` consolidated into `/gsd-plan-phase --research-phase <N>`** — the standalone research command's slash-command stub was never registered (#3042). Rather than restore the orphan, the research-only capability now lives as a flag on `/gsd-plan-phase`. New modifiers: `--view` prints existing `RESEARCH.md` to stdout without spawning, `--research` forces refresh, otherwise prompts `update / view / skip` when `RESEARCH.md` already exists. Also scrubs four other stale slash-command references (`/gsd-check-todos`, `/gsd-new-workspace`, `/gsd-status`, residual `/gsd-plan-milestone-gaps`) across English + 4 localized doc sets (#3044). Closes #3042 and #3044.

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 3029
---
**`/gsd-code-review-fix` and `/gsd-plan-milestone-gaps` no longer surface as "Unknown command"** — both were consolidated by #2790 (`/gsd-code-review --fix` and inline gap planning in `/gsd-audit-milestone` respectively), but several user-facing surfaces still emitted the old slash forms in their offer text. Fixed audit-milestone offer blocks, gsd-complete-milestone routing, code-review/execute-phase offer text, gsd-code-fixer agent role card, and the doc surfaces (USER-GUIDE, FEATURES, INVENTORY, AGENTS, CONFIGURATION). Closes #3029, closes #3034.

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 2990
---
gsd-code-fixer worktree no longer fails on the same-branch checkout — the agent now creates a new gsd-reviewfix/ branch via git worktree add -b and fast-forwards the user's branch on cleanup. See #2990.

View File

@@ -0,0 +1,5 @@
---
type: Added
pr: 2982
---
Extended no-source-grep lint to catch var-binding readFileSync.includes() pattern. Tests now fail when source-grep is hidden behind a parser wrapper. See #2982.

View File

@@ -0,0 +1,6 @@
---
type: Changed
pr: 3065
---
**Dispatch policy seam now returns a structured result contract** across native and fallback query execution paths (`ok`, typed error `kind`, `details`, and final `exit_code`), with CLI consuming the unified result instead of mixed throw/result handling.

View File

@@ -0,0 +1,5 @@
---
type: Changed
pr: 3060
---
**Query static command registrations now split into domain catalog modules** — preserves command order/strings while improving registry locality and maintenance.

View File

@@ -0,0 +1,5 @@
---
type: Changed
pr: 3085
---
**`GSDTools` query execution internals now use deep Module seams** — refactors runtime composition, native/subprocess adapters, and output projection behind stable public interfaces for better locality and testability.

View File

@@ -0,0 +1,5 @@
---
type: Changed
pr: 2974
---
Migrated 8 test files from raw text matching (`stdout.includes(...)`, `assert.match(stderr, ...)`) to typed-IR assertions per CONTRIBUTING.md. Adds shared `ERROR_REASON` enum and `--json-errors` flag in `core.cjs`, typed `GRAPHIFY_REASON` in `graphify.cjs`, pure `buildSdkFailFastReport()` IR builder in `bin/install.js`, and Claude Code JSON envelope output (`hookSpecificOutput` with typed fields) for `gsd-session-state.sh` and `gsd-phase-boundary.sh`. Tests now assert on structured fields (`reason`, `context`, `state_present`, `planning_modified`, etc.) instead of substring matching. See #2974.

View File

@@ -0,0 +1,5 @@
---
type: Added
pr: 2795
---
**Optional update banner for non-GSD statusline users** — when the installer detects you've declined or kept a non-GSD statusline, it now offers an opt-in `SessionStart` banner that surfaces update availability via the existing `~/.cache/gsd/gsd-update-check.json` cache. Silent when up-to-date, rate-limits failure diagnostics to once per 24h, removed cleanly by `npx get-shit-done-cc --uninstall`.

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 2973
---
/gsd-profile-user --refresh writes dev-preferences.md to ~/.claude/skills/gsd-dev-preferences/SKILL.md instead of the legacy commands/gsd/ directory. Installer migrates any preserved legacy file to the new location. See #2973.

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 2992
---
/gsd-update queries wrong npm package names — moved package name into a deterministic check-latest-version.cjs script and updated the workflow to use ${GSD_DIR} from get_installed_version. See #2992.

View File

@@ -0,0 +1,5 @@
---
type: Fixed
pr: 2979
---
Managed JS hooks now resolve under GUI/minimal-PATH runtimes — installer emits process.execPath (absolute, quoted, forward-slash-normalized) as the runner for every .js hook command instead of bare node. See #2979.

View File

@@ -0,0 +1,5 @@
---
type: Added
pr: 2982
---
Extended no-source-grep lint to catch var-binding readFileSync.includes() pattern. Tests now fail when source-grep is hidden behind a parser wrapper. See #2982.

View File

@@ -73,7 +73,7 @@ Closes #
- [ ] Changes are scoped to the approved enhancement — nothing extra included - [ ] Changes are scoped to the approved enhancement — nothing extra included
- [ ] All existing tests pass (`npm test`) - [ ] All existing tests pass (`npm test`)
- [ ] New or updated tests cover the enhanced behavior - [ ] New or updated tests cover the enhanced behavior
- [ ] CHANGELOG.md updated - [ ] `.changeset/` fragment added (`npm run changeset -- --type Changed --pr <NNN> --body "..."`) — or `no-changelog` label applied if not user-facing
- [ ] Documentation updated if behavior or output changed - [ ] Documentation updated if behavior or output changed
- [ ] No unnecessary dependencies added - [ ] No unnecessary dependencies added

View File

@@ -94,7 +94,7 @@ Closes #
- [ ] Implementation scope matches the approved spec exactly - [ ] Implementation scope matches the approved spec exactly
- [ ] All existing tests pass (`npm test`) - [ ] All existing tests pass (`npm test`)
- [ ] New tests cover the happy path, error cases, and edge cases - [ ] New tests cover the happy path, error cases, and edge cases
- [ ] CHANGELOG.md updated with a user-facing description of the feature - [ ] `.changeset/` fragment added with a user-facing description of the feature (`npm run changeset -- --type Added --pr <NNN> --body "..."`)
- [ ] Documentation updated — commands, workflows, references, README if applicable - [ ] Documentation updated — commands, workflows, references, README if applicable
- [ ] No unnecessary external dependencies added - [ ] No unnecessary external dependencies added
- [ ] Works on Windows (backslash paths handled) - [ ] Works on Windows (backslash paths handled)

View File

@@ -63,7 +63,7 @@ Fixes #
- [ ] Fix is scoped to the reported bug — no unrelated changes included - [ ] Fix is scoped to the reported bug — no unrelated changes included
- [ ] Regression test added (or explained why not) - [ ] Regression test added (or explained why not)
- [ ] All existing tests pass (`npm test`) - [ ] All existing tests pass (`npm test`)
- [ ] CHANGELOG.md updated if this is a user-facing fix - [ ] `.changeset/` fragment added if this is a user-facing fix (`npm run changeset -- --type Fixed --pr <NNN> --body "..."`) — or `no-changelog` label applied
- [ ] No unnecessary dependencies added - [ ] No unnecessary dependencies added
## Breaking changes ## Breaking changes

View File

@@ -0,0 +1,24 @@
name: Changeset Required
on:
pull_request:
types: [opened, synchronize, reopened, labeled, unlabeled]
permissions:
contents: read
pull-requests: read
jobs:
changeset-lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-node@v4
with:
node-version: '24'
- name: Run changeset lint
env:
GITHUB_BASE_REF: ${{ github.base_ref }}
run: node scripts/changeset/lint.cjs

View File

@@ -0,0 +1,104 @@
# Render agent definitions from templates at install/config-change time
**Source:** [#2758](https://github.com/gsd-build/get-shit-done/issues/2758)
**Decision:** wontfix — closed on the technical merits
**Date:** 2026-05-02
## Proposal summary
Move config-gated prose out of `agents/*.md` into `agents/templates/*.md.tmpl`,
rendered at install time and after `.planning/config.json` writes via a new
`gsd-sdk agents render` subcommand. Conditional branches resolve at render time
(deterministic code) instead of at inference time (LLM interpretation).
Three named benefits:
1. Token reduction proportional to disabled features.
2. Deterministic feature gating (impossible-by-construction vs. test-for).
3. Single source of truth for contributor-facing gating.
Cites PR #2279 (Codex/OpenCode model embedding at install time) as direct
precedent for compile-time embedding.
## Why GSD does not own this
### 1. The determinism claim is theoretical, not observed
The proposal's strongest argument is that config-gated branches in agent prose
are a determinism failure surface. The actual patterns in the codebase today are
already heavily mitigated:
- The `use_worktrees` branch in `gsd-executor` is resolved deterministically via
`gsd-sdk query config-get` in bash — it is not LLM-interpreted.
- "Skip if `workflow.X` is `false`" prose patterns are short, stable, and
follow a uniform "missing key = enabled" convention. There is no documented
history of LLMs running disabled checks or skipping enabled ones because of
this prose.
A theoretical failure surface should not be traded for a real, high-risk
patch-migration surface (`gsd-local-patches/` rebase logic, by the reporter's own
admission "the highest-risk piece of the change"). The reporter was asked for
documented evidence; none was provided.
### 2. Token waste is small and bounded
The codebase has roughly 5 `workflow.*` toggle references in agent files and
~20 "Skip if" conditional-prose patterns total — most 12 sentences. The
"real spend across multi-phase milestones" claim was not measured against
`gsd-context-monitor` output despite being asked. Without a measured baseline,
the token-savings argument is asserted rather than demonstrated, and the savings
ceiling on ~20 short conditionals is small enough that it does not justify a new
template-and-rendering subsystem with a CI-enforced template/generated split.
### 3. The deterministic-gating need is already served
PR #2279 established orchestrator-time config embedding for the cases that
genuinely need deterministic resolution (model selection, reasoning effort,
worktree mode). That mechanism is the right layer for orchestration-time
decisions and can be extended toggle-by-toggle along the existing path without
introducing a parallel templating subsystem. The proposal's own "Alternative #1"
(continue the orchestrator-embedding pattern) was rejected on the grounds that
agent-internal conditionals belong in the agent layer, but the asks behind the
proposal — determinism, lower token cost — are equally satisfied by extending
PR #2279 incrementally without a second mechanism.
Adding a templating layer alongside orchestrator-embedding means two mechanisms
own the same problem. The proposal does not specify a partition rule, and the
reporter did not respond when asked for one.
### 4. Patch-migration risk is disproportionate to benefit
The `/gsd-reapply-patches` three-way-merge migration for `gsd-local-patches/`
is, in the proposal's own words, the highest-risk piece of the change. It exists
solely to absorb a contributor-workflow shift — the user-facing surface is
unchanged. Risk that flows entirely from internal restructuring, where the
benefit is unmeasured token savings and a theoretical determinism gain, is the
wrong trade.
The reduced-scope variant (Alternative #5: fresh installs only, defer the
migration) avoids that specific risk but still ships a parallel mechanism for
benefits that remain unmeasured and that PR #2279's path can absorb.
## Re-open criteria
This may be revisited if a contributor:
- Provides measured token deltas via `gsd-context-monitor` against a
representative all-toggles-off config, and the delta is materially larger
than what extending PR #2279's orchestrator-embedding path one toggle at a
time would produce.
- Documents a real LLM misinterpretation of an existing toggle conditional
(executor ignored `workflow.use_worktrees: false`, verifier ran when
`workflow.verifier: false`, etc.) — not a projected failure mode.
- Proposes a clear partition rule between orchestrator-time embedding (PR #2279)
and any new install-time templating layer, so the two mechanisms do not
overlap.
## Related
- PR #2279 — Codex/OpenCode model embedding at install time (the established
precedent for deterministic compile-time embedding into agent files)
- v1.37.0 release notes — shared-boilerplate extraction (reference files for
mandatory-initial-read, project-skills-discovery)
- `get-shit-done/workflows/` — workflow-level config embedding before subagent
spawn (the path of least friction for incremental deterministic gating)

View File

@@ -0,0 +1,56 @@
# Temporal context as a first-class GSD signal
**Source:** [#2756](https://github.com/gsd-build/get-shit-done/issues/2756)
**Decision:** wontfix — closed without further engagement
**Date:** 2026-05-02
## Proposal summary
Reporter proposed treating idle-time-between-turns as a first-class context signal in
GSD. Three flavors floated across the issue:
1. **Passive** — block at session resume injecting "you've been idle Nh, here's what was
open" into the orchestrator prompt.
2. **Active**`/resume-context` slash command.
3. **Retrospective**`HANDOFF.json` written at session end, read at next start.
Framed initially as a `claude-inject-idle-time` plugin, with a request that GSD treat
the pattern as core.
## Why GSD does not own this
- **Subagent gap unsolved.** Passive injection lands in the orchestrator's context
only. Subagents (the workers that actually do GSD's planning, execution, verification)
spawn fresh and never see the temporal signal. The proposal does not solve this, and
any GSD-core integration would inherit the gap. Until the subagent boundary is
addressed, "first-class temporal context" is at best a partial feature.
- **`HANDOFF.json` duplicates existing artifacts.** GSD already persists session
continuity through `.planning/state/*` and per-phase artifacts (PLAN.md, RESEARCH.md,
REVIEW.md, VERIFICATION.md). A separate handoff file would either drift from those or
redundantly mirror them. The right primitive for "what was I doing" already exists.
- **Statusline / TUI re-entry is platform-level, not GSD-level.** A statusline showing
idle time belongs in Claude Code itself or in a thin user plugin, not in GSD's phase
machinery.
- **Scope is unstable.** Reporter agreed with the narrowed minimum ask ("doc mention
only, rest opt-in"), then partially retracted it in a follow-up comment ("very
integral to myself"). The maintainer asked which version of the ask should move
forward; reporter did not respond.
## Re-open criteria
This may be revisited if a reporter:
- Engages with the subagent-gap problem and proposes a concrete mechanism for
temporal context to reach subagents (not just the orchestrator).
- Demonstrates a use case `.planning/state/*` provably cannot serve.
- Commits to a single stable scope (doc mention OR core integration OR plugin
reference) rather than oscillating between them mid-thread.
A drive-by enhancement request that the author does not return to engage with after
maintainer questions is not actionable. Future proposers: please plan to participate
through to a triage decision rather than dropping an issue and moving on.
## Related
- `.planning/state/` — existing session-continuity artifacts
- `get-shit-done/references/` — where any future plugin-interface doc would live

View File

@@ -4,21 +4,10 @@ All notable changes to GSD will be documented in this file.
Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
## [Unreleased](https://github.com/gsd-build/get-shit-done/compare/v1.38.5...HEAD) ## [Unreleased](https://github.com/gsd-build/get-shit-done/compare/v1.39.1...HEAD)
### Fixed ### Feature
- **`release-sdk` hotfix re-run no longer fails at `Dry-run publish validation` when the version is already on npm** — the `Detect prior publish (reconciliation mode)` step sets `skip_publish=true` when the package version is already on the registry, and the actual publish step honors that gate. The `Dry-run publish validation` step was missing the same guard, so any operator re-run of an already-published hotfix (the typical recovery path when later steps fail mid-flight) hit `npm publish --dry-run` first and got `npm error You cannot publish over the previously published versions: X.Y.Z``npm publish --dry-run` contacts the registry and rejects existing-version targets even though it doesn't actually publish. The dry-run validation step is now gated on the same `steps.prior_publish.outputs.skip_publish != 'true'` condition as the publish step. The rehearsal still runs on first publishes (where it has value); it skips only in the specific reconciliation case where the publish itself would be skipped. Trigger run: [25233855236](https://github.com/gsd-build/get-shit-done/actions/runs/25233855236/job/73995605643). Regression covered by `tests/bug-2987-dry-run-validation-skip-on-reconciliation.test.cjs`. (#2987)
- **`release-sdk` hotfix flow hardened against silent classifier failures, missing-classifier-at-base-tag, and a vestigial merge-back PR step** — three issues surfaced by CodeRabbit's post-merge review of #2981 plus a production failure on the v1.39.1 release run. **(1)** `scripts/diff-touches-shipped-paths.cjs` reused exit code `1` for both the legitimate "no shipped paths" classifier result and Node's default uncaught-throw exit, so any tooling failure was indistinguishable from a normal skip. The script now uses `0` (shipped), `1` (not shipped), `2` (classifier error) with `try`/`catch` + `uncaughtException`/`unhandledRejection` handlers routing all failure paths to exit `2`. **(2)** The workflow's `git checkout -b "$BRANCH" "$BASE_TAG"` overwrote the working tree with the base tag's contents *before* the cherry-pick loop ran the classifier — but base tags predating the classifier's introduction (notably v1.39.0) don't have the file in their tree, so `node scripts/diff-touches-shipped-paths.cjs` would exit non-zero and silently drop every commit, producing an empty hotfix release. The classifier is now staged into `$RUNNER_TEMP` at the top of `Prepare hotfix branch` (before any working-tree-mutating git command), and the loop references that staged copy. The cherry-pick loop snapshots `$PIPESTATUS` into a local array (`PIPE_RC=("${PIPESTATUS[@]}")`) immediately after the classifier pipeline — under bracketed `set +e`/`set -e` — and dispatches via explicit `case`: `0` proceeds, `1` skips into `NON_SHIPPED_SKIPPED`, anything else emits `::error::shipped-paths classifier failed for $SHA (exit N)` and fails the workflow. CodeRabbit on PR #2984 caught a subtler bug in the first iteration: `pipeline \|\| true; RC=${PIPESTATUS[1]}` is broken because `\|\| true` runs `true` as its own one-command pipeline on the failure paths, overwriting `PIPESTATUS` to `(0)` and leaving `${PIPESTATUS[1]}` unset. The array-snapshot form is invariant against this. The same hardening also surfaces `git diff-tree`'s exit code (via `PIPE_RC[0]`); a non-zero diff-tree result now also fails the workflow rather than feeding partial input to the classifier. **(3)** Removed the `Open merge-back PR (hotfix only)` step. The auto-cherry-pick hotfix flow only picks commits already on main (`git cherry HEAD origin/main` outputs the unmerged ones), so by construction every code commit on the hotfix branch is already on main. The only hotfix-branch-only commit is the version-bump chore, which would either no-op against main or rewind main's in-progress version. The step also failed in production with `GitHub Actions is not permitted to create or approve pull requests (createPullRequest)` (org policy) on run [25232968975](https://github.com/gsd-build/get-shit-done/actions/runs/25232968975). The `pull-requests: write` permission previously granted to the release job has been dropped in line with least-privilege. The run-summary line that previously echoed `Merge-back PR opened against main` has been replaced with `No merge-back PR (auto-picked commits are already on main)` so operators reading the summary see an accurate non-action statement (CodeRabbit on PR #2984). Regression covered by `tests/bug-2983-classifier-exit-codes-and-base-tag-staging.test.cjs` (15 assertions across exit-code semantics, classifier staging, error dispatch, PIPESTATUS-snapshot hardening, diff-tree fail-fast, merge-back removal, and run-summary accuracy). (#2983)
- **`release-sdk` hotfix only cherry-picks commits that change what actually ships** — the `fix:`/`chore:` filter in `Prepare hotfix branch` was too broad: it picked any commit with that conventional-commit type regardless of whether the diff could affect the published npm package. CI-only fixes (release-sdk.yml itself, hotfix tooling, test-only commits) were getting cherry-picked into hotfix branches even though they cannot change the tarball — and the subset touching `.github/workflows/*` then caused the prepare job's `git push` to be rejected by GitHub because the default `GITHUB_TOKEN` lacks the `workflow` scope, aborting the run. v1.39.1 hit this on PR #2977 (run [25232010071](https://github.com/gsd-build/get-shit-done/actions/runs/25232010071)). The loop now pre-skips any candidate commit whose `git diff-tree` output doesn't intersect the npm tarball's shipped paths (entries in `package.json` `files`, plus `package.json` itself, which `npm pack` always includes). Skipped commits land in a new `NON_SHIPPED_SKIPPED` summary bucket framed as informational — non-shipping commits cannot affect the package, so the skip needs no operator action. The shipped-paths classifier lives in `scripts/diff-touches-shipped-paths.cjs` so its rules (file-OR-directory prefix matching `npm pack` semantics, the always-shipped rule for `package.json`, the lockfile-not-shipped rule) are unit-testable. Regression covered by `tests/bug-2980-hotfix-only-picks-shipping-changes.test.cjs`. (#2980)
- **`release-sdk` hotfix workflow fails on real run with `npm error Version not changed`** — the `release` job's `Bump in-tree version (not committed)` step ran `npm version "$VERSION"` without `--allow-same-version`, so it errored on real (non-dry-run) hotfix runs because `prepare` had already committed the bump on the hotfix branch. The release job's checkout `ref` is asymmetric — `BRANCH` (already bumped) on real runs vs `BASE_TAG` (older version) on dry-runs — which is why dry-run never caught the bug. Both `npm version` calls in that step now pass `--allow-same-version`, matching the existing pattern in `release.yml:326`. (#2976)
- **`gsd-sdk query agent-skills` emits raw `<agent_skills>` block instead of JSON-wrapped string** — workflows that embed via `$(gsd-sdk query agent-skills <agent>)` were receiving a JSON-quoted string literal mid-prompt (e.g. `"<agent_skills>\n…"`), silently breaking all `<agent_skills>` injection into spawned subagents. The CLI dispatcher now honors an opt-in `format: 'text'` field on `QueryResult` and writes such results raw via `process.stdout.write`; `--pick` always returns JSON regardless. (#2917)
- **`sketch --wrap-up` now dispatches correctly** — `/gsd-sketch --wrap-up` was silently no-oping because the flag dispatch wiring was omitted when the micro-skill entry point was absorbed in #2790. (#2949)
- **`help.md` no longer advertises eight slash commands removed by the #2824 consolidation** — `/gsd-do`, `/gsd-note`, `/gsd-check-todos`, `/gsd-plant-seed`, `/gsd-research-phase`, `/gsd-list-phase-assumptions`, `/gsd-plan-milestone-gaps`, and `/gsd-join-discord` were removed when 86 skills were folded into 59. `help.md` was not updated alongside, so users typing the documented commands hit *Unknown command*. Each entry is now either rewritten to the surviving flag-based dispatcher (e.g., `/gsd-do …``/gsd-progress --do "…"`, `/gsd-note``/gsd-capture --note`, `/gsd-plant-seed``/gsd-capture --seed`, `/gsd-check-todos``/gsd-capture --list`) or removed for skills with no replacement. A regression test now asserts every `/gsd-*` reference in `help.md` has a matching `commands/gsd/*.md` stub. (#2954)
- **`--sdk` install on Windows now writes a callable `gsd-sdk` shim** — `npx get-shit-done-cc@latest --claude --global --sdk` on Windows previously left `gsd-sdk` off PATH because `trySelfLinkGsdSdk` returned `null` unconditionally on `win32` (a missed gap from #2775's POSIX self-link, not an intentional deferral). The function now dispatches to a Windows counterpart that writes the standard npm shim triple (`gsd-sdk.cmd`, `gsd-sdk.ps1`, and a Bash wrapper) to npm's global bin, so `gsd-sdk` resolves in a fresh shell across cmd.exe, PowerShell, and Cygwin/MSYS/Git-Bash. A new regression guard in `tests/no-unconditional-win32-skip.test.cjs` blocks any future `if (process.platform === 'win32') return null;` skip-only branches in `bin/install.js`. (#2962)
- **`/gsd-reapply-patches` Step 5 gate is now deterministic — no more silent content drops** — the prior gate parsed a Claude-generated *Hunk Verification Table* whose `verified: yes` rows were filled in without actually checking content presence, leading to merged files that lost user-added blocks (e.g., a `<visual_companion>` section, an `--execute-only` flag block) while the workflow reported success. The gate now invokes a Node script (`scripts/verify-reapply-patches.cjs`) that diffs each backup against the pristine baseline, computes the user-added significant lines, and asserts each one is present in the merged file. Exits non-zero with a per-file diagnostic on any miss; the workflow halts and surfaces the JSON output to the user. The verifier ignores low-signal lines (too short, pure whitespace, decorative comments) so trivial differences don't trigger false failures. Out of scope here: the manifest-baseline tightening described in #2969 Failure 1 — that's separate work. (#2969)
### Added — 1.40.0-rc.1
- **Six namespace meta-skills with keyword-tag descriptions** — replace the flat 86-skill - **Six namespace meta-skills with keyword-tag descriptions** — replace the flat 86-skill
listing with two-stage hierarchical routing. Model sees 6 namespace routers listing with two-stage hierarchical routing. Model sees 6 namespace routers
(`gsd:workflow`, `gsd:project`, `gsd:review`, `gsd:context`, `gsd:manage`, (`gsd:workflow`, `gsd:project`, `gsd:review`, `gsd:context`, `gsd:manage`,
@@ -36,49 +25,6 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
in-flight, idle, and progress display. All fields default to undefined so existing in-flight, idle, and progress display. All fields default to undefined so existing
STATE.md files keep rendering. Write-side and status-line wiring follow in a later STATE.md files keep rendering. Write-side and status-line wiring follow in a later
RC. (#2833) RC. (#2833)
### Changed — 1.40.0-rc.1
- **Hotfix release flow now auto-incorporates fixes from `main` and bundles the SDK** — `hotfix.yml create` auto-cherry-picks every `fix:`/`chore:` commit on `origin/main` not yet shipped (oldest-first; patch-equivalents skipped via `git cherry`; `feat:`/`refactor:` excluded; conflicts halt with the offending SHA; run summary lists every included SHA). `hotfix.yml finalize` adds the `install-smoke` cross-platform gate, bundles `sdk-bundle/gsd-sdk.tgz` inside the CC tarball (parity with `release-sdk.yml`), tightens the `next` dist-tag re-point, and marks the GitHub Release `--latest`. `release-sdk.yml` gains `action: publish | hotfix` plus an `auto_cherry_pick` toggle, with a new `prepare` job that branches `hotfix/X.YY.Z` from the highest existing `vX.YY.*` tag and runs the same cherry-pick logic — idempotent if the branch was pre-prepared via `hotfix.yml`. Hotfix `vX.YY.Z` is now defined as everything in `vX.YY.{Z-1}` plus every `fix:`/`chore:` since that base, so each tag is the cumulative-fix anchor for the next. (#2955)
- **Planning workspace seam extracted from `core.cjs` into `planning-workspace.cjs`** — path/workstream/lock behavior now lives in a dedicated module (`planningDir`, `planningPaths`, `planningRoot`, active-workstream routing, `withPlanningLock`). `core.cjs` keeps compatibility re-exports while call-sites migrate to direct imports, improving locality and reducing coupling. (#2900)
- **Skill surface consolidated 86 → 59 `commands/gsd/*.md` entries** — four new
grouped skills (`capture`, `phase`, `config`, `workspace`) replace clusters of
micro-skills. Six existing parents absorb wrap-up and sub-operations as flags:
`update --sync/--reapply`, `sketch --wrap-up`, `spike --wrap-up`,
`map-codebase --fast/--query`, `code-review --fix`, `progress --do/--next`. Zero
functional loss; 31 micro-skills deleted. `autonomous.md` corrected to call
`gsd:code-review --fix` (was invoking deleted `gsd:code-review-fix`). (#2790)
- **PRs missing `Closes #NNN` are auto-closed** — the `Issue link required` workflow
now auto-closes PRs opened without a closing keyword that links a tracking issue,
posting a comment that points to the contribution guide. (#2872)
### Fixed
- **Stale deleted command references updated across workflow files** — `help.md`, `do.md`, `settings.md`, `discuss-phase.md`, `new-project.md`, `plan-phase.md`, `spike.md`, and `sketch.md` referenced command names removed in #2790; updated to new consolidated equivalents. (#2950)
### Fixed — 1.40.0-rc.1
- **`spike --wrap-up` now dispatches correctly** — `/gsd-spike --wrap-up` was silently no-oping because the flag dispatch wiring was omitted when the micro-skill entry point was absorbed in #2790. (#2948)
- **`config-get context_window` returns `200000` when key absent** — querying an unset `context_window` previously exited 1 with "Key not found", surfacing a confusing error in planning logs even though the workflow fallback worked correctly. `cmdConfigGet` now consults a `SCHEMA_DEFAULTS` map and returns the documented default (`200000`, exit 0) for absent schema-defaulted keys; unknown absent keys still error as before. (#2943)
- **`gap-analysis` now parses non-`REQ-` requirement IDs and ignores traceability table headers** — `parseRequirements()` no longer hard-codes the `REQ-` prefix and now accepts uppercase prefixed IDs such as `TST-01`, `BACK-07`, and `INSP-04`; markdown table header rows (for example `| REQ-ID | ... |`) are excluded so header tokens are not reported as phantom uncovered requirements. Added regression coverage for mixed-prefix REQUIREMENTS files with traceability tables. (#2897)
- **Gemini slash commands namespaced as `/gsd:<cmd>` instead of `/gsd-<cmd>`** —
Gemini CLI namespaces commands under `gsd:`, so `/gsd-plan-phase` was unexecutable.
Body-text references in commands, agents, banners, and patch-reapply hints are now
converted via a roster-checked regex (boundary lookbehind + extension-aware
lookahead + roster lookup, defense-in-depth). The roster fail-loud guard prevents
silent no-op'ing if `commands/gsd/` is ever missing. (#2768, #2783)
- **`SKILL.md` description quoted for Copilot / Antigravity / Trae / CodeBuddy** —
descriptions starting with a YAML 1.2 flow indicator (`[BETA]`, `{`, `*`, `&`, `!`,
`|`, `>`, `%`, `@`, backtick) crashed gh-copilot's strict YAML loader. Six emission
sites now wrap descriptions in `yamlQuote(...)` (= `JSON.stringify`, a valid YAML
1.2 double-quoted scalar). (#2876)
- **`gsd-tools` invocations use the absolute installed path** — bare `gsd-tools …`
calls inside skill bodies relied on PATH resolution that is not guaranteed in every
runtime; replaced with the absolute path emitted at install time. (#2851)
- **Codex installer preserves trailing newline when stripping legacy hooks** — the
legacy-hook strip in the Codex installer ran against files with no terminating
newline at EOF and emitted a config that lost the newline, breaking downstream
parsers. (#2866)
### Added
- `--minimal` install flag (alias `--core-only`) writes only the main-loop core skills - `--minimal` install flag (alias `--core-only`) writes only the main-loop core skills
(`new-project`, `discuss-phase`, `plan-phase`, `execute-phase`, `help`, `update`) and (`new-project`, `discuss-phase`, `plan-phase`, `execute-phase`, `help`, `update`) and
zero `gsd-*` subagents. Cuts cold-start system-prompt overhead from ~12k tokens to zero `gsd-*` subagents. Cuts cold-start system-prompt overhead from ~12k tokens to
@@ -107,7 +53,21 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
on every push to main was rejected because submission rate is too high). Includes an on every push to main was rejected because submission rate is too high). Includes an
optional `dry_run` boolean and the same publish-verification gate as `release.yml`. (#2828) optional `dry_run` boolean and the same publish-verification gate as `release.yml`. (#2828)
### Changed ### Enhancement
- **Test suite for `config-schema.cjs` is now mutation-resistant** — Stryker measured a 4.62% mutation score on `get-shit-done/bin/lib/config-schema.cjs` (6 killed, 124 survived out of 130). Surviving mutants flagged that existing tests were exercising paths but not verifying outputs: a polarity flip (`return true``return false`), a predicate swap (`.some``.every`), or a guard removal (`if (VALID_CONFIG_KEYS.has(...)) return true;` → unguarded fallthrough) all passed every test. New `tests/bug-2986-config-schema-mutation-killers.test.cjs` adds 95 tests across four suites that target each surviving mutant class: (1) parameterized `isValidConfigKey('${key}') === true` for every member of `VALID_CONFIG_KEYS` (kills the static-key-fast-path mutation), (2) representative dynamic-pattern keys that match exactly one pattern (kills the `.some``.every` mutation, with an inline mutual-exclusivity invariant check), (3) `strictEqual` against the literal boolean `true`/`false` instead of `assert.ok` truthy checks (kills polarity-flip mutations), (4) anchor-tightening cases that differ from valid keys by one character beyond the documented shape (kills regex-loosening mutations on `^`, `$`, and character-class boundaries). Tests use the lib's public surface (typed boolean assertions on `isValidConfigKey` return values), no source-grep. (#2986)
- **Hotfix release flow now auto-incorporates fixes from `main` and bundles the SDK** — `hotfix.yml create` auto-cherry-picks every `fix:`/`chore:` commit on `origin/main` not yet shipped (oldest-first; patch-equivalents skipped via `git cherry`; `feat:`/`refactor:` excluded; conflicts halt with the offending SHA; run summary lists every included SHA). `hotfix.yml finalize` adds the `install-smoke` cross-platform gate, bundles `sdk-bundle/gsd-sdk.tgz` inside the CC tarball (parity with `release-sdk.yml`), tightens the `next` dist-tag re-point, and marks the GitHub Release `--latest`. `release-sdk.yml` gains `action: publish | hotfix` plus an `auto_cherry_pick` toggle, with a new `prepare` job that branches `hotfix/X.YY.Z` from the highest existing `vX.YY.*` tag and runs the same cherry-pick logic — idempotent if the branch was pre-prepared via `hotfix.yml`. Hotfix `vX.YY.Z` is now defined as everything in `vX.YY.{Z-1}` plus every `fix:`/`chore:` since that base, so each tag is the cumulative-fix anchor for the next. (#2955)
- **Planning workspace seam extracted from `core.cjs` into `planning-workspace.cjs`** — path/workstream/lock behavior now lives in a dedicated module (`planningDir`, `planningPaths`, `planningRoot`, active-workstream routing, `withPlanningLock`). `core.cjs` keeps compatibility re-exports while call-sites migrate to direct imports, improving locality and reducing coupling. (#2900)
- **Skill surface consolidated 86 → 59 `commands/gsd/*.md` entries** — four new
grouped skills (`capture`, `phase`, `config`, `workspace`) replace clusters of
micro-skills. Six existing parents absorb wrap-up and sub-operations as flags:
`update --sync/--reapply`, `sketch --wrap-up`, `spike --wrap-up`,
`map-codebase --fast/--query`, `code-review --fix`, `progress --do/--next`. Zero
functional loss; 31 micro-skills deleted. `autonomous.md` corrected to call
`gsd:code-review --fix` (was invoking deleted `gsd:code-review-fix`). (#2790)
- **PRs missing `Closes #NNN` are auto-closed** — the `Issue link required` workflow
now auto-closes PRs opened without a closing keyword that links a tracking issue,
posting a comment that points to the contribution guide. (#2872)
- **Canary release workflow now publishes from `dev` branch only** — `.github/workflows/canary.yml` - **Canary release workflow now publishes from `dev` branch only** — `.github/workflows/canary.yml`
swaps its four publish-step guards from `refs/heads/main` to `refs/heads/dev`. Aligns the swaps its four publish-step guards from `refs/heads/main` to `refs/heads/dev`. Aligns the
workflow with the new branch→dist-tag policy (`dev``@canary`, `main``@next`/`@latest`). workflow with the new branch→dist-tag policy (`dev``@canary`, `main``@next`/`@latest`).
@@ -121,8 +81,6 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
- **`scripts/lint-descriptions.cjs` added** — CI lint gate that fails if any - **`scripts/lint-descriptions.cjs` added** — CI lint gate that fails if any
`commands/gsd/*.md` description exceeds 100 chars. Run via `npm run lint:descriptions`. `commands/gsd/*.md` description exceeds 100 chars. Run via `npm run lint:descriptions`.
(#2789) (#2789)
### Changed
- **Skill surface consolidated from 86 → 59 `commands/gsd/*.md` entries** — four new - **Skill surface consolidated from 86 → 59 `commands/gsd/*.md` entries** — four new
grouped skills replace clusters of micro-skills: `capture` (add-todo, note, add-backlog, grouped skills replace clusters of micro-skills: `capture` (add-todo, note, add-backlog,
plant-seed, check-todos), `phase` (add-phase, insert-phase, remove-phase, edit-phase), plant-seed, check-todos), `phase` (add-phase, insert-phase, remove-phase, edit-phase),
@@ -133,8 +91,6 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
`progress --do/--next`. Zero functional loss. (#2790) `progress --do/--next`. Zero functional loss. (#2790)
- **`autonomous.md` corrected** — was invoking deleted `gsd:code-review-fix`; now calls - **`autonomous.md` corrected** — was invoking deleted `gsd:code-review-fix`; now calls
`gsd:code-review --fix`. (#2790) `gsd:code-review --fix`. (#2790)
### Removed
- **31 micro-skills deleted** — absorbed into consolidated parents or removed outright: - **31 micro-skills deleted** — absorbed into consolidated parents or removed outright:
add-todo, note, add-backlog, plant-seed, check-todos, add-phase, insert-phase, add-todo, note, add-backlog, plant-seed, check-todos, add-phase, insert-phase,
remove-phase, edit-phase, settings-advanced, settings-integrations, set-profile, remove-phase, edit-phase, settings-advanced, settings-integrations, set-profile,
@@ -143,8 +99,39 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
join-discord, research-phase, session-report, from-gsd2, analyze-dependencies, join-discord, research-phase, session-report, from-gsd2, analyze-dependencies,
list-phase-assumptions, plan-milestone-gaps. All functionality preserved via flags on list-phase-assumptions, plan-milestone-gaps. All functionality preserved via flags on
consolidated skills. (#2790) consolidated skills. (#2790)
- **`discuss-phase` lazy file loading** — entry-point `@file` directives replaced with
on-demand `Read()` calls gated behind mode routing. Tokens loaded at skill entry drop
from ~13k to near zero; only the branch actually invoked is loaded. (#2606)
### Fixed ### Fix
- **`gsd-pristine/` is now populated by the installer when local patches are detected** — `saveLocalPatches` declared a `pristineDir` variable and JSDoc'd "saves pristine copies (from manifest) to gsd-pristine/ to enable three-way merge during reapply-patches", but no code ever wrote to that directory. Effect: the `/gsd-reapply-patches` Step 5 verifier (#2972) silently degraded to its over-broad fallback heuristic ("every significant backup line"), exactly the silent-success-on-lost-content failure mode #2969 was designed to prevent. Fix: new `populatePristineDir({ packageSrc, pristineDir, modified, runtime, pathPrefix, isGlobal })` helper runs the install transform pipeline (`copyWithPathReplacement`) into a tmp staging dir, then copies out only the modified-file paths into `gsd-pristine/`. `saveLocalPatches` now accepts a `pristineCtx` and calls the helper when local patches are detected; the install entry point passes the package source root, runtime, pathPrefix, and isGlobal so transforms produce byte-identical output to what `copyWithPathReplacement` would have written under normal install. Soft-fails on transform errors (logs a warning, continues with empty pristine — no worse than pre-fix behavior). Pristine reflects the about-to-install version's content, which is what the verifier needs as the "what would survive without the user's modifications" baseline. Regression covered by `tests/bug-2998-pristine-dir-populated.test.cjs` (6 tests across two suites): asserts the helper is exported, returns 0 for empty modified list, writes one pristine file per source-existing path, skips ghost paths without corrupting pristine, and produces deterministic output (two runs with same inputs yield byte-identical pristine — the property `pristine_hashes` in `backup-meta.json` depends on). (#2998)
- **`release-sdk` hotfix re-run no longer fails at `Dry-run publish validation` when the version is already on npm** — the `Detect prior publish (reconciliation mode)` step sets `skip_publish=true` when the package version is already on the registry, and the actual publish step honors that gate. The `Dry-run publish validation` step was missing the same guard, so any operator re-run of an already-published hotfix (the typical recovery path when later steps fail mid-flight) hit `npm publish --dry-run` first and got `npm error You cannot publish over the previously published versions: X.Y.Z``npm publish --dry-run` contacts the registry and rejects existing-version targets even though it doesn't actually publish. The dry-run validation step is now gated on the same `steps.prior_publish.outputs.skip_publish != 'true'` condition as the publish step. The rehearsal still runs on first publishes (where it has value); it skips only in the specific reconciliation case where the publish itself would be skipped. Trigger run: [25233855236](https://github.com/gsd-build/get-shit-done/actions/runs/25233855236/job/73995605643). Regression covered by `tests/bug-2987-dry-run-validation-skip-on-reconciliation.test.cjs`. (#2987)
- **`release-sdk` hotfix flow hardened against silent classifier failures, missing-classifier-at-base-tag, and a vestigial merge-back PR step** — three issues surfaced by CodeRabbit's post-merge review of #2981 plus a production failure on the v1.39.1 release run. **(1)** `scripts/diff-touches-shipped-paths.cjs` reused exit code `1` for both the legitimate "no shipped paths" classifier result and Node's default uncaught-throw exit, so any tooling failure was indistinguishable from a normal skip. The script now uses `0` (shipped), `1` (not shipped), `2` (classifier error) with `try`/`catch` + `uncaughtException`/`unhandledRejection` handlers routing all failure paths to exit `2`. **(2)** The workflow's `git checkout -b "$BRANCH" "$BASE_TAG"` overwrote the working tree with the base tag's contents *before* the cherry-pick loop ran the classifier — but base tags predating the classifier's introduction (notably v1.39.0) don't have the file in their tree, so `node scripts/diff-touches-shipped-paths.cjs` would exit non-zero and silently drop every commit, producing an empty hotfix release. The classifier is now staged into `$RUNNER_TEMP` at the top of `Prepare hotfix branch` (before any working-tree-mutating git command), and the loop references that staged copy. The cherry-pick loop snapshots `$PIPESTATUS` into a local array (`PIPE_RC=("${PIPESTATUS[@]}")`) immediately after the classifier pipeline — under bracketed `set +e`/`set -e` — and dispatches via explicit `case`: `0` proceeds, `1` skips into `NON_SHIPPED_SKIPPED`, anything else emits `::error::shipped-paths classifier failed for $SHA (exit N)` and fails the workflow. CodeRabbit on PR #2984 caught a subtler bug in the first iteration: `pipeline \|\| true; RC=${PIPESTATUS[1]}` is broken because `\|\| true` runs `true` as its own one-command pipeline on the failure paths, overwriting `PIPESTATUS` to `(0)` and leaving `${PIPESTATUS[1]}` unset. The array-snapshot form is invariant against this. The same hardening also surfaces `git diff-tree`'s exit code (via `PIPE_RC[0]`); a non-zero diff-tree result now also fails the workflow rather than feeding partial input to the classifier. **(3)** Removed the `Open merge-back PR (hotfix only)` step. The auto-cherry-pick hotfix flow only picks commits already on main (`git cherry HEAD origin/main` outputs the unmerged ones), so by construction every code commit on the hotfix branch is already on main. The only hotfix-branch-only commit is the version-bump chore, which would either no-op against main or rewind main's in-progress version. The step also failed in production with `GitHub Actions is not permitted to create or approve pull requests (createPullRequest)` (org policy) on run [25232968975](https://github.com/gsd-build/get-shit-done/actions/runs/25232968975). The `pull-requests: write` permission previously granted to the release job has been dropped in line with least-privilege. The run-summary line that previously echoed `Merge-back PR opened against main` has been replaced with `No merge-back PR (auto-picked commits are already on main)` so operators reading the summary see an accurate non-action statement (CodeRabbit on PR #2984). Regression covered by `tests/bug-2983-classifier-exit-codes-and-base-tag-staging.test.cjs` (15 assertions across exit-code semantics, classifier staging, error dispatch, PIPESTATUS-snapshot hardening, diff-tree fail-fast, merge-back removal, and run-summary accuracy). (#2983)
- **`release-sdk` hotfix only cherry-picks commits that change what actually ships** — the `fix:`/`chore:` filter in `Prepare hotfix branch` was too broad: it picked any commit with that conventional-commit type regardless of whether the diff could affect the published npm package. CI-only fixes (release-sdk.yml itself, hotfix tooling, test-only commits) were getting cherry-picked into hotfix branches even though they cannot change the tarball — and the subset touching `.github/workflows/*` then caused the prepare job's `git push` to be rejected by GitHub because the default `GITHUB_TOKEN` lacks the `workflow` scope, aborting the run. v1.39.1 hit this on PR #2977 (run [25232010071](https://github.com/gsd-build/get-shit-done/actions/runs/25232010071)). The loop now pre-skips any candidate commit whose `git diff-tree` output doesn't intersect the npm tarball's shipped paths (entries in `package.json` `files`, plus `package.json` itself, which `npm pack` always includes). Skipped commits land in a new `NON_SHIPPED_SKIPPED` summary bucket framed as informational — non-shipping commits cannot affect the package, so the skip needs no operator action. The shipped-paths classifier lives in `scripts/diff-touches-shipped-paths.cjs` so its rules (file-OR-directory prefix matching `npm pack` semantics, the always-shipped rule for `package.json`, the lockfile-not-shipped rule) are unit-testable. Regression covered by `tests/bug-2980-hotfix-only-picks-shipping-changes.test.cjs`. (#2980)
- **`release-sdk` hotfix workflow fails on real run with `npm error Version not changed`** — the `release` job's `Bump in-tree version (not committed)` step ran `npm version "$VERSION"` without `--allow-same-version`, so it errored on real (non-dry-run) hotfix runs because `prepare` had already committed the bump on the hotfix branch. The release job's checkout `ref` is asymmetric — `BRANCH` (already bumped) on real runs vs `BASE_TAG` (older version) on dry-runs — which is why dry-run never caught the bug. Both `npm version` calls in that step now pass `--allow-same-version`, matching the existing pattern in `release.yml:326`. (#2976)
- **Stale deleted command references updated across workflow files** — `help.md`, `do.md`, `settings.md`, `discuss-phase.md`, `new-project.md`, `plan-phase.md`, `spike.md`, and `sketch.md` referenced command names removed in #2790; updated to new consolidated equivalents. (#2950)
- **`spike --wrap-up` now dispatches correctly** — `/gsd-spike --wrap-up` was silently no-oping because the flag dispatch wiring was omitted when the micro-skill entry point was absorbed in #2790. (#2948)
- **`config-get context_window` returns `200000` when key absent** — querying an unset `context_window` previously exited 1 with "Key not found", surfacing a confusing error in planning logs even though the workflow fallback worked correctly. `cmdConfigGet` now consults a `SCHEMA_DEFAULTS` map and returns the documented default (`200000`, exit 0) for absent schema-defaulted keys; unknown absent keys still error as before. (#2943)
- **`gap-analysis` now parses non-`REQ-` requirement IDs and ignores traceability table headers** — `parseRequirements()` no longer hard-codes the `REQ-` prefix and now accepts uppercase prefixed IDs such as `TST-01`, `BACK-07`, and `INSP-04`; markdown table header rows (for example `| REQ-ID | ... |`) are excluded so header tokens are not reported as phantom uncovered requirements. Added regression coverage for mixed-prefix REQUIREMENTS files with traceability tables. (#2897)
- **Gemini slash commands namespaced as `/gsd:<cmd>` instead of `/gsd-<cmd>`** —
Gemini CLI namespaces commands under `gsd:`, so `/gsd-plan-phase` was unexecutable.
Body-text references in commands, agents, banners, and patch-reapply hints are now
converted via a roster-checked regex (boundary lookbehind + extension-aware
lookahead + roster lookup, defense-in-depth). The roster fail-loud guard prevents
silent no-op'ing if `commands/gsd/` is ever missing. (#2768, #2783)
- **`SKILL.md` description quoted for Copilot / Antigravity / Trae / CodeBuddy** —
descriptions starting with a YAML 1.2 flow indicator (`[BETA]`, `{`, `*`, `&`, `!`,
`|`, `>`, `%`, `@`, backtick) crashed gh-copilot's strict YAML loader. Six emission
sites now wrap descriptions in `yamlQuote(...)` (= `JSON.stringify`, a valid YAML
1.2 double-quoted scalar). (#2876)
- **`gsd-tools` invocations use the absolute installed path** — bare `gsd-tools …`
calls inside skill bodies relied on PATH resolution that is not guaranteed in every
runtime; replaced with the absolute path emitted at install time. (#2851)
- **Codex installer preserves trailing newline when stripping legacy hooks** — the
legacy-hook strip in the Codex installer ran against files with no terminating
newline at EOF and emitted a config that lost the newline, breaking downstream
parsers. (#2866)
- **GSD slash command namespace drift cleaned up across docs, workflows, and autocomplete** — remaining active `/gsd:<cmd>` references now use canonical `/gsd-<cmd>`, escaped workflow `Skill(skill=\"gsd:...\")` prompts now use hyphenated skill names, `scripts/fix-slash-commands.cjs` rewrites retired colon syntax to hyphen syntax, and the extract-learnings command file now uses `extract-learnings.md` so generated Claude/Qwen skill autocomplete exposes `gsd-extract-learnings` instead of `gsd-extract_learnings`. (#2855) - **GSD slash command namespace drift cleaned up across docs, workflows, and autocomplete** — remaining active `/gsd:<cmd>` references now use canonical `/gsd-<cmd>`, escaped workflow `Skill(skill=\"gsd:...\")` prompts now use hyphenated skill names, `scripts/fix-slash-commands.cjs` rewrites retired colon syntax to hyphen syntax, and the extract-learnings command file now uses `extract-learnings.md` so generated Claude/Qwen skill autocomplete exposes `gsd-extract-learnings` instead of `gsd-extract_learnings`. (#2855)
- **`extractCurrentMilestone` no longer truncates ROADMAP.md at heading-like lines inside fenced code blocks** — the milestone-end search now scans line-by-line while tracking ` ``` ` / `~~~` fence state, so a line like `# Ops runbook (v1.0 compat)` inside a code block no longer acts as a milestone boundary. Previously, any phase defined after such a block was invisible to `roadmap analyze`, `roadmap get-phase`, `/gsd-autonomous`, and all phase-number commands. (#2787) - **`extractCurrentMilestone` no longer truncates ROADMAP.md at heading-like lines inside fenced code blocks** — the milestone-end search now scans line-by-line while tracking ` ``` ` / `~~~` fence state, so a line like `# Ops runbook (v1.0 compat)` inside a code block no longer acts as a milestone boundary. Previously, any phase defined after such a block was invisible to `roadmap analyze`, `roadmap get-phase`, `/gsd-autonomous`, and all phase-number commands. (#2787)
- **Codex install no longer corrupts existing `~/.codex/config.toml`** — the installer - **Codex install no longer corrupts existing `~/.codex/config.toml`** — the installer
@@ -320,10 +307,19 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
pre-existing sentinel force-removes the orphan worktree before starting fresh, making pre-existing sentinel force-removes the orphan worktree before starting fresh, making
the agent self-healing across crashes. (#2839) the agent self-healing across crashes. (#2839)
### Performance
- **`discuss-phase` lazy file loading** — entry-point `@file` directives replaced with ## [1.39.1] - 2026-05-01
on-demand `Read()` calls gated behind mode routing. Tokens loaded at skill entry drop
from ~13k to near zero; only the branch actually invoked is loaded. (#2606) Hotfix release. Cherry-picks user-facing fixes from `main` onto the v1.39.0 stable
line. Install: `npm install -g get-shit-done-cc@latest` (or `@1.39.1` to pin).
### Fixed
- **`gsd-sdk query agent-skills` emits raw `<agent_skills>` block instead of JSON-wrapped string** — workflows that embed via `$(gsd-sdk query agent-skills <agent>)` were receiving a JSON-quoted string literal mid-prompt (e.g. `"<agent_skills>\n…"`), silently breaking all `<agent_skills>` injection into spawned subagents. The CLI dispatcher now honors an opt-in `format: 'text'` field on `QueryResult` and writes such results raw via `process.stdout.write`; `--pick` always returns JSON regardless. (#2917)
- **`sketch --wrap-up` now dispatches correctly** — `/gsd-sketch --wrap-up` was silently no-oping because the flag dispatch wiring was omitted when the micro-skill entry point was absorbed in #2790. (#2949)
- **`help.md` no longer advertises eight slash commands removed by the #2824 consolidation** — `/gsd-do`, `/gsd-note`, `/gsd-check-todos`, `/gsd-plant-seed`, `/gsd-research-phase`, `/gsd-list-phase-assumptions`, `/gsd-plan-milestone-gaps`, and `/gsd-join-discord` were removed when 86 skills were folded into 59. `help.md` was not updated alongside, so users typing the documented commands hit *Unknown command*. Each entry is now either rewritten to the surviving flag-based dispatcher (e.g., `/gsd-do …``/gsd-progress --do "…"`, `/gsd-note``/gsd-capture --note`, `/gsd-plant-seed``/gsd-capture --seed`, `/gsd-check-todos``/gsd-capture --list`) or removed for skills with no replacement. A regression test now asserts every `/gsd-*` reference in `help.md` has a matching `commands/gsd/*.md` stub. (#2954)
- **`--sdk` install on Windows now writes a callable `gsd-sdk` shim** — `npx get-shit-done-cc@latest --claude --global --sdk` on Windows previously left `gsd-sdk` off PATH because `trySelfLinkGsdSdk` returned `null` unconditionally on `win32` (a missed gap from #2775's POSIX self-link, not an intentional deferral). The function now dispatches to a Windows counterpart that writes the standard npm shim triple (`gsd-sdk.cmd`, `gsd-sdk.ps1`, and a Bash wrapper) to npm's global bin, so `gsd-sdk` resolves in a fresh shell across cmd.exe, PowerShell, and Cygwin/MSYS/Git-Bash. A new regression guard in `tests/no-unconditional-win32-skip.test.cjs` blocks any future `if (process.platform === 'win32') return null;` skip-only branches in `bin/install.js`. (#2962)
- **`/gsd-reapply-patches` Step 5 gate is now deterministic — no more silent content drops** — the prior gate parsed a Claude-generated *Hunk Verification Table* whose `verified: yes` rows were filled in without actually checking content presence, leading to merged files that lost user-added blocks (e.g., a `<visual_companion>` section, an `--execute-only` flag block) while the workflow reported success. The gate now invokes a Node script (`scripts/verify-reapply-patches.cjs`) that diffs each backup against the pristine baseline, computes the user-added significant lines, and asserts each one is present in the merged file. Exits non-zero with a per-file diagnostic on any miss; the workflow halts and surfaces the JSON output to the user. The verifier ignores low-signal lines (too short, pure whitespace, decorative comments) so trivial differences don't trigger false failures. Out of scope here: the manifest-baseline tightening described in #2969 Failure 1 — that's separate work. (#2969)
## [1.38.5] - 2026-04-25 ## [1.38.5] - 2026-04-25

41
CONTEXT.md Normal file
View File

@@ -0,0 +1,41 @@
# Context
## Domain terms
### Dispatch Policy Module
Module owning dispatch error mapping, fallback policy, timeout classification, and CLI exit mapping contract.
Canonical error kind set:
- `unknown_command`
- `native_failure`
- `native_timeout`
- `fallback_failure`
- `validation_error`
- `internal_error`
### Command Definition Module
Canonical command metadata Interface powering alias, catalog, and semantics generation.
### Query Runtime Context Module
Module owning query-time context resolution for `projectDir` and `ws`, including precedence and validation policy used by query adapters.
### Native Dispatch Adapter Module
Adapter Module that satisfies native query dispatch at the Dispatch Policy seam, so policy modules consume a focused dispatch Interface instead of closure-wired call sites.
### Query CLI Output Module
Module owning projection from dispatch results/errors to CLI `{ exitCode, stdoutChunks, stderrLines }` output contract.
### Query Execution Policy Module
Module owning query transport routing policy projection (`preferNative`, fallback policy, workstream subprocess forcing) at execution seam.
### Query Subprocess Adapter Module
Adapter Module owning subprocess execution contract for query commands (JSON/raw invocation, `@file:` indirection parsing, timeout/exit error projection).
### Query Command Resolution Module
Canonical command normalization and resolution Interface (`query-command-resolution-strategy`) used by internal query/transport paths after dead-wrapper convergence.
### Command Topology Module
Module owning command resolution, policy projection (`mutation`, `output_mode`), unknown-command diagnosis, and handler Adapter binding at one seam for query dispatch.
### Query Pre-Project Config Policy Module
Module policy that defines query-time behavior when `.planning/config.json` is absent: use built-in defaults for parity-sensitive query Interfaces, and emit parity-aligned empty model ids for pre-project model resolution surfaces.

View File

@@ -81,6 +81,20 @@ PRs that arrive without a properly-labeled linked issue are closed automatically
## Pull Request Guidelines ## Pull Request Guidelines
### Architecture & Domain Standards (Maintainer-Defined)
The following files are maintainer-owned coding standards and must be treated as canonical when contributing:
- `CONTEXT.md` — domain language and module naming standards
- `docs/adr/` — Architecture Decision Records (ADRs) for accepted architectural decisions
Contributor requirements:
- Read `CONTEXT.md` before naming or refactoring modules/interfaces/seams.
- Use `CONTEXT.md` vocabulary consistently in code comments, tests, issue/PR text, and docs for the touched area.
- Check relevant ADRs in `docs/adr/` before proposing or implementing architectural changes.
- If a change intentionally revisits an ADR decision, call it out explicitly in the linked issue and PR rationale.
- Do not rewrite maintainer intent in `CONTEXT.md`/ADRs as part of drive-by cleanup; propose focused updates tied to approved scope.
**Every PR must link to an approved issue.** PRs without a linked issue are closed without review, no exceptions. **Every PR must link to an approved issue.** PRs without a linked issue are closed without review, no exceptions.
- **No draft PRs** — draft PRs are automatically closed. Only open a PR when it is complete, tested, and ready for review. If your work is not finished, keep it on your local branch until it is. - **No draft PRs** — draft PRs are automatically closed. Only open a PR when it is complete, tested, and ready for review. If your work is not finished, keep it on your local branch until it is.
@@ -91,6 +105,23 @@ PRs that arrive without a properly-labeled linked issue are closed automatically
- **CI must pass** — all matrix jobs (Ubuntu × Node 22, 24; macOS × Node 24) must be green - **CI must pass** — all matrix jobs (Ubuntu × Node 22, 24; macOS × Node 24) must be green
- **Scope matches the approved issue** — if your PR does more than what the issue describes, the extra changes will be asked to be removed or moved to a new issue - **Scope matches the approved issue** — if your PR does more than what the issue describes, the extra changes will be asked to be removed or moved to a new issue
## CHANGELOG Entries — Drop a Fragment
**Do not edit `CHANGELOG.md` directly.** Two PRs that both append to a `### Fixed` block always conflict on merge — git can't pick a serialization order without a human. Instead, every PR with user-facing changes drops a fragment file in `.changeset/`.
```bash
npm run changeset -- --type Fixed --pr <YOUR_PR_NUMBER> \
--body "**\`/gsd-foo\` no longer drops trailing slashes** — explain the user-visible change."
```
This writes `.changeset/<adjective>-<noun>-<noun>.md`. Three random words → concurrent PRs never collide. Allowed `type:` values follow [Keep a Changelog](https://keepachangelog.com/): `Added`, `Changed`, `Deprecated`, `Removed`, `Fixed`, `Security`.
Fragments are consolidated into `CHANGELOG.md` at release time by the release workflow. See [`.changeset/README.md`](.changeset/README.md) for the format spec and [#2975](https://github.com/gsd-build/get-shit-done/issues/2975) for the rationale.
**CI enforcement:** the `Changeset Required` workflow (`scripts/changeset/lint.cjs`) fails any PR that touches `bin/`, `get-shit-done/`, `agents/`, `commands/`, `hooks/`, or `sdk/src/` without a `.changeset/*.md` fragment.
**Opt-out:** PRs with no user-facing impact (test refactors, lint config changes, CI tweaks, formatting-only changes) can add the `no-changelog` label. The lint honors it. When unsure whether a change is user-facing, **add the fragment**.
## Testing Standards ## Testing Standards
All tests use Node.js built-in test runner (`node:test`) and assertion library (`node:assert`). **Do not use Jest, Mocha, Chai, or any external test framework.** All tests use Node.js built-in test runner (`node:test`) and assertion library (`node:assert`). **Do not use Jest, Mocha, Chai, or any external test framework.**
@@ -487,6 +518,14 @@ Run locally before pushing: `npm run lint:tests`
### Test Requirements by Contribution Type ### Test Requirements by Contribution Type
### Architecture-Aware Testing Requirements
When work touches architecture, routing, policy, registry assembly, or command semantics:
- Write tests against module **interfaces** and seam behavior, not implementation trivia.
- Prefer invariant/contract tests that protect ADR-backed behavior and `CONTEXT.md` terminology.
- Ensure tests validate canonical behavior through the defined seam (for example: structured result contracts, canonical command metadata, and adapter parity), not source-text coupling.
- If ADRs define expected behavior, tests should assert those expectations directly.
The required tests differ depending on what you are contributing: The required tests differ depending on what you are contributing:
**Bug Fix:** A regression test is required. Write the test first — it must demonstrate the original failure before your fix is applied, then pass after the fix. A PR that fixes a bug without a regression test will be asked to add one. "Tests pass" does not prove correctness; it proves the bug isn't present in the tests that exist. **Bug Fix:** A regression test is required. Write the test first — it must demonstrate the original failure before your fix is applied, then pass after the fix. A PR that fixes a bug without a regression test will be asked to add one. "Tests pass" does not prove correctness; it proves the bug isn't present in the tests that exist.

View File

@@ -651,7 +651,7 @@ You're never locked in. The system adapts.
| Command | What it does | | Command | What it does |
|---------|--------------| |---------|--------------|
| `/gsd-new-workspace` | Create isolated workspace with repo copies (worktrees or clones) | | `/gsd-workspace --new` | Create isolated workspace with repo copies (worktrees or clones) |
| `/gsd-list-workspaces` | Show all GSD workspaces and their status | | `/gsd-list-workspaces` | Show all GSD workspaces and their status |
| `/gsd-remove-workspace` | Remove workspace and clean up worktrees | | `/gsd-remove-workspace` | Remove workspace and clean up worktrees |
@@ -698,7 +698,6 @@ You're never locked in. The system adapts.
| `/gsd-edit-phase [N] [--force]` | Modify any field of an existing phase in place — number and position unchanged | | `/gsd-edit-phase [N] [--force]` | Modify any field of an existing phase in place — number and position unchanged |
| `/gsd-remove-phase [N]` | Remove future phase, renumber | | `/gsd-remove-phase [N]` | Remove future phase, renumber |
| `/gsd-list-phase-assumptions [N]` | See Claude's intended approach before planning | | `/gsd-list-phase-assumptions [N]` | See Claude's intended approach before planning |
| `/gsd-plan-milestone-gaps` | Create phases to close gaps from audit |
### Session ### Session
@@ -740,7 +739,7 @@ You're never locked in. The system adapts.
| `/gsd-settings` | Configure model profile and workflow agents | | `/gsd-settings` | Configure model profile and workflow agents |
| `/gsd-set-profile <profile>` | Switch model profile (quality/balanced/budget/inherit) | | `/gsd-set-profile <profile>` | Switch model profile (quality/balanced/budget/inherit) |
| `/gsd-add-todo [desc]` | Capture idea for later | | `/gsd-add-todo [desc]` | Capture idea for later |
| `/gsd-check-todos` | List pending todos | | `/gsd-capture --list` | List pending todos |
| `/gsd-debug [desc]` | Systematic debugging with persistent state | | `/gsd-debug [desc]` | Systematic debugging with persistent state |
| `/gsd-do <text>` | Route freeform text to the right GSD command automatically | | `/gsd-do <text>` | Route freeform text to the right GSD command automatically |
| `/gsd-note <text>` | Zero-friction idea capture — append, list, or promote notes to todos | | `/gsd-note <text>` | Zero-friction idea capture — append, list, or promote notes to todos |

View File

@@ -1,6 +1,6 @@
--- ---
name: gsd-code-fixer name: gsd-code-fixer
description: Applies fixes to code review findings from REVIEW.md. Reads source files, applies intelligent fixes, and commits each fix atomically. Spawned by /gsd-code-review-fix. description: Applies fixes to code review findings from REVIEW.md. Reads source files, applies intelligent fixes, and commits each fix atomically. Spawned by /gsd-code-review --fix.
tools: Read, Edit, Write, Bash, Grep, Glob tools: Read, Edit, Write, Bash, Grep, Glob
color: "#10B981" color: "#10B981"
# hooks: # hooks:
@@ -10,7 +10,7 @@ color: "#10B981"
<role> <role>
You are a GSD code fixer. You apply fixes to issues found by the gsd-code-reviewer agent. You are a GSD code fixer. You apply fixes to issues found by the gsd-code-reviewer agent.
Spawned by `/gsd-code-review-fix` workflow. You produce REVIEW-FIX.md artifact in the phase directory. Spawned by `/gsd-code-review --fix` workflow. You produce REVIEW-FIX.md artifact in the phase directory.
Your job: Read REVIEW.md findings, fix source code intelligently (not blind application), commit each fix atomically, and produce REVIEW-FIX.md report. Your job: Read REVIEW.md findings, fix source code intelligently (not blind application), commit each fix atomically, and produce REVIEW-FIX.md report.
@@ -231,39 +231,63 @@ test -n "$branch" || { echo "Detached HEAD is not supported for review-fix (#268
sentinel="${phase_dir}/.review-fix-recovery-pending.json" sentinel="${phase_dir}/.review-fix-recovery-pending.json"
if [ -f "$sentinel" ]; then if [ -f "$sentinel" ]; then
echo "Detected pre-existing recovery sentinel from a prior interrupted run: $sentinel" echo "Detected pre-existing recovery sentinel from a prior interrupted run: $sentinel"
prior_wt=$(node -e ' # Recovery must extract BOTH worktree_path AND reviewfix_branch (#3001 CR):
# if a prior run died after `git worktree remove` but before
# `git branch -D`, the orphan branch survives and clutters `git branch`
# output forever. Emit both fields newline-separated so we can read them
# independently.
prior_recovery=$(node -e '
const fs = require("fs"); const fs = require("fs");
try { try {
const parsed = JSON.parse(fs.readFileSync(process.argv[1], "utf-8")); const parsed = JSON.parse(fs.readFileSync(process.argv[1], "utf-8"));
process.stdout.write(parsed.worktree_path || ""); process.stdout.write((parsed.worktree_path || "") + "\n" + (parsed.reviewfix_branch || ""));
} catch (err) { } catch (err) {
process.stderr.write(`Warning: malformed recovery sentinel ${process.argv[1]}: ${err.message}\n`); process.stderr.write(`Warning: malformed recovery sentinel ${process.argv[1]}: ${err.message}\n`);
process.stdout.write(""); process.stdout.write("\n");
} }
' "$sentinel") ' "$sentinel")
prior_wt="$(printf '%s' "$prior_recovery" | sed -n '1p')"
prior_branch="$(printf '%s' "$prior_recovery" | sed -n '2p')"
if [ -n "$prior_wt" ] && git worktree list --porcelain | grep -q "^worktree $prior_wt$"; then if [ -n "$prior_wt" ] && git worktree list --porcelain | grep -q "^worktree $prior_wt$"; then
echo "Removing orphan worktree from prior run: $prior_wt" echo "Removing orphan worktree from prior run: $prior_wt"
git worktree remove "$prior_wt" --force || true git worktree remove "$prior_wt" --force || true
fi fi
if [ -n "$prior_branch" ]; then
# Best-effort: branch may already be gone (cleaned by an earlier
# partial recovery, or never created if `git worktree add -b` itself
# failed). `|| true` keeps recovery non-fatal.
echo "Removing orphan reviewfix branch from prior run: $prior_branch"
git branch -D "$prior_branch" 2>/dev/null || true
fi
rm -f "$sentinel" rm -f "$sentinel"
fi fi
wt=$(mktemp -d "/tmp/sv-${padded_phase}-reviewfix-XXXXXX") wt=$(mktemp -d "/tmp/sv-${padded_phase}-reviewfix-XXXXXX")
git worktree add "$wt" "$branch"
# Create a temp branch from the current branch tip so the worktree
# attaches to that NEW branch rather than the user's currently-checked-out
# branch (#2990: git refuses to check out the same branch in two
# worktrees by default; the original `git worktree add "$wt" "$branch"`
# failed before the agent could do any work). The temp branch shares
# history with $branch up to the moment of creation, so commits made
# inside the worktree fast-forward $branch on cleanup.
reviewfix_branch="gsd-reviewfix/${padded_phase}-$$"
git worktree add -b "$reviewfix_branch" "$wt" "$branch"
# Write the recovery sentinel ONLY AFTER `git worktree add` succeeds. # Write the recovery sentinel ONLY AFTER `git worktree add` succeeds.
# Writing it before would leave a sentinel pointing at a worktree that does # Writing it before would leave a sentinel pointing at a worktree that does
# not exist if `git worktree add` itself failed. # not exist if `git worktree add` itself failed.
node -e ' node -e '
const fs = require("fs"); const fs = require("fs");
const [sentinelPath, worktree_path, branch, padded_phase] = process.argv.slice(1); const [sentinelPath, worktree_path, branch, reviewfix_branch, padded_phase] = process.argv.slice(1);
fs.writeFileSync(sentinelPath, JSON.stringify({ fs.writeFileSync(sentinelPath, JSON.stringify({
worktree_path, worktree_path,
branch, branch,
reviewfix_branch,
padded_phase, padded_phase,
started_at: new Date().toISOString() started_at: new Date().toISOString()
}, null, 2)); }, null, 2));
' "$sentinel" "$wt" "$branch" "$padded_phase" ' "$sentinel" "$wt" "$branch" "$reviewfix_branch" "$padded_phase"
cd "$wt" cd "$wt"
``` ```
@@ -271,32 +295,64 @@ cd "$wt"
Concrete steps: Concrete steps:
1. Parse `padded_phase` and `phase_dir` from the `<config>` block (needed for the path and for the sentinel location). 1. Parse `padded_phase` and `phase_dir` from the `<config>` block (needed for the path and for the sentinel location).
2. Resolve the current branch: `branch=$(git branch --show-current)`. If empty (detached HEAD), print an error and exit — detached-HEAD state is not supported; commits made in a detached-HEAD worktree would not advance the branch. 2. Resolve the current branch: `branch=$(git branch --show-current)`. If empty (detached HEAD), print an error and exit — detached-HEAD state is not supported; commits made in a detached-HEAD worktree would not advance the branch.
3. **Recovery check (#2839):** If `${phase_dir}/.review-fix-recovery-pending.json` already exists, a prior run was interrupted. Parse the JSON, attempt to remove the orphan worktree it points at (best-effort, with `--force`), then delete the stale sentinel before continuing. This makes a re-run of `/gsd-code-review-fix` self-healing. 3. **Recovery check (#2839, #2990):** If `${phase_dir}/.review-fix-recovery-pending.json` already exists, a prior run was interrupted. Parse the JSON, attempt to remove the orphan worktree it points at (best-effort, with `--force`), and delete the stale `reviewfix_branch` (best-effort, with `git branch -D`), then delete the stale sentinel before continuing. This makes a re-run of `/gsd-code-review --fix` self-healing.
4. Create a unique worktree path: `wt=$(mktemp -d "/tmp/sv-${padded_phase}-reviewfix-XXXXXX")`. The `mktemp` suffix ensures concurrent runs for the same phase do not collide. 4. Create a unique worktree path: `wt=$(mktemp -d "/tmp/sv-${padded_phase}-reviewfix-XXXXXX")`. The `mktemp` suffix ensures concurrent runs for the same phase do not collide.
5. Run `git worktree add "$wt" "$branch"` — this attaches the worktree to the current branch so commits advance it. 5. Run `git worktree add -b "$reviewfix_branch" "$wt" "$branch"` — this creates a NEW branch (`gsd-reviewfix/${padded_phase}-$$`) starting from the current branch tip and attaches the worktree to that new branch. Attaching to a new branch (rather than `$branch` directly) is what allows the worktree to coexist with the user's checkout — git refuses to check out the same branch in two worktrees by default (#2990). Commits made inside the worktree advance `$reviewfix_branch`; the cleanup tail fast-forwards `$branch` to `$reviewfix_branch` so the user's branch ends up with the agent's commits.
6. **Write the recovery sentinel** at `${phase_dir}/.review-fix-recovery-pending.json` containing `{worktree_path, branch, padded_phase, started_at}`. Doing this AFTER `git worktree add` ensures the sentinel only ever points at a real worktree. 6. **Write the recovery sentinel** at `${phase_dir}/.review-fix-recovery-pending.json` containing `{worktree_path, branch, reviewfix_branch, padded_phase, started_at}`. Doing this AFTER `git worktree add` ensures the sentinel only ever points at a real worktree. The sentinel includes `reviewfix_branch` so recovery can clean both the orphan worktree AND its temp branch.
7. All subsequent file reads, edits, and commits happen inside `$wt`. 7. All subsequent file reads, edits, and commits happen inside `$wt` (which is on `$reviewfix_branch`, not `$branch`).
**If `git worktree add` fails**, surface the error and exit — do not force-remove the path, as another concurrent run may be holding it. Do not write the sentinel (the worktree does not exist). **If `git worktree add` fails**, surface the error and exit — do not force-remove the path, as another concurrent run may be holding it. Do not write the sentinel (the worktree does not exist). Do not delete `$reviewfix_branch` either; if `-b` failed, no temp branch was created.
**Cleanup tail (transactional, ALWAYS — even on failure):** After writing REVIEW-FIX.md and before returning to the orchestrator, run the two-step cleanup in this exact order: **Cleanup tail (transactional, ALWAYS — even on failure):** After writing REVIEW-FIX.md and before returning to the orchestrator, run the cleanup in this exact order:
```bash ```bash
# Step 1: drop the worktree FIRST. If this succeeds and the process is then # Step 1 (#2990): fast-forward $branch to capture the commits the agent
# killed, the next run finds a sentinel pointing at a worktree that no longer # made on $reviewfix_branch. Run from the main repo (not $wt) — the user's
# exists — the recovery branch handles this gracefully (best-effort remove + # checkout owns $branch. --ff-only ensures we never silently drop or
# sentinel delete). If we reversed the order (sentinel removed first, then # rewrite history if the user committed to $branch concurrently; on
# worktree remove), an interruption between the two steps would leave NO # divergence, this fails loudly and the temp branch is left for the
# sentinel and an orphan worktree — exactly the bug from #2839. # user to inspect/merge manually. We deliberately resolve the main repo
# path via `git worktree list --porcelain` rather than assuming $PWD,
# because the agent ran inside $wt.
# Strip the literal "worktree " prefix and print the rest of the line, then
# exit on the first match. This preserves paths that contain spaces
# (awk '$2' would truncate "/path/with spaces/repo" to "/path/with").
main_repo="$(git worktree list --porcelain | awk '/^worktree / { sub(/^worktree /, ""); print; exit }')"
ff_status=0
# Capture the exit code of `git merge` directly. `if ! cmd; then ff_status=$?`
# captures the exit code of the `!` operator (always 1 when the inner cmd
# failed) — masking the real merge exit code. Use the success/else split
# instead so $? in the else-branch is the merge command's exit code.
if git -C "$main_repo" merge --ff-only "$reviewfix_branch" 2>&1; then
ff_status=0
else
ff_status=$?
echo "WARN: could not fast-forward $branch to $reviewfix_branch (exit $ff_status)."
echo " The temp branch $reviewfix_branch is preserved for manual merge."
fi
# Step 2: drop the worktree. If this succeeds and the process is then
# killed, the next run finds a sentinel pointing at a worktree that no
# longer exists — the recovery branch handles this gracefully (best-effort
# remove + sentinel delete). If we reversed the order (sentinel removed
# first, then worktree remove), an interruption between the two steps
# would leave NO sentinel and an orphan worktree — exactly the bug from
# #2839.
git worktree remove "$wt" --force git worktree remove "$wt" --force
# Step 2: drop the recovery sentinel ONLY after `git worktree remove` returns # Step 3: delete the temp branch ONLY if the fast-forward succeeded. If
# successfully. This atomic-ish ordering is what makes the cleanup tail # it didn't, leaving the branch lets the user inspect/merge manually.
# transactional from the orchestrator's perspective. if [ "$ff_status" -eq 0 ]; then
git -C "$main_repo" branch -D "$reviewfix_branch" || true
fi
# Step 4: drop the recovery sentinel ONLY after `git worktree remove`
# returns successfully. This atomic-ish ordering is what makes the
# cleanup tail transactional from the orchestrator's perspective.
rm -f "$sentinel" rm -f "$sentinel"
``` ```
This cleanup is unconditional — register it mentally as a finally-block obligation. If the agent exits early (config error, no findings, etc.), still run the two-step cleanup tail (`git worktree remove "$wt" --force` followed by `rm -f "$sentinel"`) before exit. The sentinel must NEVER be removed before `git worktree remove` succeeds. This cleanup is unconditional — register it mentally as a finally-block obligation. If the agent exits early (config error, no findings, etc.), still run the cleanup tail in order (fast-forward → worktree remove → temp branch delete → sentinel rm) before exit. The sentinel must NEVER be removed before `git worktree remove` succeeds. The temp branch must NEVER be deleted while the fast-forward is in a diverged state.
</step> </step>
<step name="load_context"> <step name="load_context">
@@ -528,9 +584,9 @@ _Iteration: {N}_
<critical_rules> <critical_rules>
**ALWAYS run inside the isolated worktree** — set up via `branch=$(git branch --show-current)` + `wt=$(mktemp -d "/tmp/sv-${padded_phase}-reviewfix-XXXXXX")` + `git worktree add "$wt" "$branch"` at the very start (see `setup_worktree` step). Using `mktemp` ensures concurrent runs do not collide. Attaching to `$branch` (not `HEAD`) ensures commits advance the branch. Every file read, edit, and commit must happen inside `$wt`. Run `git worktree remove "$wt" --force` unconditionally when done (treat it as a finally block). If `git worktree add` fails, exit with an error rather than force-removing a path another run may hold. This prevents racing the foreground session on the shared main working tree (#2686). **ALWAYS run inside the isolated worktree** — set up via `branch=$(git branch --show-current)` + `wt=$(mktemp -d "/tmp/sv-${padded_phase}-reviewfix-XXXXXX")` + `git worktree add -b "$reviewfix_branch" "$wt" "$branch"` at the very start (see `setup_worktree` step). Using `mktemp` ensures concurrent runs do not collide. Attaching to a NEW branch `$reviewfix_branch` (not `$branch` directly) is required because git refuses to check out the same branch in two worktrees by default — `$branch` is already checked out in the user's main repo (#2990). Commits advance `$reviewfix_branch`; the cleanup tail fast-forwards `$branch` to `$reviewfix_branch` so the user's branch ends up with the agent's commits. Every file read, edit, and commit must happen inside `$wt`. Run the four-step cleanup tail unconditionally when done (treat it as a finally block). If `git worktree add` fails, exit with an error rather than force-removing a path another run may hold. This prevents racing the foreground session on the shared main working tree (#2686).
**ALWAYS run the transactional cleanup tail in order** (#2839): `git worktree remove "$wt" --force` MUST happen BEFORE `rm -f "$sentinel"` (the recovery sentinel at `${phase_dir}/.review-fix-recovery-pending.json`). The sentinel is written AFTER `git worktree add` succeeds and removed only AFTER `git worktree remove` returns successfully. This ordering is what makes the cleanup tail transactional — an interruption between commits and `git worktree remove` leaves the sentinel behind so a future run, `/gsd-resume-work`, or `/gsd-progress` can detect and complete the recovery. Reversing the order recreates the orphan-worktree bug. **ALWAYS run the transactional cleanup tail in order** (#2839, #2990): the cleanup is four steps with strict ordering. (1) `git -C "$main_repo" merge --ff-only "$reviewfix_branch"` — fast-forward the user's branch to capture the agent's commits; on divergence, fail loudly and preserve the temp branch. (2) `git worktree remove "$wt" --force`. (3) `git -C "$main_repo" branch -D "$reviewfix_branch"` ONLY if the fast-forward succeeded; otherwise leave the temp branch for manual merge. (4) `rm -f "$sentinel"` (the recovery sentinel at `${phase_dir}/.review-fix-recovery-pending.json`). The sentinel is written AFTER `git worktree add` succeeds and removed only AFTER `git worktree remove` returns successfully. The temp branch is deleted only when the fast-forward succeeded. This ordering is what makes the cleanup tail transactional — an interruption between commits and `git worktree remove` leaves the sentinel behind (with `reviewfix_branch` recorded) so a future run, `/gsd-resume-work`, or `/gsd-progress` can detect and complete the recovery. Reversing the order recreates the orphan-worktree bug.
**ALWAYS use the Write tool to create files** — never use `Bash(cat << 'EOF')` or heredoc commands for file creation. **ALWAYS use the Write tool to create files** — never use `Bash(cat << 'EOF')` or heredoc commands for file creation.

File diff suppressed because it is too large Load Diff

View File

@@ -43,7 +43,10 @@ Output: Milestone archived (roadmap + requirements), PROJECT.md evolved, git tag
- Look for `.planning/v{{version}}-MILESTONE-AUDIT.md` - Look for `.planning/v{{version}}-MILESTONE-AUDIT.md`
- If missing or stale: recommend `/gsd-audit-milestone` first - If missing or stale: recommend `/gsd-audit-milestone` first
- If audit status is `gaps_found`: recommend `/gsd-plan-milestone-gaps` first - If audit status is `gaps_found`: recommend closing the gaps inline
(the audit output already enumerates them — insert closure phases
via `/gsd-phase --insert <N>` plus the standard
discuss/plan/execute chain) before proceeding.
- If audit status is `passed`: proceed to step 1 - If audit status is `passed`: proceed to step 1
```markdown ```markdown
@@ -54,8 +57,11 @@ Output: Milestone archived (roadmap + requirements), PROJECT.md evolved, git tag
requirements coverage, cross-phase integration, and E2E flows. requirements coverage, cross-phase integration, and E2E flows.
{If audit has gaps:} {If audit has gaps:}
⚠ Milestone audit found gaps. Run `/gsd-plan-milestone-gaps` to create ⚠ Milestone audit found gaps. The audit output already enumerates the
phases that close the gaps, or proceed anyway to accept as tech debt. unsatisfied requirements, cross-phase issues, and broken flows — insert
a closure phase per gap with `/gsd-phase --insert <N>` and run the
standard `/gsd-discuss-phase` → `/gsd-plan-phase` → `/gsd-execute-phase`
chain. Or proceed anyway to accept the gaps as tech debt.
{If audit passed:} {If audit passed:}
✓ Milestone audit passed. Proceeding with completion. ✓ Milestone audit passed. Proceeding with completion.

View File

@@ -1,7 +1,7 @@
--- ---
name: gsd:plan-phase name: gsd:plan-phase
description: Create detailed phase plan (PLAN.md) with verification loop description: Create detailed phase plan (PLAN.md) with verification loop
argument-hint: "[phase] [--auto] [--research] [--skip-research] [--gaps] [--skip-verify] [--prd <file>] [--reviews] [--text] [--tdd] [--mvp]" argument-hint: "[phase] [--auto] [--research] [--skip-research] [--research-phase <N>] [--view] [--gaps] [--skip-verify] [--prd <file>] [--reviews] [--text] [--tdd] [--mvp]"
agent: gsd-planner agent: gsd-planner
allowed-tools: allowed-tools:
- Read - Read
@@ -19,6 +19,13 @@ Create executable phase prompts (PLAN.md files) for a roadmap phase with integra
**Default flow:** Research (if needed) → Plan → Verify → Done **Default flow:** Research (if needed) → Plan → Verify → Done
**Research-only mode (`--research-phase <N>`):** Spawn `gsd-phase-researcher` for phase `N`, write `RESEARCH.md`, then exit before the planner runs. Useful for cross-phase research, doc review before committing to a planning approach, and correction-without-replanning loops where iterating on research alone is dramatically cheaper than re-spawning the planner. Replaces the deleted `/gsd-research-phase` command (#3042).
**Research-only modifiers:**
- **No flag** — when `RESEARCH.md` already exists, prompt the user to choose `update / view / skip`.
- **`--research`** — force-refresh: re-spawn the researcher unconditionally, no prompt. Skips the existing-RESEARCH.md menu.
- **`--view`** — view-only: print existing `RESEARCH.md` to stdout. Does not spawn the researcher. Cheapest mode for the correction-without-replanning loop. If no `RESEARCH.md` exists yet, errors with a hint to drop `--view`.
**Orchestrator role:** Parse arguments, validate phase, research domain (unless skipped), spawn gsd-planner, verify with gsd-plan-checker, iterate until pass or max iterations, present results. **Orchestrator role:** Parse arguments, validate phase, research domain (unless skipped), spawn gsd-planner, verify with gsd-plan-checker, iterate until pass or max iterations, present results.
</objective> </objective>

View File

@@ -1,6 +1,6 @@
# GSD Agent Reference # GSD Agent Reference
> Full role cards for 21 primary agents plus concise stubs for 10 advanced/specialized agents (31 shipped agents total). The `agents/` directory and [`docs/INVENTORY.md`](INVENTORY.md) are the authoritative roster; see [Architecture](ARCHITECTURE.md) for context. > Full role cards for 21 primary agents plus concise stubs for 12 advanced/specialized agents (33 shipped agents total). The `agents/` directory and [`docs/INVENTORY.md`](INVENTORY.md) are the authoritative roster; see [Architecture](ARCHITECTURE.md) for context.
--- ---
@@ -10,7 +10,7 @@ GSD uses a multi-agent architecture where thin orchestrators (workflow files) sp
### Agent Categories ### Agent Categories
> The table below covers the **21 primary agents** detailed in this section. Ten additional shipped agents (pattern-mapper, debug-session-manager, code-reviewer, code-fixer, ai-researcher, domain-researcher, eval-planner, eval-auditor, framework-selector, intel-updater) have concise stubs in the [Advanced and Specialized Agents](#advanced-and-specialized-agents) section below. For the authoritative 31-agent roster, see [`docs/INVENTORY.md`](INVENTORY.md) and the `agents/` directory. > The table below covers the **21 primary agents** detailed in this section. Twelve additional shipped agents (pattern-mapper, debug-session-manager, code-reviewer, code-fixer, ai-researcher, domain-researcher, eval-planner, eval-auditor, framework-selector, intel-updater, doc-classifier, doc-synthesizer) have concise stubs in the [Advanced and Specialized Agents](#advanced-and-specialized-agents) section below. For the authoritative 33-agent roster, see [`docs/INVENTORY.md`](INVENTORY.md) and the `agents/` directory.
| Category | Count | Agents | | Category | Count | Agents |
|----------|-------|--------| |----------|-------|--------|
@@ -480,7 +480,7 @@ Communication style, decision patterns, debugging approach, UX preferences, vend
## Advanced and Specialized Agents ## Advanced and Specialized Agents
Ten additional agents ship under `agents/gsd-*.md` and are used by specialty workflows (`/gsd-ai-integration-phase`, `/gsd-eval-review`, `/gsd-code-review`, `/gsd-code-review-fix`, `/gsd-debug`, `/gsd-intel`, `/gsd-select-framework`) and by the planner pipeline. Each carries full frontmatter in its agent file; the stubs below are concise by design. The authoritative roster (with spawner and primary-doc status per agent) lives in [`docs/INVENTORY.md`](INVENTORY.md). Twelve additional agents ship under `agents/gsd-*.md` and are used by specialty workflows (`/gsd-ai-integration-phase`, `/gsd-eval-review`, `/gsd-code-review`, `/gsd-code-review --fix`, `/gsd-debug`, `/gsd-intel`, `/gsd-select-framework`, `/gsd-ingest-docs`) and by the planner pipeline. Each carries full frontmatter in its agent file; the stubs below are concise by design. The authoritative roster (with spawner and primary-doc status per agent) lives in [`docs/INVENTORY.md`](INVENTORY.md).
### gsd-pattern-mapper ### gsd-pattern-mapper
@@ -548,7 +548,7 @@ Ten additional agents ship under `agents/gsd-*.md` and are used by specialty wor
| Property | Value | | Property | Value |
|----------|-------| |----------|-------|
| **Spawned by** | `/gsd-code-review-fix` | | **Spawned by** | `/gsd-code-review --fix` |
| **Parallelism** | Single instance | | **Parallelism** | Single instance |
| **Tools** | Read, Edit, Write, Bash, Grep, Glob | | **Tools** | Read, Edit, Write, Bash, Grep, Glob |
| **Model (balanced)** | Sonnet | | **Model (balanced)** | Sonnet |

View File

@@ -111,14 +111,25 @@ Multiple layers prevent common failure modes:
User-facing entry points. Each file contains YAML frontmatter (name, description, allowed-tools) and a prompt body that bootstraps the workflow. Commands are installed as: User-facing entry points. Each file contains YAML frontmatter (name, description, allowed-tools) and a prompt body that bootstraps the workflow. Commands are installed as:
- **Claude Code:** Custom slash commands (`/gsd-command-name`) - **Claude Code:** Custom slash commands (hyphen form, `/gsd-command-name`)
- **OpenCode / Kilo:** Slash commands (`/gsd-command-name`) - **OpenCode / Kilo:** Slash commands (hyphen form, `/gsd-command-name`)
- **Codex:** Skills (`$gsd-command-name`) - **Codex:** Skills (`$gsd-command-name`)
- **Copilot:** Slash commands (`/gsd-command-name`) - **Copilot:** Slash commands (hyphen form, `/gsd-command-name`)
- **Gemini CLI:** Slash commands under the `gsd:` namespace (colon form, `/gsd:command-name`) — Gemini namespaces all custom commands under their plugin id, so the install path rewrites every body-text reference to colon form
- **Antigravity:** Skills - **Antigravity:** Skills
**Total commands:** see [`docs/INVENTORY.md`](INVENTORY.md#commands) for the authoritative count and full roster. **Total commands:** see [`docs/INVENTORY.md`](INVENTORY.md#commands) for the authoritative count and full roster.
#### Two-stage hierarchical routing (v1.40, [#2792](https://github.com/gsd-build/get-shit-done/issues/2792))
To keep the eager skill-listing token cost low, v1.40 introduces six namespace **meta-skills** (`gsd-workflow`, `gsd-project`, `gsd-review`, `gsd-context`, `gsd-manage`, `gsd-ideate` — sourced from `commands/gsd/ns-*.md`, but the invocable `name:` is the bare form shown here) layered above the concrete sub-skills. The model sees 6 namespace routers (~120 tokens) instead of a flat 86-skill listing (~2,150 tokens), selects a namespace, then routes to the concrete sub-skill via a routing table embedded in the namespace router's body. Namespace skills are **additive** — every concrete command is still directly invocable.
The router descriptions use pipe-separated keyword tags (≤ 60 chars) per the Tool Attention research showing keyword-dense tags outperform prose for routing at ~40 % the token cost.
#### MCP token-budget interaction
The eager skill listing is one of two recurring per-turn token costs. The other is the MCP tool schema injected by every enabled MCP server in `.claude/settings.json`. Heavyweight MCP servers (browser/playwright, Mac-tools, Windows-tools) can each cost 20 k+ tokens per turn — often dwarfing what `model_profile` tuning saves. The toggle lives in the Claude Code harness (`enabledMcpjsonServers` / `disabledMcpjsonServers` in `.claude/settings.json`) and is **not** a GSD concern. Together, the two-stage routing layer (#2792) and disciplined MCP enablement are the largest cost levers per turn. See [`docs/USER-GUIDE.md`](USER-GUIDE.md) and `references/context-budget.md` for the audit checklist.
### Workflows (`get-shit-done/workflows/*.md`) ### Workflows (`get-shit-done/workflows/*.md`)
Orchestration logic that commands reference. Contains the step-by-step process including: Orchestration logic that commands reference. Contains the step-by-step process including:
@@ -579,7 +590,7 @@ The installer (`bin/install.js`, ~3,000 lines) handles:
- Augment Code: Skills-first with full skill conversion and config management - Augment Code: Skills-first with full skill conversion and config management
5. **Path normalization** — Replaces `~/.claude/` paths with runtime-specific paths 5. **Path normalization** — Replaces `~/.claude/` paths with runtime-specific paths
6. **Settings integration** — Registers hooks in runtime's `settings.json` 6. **Settings integration** — Registers hooks in runtime's `settings.json`
7. **Patch backup** — Since v1.17, backs up locally modified files to `gsd-local-patches/` for `/gsd-reapply-patches` 7. **Patch backup** — Since v1.17, backs up locally modified files to `gsd-local-patches/` for `/gsd-update --reapply`
8. **Manifest tracking** — Writes `gsd-file-manifest.json` for clean uninstall 8. **Manifest tracking** — Writes `gsd-file-manifest.json` for clean uninstall
9. **Uninstall mode**`--uninstall` removes all GSD files, hooks, and settings 9. **Uninstall mode**`--uninstall` removes all GSD files, hooks, and settings

View File

@@ -250,8 +250,15 @@ node gsd-tools.cjs validate consistency
# Check .planning/ integrity, optionally repair # Check .planning/ integrity, optionally repair
node gsd-tools.cjs validate health [--repair] node gsd-tools.cjs validate health [--repair]
# Probe context-window utilization for status-line / hook callers (v1.40.0)
node gsd-tools.cjs validate context
``` ```
`validate context` emits a structured envelope with `utilization`, `status`
(`ok` / `warn` / `critical` at the 60 % / 70 % thresholds), and a
`suggestion` string. The same data backs `/gsd-health --context`.
--- ---
## Template Commands ## Template Commands

View File

@@ -6,10 +6,29 @@
## Command Syntax ## Command Syntax
- **Claude Code / Gemini / Copilot:** `/gsd-command-name [args]` - **Claude Code / Copilot / OpenCode / Kilo:** `/gsd-command-name [args]` (hyphen form)
- **OpenCode / Kilo:** `/gsd-command-name [args]` - **Gemini CLI:** `/gsd:command-name [args]` (colon form — Gemini namespaces commands under `gsd:`)
- **Codex:** `$gsd-command-name [args]` - **Codex:** `$gsd-command-name [args]`
The hyphen and colon forms are *runtime-specific spellings of the same command*. Whichever runtime you're on, the installer writes the correct form into your runtime's command directory.
---
## Namespace Meta-Skills
Six namespace routers ship as the first-stage entry points in v1.40. They keep the eager skill-listing token cost low (~120 tokens for 6 routers vs ~2,150 for a flat 86-skill listing) while the full surface remains directly invocable. The model selects a namespace, then routes to the concrete sub-skill. See [#2792](https://github.com/gsd-build/get-shit-done/issues/2792).
| Command | Routes to |
|---------|-----------|
| `/gsd-ns-workflow` | Phase pipeline — discuss / plan / execute / verify / phase / progress |
| `/gsd-ns-project` | Project lifecycle — milestones, audits, summary |
| `/gsd-ns-review` | Quality gates — code review, debug, audit, security, eval, ui |
| `/gsd-ns-context` | Codebase intelligence — map, graphify, docs, learnings |
| `/gsd-ns-manage` | Management — config, workspace, workstreams, thread, update, ship, inbox |
| `/gsd-ns-ideate` | Exploration & capture — explore, sketch, spike, spec, capture |
The namespace skills are **additive** — every existing concrete command (e.g. `/gsd-plan-phase`, `/gsd-code-review --fix`) is still invocable directly.
--- ---
## Core Workflow Commands ## Core Workflow Commands
@@ -123,6 +142,8 @@ Research, plan, and verify a phase.
| `--auto` | Skip interactive confirmations | | `--auto` | Skip interactive confirmations |
| `--research` | Force re-research even if RESEARCH.md exists | | `--research` | Force re-research even if RESEARCH.md exists |
| `--skip-research` | Skip domain research step | | `--skip-research` | Skip domain research step |
| `--research-phase <N>` | Research-only mode: spawn researcher for phase `<N>`, write RESEARCH.md, exit before planner. Replaces the deleted `gsd-research-phase` standalone command (#3042). |
| `--view` | Research-only modifier: when used with `--research-phase`, print existing RESEARCH.md to stdout and exit (no spawn). |
| `--gaps` | Gap closure mode (reads VERIFICATION.md, skips research) | | `--gaps` | Gap closure mode (reads VERIFICATION.md, skips research) |
| `--skip-verify` | Skip plan checker verification loop | | `--skip-verify` | Skip plan checker verification loop |
| `--prd <file>` | Use a PRD file instead of discuss-phase for context | | `--prd <file>` | Use a PRD file instead of discuss-phase for context |
@@ -134,12 +155,20 @@ Research, plan, and verify a phase.
**Prerequisites:** `.planning/ROADMAP.md` exists **Prerequisites:** `.planning/ROADMAP.md` exists
**Produces:** `{phase}-RESEARCH.md`, `{phase}-{N}-PLAN.md`, `{phase}-VALIDATION.md` **Produces:** `{phase}-RESEARCH.md`, `{phase}-{N}-PLAN.md`, `{phase}-VALIDATION.md`
**Research-only mode (`--research-phase <N>`):**
- No modifier: prompts `update / view / skip` if RESEARCH.md already exists.
- With `--research`: force-refresh — re-spawn researcher unconditionally, no prompt.
- With `--view`: print existing RESEARCH.md to stdout, no spawn. Errors if RESEARCH.md missing.
```bash ```bash
/gsd-plan-phase 1 # Research + plan + verify phase 1 /gsd-plan-phase 1 # Research + plan + verify phase 1
/gsd-plan-phase 3 --skip-research # Plan without research (familiar domain) /gsd-plan-phase 3 --skip-research # Plan without research (familiar domain)
/gsd-plan-phase --auto # Non-interactive planning /gsd-plan-phase --auto # Non-interactive planning
/gsd-plan-phase 2 --validate # Validate state before planning /gsd-plan-phase 2 --validate # Validate state before planning
/gsd-plan-phase 1 --bounce # Plan + external bounce validation /gsd-plan-phase 1 --bounce # Plan + external bounce validation
/gsd-plan-phase --research-phase 4 # Research only on phase 4 (prompts if RESEARCH.md exists)
/gsd-plan-phase --research-phase 4 --view # Print existing RESEARCH.md, no spawn
/gsd-plan-phase --research-phase 4 --research # Force-refresh research, no prompt
``` ```
--- ---
@@ -689,15 +718,19 @@ Generate a developer behavioral profile from Claude Code session analysis across
### `/gsd-health` ### `/gsd-health`
Validate `.planning/` directory integrity. Validate `.planning/` directory integrity. With `--context`, probes the
context-window utilization guard against the 60 % / 70 % thresholds (added
v1.40.0, [#2792](https://github.com/gsd-build/get-shit-done/issues/2792)).
| Flag | Description | | Flag | Description |
|------|-------------| |------|-------------|
| `--repair` | Auto-fix recoverable issues | | `--repair` | Auto-fix recoverable issues |
| `--context` | Probe context-window utilization; warns at 60 %, critical at 70 % |
```bash ```bash
/gsd-health # Check integrity /gsd-health # Check integrity
/gsd-health --repair # Check and fix /gsd-health --repair # Check and fix
/gsd-health --context # Context-utilization triage
``` ```
### `/gsd-cleanup` ### `/gsd-cleanup`

View File

@@ -16,6 +16,8 @@ GSD stores project settings in `.planning/config.json`. Created during `/gsd-new
"granularity": "standard", "granularity": "standard",
"model_profile": "balanced", "model_profile": "balanced",
"model_overrides": {}, "model_overrides": {},
"models": {},
"dynamic_routing": null,
"planning": { "planning": {
"commit_docs": true, "commit_docs": true,
"search_gitignored": false, "search_gitignored": false,
@@ -117,9 +119,14 @@ GSD stores project settings in `.planning/config.json`. Created during `/gsd-new
| `model_profile` | enum | `quality`, `balanced`, `budget`, `adaptive`, `inherit` | `balanced` | Model tier for each agent (see [Model Profiles](#model-profiles)). `adaptive` was added per [#1713](https://github.com/gsd-build/get-shit-done/issues/1713) / [#1806](https://github.com/gsd-build/get-shit-done/issues/1806) and resolves the same way as the other tiers under runtime-aware profiles. | | `model_profile` | enum | `quality`, `balanced`, `budget`, `adaptive`, `inherit` | `balanced` | Model tier for each agent (see [Model Profiles](#model-profiles)). `adaptive` was added per [#1713](https://github.com/gsd-build/get-shit-done/issues/1713) / [#1806](https://github.com/gsd-build/get-shit-done/issues/1806) and resolves the same way as the other tiers under runtime-aware profiles. |
| `runtime` | string | `claude`, `codex`, or any string | (none) | Active runtime for [runtime-aware profile resolution](#runtime-aware-profiles-2517). When set, profile tiers (opus/sonnet/haiku) resolve to runtime-native model IDs. Today only the Codex install path emits per-agent model IDs from this resolver; other runtimes (`opencode`, `gemini`, `qwen`, `copilot`, …) consume the resolver at spawn time and gain dedicated install-path support in [#2612](https://github.com/gsd-build/get-shit-done/issues/2612). When unset (default), behavior is unchanged from prior versions. Added in v1.39 | | `runtime` | string | `claude`, `codex`, or any string | (none) | Active runtime for [runtime-aware profile resolution](#runtime-aware-profiles-2517). When set, profile tiers (opus/sonnet/haiku) resolve to runtime-native model IDs. Today only the Codex install path emits per-agent model IDs from this resolver; other runtimes (`opencode`, `gemini`, `qwen`, `copilot`, …) consume the resolver at spawn time and gain dedicated install-path support in [#2612](https://github.com/gsd-build/get-shit-done/issues/2612). When unset (default), behavior is unchanged from prior versions. Added in v1.39 |
| `model_profile_overrides.<runtime>.<tier>` | string \| object | per-runtime tier override | (none) | Override the runtime-aware tier mapping for a specific `(runtime, tier)`. Tier is one of `opus`, `sonnet`, `haiku`. Value is either a model ID string (e.g. `"gpt-5-pro"`) or `{ model, reasoning_effort }`. See [Runtime-Aware Profiles](#runtime-aware-profiles-2517). Added in v1.39 | | `model_profile_overrides.<runtime>.<tier>` | string \| object | per-runtime tier override | (none) | Override the runtime-aware tier mapping for a specific `(runtime, tier)`. Tier is one of `opus`, `sonnet`, `haiku`. Value is either a model ID string (e.g. `"gpt-5-pro"`) or `{ model, reasoning_effort }`. See [Runtime-Aware Profiles](#runtime-aware-profiles-2517). Added in v1.39 |
| `models.<phase_type>` | enum | `opus`, `sonnet`, `haiku`, `inherit` | (none) | Per-phase-type model tier. Six accepted slots: `planning`, `discuss`, `research`, `execution`, `verification`, `completion`. Lets you tune at the phase level ("Opus for planning, Sonnet for the rest") without learning agent names. Resolves between `model_overrides` (higher) and `model_profile` (lower); see [Per-Phase-Type Models](#per-phase-type-models-models--added-in-v140). Added in v1.40 ([#3023](https://github.com/gsd-build/get-shit-done/pull/3030)) |
| `dynamic_routing.enabled` | boolean | `true`, `false` | `false` | Master switch for [dynamic routing with failure-tier escalation](#dynamic-routing-with-failure-tier-escalation-dynamic_routing--added-in-v140). When `true`, agents resolve to `tier_models[default_tier]` and escalate one tier up on orchestrator-detected soft failure. Added in v1.40 ([#3024](https://github.com/gsd-build/get-shit-done/pull/3031)) |
| `dynamic_routing.tier_models.<tier>` | enum | `opus`, `sonnet`, `haiku` | (none) | Tier alias for `light`, `standard`, or `heavy`. Used when `dynamic_routing.enabled: true`. Added in v1.40 |
| `dynamic_routing.escalate_on_failure` | boolean | `true`, `false` | `true` | When `false`, escalation is disabled even if `enabled: true` — every attempt uses the default tier. Added in v1.40 |
| `dynamic_routing.max_escalations` | integer | `0`, `1`, `2`, … | `1` | Hard cap on retries per agent invocation. Beyond the cap the resolver returns the cap-tier model. Added in v1.40 |
| `project_code` | string | any short string | (none) | Prefix for phase directory names (e.g., `"ABC"` produces `ABC-01-setup/`). Added in v1.31 | | `project_code` | string | any short string | (none) | Prefix for phase directory names (e.g., `"ABC"` produces `ABC-01-setup/`). Added in v1.31 |
| `response_language` | string | language code | (none) | Language for agent responses (e.g., `"pt"`, `"ko"`, `"ja"`). Propagates to all spawned agents for cross-phase language consistency. Added in v1.32 | | `response_language` | string | language code | (none) | Language for agent responses (e.g., `"pt"`, `"ko"`, `"ja"`). Propagates to all spawned agents for cross-phase language consistency. Added in v1.32 |
| `context_window` | number | any integer | `200000` | Context window size in tokens. Set `1000000` for 1M-context models (e.g., `claude-opus-4-7[1m]`). Values `>= 500000` enable adaptive context enrichment (full-body reads of prior SUMMARY.md, deeper anti-pattern reads). Configured via `/gsd-settings-advanced`. | | `context_window` | number | any integer | `200000` | Context window size in tokens. Set `1000000` for 1M-context models (e.g., `claude-opus-4-7[1m]`). Values `>= 500000` enable adaptive context enrichment (full-body reads of prior SUMMARY.md, deeper anti-pattern reads). Configured via `/gsd-config --advanced`. |
| `context_profile` | string | `dev`, `research`, `review` | (none) | Execution context preset that applies a pre-configured bundle of mode, model, and workflow settings for the current type of work. Added in v1.34 | | `context_profile` | string | `dev`, `research`, `review` | (none) | Execution context preset that applies a pre-configured bundle of mode, model, and workflow settings for the current type of work. Added in v1.34 |
| `claude_md_path` | string | any file path | `./CLAUDE.md` | Custom output path for the generated CLAUDE.md file. Useful for monorepos or projects that need CLAUDE.md in a non-root location. Defaults to `./CLAUDE.md` at the project root. Added in v1.36 | | `claude_md_path` | string | any file path | `./CLAUDE.md` | Custom output path for the generated CLAUDE.md file. Useful for monorepos or projects that need CLAUDE.md in a non-root location. Defaults to `./CLAUDE.md` at the project root. Added in v1.36 |
| `claude_md_assembly.mode` | enum | `embed`, `link` | `embed` | Controls how managed sections are written into CLAUDE.md. `embed` (default) inlines content between GSD markers. `link` writes `@.planning/<source-path>` instead — Claude Code expands the reference at runtime, reducing CLAUDE.md size by ~65% on typical projects. `link` only applies to sections that have a real source file; `workflow` and fallback sections always embed. Per-block overrides: `claude_md_assembly.blocks.<section>` (e.g. `claude_md_assembly.blocks.architecture: link`). Added in v1.38 | | `claude_md_assembly.mode` | enum | `embed`, `link` | `embed` | Controls how managed sections are written into CLAUDE.md. `embed` (default) inlines content between GSD markers. `link` writes `@.planning/<source-path>` instead — Claude Code expands the reference at runtime, reducing CLAUDE.md size by ~65% on typical projects. `link` only applies to sections that have a real source file; `workflow` and fallback sections always embed. Per-block overrides: `claude_md_assembly.blocks.<section>` (e.g. `claude_md_assembly.blocks.architecture: link`). Added in v1.38 |
@@ -136,7 +143,7 @@ GSD stores project settings in `.planning/config.json`. Created during `/gsd-new
## Integration Settings ## Integration Settings
Configured interactively via [`/gsd-settings-integrations`](COMMANDS.md#gsd-settings-integrations). These are *connectivity* settings — API keys and cross-tool routing — and are intentionally kept separate from `/gsd-settings` (workflow toggles). Configured interactively via [`/gsd-config --integrations`](COMMANDS.md#gsd-config). These are *connectivity* settings — API keys and cross-tool routing — and are intentionally kept separate from `/gsd-settings` (workflow toggles).
### Search API keys ### Search API keys
@@ -165,7 +172,7 @@ The `<cli>` slug is validated against `[a-zA-Z0-9_-]+`. Empty or path-containing
### Agent-skill injection (dynamic) ### Agent-skill injection (dynamic)
`agent_skills.<agent-type>` extends the `agent_skills` map documented below. Slug is validated against `[a-zA-Z0-9_-]+` — no path separators, no whitespace, no shell metacharacters. Configured interactively via `/gsd-settings-integrations`. `agent_skills.<agent-type>` extends the `agent_skills` map documented below. Slug is validated against `[a-zA-Z0-9_-]+` — no path separators, no whitespace, no shell metacharacters. Configured interactively via `/gsd-config --integrations`.
--- ---
@@ -192,7 +199,7 @@ All workflow toggles follow the **absent = enabled** pattern. If a key is missin
| `workflow.text_mode` | boolean | `false` | Replaces AskUserQuestion TUI menus with plain-text numbered lists. Required for Claude Code remote sessions (`/rc` mode) where TUI menus don't render. Can also be set per-session with `--text` flag on discuss-phase. Added in v1.28 | | `workflow.text_mode` | boolean | `false` | Replaces AskUserQuestion TUI menus with plain-text numbered lists. Required for Claude Code remote sessions (`/rc` mode) where TUI menus don't render. Can also be set per-session with `--text` flag on discuss-phase. Added in v1.28 |
| `workflow.use_worktrees` | boolean | `true` | When `false`, disables git worktree isolation for parallel execution. Users who prefer sequential execution or whose environment does not support worktrees can disable this. Added in v1.31 | | `workflow.use_worktrees` | boolean | `true` | When `false`, disables git worktree isolation for parallel execution. Users who prefer sequential execution or whose environment does not support worktrees can disable this. Added in v1.31 |
| `workflow.worktree_skip_hooks` | boolean | `false` | When `true`, executor agents in worktree mode pass `--no-verify` (skipping pre-commit hooks) and post-wave hook validation runs against the merged result instead. Opt-in escape hatch for projects whose hooks cannot run in agent worktrees. Default `false` runs hooks on every commit (#2924). | | `workflow.worktree_skip_hooks` | boolean | `false` | When `true`, executor agents in worktree mode pass `--no-verify` (skipping pre-commit hooks) and post-wave hook validation runs against the merged result instead. Opt-in escape hatch for projects whose hooks cannot run in agent worktrees. Default `false` runs hooks on every commit (#2924). |
| `workflow.code_review` | boolean | `true` | Enable `/gsd-code-review` and `/gsd-code-review-fix` commands. When `false`, the commands exit with a configuration gate message. Added in v1.34 | | `workflow.code_review` | boolean | `true` | Enable `/gsd-code-review` and `/gsd-code-review --fix` commands. When `false`, the commands exit with a configuration gate message. Added in v1.34 |
| `workflow.code_review_depth` | string | `standard` | Default review depth for `/gsd-code-review`: `quick` (pattern-matching only), `standard` (per-file analysis), or `deep` (cross-file with import graphs). Can be overridden per-run with `--depth=`. Added in v1.34 | | `workflow.code_review_depth` | string | `standard` | Default review depth for `/gsd-code-review`: `quick` (pattern-matching only), `standard` (per-file analysis), or `deep` (cross-file with import graphs). Can be overridden per-run with `--depth=`. Added in v1.34 |
| `workflow.plan_bounce` | boolean | `false` | Run external validation script against generated plans. When enabled, the plan-phase orchestrator pipes each PLAN.md through the script specified by `plan_bounce_script` and blocks on non-zero exit. Added in v1.36 | | `workflow.plan_bounce` | boolean | `false` | Run external validation script against generated plans. When enabled, the plan-phase orchestrator pipes each PLAN.md through the script specified by `plan_bounce_script` and blocks on non-zero exit. Added in v1.36 |
| `workflow.plan_bounce_script` | string | (none) | Path to the external script invoked for plan bounce validation. Receives the PLAN.md path as its first argument. Required when `plan_bounce` is `true`. Added in v1.36 | | `workflow.plan_bounce_script` | string | (none) | Path to the external script invoked for plan bounce validation. Receives the PLAN.md path as its first argument. Required when `plan_bounce` is `true`. Added in v1.36 |
@@ -385,6 +392,21 @@ The `features.*` namespace is a dynamic key pattern — new feature flags can be
--- ---
## STATE.md Frontmatter (Phase Lifecycle)
`STATE.md` carries YAML frontmatter that the status-line hook reads on every render. v1.40 adds four optional phase-lifecycle fields read by `parseStateMd()` and rendered by `formatGsdState()`:
| Field | Type | Purpose |
|-------|------|---------|
| `active_phase` | string (e.g. `"4.5"`) | Phase number when an orchestrator command is in flight |
| `next_action` | string | Recommended next command when idle (`discuss-phase` / `plan-phase` / `execute-phase` / `verify-phase`) |
| `next_phases` | YAML flow array | Phases the `next_action` applies to (e.g. `["4.5"]`) |
| `progress` | block | Nested `total_phases` / `completed_phases` / `percent` for the milestone progress bar |
All four fields are **optional and additive** — STATE.md files without them keep rendering exactly as in v1.38.x. See [`STATE-MD-LIFECYCLE.md`](STATE-MD-LIFECYCLE.md) for the full field reference, parser constraints, and rendering scenes.
---
## Git Branching ## Git Branching
| Setting | Type | Default | Description | | Setting | Type | Default | Description |
@@ -643,6 +665,169 @@ OpenCode's `task` interface do not accept an inline `model` parameter, so
running `gsd install <runtime>` after editing `model_overrides` is required running `gsd install <runtime>` after editing `model_overrides` is required
for the change to take effect. See issue #2256. for the change to take effect. See issue #2256.
### Per-Phase-Type Models (`models`) — added in v1.40
> Express tuning at the **phase** level (planning, research, execution, verification) without learning the agent taxonomy. Added in [#3023](https://github.com/gsd-build/get-shit-done/pull/3030).
`model_overrides` is per-**agent** (precise but verbose; you have to know that `gsd-codebase-mapper` is research and `gsd-doc-writer` is execution). The `models` block lets you say "Opus for planning and execution, Sonnet for the rest" in two lines:
```json
{
"model_profile": "balanced",
"models": {
"planning": "opus",
"discuss": "opus",
"research": "sonnet",
"execution": "opus",
"verification": "sonnet",
"completion": "sonnet"
},
"model_overrides": {
"gsd-codebase-mapper": "haiku"
}
}
```
#### Phase-type → agent mapping
| Phase type | Agents |
|---|---|
| `planning` | `gsd-planner`, `gsd-roadmapper`, `gsd-pattern-mapper` |
| `discuss` | (reserved — no subagent today) |
| `research` | `gsd-phase-researcher`, `gsd-project-researcher`, `gsd-research-synthesizer`, `gsd-codebase-mapper`, `gsd-ui-researcher` |
| `execution` | `gsd-executor`, `gsd-debugger`, `gsd-doc-writer` |
| `verification` | `gsd-verifier`, `gsd-plan-checker`, `gsd-integration-checker`, `gsd-nyquist-auditor`, `gsd-ui-checker`, `gsd-ui-auditor`, `gsd-doc-verifier` |
| `completion` | (reserved — no subagent today) |
`discuss` and `completion` are accepted by the schema for forward compatibility; setting them today is a no-op until a subagent maps to them.
#### Resolution precedence (highest → lowest)
```text
1. model_overrides[<agent>] ← per-agent; full IDs; targeted exception
2. dynamic_routing.tier_models[<tier>] ← when enabled (see §Dynamic Routing)
3. models[<phase_type>] ← coarse phase-level tier (this section)
4. model_profile (per-agent col) ← global tier strategy
5. Runtime default ← when nothing else applies
```
The five layers compose top-down: `model_profile` is the base tier, `models[<phase_type>]` overrides at the phase level, `dynamic_routing` (when enabled) escalates per-attempt on soft failure, `model_overrides[<agent>]` carves per-agent exceptions at the top, and the runtime default applies when nothing else does. In the example above, all five research agents resolve to `sonnet` *except* `gsd-codebase-mapper`, which the per-agent override pins to `haiku`. `dynamic_routing` is disabled by default — when off (`enabled: false` or block omitted), this section's behavior is unchanged from today.
#### Accepted values
`models.<phase_type>` accepts only tier aliases:
| Value | Effect |
|---|---|
| `"opus"` / `"sonnet"` / `"haiku"` | Standard tier — runtime resolution maps to the active runtime's model for that tier |
| `"inherit"` | Agents in this phase follow the session model (same semantics as `model_profile: "inherit"`) |
If you need a fully-qualified model ID (`"openai/gpt-5"`, `"google/gemini-2.5-pro"`), use `model_overrides` per agent instead. `models.*` is intentionally tier-only so the runtime-aware mapping stays correct on Codex / OpenCode / Gemini CLI installs.
#### When to use which
| You want | Use |
|---|---|
| One global tier strategy ("balanced everywhere") | `model_profile` |
| Coarse phase-level tuning ("Opus for planning") | `models.<phase_type>` |
| Per-agent precision ("force haiku on the codebase mapper") | `model_overrides[<agent>]` |
| Full model ID for a specific agent | `model_overrides[<agent>]: "openai/gpt-5"` |
Mix freely — the precedence rule above resolves any overlap deterministically.
#### Validation
`config-set` rejects unknown phase-types:
```bash
$ gsd config-set models.deployment opus
Error: 'models.deployment' is not a valid config key
# Valid:
$ gsd config-set models.research sonnet
```
Direct edits to `.planning/config.json` are looser — the resolver simply ignores values it doesn't recognize and falls through to the profile tier — so a typo doesn't silently break tier resolution.
### Dynamic Routing with Failure-Tier Escalation (`dynamic_routing`) — added in v1.40
> Start cheap, escalate only when the agent fails the gate. Added in [#3024](https://github.com/gsd-build/get-shit-done/pull/3031).
`dynamic_routing` lets you pay for the cheap tier by default and only escalate to the more expensive tier when the orchestrator detects a soft failure (verification inconclusive, plan-check FLAG, etc.).
```json
{
"dynamic_routing": {
"enabled": true,
"tier_models": {
"light": "haiku",
"standard": "sonnet",
"heavy": "opus"
},
"escalate_on_failure": true,
"max_escalations": 1
}
}
```
#### Agent default tiers
Each agent in `MODEL_PROFILES` declares one of three default tiers. The resolver picks `tier_models[default_tier]` for the first attempt.
| Tier | Agents | Use case |
|---|---|---|
| `light` | gsd-codebase-mapper, gsd-pattern-mapper, gsd-research-synthesizer, gsd-plan-checker, gsd-integration-checker, gsd-nyquist-auditor, gsd-ui-checker, gsd-ui-auditor, gsd-doc-verifier | Cheap/fast — pure mappers, scanners, low-stakes audits |
| `standard` | gsd-executor, gsd-phase-researcher, gsd-project-researcher, gsd-verifier, gsd-doc-writer, gsd-ui-researcher | Default workhorse — research, writing, primary verification |
| `heavy` | gsd-planner, gsd-roadmapper, gsd-debugger | Deep reasoning — already at top, can't escalate further |
#### Escalation flow
```text
1. Orchestrator spawns agent → resolver returns tier_models[default_tier]
2. Soft failure?
├─ no → ✓ done (cheap path)
└─ yes → orchestrator re-spawns at attempt+1
→ resolver returns tier_models[next_tier_up]
→ cap at max_escalations
3. Hard failure (exception/crash) → bypass escalation, surface immediately
```
If `dynamic_routing.escalate_on_failure: false`, soft failures do **not** advance the tier — every respawn keeps using `tier_models[default_tier]` regardless of the attempt counter. The kill-switch overrides the soft-failure branch above.
`light → standard → heavy → heavy` (heavy stays at heavy; can't go further).
#### Resolution precedence (highest → lowest)
1. **`model_overrides[<agent>]`** — full IDs accepted; targeted exception
2. **`dynamic_routing.tier_models[<tier>]`** (when `enabled: true`)
3. **`models[<phase_type>]`** — coarse phase-level (#3023)
4. **`model_profile`** — per-agent column from active profile
5. **Runtime default**
The `dynamic_routing` block is **disabled by default**`enabled: false` (or omitting the block) preserves today's static resolution exactly.
#### Settings
| Key | Type | Default | Description |
|---|---|---|---|
| `dynamic_routing.enabled` | boolean | `false` | Master switch. When `true`, the dynamic-routing resolver is used for tier selection. |
| `dynamic_routing.tier_models.light` | enum | (none) | Tier alias for the light tier. Typically `haiku`. |
| `dynamic_routing.tier_models.standard` | enum | (none) | Tier alias for standard. Typically `sonnet`. |
| `dynamic_routing.tier_models.heavy` | enum | (none) | Tier alias for heavy. Typically `opus`. |
| `dynamic_routing.escalate_on_failure` | boolean | `true` | When false, escalation is disabled (every attempt uses the default tier). |
| `dynamic_routing.max_escalations` | integer | `1` | Hard cap on retries per agent invocation. Prevents runaway loops. |
#### When to use which
| You want | Use |
|---|---|
| One tier strategy across all agents | `model_profile` |
| Coarse phase-level tuning | `models.<phase_type>` |
| Per-agent precision (full IDs) | `model_overrides` |
| **Cheap-by-default, escalate only on failure** | **`dynamic_routing`** |
`dynamic_routing` is structurally a *cost lever*: you pay Opus rates only for the hard cases that warrant Opus. Compose with `model_overrides` for per-agent exceptions (override always wins).
### Non-Claude Runtimes (Codex, OpenCode, Gemini CLI, Kilo) ### Non-Claude Runtimes (Codex, OpenCode, Gemini CLI, Kilo)
When GSD is installed for a non-Claude runtime, the installer automatically sets `resolve_model_ids: "omit"` in `~/.gsd/defaults.json`. This causes GSD to return an empty model parameter for all agents, so each agent uses whatever model the runtime is configured with. No additional setup is needed for the default case. When GSD is installed for a non-Claude runtime, the installer automatically sets `resolve_model_ids: "omit"` in `~/.gsd/defaults.json`. This causes GSD to return an empty model parameter for all agents, so each agent uses whatever model the runtime is configured with. No additional setup is needed for the default case.

View File

@@ -144,6 +144,11 @@
- [Agent Size-Budget Enforcement](#119-agent-size-budget-enforcement) - [Agent Size-Budget Enforcement](#119-agent-size-budget-enforcement)
- [Shared Boilerplate Extraction](#120-shared-boilerplate-extraction) - [Shared Boilerplate Extraction](#120-shared-boilerplate-extraction)
- [Knowledge Graph Integration](#121-knowledge-graph-integration) - [Knowledge Graph Integration](#121-knowledge-graph-integration)
- [v1.40.0 Features](#v1400-features)
- [Skill Surface Consolidation](#122-skill-surface-consolidation)
- [Namespace Meta-Skills (Two-Stage Routing)](#123-namespace-meta-skills-two-stage-routing)
- [Context-Window Utilization Guard](#124-context-window-utilization-guard)
- [Phase-Lifecycle Status-Line Read-Side](#125-phase-lifecycle-status-line-read-side)
- [v1.32 Features](#v132-features) - [v1.32 Features](#v132-features)
- [STATE.md Consistency Gates](#69-statemd-consistency-gates) - [STATE.md Consistency Gates](#69-statemd-consistency-gates)
- [Autonomous `--to N` Flag](#70-autonomous---to-n-flag) - [Autonomous `--to N` Flag](#70-autonomous---to-n-flag)
@@ -449,7 +454,6 @@
- REQ-MILE-08: New milestone MUST follow same flow as new-project (questions → research → requirements → roadmap) - REQ-MILE-08: New milestone MUST follow same flow as new-project (questions → research → requirements → roadmap)
- REQ-MILE-09: New milestone MUST NOT reset existing workflow configuration - REQ-MILE-09: New milestone MUST NOT reset existing workflow configuration
**Gap Closure:** `/gsd-plan-milestone-gaps` creates phases to close gaps identified by audit.
--- ---
@@ -865,7 +869,7 @@ continues. Drift detection cannot fail verification.
### 29. Todo Management ### 29. Todo Management
**Commands:** `/gsd-add-todo [desc]`, `/gsd-check-todos` **Commands:** `/gsd-add-todo [desc]`, `/gsd-capture --list`
**Purpose:** Capture ideas and tasks during sessions for later work. **Purpose:** Capture ideas and tasks during sessions for later work.
@@ -902,7 +906,7 @@ continues. Drift detection cannot fail verification.
- REQ-UPDATE-02: System MUST display changelog for new version before updating - REQ-UPDATE-02: System MUST display changelog for new version before updating
- REQ-UPDATE-03: System MUST be runtime-aware and target the correct directory - REQ-UPDATE-03: System MUST be runtime-aware and target the correct directory
- REQ-UPDATE-04: System MUST back up locally modified files to `gsd-local-patches/` - REQ-UPDATE-04: System MUST back up locally modified files to `gsd-local-patches/`
- REQ-UPDATE-05: `/gsd-reapply-patches` MUST restore local modifications after update - REQ-UPDATE-05: `/gsd-update --reapply` MUST restore local modifications after update
--- ---
@@ -923,6 +927,8 @@ continues. Drift detection cannot fail verification.
| `mode` | enum | `interactive` | `interactive` or `yolo` (auto-approve) | | `mode` | enum | `interactive` | `interactive` or `yolo` (auto-approve) |
| `granularity` | enum | `standard` | `coarse`, `standard`, or `fine` | | `granularity` | enum | `standard` | `coarse`, `standard`, or `fine` |
| `model_profile` | enum | `balanced` | `quality`, `balanced`, `budget`, or `inherit` | | `model_profile` | enum | `balanced` | `quality`, `balanced`, `budget`, or `inherit` |
| `models.<phase_type>` | enum | (none) | Per-phase-type tier override (`planning`, `discuss`, `research`, `execution`, `verification`, `completion`). Values: `opus`, `sonnet`, `haiku`, `inherit`. Coarse phase-level tuning that wins over `model_profile` but loses to per-agent `model_overrides`. See [CONFIGURATION.md](CONFIGURATION.md#per-phase-type-models-models--added-in-v140). Added in v1.40 |
| `dynamic_routing.enabled` | boolean | `false` | Master switch for failure-tier escalation. When `true`, agents resolve to `tier_models[default_tier]` and escalate one tier on orchestrator-detected soft failure. Capped by `max_escalations`. See [CONFIGURATION.md](CONFIGURATION.md#dynamic-routing-with-failure-tier-escalation-dynamic_routing--added-in-v140). Added in v1.40 |
| `workflow.research` | boolean | `true` | Domain research before planning | | `workflow.research` | boolean | `true` | Domain research before planning |
| `workflow.plan_check` | boolean | `true` | Plan verification loop | | `workflow.plan_check` | boolean | `true` | Plan verification loop |
| `workflow.verifier` | boolean | `true` | Post-execution verification | | `workflow.verifier` | boolean | `true` | Post-execution verification |
@@ -1030,14 +1036,25 @@ fix(03-01): correct auth token expiry
- REQ-HOOK-05: All hooks MUST include 3-second stdin timeout guard - REQ-HOOK-05: All hooks MUST include 3-second stdin timeout guard
- REQ-HOOK-06: All hooks MUST fail silently on any error - REQ-HOOK-06: All hooks MUST fail silently on any error
- REQ-HOOK-07: Context usage MUST normalize for autocompact buffer (16.5% reserved) - REQ-HOOK-07: Context usage MUST normalize for autocompact buffer (16.5% reserved)
- REQ-HOOK-08: Update banner MUST be opt-in and silent unless an update is available (PR #2795)
**Statusline Display:** **Statusline Display:**
``` ```text
[⬆ /gsd-update │] model │ [current task │] directory [█████░░░░░ 50%] [⬆ /gsd-update │] model │ [current task │] directory [█████░░░░░ 50%]
``` ```
Color coding: <50% green, <65% yellow, <80% orange, ≥80% red with skull emoji Color coding: <50% green, <65% yellow, <80% orange, ≥80% red with skull emoji
**Update Banner (opt-in, when GSD statusline isn't used):**
When the user declines (or keeps a non-GSD) statusline, the installer offers a SessionStart banner that surfaces update availability without occupying statusline real estate. The banner reads `~/.cache/gsd/gsd-update-check.json` (written by `gsd-check-update-worker.js`) and emits one line only when an update is available:
```text
GSD update available: 1.39.0 → 1.40.0. Run /gsd-update.
```
The banner is silent when up-to-date and rate-limits "check failed" diagnostics to once per 24 hours. Removed cleanly by `npx get-shit-done-cc --uninstall` or by deleting the SessionStart entry that references `gsd-update-banner.js`.
### 38. Developer Profiling ### 38. Developer Profiling
**Command:** `/gsd-profile-user [--questionnaire] [--refresh]` **Command:** `/gsd-profile-user [--questionnaire] [--refresh]`
@@ -1617,7 +1634,7 @@ Test suite that scans all agent, workflow, and command files for embedded inject
### 65. Claim Provenance Tagging ### 65. Claim Provenance Tagging
**Part of:** `/gsd-research-phase` **Part of:** `/gsd-plan-phase --research-phase <N>`
**Purpose:** Ensure research claims are tagged with source evidence and assumptions are logged separately. **Purpose:** Ensure research claims are tagged with source evidence and assumptions are logged separately.
@@ -2108,7 +2125,7 @@ Test suite that scans all agent, workflow, and command files for embedded inject
### 93. Code Review Pipeline ### 93. Code Review Pipeline
**Commands:** `/gsd-code-review`, `/gsd-code-review-fix` **Commands:** `/gsd-code-review`, `/gsd-code-review --fix`
**Purpose:** Structured review of source files changed during a phase, with a separate auto-fix pass that commits each fix atomically. **Purpose:** Structured review of source files changed during a phase, with a separate auto-fix pass that commits each fix atomically.
@@ -2116,7 +2133,7 @@ Test suite that scans all agent, workflow, and command files for embedded inject
- REQ-REVIEW-01: `gsd-code-review` MUST scope files to the phase using SUMMARY.md and git diff fallback - REQ-REVIEW-01: `gsd-code-review` MUST scope files to the phase using SUMMARY.md and git diff fallback
- REQ-REVIEW-02: Review MUST support three depth levels: `quick`, `standard`, `deep` - REQ-REVIEW-02: Review MUST support three depth levels: `quick`, `standard`, `deep`
- REQ-REVIEW-03: Findings MUST be severity-classified: Critical, Warning, Info - REQ-REVIEW-03: Findings MUST be severity-classified: Critical, Warning, Info
- REQ-REVIEW-04: `gsd-code-review-fix` MUST read REVIEW.md and fix Critical + Warning findings by default - REQ-REVIEW-04: `gsd-code-review --fix` MUST read REVIEW.md and fix Critical + Warning findings by default
- REQ-REVIEW-05: Each fix MUST be committed atomically with a descriptive message - REQ-REVIEW-05: Each fix MUST be committed atomically with a descriptive message
- REQ-REVIEW-06: `--auto` flag MUST enable fix + re-review iteration loop, capped at 3 iterations - REQ-REVIEW-06: `--auto` flag MUST enable fix + re-review iteration loop, capped at 3 iterations
- REQ-REVIEW-07: Feature MUST be gated by `workflow.code_review` config flag - REQ-REVIEW-07: Feature MUST be gated by `workflow.code_review` config flag
@@ -2255,7 +2272,7 @@ Test suite that scans all agent, workflow, and command files for embedded inject
### 103. Post-Merge Hunk Verification ### 103. Post-Merge Hunk Verification
**Command:** `/gsd-reapply-patches` **Command:** `/gsd-update --reapply`
**Purpose:** After applying local patches post-update, verify that all hunks were actually applied by comparing the expected patch content against the live filesystem. Surface any dropped or partial hunks immediately rather than silently accepting incomplete merges. **Purpose:** After applying local patches post-update, verify that all hunks were actually applied by comparing the expected patch content against the live filesystem. Surface any dropped or partial hunks immediately rather than silently accepting incomplete merges.
@@ -2600,3 +2617,83 @@ Users who run a memory / knowledge-base MCP server (for example, ExoCortex-style
**Configuration:** `graphify.enabled`, `graphify.build_timeout` **Configuration:** `graphify.enabled`, `graphify.build_timeout`
**Reference files:** `commands/gsd/graphify.md`, `bin/lib/graphify.cjs` **Reference files:** `commands/gsd/graphify.md`, `bin/lib/graphify.cjs`
---
## v1.40.0 Features
### 122. Skill Surface Consolidation
**Purpose:** Cut the eager skill-listing overhead by folding 31 micro-skills into 4 new grouped parents and 6 existing parents that absorb sub-operations as flags. Zero functional loss — every removed micro-skill's behavior survives via a flag on a consolidated parent. After consolidation, `commands/gsd/*.md` ships 59 sub-skills (plus 6 namespace meta-skills, see #123).
**Requirements:**
- REQ-CONSOLIDATE-01: Four new grouped skills replace clusters of micro-skills:
- `/gsd-capture` — folds add-todo (default), note (`--note`), add-backlog (`--backlog`), plant-seed (`--seed`), check-todos (`--list`)
- `/gsd-phase` — folds add-phase (default), insert-phase (`--insert`), remove-phase (`--remove`), edit-phase (`--edit`)
- `/gsd-config` — folds settings-advanced (`--advanced`), settings-integrations (`--integrations`), set-profile (`--profile`)
- `/gsd-workspace` — folds new-workspace (`--new`), list-workspaces (`--list`), remove-workspace (`--remove`)
- REQ-CONSOLIDATE-02: Six existing parents absorb wrap-up / sub-operations as flags: `/gsd-update --sync`, `/gsd-update --reapply`, `/gsd-sketch --wrap-up`, `/gsd-spike --wrap-up`, `/gsd-map-codebase --fast`, `/gsd-map-codebase --query`, `/gsd-code-review --fix`, `/gsd-progress --do`, `/gsd-progress --next`.
- REQ-CONSOLIDATE-03: Deleted micro-skill slash forms (the bare `gsd-add-todo`, `gsd-add-backlog`, `gsd-plant-seed`, `gsd-check-todos`, `gsd-add-phase`, `gsd-insert-phase`, `gsd-remove-phase`, `gsd-edit-phase`, `gsd-new-workspace`, `gsd-list-workspaces`, `gsd-remove-workspace`, `gsd-settings-advanced`, `gsd-settings-integrations`, `gsd-set-profile`, `gsd-sketch-wrap-up`, `gsd-spike-wrap-up`, `gsd-reapply-patches`, `gsd-code-review-fix`, …) MUST resolve to "Unknown command" — no shadow stubs.
- REQ-CONSOLIDATE-04: `autonomous.md` invokes `/gsd-code-review --fix` (was previously calling the deleted `gsd-code-review-fix`).
**Reference issue:** [#2790](https://github.com/gsd-build/get-shit-done/issues/2790)
---
### 123. Namespace Meta-Skills (Two-Stage Routing)
**Purpose:** Replace the flat eager skill listing with a two-stage hierarchical routing layer. The model sees 6 namespace routers instead of 86 entries, selects a namespace, then routes to the sub-skill. Descriptions use pipe-separated keyword tags (≤ 60 chars) for routing density.
**Commands:**
- `/gsd-ns-workflow` — phase pipeline router (discuss / plan / execute / verify / phase / progress)
- `/gsd-ns-project` — project lifecycle (milestones, audits, summary)
- `/gsd-ns-review` — quality gates (code review, debug, audit, security, eval, ui)
- `/gsd-ns-context` — codebase intelligence (map, graphify, docs, learnings)
- `/gsd-ns-manage` — config / workspace / workstreams / thread / update / ship / inbox
- `/gsd-ns-ideate` — exploration & capture (explore, sketch, spike, spec, capture)
**Token cost:**
| | Entries | Approx tokens |
|---|---|---|
| Pre-1.40 full install | 86 | ~2,150 |
| Namespace meta-skills | 6 | ~120 |
**Requirements:**
- REQ-NS-01: Six `commands/gsd/ns-*.md` namespace routers ship with pipe-separated keyword-tag descriptions (≤ 60 chars).
- REQ-NS-02: Existing sub-skills are unchanged and still invocable directly — namespace skills are additive, not a replacement for direct slash forms.
- REQ-NS-03: The body of each namespace router contains a routing table that maps user intent to the correct concrete sub-skill on the post-#2790 consolidated surface.
**Reference issue:** [#2792](https://github.com/gsd-build/get-shit-done/issues/2792)
---
### 124. Context-Window Utilization Guard
**Command:** `/gsd-health --context`
**Purpose:** Quality guard against context-window saturation. Two thresholds: 60 % utilization warns ("consider `/gsd-thread`"), 70 % is critical ("reasoning quality may degrade"; matches the fracture-point per recent context-attention research).
**Requirements:**
- REQ-CTX-GUARD-01: `/gsd-health --context` prints a structured status line with current utilization, threshold tier (`ok` / `warn` / `critical`), and a remediation suggestion.
- REQ-CTX-GUARD-02: The same triage is exposed as `gsd-sdk query validate.context --tokens-used <int> --context-window <int>` — a structured envelope for status-line and hook callers (#125). Both flags are required; the handler returns the same `{ percent, state }` envelope as the pure classifier in REQ-CTX-GUARD-03.
- REQ-CTX-GUARD-03: The classifier (`bin/lib/context-utilization.cjs`) is pure: input `(tokensUsed, contextWindow)`, output `{ percent, state }`. Easy to unit-test, easy to reuse from any caller.
**Reference issue:** [#2792](https://github.com/gsd-build/get-shit-done/issues/2792)
---
### 125. Phase-Lifecycle Status-Line Read-Side
**Purpose:** Surface phase orchestration state on the status-line. `parseStateMd()` reads four new STATE.md frontmatter fields and `formatGsdState()` renders in-flight, idle, and progress scenes. Write-side wiring follows in a later RC.
**Requirements:**
- REQ-LIFECYCLE-01: `parseStateMd()` reads four optional fields:
- `active_phase` — phase number when an orchestrator is in flight
- `next_action` — recommended next command when idle
- `next_phases` — YAML flow array of next phase numbers
- `progress` — nested `total_phases` / `completed_phases` / `percent` block
- REQ-LIFECYCLE-02: `formatGsdState()` checks the lifecycle fields in priority order and emits the first matching scene (Phase active → Idle next-recommended → Milestone complete → Default fallback).
- REQ-LIFECYCLE-03: All four fields default to undefined; existing STATE.md files render byte-for-byte identically.
**Reference issue:** [#2833](https://github.com/gsd-build/get-shit-done/issues/2833) — see [`docs/STATE-MD-LIFECYCLE.md`](STATE-MD-LIFECYCLE.md) for the full field reference and rendering rules.

View File

@@ -1,5 +1,5 @@
{ {
"generated": "2026-04-30", "generated": "2026-05-03",
"families": { "families": {
"agents": [ "agents": [
"gsd-advisor-researcher", "gsd-advisor-researcher",
@@ -163,7 +163,6 @@
"reapply-patches.md", "reapply-patches.md",
"remove-phase.md", "remove-phase.md",
"remove-workspace.md", "remove-workspace.md",
"research-phase.md",
"resume-project.md", "resume-project.md",
"review.md", "review.md",
"scan.md", "scan.md",
@@ -296,6 +295,7 @@
"gsd-read-injection-scanner.js", "gsd-read-injection-scanner.js",
"gsd-session-state.sh", "gsd-session-state.sh",
"gsd-statusline.js", "gsd-statusline.js",
"gsd-update-banner.js",
"gsd-validate-commit.sh", "gsd-validate-commit.sh",
"gsd-workflow-guard.js" "gsd-workflow-guard.js"
] ]

View File

@@ -40,7 +40,7 @@ Full roster at `agents/gsd-*.md`. The "Primary doc" column flags whether [`docs/
| gsd-pattern-mapper | Maps new files to closest existing analogs; writes PATTERNS.md for the planner. | `/gsd-plan-phase` (between research and planning) | advanced stub | | gsd-pattern-mapper | Maps new files to closest existing analogs; writes PATTERNS.md for the planner. | `/gsd-plan-phase` (between research and planning) | advanced stub |
| gsd-debug-session-manager | Runs the full `/gsd-debug` checkpoint-and-continuation loop in isolated context so main stays lean. | `/gsd-debug` | advanced stub | | gsd-debug-session-manager | Runs the full `/gsd-debug` checkpoint-and-continuation loop in isolated context so main stays lean. | `/gsd-debug` | advanced stub |
| gsd-code-reviewer | Reviews source files for bugs, security issues, and code-quality problems; produces REVIEW.md. | `/gsd-code-review` | advanced stub | | gsd-code-reviewer | Reviews source files for bugs, security issues, and code-quality problems; produces REVIEW.md. | `/gsd-code-review` | advanced stub |
| gsd-code-fixer | Applies fixes to REVIEW.md findings with atomic per-fix commits; produces REVIEW-FIX.md. | `/gsd-code-review-fix` | advanced stub | | gsd-code-fixer | Applies fixes to REVIEW.md findings with atomic per-fix commits; produces REVIEW-FIX.md. | `/gsd-code-review --fix` | advanced stub |
| gsd-ai-researcher | Researches a chosen AI framework's official docs into implementation-ready guidance (AI-SPEC.md §3§4b). | `/gsd-ai-integration-phase` | advanced stub | | gsd-ai-researcher | Researches a chosen AI framework's official docs into implementation-ready guidance (AI-SPEC.md §3§4b). | `/gsd-ai-integration-phase` | advanced stub |
| gsd-domain-researcher | Surfaces domain-expert evaluation criteria and failure modes for an AI system (AI-SPEC.md §1b). | `/gsd-ai-integration-phase` | advanced stub | | gsd-domain-researcher | Surfaces domain-expert evaluation criteria and failure modes for an AI system (AI-SPEC.md §1b). | `/gsd-ai-integration-phase` | advanced stub |
| gsd-eval-planner | Designs structured evaluation strategy for an AI phase (AI-SPEC.md §5§7). | `/gsd-ai-integration-phase` | advanced stub | | gsd-eval-planner | Designs structured evaluation strategy for an AI phase (AI-SPEC.md §5§7). | `/gsd-ai-integration-phase` | advanced stub |
@@ -162,13 +162,13 @@ These six routers are descriptor-only entries that the model picks first; the bo
--- ---
## Workflows (85 shipped) ## Workflows (84 shipped)
Full roster at `get-shit-done/workflows/*.md`. Workflows are thin orchestrators that commands reference internally; most are not read directly by end users. Rows below map each workflow file to its role (derived from the `<purpose>` block) and, where applicable, to the command that invokes it. Full roster at `get-shit-done/workflows/*.md`. Workflows are thin orchestrators that commands reference internally; most are not read directly by end users. Rows below map each workflow file to its role (derived from the `<purpose>` block) and, where applicable, to the command that invokes it.
| Workflow | Role | Invoked by | | Workflow | Role | Invoked by |
|----------|------|------------| |----------|------|------------|
| `add-phase.md` | Add a new integer phase to the end of the current milestone in the roadmap. | `/gsd-add-phase` | | `add-phase.md` | Add a new integer phase to the end of the current milestone in the roadmap. | `/gsd-phase` (default) |
| `add-tests.md` | Generate unit and E2E tests for a completed phase based on its artifacts. | `/gsd-add-tests` | | `add-tests.md` | Generate unit and E2E tests for a completed phase based on its artifacts. | `/gsd-add-tests` |
| `add-todo.md` | Capture an idea or task that surfaces during a session as a structured todo. | `/gsd-capture` (default), `/gsd-capture --backlog` | | `add-todo.md` | Capture an idea or task that surfaces during a session as a structured todo. | `/gsd-capture` (default), `/gsd-capture --backlog` |
| `ai-integration-phase.md` | Orchestrate framework selection → AI research → domain research → eval planning into AI-SPEC.md. | `/gsd-ai-integration-phase` | | `ai-integration-phase.md` | Orchestrate framework selection → AI research → domain research → eval planning into AI-SPEC.md. | `/gsd-ai-integration-phase` |
@@ -179,7 +179,7 @@ Full roster at `get-shit-done/workflows/*.md`. Workflows are thin orchestrators
| `autonomous.md` | Drive milestone phases autonomously — all remaining, a range, or a single phase. | `/gsd-autonomous` | | `autonomous.md` | Drive milestone phases autonomously — all remaining, a range, or a single phase. | `/gsd-autonomous` |
| `check-todos.md` | List pending todos, allow selection, load context, and route to the appropriate action. | `/gsd-capture --list` | | `check-todos.md` | List pending todos, allow selection, load context, and route to the appropriate action. | `/gsd-capture --list` |
| `cleanup.md` | Archive accumulated phase directories from completed milestones. | `/gsd-cleanup` | | `cleanup.md` | Archive accumulated phase directories from completed milestones. | `/gsd-cleanup` |
| `code-review-fix.md` | Auto-fix issues from REVIEW.md via gsd-code-fixer with per-fix atomic commits. | `/gsd-code-review-fix` | | `code-review-fix.md` | Auto-fix issues from REVIEW.md via gsd-code-fixer with per-fix atomic commits. | `/gsd-code-review --fix` |
| `code-review.md` | Review phase source changes via gsd-code-reviewer; produces REVIEW.md. | `/gsd-code-review` | | `code-review.md` | Review phase source changes via gsd-code-reviewer; produces REVIEW.md. | `/gsd-code-review` |
| `complete-milestone.md` | Mark a shipped version as complete — MILESTONES.md entry, PROJECT.md evolution, tag. | `/gsd-complete-milestone` | | `complete-milestone.md` | Mark a shipped version as complete — MILESTONES.md entry, PROJECT.md evolution, tag. | `/gsd-complete-milestone` |
| `diagnose-issues.md` | Orchestrate parallel debug agents to investigate UAT gaps and find root causes. | `/gsd-verify-work` (auto-diagnosis) | | `diagnose-issues.md` | Orchestrate parallel debug agents to investigate UAT gaps and find root causes. | `/gsd-verify-work` (auto-diagnosis) |
@@ -203,20 +203,19 @@ Full roster at `get-shit-done/workflows/*.md`. Workflows are thin orchestrators
| `import.md` | Ingest external plans with conflict detection against existing project decisions. | `/gsd-import` | | `import.md` | Ingest external plans with conflict detection against existing project decisions. | `/gsd-import` |
| `inbox.md` | Triage open GitHub issues and PRs against project contribution templates. | `/gsd-inbox` | | `inbox.md` | Triage open GitHub issues and PRs against project contribution templates. | `/gsd-inbox` |
| `ingest-docs.md` | Scan a repo for mixed planning docs; classify, synthesize, and bootstrap or merge into `.planning/` with a conflicts report. | `/gsd-ingest-docs` | | `ingest-docs.md` | Scan a repo for mixed planning docs; classify, synthesize, and bootstrap or merge into `.planning/` with a conflicts report. | `/gsd-ingest-docs` |
| `insert-phase.md` | Insert a decimal phase for urgent work discovered mid-milestone. | `/gsd-insert-phase` | | `insert-phase.md` | Insert a decimal phase for urgent work discovered mid-milestone. | `/gsd-phase --insert` |
| `list-phase-assumptions.md` | Surface Claude's assumptions about a phase before planning. | `/gsd-list-phase-assumptions` | | `list-phase-assumptions.md` | Surface Claude's assumptions about a phase before planning. | `/gsd-list-phase-assumptions` |
| `list-workspaces.md` | List all GSD workspaces found in `~/gsd-workspaces/` with their status. | `/gsd-list-workspaces` | | `list-workspaces.md` | List all GSD workspaces found in `~/gsd-workspaces/` with their status. | `/gsd-workspace --list` |
| `manager.md` | Interactive milestone command center — dashboard, inline discuss, background plan/execute. | `/gsd-manager` | | `manager.md` | Interactive milestone command center — dashboard, inline discuss, background plan/execute. | `/gsd-manager` |
| `map-codebase.md` | Orchestrate parallel codebase mapper agents to produce `.planning/codebase/` docs. | `/gsd-map-codebase` | | `map-codebase.md` | Orchestrate parallel codebase mapper agents to produce `.planning/codebase/` docs. | `/gsd-map-codebase` |
| `milestone-summary.md` | Milestone summary synthesis — onboarding and review artifact from milestone artifacts. | `/gsd-milestone-summary` | | `milestone-summary.md` | Milestone summary synthesis — onboarding and review artifact from milestone artifacts. | `/gsd-milestone-summary` |
| `new-milestone.md` | Start a new milestone cycle — load project context, gather goals, update PROJECT.md/STATE.md. | `/gsd-new-milestone` | | `new-milestone.md` | Start a new milestone cycle — load project context, gather goals, update PROJECT.md/STATE.md. | `/gsd-new-milestone` |
| `new-project.md` | Unified new-project flow — questioning, research (optional), requirements, roadmap. | `/gsd-new-project` | | `new-project.md` | Unified new-project flow — questioning, research (optional), requirements, roadmap. | `/gsd-new-project` |
| `new-workspace.md` | Create an isolated workspace with repo worktrees/clones and an independent `.planning/`. | `/gsd-new-workspace` | | `new-workspace.md` | Create an isolated workspace with repo worktrees/clones and an independent `.planning/`. | `/gsd-workspace --new` |
| `next.md` | Detect current project state and automatically advance to the next logical step. | `/gsd-progress --next` | | `next.md` | Detect current project state and automatically advance to the next logical step. | `/gsd-progress --next` |
| `node-repair.md` | Autonomous repair operator for failed task verification; invoked by `execute-plan`. | `execute-plan.md` (recovery) | | `node-repair.md` | Autonomous repair operator for failed task verification; invoked by `execute-plan`. | `execute-plan.md` (recovery) |
| `note.md` | Zero-friction idea capture — one Write call, one confirmation line. | `/gsd-capture --note` | | `note.md` | Zero-friction idea capture — one Write call, one confirmation line. | `/gsd-capture --note` |
| `pause-work.md` | Create structured `.planning/HANDOFF.json` and `.continue-here.md` handoff files. | `/gsd-pause-work` | | `pause-work.md` | Create structured `.planning/HANDOFF.json` and `.continue-here.md` handoff files. | `/gsd-pause-work` |
| `plan-milestone-gaps.md` | Create all phases necessary to close gaps identified by `/gsd-audit-milestone`. | `/gsd-plan-milestone-gaps` |
| `plan-phase.md` | Create executable PLAN.md files with integrated research and verification loop. | `/gsd-plan-phase`, `/gsd-quick` | | `plan-phase.md` | Create executable PLAN.md files with integrated research and verification loop. | `/gsd-plan-phase`, `/gsd-quick` |
| `plan-review-convergence.md` | Cross-AI plan convergence loop — replan with review feedback until no HIGH concerns remain. | `/gsd-plan-review-convergence` | | `plan-review-convergence.md` | Cross-AI plan convergence loop — replan with review feedback until no HIGH concerns remain. | `/gsd-plan-review-convergence` |
| `plant-seed.md` | Capture a forward-looking idea as a structured seed file with trigger conditions. | `/gsd-capture --seed` | | `plant-seed.md` | Capture a forward-looking idea as a structured seed file with trigger conditions. | `/gsd-capture --seed` |
@@ -224,24 +223,23 @@ Full roster at `get-shit-done/workflows/*.md`. Workflows are thin orchestrators
| `profile-user.md` | Orchestrate the full developer profiling flow — consent, session scan, profile generation. | `/gsd-profile-user` | | `profile-user.md` | Orchestrate the full developer profiling flow — consent, session scan, profile generation. | `/gsd-profile-user` |
| `progress.md` | Progress rendering — project context, position, and next-action routing. | `/gsd-progress` | | `progress.md` | Progress rendering — project context, position, and next-action routing. | `/gsd-progress` |
| `quick.md` | Quick-task execution with GSD guarantees (atomic commits, state tracking). | `/gsd-quick` | | `quick.md` | Quick-task execution with GSD guarantees (atomic commits, state tracking). | `/gsd-quick` |
| `reapply-patches.md` | Reapply local modifications after a GSD update. | `/gsd-reapply-patches` | | `reapply-patches.md` | Reapply local modifications after a GSD update. | `/gsd-update --reapply` |
| `remove-phase.md` | Remove a future phase from the roadmap and renumber subsequent phases. | `/gsd-remove-phase` | | `remove-phase.md` | Remove a future phase from the roadmap and renumber subsequent phases. | `/gsd-phase --remove` |
| `remove-workspace.md` | Remove a GSD workspace and clean up worktrees. | `/gsd-remove-workspace` | | `remove-workspace.md` | Remove a GSD workspace and clean up worktrees. | `/gsd-workspace --remove` |
| `research-phase.md` | Standalone phase research workflow (usually invoked via `plan-phase`). | `/gsd-research-phase` |
| `resume-project.md` | Resume work — restore full context from STATE.md, HANDOFF.json, and artifacts. | `/gsd-resume-work` | | `resume-project.md` | Resume work — restore full context from STATE.md, HANDOFF.json, and artifacts. | `/gsd-resume-work` |
| `review.md` | Cross-AI plan review via external CLIs; produces REVIEWS.md. | `/gsd-review` | | `review.md` | Cross-AI plan review via external CLIs; produces REVIEWS.md. | `/gsd-review` |
| `scan.md` | Rapid single-focus codebase scan — lightweight alternative to map-codebase. | `/gsd-scan` | | `scan.md` | Rapid single-focus codebase scan — lightweight alternative to map-codebase. | `/gsd-scan` |
| `secure-phase.md` | Retroactive threat-mitigation audit for a completed phase. | `/gsd-secure-phase` | | `secure-phase.md` | Retroactive threat-mitigation audit for a completed phase. | `/gsd-secure-phase` |
| `session-report.md` | Session report — token usage, work summary, outcomes. | `/gsd-session-report` | | `session-report.md` | Session report — token usage, work summary, outcomes. | `/gsd-session-report` |
| `settings.md` | Configure GSD workflow toggles and model profile. | `/gsd-settings`, `/gsd-set-profile` | | `settings.md` | Configure GSD workflow toggles and model profile. | `/gsd-settings`, `/gsd-config --profile` |
| `settings-advanced.md` | Configure GSD power-user knobs — plan bounce, timeouts, branch templates, cross-AI execution, runtime knobs. | `/gsd-settings-advanced` | | `settings-advanced.md` | Configure GSD power-user knobs — plan bounce, timeouts, branch templates, cross-AI execution, runtime knobs. | `/gsd-config --advanced` |
| `settings-integrations.md` | Configure third-party API keys (Brave/Firecrawl/Exa), `review.models.<cli>` CLI routing, and `agent_skills.<agent-type>` injection with masked (`****<last-4>`) display. | `/gsd-settings-integrations` | | `settings-integrations.md` | Configure third-party API keys (Brave/Firecrawl/Exa), `review.models.<cli>` CLI routing, and `agent_skills.<agent-type>` injection with masked (`****<last-4>`) display. | `/gsd-config --integrations` |
| `ship.md` | Create PR, run review, and prepare for merge after verification. | `/gsd-ship` | | `ship.md` | Create PR, run review, and prepare for merge after verification. | `/gsd-ship` |
| `sketch.md` | Explore design directions through throwaway HTML mockups with 2-3 variants per sketch. | `/gsd-sketch` | | `sketch.md` | Explore design directions through throwaway HTML mockups with 2-3 variants per sketch. | `/gsd-sketch` |
| `sketch-wrap-up.md` | Curate sketch findings and package them as a persistent `sketch-findings-[project]` skill. | `/gsd-sketch-wrap-up` | | `sketch-wrap-up.md` | Curate sketch findings and package them as a persistent `sketch-findings-[project]` skill. | `/gsd-sketch --wrap-up` |
| `spec-phase.md` | Socratic spec refinement with ambiguity scoring; produces SPEC.md. | `/gsd-spec-phase` | | `spec-phase.md` | Socratic spec refinement with ambiguity scoring; produces SPEC.md. | `/gsd-spec-phase` |
| `spike.md` | Rapid feasibility validation through focused, throwaway experiments. | `/gsd-spike` | | `spike.md` | Rapid feasibility validation through focused, throwaway experiments. | `/gsd-spike` |
| `spike-wrap-up.md` | Curate spike findings and package them as a persistent `spike-findings-[project]` skill. | `/gsd-spike-wrap-up` | | `spike-wrap-up.md` | Curate spike findings and package them as a persistent `spike-findings-[project]` skill. | `/gsd-spike --wrap-up` |
| `stats.md` | Project statistics rendering — phases, plans, requirements, git metrics. | `/gsd-stats` | | `stats.md` | Project statistics rendering — phases, plans, requirements, git metrics. | `/gsd-stats` |
| `sync-skills.md` | Cross-runtime GSD skill sync — diff and apply `gsd-*` skill directories across runtime roots. | `/gsd-update --sync` | | `sync-skills.md` | Cross-runtime GSD skill sync — diff and apply `gsd-*` skill directories across runtime roots. | `/gsd-update --sync` |
| `transition.md` | Phase-boundary transition workflow — workstream checks, state advancement. | `execute-phase.md`, `/gsd-progress --next` | | `transition.md` | Phase-boundary transition workflow — workstream checks, state advancement. | `execute-phase.md`, `/gsd-progress --next` |
@@ -385,7 +383,7 @@ Full listing: `get-shit-done/bin/lib/*.cjs`.
| `roadmap-command-router.cjs` | Thin CJS subcommand router adapter for `gsd-tools roadmap` | | `roadmap-command-router.cjs` | Thin CJS subcommand router adapter for `gsd-tools roadmap` |
| `roadmap.cjs` | ROADMAP.md parsing, phase extraction, plan progress | | `roadmap.cjs` | ROADMAP.md parsing, phase extraction, plan progress |
| `schema-detect.cjs` | Schema-drift detection for ORM patterns (Prisma, Drizzle, etc.) | | `schema-detect.cjs` | Schema-drift detection for ORM patterns (Prisma, Drizzle, etc.) |
| `secrets.cjs` | Secret-config masking convention (`****<last-4>`) for integration keys managed by `/gsd-settings-integrations` — keeps plaintext out of `config-set` output | | `secrets.cjs` | Secret-config masking convention (`****<last-4>`) for integration keys managed by `/gsd-config --integrations` — keeps plaintext out of `config-set` output |
| `security.cjs` | Path traversal prevention, prompt injection detection, safe JSON/shell helpers | | `security.cjs` | Path traversal prevention, prompt injection detection, safe JSON/shell helpers |
| `state-command-router.cjs` | Thin CJS subcommand router adapter for `gsd-tools state` | | `state-command-router.cjs` | Thin CJS subcommand router adapter for `gsd-tools state` |
| `state.cjs` | STATE.md parsing, updating, progression, metrics | | `state.cjs` | STATE.md parsing, updating, progression, metrics |
@@ -400,7 +398,7 @@ Full listing: `get-shit-done/bin/lib/*.cjs`.
--- ---
## Hooks (11 shipped) ## Hooks (12 shipped)
Full listing: `hooks/`. Full listing: `hooks/`.
@@ -410,6 +408,7 @@ Full listing: `hooks/`.
| `gsd-context-monitor.js` | `PostToolUse` / `AfterTool` | Injects agent-facing context warnings at 35%/25% remaining | | `gsd-context-monitor.js` | `PostToolUse` / `AfterTool` | Injects agent-facing context warnings at 35%/25% remaining |
| `gsd-check-update.js` | `SessionStart` | Background check for new GSD versions | | `gsd-check-update.js` | `SessionStart` | Background check for new GSD versions |
| `gsd-check-update-worker.js` | (worker) | Background worker helper for check-update | | `gsd-check-update-worker.js` | (worker) | Background worker helper for check-update |
| `gsd-update-banner.js` | `SessionStart` | Opt-in banner surfacing update availability when GSD statusline isn't used (PR #2795) |
| `gsd-prompt-guard.js` | `PreToolUse` | Scans `.planning/` writes for prompt-injection patterns (advisory) | | `gsd-prompt-guard.js` | `PreToolUse` | Scans `.planning/` writes for prompt-injection patterns (advisory) |
| `gsd-workflow-guard.js` | `PreToolUse` | Detects file edits outside GSD workflow context (advisory, opt-in) | | `gsd-workflow-guard.js` | `PreToolUse` | Detects file edits outside GSD workflow context (advisory, opt-in) |
| `gsd-read-guard.js` | `PreToolUse` | Advisory guard preventing Edit/Write on unread files | | `gsd-read-guard.js` | `PreToolUse` | Advisory guard preventing Edit/Write on unread files |

View File

@@ -15,6 +15,7 @@ Language versions: [English](README.md) · [Português (pt-BR)](pt-BR/README.md)
| [CLI Tools Reference](CLI-TOOLS.md) | Contributors, agent authors | `gsd-tools.cjs` programmatic API for workflows and agents | | [CLI Tools Reference](CLI-TOOLS.md) | Contributors, agent authors | `gsd-tools.cjs` programmatic API for workflows and agents |
| [Agent Reference](AGENTS.md) | Contributors, advanced users | Role cards for primary agents — roles, tools, spawn patterns (the `agents/` filesystem is authoritative) | | [Agent Reference](AGENTS.md) | Contributors, advanced users | Role cards for primary agents — roles, tools, spawn patterns (the `agents/` filesystem is authoritative) |
| [User Guide](USER-GUIDE.md) | All users | Workflow walkthroughs, troubleshooting, and recovery | | [User Guide](USER-GUIDE.md) | All users | Workflow walkthroughs, troubleshooting, and recovery |
| [Issue-Driven Orchestration](issue-driven-orchestration.md) | All users | Recipe for driving GSD from a tracker issue (GitHub / Linear / Jira) using existing primitives — no new commands or daemon |
| [Context Monitor](context-monitor.md) | All users | Context window monitoring hook architecture | | [Context Monitor](context-monitor.md) | All users | Context window monitoring hook architecture |
| [Discuss Mode](workflow-discuss-mode.md) | All users | Assumptions vs interview mode for discuss-phase | | [Discuss Mode](workflow-discuss-mode.md) | All users | Assumptions vs interview mode for discuss-phase |

View File

@@ -1,9 +1,11 @@
# STATE.md Phase Lifecycle Frontmatter # STATE.md Phase Lifecycle Frontmatter
> **Status:** Reference for the phase-lifecycle status-line proposed in > **Status:** Read-side shipped in v1.40.0 (issue
> [issue #2833](https://github.com/gsd-build/get-shit-done/issues/2833). > [#2833](https://github.com/gsd-build/get-shit-done/issues/2833)).
> The status-line hook (`hooks/gsd-statusline.js`) reads the fields below; > `parseStateMd()` reads the four frontmatter fields below and
> SDK write-side support to maintain them is tracked separately. > `formatGsdState()` renders the in-flight / idle / progress scenes.
> SDK write-side support to maintain the fields automatically is tracked
> separately.
GSD's `STATE.md` carries YAML frontmatter that the status-line hook reads on GSD's `STATE.md` carries YAML frontmatter that the status-line hook reads on
every render. This document describes the **phase-lifecycle fields** and the every render. This document describes the **phase-lifecycle fields** and the

View File

@@ -18,6 +18,37 @@ A detailed reference for workflows, troubleshooting, and configuration. For quic
- [Troubleshooting](#troubleshooting) - [Troubleshooting](#troubleshooting)
- [Recovery Quick Reference](#recovery-quick-reference) - [Recovery Quick Reference](#recovery-quick-reference)
For driving GSD directly from a GitHub / Linear / Jira issue, see the
[Issue-Driven Orchestration guide](issue-driven-orchestration.md) — a
recipe that maps tracker issues onto the workspace → discuss → plan →
execute → verify → review → ship loop using existing GSD primitives.
---
## Slash-command forms (hyphen vs colon)
GSD ships **the same set of skills** to every supported runtime, but two slash-form spellings are in play:
- **Hyphen form** — `/gsd-command-name` — used by Claude Code, Copilot, OpenCode, Kilo, Cursor, Windsurf, Augment, Antigravity, and Trae.
- **Colon form** — `/gsd:command-name` — used by **Gemini CLI only**. Gemini namespaces every plugin's commands under the plugin id, so the install path rewrites every body-text reference and command file to the colon form during `--gemini` install.
You don't need to choose — the installer writes the correct form into the command directory of each runtime you target. When following a walkthrough on a Gemini terminal, replace the hyphen after `gsd` with a colon as you read each slash command.
## Namespace routing primer (`gsd:<namespace>`, v1.40)
v1.40 ships six **namespace meta-skills** as the first-stage entry points for hierarchical routing — they keep the eager skill-listing token cost low (~120 tokens for 6 routers vs ~2,150 for a flat 86-skill listing) while every concrete sub-skill remains directly invocable. Each namespace router's body contains a routing table that maps your intent to the correct concrete sub-skill.
| Namespace | Router | Routes to |
|-----------|--------|-----------|
| Phase pipeline | `/gsd-ns-workflow` | discuss / plan / execute / verify / phase / progress |
| Project lifecycle | `/gsd-ns-project` | milestones, audits, summary |
| Quality gates | `/gsd-ns-review` | code review, debug, audit, security, eval, ui |
| Codebase intelligence | `/gsd-ns-context` | map, graphify, docs, learnings |
| Management | `/gsd-ns-manage` | config, workspace, workstreams, thread, update, ship, inbox |
| Exploration & capture | `/gsd-ns-ideate` | explore, sketch, spike, spec, capture |
You almost never need to type a namespace router yourself. Their value is in the routing layer the model uses to discover the right sub-skill — they exist so the system prompt can list 6 entries instead of 86. If you already know the concrete command (e.g. `/gsd-plan-phase`), call it directly.
--- ---
## End-to-End Walkthrough ## End-to-End Walkthrough
@@ -566,7 +597,7 @@ Each spike runs 25 experiments. Every experiment has:
Results land in `.planning/spikes/NNN-name/README.md` and are indexed in `.planning/spikes/MANIFEST.md`. Results land in `.planning/spikes/NNN-name/README.md` and are indexed in `.planning/spikes/MANIFEST.md`.
Once you have signal, run `/gsd-spike-wrap-up` to package the findings into `.claude/skills/spike-findings-[project]/` — future sessions will load them automatically via project-skills discovery. Once you have signal, run `/gsd-spike --wrap-up` to package the findings into `.claude/skills/spike-findings-[project]/` — future sessions will load them automatically via project-skills discovery.
### When to Sketch ### When to Sketch
@@ -581,16 +612,16 @@ Sketch when you need to compare layout structures, interaction models, or visual
Each sketch answers **one design question** with 23 variants in a single `index.html` you open directly in a browser — no build step. Variants use tab navigation and shared CSS variables from `themes/default.css`. All interactive elements (hover, click, transitions) are functional. Each sketch answers **one design question** with 23 variants in a single `index.html` you open directly in a browser — no build step. Variants use tab navigation and shared CSS variables from `themes/default.css`. All interactive elements (hover, click, transitions) are functional.
After picking a winner, run `/gsd-sketch-wrap-up` to capture the visual decisions into `.claude/skills/sketch-findings-[project]/`. After picking a winner, run `/gsd-sketch --wrap-up` to capture the visual decisions into `.claude/skills/sketch-findings-[project]/`.
### Spike → Sketch → Phase Flow ### Spike → Sketch → Phase Flow
``` ```
/gsd-spike "SSE vs WebSocket" # Validate the approach /gsd-spike "SSE vs WebSocket" # Validate the approach
/gsd-spike-wrap-up # Package learnings /gsd-spike --wrap-up # Package learnings
/gsd-sketch "real-time feed UI" # Explore the design /gsd-sketch "real-time feed UI" # Explore the design
/gsd-sketch-wrap-up # Package decisions /gsd-sketch --wrap-up # Package decisions
/gsd-discuss-phase N # Lock in preferences (now informed by spike + sketch) /gsd-discuss-phase N # Lock in preferences (now informed by spike + sketch)
/gsd-plan-phase N # Plan with confidence /gsd-plan-phase N # Plan with confidence
@@ -605,8 +636,8 @@ After picking a winner, run `/gsd-sketch-wrap-up` to capture the visual decision
Ideas that aren't ready for active planning go into the backlog using 999.x numbering, keeping them outside the active phase sequence. Ideas that aren't ready for active planning go into the backlog using 999.x numbering, keeping them outside the active phase sequence.
``` ```
/gsd-add-backlog "GraphQL API layer" # Creates 999.1-graphql-api-layer/ /gsd-capture --backlog "GraphQL API layer" # Creates 999.1-graphql-api-layer/
/gsd-add-backlog "Mobile responsive" # Creates 999.2-mobile-responsive/ /gsd-capture --backlog "Mobile responsive" # Creates 999.2-mobile-responsive/
``` ```
Backlog items get full phase directories, so you can use `/gsd-discuss-phase 999.1` to explore an idea further or `/gsd-plan-phase 999.1` when it's ready. Backlog items get full phase directories, so you can use `/gsd-discuss-phase 999.1` to explore an idea further or `/gsd-plan-phase 999.1` when it's ready.
@@ -618,7 +649,7 @@ Backlog items get full phase directories, so you can use `/gsd-discuss-phase 999
Seeds are forward-looking ideas with trigger conditions. Unlike backlog items, seeds surface automatically when the right milestone arrives. Seeds are forward-looking ideas with trigger conditions. Unlike backlog items, seeds surface automatically when the right milestone arrives.
``` ```
/gsd-plant-seed "Add real-time collab when WebSocket infra is in place" /gsd-capture --seed "Add real-time collab when WebSocket infra is in place"
``` ```
Seeds preserve the full WHY and WHEN to surface. `/gsd-new-milestone` scans all seeds and presents matches. Seeds preserve the full WHY and WHEN to surface. `/gsd-new-milestone` scans all seeds and presents matches.
@@ -637,7 +668,7 @@ Threads are lightweight cross-session knowledge stores for work that spans multi
Threads are lighter weight than `/gsd-pause-work` — no phase state, no plan context. Each thread file includes Goal, Context, References, and Next Steps sections. Threads are lighter weight than `/gsd-pause-work` — no phase state, no plan context. Each thread file includes Goal, Context, References, and Next Steps sections.
Threads can be promoted to phases (`/gsd-add-phase`) or backlog items (`/gsd-add-backlog`) when they mature. Threads can be promoted to phases (`/gsd-phase`) or backlog items (`/gsd-capture --backlog`) when they mature.
**Storage:** `.planning/threads/{slug}.md` **Storage:** `.planning/threads/{slug}.md`
@@ -664,7 +695,7 @@ Workstreams let you work on multiple milestone areas concurrently without state
Each workstream maintains its own `.planning/` directory subtree. When you switch workstreams, GSD swaps the active planning context so that `/gsd-progress`, `/gsd-discuss-phase`, `/gsd-plan-phase`, and other commands operate on that workstream's state. Active context is session-scoped when the runtime exposes a stable session identifier, which prevents one terminal or AI instance from repointing another instance's `STATE.md`. Each workstream maintains its own `.planning/` directory subtree. When you switch workstreams, GSD swaps the active planning context so that `/gsd-progress`, `/gsd-discuss-phase`, `/gsd-plan-phase`, and other commands operate on that workstream's state. Active context is session-scoped when the runtime exposes a stable session identifier, which prevents one terminal or AI instance from repointing another instance's `STATE.md`.
This is lighter weight than `/gsd-new-workspace` (which creates separate repo worktrees). Workstreams share the same codebase and git history but isolate planning artifacts. This is lighter weight than `/gsd-workspace --new` (which creates separate repo worktrees). Workstreams share the same codebase and git history but isolate planning artifacts.
--- ---
@@ -743,8 +774,8 @@ After executing a phase, run a structured code review before UAT:
The reviewer scopes files automatically using SUMMARY.md (preferred) or git diff fallback. Findings are classified as Critical, Warning, or Info in `{phase}-REVIEW.md`. The reviewer scopes files automatically using SUMMARY.md (preferred) or git diff fallback. Findings are classified as Critical, Warning, or Info in `{phase}-REVIEW.md`.
```bash ```bash
/gsd-code-review-fix 3 # Fix Critical + Warning findings atomically /gsd-code-review 3 --fix # Fix Critical + Warning findings atomically
/gsd-code-review-fix 3 --auto # Fix and re-review until clean (max 3 iterations) /gsd-code-review 3 --fix --auto # Fix and re-review until clean (max 3 iterations)
``` ```
### Autonomous Audit-to-Fix ### Autonomous Audit-to-Fix
@@ -761,7 +792,7 @@ To run an audit and fix all auto-fixable issues in one pass:
The review step slots in after execution and before UAT: The review step slots in after execution and before UAT:
``` ```
/gsd-execute-phase N -> /gsd-code-review N -> /gsd-code-review-fix N -> /gsd-verify-work N /gsd-execute-phase N -> /gsd-code-review N -> /gsd-code-review N --fix -> /gsd-verify-work N
``` ```
--- ---
@@ -895,7 +926,6 @@ The gate is non-blocking: any internal failure logs and the phase continues.
```bash ```bash
/gsd-audit-milestone # Check requirements coverage, detect stubs /gsd-audit-milestone # Check requirements coverage, detect stubs
/gsd-plan-milestone-gaps # If audit found gaps, create phases to close them
/gsd-complete-milestone # Archive, tag, done /gsd-complete-milestone # Archive, tag, done
``` ```
@@ -914,11 +944,13 @@ The gate is non-blocking: any internal failure logs and the phase continues.
### Mid-Milestone Scope Changes ### Mid-Milestone Scope Changes
```bash ```bash
/gsd-add-phase # Append a new phase to the roadmap /gsd-phase # Append a new phase to the roadmap (default mode)
# or # or
/gsd-insert-phase 3 # Insert urgent work between phases 3 and 4 /gsd-phase --insert 3 # Insert urgent work between phases 3 and 4
# or # or
/gsd-remove-phase 7 # Descope phase 7 and renumber /gsd-phase --remove 7 # Descope phase 7 and renumber
# or
/gsd-phase --edit 4 # Edit any field of phase 4 in place
``` ```
### Multi-Project Workspaces ### Multi-Project Workspaces
@@ -927,18 +959,18 @@ Work on multiple repos or features in parallel with isolated GSD state.
```bash ```bash
# Create a workspace with repos from your monorepo # Create a workspace with repos from your monorepo
/gsd-new-workspace --name feature-b --repos hr-ui,ZeymoAPI /gsd-workspace --new --name feature-b --repos hr-ui,ZeymoAPI
# Feature branch isolation — worktree of current repo with its own .planning/ # Feature branch isolation — worktree of current repo with its own .planning/
/gsd-new-workspace --name feature-b --repos . /gsd-workspace --new --name feature-b --repos .
# Then cd into the workspace and initialize GSD # Then cd into the workspace and initialize GSD
cd ~/gsd-workspaces/feature-b cd ~/gsd-workspaces/feature-b
/gsd-new-project /gsd-new-project
# List and manage workspaces # List and manage workspaces
/gsd-list-workspaces /gsd-workspace --list
/gsd-remove-workspace feature-b /gsd-workspace --remove feature-b
``` ```
Each workspace gets: Each workspace gets:
@@ -1010,7 +1042,95 @@ Do not re-run `/gsd-execute-phase`. Use `/gsd-quick` for targeted fixes, or `/gs
### Model Costs Too High ### Model Costs Too High
Switch to budget profile: `/gsd-set-profile budget`. Disable research and plan-check agents via `/gsd-settings` if the domain is familiar to you (or to Claude). Switch to budget profile: `/gsd-config --profile budget`. Disable research and plan-check agents via `/gsd-settings` if the domain is familiar to you (or to Claude).
### Tuning model cost by phase (`models`) — added in v1.40
If you've heard "use Opus for planning, Sonnet for verification" and want to apply that without learning the agent taxonomy, add a `models` block to `.planning/config.json`:
```json
{
"model_profile": "balanced",
"models": {
"planning": "opus",
"discuss": "opus",
"research": "sonnet",
"execution": "opus",
"verification": "sonnet",
"completion": "sonnet"
}
}
```
The six slots (`planning` / `discuss` / `research` / `execution` / `verification` / `completion`) accept tier aliases (`opus`, `sonnet`, `haiku`, `inherit`). Each slot covers a group of agents — for example, setting `models.research = "sonnet"` applies to `gsd-phase-researcher`, `gsd-codebase-mapper`, `gsd-research-synthesizer`, and the other research agents in one shot.
Need a per-agent exception? Add `model_overrides` alongside — it wins over `models`:
```json
{
"models": { "research": "sonnet" },
"model_overrides": {
"gsd-codebase-mapper": "haiku"
}
}
```
That gives sonnet to all research agents *except* the codebase mapper, which runs haiku for the cheap-but-broad fan-out scan.
For the full mapping table and resolution-precedence rules, see [Per-Phase-Type Models](CONFIGURATION.md#per-phase-type-models-models--added-in-v140) in the configuration reference.
### Cheap-by-default with `dynamic_routing` — added in v1.40
If you've been paying Opus rates everywhere as insurance against a single hard verification, dynamic routing flips it: every agent starts on a cheaper tier and escalates only when the orchestrator marks a soft failure (verification inconclusive, plan-check FLAG, etc.).
```json
{
"dynamic_routing": {
"enabled": true,
"tier_models": {
"light": "haiku",
"standard": "sonnet",
"heavy": "opus"
},
"escalate_on_failure": true,
"max_escalations": 1
}
}
```
Each agent has a default tier (`light`, `standard`, or `heavy`). On the first attempt, GSD picks `tier_models[default_tier]`. If the orchestrator detects a soft failure, it re-spawns once at the next tier up. `max_escalations` caps total retries so a runaway loop can't burn through your budget.
Concretely:
- `gsd-codebase-mapper` (default `light`) → first attempt = `haiku`. If escalated → `sonnet`.
- `gsd-verifier` (default `standard`) → first attempt = `sonnet`. If escalated → `opus`.
- `gsd-planner` (default `heavy`) → always `opus`. No tier above; can't escalate further.
To turn it off, set `dynamic_routing.enabled: false` (the default) — behavior is identical to today.
For the full agent → tier mapping and resolution-precedence rules, see [Dynamic Routing](CONFIGURATION.md#dynamic-routing-with-failure-tier-escalation-dynamic_routing--added-in-v140) in the configuration reference.
### Trim MCP servers to reduce per-turn cost (the biggest lever GSD doesn't own)
Before tuning `model_profile` or `models.<phase_type>`, audit which **MCP servers** your harness has enabled. Every enabled MCP server injects its tool schema into every turn — heavyweight servers like browser/playwright tools or platform-specific helpers can cost 20k+ tokens each, often dwarfing whatever GSD's resolver can save.
This is a **harness setting**, not a GSD setting. The toggle lives in `.claude/settings.json`:
```json
{
"enabledMcpjsonServers": ["context7"],
"disabledMcpjsonServers": ["playwright", "mac-tools"]
}
```
Quick audit before a long phase:
- Are any browser / playwright tools enabled when this phase has no UI work?
- Are any platform-specific tools (Mac-tools, Windows-tools, OS-specific) enabled when not needed?
- Are any project-specific MCPs from a different project still enabled here?
Each disabled server removes its schema from every subsequent turn for the rest of the session. Trimming MCPs **compounds** with `model_profile` tuning — both levers are additive, and MCP savings show up immediately across every subagent the orchestrator spawns.
For the full audit, harness reference, and the composition note with `model_profile`, see [MCP Tool Schema Cost](../get-shit-done/references/context-budget.md#mcp-tool-schema-cost-harness-concern) in the bundled `context-budget.md` reference.
### Using Non-Claude Runtimes (Codex, OpenCode, Gemini CLI, Kilo) ### Using Non-Claude Runtimes (Codex, OpenCode, Gemini CLI, Kilo)
@@ -1082,7 +1202,7 @@ Skills are installed to `~/.qwen/skills/gsd-*/SKILL.md`. Use the `QWEN_CONFIG_DI
### Using Claude Code with Non-Anthropic Providers (OpenRouter, Local) ### Using Claude Code with Non-Anthropic Providers (OpenRouter, Local)
If GSD subagents call Anthropic models and you're paying through OpenRouter or a local provider, switch to the `inherit` profile: `/gsd-set-profile inherit`. This makes all agents use your current session model instead of specific Anthropic models. See also `/gsd-settings` → Model Profile → Inherit. If GSD subagents call Anthropic models and you're paying through OpenRouter or a local provider, switch to the `inherit` profile: `/gsd-config --profile inherit`. This makes all agents use your current session model instead of specific Anthropic models. See also `/gsd-settings` → Model Profile → Inherit.
### Working on a Sensitive/Private Project ### Working on a Sensitive/Private Project
@@ -1090,12 +1210,36 @@ Set `commit_docs: false` during `/gsd-new-project` or via `/gsd-settings`. Add `
### GSD Update Overwrote My Local Changes ### GSD Update Overwrote My Local Changes
Since v1.17, the installer backs up locally modified files to `gsd-local-patches/`. Run `/gsd-reapply-patches` to merge your changes back. Since v1.17, the installer backs up locally modified files to `gsd-local-patches/`. Run `/gsd-update --reapply` to merge your changes back.
### Cannot Update via npm ### Cannot Update via npm
If `npx get-shit-done-cc` fails due to npm outages or network restrictions, see [docs/manual-update.md](manual-update.md) for a step-by-step manual update procedure that works without npm access. If `npx get-shit-done-cc` fails due to npm outages or network restrictions, see [docs/manual-update.md](manual-update.md) for a step-by-step manual update procedure that works without npm access.
### Surface GSD Update Notifications Without GSD's Statusline
GSD checks for new versions in the background and writes the result to `~/.cache/gsd/gsd-update-check.json`. By default, GSD's statusline (`hooks/gsd-statusline.js`) reads that cache and shows the update indicator. If you use a different statusline (for example `ccstatusline`) or none at all, the update info is invisible.
**Opt-in fix:** during interactive install, when you decline (or keep your existing) statusline, the installer offers a one-time prompt:
```text
Optional: GSD update banner
1) No banner (default)
2) Install update banner
```
Choose `2` (or type `y`/`yes`) and the installer registers `hooks/gsd-update-banner.js` as a `SessionStart` hook. From the next session onward, GSD prints a one-line `systemMessage` only when the cache reports an update available:
```text
GSD update available: 1.39.0 → 1.40.0. Run /gsd-update.
```
The banner is silent when no update is available. If the cache file is corrupt, GSD emits one diagnostic line (`GSD update check failed.`) and stays silent for 24 hours so a broken cache does not nag every session.
**Opt-out / removal:** delete the SessionStart hook entry that references `gsd-update-banner.js` from your runtime's `settings.json` (Claude Code: `~/.claude/settings.json`; Gemini: `~/.gemini/settings.json`). `npx get-shit-done-cc --uninstall` removes both the script and the registration in one pass.
The banner is not offered when GSD's statusline is installed — that channel already surfaces update info, so re-prompting would be noise.
### Workflow Diagnostics (`/gsd-forensics`) ### Workflow Diagnostics (`/gsd-forensics`)
When a workflow fails in a way that isn't obvious -- plans reference nonexistent files, execution produces unexpected results, or state seems corrupted -- run `/gsd-forensics` to generate a diagnostic report. When a workflow fails in a way that isn't obvious -- plans reference nonexistent files, execution produces unexpected results, or state seems corrupted -- run `/gsd-forensics` to generate a diagnostic report.
@@ -1241,15 +1385,14 @@ If the installer crashes with `EPERM: operation not permitted, scandir` on Windo
| ------------------------------------ | ------------------------------------------------------------------------ | | ------------------------------------ | ------------------------------------------------------------------------ |
| Lost context / new session | `/gsd-resume-work` or `/gsd-progress` | | Lost context / new session | `/gsd-resume-work` or `/gsd-progress` |
| Phase went wrong | `git revert` the phase commits, then re-plan | | Phase went wrong | `git revert` the phase commits, then re-plan |
| Need to change scope | `/gsd-add-phase`, `/gsd-insert-phase`, or `/gsd-remove-phase` | | Need to change scope | `/gsd-phase` (default), `/gsd-phase --insert`, or `/gsd-phase --remove` |
| Milestone audit found gaps | `/gsd-plan-milestone-gaps` |
| Something broke | `/gsd-debug "description"` (add `--diagnose` for analysis without fixes) | | Something broke | `/gsd-debug "description"` (add `--diagnose` for analysis without fixes) |
| STATE.md out of sync | `state validate` then `state sync` | | STATE.md out of sync | `state validate` then `state sync` |
| Workflow state seems corrupted | `/gsd-forensics` | | Workflow state seems corrupted | `/gsd-forensics` |
| Quick targeted fix | `/gsd-quick` | | Quick targeted fix | `/gsd-quick` |
| Plan doesn't match your vision | `/gsd-discuss-phase [N]` then re-plan | | Plan doesn't match your vision | `/gsd-discuss-phase [N]` then re-plan |
| Costs running high | `/gsd-set-profile budget` and `/gsd-settings` to toggle agents off | | Costs running high | `/gsd-config --profile budget` and `/gsd-settings` to toggle agents off |
| Update broke local changes | `/gsd-reapply-patches` | | Update broke local changes | `/gsd-update --reapply` |
| Want session summary for stakeholder | `/gsd-session-report` | | Want session summary for stakeholder | `/gsd-session-report` |
| Don't know what step is next | `/gsd-next` | | Don't know what step is next | `/gsd-next` |
| Parallel execution build errors | Update GSD or set `parallelization.enabled: false` | | Parallel execution build errors | Update GSD or set `parallelization.enabled: false` |

View File

@@ -0,0 +1,26 @@
# Dispatch policy module as single seam for query execution outcomes
We decided to centralize query dispatch outcomes in one Dispatch Policy Module that returns a structured union result (`ok` success or failure with typed `kind`, `details`, and final `exit_code`) instead of mixing throws and ad-hoc error mapping across CLI and SDK paths. This keeps fallback policy, timeout classification, and exit mapping in one place for better locality, prevents drift between native and fallback behavior, and makes callers thin adapters over a stable interface.
## Amendment (2026-05-03): query seam deepening completion
To complete the query architecture pass, we deepened adjacent seams around the Dispatch Policy Module:
- Extracted **Query Runtime Context Module** to own `projectDir` + `ws` resolution policy.
- Extracted **Native Dispatch Adapter Module** so Dispatch Policy consumes a stable native dispatch Interface (not closure-wired call sites).
- Extracted **Query CLI Output Module** to own projection from dispatch results/errors to CLI output contract.
- Converged internal command-resolution and policy imports onto canonical modules and removed dead wrapper modules.
- Added **Command Topology Module** as dispatch-facing seam that resolves commands, projects command policy, binds handler Adapters, and emits no-match diagnosis consumed by Dispatch Policy.
- Locked **pre-project query config policy** for parity-sensitive query Interfaces: when `.planning/config.json` is absent, use built-in defaults and parity-aligned empty model ids for model-resolution surfaces.
- Gated real-CLI SDK E2E suites behind explicit opt-in (`GSD_ENABLE_E2E=1`) to keep default CI/local verification deterministic while preserving full-path validation when requested.
### Dead-wrapper convergence
Removed wrapper Modules after call-site convergence:
- `normalize-query-command.ts`
- `command-resolution.ts`
- `policy-convergence.ts`
- `query-policy-snapshot.ts`
- `query-registry-capability.ts`
This amendment preserves the original ADR direction: keep policy depth high, adapters thin, and locality concentrated in explicit modules.

View File

@@ -0,0 +1,183 @@
# Issue-Driven Orchestration with GSD
**Status:** stable workflow guide
**Audience:** developers who track work in GitHub Issues, Linear, Jira, or
similar issue trackers and want to drive AI-assisted implementation
through GSD's existing primitives.
## What this guide is
A recipe for combining commands GSD already ships into an issue-tracker
→ workspace → plan/execute → verify/review → PR loop. It is documentation
only. No new commands, no daemon, no tracker integration — every command
referenced below already exists in GSD today.
The shape is inspired by OpenAI's open-source [Symphony orchestration
reference](https://openai.com/index/open-source-codex-orchestration-symphony/)
([repository](https://github.com/openai/symphony)). GSD does not vendor or
wrap Symphony. The orchestration *concepts* map cleanly onto primitives
GSD already exposes; this guide just spells the mapping out so you can
adopt the pattern without writing glue code or bypassing GSD's safety
gates.
## Why this exists
GSD has the building blocks for issue-driven AI development —
`/gsd-workspace --new`, `/gsd-manager`, `/gsd-autonomous`, `/gsd-verify-work`,
`/gsd-review`, `/gsd-ship`, plus `STATE.md` and the phase artifact suite
— but no guide that walks through how to drive them from a single tracker
issue without writing custom orchestration scripts. Without that guide
the failure modes are:
- Underuse: developers run discuss/plan/execute manually and never reach
for `/gsd-manager` or `/gsd-autonomous` even when their work pattern
fits.
- Workaround scripts: developers wire ad-hoc shell loops between their
tracker and `claude` invocations, bypassing `STATE.md`, the phase
manifest, and the verification gates.
This guide makes the canonical loop discoverable.
## Concept mapping
Each row maps a Symphony-style orchestration concept to the GSD primitive
that already serves it. Use this table as a translation key when reading
Symphony docs, blog posts, or third-party orchestration write-ups.
| Symphony concept | GSD primitive |
|---|---|
| `WORKFLOW.md` (top-level intent) | `ROADMAP.md` (project intent), `STATE.md` (live status), phase `CONTEXT.md` (per-phase scope), phase `PLAN.md` (executable steps) |
| One isolated agent workspace per task | `/gsd-workspace --new --strategy worktree` |
| Agent dispatch and concurrency | `/gsd-manager` (interactive dashboard), `/gsd-autonomous` (unattended) |
| Per-phase plan and discuss steps | `/gsd-discuss-phase``/gsd-plan-phase``/gsd-execute-phase` |
| Proof-of-work / test evidence | `/gsd-verify-work` (UAT.md persisted across `/clear`) |
| Adversarial review | `/gsd-review` (cross-AI peer review of plans) |
| Human merge gate | `/gsd-ship` (creates PR, optional code review, prepares merge) |
| Follow-up capture | `/gsd-note`, `/gsd-plant-seed`, `/gsd-new-milestone`, or a manually opened tracker issue |
| Concurrency control | Manager / background-agent semantics (no always-on poller) |
The mapping is one-way: GSD owns the safety gates (verification, human
review, explicit confirmation for follow-up creation). Symphony's
"continuous orchestration" framing is intentionally not adopted — see
[Non-goals](#non-goals).
## End-to-end flow
The canonical issue → PR loop, written so it can run from a single
tracker issue end-to-end. Replace bracketed placeholders before running.
1. **Pick the tracker issue.** Choose one issue from your tracker (GitHub,
Linear, etc.) that is well-scoped enough for autonomous implementation
— bounded scope, observable acceptance criteria, no upstream
dependencies that block execution.
2. **Map to a GSD phase.** If the issue maps onto an existing phase in
`ROADMAP.md`, select it. If not, run `/gsd-new-milestone` (for a new
milestone of related issues) or open a phase via `/gsd-add-phase` /
`/gsd-insert-phase`. Capture the tracker issue URL in the phase's
`CONTEXT.md` so traceability survives compaction.
3. **Create an isolated workspace.** Run
`/gsd-workspace --new --strategy worktree <slug>` to spin up a git
worktree with an independent `.planning/` directory. The worktree is
the safety boundary: any exploration, partial commits, or aborted
plans stay outside `main`.
4. **Run discuss → plan → execute through GSD.** From inside the
workspace, run `/gsd-discuss-phase` to clarify ambiguities,
`/gsd-plan-phase` to produce `PLAN.md`, and either `/gsd-manager`
(interactive dashboard) or `/gsd-execute-phase` / `/gsd-autonomous`
(unattended) to implement. Avoid driving raw `claude` invocations
from outside GSD — that bypasses `STATE.md` updates and the phase
manifest.
5. **Demand proof-of-work.** Run `/gsd-verify-work` to walk the user
through UAT against the phase's acceptance criteria. Tests,
screenshots, log captures, and config diffs are all recorded in
`UAT.md`, which persists across `/clear` and feeds gaps into
`/gsd-plan-phase --gaps` when verification surfaces missed scope.
6. **Pass through the review and ship gates.** Run `/gsd-review` to get
adversarial peer review of the plan from independent AI CLIs (catches
blind spots model-by-model), then `/gsd-ship` to open the PR with a
rich body assembled from the planning artifacts. Both gates require a
human decision before anything reaches the remote.
7. **Capture follow-up work explicitly.** Use `/gsd-note` for inline
notes, `/gsd-plant-seed` for ideas worth a future phase, or
`/gsd-new-milestone` for a coherent group of follow-ups. Creating a
tracker issue from a discovered follow-up requires explicit user
confirmation — GSD does not post to remote trackers automatically.
When the PR merges, the loop closes. Auto-close keywords in the PR body
(`Closes #NNN` / `Fixes #NNN`) close the tracker issue at merge time.
## Safety boundaries
The loop is safe because four invariants hold by construction:
- **Isolated worktrees.** Every issue runs in a `/gsd-workspace --new`
worktree, so partial work, aborted plans, and exploratory commits
never touch `main`. `gsd-local-patches/` is the recovery surface if a
worktree's hand-edits need to come back across an update.
- **Explicit human review.** `/gsd-review` and `/gsd-ship` both stop for
human approval. There is no auto-merge and no auto-PR-from-execution
path. If you want to remove the human gate for a specific repository,
that is your branch-protection / merge-queue policy decision, not
something GSD opts into for you.
- **No automatic public posting.** GSD never opens, comments on, or
closes a tracker issue without an explicit user-initiated command.
Follow-up capture defaults to local artifacts (notes, seeds,
milestones); pushing back to the tracker is a separate manual step.
- **Verification before ship.** `/gsd-verify-work`'s UAT.md must record
evidence before `/gsd-ship` is run. The recommended discipline is to
treat `verification_failed` as a blocker even when the implementation
looks correct — the failure usually surfaces a missed acceptance
criterion, not a flaky test.
If any of these invariants is bypassed (e.g. running `claude` directly
against the worktree, skipping `/gsd-verify-work`, or scripting issue
creation through the tracker API without user confirmation), the
guarantees of this guide do not apply.
## Non-goals
This guide deliberately does **not** propose any of the following. They
are listed here so future contributors don't re-litigate them in code
review:
- **No vendoring or copying Symphony code.** GSD reuses its own
primitives. The mapping above is conceptual; no Symphony-derived
source ships in this repo.
- **No long-running daemon.** GSD does not poll GitHub or Linear. The
manager and autonomous workflows handle concurrency through
background-agent semantics, not a daemon.
- **No mandatory tracker dependency.** The loop works without any
tracker integration. The "tracker issue" step is a *human input*
the URL goes into `CONTEXT.md`. GSD has no opinion about which
tracker you use, or whether you use one at all.
- **No bypass of verification, review, or human decision gates.** Even
when running `/gsd-autonomous`, the verification and review gates
still fire. The "autonomous" label refers to phase-to-phase
progression, not to skipping human approval.
- **No expansion of the default skill / command surface.** Every
command referenced in this guide already exists. This guide is a
documentation surface, not a feature surface.
## Possible future follow-up
If maintainer experience with this loop justifies it, a separate
approved-enhancement could later add a *minimal* tracker bridge:
- Importing one GitHub or Linear issue into a GSD workspace / phase.
- Exporting `UAT.md` evidence as a comment on the source issue.
- Generating follow-up tracker issues from `/gsd-plant-seed` output.
Each of those would be its own enhancement proposal because each adds
integration surface and ongoing maintenance burden. They are out of
scope for this guide.
## Related
- [docs/USER-GUIDE.md](USER-GUIDE.md) — task-oriented walkthroughs of
individual commands referenced above.
- [docs/COMMANDS.md](COMMANDS.md) — full reference for `/gsd-*`
commands.
- [docs/FEATURES.md](FEATURES.md) — feature-level capability matrix
(workspaces, manager, autonomous, verify, review, ship).
- [docs/ARCHITECTURE.md](ARCHITECTURE.md) — phase-artifact lifecycle
and `STATE.md` mechanics.

View File

@@ -411,7 +411,7 @@ UI-SPEC.md (per phase) ───────────────────
│ ├── pending/ # キャプチャされたアイデア │ ├── pending/ # キャプチャされたアイデア
│ └── done/ # 完了済みtodo │ └── done/ # 完了済みtodo
├── threads/ # 永続コンテキストスレッド(/gsd-thread から) ├── threads/ # 永続コンテキストスレッド(/gsd-thread から)
├── seeds/ # 将来に向けたアイデア(/gsd-plant-seed から) ├── seeds/ # 将来に向けたアイデア(/gsd-capture --seed から)
├── debug/ # アクティブなデバッグセッション ├── debug/ # アクティブなデバッグセッション
│ ├── *.md # アクティブセッション │ ├── *.md # アクティブセッション
│ ├── resolved/ # アーカイブ済みセッション │ ├── resolved/ # アーカイブ済みセッション
@@ -439,7 +439,7 @@ UI-SPEC.md (per phase) ───────────────────
- Antigravity: Googleモデル同等品によるスキルファースト - Antigravity: Googleモデル同等品によるスキルファースト
5. **パス正規化**`~/.claude/` パスをランタイム固有のパスに置換 5. **パス正規化**`~/.claude/` パスをランタイム固有のパスに置換
6. **設定統合** — ランタイムの `settings.json` にフックを登録 6. **設定統合** — ランタイムの `settings.json` にフックを登録
7. **パッチバックアップ** — v1.17以降、ローカルで変更されたファイルを `/gsd-reapply-patches` 用に `gsd-local-patches/` へバックアップ 7. **パッチバックアップ** — v1.17以降、ローカルで変更されたファイルを `/gsd-update --reapply` 用に `gsd-local-patches/` へバックアップ
8. **マニフェスト追跡** — クリーンアンインストールのために `gsd-file-manifest.json` を書き込み 8. **マニフェスト追跡** — クリーンアンインストールのために `gsd-file-manifest.json` を書き込み
9. **アンインストールモード**`--uninstall` ですべてのGSDファイル、フック、設定を削除 9. **アンインストールモード**`--uninstall` ですべてのGSDファイル、フック、設定を削除

View File

@@ -32,7 +32,7 @@
--- ---
### `/gsd-new-workspace` ### `/gsd-workspace --new`
リポジトリのコピーと独立した `.planning/` ディレクトリを持つ分離されたワークスペースを作成します。 リポジトリのコピーと独立した `.planning/` ディレクトリを持つ分離されたワークスペースを作成します。
@@ -52,14 +52,14 @@
**生成物:** `WORKSPACE.md``.planning/`、リポジトリコピーworktreeまたはclone **生成物:** `WORKSPACE.md``.planning/`、リポジトリコピーworktreeまたはclone
```bash ```bash
/gsd-new-workspace --name feature-b --repos hr-ui,ZeymoAPI /gsd-workspace --new --name feature-b --repos hr-ui,ZeymoAPI
/gsd-new-workspace --name feature-b --repos . --strategy worktree # 同一リポジトリの分離 /gsd-workspace --new --name feature-b --repos . --strategy worktree # 同一リポジトリの分離
/gsd-new-workspace --name spike --repos api,web --strategy clone # フルクローン /gsd-workspace --new --name spike --repos api,web --strategy clone # フルクローン
``` ```
--- ---
### `/gsd-list-workspaces` ### `/gsd-workspace --list`
アクティブなGSDワークスペースとそのステータスを一覧表示します。 アクティブなGSDワークスペースとそのステータスを一覧表示します。
@@ -67,12 +67,12 @@
**表示内容:** 名前、リポジトリ数、戦略、GSDプロジェクトのステータス **表示内容:** 名前、リポジトリ数、戦略、GSDプロジェクトのステータス
```bash ```bash
/gsd-list-workspaces /gsd-workspace --list
``` ```
--- ---
### `/gsd-remove-workspace` ### `/gsd-workspace --remove`
ワークスペースを削除し、git worktreeをクリーンアップします。 ワークスペースを削除し、git worktreeをクリーンアップします。
@@ -83,7 +83,7 @@
**安全性:** コミットされていない変更があるリポジトリの削除を拒否します。名前の確認が必要です。 **安全性:** コミットされていない変更があるリポジトリの削除を拒否します。名前の確認が必要です。
```bash ```bash
/gsd-remove-workspace feature-b /gsd-workspace --remove feature-b
``` ```
--- ---
@@ -368,15 +368,15 @@
## フェーズ管理コマンド ## フェーズ管理コマンド
### `/gsd-add-phase` ### `/gsd-phase`
ロードマップに新しいフェーズを追加します。 ロードマップに新しいフェーズを追加します。
```bash ```bash
/gsd-add-phase # 対話型 — フェーズの説明を入力 /gsd-phase # 対話型 — フェーズの説明を入力
``` ```
### `/gsd-insert-phase` ### `/gsd-phase --insert`
小数番号を使用して、フェーズ間に緊急の作業を挿入します。 小数番号を使用して、フェーズ間に緊急の作業を挿入します。
@@ -385,10 +385,10 @@
| `N` | いいえ | このフェーズ番号の後に挿入 | | `N` | いいえ | このフェーズ番号の後に挿入 |
```bash ```bash
/gsd-insert-phase 3 # フェーズ3と4の間に挿入 → 3.1を作成 /gsd-phase --insert 3 # フェーズ3と4の間に挿入 → 3.1を作成
``` ```
### `/gsd-remove-phase` ### `/gsd-phase --remove`
将来のフェーズを削除し、後続のフェーズの番号を振り直します。 将来のフェーズを削除し、後続のフェーズの番号を振り直します。
@@ -397,7 +397,7 @@
| `N` | いいえ | 削除するフェーズ番号 | | `N` | いいえ | 削除するフェーズ番号 |
```bash ```bash
/gsd-remove-phase 7 # フェーズ7を削除、8→7、9→8等に番号振り直し /gsd-phase --remove 7 # フェーズ7を削除、8→7、9→8等に番号振り直し
``` ```
### `/gsd-list-phase-assumptions` ### `/gsd-list-phase-assumptions`
@@ -412,15 +412,8 @@
/gsd-list-phase-assumptions 2 # フェーズ2の前提を確認 /gsd-list-phase-assumptions 2 # フェーズ2の前提を確認
``` ```
### `/gsd-plan-milestone-gaps`
マイルストーン監査のギャップを解消するフェーズを作成します。 ### `/gsd-plan-phase --research-phase`
```bash
/gsd-plan-milestone-gaps # 各監査ギャップに対してフェーズを作成
```
### `/gsd-research-phase`
詳細なエコシステム調査のみを実行します(単体機能 — 通常は `/gsd-plan-phase` を使用してください)。 詳細なエコシステム調査のみを実行します(単体機能 — 通常は `/gsd-plan-phase` を使用してください)。
@@ -429,7 +422,7 @@
| `N` | いいえ | フェーズ番号 | | `N` | いいえ | フェーズ番号 |
```bash ```bash
/gsd-research-phase 4 # フェーズ4のドメインを調査 /gsd-plan-phase --research-phase 4 # フェーズ4のドメインを調査
``` ```
### `/gsd-validate-phase` ### `/gsd-validate-phase`
@@ -598,7 +591,7 @@ GSDの保証付きでアドホックタスクを実行します。
/gsd-debug --diagnose "API returning 500 on /users endpoint" /gsd-debug --diagnose "API returning 500 on /users endpoint"
``` ```
### `/gsd-add-todo` ### `/gsd-capture`
後で取り組むアイデアやタスクをキャプチャします。 後で取り組むアイデアやタスクをキャプチャします。
@@ -607,15 +600,15 @@ GSDの保証付きでアドホックタスクを実行します。
| `description` | いいえ | Todoの説明 | | `description` | いいえ | Todoの説明 |
```bash ```bash
/gsd-add-todo "Consider adding dark mode support" /gsd-capture "Consider adding dark mode support"
``` ```
### `/gsd-check-todos` ### `/gsd-capture --list`
保留中のTodoを一覧表示し、取り組むものを選択します。 保留中のTodoを一覧表示し、取り組むものを選択します。
```bash ```bash
/gsd-check-todos /gsd-capture --list
``` ```
### `/gsd-add-tests` ### `/gsd-add-tests`
@@ -752,7 +745,7 @@ Claude Codeのセッション分析から8つの次元コミュニケーシ
/gsd-settings # 対話型設定 /gsd-settings # 対話型設定
``` ```
### `/gsd-set-profile` ### `/gsd-config --profile`
クイックプロファイル切り替え。 クイックプロファイル切り替え。
@@ -761,8 +754,8 @@ Claude Codeのセッション分析から8つの次元コミュニケーシ
| `profile` | **はい** | `quality``balanced``budget`、または `inherit` | | `profile` | **はい** | `quality``balanced``budget`、または `inherit` |
```bash ```bash
/gsd-set-profile budget # budgetプロファイルに切り替え /gsd-config --profile budget # budgetプロファイルに切り替え
/gsd-set-profile quality # qualityプロファイルに切り替え /gsd-config --profile quality # qualityプロファイルに切り替え
``` ```
--- ---
@@ -794,12 +787,12 @@ Claude Codeのセッション分析から8つの次元コミュニケーシ
/gsd-update # アップデートを確認してインストール /gsd-update # アップデートを確認してインストール
``` ```
### `/gsd-reapply-patches` ### `/gsd-update --reapply`
GSDアップデート後にローカルの変更を復元します。 GSDアップデート後にローカルの変更を復元します。
```bash ```bash
/gsd-reapply-patches # ローカルの変更をマージバック /gsd-update --reapply # ローカルの変更をマージバック
``` ```
--- ---
@@ -885,7 +878,7 @@ GSDアップデート後にローカルの変更を復元します。
## バックログ&スレッドコマンド ## バックログ&スレッドコマンド
### `/gsd-add-backlog` ### `/gsd-capture --backlog`
999.x番号付けを使用して、バックログのパーキングロットにアイデアを追加します。 999.x番号付けを使用して、バックログのパーキングロットにアイデアを追加します。
@@ -896,8 +889,8 @@ GSDアップデート後にローカルの変更を復元します。
**999.x番号付け**により、バックログ項目はアクティブなフェーズシーケンスの外に保持されます。フェーズディレクトリは即座に作成されるため、`/gsd-discuss-phase``/gsd-plan-phase` がそれらに対して動作します。 **999.x番号付け**により、バックログ項目はアクティブなフェーズシーケンスの外に保持されます。フェーズディレクトリは即座に作成されるため、`/gsd-discuss-phase``/gsd-plan-phase` がそれらに対して動作します。
```bash ```bash
/gsd-add-backlog "GraphQL API layer" /gsd-capture --backlog "GraphQL API layer"
/gsd-add-backlog "Mobile responsive redesign" /gsd-capture --backlog "Mobile responsive redesign"
``` ```
--- ---
@@ -914,7 +907,7 @@ GSDアップデート後にローカルの変更を復元します。
--- ---
### `/gsd-plant-seed` ### `/gsd-capture --seed`
トリガー条件付きの将来のアイデアをキャプチャ — 適切なマイルストーンで自動的に表面化します。 トリガー条件付きの将来のアイデアをキャプチャ — 適切なマイルストーンで自動的に表面化します。
@@ -928,7 +921,7 @@ GSDアップデート後にローカルの変更を復元します。
**利用先:** `/gsd-new-milestone`(シードをスキャンしてマッチするものを提示) **利用先:** `/gsd-new-milestone`(シードをスキャンしてマッチするものを提示)
```bash ```bash
/gsd-plant-seed "Add real-time collaboration when WebSocket infra is in place" /gsd-capture --seed "Add real-time collaboration when WebSocket infra is in place"
``` ```
--- ---

View File

@@ -386,7 +386,6 @@
- REQ-MILE-08: 新しいマイルストーンは new-project と同じフロー(質問 → リサーチ → 要件 → ロードマップ)に従わなければならない - REQ-MILE-08: 新しいマイルストーンは new-project と同じフロー(質問 → リサーチ → 要件 → ロードマップ)に従わなければならない
- REQ-MILE-09: 新しいマイルストーンは既存のワークフロー設定をリセットしてはならない - REQ-MILE-09: 新しいマイルストーンは既存のワークフロー設定をリセットしてはならない
**ギャップクローズ:** `/gsd-plan-milestone-gaps` は監査で特定されたギャップを埋めるためのフェーズを作成します。
--- ---
@@ -394,7 +393,7 @@
### 9. フェーズ管理 ### 9. フェーズ管理
**コマンド:** `/gsd-add-phase``/gsd-insert-phase [N]``/gsd-remove-phase [N]` **コマンド:** `/gsd-phase``/gsd-phase --insert [N]``/gsd-phase --remove [N]`
**目的:** 開発中のロードマップの動的な変更。 **目的:** 開発中のロードマップの動的な変更。
@@ -681,7 +680,7 @@
### 26. モデルプロファイル ### 26. モデルプロファイル
**コマンド:** `/gsd-set-profile <quality|balanced|budget|inherit>` **コマンド:** `/gsd-config --profile <quality|balanced|budget|inherit>`
**目的:** 各エージェントが使用する AI モデルを制御し、品質とコストのバランスを取ります。 **目的:** 各エージェントが使用する AI モデルを制御し、品質とコストのバランスを取ります。
@@ -763,7 +762,7 @@
### 29. Todo 管理 ### 29. Todo 管理
**コマンド:** `/gsd-add-todo [desc]``/gsd-check-todos` **コマンド:** `/gsd-capture [desc]``/gsd-capture --list`
**目的:** セッション中にアイデアやタスクをキャプチャし、後で作業できるようにします。 **目的:** セッション中にアイデアやタスクをキャプチャし、後で作業できるようにします。
@@ -800,7 +799,7 @@
- REQ-UPDATE-02: システムは更新前に新しいバージョンのチェンジログを表示しなければならない - REQ-UPDATE-02: システムは更新前に新しいバージョンのチェンジログを表示しなければならない
- REQ-UPDATE-03: システムはランタイムを認識し、正しいディレクトリを対象としなければならない - REQ-UPDATE-03: システムはランタイムを認識し、正しいディレクトリを対象としなければならない
- REQ-UPDATE-04: システムはローカルで変更されたファイルを `gsd-local-patches/` にバックアップしなければならない - REQ-UPDATE-04: システムはローカルで変更されたファイルを `gsd-local-patches/` にバックアップしなければならない
- REQ-UPDATE-05: `/gsd-reapply-patches` は更新後にローカルの変更を復元しなければならない - REQ-UPDATE-05: `/gsd-update --reapply` は更新後にローカルの変更を復元しなければならない
--- ---
@@ -1066,7 +1065,7 @@ fix(03-01): correct auth token expiry
### 43. バックログパーキングロット ### 43. バックログパーキングロット
**コマンド:** `/gsd-add-backlog <description>``/gsd-review-backlog``/gsd-plant-seed <idea>` **コマンド:** `/gsd-capture --backlog <description>``/gsd-review-backlog``/gsd-capture --seed <idea>`
**目的:** アクティブなプランニングの準備ができていないアイデアをキャプチャします。バックログ項目は 999.x の番号付けを使用して、アクティブなフェーズシーケンスの外に留まります。シードは、適切なマイルストーンで自動的に表面化するトリガー条件を持つ、将来を見据えたアイデアです。 **目的:** アクティブなプランニングの準備ができていないアイデアをキャプチャします。バックログ項目は 999.x の番号付けを使用して、アクティブなフェーズシーケンスの外に留まります。シードは、適切なマイルストーンで自動的に表面化するトリガー条件を持つ、将来を見据えたアイデアです。
@@ -1516,7 +1515,7 @@ Claude が GSD ワークフローコンテキスト外でファイル編集を
### 65. クレーム出所タグ付け ### 65. クレーム出所タグ付け
**対象:** `/gsd-research-phase` **対象:** `/gsd-plan-phase --research-phase`
**目的:** リサーチのクレームにソースエビデンスのタグを付け、仮定を別途記録します。 **目的:** リサーチのクレームにソースエビデンスのタグを付け、仮定を別途記録します。

View File

@@ -18,7 +18,7 @@ Get Shit DoneGSDフレームワークの包括的なドキュメントで
## クイックリンク ## クイックリンク
- **v1.39 の新機能:** `--minimal` インストールプロファイル≥94% コールドスタート削減)、`/gsd-edit-phase`、マージ後ビルド & テストゲート、`review.models.<cli>` ランタイム別レビューモデル、ワークストリーム設定の継承、手動カナリアリリースワークフロー、スキル統合86 → 59 - **v1.39 の新機能:** `--minimal` インストールプロファイル≥94% コールドスタート削減)、`/gsd-phase --edit`、マージ後ビルド & テストゲート、`review.models.<cli>` ランタイム別レビューモデル、ワークストリーム設定の継承、手動カナリアリリースワークフロー、スキル統合86 → 59
- **はじめに:** [README](../README.md) → インストール → `/gsd-new-project` - **はじめに:** [README](../README.md) → インストール → `/gsd-new-project`
- **ワークフロー完全ガイド:** [ユーザーガイド](USER-GUIDE.md) - **ワークフロー完全ガイド:** [ユーザーガイド](USER-GUIDE.md)
- **コマンド一覧:** [コマンドリファレンス](COMMANDS.md) - **コマンド一覧:** [コマンドリファレンス](COMMANDS.md)

View File

@@ -256,8 +256,8 @@ React/Next.js/Vite プロジェクトの場合、UI リサーチャーは `compo
アクティブなプランニングの準備ができていないアイデアは、999.x 番号を使用してバックログに格納され、アクティブなフェーズシーケンスの外に保持されます。 アクティブなプランニングの準備ができていないアイデアは、999.x 番号を使用してバックログに格納され、アクティブなフェーズシーケンスの外に保持されます。
``` ```
/gsd-add-backlog "GraphQL API layer" # Creates 999.1-graphql-api-layer/ /gsd-capture --backlog "GraphQL API layer" # Creates 999.1-graphql-api-layer/
/gsd-add-backlog "Mobile responsive" # Creates 999.2-mobile-responsive/ /gsd-capture --backlog "Mobile responsive" # Creates 999.2-mobile-responsive/
``` ```
バックログアイテムは完全なフェーズディレクトリを取得するため、`/gsd-discuss-phase 999.1` でアイデアをさらに探索したり、準備が整ったら `/gsd-plan-phase 999.1` を使用できます。 バックログアイテムは完全なフェーズディレクトリを取得するため、`/gsd-discuss-phase 999.1` でアイデアをさらに探索したり、準備が整ったら `/gsd-plan-phase 999.1` を使用できます。
@@ -269,7 +269,7 @@ React/Next.js/Vite プロジェクトの場合、UI リサーチャーは `compo
シードは、トリガー条件を持つ将来を見据えたアイデアです。バックログアイテムとは異なり、適切なマイルストーンが到来すると自動的に表面化されます。 シードは、トリガー条件を持つ将来を見据えたアイデアです。バックログアイテムとは異なり、適切なマイルストーンが到来すると自動的に表面化されます。
``` ```
/gsd-plant-seed "Add real-time collab when WebSocket infra is in place" /gsd-capture --seed "Add real-time collab when WebSocket infra is in place"
``` ```
シードは完全な WHY と表面化タイミングを保持します。`/gsd-new-milestone` はすべてのシードをスキャンし、一致するものを提示します。 シードは完全な WHY と表面化タイミングを保持します。`/gsd-new-milestone` はすべてのシードをスキャンし、一致するものを提示します。
@@ -288,7 +288,7 @@ React/Next.js/Vite プロジェクトの場合、UI リサーチャーは `compo
スレッドは `/gsd-pause-work` より軽量です — フェーズ状態やプランコンテキストはありません。各スレッドファイルには Goal、Context、References、Next Steps セクションが含まれます。 スレッドは `/gsd-pause-work` より軽量です — フェーズ状態やプランコンテキストはありません。各スレッドファイルには Goal、Context、References、Next Steps セクションが含まれます。
スレッドは成熟した段階でフェーズ (`/gsd-add-phase`) やバックログアイテム (`/gsd-add-backlog`) にプロモーションできます。 スレッドは成熟した段階でフェーズ (`/gsd-phase`) やバックログアイテム (`/gsd-capture --backlog`) にプロモーションできます。
**保存場所:** `.planning/threads/{slug}.md` **保存場所:** `.planning/threads/{slug}.md`
@@ -313,7 +313,7 @@ React/Next.js/Vite プロジェクトの場合、UI リサーチャーは `compo
各ワークストリームは独自の `.planning/` ディレクトリサブツリーを維持します。ワークストリームを切り替えると、GSD はアクティブなプランニングコンテキストを入れ替え、`/gsd-progress``/gsd-discuss-phase``/gsd-plan-phase` などのコマンドがそのワークストリームの状態に対して動作するようにします。 各ワークストリームは独自の `.planning/` ディレクトリサブツリーを維持します。ワークストリームを切り替えると、GSD はアクティブなプランニングコンテキストを入れ替え、`/gsd-progress``/gsd-discuss-phase``/gsd-plan-phase` などのコマンドがそのワークストリームの状態に対して動作するようにします。
これは `/gsd-new-workspace`(別のリポジトリワークツリーを作成)より軽量です。ワークストリームは同じコードベースと git 履歴を共有しつつ、プランニングアーティファクトを分離します。 これは `/gsd-workspace --new`(別のリポジトリワークツリーを作成)より軽量です。ワークストリームは同じコードベースと git 履歴を共有しつつ、プランニングアーティファクトを分離します。
--- ---
@@ -413,12 +413,11 @@ GSD はマークダウンファイルを生成し、それが LLM のシステ
| コマンド | 用途 | 使用タイミング | | コマンド | 用途 | 使用タイミング |
|---------|---------|-------------| |---------|---------|-------------|
| `/gsd-add-phase` | ロードマップに新しいフェーズを追加 | 初期プランニング後にスコープが拡大した場合 | | `/gsd-phase` | ロードマップに新しいフェーズを追加 | 初期プランニング後にスコープが拡大した場合 |
| `/gsd-insert-phase [N]` | 緊急作業を挿入(小数番号) | マイルストーン中の緊急修正 | | `/gsd-phase --insert [N]` | 緊急作業を挿入(小数番号) | マイルストーン中の緊急修正 |
| `/gsd-remove-phase [N]` | 将来のフェーズを削除して番号を振り直す | 機能のスコープ縮小 | | `/gsd-phase --remove [N]` | 将来のフェーズを削除して番号を振り直す | 機能のスコープ縮小 |
| `/gsd-list-phase-assumptions [N]` | Claude の意図するアプローチをプレビュー | プランニング前に方向性を確認 | | `/gsd-list-phase-assumptions [N]` | Claude の意図するアプローチをプレビュー | プランニング前に方向性を確認 |
| `/gsd-plan-milestone-gaps` | 監査ギャップに対するフェーズを作成 | 監査で不足項目が見つかった後 | | `/gsd-plan-phase --research-phase [N]` | エコシステムの深いリサーチのみ | 複雑または不慣れなドメイン |
| `/gsd-research-phase [N]` | エコシステムの深いリサーチのみ | 複雑または不慣れなドメイン |
### ブラウンフィールドとユーティリティ ### ブラウンフィールドとユーティリティ
@@ -428,11 +427,11 @@ GSD はマークダウンファイルを生成し、それが LLM のシステ
| `/gsd-quick` | GSD 保証付きのアドホックタスク | バグ修正、小機能、設定変更 | | `/gsd-quick` | GSD 保証付きのアドホックタスク | バグ修正、小機能、設定変更 |
| `/gsd-debug [desc]` | 永続状態を持つ体系的デバッグ | 何かが壊れた時 | | `/gsd-debug [desc]` | 永続状態を持つ体系的デバッグ | 何かが壊れた時 |
| `/gsd-forensics` | ワークフロー障害の診断レポート | 状態、アーティファクト、git 履歴が破損していると思われる場合 | | `/gsd-forensics` | ワークフロー障害の診断レポート | 状態、アーティファクト、git 履歴が破損していると思われる場合 |
| `/gsd-add-todo [desc]` | 後でやるアイデアを記録 | セッション中にアイデアが浮かんだ時 | | `/gsd-capture [desc]` | 後でやるアイデアを記録 | セッション中にアイデアが浮かんだ時 |
| `/gsd-check-todos` | 保留中の TODO を一覧表示 | 記録したアイデアのレビュー | | `/gsd-capture --list` | 保留中の TODO を一覧表示 | 記録したアイデアのレビュー |
| `/gsd-settings` | ワークフロートグルとモデルプロファイルを設定 | モデル変更、エージェントのトグル | | `/gsd-settings` | ワークフロートグルとモデルプロファイルを設定 | モデル変更、エージェントのトグル |
| `/gsd-set-profile <profile>` | クイックプロファイル切り替え | コスト/品質トレードオフの変更 | | `/gsd-config --profile <profile>` | クイックプロファイル切り替え | コスト/品質トレードオフの変更 |
| `/gsd-reapply-patches` | アップデート後にローカル変更を復元 | ローカル編集がある場合の `/gsd-update` 後 | | `/gsd-update --reapply` | アップデート後にローカル変更を復元 | ローカル編集がある場合の `/gsd-update` 後 |
### コード品質とレビュー ### コード品質とレビュー
@@ -446,9 +445,9 @@ GSD はマークダウンファイルを生成し、それが LLM のシステ
| コマンド | 用途 | 使用タイミング | | コマンド | 用途 | 使用タイミング |
|---------|---------|-------------| |---------|---------|-------------|
| `/gsd-add-backlog <desc>` | バックログパーキングロットにアイデアを追加999.x | アクティブなプランニングの準備ができていないアイデア | | `/gsd-capture --backlog <desc>` | バックログパーキングロットにアイデアを追加999.x | アクティブなプランニングの準備ができていないアイデア |
| `/gsd-review-backlog` | バックログアイテムのプロモーション/保持/削除 | 新マイルストーン前の優先順位付け | | `/gsd-review-backlog` | バックログアイテムのプロモーション/保持/削除 | 新マイルストーン前の優先順位付け |
| `/gsd-plant-seed <idea>` | トリガー条件付きの将来を見据えたアイデア | 将来のマイルストーンで表面化すべきアイデア | | `/gsd-capture --seed <idea>` | トリガー条件付きの将来を見据えたアイデア | 将来のマイルストーンで表面化すべきアイデア |
| `/gsd-thread [name]` | 永続コンテキストスレッド | フェーズ構造外のクロスセッション作業 | | `/gsd-thread [name]` | 永続コンテキストスレッド | フェーズ構造外のクロスセッション作業 |
--- ---
@@ -642,7 +641,6 @@ claude --dangerously-skip-permissions
```bash ```bash
/gsd-audit-milestone # 要件カバレッジを確認、スタブを検出 /gsd-audit-milestone # 要件カバレッジを確認、スタブを検出
/gsd-plan-milestone-gaps # 監査でギャップが見つかった場合、フェーズを作成して埋める
/gsd-complete-milestone # アーカイブ、タグ付け、完了 /gsd-complete-milestone # アーカイブ、タグ付け、完了
``` ```
@@ -659,11 +657,11 @@ claude --dangerously-skip-permissions
### マイルストーン中のスコープ変更 ### マイルストーン中のスコープ変更
```bash ```bash
/gsd-add-phase # ロードマップに新しいフェーズを追加 /gsd-phase # ロードマップに新しいフェーズを追加
# または # または
/gsd-insert-phase 3 # フェーズ 3 と 4 の間に緊急作業を挿入 /gsd-phase --insert 3 # フェーズ 3 と 4 の間に緊急作業を挿入
# または # または
/gsd-remove-phase 7 # フェーズ 7 をスコープ外にして番号を振り直す /gsd-phase --remove 7 # フェーズ 7 をスコープ外にして番号を振り直す
``` ```
### マルチプロジェクトワークスペース ### マルチプロジェクトワークスペース
@@ -672,18 +670,18 @@ claude --dangerously-skip-permissions
```bash ```bash
# モノレポからリポジトリを含むワークスペースを作成 # モノレポからリポジトリを含むワークスペースを作成
/gsd-new-workspace --name feature-b --repos hr-ui,ZeymoAPI /gsd-workspace --new --name feature-b --repos hr-ui,ZeymoAPI
# フィーチャーブランチの分離 — 独自の .planning/ を持つ現在のリポジトリのワークツリー # フィーチャーブランチの分離 — 独自の .planning/ を持つ現在のリポジトリのワークツリー
/gsd-new-workspace --name feature-b --repos . /gsd-workspace --new --name feature-b --repos .
# ワークスペースに移動して GSD を初期化 # ワークスペースに移動して GSD を初期化
cd ~/gsd-workspaces/feature-b cd ~/gsd-workspaces/feature-b
/gsd-new-project /gsd-new-project
# ワークスペースの一覧と管理 # ワークスペースの一覧と管理
/gsd-list-workspaces /gsd-workspace --list
/gsd-remove-workspace feature-b /gsd-workspace --remove feature-b
``` ```
各ワークスペースには以下が含まれます: 各ワークスペースには以下が含まれます:
@@ -721,7 +719,7 @@ cd ~/gsd-workspaces/feature-b
### モデルのコストが高すぎる ### モデルのコストが高すぎる
budget プロファイルに切り替えてください:`/gsd-set-profile budget`。ドメインに慣れている場合またはClaude が慣れている場合)は、`/gsd-settings` でリサーチエージェントと plan-check エージェントを無効にしてください。 budget プロファイルに切り替えてください:`/gsd-config --profile budget`。ドメインに慣れている場合またはClaude が慣れている場合)は、`/gsd-settings` でリサーチエージェントと plan-check エージェントを無効にしてください。
### 非 Claude ランタイムの使用Codex、OpenCode、Gemini CLI、Kilo ### 非 Claude ランタイムの使用Codex、OpenCode、Gemini CLI、Kilo
@@ -746,7 +744,7 @@ budget プロファイルに切り替えてください:`/gsd-set-profile budg
### 非 Anthropic プロバイダーでの Claude Code の使用OpenRouter、ローカル ### 非 Anthropic プロバイダーでの Claude Code の使用OpenRouter、ローカル
GSD サブエージェントが Anthropic モデルを呼び出し、OpenRouter やローカルプロバイダーを通じて支払っている場合は、`inherit` プロファイルに切り替えてください:`/gsd-set-profile inherit`。これにより、すべてのエージェントが特定の Anthropic モデルの代わりに現在のセッションモデルを使用します。`/gsd-settings` → モデルプロファイル → Inherit も参照してください。 GSD サブエージェントが Anthropic モデルを呼び出し、OpenRouter やローカルプロバイダーを通じて支払っている場合は、`inherit` プロファイルに切り替えてください:`/gsd-config --profile inherit`。これにより、すべてのエージェントが特定の Anthropic モデルの代わりに現在のセッションモデルを使用します。`/gsd-settings` → モデルプロファイル → Inherit も参照してください。
### 機密/プライベートプロジェクトでの作業 ### 機密/プライベートプロジェクトでの作業
@@ -754,7 +752,7 @@ GSD サブエージェントが Anthropic モデルを呼び出し、OpenRouter
### GSD アップデートがローカル変更を上書きした ### GSD アップデートがローカル変更を上書きした
v1.17 以降、インストーラーはローカルで変更されたファイルを `gsd-local-patches/` にバックアップします。`/gsd-reapply-patches` を実行して変更をマージし直してください。 v1.17 以降、インストーラーはローカルで変更されたファイルを `gsd-local-patches/` にバックアップします。`/gsd-update --reapply` を実行して変更をマージし直してください。
### ワークフロー診断 (`/gsd-forensics`) ### ワークフロー診断 (`/gsd-forensics`)
@@ -794,14 +792,13 @@ Windows でインストーラーが `EPERM: operation not permitted, scandir`
|---------|----------| |---------|----------|
| コンテキストの喪失 / 新セッション | `/gsd-resume-work` または `/gsd-progress` | | コンテキストの喪失 / 新セッション | `/gsd-resume-work` または `/gsd-progress` |
| フェーズが失敗した | フェーズのコミットを `git revert` して再プランニング | | フェーズが失敗した | フェーズのコミットを `git revert` して再プランニング |
| スコープ変更が必要 | `/gsd-add-phase``/gsd-insert-phase`、または `/gsd-remove-phase` | | スコープ変更が必要 | `/gsd-phase``/gsd-phase --insert`、または `/gsd-phase --remove` |
| マイルストーン監査でギャップを発見 | `/gsd-plan-milestone-gaps` |
| 何かが壊れた | `/gsd-debug "description"` | | 何かが壊れた | `/gsd-debug "description"` |
| ワークフロー状態が破損している可能性 | `/gsd-forensics` | | ワークフロー状態が破損している可能性 | `/gsd-forensics` |
| ターゲットを絞った修正 | `/gsd-quick` | | ターゲットを絞った修正 | `/gsd-quick` |
| プランがビジョンに合わない | `/gsd-discuss-phase [N]` で再プランニング | | プランがビジョンに合わない | `/gsd-discuss-phase [N]` で再プランニング |
| コストが高い | `/gsd-set-profile budget``/gsd-settings` でエージェントをオフ | | コストが高い | `/gsd-config --profile budget``/gsd-settings` でエージェントをオフ |
| アップデートがローカル変更を壊した | `/gsd-reapply-patches` | | アップデートがローカル変更を壊した | `/gsd-update --reapply` |
| ステークホルダー向けセッションサマリーが欲しい | `/gsd-session-report` | | ステークホルダー向けセッションサマリーが欲しい | `/gsd-session-report` |
| 次のステップがわからない | `/gsd-next` | | 次のステップがわからない | `/gsd-next` |
| 並列実行でビルドエラー | GSD を更新するか `parallelization.enabled: false` を設定 | | 並列実行でビルドエラー | GSD を更新するか `parallelization.enabled: false` を設定 |

View File

@@ -411,7 +411,7 @@ UI-SPEC.md (per phase) ───────────────────
│ ├── pending/ # 캡처된 아이디어 │ ├── pending/ # 캡처된 아이디어
│ └── done/ # 완료된 할 일 │ └── done/ # 완료된 할 일
├── threads/ # 영구 컨텍스트 스레드 (/gsd-thread에서) ├── threads/ # 영구 컨텍스트 스레드 (/gsd-thread에서)
├── seeds/ # 미래 지향적 아이디어 (/gsd-plant-seed에서) ├── seeds/ # 미래 지향적 아이디어 (/gsd-capture --seed에서)
├── debug/ # 활성 디버그 세션 ├── debug/ # 활성 디버그 세션
│ ├── *.md # 활성 세션 │ ├── *.md # 활성 세션
│ ├── resolved/ # 보관된 세션 │ ├── resolved/ # 보관된 세션
@@ -439,7 +439,7 @@ UI-SPEC.md (per phase) ───────────────────
- Antigravity: Google 모델 등가물을 사용한 skills-first 방식 - Antigravity: Google 모델 등가물을 사용한 skills-first 방식
5. **경로 정규화**`~/.claude/` 경로를 런타임별 경로로 교체 5. **경로 정규화**`~/.claude/` 경로를 런타임별 경로로 교체
6. **설정 통합** — 런타임의 `settings.json`에 훅 등록 6. **설정 통합** — 런타임의 `settings.json`에 훅 등록
7. **패치 백업** — v1.17부터 로컬 수정 파일을 `gsd-local-patches/`에 백업하여 `/gsd-reapply-patches`에 사용 7. **패치 백업** — v1.17부터 로컬 수정 파일을 `gsd-local-patches/`에 백업하여 `/gsd-update --reapply`에 사용
8. **매니페스트 추적** — 깔끔한 제거를 위해 `gsd-file-manifest.json` 작성 8. **매니페스트 추적** — 깔끔한 제거를 위해 `gsd-file-manifest.json` 작성
9. **제거 모드**`--uninstall`로 모든 GSD 파일, 훅, 설정 제거 9. **제거 모드**`--uninstall`로 모든 GSD 파일, 훅, 설정 제거

View File

@@ -32,7 +32,7 @@
--- ---
### `/gsd-new-workspace` ### `/gsd-workspace --new`
격리된 워크스페이스를 생성합니다. 저장소 복사본과 독립적인 `.planning/` 디렉터리가 포함됩니다. 격리된 워크스페이스를 생성합니다. 저장소 복사본과 독립적인 `.planning/` 디렉터리가 포함됩니다.
@@ -52,14 +52,14 @@
**생성 파일:** `WORKSPACE.md`, `.planning/`, 저장소 복사본 (worktree 또는 clone) **생성 파일:** `WORKSPACE.md`, `.planning/`, 저장소 복사본 (worktree 또는 clone)
```bash ```bash
/gsd-new-workspace --name feature-b --repos hr-ui,ZeymoAPI /gsd-workspace --new --name feature-b --repos hr-ui,ZeymoAPI
/gsd-new-workspace --name feature-b --repos . --strategy worktree # 동일 저장소 격리 /gsd-workspace --new --name feature-b --repos . --strategy worktree # 동일 저장소 격리
/gsd-new-workspace --name spike --repos api,web --strategy clone # 전체 클론 /gsd-workspace --new --name spike --repos api,web --strategy clone # 전체 클론
``` ```
--- ---
### `/gsd-list-workspaces` ### `/gsd-workspace --list`
활성 GSD 워크스페이스와 상태를 목록으로 표시합니다. 활성 GSD 워크스페이스와 상태를 목록으로 표시합니다.
@@ -67,12 +67,12 @@
**표시 항목:** 이름, 저장소 수, 전략, GSD 프로젝트 상태 **표시 항목:** 이름, 저장소 수, 전략, GSD 프로젝트 상태
```bash ```bash
/gsd-list-workspaces /gsd-workspace --list
``` ```
--- ---
### `/gsd-remove-workspace` ### `/gsd-workspace --remove`
워크스페이스를 제거하고 git worktree를 정리합니다. 워크스페이스를 제거하고 git worktree를 정리합니다.
@@ -83,7 +83,7 @@
**안전 장치:** 저장소에 커밋되지 않은 변경사항이 있으면 제거를 거부합니다. 이름 확인이 필요합니다. **안전 장치:** 저장소에 커밋되지 않은 변경사항이 있으면 제거를 거부합니다. 이름 확인이 필요합니다.
```bash ```bash
/gsd-remove-workspace feature-b /gsd-workspace --remove feature-b
``` ```
--- ---
@@ -368,15 +368,15 @@
## 페이즈 관리 명령어 ## 페이즈 관리 명령어
### `/gsd-add-phase` ### `/gsd-phase`
로드맵에 새 페이즈를 추가합니다. 로드맵에 새 페이즈를 추가합니다.
```bash ```bash
/gsd-add-phase # 대화형 — 페이즈를 설명합니다 /gsd-phase # 대화형 — 페이즈를 설명합니다
``` ```
### `/gsd-insert-phase` ### `/gsd-phase --insert`
소수점 번호 체계를 사용하여 페이즈 사이에 긴급 작업을 삽입합니다. 소수점 번호 체계를 사용하여 페이즈 사이에 긴급 작업을 삽입합니다.
@@ -385,10 +385,10 @@
| `N` | 아니오 | 이 페이즈 번호 다음에 삽입합니다 | | `N` | 아니오 | 이 페이즈 번호 다음에 삽입합니다 |
```bash ```bash
/gsd-insert-phase 3 # 페이즈 3과 4 사이에 삽입 → 3.1 생성 /gsd-phase --insert 3 # 페이즈 3과 4 사이에 삽입 → 3.1 생성
``` ```
### `/gsd-remove-phase` ### `/gsd-phase --remove`
미래 페이즈를 제거하고 이후 페이즈 번호를 재정렬합니다. 미래 페이즈를 제거하고 이후 페이즈 번호를 재정렬합니다.
@@ -397,7 +397,7 @@
| `N` | 아니오 | 제거할 페이즈 번호 | | `N` | 아니오 | 제거할 페이즈 번호 |
```bash ```bash
/gsd-remove-phase 7 # 페이즈 7 제거, 8→7, 9→8 등으로 재번호 /gsd-phase --remove 7 # 페이즈 7 제거, 8→7, 9→8 등으로 재번호
``` ```
### `/gsd-list-phase-assumptions` ### `/gsd-list-phase-assumptions`
@@ -412,15 +412,8 @@
/gsd-list-phase-assumptions 2 # 페이즈 2 가정 사항 확인 /gsd-list-phase-assumptions 2 # 페이즈 2 가정 사항 확인
``` ```
### `/gsd-plan-milestone-gaps`
마일스톤 감사에서 발견된 갭을 보완하는 페이즈를 생성합니다. ### `/gsd-plan-phase --research-phase`
```bash
/gsd-plan-milestone-gaps # 각 감사 갭에 대한 페이즈 생성
```
### `/gsd-research-phase`
심층 에코시스템 조사만 수행합니다 (독립 실행 — 일반적으로 `/gsd-plan-phase`를 사용하세요). 심층 에코시스템 조사만 수행합니다 (독립 실행 — 일반적으로 `/gsd-plan-phase`를 사용하세요).
@@ -429,7 +422,7 @@
| `N` | 아니오 | 페이즈 번호 | | `N` | 아니오 | 페이즈 번호 |
```bash ```bash
/gsd-research-phase 4 # 페이즈 4 도메인 조사 /gsd-plan-phase --research-phase 4 # 페이즈 4 도메인 조사
``` ```
### `/gsd-validate-phase` ### `/gsd-validate-phase`
@@ -598,7 +591,7 @@ GSD 보증을 갖춘 임시 작업을 실행합니다.
/gsd-debug --diagnose "API returning 500 on /users endpoint" /gsd-debug --diagnose "API returning 500 on /users endpoint"
``` ```
### `/gsd-add-todo` ### `/gsd-capture`
나중을 위한 아이디어나 작업을 캡처합니다. 나중을 위한 아이디어나 작업을 캡처합니다.
@@ -607,15 +600,15 @@ GSD 보증을 갖춘 임시 작업을 실행합니다.
| `description` | 아니오 | 할 일 설명 | | `description` | 아니오 | 할 일 설명 |
```bash ```bash
/gsd-add-todo "Consider adding dark mode support" /gsd-capture "Consider adding dark mode support"
``` ```
### `/gsd-check-todos` ### `/gsd-capture --list`
보류 중인 할 일 목록을 표시하고 작업할 항목을 선택합니다. 보류 중인 할 일 목록을 표시하고 작업할 항목을 선택합니다.
```bash ```bash
/gsd-check-todos /gsd-capture --list
``` ```
### `/gsd-add-tests` ### `/gsd-add-tests`
@@ -752,7 +745,7 @@ Claude Code 세션 분석을 통해 8개 차원(커뮤니케이션 스타일,
/gsd-settings # 대화형 설정 /gsd-settings # 대화형 설정
``` ```
### `/gsd-set-profile` ### `/gsd-config --profile`
프로필을 빠르게 전환합니다. 프로필을 빠르게 전환합니다.
@@ -761,8 +754,8 @@ Claude Code 세션 분석을 통해 8개 차원(커뮤니케이션 스타일,
| `profile` | **예** | `quality`, `balanced`, `budget`, 또는 `inherit` | | `profile` | **예** | `quality`, `balanced`, `budget`, 또는 `inherit` |
```bash ```bash
/gsd-set-profile budget # 예산 프로필로 전환 /gsd-config --profile budget # 예산 프로필로 전환
/gsd-set-profile quality # 품질 프로필로 전환 /gsd-config --profile quality # 품질 프로필로 전환
``` ```
--- ---
@@ -794,12 +787,12 @@ Claude Code 세션 분석을 통해 8개 차원(커뮤니케이션 스타일,
/gsd-update # 업데이트 확인 및 설치 /gsd-update # 업데이트 확인 및 설치
``` ```
### `/gsd-reapply-patches` ### `/gsd-update --reapply`
GSD 업데이트 후 로컬 수정사항을 복원합니다. GSD 업데이트 후 로컬 수정사항을 복원합니다.
```bash ```bash
/gsd-reapply-patches # 로컬 변경사항 병합 /gsd-update --reapply # 로컬 변경사항 병합
``` ```
--- ---
@@ -885,7 +878,7 @@ GSD 업데이트 후 로컬 수정사항을 복원합니다.
## 백로그 및 스레드 명령어 ## 백로그 및 스레드 명령어
### `/gsd-add-backlog` ### `/gsd-capture --backlog`
999.x 번호 체계를 사용하여 백로그 파킹 롯에 아이디어를 추가합니다. 999.x 번호 체계를 사용하여 백로그 파킹 롯에 아이디어를 추가합니다.
@@ -896,8 +889,8 @@ GSD 업데이트 후 로컬 수정사항을 복원합니다.
**999.x 번호 체계**는 백로그 항목을 활성 페이즈 순서 밖에 유지합니다. 페이즈 디렉터리가 즉시 생성되므로 해당 항목에 대해 `/gsd-discuss-phase``/gsd-plan-phase`를 사용할 수 있습니다. **999.x 번호 체계**는 백로그 항목을 활성 페이즈 순서 밖에 유지합니다. 페이즈 디렉터리가 즉시 생성되므로 해당 항목에 대해 `/gsd-discuss-phase``/gsd-plan-phase`를 사용할 수 있습니다.
```bash ```bash
/gsd-add-backlog "GraphQL API layer" /gsd-capture --backlog "GraphQL API layer"
/gsd-add-backlog "Mobile responsive redesign" /gsd-capture --backlog "Mobile responsive redesign"
``` ```
--- ---
@@ -914,7 +907,7 @@ GSD 업데이트 후 로컬 수정사항을 복원합니다.
--- ---
### `/gsd-plant-seed` ### `/gsd-capture --seed`
트리거 조건이 있는 미래 지향적인 아이디어를 캡처합니다. 적절한 마일스톤 시점에 자동으로 표면화됩니다. 트리거 조건이 있는 미래 지향적인 아이디어를 캡처합니다. 적절한 마일스톤 시점에 자동으로 표면화됩니다.
@@ -928,7 +921,7 @@ GSD 업데이트 후 로컬 수정사항을 복원합니다.
**사용처:** `/gsd-new-milestone` (시드를 스캔하여 일치 항목 제시) **사용처:** `/gsd-new-milestone` (시드를 스캔하여 일치 항목 제시)
```bash ```bash
/gsd-plant-seed "Add real-time collaboration when WebSocket infra is in place" /gsd-capture --seed "Add real-time collaboration when WebSocket infra is in place"
``` ```
--- ---

View File

@@ -386,7 +386,6 @@
- REQ-MILE-08: 새 마일스톤은 new-project와 동일한 흐름을 따라야 합니다(질문 → 연구 → 요구사항 → 로드맵). - REQ-MILE-08: 새 마일스톤은 new-project와 동일한 흐름을 따라야 합니다(질문 → 연구 → 요구사항 → 로드맵).
- REQ-MILE-09: 새 마일스톤은 기존 워크플로우 구성을 초기화해서는 안 됩니다. - REQ-MILE-09: 새 마일스톤은 기존 워크플로우 구성을 초기화해서는 안 됩니다.
**갭 해소.** `/gsd-plan-milestone-gaps`는 감사에서 식별된 갭을 해소하는 페이즈를 생성합니다.
--- ---
@@ -394,7 +393,7 @@
### 9. Phase Management ### 9. Phase Management
**명령어:** `/gsd-add-phase`, `/gsd-insert-phase [N]`, `/gsd-remove-phase [N]` **명령어:** `/gsd-phase`, `/gsd-phase --insert [N]`, `/gsd-phase --remove [N]`
**목적:** 개발 중 동적 로드맵 수정. **목적:** 개발 중 동적 로드맵 수정.
@@ -681,7 +680,7 @@
### 26. Model Profiles ### 26. Model Profiles
**명령어:** `/gsd-set-profile <quality|balanced|budget|inherit>` **명령어:** `/gsd-config --profile <quality|balanced|budget|inherit>`
**목적:** 각 에이전트가 사용하는 AI 모델을 제어하여 품질과 비용의 균형을 맞춥니다. **목적:** 각 에이전트가 사용하는 AI 모델을 제어하여 품질과 비용의 균형을 맞춥니다.
@@ -763,7 +762,7 @@
### 29. Todo Management ### 29. Todo Management
**명령어:** `/gsd-add-todo [desc]`, `/gsd-check-todos` **명령어:** `/gsd-capture [desc]`, `/gsd-capture --list`
**목적:** 세션 중 나중에 처리할 아이디어와 작업을 캡처합니다. **목적:** 세션 중 나중에 처리할 아이디어와 작업을 캡처합니다.
@@ -800,7 +799,7 @@
- REQ-UPDATE-02: 업데이트 전에 새 버전의 변경 로그를 표시해야 합니다. - REQ-UPDATE-02: 업데이트 전에 새 버전의 변경 로그를 표시해야 합니다.
- REQ-UPDATE-03: 런타임을 인식하고 올바른 디렉토리를 대상으로 해야 합니다. - REQ-UPDATE-03: 런타임을 인식하고 올바른 디렉토리를 대상으로 해야 합니다.
- REQ-UPDATE-04: 로컬에서 수정된 파일을 `gsd-local-patches/`에 백업해야 합니다. - REQ-UPDATE-04: 로컬에서 수정된 파일을 `gsd-local-patches/`에 백업해야 합니다.
- REQ-UPDATE-05: `/gsd-reapply-patches`는 업데이트 후 로컬 수정사항을 복원해야 합니다. - REQ-UPDATE-05: `/gsd-update --reapply`는 업데이트 후 로컬 수정사항을 복원해야 합니다.
--- ---
@@ -1066,7 +1065,7 @@ fix(03-01): correct auth token expiry
### 43. Backlog Parking Lot ### 43. Backlog Parking Lot
**명령어:** `/gsd-add-backlog <description>`, `/gsd-review-backlog`, `/gsd-plant-seed <idea>` **명령어:** `/gsd-capture --backlog <description>`, `/gsd-review-backlog`, `/gsd-capture --seed <idea>`
**목적:** 아직 적극적인 계획에 준비되지 않은 아이디어를 캡처합니다. 백로그 항목은 활성 페이즈 순서 밖에 있기 위해 999.x 번호를 사용합니다. 시드는 올바른 마일스톤에서 자동으로 표시되는 트리거 조건이 있는 미래 지향적 아이디어입니다. **목적:** 아직 적극적인 계획에 준비되지 않은 아이디어를 캡처합니다. 백로그 항목은 활성 페이즈 순서 밖에 있기 위해 999.x 번호를 사용합니다. 시드는 올바른 마일스톤에서 자동으로 표시되는 트리거 조건이 있는 미래 지향적 아이디어입니다.
@@ -1516,7 +1515,7 @@ Claude가 GSD 워크플로우 컨텍스트 밖에서 파일 편집을 시도하
### 65. 주장 출처 태깅 ### 65. 주장 출처 태깅
**대상:** `/gsd-research-phase` **대상:** `/gsd-plan-phase --research-phase`
**목적:** 연구 주장에 출처 증거를 태깅하고 가정을 별도로 기록합니다. **목적:** 연구 주장에 출처 증거를 태깅하고 가정을 별도로 기록합니다.

View File

@@ -20,7 +20,7 @@ Get Shit Done (GSD) 프레임워크의 종합 문서입니다. GSD는 AI 코딩
## 빠른 링크 ## 빠른 링크
- **v1.39의 새로운 기능:** `--minimal` 설치 프로파일(콜드 스타트 ≥94% 감소), `/gsd-edit-phase`, 머지 후 빌드 & 테스트 게이트, `review.models.<cli>` 런타임별 리뷰 모델, 워크스트림 설정 상속, 수동 카나리 릴리스 워크플로, 스킬 통합(86 → 59) - **v1.39의 새로운 기능:** `--minimal` 설치 프로파일(콜드 스타트 ≥94% 감소), `/gsd-phase --edit`, 머지 후 빌드 & 테스트 게이트, `review.models.<cli>` 런타임별 리뷰 모델, 워크스트림 설정 상속, 수동 카나리 릴리스 워크플로, 스킬 통합(86 → 59)
- **시작하기:** [README](../README.md) → 설치 → `/gsd-new-project` - **시작하기:** [README](../README.md) → 설치 → `/gsd-new-project`
- **전체 워크플로우 안내:** [User Guide](USER-GUIDE.md) - **전체 워크플로우 안내:** [User Guide](USER-GUIDE.md)
- **모든 명령어 한눈에 보기:** [Command Reference](COMMANDS.md) - **모든 명령어 한눈에 보기:** [Command Reference](COMMANDS.md)

View File

@@ -256,8 +256,8 @@ React/Next.js/Vite 프로젝트에서 `components.json`이 없으면 UI 조사
활성 계획에 아직 준비되지 않은 아이디어는 999.x 번호 체계를 사용하여 백로그에 보관하며 활성 페이즈 순서 밖에 유지됩니다. 활성 계획에 아직 준비되지 않은 아이디어는 999.x 번호 체계를 사용하여 백로그에 보관하며 활성 페이즈 순서 밖에 유지됩니다.
``` ```
/gsd-add-backlog "GraphQL API layer" # Creates 999.1-graphql-api-layer/ /gsd-capture --backlog "GraphQL API layer" # Creates 999.1-graphql-api-layer/
/gsd-add-backlog "Mobile responsive" # Creates 999.2-mobile-responsive/ /gsd-capture --backlog "Mobile responsive" # Creates 999.2-mobile-responsive/
``` ```
백로그 항목은 전체 페이즈 디렉터리를 얻으므로 `/gsd-discuss-phase 999.1`로 아이디어를 더 탐구하거나 준비가 되면 `/gsd-plan-phase 999.1`을 사용할 수 있습니다. 백로그 항목은 전체 페이즈 디렉터리를 얻으므로 `/gsd-discuss-phase 999.1`로 아이디어를 더 탐구하거나 준비가 되면 `/gsd-plan-phase 999.1`을 사용할 수 있습니다.
@@ -269,7 +269,7 @@ React/Next.js/Vite 프로젝트에서 `components.json`이 없으면 UI 조사
시드는 트리거 조건이 있는 미래 지향적인 아이디어입니다. 백로그 항목과 달리 시드는 적절한 마일스톤 시점에 자동으로 표면화됩니다. 시드는 트리거 조건이 있는 미래 지향적인 아이디어입니다. 백로그 항목과 달리 시드는 적절한 마일스톤 시점에 자동으로 표면화됩니다.
``` ```
/gsd-plant-seed "Add real-time collab when WebSocket infra is in place" /gsd-capture --seed "Add real-time collab when WebSocket infra is in place"
``` ```
시드는 전체 WHY와 언제 표면화할지를 보존합니다. `/gsd-new-milestone`은 모든 시드를 스캔하여 일치 항목을 제시합니다. 시드는 전체 WHY와 언제 표면화할지를 보존합니다. `/gsd-new-milestone`은 모든 시드를 스캔하여 일치 항목을 제시합니다.
@@ -288,7 +288,7 @@ React/Next.js/Vite 프로젝트에서 `components.json`이 없으면 UI 조사
스레드는 `/gsd-pause-work`보다 가볍습니다. 페이즈 상태나 계획 컨텍스트가 없습니다. 각 스레드 파일에는 목표, 컨텍스트, 참조, 다음 단계 섹션이 포함됩니다. 스레드는 `/gsd-pause-work`보다 가볍습니다. 페이즈 상태나 계획 컨텍스트가 없습니다. 각 스레드 파일에는 목표, 컨텍스트, 참조, 다음 단계 섹션이 포함됩니다.
스레드가 성숙해지면 페이즈(`/gsd-add-phase`)나 백로그 항목(`/gsd-add-backlog`)으로 승격할 수 있습니다. 스레드가 성숙해지면 페이즈(`/gsd-phase`)나 백로그 항목(`/gsd-capture --backlog`)으로 승격할 수 있습니다.
**저장 위치:** `.planning/threads/{slug}.md` **저장 위치:** `.planning/threads/{slug}.md`
@@ -313,7 +313,7 @@ React/Next.js/Vite 프로젝트에서 `components.json`이 없으면 UI 조사
각 워크스트림은 자체 `.planning/` 디렉터리 하위 트리를 유지합니다. 워크스트림을 전환하면 GSD가 활성 계획 컨텍스트를 교체하여 `/gsd-progress`, `/gsd-discuss-phase`, `/gsd-plan-phase` 및 기타 명령어가 해당 워크스트림의 상태로 동작합니다. 각 워크스트림은 자체 `.planning/` 디렉터리 하위 트리를 유지합니다. 워크스트림을 전환하면 GSD가 활성 계획 컨텍스트를 교체하여 `/gsd-progress`, `/gsd-discuss-phase`, `/gsd-plan-phase` 및 기타 명령어가 해당 워크스트림의 상태로 동작합니다.
이는 `/gsd-new-workspace`(별도 저장소 worktree를 생성)보다 가볍습니다. 워크스트림은 동일한 코드베이스와 git 히스토리를 공유하지만 계획 아티팩트를 격리합니다. 이는 `/gsd-workspace --new`(별도 저장소 worktree를 생성)보다 가볍습니다. 워크스트림은 동일한 코드베이스와 git 히스토리를 공유하지만 계획 아티팩트를 격리합니다.
--- ---
@@ -413,12 +413,11 @@ GSD는 LLM 시스템 프롬프트가 되는 마크다운 파일을 생성합니
| 명령어 | 목적 | 사용 시점 | | 명령어 | 목적 | 사용 시점 |
|--------|------|----------| |--------|------|----------|
| `/gsd-add-phase` | 로드맵에 새 페이즈 추가 | 초기 계획 후 범위가 늘어날 때 | | `/gsd-phase` | 로드맵에 새 페이즈 추가 | 초기 계획 후 범위가 늘어날 때 |
| `/gsd-insert-phase [N]` | 긴급 작업 삽입 (소수점 번호 체계) | 마일스톤 중간의 긴급 수정 시 | | `/gsd-phase --insert [N]` | 긴급 작업 삽입 (소수점 번호 체계) | 마일스톤 중간의 긴급 수정 시 |
| `/gsd-remove-phase [N]` | 미래 페이즈 제거 및 재번호 | 기능 범위 축소 시 | | `/gsd-phase --remove [N]` | 미래 페이즈 제거 및 재번호 | 기능 범위 축소 시 |
| `/gsd-list-phase-assumptions [N]` | Claude의 예상 접근 방식 미리 확인 | 계획 전 방향 검증 시 | | `/gsd-list-phase-assumptions [N]` | Claude의 예상 접근 방식 미리 확인 | 계획 전 방향 검증 시 |
| `/gsd-plan-milestone-gaps` | 감사 갭을 위한 페이즈 생성 | 감사에서 누락 항목이 발견된 후 | | `/gsd-plan-phase --research-phase [N]` | 심층 에코시스템 조사만 수행 | 복잡하거나 익숙하지 않은 도메인 |
| `/gsd-research-phase [N]` | 심층 에코시스템 조사만 수행 | 복잡하거나 익숙하지 않은 도메인 |
### 브라운필드 및 유틸리티 ### 브라운필드 및 유틸리티
@@ -428,11 +427,11 @@ GSD는 LLM 시스템 프롬프트가 되는 마크다운 파일을 생성합니
| `/gsd-quick` | GSD 보증을 갖춘 임시 작업 | 버그 수정, 소규모 기능, 설정 변경 | | `/gsd-quick` | GSD 보증을 갖춘 임시 작업 | 버그 수정, 소규모 기능, 설정 변경 |
| `/gsd-debug [desc]` | 지속적인 상태를 유지하는 체계적인 디버깅 | 문제가 발생했을 때 | | `/gsd-debug [desc]` | 지속적인 상태를 유지하는 체계적인 디버깅 | 문제가 발생했을 때 |
| `/gsd-forensics` | 워크플로우 실패에 대한 진단 보고서 | 상태, 아티팩트, git 히스토리가 손상된 것 같을 때 | | `/gsd-forensics` | 워크플로우 실패에 대한 진단 보고서 | 상태, 아티팩트, git 히스토리가 손상된 것 같을 때 |
| `/gsd-add-todo [desc]` | 나중을 위한 아이디어 캡처 | 세션 중에 생각이 날 때 | | `/gsd-capture [desc]` | 나중을 위한 아이디어 캡처 | 세션 중에 생각이 날 때 |
| `/gsd-check-todos` | 보류 중인 할 일 목록 | 캡처된 아이디어 검토 시 | | `/gsd-capture --list` | 보류 중인 할 일 목록 | 캡처된 아이디어 검토 시 |
| `/gsd-settings` | 워크플로우 토글 및 모델 프로필 설정 | 모델 변경, 에이전트 토글 시 | | `/gsd-settings` | 워크플로우 토글 및 모델 프로필 설정 | 모델 변경, 에이전트 토글 시 |
| `/gsd-set-profile <profile>` | 빠른 프로필 전환 | 비용/품질 트레이드오프 변경 시 | | `/gsd-config --profile <profile>` | 빠른 프로필 전환 | 비용/품질 트레이드오프 변경 시 |
| `/gsd-reapply-patches` | 업데이트 후 로컬 수정사항 복원 | 로컬 편집이 있는 상태에서 `/gsd-update` 이후 | | `/gsd-update --reapply` | 업데이트 후 로컬 수정사항 복원 | 로컬 편집이 있는 상태에서 `/gsd-update` 이후 |
### 코드 품질 및 리뷰 ### 코드 품질 및 리뷰
@@ -446,9 +445,9 @@ GSD는 LLM 시스템 프롬프트가 되는 마크다운 파일을 생성합니
| 명령어 | 목적 | 사용 시점 | | 명령어 | 목적 | 사용 시점 |
|--------|------|----------| |--------|------|----------|
| `/gsd-add-backlog <desc>` | 백로그 파킹 롯에 아이디어 추가 (999.x) | 활성 계획에 준비되지 않은 아이디어 | | `/gsd-capture --backlog <desc>` | 백로그 파킹 롯에 아이디어 추가 (999.x) | 활성 계획에 준비되지 않은 아이디어 |
| `/gsd-review-backlog` | 백로그 항목 승격/유지/제거 | 새 마일스톤 전 우선순위 결정 시 | | `/gsd-review-backlog` | 백로그 항목 승격/유지/제거 | 새 마일스톤 전 우선순위 결정 시 |
| `/gsd-plant-seed <idea>` | 트리거 조건이 있는 미래 지향적인 아이디어 | 미래 마일스톤에서 표면화되어야 할 아이디어 | | `/gsd-capture --seed <idea>` | 트리거 조건이 있는 미래 지향적인 아이디어 | 미래 마일스톤에서 표면화되어야 할 아이디어 |
| `/gsd-thread [name]` | 지속적인 컨텍스트 스레드 | 페이즈 구조 밖의 교차 세션 작업 | | `/gsd-thread [name]` | 지속적인 컨텍스트 스레드 | 페이즈 구조 밖의 교차 세션 작업 |
--- ---
@@ -642,7 +641,6 @@ claude --dangerously-skip-permissions
```bash ```bash
/gsd-audit-milestone # Check requirements coverage, detect stubs /gsd-audit-milestone # Check requirements coverage, detect stubs
/gsd-plan-milestone-gaps # If audit found gaps, create phases to close them
/gsd-complete-milestone # Archive, tag, done /gsd-complete-milestone # Archive, tag, done
``` ```
@@ -659,11 +657,11 @@ claude --dangerously-skip-permissions
### 마일스톤 중간 범위 변경 ### 마일스톤 중간 범위 변경
```bash ```bash
/gsd-add-phase # Append a new phase to the roadmap /gsd-phase # Append a new phase to the roadmap
# or # or
/gsd-insert-phase 3 # Insert urgent work between phases 3 and 4 /gsd-phase --insert 3 # Insert urgent work between phases 3 and 4
# or # or
/gsd-remove-phase 7 # Descope phase 7 and renumber /gsd-phase --remove 7 # Descope phase 7 and renumber
``` ```
### 멀티 프로젝트 워크스페이스 ### 멀티 프로젝트 워크스페이스
@@ -672,18 +670,18 @@ claude --dangerously-skip-permissions
```bash ```bash
# Create a workspace with repos from your monorepo # Create a workspace with repos from your monorepo
/gsd-new-workspace --name feature-b --repos hr-ui,ZeymoAPI /gsd-workspace --new --name feature-b --repos hr-ui,ZeymoAPI
# Feature branch isolation — worktree of current repo with its own .planning/ # Feature branch isolation — worktree of current repo with its own .planning/
/gsd-new-workspace --name feature-b --repos . /gsd-workspace --new --name feature-b --repos .
# Then cd into the workspace and initialize GSD # Then cd into the workspace and initialize GSD
cd ~/gsd-workspaces/feature-b cd ~/gsd-workspaces/feature-b
/gsd-new-project /gsd-new-project
# List and manage workspaces # List and manage workspaces
/gsd-list-workspaces /gsd-workspace --list
/gsd-remove-workspace feature-b /gsd-workspace --remove feature-b
``` ```
각 워크스페이스는 다음을 포함합니다. 각 워크스페이스는 다음을 포함합니다.
@@ -721,7 +719,7 @@ cd ~/gsd-workspaces/feature-b
### 모델 비용이 너무 높은 경우 ### 모델 비용이 너무 높은 경우
예산 프로필로 전환하세요: `/gsd-set-profile budget`. 도메인이 익숙하다면 (또는 Claude에게 익숙하다면) `/gsd-settings`에서 조사 및 plan-check 에이전트를 비활성화하세요. 예산 프로필로 전환하세요: `/gsd-config --profile budget`. 도메인이 익숙하다면 (또는 Claude에게 익숙하다면) `/gsd-settings`에서 조사 및 plan-check 에이전트를 비활성화하세요.
### 비Claude 런타임 사용 (Codex, OpenCode, Gemini CLI, Kilo) ### 비Claude 런타임 사용 (Codex, OpenCode, Gemini CLI, Kilo)
@@ -746,7 +744,7 @@ cd ~/gsd-workspaces/feature-b
### 비Anthropic 공급자와 함께 Claude Code 사용 (OpenRouter, 로컬) ### 비Anthropic 공급자와 함께 Claude Code 사용 (OpenRouter, 로컬)
GSD 서브에이전트가 Anthropic 모델을 호출하는데 OpenRouter나 로컬 공급자를 통해 비용을 지불하고 있다면 `inherit` 프로필로 전환하세요: `/gsd-set-profile inherit`. 이렇게 하면 모든 에이전트가 특정 Anthropic 모델 대신 현재 세션 모델을 사용합니다. `/gsd-settings` → Model Profile → Inherit도 참고하세요. GSD 서브에이전트가 Anthropic 모델을 호출하는데 OpenRouter나 로컬 공급자를 통해 비용을 지불하고 있다면 `inherit` 프로필로 전환하세요: `/gsd-config --profile inherit`. 이렇게 하면 모든 에이전트가 특정 Anthropic 모델 대신 현재 세션 모델을 사용합니다. `/gsd-settings` → Model Profile → Inherit도 참고하세요.
### 민감하거나 비공개 프로젝트에서 작업하는 경우 ### 민감하거나 비공개 프로젝트에서 작업하는 경우
@@ -754,7 +752,7 @@ GSD 서브에이전트가 Anthropic 모델을 호출하는데 OpenRouter나 로
### GSD 업데이트가 로컬 변경사항을 덮어쓴 경우 ### GSD 업데이트가 로컬 변경사항을 덮어쓴 경우
v1.17부터 설치 프로그램이 로컬로 수정된 파일을 `gsd-local-patches/`에 백업합니다. 변경사항을 다시 병합하려면 `/gsd-reapply-patches`를 실행하세요. v1.17부터 설치 프로그램이 로컬로 수정된 파일을 `gsd-local-patches/`에 백업합니다. 변경사항을 다시 병합하려면 `/gsd-update --reapply`를 실행하세요.
### 워크플로우 진단 (`/gsd-forensics`) ### 워크플로우 진단 (`/gsd-forensics`)
@@ -794,14 +792,13 @@ Windows에서 설치 프로그램이 `EPERM: operation not permitted, scandir`
|------|----------| |------|----------|
| 컨텍스트 손실 / 새 세션 | `/gsd-resume-work` 또는 `/gsd-progress` | | 컨텍스트 손실 / 새 세션 | `/gsd-resume-work` 또는 `/gsd-progress` |
| 페이즈가 잘못됨 | 페이즈 커밋에 `git revert` 후 재계획 | | 페이즈가 잘못됨 | 페이즈 커밋에 `git revert` 후 재계획 |
| 범위 변경 필요 | `/gsd-add-phase`, `/gsd-insert-phase`, 또는 `/gsd-remove-phase` | | 범위 변경 필요 | `/gsd-phase`, `/gsd-phase --insert`, 또는 `/gsd-phase --remove` |
| 마일스톤 감사에서 갭 발견 | `/gsd-plan-milestone-gaps` |
| 무언가 고장남 | `/gsd-debug "description"` | | 무언가 고장남 | `/gsd-debug "description"` |
| 워크플로우 상태 손상 의심 | `/gsd-forensics` | | 워크플로우 상태 손상 의심 | `/gsd-forensics` |
| 빠른 목표 수정 | `/gsd-quick` | | 빠른 목표 수정 | `/gsd-quick` |
| 계획이 비전과 맞지 않음 | `/gsd-discuss-phase [N]` 후 재계획 | | 계획이 비전과 맞지 않음 | `/gsd-discuss-phase [N]` 후 재계획 |
| 비용이 높아짐 | `/gsd-set-profile budget``/gsd-settings`에서 에이전트 비활성화 | | 비용이 높아짐 | `/gsd-config --profile budget``/gsd-settings`에서 에이전트 비활성화 |
| 업데이트가 로컬 변경사항 파괴 | `/gsd-reapply-patches` | | 업데이트가 로컬 변경사항 파괴 | `/gsd-update --reapply` |
| 이해관계자를 위한 세션 요약 필요 | `/gsd-session-report` | | 이해관계자를 위한 세션 요약 필요 | `/gsd-session-report` |
| 다음 단계를 모르겠음 | `/gsd-next` | | 다음 단계를 모르겠음 | `/gsd-next` |
| 병렬 실행 빌드 오류 | GSD 업데이트 또는 `parallelization.enabled: false` 설정 | | 병렬 실행 빌드 오류 | GSD 업데이트 또는 `parallelization.enabled: false` 설정 |

View File

@@ -59,4 +59,4 @@ The installer performs a clean wipe-and-replace of GSD-managed directories only:
- Your `CLAUDE.md` files - Your `CLAUDE.md` files
- Custom hooks - Custom hooks
Locally modified GSD files are automatically backed up to `gsd-local-patches/` before the install. Run `/gsd-reapply-patches` after updating to merge your modifications back in. Locally modified GSD files are automatically backed up to `gsd-local-patches/` before the install. Run `/gsd-update --reapply` after updating to merge your modifications back in.

View File

@@ -35,11 +35,10 @@ Para detalhes completos de flags avançadas e mudanças recentes, consulte tamb
| Comando | Finalidade | | Comando | Finalidade |
|---------|------------| |---------|------------|
| `/gsd-add-phase` | Adiciona fase no roadmap | | `/gsd-phase` | Adiciona fase no roadmap |
| `/gsd-insert-phase [N]` | Insere trabalho urgente entre fases | | `/gsd-phase --insert [N]` | Insere trabalho urgente entre fases |
| `/gsd-remove-phase [N]` | Remove fase futura e reenumera | | `/gsd-phase --remove [N]` | Remove fase futura e reenumera |
| `/gsd-list-phase-assumptions [N]` | Mostra abordagem assumida pelo Claude | | `/gsd-list-phase-assumptions [N]` | Mostra abordagem assumida pelo Claude |
| `/gsd-plan-milestone-gaps` | Cria fases para fechar lacunas de auditoria |
## Brownfield e Utilidades ## Brownfield e Utilidades
@@ -51,7 +50,7 @@ Para detalhes completos de flags avançadas e mudanças recentes, consulte tamb
| `/gsd-analyze-dependencies` | Detecta dependências entre fases e sugere `Depends on` no ROADMAP.md (v1.32) | | `/gsd-analyze-dependencies` | Detecta dependências entre fases e sugere `Depends on` no ROADMAP.md (v1.32) |
| `/gsd-forensics` | Diagnóstico de falhas no workflow | | `/gsd-forensics` | Diagnóstico de falhas no workflow |
| `/gsd-settings` | Configuração de agentes, perfil e toggles | | `/gsd-settings` | Configuração de agentes, perfil e toggles |
| `/gsd-set-profile <perfil>` | Troca rápida de perfil de modelo | | `/gsd-config --profile <perfil>` | Troca rápida de perfil de modelo |
## Qualidade de Código ## Qualidade de Código
@@ -65,9 +64,9 @@ Para detalhes completos de flags avançadas e mudanças recentes, consulte tamb
| Comando | Finalidade | | Comando | Finalidade |
|---------|------------| |---------|------------|
| `/gsd-add-backlog <desc>` | Adiciona item no backlog (999.x) | | `/gsd-capture --backlog <desc>` | Adiciona item no backlog (999.x) |
| `/gsd-review-backlog` | Promove, mantém ou remove itens | | `/gsd-review-backlog` | Promove, mantém ou remove itens |
| `/gsd-plant-seed <ideia>` | Registra ideia com gatilho futuro | | `/gsd-capture --seed <ideia>` | Registra ideia com gatilho futuro |
| `/gsd-thread [nome]` | Gerencia threads persistentes | | `/gsd-thread [nome]` | Gerencia threads persistentes |
## Gerenciamento de Estado ## Gerenciamento de Estado

View File

@@ -80,7 +80,7 @@ Esta versão resume os parâmetros principais em Português. Para schema complet
Troca rápida: Troca rápida:
```bash ```bash
/gsd-set-profile budget /gsd-config --profile budget
``` ```
## Novidades de configuração v1.31--v1.32 ## Novidades de configuração v1.31--v1.32

View File

@@ -20,7 +20,7 @@ Documentação abrangente do framework Get Shit Done (GSD) — um sistema de met
## Novidades v1.39 ## Novidades v1.39
Perfil de instalação `--minimal` (≥94% de redução no cold-start), `/gsd-edit-phase`, build & test gate pós-merge, `review.models.<cli>` para escolha de modelo de review por runtime, herança de configuração de workstream, workflow manual de canary release, consolidação de skills (86 → 59). Perfil de instalação `--minimal` (≥94% de redução no cold-start), `/gsd-phase --edit`, build & test gate pós-merge, `review.models.<cli>` para escolha de modelo de review por runtime, herança de configuração de workstream, workflow manual de canary release, consolidação de skills (86 → 59).
## Links rápidos ## Links rápidos

View File

@@ -92,8 +92,8 @@ Com `workflow.discuss_mode: "assumptions"`, o GSD analisa o código antes de per
Ideias fora da sequência ativa vão para backlog: Ideias fora da sequência ativa vão para backlog:
```bash ```bash
/gsd-add-backlog "Camada GraphQL" /gsd-capture --backlog "Camada GraphQL"
/gsd-add-backlog "Responsividade mobile" /gsd-capture --backlog "Responsividade mobile"
``` ```
Promover/revisar: Promover/revisar:
@@ -107,7 +107,7 @@ Promover/revisar:
Seeds guardam ideias futuras com condição de gatilho: Seeds guardam ideias futuras com condição de gatilho:
```bash ```bash
/gsd-plant-seed "Adicionar colaboração real-time quando infra de WebSocket estiver pronta" /gsd-capture --seed "Adicionar colaboração real-time quando infra de WebSocket estiver pronta"
``` ```
### Threads persistentes ### Threads persistentes
@@ -176,7 +176,7 @@ Para arquivos sensíveis, use deny list no Claude Code.
| `/gsd-debug [desc]` | Debug sistemático | | `/gsd-debug [desc]` | Debug sistemático |
| `/gsd-forensics` | Diagnóstico de workflow quebrado | | `/gsd-forensics` | Diagnóstico de workflow quebrado |
| `/gsd-settings` | Ajustar workflow/modelos | | `/gsd-settings` | Ajustar workflow/modelos |
| `/gsd-set-profile <profile>` | Troca rápida de perfil | | `/gsd-config --profile <profile>` | Troca rápida de perfil |
Para lista completa e flags avançadas, consulte [Command Reference](../COMMANDS.md). Para lista completa e flags avançadas, consulte [Command Reference](../COMMANDS.md).
@@ -251,7 +251,6 @@ claude --dangerously-skip-permissions
```bash ```bash
/gsd-audit-milestone /gsd-audit-milestone
/gsd-plan-milestone-gaps
/gsd-complete-milestone /gsd-complete-milestone
``` ```
@@ -280,7 +279,7 @@ Replaneje com escopo menor (tarefas menores por plano).
Use perfil budget: Use perfil budget:
```bash ```bash
/gsd-set-profile budget /gsd-config --profile budget
``` ```
### Runtime não-Claude (Codex/OpenCode/Gemini/Kilo) ### Runtime não-Claude (Codex/OpenCode/Gemini/Kilo)
@@ -295,10 +294,10 @@ Use `resolve_model_ids: "omit"` para deixar o runtime resolver modelos padrão.
|---------|---------| |---------|---------|
| Perdeu contexto | `/gsd-resume-work` ou `/gsd-progress` | | Perdeu contexto | `/gsd-resume-work` ou `/gsd-progress` |
| Fase deu errado | `git revert` + replanejar | | Fase deu errado | `git revert` + replanejar |
| Precisa alterar escopo | `/gsd-add-phase`, `/gsd-insert-phase`, `/gsd-remove-phase` | | Precisa alterar escopo | `/gsd-phase`, `/gsd-phase --insert`, `/gsd-phase --remove` |
| Bug em workflow | `/gsd-forensics` | | Bug em workflow | `/gsd-forensics` |
| Correção pontual | `/gsd-quick` | | Correção pontual | `/gsd-quick` |
| Custo alto | `/gsd-set-profile budget` | | Custo alto | `/gsd-config --profile budget` |
| Não sabe próximo passo | `/gsd-next` | | Não sabe próximo passo | `/gsd-next` |
--- ---

View File

@@ -511,11 +511,10 @@ lmn012o feat(08-02): 创建注册端点
| 命令 | 作用 | | 命令 | 作用 |
|---------|--------------| |---------|--------------|
| `/gsd-add-phase` | 向路线图追加阶段 | | `/gsd-phase` | 向路线图追加阶段 |
| `/gsd-insert-phase [N]` | 在阶段之间插入紧急工作 | | `/gsd-phase --insert [N]` | 在阶段之间插入紧急工作 |
| `/gsd-remove-phase [N]` | 删除未来阶段,重新编号 | | `/gsd-phase --remove [N]` | 删除未来阶段,重新编号 |
| `/gsd-list-phase-assumptions [N]` | 规划前查看 Claude 的预期方法 | | `/gsd-list-phase-assumptions [N]` | 规划前查看 Claude 的预期方法 |
| `/gsd-plan-milestone-gaps` | 创建阶段以填补审计发现的差距 |
| `/gsd-autonomous [--from N] [--to N] [--only N]` | 自主执行所有剩余阶段(`--to N` 执行到阶段 N 停止,`--only N` 只执行单个阶段) | | `/gsd-autonomous [--from N] [--to N] [--only N]` | 自主执行所有剩余阶段(`--to N` 执行到阶段 N 停止,`--only N` 只执行单个阶段) |
| `/gsd-analyze-dependencies` | 检测阶段间依赖关系并建议 ROADMAP.md 的 `Depends on` 条目 | | `/gsd-analyze-dependencies` | 检测阶段间依赖关系并建议 ROADMAP.md 的 `Depends on` 条目 |
@@ -531,9 +530,9 @@ lmn012o feat(08-02): 创建注册端点
| 命令 | 作用 | | 命令 | 作用 |
|---------|--------------| |---------|--------------|
| `/gsd-settings` | 配置模型配置文件和工作流代理 | | `/gsd-settings` | 配置模型配置文件和工作流代理 |
| `/gsd-set-profile <profile>` | 切换模型配置文件quality/balanced/budget | | `/gsd-config --profile <profile>` | 切换模型配置文件quality/balanced/budget/inherit |
| `/gsd-add-todo [desc]` | 捕获想法留待后用 | | `/gsd-capture [desc]` | 捕获想法留待后用 |
| `/gsd-check-todos` | 列出待处理事项 | | `/gsd-capture --list` | 列出待处理事项 |
| `/gsd-debug [desc] [--diagnose]` | 带持久状态的系统化调试(`--diagnose` 仅诊断不修复) | | `/gsd-debug [desc] [--diagnose]` | 带持久状态的系统化调试(`--diagnose` 仅诊断不修复) |
| `/gsd-quick [--full] [--discuss] [--research]` | 用 GSD 保证执行临时任务(`--full` 启用全部阶段,`--discuss` 先收集上下文,`--research` 规划前调查方法) | | `/gsd-quick [--full] [--discuss] [--research]` | 用 GSD 保证执行临时任务(`--full` 启用全部阶段,`--discuss` 先收集上下文,`--research` 规划前调查方法) |
| `/gsd-health [--repair]` | 验证 `.planning/` 目录完整性,用 `--repair` 自动修复 | | `/gsd-health [--repair]` | 验证 `.planning/` 目录完整性,用 `--repair` 自动修复 |
@@ -565,7 +564,7 @@ GSD 在 `.planning/config.json` 中存储项目设置。在 `/gsd-new-project`
切换配置: 切换配置:
``` ```
/gsd-set-profile budget /gsd-config --profile budget
``` ```
或通过 `/gsd-settings` 配置。 或通过 `/gsd-settings` 配置。

View File

@@ -205,12 +205,11 @@
| 命令 | 用途 | 何时使用 | | 命令 | 用途 | 何时使用 |
|---------|---------|-------------| |---------|---------|-------------|
| `/gsd-add-phase` | 向路线图追加新阶段 | 初始规划后范围增长 | | `/gsd-phase` | 向路线图追加新阶段 | 初始规划后范围增长 |
| `/gsd-insert-phase [N]` | 插入紧急工作(小数编号) | 里程碑中途紧急修复 | | `/gsd-phase --insert [N]` | 插入紧急工作(小数编号) | 里程碑中途紧急修复 |
| `/gsd-remove-phase [N]` | 删除未来阶段并重新编号 | 移除某个功能 | | `/gsd-phase --remove [N]` | 删除未来阶段并重新编号 | 移除某个功能 |
| `/gsd-list-phase-assumptions [N]` | 预览 Claude 的预期方法 | 规划前,验证方向 | | `/gsd-list-phase-assumptions [N]` | 预览 Claude 的预期方法 | 规划前,验证方向 |
| `/gsd-plan-milestone-gaps` | 为审计缺口创建阶段 | 审计发现缺失项后 | | `/gsd-plan-phase --research-phase [N]` | 仅深度生态研究 | 复杂或不熟悉的领域 |
| `/gsd-research-phase [N]` | 仅深度生态研究 | 复杂或不熟悉的领域 |
| `/gsd-autonomous [--from N] [--to N] [--only N]` | 自主执行剩余阶段(`--to N` 到阶段 N 停止) | 批量自动处理 | | `/gsd-autonomous [--from N] [--to N] [--only N]` | 自主执行剩余阶段(`--to N` 到阶段 N 停止) | 批量自动处理 |
| `/gsd-analyze-dependencies` | 检测阶段间依赖关系 | `/gsd-manager` 前分析 | | `/gsd-analyze-dependencies` | 检测阶段间依赖关系 | `/gsd-manager` 前分析 |
@@ -230,11 +229,11 @@
| `/gsd-map-codebase` | 分析现有代码库 | 在现有代码上运行 `/gsd-new-project` 之前 | | `/gsd-map-codebase` | 分析现有代码库 | 在现有代码上运行 `/gsd-new-project` 之前 |
| `/gsd-quick` | 带 GSD 保证的临时任务 | Bug 修复、小功能、配置更改 | | `/gsd-quick` | 带 GSD 保证的临时任务 | Bug 修复、小功能、配置更改 |
| `/gsd-debug [desc] [--diagnose]` | 带持久状态的系统化调试(`--diagnose` 仅诊断) | 出问题时 | | `/gsd-debug [desc] [--diagnose]` | 带持久状态的系统化调试(`--diagnose` 仅诊断) | 出问题时 |
| `/gsd-add-todo [desc]` | 捕获想法留待后用 | 会话期间想到什么 | | `/gsd-capture [desc]` | 捕获想法留待后用 | 会话期间想到什么 |
| `/gsd-check-todos` | 列出待处理事项 | 查看捕获的想法 | | `/gsd-capture --list` | 列出待处理事项 | 查看捕获的想法 |
| `/gsd-settings` | 配置工作流开关和模型配置 | 更改模型、切换代理 | | `/gsd-settings` | 配置工作流开关和模型配置 | 更改模型、切换代理 |
| `/gsd-set-profile <profile>` | 快速切换配置 | 更改成本/质量权衡 | | `/gsd-config --profile <profile>` | 快速切换配置 | 更改成本/质量权衡 |
| `/gsd-reapply-patches` | 更新后恢复本地修改 | 如果你有本地编辑,在 `/gsd-update` 后 | | `/gsd-update --reapply` | 更新后恢复本地修改 | 如果你有本地编辑,在 `/gsd-update` 后 |
--- ---
@@ -390,7 +389,6 @@ claude --dangerously-skip-permissions
```bash ```bash
/gsd-audit-milestone # 检查需求覆盖率,检测存根 /gsd-audit-milestone # 检查需求覆盖率,检测存根
/gsd-plan-milestone-gaps # 如果审计发现缺口,创建阶段来填补
/gsd-complete-milestone # 归档,标记,完成 /gsd-complete-milestone # 归档,标记,完成
``` ```
@@ -405,11 +403,11 @@ claude --dangerously-skip-permissions
### 里程碑中途范围变更 ### 里程碑中途范围变更
```bash ```bash
/gsd-add-phase # 向路线图追加新阶段 /gsd-phase # 向路线图追加新阶段
# 或 # 或
/gsd-insert-phase 3 # 在阶段 3 和 4 之间插入紧急工作 /gsd-phase --insert 3 # 在阶段 3 和 4 之间插入紧急工作
# 或 # 或
/gsd-remove-phase 7 # 移除阶段 7 并重新编号 /gsd-phase --remove 7 # 移除阶段 7 并重新编号
``` ```
--- ---
@@ -458,7 +456,7 @@ node gsd-tools.cjs state sync # 从磁盘重建 STATE.md
### 模型成本太高 ### 模型成本太高
切换到 budget 配置:`/gsd-set-profile budget`。如果领域对你(或 Claude熟悉通过 `/gsd-settings` 禁用研究和计划检查代理。 切换到 budget 配置:`/gsd-config --profile budget`。如果领域对你(或 Claude熟悉通过 `/gsd-settings` 禁用研究和计划检查代理。
### 处理敏感/私有项目 ### 处理敏感/私有项目
@@ -466,7 +464,7 @@ node gsd-tools.cjs state sync # 从磁盘重建 STATE.md
### GSD 更新覆盖了我的本地更改 ### GSD 更新覆盖了我的本地更改
从 v1.17 开始,安装程序将本地修改的文件备份到 `gsd-local-patches/`。运行 `/gsd-reapply-patches` 将你的更改合并回来。 从 v1.17 开始,安装程序将本地修改的文件备份到 `gsd-local-patches/`。运行 `/gsd-update --reapply` 将你的更改合并回来。
### 子代理似乎失败但工作已完成 ### 子代理似乎失败但工作已完成
@@ -480,14 +478,13 @@ node gsd-tools.cjs state sync # 从磁盘重建 STATE.md
|---------|----------| |---------|----------|
| 丢失上下文 / 新会话 | `/gsd-resume-work``/gsd-progress` | | 丢失上下文 / 新会话 | `/gsd-resume-work``/gsd-progress` |
| 阶段出错 | `git revert` 阶段提交,然后重新规划 | | 阶段出错 | `git revert` 阶段提交,然后重新规划 |
| 需要更改范围 | `/gsd-add-phase``/gsd-insert-phase``/gsd-remove-phase` | | 需要更改范围 | `/gsd-phase``/gsd-phase --insert``/gsd-phase --remove` |
| 里程碑审计发现缺口 | `/gsd-plan-milestone-gaps` |
| 出问题了 | `/gsd-debug "描述"` | | 出问题了 | `/gsd-debug "描述"` |
| STATE.md 不同步 | `state validate` 然后 `state sync` | | STATE.md 不同步 | `state validate` 然后 `state sync` |
| 快速针对性修复 | `/gsd-quick` | | 快速针对性修复 | `/gsd-quick` |
| 计划与你的愿景不符 | `/gsd-discuss-phase [N]` 然后重新规划 | | 计划与你的愿景不符 | `/gsd-discuss-phase [N]` 然后重新规划 |
| 成本过高 | `/gsd-set-profile budget``/gsd-settings` 关闭代理 | | 成本过高 | `/gsd-config --profile budget``/gsd-settings` 关闭代理 |
| 更新破坏了本地更改 | `/gsd-reapply-patches` | | 更新破坏了本地更改 | `/gsd-update --reapply` |
--- ---

View File

@@ -99,7 +99,7 @@
**也可选:** **也可选:**
- `/gsd-discuss-phase 2` — 先收集上下文 - `/gsd-discuss-phase 2` — 先收集上下文
- `/gsd-research-phase 2` — 调查未知项 - `/gsd-plan-phase --research-phase 2` — 调查未知项
- 审查路线图 - 审查路线图
--- ---
@@ -128,7 +128,7 @@
**也可选:** **也可选:**
- `/gsd-discuss-phase 3` — 先收集上下文 - `/gsd-discuss-phase 3` — 先收集上下文
- `/gsd-research-phase 3` — 调查未知项 - `/gsd-plan-phase --research-phase 3` — 调查未知项
- 回顾阶段 2 构建的内容 - 回顾阶段 2 构建的内容
--- ---
@@ -149,7 +149,7 @@
**先讨论上下文:** `/gsd-discuss-phase 3` **先讨论上下文:** `/gsd-discuss-phase 3`
**研究未知项:** `/gsd-research-phase 3` **研究未知项:** `/gsd-plan-phase --research-phase 3`
<sub>`/clear` 优先 → 全新上下文窗口</sub> <sub>`/clear` 优先 → 全新上下文窗口</sub>

View File

@@ -0,0 +1,99 @@
#!/usr/bin/env node
'use strict';
/**
* Deterministic latest-version check for /gsd-update (#2992).
*
* The /gsd-update workflow's check_latest_version step was previously
* prescribed in LLM-driven prose ("run `npm view get-shit-done-cc
* version`"). The executing model could shortcut the prescription and
* invent npm queries against wrong-shaped names (`@get-shit-done/cli`,
* `get-shit-done-cli`, `gsd`), all of which 404 or — worse — return an
* unrelated typosquat package.
*
* This script makes the package name a CONSTANT in code, not a free
* choice at execution time. The workflow calls it via `npm run
* check-latest-version -- --json` and parses the structured response.
*
* Tests assert on the typed CHECK_REASON enum and the structured result
* record, never on console prose. See CONTRIBUTING.md "Prohibited: Raw
* Text Matching on Test Outputs".
*/
const cp = require('node:child_process');
// Hardcoded. Do not parameterise — the whole point of this script is that
// the package name is not a runtime choice for the caller.
const PACKAGE_NAME = 'get-shit-done-cc';
const CHECK_REASON = Object.freeze({
OK: 'ok',
FAIL_NPM_FAILED: 'fail_npm_failed',
FAIL_INVALID_OUTPUT: 'fail_invalid_output',
});
const SEMVER_RE = /^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$/;
/**
* Pure-ish: takes an injected spawn function so tests don't actually run npm.
* In production, defaults to cp.spawnSync('npm', ...).
*/
function checkLatestVersion(opts = {}) {
const defaultSpawn = () => cp.spawnSync('npm', ['view', PACKAGE_NAME, 'version'], {
encoding: 'utf8',
stdio: ['ignore', 'pipe', 'pipe'],
shell: process.platform === 'win32', // npm is npm.cmd on Windows
// Bound the registry call so a hung network/registry doesn't block the
// entire /gsd-update workflow indefinitely (#2993 CR). 15s is generous
// for `npm view <pkg> version`; on timeout, spawnSync returns with
// signal !== null and the existing failure path emits FAIL_NPM_FAILED.
timeout: 15_000,
});
const spawn = opts.spawn || defaultSpawn;
const r = spawn();
if (!r || r.status !== 0) {
// Distinguish timeout (status null, signal set, stderr empty) from a
// genuine npm failure. Without this, both surfaced as "npm exited
// non-zero" and the operator couldn't tell which (#2993 CR).
let detail;
if (r && r.signal) {
detail = `npm timed out (signal: ${r.signal})`;
} else if (r && r.stderr) {
detail = r.stderr.trim();
} else {
detail = 'npm exited non-zero';
}
return {
ok: false,
reason: CHECK_REASON.FAIL_NPM_FAILED,
detail,
};
}
const version = (r.stdout || '').trim();
if (!SEMVER_RE.test(version)) {
return {
ok: false,
reason: CHECK_REASON.FAIL_INVALID_OUTPUT,
detail: version || '(empty)',
};
}
return { ok: true, version, reason: CHECK_REASON.OK };
}
function main() {
const json = process.argv.includes('--json');
const r = checkLatestVersion();
if (json) {
process.stdout.write(JSON.stringify(r) + '\n');
} else if (r.ok) {
process.stdout.write(r.version + '\n');
} else {
process.stderr.write(`check-latest-version: ${r.reason}: ${r.detail}\n`);
}
process.exit(r.ok ? 0 : 1);
}
if (require.main === module) main();
module.exports = { checkLatestVersion, CHECK_REASON, PACKAGE_NAME };

View File

@@ -305,6 +305,18 @@ async function main() {
const raw = rawIndex !== -1; const raw = rawIndex !== -1;
if (rawIndex !== -1) args.splice(rawIndex, 1); if (rawIndex !== -1) args.splice(rawIndex, 1);
// --json-errors: when present, error() emits structured JSON to stderr
// ({ ok: false, reason: <ERROR_REASON code>, message }) instead of plain
// "Error: <text>". Lets test suites assert on typed reason codes per the
// CONTRIBUTING.md "Prohibited: Raw Text Matching on Test Outputs" rule
// (#2974). Default off — human operators see the original plain-text
// diagnostic.
const jsonErrorsIdx = args.indexOf('--json-errors');
if (jsonErrorsIdx !== -1) {
core.setJsonErrorMode(true);
args.splice(jsonErrorsIdx, 1);
}
// --pick <name>: extract a single field from JSON output (replaces jq dependency). // --pick <name>: extract a single field from JSON output (replaces jq dependency).
// Supports dot-notation (e.g., --pick workflow.research) and bracket notation // Supports dot-notation (e.g., --pick workflow.research) and bracket notation
// for arrays (e.g., --pick directories[-1]). // for arrays (e.g., --pick directories[-1]).
@@ -329,17 +341,50 @@ async function main() {
const command = args[0]; const command = args[0];
// Top-level usage string — emitted by `gsd-tools` (no args) and by
// `gsd-tools --help` / any `--help` request below.
// CR feedback: the command list must enumerate every top-level command
// supported by the dispatcher so `--help` is actually useful for
// discovery; previously it was a partial subset that didn't include
// phase / roadmap / milestone / progress / etc.
const TOP_LEVEL_USAGE = 'Usage: gsd-tools <command> [args] [--raw] [--pick <field>] [--cwd <path>] [--ws <name>]\n' +
'Commands: agent-skills, audit-open, audit-uat, check-commit, commit, commit-to-subrepo, ' +
'config-ensure-section, config-get, config-new-project, config-path, config-set, ' +
'current-timestamp, detect-custom-files, docs-init, extract-messages, find-phase, ' +
'from-gsd2, frontmatter, gap-analysis, generate-claude-md, generate-claude-profile, ' +
'generate-dev-preferences, generate-slug, graphify, history-digest, init, intel, ' +
'learnings, list-todos, milestone, phase, phase-plan-index, phases, profile-questionnaire, ' +
'profile-sample, progress, requirements, resolve-model, roadmap, scaffold, state, ' +
'template, validate, verify, verify-path-exists, verify-summary, workstream\n\n' +
'For command-specific argument requirements, invoke the command without args ' +
'(e.g. `gsd-tools phase add`) — the resulting error lists what is required.';
if (!command) { if (!command) {
error('Usage: gsd-tools <command> [args] [--raw] [--pick <field>] [--cwd <path>] [--ws <name>]\nCommands: state, resolve-model, find-phase, commit, verify-summary, verify, frontmatter, template, generate-slug, current-timestamp, list-todos, verify-path-exists, config-ensure-section, config-new-project, init, workstream, docs-init'); error(TOP_LEVEL_USAGE);
} }
// Reject flags that are never valid for any gsd-tools command. AI agents // #3019: a `--help` / `-h` flag in argv must render the top-level usage
// sometimes hallucinate --help or --version on tool invocations; silently // and exit 0 — not error out with "Unknown flag". The previous shape
// ignoring them can cause destructive operations to proceed unchecked. // erred on agent-hallucinated flags, but it also blocked humans from
const NEVER_VALID_FLAGS = new Set(['-h', '--help', '-?', '--h', '--version', '-v', '--usage']); // discovering the command surface via subcommand help requests routed
// here from the SDK CLI's query dispatcher (after the cli.ts fix that
// stops harvesting --help as a global flag). Rendering top-level usage
// on --help is strictly better UX than the old short-circuit, which
// printed the SDK-level usage that doesn't mention any of these
// subcommands.
const HELP_FLAGS = new Set(['-h', '--help', '-?', '--h', '--usage']);
if (args.some((a) => HELP_FLAGS.has(a))) {
process.stdout.write(TOP_LEVEL_USAGE + '\n');
return;
}
// Reject version flags. AI agents sometimes hallucinate --version on tool
// invocations; silently ignoring it can cause destructive operations to
// proceed unchecked. (Help flags are handled above.)
const NEVER_VALID_FLAGS = new Set(['--version', '-v']);
for (const arg of args) { for (const arg of args) {
if (NEVER_VALID_FLAGS.has(arg)) { if (NEVER_VALID_FLAGS.has(arg)) {
error(`Unknown flag: ${arg}\ngsd-tools does not accept help or version flags. Run "gsd-tools" with no arguments for usage.`); error(`Unknown flag: ${arg}\ngsd-tools does not accept version flags. Run "gsd-tools" with no arguments for usage.`);
} }
} }

View File

@@ -84,6 +84,17 @@ const DYNAMIC_KEY_PATTERNS = [
// <runtime> is a free string (so users can map non-built-in runtimes); <tier> is enum-restricted. // <runtime> is a free string (so users can map non-built-in runtimes); <tier> is enum-restricted.
{ topLevel: 'model_profile_overrides', test: (k) => /^model_profile_overrides\.[a-zA-Z0-9_-]+\.(opus|sonnet|haiku)$/.test(k), { topLevel: 'model_profile_overrides', test: (k) => /^model_profile_overrides\.[a-zA-Z0-9_-]+\.(opus|sonnet|haiku)$/.test(k),
description: 'model_profile_overrides.<runtime>.<opus|sonnet|haiku>' }, description: 'model_profile_overrides.<runtime>.<opus|sonnet|haiku>' },
// #3023 — per-phase-type model map: models.<phase_type> = <tier>
// Six named slots (planning/discuss/research/execution/verification/completion);
// unknown phase-types are rejected. Per-agent model_overrides still take
// precedence over phase-type at resolve time.
{ topLevel: 'models', test: (k) => /^models\.(planning|discuss|research|execution|verification|completion)$/.test(k),
description: 'models.<planning|discuss|research|execution|verification|completion>' },
// #3024 — dynamic routing block. Three top-level scalar settings
// plus a tier_models sub-block keyed by light/standard/heavy.
{ topLevel: 'dynamic_routing',
test: (k) => /^dynamic_routing\.(enabled|escalate_on_failure|max_escalations|tier_models\.(light|standard|heavy))$/.test(k),
description: 'dynamic_routing.<enabled|escalate_on_failure|max_escalations|tier_models.<light|standard|heavy>>' },
]; ];
/** /**

View File

@@ -4,7 +4,7 @@
const fs = require('fs'); const fs = require('fs');
const path = require('path'); const path = require('path');
const { output, error, CONFIG_DEFAULTS, atomicWriteFileSync } = require('./core.cjs'); const { output, error, ERROR_REASON, CONFIG_DEFAULTS, atomicWriteFileSync } = require('./core.cjs');
const { planningDir, withPlanningLock } = require('./planning-workspace.cjs'); const { planningDir, withPlanningLock } = require('./planning-workspace.cjs');
const { const {
VALID_PROFILES, VALID_PROFILES,
@@ -33,7 +33,7 @@ const CONFIG_KEY_SUGGESTIONS = {
function validateKnownConfigKeyPath(keyPath) { function validateKnownConfigKeyPath(keyPath) {
const suggested = CONFIG_KEY_SUGGESTIONS[keyPath]; const suggested = CONFIG_KEY_SUGGESTIONS[keyPath];
if (suggested) { if (suggested) {
error(`Unknown config key: ${keyPath}. Did you mean ${suggested}?`); error(`Unknown config key: ${keyPath}. Did you mean ${suggested}?`, ERROR_REASON.CONFIG_INVALID_KEY);
} }
} }
@@ -278,7 +278,7 @@ function setConfigValue(cwd, keyPath, parsedValue) {
config = JSON.parse(fs.readFileSync(configPath, 'utf-8')); config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
} }
} catch (err) { } catch (err) {
error('Failed to read config.json: ' + err.message); error('Failed to read config.json: ' + err.message, ERROR_REASON.CONFIG_PARSE_FAILED);
} }
// Set nested value using dot notation (e.g., "workflow.research") // Set nested value using dot notation (e.g., "workflow.research")
@@ -319,7 +319,7 @@ function cmdConfigSet(cwd, keyPath, value, raw) {
validateKnownConfigKeyPath(keyPath); validateKnownConfigKeyPath(keyPath);
if (!isValidConfigKey(keyPath)) { if (!isValidConfigKey(keyPath)) {
error(`Unknown config key: "${keyPath}". Valid keys: ${[...VALID_CONFIG_KEYS].sort().join(', ')}, agent_skills.<agent-type>, features.<feature_name>`); error(`Unknown config key: "${keyPath}". Valid keys: ${[...VALID_CONFIG_KEYS].sort().join(', ')}, agent_skills.<agent-type>, features.<feature_name>`, ERROR_REASON.CONFIG_INVALID_KEY);
} }
// Parse value (handle booleans, numbers, and JSON arrays/objects) // Parse value (handle booleans, numbers, and JSON arrays/objects)
@@ -402,11 +402,11 @@ function cmdConfigGet(cwd, keyPath, raw, defaultValue) {
output(defaultValue, raw, String(defaultValue)); output(defaultValue, raw, String(defaultValue));
return; return;
} else { } else {
error('No config.json found at ' + configPath); error('No config.json found at ' + configPath, ERROR_REASON.CONFIG_NO_FILE);
} }
} catch (err) { } catch (err) {
if (err.message.startsWith('No config.json')) throw err; if (err.message.startsWith('No config.json')) throw err;
error('Failed to read config.json: ' + err.message); error('Failed to read config.json: ' + err.message, ERROR_REASON.CONFIG_PARSE_FAILED);
} }
// Traverse dot-notation path (e.g., "workflow.auto_advance") // Traverse dot-notation path (e.g., "workflow.auto_advance")
@@ -420,7 +420,7 @@ function cmdConfigGet(cwd, keyPath, raw, defaultValue) {
output(def, raw, String(def)); output(def, raw, String(def));
return; return;
} }
error(`Key not found: ${keyPath}`); error(`Key not found: ${keyPath}`, ERROR_REASON.CONFIG_KEY_NOT_FOUND);
} }
current = current[key]; current = current[key];
} }
@@ -432,7 +432,7 @@ function cmdConfigGet(cwd, keyPath, raw, defaultValue) {
output(def, raw, String(def)); output(def, raw, String(def));
return; return;
} }
error(`Key not found: ${keyPath}`); error(`Key not found: ${keyPath}`, ERROR_REASON.CONFIG_KEY_NOT_FOUND);
} }
// Never echo plaintext for sensitive keys via config-get. Plaintext lives // Never echo plaintext for sensitive keys via config-get. Plaintext lives

Some files were not shown because too many files have changed in this diff Show More