diff --git a/.changeset/1143-claude-orchestration-capability.md b/.changeset/1143-claude-orchestration-capability.md deleted file mode 100644 index d87aae625..000000000 --- a/.changeset/1143-claude-orchestration-capability.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Added -pr: 2044 ---- -**A default-off, BETA, claude-only "Claude orchestration" capability** — adopts Claude Code's Workflow tool (`/effort ultracode`, Agent SDK ≥ v0.3.149) as an optional parallel-execution backend for the GSD loop, restoring the wave parallelism + plan-checker + verifier that the #853 backgrounded-agent nesting limitation forces inline on Claude Code, and folding the existing `gsd-ultraplan-phase` plan-offload under the same runtime gate. When `claude_orchestration.enabled` is on AND the runtime is Claude AND the Workflow tool is detected AND the Agent SDK meets the floor (`claude_orchestration.min_agent_sdk_version`, default `0.3.149`), `execute-phase` emits a generated Workflow script (`waves → parallel() barriers`, `plans → agent({ agentType: 'gsd-executor', isolation: 'worktree' })`, `files_modified overlap → separate sequential stages`, `resumeFromRunId` wired to the phase run id, shared `budget` pool) that composes the SAME executor agent + worktree isolation the inline path uses, so artifacts/commits are produced identically. Detection is pure and fail-closed (any miss → inline), so on any runtime lacking the Workflow tool behaviour is byte-identical to today. Adds a pure module `gsd-core/bin/lib/claude-orchestration.cjs` (`detectWorkflowBackend`, `emitWorkflowScript`), the `capabilities/claude-orchestration/` declaration with two gated loop contributions (`execute:wave:post`, `plan:post`) and a `claude-orchestration` command family (`gsd-tools claude-orchestration detect-backend|emit-workflow`), federated config keys, and an ADR-1143 implementation amendment. (#1143) diff --git a/.changeset/1528-verify-work-security-blocked-next-phase.md b/.changeset/1528-verify-work-security-blocked-next-phase.md deleted file mode 100644 index 2525e0ef4..000000000 --- a/.changeset/1528-verify-work-security-blocked-next-phase.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 1687 ---- -The `verify-work` security-blocked presentation no longer offers next-phase planning. When security enforcement blocks phase advancement (no `SECURITY.md` produced), the workflow now routes only to the current-phase fix instead of competing `/gsd:plan-phase {next}` and `/gsd:execute-phase {next}` options. diff --git a/.changeset/1562-api-coverage-gate.md b/.changeset/1562-api-coverage-gate.md deleted file mode 100644 index 9abfb1f52..000000000 --- a/.changeset/1562-api-coverage-gate.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Added -pr: 2065 ---- -**Phases that integrate an external API/SDK/service can no longer seal without a decided coverage matrix** — a new `api-coverage` gate on the `ai-integration` capability blocks `/gsd:verify-work` until the phase produces a `COVERAGE.md` enumerating the API's full capability surface, with every non-integrated capability an explicit, reasoned opt-out. Full coverage is the default; the matrix is the subtraction record, so "we integrated the API" can no longer silently mean "we integrated whatever the first use case exercised." Toggleable via `workflow.api_coverage_gate` (on by default). (#1562) diff --git a/.changeset/1580-999-sentinel-milestone-roadmap.md b/.changeset/1580-999-sentinel-milestone-roadmap.md deleted file mode 100644 index 2ddf49e5f..000000000 --- a/.changeset/1580-999-sentinel-milestone-roadmap.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 1691 ---- -`milestone complete` and `roadmap analyze` now exclude the Phase 0 / Phase 999 backlog sentinels. A milestone whose only directory-less ROADMAP heading is a backlog sentinel can be completed without `--force`, and `roadmap analyze` no longer counts the sentinel in `phase_count` or routes `next_phase` into it. Completes the `^999` exclusion #1445 added to the progress denominators. diff --git a/.changeset/1581-config-set-coercion.md b/.changeset/1581-config-set-coercion.md deleted file mode 100644 index f035d15b2..000000000 --- a/.changeset/1581-config-set-coercion.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2023 ---- -**`config-set` no longer silently coerces values into something the disk never sees** — `Number.isFinite` replaced `!isNaN` in the value parser so `Infinity`/`-Infinity` are no longer coerced to non-finite numbers that `JSON.stringify` then renders as `null` on disk while the CLI echoes `Infinity` (output ≠ disk). `context_window` now has a per-key validator requiring a finite positive integer (rejects `Infinity`, `0`, negatives, non-integers with a non-zero exit), and `project_code` is always persisted as a string so a leading-zero code like `007` survives verbatim instead of collapsing to `7`. Numeric coercion for genuine numeric keys (e.g. `granularity 42`) is unchanged. (#1581) diff --git a/.changeset/1591-phase-complete-details-wrapped-checklist.md b/.changeset/1591-phase-complete-details-wrapped-checklist.md deleted file mode 100644 index 1c2ef3625..000000000 --- a/.changeset/1591-phase-complete-details-wrapped-checklist.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -type: Fixed -pr: 1819 ---- -**`phase.complete` no longer reports a false `is_last_phase` on a `
`-wrapped checkbox checklist (#1591, #1752)** — when the active milestone's phase checklist was written as `- [ ] Phase N:` checkbox items inside a `
` block and the next phase had no directory on disk yet (still in planning), `phase.complete`'s `isLastPhase` roadmap-enumeration fallback used a heading-only pattern (`/#{2,4}\s*Phase…/`) that never matched checkbox items. It returned `is_last_phase: true, next_phase: null` on a mid-milestone phase and — via the milestone-complete cascade — wrongly flipped STATE.md to `Milestone complete` and decremented `progress.total_phases` (e.g. 8 → 7). The pattern now matches heading-style (`### Phase N:`), plain checkbox-list phases (`- [ ] Phase N:` / `- [x] Phase N:`), and the canonical **bold** checklist form the roadmap template emits (`- [ ] **Phase N: Name**`); `extractCurrentMilestone` already surfaces the `
`-wrapped checklist correctly, so no parser change was needed. Only the reproduced `phase.complete` fallback is changed; the heading-only sibling patterns elsewhere in `phase.cts` are untouched. - diff --git a/.changeset/1682-opencode-mcp-binding.md b/.changeset/1682-opencode-mcp-binding.md deleted file mode 100644 index 4b71a79c5..000000000 --- a/.changeset/1682-opencode-mcp-binding.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -type: Added -pr: 1929 ---- - -**OpenCode installs now auto-register the GSD companion MCP server (`mcp.gsd`)** — `--opencode` install writes a `mcp.gsd` entry (local stdio → `gsd-mcp-server`) into `opencode.json`, so OpenCode drives GSD's command + planning-state surface over MCP with no bespoke plugin (ADR-1239 Phase D / #1682). Idempotent and non-clobbering; a user-defined `mcp.gsd` is preserved. (#1682) diff --git a/.changeset/1682-opencode-subset-dialect.md b/.changeset/1682-opencode-subset-dialect.md deleted file mode 100644 index ef9e18138..000000000 --- a/.changeset/1682-opencode-subset-dialect.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -type: Added -pr: 1930 ---- - -**OpenCode plugin handles `session.idle` + the `opencode-subset` hook dialect is implemented** — the GSD OpenCode plugin now recognizes `session.idle` (↔ Claude `Stop` lifecycle point), completing the compaction/idle pair (#1914 shipped compaction). The reserved `opencode-subset` dialect gains a consumer — `hookEventSurfaceFor()` in `host-integration.cts` — describing OpenCode's session/tool/file event subset (no workflow-phase events; the engine owns phase sequencing, ADR-1239 §OpenCode binding). Adds a Claude-parity test asserting the plugin covers the full declared subset. (#1682) diff --git a/.changeset/1688-stale-bake-guard.md b/.changeset/1688-stale-bake-guard.md deleted file mode 100644 index 63e5af983..000000000 --- a/.changeset/1688-stale-bake-guard.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Added -pr: 1692 ---- -**GSD now warns when model config changed without re-running the installer on static-frontmatter runtimes** — on `codex` and `opencode`, editing `model_overrides` or `model_profile_overrides` or `model_policy.runtime_tiers` in `.planning/config.json` or `~/.gsd/defaults.json` previously had no effect until the user re-ran `gsd install `, and the failure was silent: the sub-agent kept using the base model. Workflow entry points like `gsd-tools init *` now emit a one-line stderr warning naming the changed config file and the exact remediation command when they detect the config is newer than the baked agent files. The guard is read-only and warning-only by default, dedup'd per session, and skipped entirely on Claude Code because Claude Code resolves models at spawn time. Resolves #1688 as the structural follow-up to #1650. diff --git a/.changeset/1733-windows-agent-skills-path-leak.md b/.changeset/1733-windows-agent-skills-path-leak.md deleted file mode 100644 index 6c40bb8bc..000000000 --- a/.changeset/1733-windows-agent-skills-path-leak.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 1736 ---- -The `` block emitted by `gsd init` no longer leaks backslash paths into `@`-reference skill paths on Windows. The global skill directory (a native `path.join` result) was interpolated into the generated markdown without POSIX normalization, producing references like `@C:\…\skills\name/SKILL.md`; the reference is now normalized at the emit site so skill references use forward slashes on every platform. diff --git a/.changeset/1747-new-project-search-provider-keys.md b/.changeset/1747-new-project-search-provider-keys.md deleted file mode 100644 index 08f8fdbe0..000000000 --- a/.changeset/1747-new-project-search-provider-keys.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 1814 ---- -**`/gsd-settings` no longer warns about four search-provider keys on fresh projects (#1747)** — `buildNewProjectConfig` emits seven search-provider availability flags and `research-provider.cts` `providerAvailability()` consumes all seven, but only three were registered in `VALID_CONFIG_KEYS` (`config-schema.manifest.json`). Running `/gsd-settings` on a freshly generated `.planning/config.json` printed `unknown config key(s) … tavily_search, ref_search, perplexity, jina — these will be ignored` even though the user never hand-edited the config. The four missing keys are now registered alongside `brave_search`/`firecrawl`/`exa_search` and documented in `docs/CONFIGURATION.md`; a drift guard in `tests/bug-2530-valid-config-keys.test.cjs` now requires every config-driven research-provider flag to be in the schema, so a future provider addition cannot reintroduce the drift. diff --git a/.changeset/1761-state-json-unbounded-milestone-read-path.md b/.changeset/1761-state-json-unbounded-milestone-read-path.md deleted file mode 100644 index bd1c4f043..000000000 --- a/.changeset/1761-state-json-unbounded-milestone-read-path.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 1818 ---- -**`gsd-tools state json` no longer reports conflated progress for an unversioned milestone (#1761)** — the ADR-1769 Phase 7 fix (#1794) taught `state sync` to leave Progress untouched when a milestone version is asserted but the ROADMAP has no versioned heading for it, but the `state json` **read** path still rebuilt progress via `buildStateFrontmatter`, whose phase-heading count fell back to the whole document and summed sibling milestones. `state json` therefore reported a conflated `total_phases` (e.g. 8 = 4+4 across two milestones) plus a derived `percent`, contradicting the sync guard on the very same project. The read path now mirrors the sync guard: when the asserted milestone cannot be bounded to a versioned ROADMAP heading, `total_phases` falls back to the on-disk phase-dir count and `percent` is omitted. Bounded milestones (versioned ROADMAP, or no milestone asserted) are unchanged; the signal rides on the existing `_diskScanCache` so `extractCurrentMilestone`'s return contract and its other callers are untouched. diff --git a/.changeset/1772-graphify-update-multi-line-command.md b/.changeset/1772-graphify-update-multi-line-command.md deleted file mode 100644 index 7e188785c..000000000 --- a/.changeset/1772-graphify-update-multi-line-command.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 1815 ---- -**`gsd-graphify-update.sh` now reads the full multi-line command in Gate 2 (#1772)** — the PostToolUse auto-update hook joined `tool_name` + `\n` + `tool_input.command` and extracted the command with `sed -n '2p'` (line 2 only). Agent runtimes (Claude Code's Bash tool among them) routinely emit HEAD-advancing commits as multi-line scripts (`cd /path`, then `git add`, then `git commit …`), so line 2 was the `cd`, Gate 2's `*"git commit"*` match failed, and the rebuild silently no-op'd on real commits even with `graphify.auto_update: true`. The failure was invisible in manual probes because a single-line `git commit -m x` passes line 2 verbatim. The hook now captures line 2 through EOF (`sed -n '2,$p'`) so the `case` glob sees the full command string; single-line behavior is unchanged and multi-line commands without a HEAD-advancing op still no-op cleanly. diff --git a/.changeset/1778-thread-workflow-frontmatter-set-args.md b/.changeset/1778-thread-workflow-frontmatter-set-args.md deleted file mode 100644 index 5117b9fae..000000000 --- a/.changeset/1778-thread-workflow-frontmatter-set-args.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 1816 ---- -**`/gsd-thread close|resume` now writes the thread status/updated frontmatter (#1778)** — the thread workflow's CLOSE and RESUME branches invoked `frontmatter.set` with the pre-1.6 fully-positional shape (`frontmatter.set `), but since 1.6 the dispatcher parses the file positionally and reads `field`/`value` from the named flags `--field`/`--value` via `parseNamedArgs`. The positional form left `field`/`value` undefined, `cmdFrontmatterSet` errored `file, field, and value required`, and the writes were silently skipped — so closing a thread never marked it `status: resolved` and resuming never marked it `status: in_progress`, with the error scrolling past on every thread command. All four sites (CLOSE `status`+`updated`, RESUME `status`+`updated`) now use the 1.6 hybrid form that `verify-work.md` already uses (`frontmatter.set --field --value `). diff --git a/.changeset/1817-state-rebuild.md b/.changeset/1817-state-rebuild.md deleted file mode 100644 index 8a7ddd6a3..000000000 --- a/.changeset/1817-state-rebuild.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Added -pr: 1830 ---- -**`gsd-tools state rebuild`** — new subcommand that re-derives STATE.md body structure from canonical sources (frontmatter + `.planning/phases/` disk scan), reconciling drifted `## Current Position` prose, dropping orphaned rows from the `**By Phase:**` table, clearing template-placeholder field values, and de-duplicating `## Session Continuity Archive` blocks. Every mutation is recorded in a `## Rebuild Log` audit section. Idempotent (running twice on a clean file is a no-op). Supports `--dry-run` (preview) and `--verbose` (tee log to stderr). Heavier, manual counterpart to the lightweight auto-triggered `state sync`. diff --git a/.changeset/1821-kilo-zcode-dead-hooks.md b/.changeset/1821-kilo-zcode-dead-hooks.md deleted file mode 100644 index 2840e7640..000000000 --- a/.changeset/1821-kilo-zcode-dead-hooks.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2057 ---- -**The installer no longer copies dead lifecycle hook scripts for Kilo and ZCode** — both declare `hooksSurface: 'none'` and have no plugin surface, so the staged `hooks/*.js`, `hooks/*.sh`, `hooks/lib/` and the CommonJS `package.json` marker were dead weight in `~/.kilo/` and `~/.zcode/`. The two hook-copy guards in `install.js` now exclude Kilo and ZCode alongside the other no-hook runtimes. OpenCode, which also declares `hooksSurface: 'none'`, is deliberately kept: its native plugin adapter (#1914) spawns those staged hooks via OpenCode's event bus and needs both them and the marker. diff --git a/.changeset/1825-graphify-graph-path.md b/.changeset/1825-graphify-graph-path.md deleted file mode 100644 index f260e261d..000000000 --- a/.changeset/1825-graphify-graph-path.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Added -pr: 2013 ---- -**`graphify.graph_path` makes the knowledge-graph location configurable so one umbrella graph can serve multiple projects** — a new `.planning/config.json` key (path relative to project root, or absolute) overrides where `/gsd-graphify query|status|diff` read the graph, letting a single curated cross-repo umbrella graph serve every sibling sub-project without N drifting ~5 MB mirror copies. Previously the graph location was hardcoded to `/.planning/graphs/` with no override; the only workaround was copying the umbrella `graph.json` into each project (which drifted, wasted disk, and could be silently overwritten by an in-project build). The diff snapshot travels with the configured graph; build stays project-scoped; unset → byte-identical default; a configured-but-missing file yields an actionable error naming the path. (#1825) diff --git a/.changeset/1847-claude-sonnet-5-standard-tier.md b/.changeset/1847-claude-sonnet-5-standard-tier.md deleted file mode 100644 index 34682694f..000000000 --- a/.changeset/1847-claude-sonnet-5-standard-tier.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -type: Added -pr: 1848 ---- -**Claude Sonnet 5 is now the `standard` (sonnet) tier model.** The model catalog and provider presets resolve the sonnet/standard tier to `claude-sonnet-5` (GA 2026-06-30) across the Anthropic-backed runtimes (`claude`, `copilot`, and the `anthropic`/`anthropic-fable` presets), plus the OpenRouter-style `anthropic/claude-sonnet-5` for `opencode`/`hermes`, replacing the superseded `claude-sonnet-4-6`. Opus and Haiku tier defaults are unchanged (the `haiku` high-effort preset's escalation slot tracks the current sonnet model). Shipped in 1.6.1. (#1847) - - diff --git a/.changeset/1857-test-gate-watch-mode-timeout.md b/.changeset/1857-test-gate-watch-mode-timeout.md deleted file mode 100644 index 7d9054ff7..000000000 --- a/.changeset/1857-test-gate-watch-mode-timeout.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2060 ---- -**Test gates can no longer hang forever on a watch-mode test runner.** vitest defaults to watch mode in an interactive terminal (exactly where `gsd-execute-phase` runs), so a resolved `npm test` / `pnpm test` that maps to vitest never exited and the orchestrator waited indefinitely until the user manually intervened. Every GSD test-command gate — the regression gate, the post-merge gate, the audit-fix gate, and the verify-phase gate — now routes the resolved command through a shared `normalize-test-command` helper that rewrites it to a one-shot form (direct vitest → `vitest run`; jest `--watch` → `--watchAll=false`; a package-manager `test` script backed by watch-vitest → `CI=true` prefix; already-one-shot commands are left unchanged). The three gates that previously hung or silently continued — the regression, post-merge, and audit-fix gates — additionally bound execution with a configurable `workflow.test_gate_timeout` (default 600s), aborting or surfacing the cause on timeout instead of hanging; the verify-phase gate was already bounded (a fixed 5-minute limit) and keeps it, now naming watch mode on timeout. The normalizer only rewrites a runner named as a standalone command token (so paths/targets like `run-vitest.js` are never mangled), is length-capped and linear-time on adversarial input, and only reads a regular-file `package.json`. diff --git a/.changeset/1864-settings-step-balance.md b/.changeset/1864-settings-step-balance.md deleted file mode 100644 index 1dcbdced0..000000000 --- a/.changeset/1864-settings-step-balance.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2014 ---- -**`settings-advanced.md` no longer has an orphan `` around §8 Model Policy** — the §8 Model Policy block ended with a closing `` but had no matching opening tag (5 opens / 6 closes), leaving its content as loose inter-step prose that could fail to execute reliably. Added the missing `` opener so the section is a proper step. A new workflow ``-tag-balance regression guard (fenced-code-stripped) now blocks any future orphan tag across all top-level workflows. (#1864) diff --git a/.changeset/1865-launcher-claude-config-dir.md b/.changeset/1865-launcher-claude-config-dir.md deleted file mode 100644 index 4828fb14f..000000000 --- a/.changeset/1865-launcher-claude-config-dir.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2024 ---- -**The runtime launcher now honors `CLAUDE_CONFIG_DIR`** — the `gsd_run` preamble embedded in every workflow/agent resolved the Claude global install only at `$HOME/.claude/gsd-core/bin/`, while the installer honored `CLAUDE_CONFIG_DIR`, so a global install redirected via `CLAUDE_CONFIG_DIR` was invisible to every `gsd_run` call (every GSD command failed with `gsd-tools.cjs not found`). The Claude resolver arm now uses `${CLAUDE_CONFIG_DIR:-$HOME/.claude}` — matching the installer and the other runtimes' `${VAR:-default}` pattern — so a custom `CLAUDE_CONFIG_DIR` is found and the default `$HOME/.claude` path is unchanged. Re-synced into all 95 workflows/agents; two capped workflows trimmed to stay under their byte budgets. (#1865) diff --git a/.changeset/1906-node-test-causation-mandatory.md b/.changeset/1906-node-test-causation-mandatory.md deleted file mode 100644 index 4c6fc413e..000000000 --- a/.changeset/1906-node-test-causation-mandatory.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2001 ---- -**Node-test prohibition proofs now require a clean-fixture causation control** — a `node-test` prohibition's fail-first proof no longer accepts a deceptive content-independent negative test (one that reds merely because `GSD_PROHIB_SUBJECT` is *set*, ignoring the subject's content). The `check_clean_fixture` control is now **mandatory** for the `node-test` kind: a descriptor that omits it is un-provable and hard-gates, rather than greening on the violation alone. **Breaking (Hyrum):** a previously-green node-test prohibition with no clean fixture now hard-gates — blast radius is zero in-tree (no `node-test` prohibition ships today). The `lint-rule` kind is unchanged (its subject IS the linted file, no `GSD_PROHIB_SUBJECT` indirection). (#1906) diff --git a/.changeset/1920-installer-capability-generators-host-version.md b/.changeset/1920-installer-capability-generators-host-version.md deleted file mode 100644 index 37d491fe0..000000000 --- a/.changeset/1920-installer-capability-generators-host-version.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 1938 ---- -**Third-party capabilities now work on installed layouts.** `capability install` no longer rejects capabilities with a real `engines.gsd` range as "incompatible with GSD 0.0.0" — the host version is now read from the authoritative `gsd-core/VERSION` file across every runtime and the `capability install` CLI. The installer also now ships the registry generator scripts (`gen-capability-registry.cjs`, `gen-loop-host-contract.cjs`), so installed third-party capabilities actually compose into the loop instead of being silently discarded. diff --git a/.changeset/1921-verify-work-gap-recovery.md b/.changeset/1921-verify-work-gap-recovery.md deleted file mode 100644 index 776f031bb..000000000 --- a/.changeset/1921-verify-work-gap-recovery.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2025 ---- -**`/gsd:verify-work` preserves verification state across gap-closure execution and no longer auto-promotes deferred follow-ups into blocking gaps** — resuming after `/gsd:execute-phase --gaps-only` used to lose the verification state: the UAT `## Gaps` still read `status: failed` even after their fix plans executed, so verify-work re-diagnosed them as fresh blockers, spawned a new gap plan, and reported only the new plan as verified. A state contract now links each gap to its fix plan: every UAT gap carries a stable `gap_id` (`G-{phase}-{N}`), gap-closure plans tag the ids they address in their frontmatter (`gap_ids: […]`), and a new `reconcile_gaps` step on resume marks a gap `status: resolved` when its plan has a matching `*-SUMMARY.md` — so fixed gaps aren't re-diagnosed and the phase can close. Separately, a deferred-follow-up branch captures future-work ideas (signals like "later", "next version", "out of scope") into a `## Deferred Follow-Ups` section instead of creating a blocking gap/plan. (#1921) diff --git a/.changeset/1988-roadmap-stray-summary-count.md b/.changeset/1988-roadmap-stray-summary-count.md deleted file mode 100644 index 4662bee37..000000000 --- a/.changeset/1988-roadmap-stray-summary-count.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2016 ---- -**`roadmap update-plan-progress` no longer counts stray non-plan `*-SUMMARY.md` files against phase completion** — remediation/gap-closure summaries (e.g. `30-FIX-CR02-SUMMARY.md`, `30-GAPCLOSURE-SUMMARY.md`) inflated `summary_count`, and once `summary_count >= plan_count` the phase silently flipped to `Complete` (checkbox checked, date stamped) even though several plans had no summary. A new `countMatchedSummaries` helper (core-utils) pairs summaries to plans via the `PLAN→SUMMARY` marker swap + the `-SUMMARY.md` form (layout-agnostic across root, bare, and nested layouts), so only a summary that corresponds to a real plan counts. Wired into `scanPhasePlans` (fixing roadmap listing, state sync, verification, workstream inventory at once) and `cmdRoadmapUpdatePlanProgress`. (#1988) diff --git a/.changeset/1993-milestone-ws-requirements-header.md b/.changeset/1993-milestone-ws-requirements-header.md deleted file mode 100644 index aa53bf197..000000000 --- a/.changeset/1993-milestone-ws-requirements-header.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2015 ---- -**`milestone complete --ws` requirements archive header now points at the workstream REQUIREMENTS.md** — the archive header string hardcoded the root path (`` `…see .planning/REQUIREMENTS.md` ``), so a workstream archive directed readers at the wrong file even though #1917 had already fixed the archive *locations* to land inside the workstream. The display path is now derived from the same workstream-aware `reqPath` the writer uses (`path.relative(cwd, reqPath)`), so root behavior is byte-identical and the workstream case correctly reads `.planning/workstreams//REQUIREMENTS.md`. (#1993) diff --git a/.changeset/2002-cli-self-healing-runtime-build.md b/.changeset/2002-cli-self-healing-runtime-build.md deleted file mode 100644 index 3e2f35507..000000000 --- a/.changeset/2002-cli-self-healing-runtime-build.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -type: Changed -pr: 2036 ---- - -**The GSD CLI now self-heals a missing runtime build.** The compiled `gsd-core/bin/lib/*.cjs` modules are gitignored build artifacts (ADR-457) that ship prebuilt in the npm tarball but are absent on a Claude Code plugin-marketplace / git-clone install, which never runs `npm run build:lib`. Previously every command died at load with `Cannot find module './lib/cli-exit.cjs'`. The `gsd-tools` entrypoint now detects the missing output and compiles it once, on demand (lock-guarded so parallel invocations don't race), then proceeds — a single no-op check on the already-built npm path. When TypeScript is genuinely unavailable it prints an actionable `npm install && npm run build:lib` message instead of crashing. diff --git a/.changeset/2008-command-exit-zero-gate.md b/.changeset/2008-command-exit-zero-gate.md deleted file mode 100644 index 49151b5c2..000000000 --- a/.changeset/2008-command-exit-zero-gate.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Added -pr: 2011 ---- -**Third-party capability gates now actually fire via a generic `command-exit-zero` predicate.** — a capability's declared `check.predicate` gate was rendered for display but never evaluated (only built-in `check.query` gates were enforced, and the `security` capability's gate worked solely via a hard-coded `ship.md` branch). A new generic evaluator (`gsd_run check predicate`) now evaluates `check.predicate` blocks by `kind`; the first built-in kind `command-exit-zero` runs a bounded `sh -c` command at the project root and blocks the loop on non-zero exit (timeout → block, fail-closed). The `execute:wave:post`, `execute:post`, and `plan:post` gate-dispatch sites route `predicate` gates to the new evaluator automatically. (#2008) diff --git a/.changeset/2009-load-failed-capability-fail-open.md b/.changeset/2009-load-failed-capability-fail-open.md deleted file mode 100644 index 22ce740cf..000000000 --- a/.changeset/2009-load-failed-capability-fail-open.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2075 ---- -**Load-failed capability gates now fail open with a loud warning instead of blocking the whole project** — when an installed overlay (third-party) capability failed to load (e.g. an incompatible `engines.gsd` range) but had declared a `gate`-kind loop hook, the loop resolver injected a blocking synthetic gate (`blocking:true`, `onError:halt`) at every point where that capability declared a gate. A single incompatible capability therefore halted every `ship:pre` and `verify:post` in the project — unrelated to what the gate would have checked, and with no remediation surfaced. The resolver now injects no gate and instead emits a loud warning — to stderr and in the `loop render-hooks` envelope's `warnings` array — naming the load-failure reason and the exact `gsd capability remove ` remediation, and the loop proceeds (fail open). The capability id embedded in that remediation is validated against the canonical id shape first, so a malformed overlay directory name cannot inject shell metacharacters into the surfaced command. The loader still records `_overlay.blockedGates`; only the consequence changes from block to warn. `step`/`contribution` overlays were already skip-open. (#2009) diff --git a/.changeset/2012-phase-complete-progress-row.md b/.changeset/2012-phase-complete-progress-row.md deleted file mode 100644 index 3bc84044c..000000000 --- a/.changeset/2012-phase-complete-progress-row.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2032 ---- -**`phase.complete` now updates the `## Progress` rollup row even when an earlier phase-numbered table precedes it** — the Progress-row writer used a non-global regex that matched *any* table row starting with the phase number, so it bound to the first such row (e.g. a `| Phase | Requirements | Count |` coverage table), no-op'd on the wrong 3-column row, and never reached the real Progress row. The regex is now scoped to the `## Progress` section so it binds to the correct table. The command still returned `roadmap_updated: true` (that field is `fs.existsSync(ROADMAP.md)`), masking the silent failure. (#2012) diff --git a/.changeset/2017-context7-plugin-grant-prefix.md b/.changeset/2017-context7-plugin-grant-prefix.md deleted file mode 100644 index 91eb0250b..000000000 --- a/.changeset/2017-context7-plugin-grant-prefix.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2029 ---- -**context7 now works for plugin-marketplace installs (8 agents regained doc lookup)** — the agents granted only `mcp__context7__*`, which matches a standalone context7 MCP server but not the official Claude Code plugin-marketplace install (`context7@claude-plugins-official`), whose tools are named `mcp__plugin_context7_context7__*`. The grant never matched, so advisor/ai/domain/phase/project/ui-researcher + planner + executor silently lost documentation lookup and fell back to WebSearch. All 8 agents now grant both forms, the researcher profile table is updated, and a parity guard asserts no agent grants the standalone form without the plugin form. (#2017) diff --git a/.changeset/2018-applysurface-empty-manifest-agents.md b/.changeset/2018-applysurface-empty-manifest-agents.md deleted file mode 100644 index 68ddf4024..000000000 --- a/.changeset/2018-applysurface-empty-manifest-agents.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2031 ---- -**`applySurface` no longer deletes every `gsd-*` agent when the skills manifest resolves empty** — the agent-prune loop in `_syncGsdDir` deleted any `gsd-*.md` not in the staged set, and when the manifest was empty/unresolvable (null manifest, no array entries, no `files` key, or an unresolvable install source root), the staged set was empty → every agent was pruned. Skills were guarded by `pruneSkillDirs`'s manifest-membership check (conservative preservation on empty manifest); agents had no equivalent. The agent-prune loop is now skipped when the manifest is empty/absent, so agents are preserved while copy (adding genuinely new agents) still runs. (#2018) diff --git a/.changeset/2019-planning-config-learnings-path.md b/.changeset/2019-planning-config-learnings-path.md deleted file mode 100644 index 110e8ef95..000000000 --- a/.changeset/2019-planning-config-learnings-path.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2026 ---- -**`planning-config.md` global-learnings path corrected to `~/.gsd/knowledge/`** — the `features.global_learnings` row directed users to `~/.gsd/learnings/`, but the implementation (`src/learnings.cts`, `execute-phase.md`) stores and reads global learnings from `~/.gsd/knowledge/`. Anyone following the docs to inspect, back up, or seed their global learnings looked in a directory the code never touches. (#2019) diff --git a/.changeset/2020-executor-dead-sdk-ref.md b/.changeset/2020-executor-dead-sdk-ref.md deleted file mode 100644 index 2491f753e..000000000 --- a/.changeset/2020-executor-dead-sdk-ref.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2027 ---- -**Removed dead SDK file references from runtime-loaded markdown that triggered an infinite `find.exe` storm on Windows** — `agents/gsd-executor.md` pointed at `sdk/src/query/QUERY-HANDLERS.md` and `gsd-core/workflows/reapply-patches.md` at `sdk/dist/cli.js`, both retired with the SDK package (ADR-0174). AI runtimes that resolve doc references by filesystem search ran `find / -iname …`; on Git Bash for Windows `/` maps to the drive root, so `find.exe` traversed the whole disk (14h+, orphaned processes, 4M+ open handles each, unkillable). The references now resolve to live paths, and a new regression guard asserts no `sdk/src|sdk/dist|sdk/handlers` file references remain in agents/workflows/references markdown. (#2020) diff --git a/.changeset/2022-roadmap-verify-gate.md b/.changeset/2022-roadmap-verify-gate.md deleted file mode 100644 index bd31bfd92..000000000 --- a/.changeset/2022-roadmap-verify-gate.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2030 ---- -**`roadmap update-plan-progress` no longer checks the phase checkbox without verification** — the command stamped the phase-level ROADMAP checkbox and completion date the moment the last plan summary landed (called routinely after every wave and every plan), with **no verification gate** — unlike `phase.complete` which correctly requires `readVerificationStatus(...).status === 'passed'`. Now `isComplete` requires both all plan summaries AND a passed verification, matching the `cmdPhaseComplete` contract, so the checkbox only fires after `gsd-verifier` has confirmed the phase. (#2022) diff --git a/.changeset/2028-phase-complete-milestone-end-workstream-guard.md b/.changeset/2028-phase-complete-milestone-end-workstream-guard.md deleted file mode 100644 index 3f1f184e2..000000000 --- a/.changeset/2028-phase-complete-milestone-end-workstream-guard.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2066 ---- -**`phase complete` no longer marks a milestone done out of order, nor silently writes root state in workstream mode.** Completing the numerically-highest phase while an earlier phase was still outstanding wrongly flipped STATE.md to `Status: Milestone complete` (the milestone-end check only looked for higher-numbered phases, so an out-of-order completion — e.g. Phase 10 before Phase 9 — read as the end). It now reports milestone-end only when every lower-numbered phase in the milestone is checked complete. Separately, in workstream mode with no active workstream, `phase complete` previously fell back to root `.planning` and wrote STATE.md/ROADMAP.md (and the mislabel) into the shared root other workstreams read; it now fails safe — asking for `--ws ` or an active workstream — mirroring the existing `init progress` guard. (#2066) diff --git a/.changeset/2043-phase-token-single-digit-slug.md b/.changeset/2043-phase-token-single-digit-slug.md deleted file mode 100644 index ce7b100ac..000000000 --- a/.changeset/2043-phase-token-single-digit-slug.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2059 ---- -**Phase directories whose slug begins with a single digit now resolve correctly.** A phase like `46-6-rs-pipeline-orchestrator` (roadmap name "6 Rs Pipeline Orchestrator") had its phase token over-collected as `46-6` instead of `46`, so `gsd-tools` phase-by-number lookups resolved `phase_dir=null` / `has_context=false` (breaking `init.plan-phase`, `init.phase-op`, and downstream execute/verify/ship). Numeric phase-token components must now be zero-padded (≥2 digits), so a single-digit slug word is no longer absorbed into the token. Fixed consistently across every same-class implementation — `extractPhaseToken`, `PHASE_TOKEN_FROM_DIR_RE` and `canonicalPlanStem` (health checks / plan pairing), `isDirInMilestone`'s numeric matcher (milestone filtering), and `extractCanonicalPlanId` — so the health-check and milestone-filter subsystems are fixed alongside phase resolution. diff --git a/.changeset/2046-config-set-null-unset.md b/.changeset/2046-config-set-null-unset.md deleted file mode 100644 index 1272e73da..000000000 --- a/.changeset/2046-config-set-null-unset.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2058 ---- -**`gsd-tools config-set null` now clears (removes) the key instead of persisting the literal string `"null"`.** The documented "Clear" action previously fell through the value parser and stored `"null"` — a truthy value — so "cleared" keys stayed set and `config-get` returned `"null"`; for secret keys (`brave_search`/`firecrawl`/`exa_search`) a masked success line hid a truthy value on disk that integrations could pass along as a real credential. `config-set null` now deletes the key (short-circuiting the typed per-key validators so clearing an enum/boolean/number key removes it rather than being rejected), making the "Clear" flows in `settings-integrations.md` / `settings-advanced.md` actually clear. diff --git a/.changeset/2056-plan-phase-foreign-prefix.md b/.changeset/2056-plan-phase-foreign-prefix.md deleted file mode 100644 index 38f905fec..000000000 --- a/.changeset/2056-plan-phase-foreign-prefix.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2105 ---- -**`init plan-phase` no longer collapses foreign-prefixed task/workstream IDs into numeric phases** — a query like `MEM-01` (where `MEM` is not the configured `project_code`) used to have its prefix stripped and resolve to the unrelated numeric Phase 01; it now reports `phase_found: false` unless a phase directory or roadmap entry literally carries that prefix. The configured `project_code`'s own prefixed phases (e.g. `LKML-01` under `project_code: LKML`) continue to resolve as before. (#2056) diff --git a/.changeset/2067-phase-complete-checkbox-regex.md b/.changeset/2067-phase-complete-checkbox-regex.md deleted file mode 100644 index 892a3763a..000000000 --- a/.changeset/2067-phase-complete-checkbox-regex.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2079 ---- -**`phase complete` no longer ticks the wrong phase's ROADMAP checkbox** — completing a phase whose number also appears in a later phase's description (e.g. an idempotent re-run of an already-complete phase) used to mark the *wrong* phase done, because the checkbox-matching regex greedily spanned from `]` to any later "Phase N" mention instead of only the immediately-following phase title. (#2067) diff --git a/.changeset/2071-effort-sync-installed-runtime.md b/.changeset/2071-effort-sync-installed-runtime.md deleted file mode 100644 index 2c9a0b663..000000000 --- a/.changeset/2071-effort-sync-installed-runtime.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2076 ---- -**`gsd-tools effort sync` no longer crashes in an installed runtime.** In any global install (e.g. `~/.claude/gsd-core/`), `effort sync` threw `Cannot find module '../../../bin/install.js'` — the command reached into the package-root `bin/install.js` for its install-time effort resolvers, but the installer only copies the `gsd-core/` subtree into a runtime home, so that file is never present there. As a result, `effort` config changes (`routing_tier_defaults` / `agent_overrides`) silently never reached installed agents without a full reinstall. The two resolvers (`readGsdEffectiveEffortConfig` + `resolveInstallTimeEffort`, with their helpers) are now extracted into a shipped `gsd-core/bin/lib/install-effort-resolver.cjs` that both `effort sync` and the installer import — a single source of truth that is always present in the installed tree. (#2076) diff --git a/.changeset/2072-thread-model-into-routed-agent-spawns.md b/.changeset/2072-thread-model-into-routed-agent-spawns.md deleted file mode 100644 index a74b21ff9..000000000 --- a/.changeset/2072-thread-model-into-routed-agent-spawns.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2074 ---- -**`model_overrides` and per-phase-type models now actually apply to the assumptions-analyzer, code-reviewer, and code-fixer agents on Claude Code.** Previously `model_overrides["gsd-code-reviewer"]` / `["gsd-assumptions-analyzer"]` / `["gsd-code-fixer"]` (and `models.verification` / `models.discuss` / `models.execution`) were accepted and resolved but silently dropped — the workflows spawned these agents with no model, so they inherited the session model and the configured routing never took effect (no warning). Every spawn now threads its resolved model: `discuss-phase-assumptions`, `code-review`, and `code-review-fix` (both the re-review and the two fixer spawns) resolve it inline, and `quick`'s review step uses the code-reviewer's own resolved model instead of the executor's. The stale "`discuss` — reserved, no subagent" model-profile docs are corrected to list `gsd-assumptions-analyzer`, and the `verification` row now includes `gsd-code-reviewer`. (#2074) diff --git a/.changeset/2073-antigravity-reviewer-block.md b/.changeset/2073-antigravity-reviewer-block.md deleted file mode 100644 index 009c6cd5e..000000000 --- a/.changeset/2073-antigravity-reviewer-block.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2109 ---- -**`/gsd-review`'s Antigravity CLI reviewer no longer fails silently on large prompts, unavailable pinned models, or pre-session stalls** — the `agy` invocation now uses a file-reference prompt to avoid exec arg-list overflow, is wrapped in an external wall-clock `timeout` paired with `--print-timeout` because `--print-timeout` cannot fire before `agy` creates a session, passes `--model` from `review.models.agy` when set as an escape hatch for a 404'd pinned model, and its empty-output stub now surfaces an `agy` cli.log diagnostic instead of a bare generic message. Supersedes the #687 "no external killer / inline `$(cat)`" contract, which predated `agy` gaining `--model` and predated its own guidance to pair `--print-timeout` with a terminal timeout. (#2073) diff --git a/.changeset/2086-eos-claude-imperative-adapter.md b/.changeset/2086-eos-claude-imperative-adapter.md deleted file mode 100644 index 73ab37742..000000000 --- a/.changeset/2086-eos-claude-imperative-adapter.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Changed -pr: 2106 ---- -**Internal: Claude Code's installer is now driven through the public Host-Integration Interface (ADR-1239 / EoS).** `bin/install.js` routes `claude` install/uninstall through the imperative adapter (`createImperativeAdapter`) instead of calling the engine directly, and its 13 hardcoded `runtime === 'claude'` / `runtime !== 'claude'` branches are folded into descriptor-driven `runtime.hostBehaviors` on `capabilities/claude/capability.json` (permission schema, `settings.local.json` scope routing, `.gsd-source` marker, effort frontmatter, canonical-workflow authorship, and more). Install/uninstall output is **byte-identical** for both the global skills layout and the local legacy layout (golden-parity asserted for both scopes); no other runtime changes. Removes the "add-a-host tax" of scattered string-equality checks for the tier-1 reference host. No user-facing change. (#2086) diff --git a/.changeset/2087-eos-opencode-imperative-adapter.md b/.changeset/2087-eos-opencode-imperative-adapter.md deleted file mode 100644 index 82b18defb..000000000 --- a/.changeset/2087-eos-opencode-imperative-adapter.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Changed -pr: 2108 ---- -**OpenCode is now driven through the public Host-Integration Interface, with two capability upgrades (ADR-1239 / EoS).** OpenCode and its Kilo sibling previously installed via a bespoke `runtime === 'opencode'`/`isOpencode` branch in `bin/install.js`; its commands+skills+plugin install now runs through the imperative adapter → the engine's combined-family install path (`installRuntimeArtifacts`), and every hardcoded `runtime === 'opencode'` branch is folded into descriptor-driven `runtime.hostBehaviors`. Install/uninstall output is **byte-identical** (golden parity asserted for all 16 runtimes). Two Context7-verified upgrades land: (1) **background dispatch** — OpenCode shipped experimental background subagents in v1.15 and made them default-on in v1.17, so `dispatch.background`/`backgroundDispatch` flip to `true`; GSD no longer force-flattens OpenCode-hosted wave dispatch (`shouldFlattenDispatch` now returns `false`), letting agents run concurrently where the host supports it. (2) **expanded event surface** — the OpenCode plugin now subscribes to `permission.asked`, `permission.replied`, and `session.error` (added to `EXTENSION_EVENT_SURFACES.opencode`), wiring the declared surface for future permission/error-aware bindings. (#2087) diff --git a/.changeset/2088-eos-codex-declarative-adapter.md b/.changeset/2088-eos-codex-declarative-adapter.md deleted file mode 100644 index e929c3ddc..000000000 --- a/.changeset/2088-eos-codex-declarative-adapter.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Changed -pr: 2110 ---- -**Codex is now driven through the public Host-Integration Interface, with three capability upgrades (ADR-1239 / EoS).** Codex previously installed via hardcoded `runtime === 'codex'`/`isCodex` projection in `bin/install.js`; its `config.toml` / agent-`.toml` / `hooks.json` install now runs through the declarative embedding adapter and descriptor-driven `runtime.hostBehaviors`, with **zero** positive `isCodex` gates and **zero** `runtime === 'codex'` branches remaining (source-guarded). Install/uninstall output stays byte-parity-gated (`tests/fixtures/golden-install-parity/codex.json`). Three Context7-verified upgrades land, each with a test driving the user-reachable surface: (1) **skill root** — GSD skills now install to Codex's canonical `$HOME/.agents/skills` (via a skills-kind `home` override) instead of the deprecated `$CODEX_HOME/skills` fallback, and pre-move installs are migrated (stale `~/.codex/skills/gsd-*` cleaned on both install and uninstall, user-owned content preserved); (2) **hook events** — GSD registers the six documented Codex lifecycle events it previously skipped (`PreToolUse`, `PermissionRequest`, `PreCompact`, `PostCompact`, `SubagentStop`, `UserPromptSubmit`, in addition to the existing `SessionStart`/`SubagentStart`/`Stop`/`PostToolUse`) in `hooks.json`, so `gsd-context-monitor` fires at the same points as in Claude Code, and the descriptor `extendedHookEvents` is reconciled from `[]` to the schema-valid wired subset; (3) **dispatch tuning** — `[agents] max_depth = 1` is written explicitly into the managed `config.toml` block to pin the negotiated `dispatch.maxDepth: 1` axis (`degradationFor` flattens GSD-hosted waves to single-level), and `validateCodexConfigSchema` now permits a known-scalar-only `[agents]` AgentsToml table (coexisting with the flattened `[agents.gsd-*]` role sub-tables) while still rejecting the `[[agents]]` and unknown-key break-forms from #2760. (#2088) diff --git a/.changeset/2089-eos-cursor-imperative-adapter.md b/.changeset/2089-eos-cursor-imperative-adapter.md deleted file mode 100644 index 870d57748..000000000 --- a/.changeset/2089-eos-cursor-imperative-adapter.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Changed -pr: 2120 ---- -**Cursor is now driven through the public Host-Integration Interface, with two capability upgrades (ADR-1239 / EoS).** Cursor previously installed via hardcoded `runtime === 'cursor'`/`isCursor` branches in `bin/install.js`; its install/uninstall now runs through the imperative adapter, and every hardcoded cursor branch is folded into descriptor-driven `runtime.hostBehaviors` (reapplyCommand, frontmatterDialect, hooksJsonSurface, skipSharedHooksInstall, reportCommandsDir, managedHookEvents). Install/uninstall output is **byte-identical** (golden parity asserted for all 16 runtimes). Two Context7-verified upgrades land: (1) **expanded hook-bus coverage** — GSD registers all 6 managed lifecycle events in Cursor's `hooks.json` (`preToolUse`, `stop`, `subagentStart`, `subagentStop` in addition to the original `sessionStart`/`postToolUse`), driven by a new descriptor-driven adapter module (`src/host-integration-adapters/imperative-hook-bus.cts`) that reads `hostBehaviors.managedHookEvents` instead of a hardcoded event pair; cite https://cursor.com/docs/hooks. (2) **named/background nested subagent dispatch** — Cursor's `dispatch.background`/`backgroundDispatch`/`nested` are all `true` with `maxDepth: 2`, so `shouldFlattenDispatch(cursor)` returns `false` and GSD's wave-based execution drives Cursor's native background + depth-2 nested subagent invocation instead of flattening to inline sequential calls; cite https://cursor.com/docs/subagents + https://cursor.com/docs/sdk/typescript. (#2089) diff --git a/.changeset/2090-eos-cline-imperative-adapter.md b/.changeset/2090-eos-cline-imperative-adapter.md deleted file mode 100644 index b6109ac51..000000000 --- a/.changeset/2090-eos-cline-imperative-adapter.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Changed -pr: 2132 ---- -**Cline is now driven through the public Host-Integration Interface, with two capability upgrades (ADR-1239 / EoS).** Cline previously installed via hardcoded `runtime === 'cline'`/`isCline` branches in `bin/install.js`; its install/uninstall now runs through the imperative adapter, and every hardcoded cline branch is folded into descriptor-driven `runtime.hostBehaviors` (reapplyCommand, frontmatterDialect, skipSharedHooksInstall, localTargetIsProjectRoot, clineRulesSurface, localCommandsViaRules). Install/uninstall output is **byte-identical** (golden parity asserted for cline + claude/cursor/codex/opencode). Two Context7-verified upgrades land: (1) **`AgentPlugin.hooks.beforeTool` planning guard** — the `.clinerules/hooks/PreToolUse` file-convention hook (#787) is re-implemented as a real Cline SDK `AgentPlugin` that cancels write-class calls targeting `.planning/` (same fail-open semantics), driven by a new descriptor-driven adapter module (`src/host-integration-adapters/cline-sdk-binding.cts`); cite https://github.com/cline/cline/blob/main/docs/sdk/plugins.mdx. (2) **`createAgentModel` model overrides** — `DefaultGateway.createAgentModel({providerId, modelId})` is wired so GSD's per-subagent `model_overrides`/`model_profile_overrides` resolution applies to Cline subagents (`modelMode: active`); cite https://github.com/cline/cline/blob/main/docs/sdk/reference/gateway.mdx. Cline's dispatch deliberately stays **degraded/flat** (`maxDepth: 1`, read-only, no nested spawning) per the documented host restriction — never silently upgraded to full nested/background. (#2090) diff --git a/.changeset/2091-eos-hermes-imperative-adapter.md b/.changeset/2091-eos-hermes-imperative-adapter.md deleted file mode 100644 index 00aadd9ed..000000000 --- a/.changeset/2091-eos-hermes-imperative-adapter.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Changed -pr: 2134 ---- -**Hermes Agent is now driven through the public Host-Integration Interface, with three capability upgrades (ADR-1239 / EoS).** Hermes previously installed via hardcoded `runtime === 'hermes'`/`isHermes` branches in `bin/install.js`; its install/uninstall now runs through the imperative adapter, and every hardcoded hermes branch is folded into descriptor-driven `runtime.hostBehaviors`. Three upgrades land: (1) **real plugin hook vocabulary** — GSD registers a new `extensionEvents: "hermes"` dialect carrying the 13 documented Hermes plugin events (`pre_tool_call`, `post_tool_call`, `pre_llm_call`, `post_llm_call`, `on_session_start`, `on_session_end`, `on_session_finalize`, `on_session_reset`, `subagent_start`, `subagent_stop`, `pre_gateway_dispatch`, `pre_approval_request`, `transform_tool_result`), replacing the borrowed `hookEvents: "claude"` 6-event surface that silently never fired; cite https://github.com/nousresearch/hermes-agent/blob/main/website/docs/user-guide/features/hooks.md. (2) **dispatch posture** — Hermes' `dispatch.nested: true` with `maxDepth: 1` is correctly negotiated (not silently flattened). (3) **branding/category metadata** — `DESCRIPTION.md` category descriptions, `version:` frontmatter, and branding rewrites are now descriptor-driven rather than hardcoded. Install/uninstall output is byte-identical (golden parity asserted for all runtimes). (#2091) diff --git a/.changeset/2092-eos-qwen-imperative-adapter.md b/.changeset/2092-eos-qwen-imperative-adapter.md deleted file mode 100644 index d85dcc8af..000000000 --- a/.changeset/2092-eos-qwen-imperative-adapter.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Changed -pr: 2153 ---- -**Qwen Code now projects GSD's specialist agents as native subagents** — installing GSD into Qwen Code writes `~/.qwen/agents/gsd-*.md` files you can invoke directly (planner, executor, code-reviewer, …) instead of reaching them only through skill prose, and a `SubagentStart` hook now fires alongside `SubagentStop`. Qwen's install is driven by its negotiated capability descriptor instead of hardcoded runtime special-cases. (#2092) diff --git a/.changeset/2093-eos-kilo-imperative-adapter.md b/.changeset/2093-eos-kilo-imperative-adapter.md deleted file mode 100644 index e02477881..000000000 --- a/.changeset/2093-eos-kilo-imperative-adapter.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Changed -pr: 2156 ---- -**Kilo Code now supports native hooks, active-model routing, and named subagent dispatch** — installing GSD into Kilo wires a lifecycle-hook plugin, keeps each agent's requested model instead of dropping it, projects GSD's specialist agents as invokable subagents, and documents the GSD MCP companion. Kilo's install is driven by its negotiated capability descriptor instead of hardcoded runtime special-cases. (#2093) diff --git a/.changeset/2094-eos-trae-imperative-adapter.md b/.changeset/2094-eos-trae-imperative-adapter.md deleted file mode 100644 index 8139f82bd..000000000 --- a/.changeset/2094-eos-trae-imperative-adapter.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Changed -pr: 2157 ---- -**GSD skills installed for Trae now carry SOLO stage metadata** — Trae's SOLO Agent can recognize GSD skills as workflow-stage skills for auto-invocation instead of requiring manual triggering. Several of Trae's install branches (shared-hooks gating, path rewrites) also move onto its capability descriptor. Note: the stage-metadata field is a best-effort/inferred shape — Trae publishes no formal schema. (#2094) diff --git a/.changeset/2095-eos-kimi-imperative-adapter.md b/.changeset/2095-eos-kimi-imperative-adapter.md deleted file mode 100644 index 123cde5a7..000000000 --- a/.changeset/2095-eos-kimi-imperative-adapter.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Added -pr: 2159 ---- -**GSD's lifecycle hooks now run under Kimi CLI** — installing GSD into Kimi wires its session-state, phase-boundary, graphify, and guard hooks into Kimi's own native `config.toml` `[[hooks]]` bus (Beta on Kimi's side) instead of silently no-op'ing, and GSD's Kimi subagents can now run in the background. Kimi's install is driven by its negotiated capability descriptor instead of hardcoded runtime special-cases. (#2095) diff --git a/.changeset/2096-eos-antigravity-imperative-adapter.md b/.changeset/2096-eos-antigravity-imperative-adapter.md deleted file mode 100644 index 5e5828552..000000000 --- a/.changeset/2096-eos-antigravity-imperative-adapter.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Changed -pr: 2165 ---- -**Installing GSD into Antigravity now writes the `permissions.allow` rules its CLI documents** — so GSD's own reads and hooks aren't stuck on interactive prompts — and registers GSD's companion MCP server via a standalone `mcp_config.json` (best-effort: Antigravity's raw config schema isn't published, so this uses the Gemini-CLI-successor format). Antigravity's install is now driven by its negotiated capability descriptor instead of hardcoded runtime special-cases. (#2096) diff --git a/.changeset/2097-eos-augment-imperative-adapter.md b/.changeset/2097-eos-augment-imperative-adapter.md deleted file mode 100644 index fe67b40f2..000000000 --- a/.changeset/2097-eos-augment-imperative-adapter.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -type: Changed -pr: 2166 ---- - -**Augment Code now installs through its capability descriptor, with a native MCP companion** — installing GSD into Augment registers the GSD companion server in Augment's `settings.json` `mcpServers` and drives command/skill/agent conversion from Augment's negotiated descriptor instead of hardcoded runtime special-cases. (#2097) diff --git a/.changeset/2098-eos-codebuddy.md b/.changeset/2098-eos-codebuddy.md deleted file mode 100644 index 66cf3cb78..000000000 --- a/.changeset/2098-eos-codebuddy.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -type: Changed -pr: 2169 ---- - -**CodeBuddy now wires GSD's full extended lifecycle hook set and is driven by its capability descriptor** — installing GSD into CodeBuddy now registers `SubagentStart`, `SubagentStop`, `Stop`, and `PreCompact` hooks in its `settings.json` (it previously had none of these), matching the coverage Qwen/Kimi already ship, and CodeBuddy's install is fully descriptor-driven instead of via residual hardcoded runtime branches. (#2098) diff --git a/.changeset/2099-eos-copilot.md b/.changeset/2099-eos-copilot.md deleted file mode 100644 index a08e5dcba..000000000 --- a/.changeset/2099-eos-copilot.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -type: Changed -pr: 2172 ---- - -**GitHub Copilot now wires GSD's full lifecycle hook bus and is driven by its capability descriptor** — installing GSD into Copilot registers `preToolUse`, `postToolUse`, `userPromptSubmitted`, and `sessionEnd` handlers in its `hooks/gsd-session.json` (beyond today's `sessionStart`-only advisory), and Copilot's residual hardcoded runtime branches are folded onto descriptor-driven `hostBehaviors`. (#2099) diff --git a/.changeset/2100-eos-windsurf.md b/.changeset/2100-eos-windsurf.md deleted file mode 100644 index 8e78f64f9..000000000 --- a/.changeset/2100-eos-windsurf.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Changed -pr: 2190 ---- -**Windsurf now enforces GSD's write/command safety guards through Cascade's native hook bus** — installing GSD into Windsurf registers blocking `pre_write_code`/`pre_run_command` hooks in `.windsurf/hooks.json` (exit-code-2 blocking) and drives Windsurf's install from its capability descriptor instead of hardcoded runtime branches. (#2100) diff --git a/.changeset/2101-eos-zcode.md b/.changeset/2101-eos-zcode.md deleted file mode 100644 index e3770c283..000000000 --- a/.changeset/2101-eos-zcode.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Changed -pr: 2195 ---- -**ZCode's install is now driven and regression-tested through its capability descriptor** — ZCode joins the dogfooded declarative-adapter reference hosts with a byte-identical install, and its shared-hooks exclusion is folded onto `hostBehaviors` instead of a hardcoded runtime branch. (Hook-automation and MCP upgrades remain blocked on ZCode publishing its on-disk config formats.) (#2101) diff --git a/.changeset/2102-eos-pi.md b/.changeset/2102-eos-pi.md deleted file mode 100644 index 4cbebe59e..000000000 --- a/.changeset/2102-eos-pi.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Added -pr: 2205 ---- -**GSD is now installable on pi** — `npx @opengsd/gsd-core --pi` installs the GSD extension to `~/.pi/agent/extensions/gsd.cjs`, and `/gsd ` now dispatches real commands through the embedded engine (the reference binding previously could only run `query help`). Drives pi through the negotiated imperative Host-Integration adapter, with active-model steering and the full pi lifecycle-event surface. (#2102) diff --git a/.changeset/2104-foreign-prefix-sibling-commands.md b/.changeset/2104-foreign-prefix-sibling-commands.md deleted file mode 100644 index 9662fe629..000000000 --- a/.changeset/2104-foreign-prefix-sibling-commands.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2149 ---- -**`init execute-phase`, `init verify-work`, and `init phase-op` no longer collapse foreign-prefixed task IDs to numeric phases** — `MEM-01` under `project_code: LKML` was silently stripped to `01` and resolved to the unrelated numeric Phase 01, because the #2056 guard was applied only to `init plan-phase`. The guard is now extracted into shared helpers (`guardedFindPhase` / `guardedGetRoadmapPhase`) that delegate to the canonical `isForeignPrefixedPhaseQuery` from `phase-id.cts`, and all four init commands route through them. (#2104) diff --git a/.changeset/2107-orchestrator-honors-blocking-human-gate.md b/.changeset/2107-orchestrator-honors-blocking-human-gate.md deleted file mode 100644 index a4d745e9b..000000000 --- a/.changeset/2107-orchestrator-honors-blocking-human-gate.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Security -pr: 2113 ---- -**`gate="blocking-human"` checkpoints are no longer auto-approved by the execute-phase orchestrator** — the package-legitimacy gate (#2827) spans two layers: `gsd-executor` refuses to auto-approve a `gate="blocking-human"` checkpoint and escalates it via `checkpoint_return_format` so a human can vet the package, and `execute-phase`'s `checkpoint_handling` step decides what happens next. That step dispatched purely on checkpoint *type* and never read `gate`, so under `--auto` / `--chain` it immediately auto-approved the very checkpoint the executor had just refused to auto-approve (`human-verify → {user_response} = "approved"`). The slopsquatting defence was therefore inert in exactly the unattended mode where nobody is watching: an `[ASSUMED]`/`[SUS]` package reached install with no human ever seeing the verification prompt. `checkpoint_handling` now carves out `gate="blocking-human"` (and the package-legitimacy `what-built` markers) ahead of every auto-mode branch, routing those checkpoints to the standard present-to-user flow regardless of type. `references/checkpoints.md` documents the `gate` attribute and its two values for the first time — previously `blocking-human` appeared nowhere outside `agents/gsd-executor.md`, so no planner had a documented way to author a checkpoint that auto-mode could not bypass. The existing regression test asserted the executor half only; it now asserts the orchestrator half too, which is why it stayed green while the gate was open. (#2107) diff --git a/.changeset/2112-commit-files-pathspec.md b/.changeset/2112-commit-files-pathspec.md deleted file mode 100644 index 1e8a1118d..000000000 --- a/.changeset/2112-commit-files-pathspec.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2148 ---- -**`commit --files` now commits only the declared paths** — `gsd-tools commit --files A B` previously ran a bare `git commit` that absorbed the entire staged index, silently sweeping in unrelated files the caller never named. The commit now appends a pathspec (`-- `) so only the staged subset of `--files` lands in the commit; the no-`--files` default path is unchanged. Missing tracked files are still skipped (not committed as deletions, #2014), and when all declared files are missing the function short-circuits to `nothing_to_commit` instead of absorbing the index. (#2112) diff --git a/.changeset/2116-surface-bare-require.md b/.changeset/2116-surface-bare-require.md deleted file mode 100644 index f48850120..000000000 --- a/.changeset/2116-surface-bare-require.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2213 ---- -**Fixed unresolvable bare `require('gsd-core/...')` in `gsd-surface` command doc** — the four `require()` examples now derive the engine path from `runtimeConfigDir` (resolvable at runtime), and the reinstall hint corrects `npm i -g gsd-core` to `npm i -g @opengsd/gsd-core`. (#2116) diff --git a/.changeset/2118-milestone-complete-dry-run.md b/.changeset/2118-milestone-complete-dry-run.md deleted file mode 100644 index d0f3d2659..000000000 --- a/.changeset/2118-milestone-complete-dry-run.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2155 ---- -**`milestone complete --dry-run` now prints a preview plan instead of silently mutating** — `gsd-tools milestone complete --dry-run` was neither parsed nor rejected, so a caller expecting a preview triggered the full destructive mutation (archive phases, move audit artifacts, rewrite STATE.md) with no way to back out. The `--dry-run` flag is now honored: it returns a JSON plan listing `would_archive` (roadmap, requirements, audit, phase dirs) and `would_update` (MILESTONES.md, STATE.md) targets with zero filesystem mutations. (#2118) diff --git a/.changeset/2119-secure-phase-single-writer.md b/.changeset/2119-secure-phase-single-writer.md deleted file mode 100644 index 172b29463..000000000 --- a/.changeset/2119-secure-phase-single-writer.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2154 ---- -**`/gsd-secure-phase` now has a single SECURITY.md writer** — the `gsd-security-auditor` subagent previously held `Write`/`Edit` tools and was instructed to "write SECURITY.md" with no padded `-` prefix and no template frontmatter, while the orchestrator's Step 6 also wrote the phase-scoped `-SECURITY.md` from `templates/SECURITY.md`. The auditor is now return-only (drops `Write`/`Edit`, returns a structured verdict with `threats_open`); the orchestrator is the sole file writer. The workflow's Step 5 spawn constraints explicitly forbid the auditor from writing SECURITY.md. (#2119) diff --git a/.changeset/2122-codex-gpt56-model-defaults.md b/.changeset/2122-codex-gpt56-model-defaults.md deleted file mode 100644 index 4da36b5c0..000000000 --- a/.changeset/2122-codex-gpt56-model-defaults.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Changed -pr: 2146 ---- -**Codex/OpenAI default models advance to the GPT-5.6 family (Sol/Terra/Luna)** — the Codex runtime tier defaults and the `openai` provider preset now resolve to current-generation model IDs instead of the superseded GPT-5.4/5.5 line, so Codex users on default profiles get improved agentic coding (Sol) and lower costs (Terra/Luna) without changing any config. (#2122) diff --git a/.changeset/2198-security-dead-scan-exports.md b/.changeset/2198-security-dead-scan-exports.md deleted file mode 100644 index a28eb2c42..000000000 --- a/.changeset/2198-security-dead-scan-exports.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2211 ---- -**Dead security scan exports removed; injection-scan docs corrected to match reality** — `scanEntropyAnomalies` and `shannonEntropy` were dead code with zero production callers (live hooks inline their own patterns for independence). REQ-SCAN-INJ-02/-03 now accurately describe what runs live (injection patterns, invisible Unicode) vs CI-only (base64-decode, codebase scan). (#2198) diff --git a/.changeset/agile-newts-roar.md b/.changeset/agile-newts-roar.md deleted file mode 100644 index a767ec9c2..000000000 --- a/.changeset/agile-newts-roar.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -type: Changed -pr: 1813 ---- -**Internal: the installer's `program` (display-name) + `command` (slash-invocation) chains are now single-source lookups** — the 14-line `program` chain (an exact duplicate of `runtimeLabel`) → `getRuntimeLabel`, and the 14-line `command` chain (the per-runtime `/gsd-new-project` syntax: gemini `/gsd:`, codex `$`, cursor skill-mention, kimi `/skill:`, default `/gsd-new-project`) → new `getRuntimeNewProjectCommand(runtime)` helper (ADR-1239 Phase B / #1679 AC2 slice 4). `runtime ===` count in `bin/install.js`: 53 → 25 (cumulative this session: 129 → 25). Stdout strings preserved byte-for-byte; no install-output change (golden-parity 16/16). No user-facing change. - - diff --git a/.changeset/agile-pandas-dance.md b/.changeset/agile-pandas-dance.md deleted file mode 100644 index 5041d24ea..000000000 --- a/.changeset/agile-pandas-dance.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2233 ---- -**Custom STATE.md frontmatter keys are no longer dropped on every mutating verb** — syncStateFrontmatter rebuilt the frontmatter from a fixed schema, silently dropping any custom key. It now carries forward existing keys the schema does not own. (#2202) diff --git a/.changeset/agile-rams-climb.md b/.changeset/agile-rams-climb.md deleted file mode 100644 index d91050d43..000000000 --- a/.changeset/agile-rams-climb.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2222 ---- -**Non-frontend phases with `UI hint: no` are no longer blocked by the UI-SPEC gate** — the UI safety gate's token list included the bare token `UI`, which matched GSD's own `**UI hint**: no` metadata line and false-detected a UI, blocking backend/infra phases at /gsd-plan-phase. An explicit `UI hint: yes|no` is now authoritative and the hint line is no longer token-sniffed. (#2150) diff --git a/.changeset/bold-deer-zip.md b/.changeset/bold-deer-zip.md deleted file mode 100644 index 065cc968b..000000000 --- a/.changeset/bold-deer-zip.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 1992 ---- -**OpenCode reviewer no longer silently yields an empty review on large prompts** — `/gsd-review --opencode` now invokes `opencode run --format json` and reconstructs the review from the assistant text parts, so a large-prompt run where the default `build` agent ends its turn with zero output tokens no longer produces an empty stub. When the agent genuinely emits no text, the stub now reports the stop reason, output-token count, and captured stderr instead of a generic message. (#1936) diff --git a/.changeset/bold-orcas-wander.md b/.changeset/bold-orcas-wander.md deleted file mode 100644 index dbdce1386..000000000 --- a/.changeset/bold-orcas-wander.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -type: Changed -pr: 1811 ---- -**Internal: the installer's per-function `is` flag-declaration blocks are now a single `runtimeFlags` lookup** — the four duplicated `const isX = runtime === 'x'` blocks in `bin/install.js` (uninstall / writeManager / install / a fourth helper — 48 branches) are collapsed into one `runtimeFlags(runtime)` helper in `runtime-name-policy.cts` (ADR-1239 Phase B / #1679 AC2 slice 3). The add-a-host tax for flags is removed (one `RUNTIME_FLAG_IDS` entry, not four declaration blocks). Install output is byte-identical for all 16 runtimes (golden-parity asserted); `runtime ===` count in `bin/install.js`: 101 → 53. No user-facing change. - - diff --git a/.changeset/bold-ravens-wake.md b/.changeset/bold-ravens-wake.md deleted file mode 100644 index 0d1b55798..000000000 --- a/.changeset/bold-ravens-wake.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -type: Changed -pr: 1808 ---- -**Internal: third-party descriptor loader enforces `configHome` write-confinement at load time** — `loadRegistry({includeInstalled:true, configHome})` now rejects (skip + warn, fail-closed) any installed third-party host-plugin descriptor whose declared `destSubpath` resolves outside the supplied `configHome`, before it is composed into the registry (ADR-1239 Phase C-2 / #1681 slice 2). The `configHome` option is optional and backward-compatible (omitted → no load-time check; install-time gate still bounds writes). No user-facing change for existing flows. - - diff --git a/.changeset/bold-seals-chatter.md b/.changeset/bold-seals-chatter.md deleted file mode 100644 index 2f98cafcf..000000000 --- a/.changeset/bold-seals-chatter.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2223 ---- -**`stale-bake-guard` hermeticity fix (test-isolation)** — the readGsdEffectiveModelOverrides subtest no longer reads the developer's real `~/.gsd/defaults.json`; the resolver now accepts a homedir seam so the test sandboxes HOME. (#2152) diff --git a/.changeset/brave-hawks-fly.md b/.changeset/brave-hawks-fly.md deleted file mode 100644 index b07b243e8..000000000 --- a/.changeset/brave-hawks-fly.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 1487 ---- -**`/gsd-surface` (`list`/`status`) works on Claude Code global installs** — the installer now writes a `.gsd-source` marker pointing at its `commands/gsd` source, so `findInstallSourceRoot` resolves on the global skills layout (which ships no `commands/gsd` tree) instead of throwing `could not locate commands/gsd`. (#1487) diff --git a/.changeset/calm-eagles-tumble.md b/.changeset/calm-eagles-tumble.md deleted file mode 100644 index d2131759c..000000000 --- a/.changeset/calm-eagles-tumble.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -type: Added -pr: 1965 ---- - -**GSD now ships a pi extension** — a real, jiti-loadable ExtensionAPI module (`pi/gsd.cjs`) that registers `/gsd` (dispatches through the GSD command-routing hub) + `gsd_invoke` tool + `tool_call` event, installable at `~/.pi/agent/extensions/`. A reachability test proves the `/gsd` handler dispatches through the engine (keystone wired, not just registered on a mock). (#1965) diff --git a/.changeset/clever-cats-howl.md b/.changeset/clever-cats-howl.md deleted file mode 100644 index af82bb000..000000000 --- a/.changeset/clever-cats-howl.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -type: Changed -pr: 1764 ---- -**Internal: agent install for cursor/windsurf/augment/trae/codebuddy now flows through the descriptor path** — ADR-1235 step 1 routes the trivial-converter runtime group's agents off the inline install() loop onto the descriptor-driven `installRuntimeArtifacts` path, applying the cross-cutting steps uniformly (pre-converter, no workflow-stamp). Agent output is byte-identical for all 16 runtimes (golden-parity asserted, global + local verified); no user-facing change. - - diff --git a/.changeset/clever-cats-roar.md b/.changeset/clever-cats-roar.md deleted file mode 100644 index d625246b2..000000000 --- a/.changeset/clever-cats-roar.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Changed -pr: 1584 ---- -**gsd-ui-checker gains an adversarial FORCE stance (LLM-playbook principle 16)** — the only verdict-producing critic that lacked one now resists rubber-stamping UI-SPEC contracts, with BLOCK/FLAG/PASS classification. Based on arXiv 2505.23840 (third-person objective persona), 2506.04975 (objective-not-hostile persona). diff --git a/.changeset/clever-eagles-romp.md b/.changeset/clever-eagles-romp.md deleted file mode 100644 index 423a3ae27..000000000 --- a/.changeset/clever-eagles-romp.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2231 ---- -**`phase complete --phase N` now works alongside the positional form** — the phase verb family treated the first positional as the phase number, so `--phase 12` was passed as the literal phase name and failed with 'Phase --phase not found'. The phase family now accepts the --phase flag consistently with the state family, and unrecognized flags yield a usage error. (#2201) diff --git a/.changeset/clever-lemurs-march.md b/.changeset/clever-lemurs-march.md deleted file mode 100644 index d585f6d7d..000000000 --- a/.changeset/clever-lemurs-march.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2054 ---- -**Third-party capability skills now surface correctly after install** — a skills-only `role: feature` capability installed `active` but its skills never reached the runtime surface, `capability enable`/`set` rejected it as `unknown capability`, and `capability list` disagreed with `capability state`. `resolveSurface` now unions the composed registry's `capabilityClusters` into the surfaced skill set (no on-disk linking), the writer validates against the composed overlay-aware registry, and `capability list` carries a `surfaced` field matching `capability state`. diff --git a/.changeset/clever-rams-march.md b/.changeset/clever-rams-march.md deleted file mode 100644 index 3912be397..000000000 --- a/.changeset/clever-rams-march.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 1910 ---- -Fixed: probe-core's runProbeCli now fails closed on per-item adapter garbage inside a well-shaped report envelope, matching its documented 'fails closed on adapter garbage' contract. diff --git a/.changeset/curious-koalas-gather.md b/.changeset/curious-koalas-gather.md deleted file mode 100644 index 263a88a61..000000000 --- a/.changeset/curious-koalas-gather.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 1722 ---- -**`/gsd:verify-work` no longer silently terminates when all remaining UAT tests are blocked** — sessions with `blocked_count > 0` and `pending_count == 0` now route to `complete_session` as expected, enabling the zero-issues auto-transition path. diff --git a/.changeset/curious-pandas-howl.md b/.changeset/curious-pandas-howl.md deleted file mode 100644 index fbbc13626..000000000 --- a/.changeset/curious-pandas-howl.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2253 ---- -**state record-metric no longer appends per-plan rows into the By-Phase velocity table** — it now maintains its own Per-Plan Metrics table (self-created on first use), and its auto-create scaffold header is corrected. (#2253) diff --git a/.changeset/daring-badgers-forage.md b/.changeset/daring-badgers-forage.md deleted file mode 100644 index f644f7212..000000000 --- a/.changeset/daring-badgers-forage.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 1709 ---- -Codex reviewer now captures the review via codex's --output-last-message flag instead of redirecting stdout, so Windows process-teardown output no longer pollutes the review file and slips past the empty-output guard. diff --git a/.changeset/daring-cats-snooze.md b/.changeset/daring-cats-snooze.md deleted file mode 100644 index eb1c797ce..000000000 --- a/.changeset/daring-cats-snooze.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2216 ---- -**`last_activity` now shows your local calendar day** — the clock seam derived the date by slicing a UTC instant, so in negative-UTC-offset zones during UTC's early evening the date-only `last_activity` field jumped a day ahead of the operator's actual date (and of `last_updated`'s local date). Operator-facing date fields now use a host-local calendar day while internal/cosmetic stamps stay UTC. (#2136) diff --git a/.changeset/daring-deer-leap.md b/.changeset/daring-deer-leap.md deleted file mode 100644 index 310fb39bd..000000000 --- a/.changeset/daring-deer-leap.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -type: Changed -pr: 1802 ---- -**Internal: the declarative embedding adapter is now named + bound behind a minimal `HostIntegrationInterface`** — `createDeclarativeAdapter({runtime})` (new `src/adapter-declarative.cts`) delegates in-process to `install-engine`'s `installRuntimeArtifacts`/`uninstallRuntimeArtifacts`, formalizing today's projection path as one of the two embedding adapters behind a common contract (ADR-1239 Phase C-1 / #1680 AC1). Output is byte-identical to today's install (gated by `golden-install-parity`). The full 6-point interface binding surface is deferred until the imperative adapter (AC2) fixes the shape (ADR-1239 open wire-shape question). No user-facing change — the adapter is not yet wired to any runtime path. - - diff --git a/.changeset/daring-otters-dart.md b/.changeset/daring-otters-dart.md deleted file mode 100644 index 54f340c3a..000000000 --- a/.changeset/daring-otters-dart.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Changed -pr: 1757 ---- -**Internal: getDirName is now derived from a documented `runtime.localConfigDir` descriptor field** — each runtime's local content-rewrite directory (e.g. `cursor`→`.cursor`, `copilot`→`.github`) moved from a hand-maintained if-chain into its capability descriptor (ADR-1239 Phase B), so it can no longer drift from the registry. Install output is byte-identical for all 16 runtimes (golden-parity asserted); no user-facing change. diff --git a/.changeset/eager-bears-wander.md b/.changeset/eager-bears-wander.md deleted file mode 100644 index 32094114e..000000000 --- a/.changeset/eager-bears-wander.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2215 ---- -**`milestone_name` is no longer clobbered with a delimiter-led fragment** — getMilestoneInfo's `##` heading regex was unanchored, so it matched a heading quoted inside backticks in the Milestones bullet and wrote garbage like `— Active Milestone` over the curated milestone name on every phase transition. Now consults the 🚧 marker first, anchors the regex to line start, strips the leading delimiter, and widens the preserve guard so a bad derive keeps the existing name. (#2135) diff --git a/.changeset/eager-elks-frolic.md b/.changeset/eager-elks-frolic.md deleted file mode 100644 index de18b72a0..000000000 --- a/.changeset/eager-elks-frolic.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -type: Changed -pr: 1759 ---- -**Internal: copyWithPathReplacement converter selection is now data-driven** — the installer's back-compat content-copy path replaced its 13 hardcoded `runtime === 'x'` flag chains with a single per-runtime dispatch table (ADR-1239 Phase B). Install output is byte-identical for all 16 runtimes (golden-parity asserted); no user-facing change. - - diff --git a/.changeset/eager-ibex-bark.md b/.changeset/eager-ibex-bark.md deleted file mode 100644 index 467e97c0e..000000000 --- a/.changeset/eager-ibex-bark.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 1844 ---- -**`init milestone-op` now counts project_code-prefixed phase directories correctly** — fully shipped milestones using the standard prefixed directory layout no longer report `completed_phases: 0` or stay falsely incomplete. (#1844) diff --git a/.changeset/eager-tunas-swim.md b/.changeset/eager-tunas-swim.md deleted file mode 100644 index 5a77fc331..000000000 --- a/.changeset/eager-tunas-swim.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 1991 ---- -**`/gsd-quick` no longer halts with a stale-base worktree mismatch** — the worktree executor now degrades to sequential execution when its fork base has diverged from origin/HEAD, instead of spawning a worktree guaranteed to fail the base-mismatch guard. diff --git a/.changeset/external-job-config-wiring.md b/.changeset/external-job-config-wiring.md deleted file mode 100644 index 8b06a03cd..000000000 --- a/.changeset/external-job-config-wiring.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2006 ---- -**Setting `external_job.submit_timeout_ms` / `poll_timeout_ms` / `artifact_dir` in `.planning/config.json` now actually configures the SLURM adapter** — the keys were declared by the external-job capability but the adapter only read env vars, so config edits silently had no effect. The adapter now resolves them through the canonical capability-config seam (env override > config > registry default), surfaces the resolved `artifact_dir` in `submit` output, documents why the contribution registers at `execute:wave:post` (#1164 asks for `wave:pre`, which `execute-phase.md` does not dispatch today; wiring it is a core-loop change #1164 explicitly defers), and gains unit coverage for the CLI surface (`parseFlags`, `findPlanningDir`, `resolveExternalJobSettings`, `formatShowReport`). (#1164) diff --git a/.changeset/fierce-bears-gather.md b/.changeset/fierce-bears-gather.md deleted file mode 100644 index ade0d2278..000000000 --- a/.changeset/fierce-bears-gather.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Added -pr: 1835 ---- -`plan-phase` now authors edge and prohibition predicates into PLAN.md `must_haves` when a phase SPEC omits `## Edge Coverage` / `## Prohibitions`, so goal-backward verification still has predicates to check on a spec-less phase (ADR-857 Phase 6). Gated by the new default-on `workflow.specless_probe_fallback` toggle — disable it to skip the fallback (the skip is recorded visibly in the plan). Spec-less prohibitions are authored descriptor-less and disposed flagged/unverified (honest verifier #1154), never a silent pass. diff --git a/.changeset/fierce-pumas-gather.md b/.changeset/fierce-pumas-gather.md deleted file mode 100644 index 352163e1e..000000000 --- a/.changeset/fierce-pumas-gather.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2184 ---- -**The Antigravity reviewer in `/gsd-review` no longer reviews blind** — `agy -p` never granted the agent the repo under review, so it frequently anchored on its own scratch directory and returned plan-text-only verdicts counted at full consensus weight. The reviewer is now granted the repo (capability-probed `--add-dir`) and anchored to the absolute repo root; a review that still runs without repo access is stamped `[reviewed-without-repo-access]` and down-weighted in the Consensus Summary. The cursor-agent prompt gains the same absolute-root anchor. (#2176) diff --git a/.changeset/gallant-cats-hum.md b/.changeset/gallant-cats-hum.md deleted file mode 100644 index e795dba0b..000000000 --- a/.changeset/gallant-cats-hum.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 1846 ---- -**Autonomous reruns now skip phases with deferred verification until you resume them explicitly** — if a prior `/gsd-autonomous` run recorded `verification_deferred_human` or `verification_deferred_gaps`, later reruns no longer drop back into the same prompt loop and instead point you at the saved resume command. (#1846) diff --git a/.changeset/gallant-foxes-bark.md b/.changeset/gallant-foxes-bark.md deleted file mode 100644 index 51e5c2741..000000000 --- a/.changeset/gallant-foxes-bark.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Changed -pr: 2259 ---- -**Phase-completion now writes `Status: All phases complete` instead of the overloaded bare `Milestone complete`** — the phase-level completion verb (`completePhaseCore`) was writing the same bare 'Milestone complete' string that the milestone-close verb uses for terminal state, causing a phase-level verb to own a milestone-level field. Per ADR-2207, phase-completion now writes the existing intermediate value 'All phases complete' (already used in gsd2-import.cts); milestone termination (' milestone complete' / 'Awaiting next milestone') remains solely with the milestone-close verb. (#2204) diff --git a/.changeset/gallant-herons-rest.md b/.changeset/gallant-herons-rest.md deleted file mode 100644 index 54ef34c5e..000000000 --- a/.changeset/gallant-herons-rest.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2219 ---- -**`requirements mark-complete` no longer reports silent success when the traceability row is missing** — it OR-ed its checkbox and table-row writes into one flag, so a checkbox-only reconcile returned a payload byte-identical to a full reconcile while the traceability row stayed Pending (and re-run masked it as already-complete). It now surfaces `table_unmatched` for IDs whose checkbox reconciled but whose table row is absent, and treats a checked box with no table row as partial rather than done. (#2140) diff --git a/.changeset/gallant-rams-rally.md b/.changeset/gallant-rams-rally.md deleted file mode 100644 index 84f759dc1..000000000 --- a/.changeset/gallant-rams-rally.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Added -pr: 2188 ---- -**Discover third-party GSD Capabilities in a new Community Capability Registry.** — A non-endorsing discoverability catalog where authors register a Capability via a documentation PR; each entry carries a live latest-release badge and a per-entry GitHub Discussion for community ranking and comments. (#2188) diff --git a/.changeset/gallant-wasps-wave.md b/.changeset/gallant-wasps-wave.md deleted file mode 100644 index 118c6ddc1..000000000 --- a/.changeset/gallant-wasps-wave.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 1832 ---- -state prune now resolves the current phase from the canonical location — frontmatter current_phase, the Current Phase field, or the prose Phase: line scoped to the ## Current Position section — instead of extracting Phase over the whole document, where stateExtractField's pipe-table fallback could latch onto an unrelated | Phase | N | row (e.g. a historical verification table) and compute a wrong prune cutoff. diff --git a/.changeset/gentle-badgers-roar.md b/.changeset/gentle-badgers-roar.md deleted file mode 100644 index a20eb5765..000000000 --- a/.changeset/gentle-badgers-roar.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2048 ---- -**`model_overrides` Claude model IDs now resolve to Agent-tool aliases on the claude runtime** — a full Claude model ID (e.g. `claude-sonnet-5`) in `model_overrides` was returned verbatim and silently dropped by the Claude Agent tool (whose `model` parameter documents only tier aliases), causing the spawned subagent to inherit the parent session model instead of the configured one. It now maps to the tier alias (`sonnet`/`opus`/`haiku`/`fable`), consistent with the `model_policy` path (#1144). Bare aliases, non-Claude values, and non-Claude runtimes are unchanged; a Claude ID with no alias warns once and falls through to tier resolution. (#2041) diff --git a/.changeset/graceful-badgers-click.md b/.changeset/graceful-badgers-click.md deleted file mode 100644 index cec90ae43..000000000 --- a/.changeset/graceful-badgers-click.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 1765 ---- -Phase headers that place a parenthetical tag before the colon (`### Phase 26 (Cluster B): Title`) now resolve and enumerate the same as untagged headers. Previously the resolver returned not-found and `roadmap analyze`/listing silently dropped the phase (wrong phase_count, progress, and next_phase). Tag tolerance is applied at every phase-header read site; untagged and all existing header formats parse unchanged. diff --git a/.changeset/graceful-badgers-dance.md b/.changeset/graceful-badgers-dance.md deleted file mode 100644 index 0f8d58286..000000000 --- a/.changeset/graceful-badgers-dance.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Changed -pr: 1719 ---- -**#853 dispatch-flatten is now data-driven (ADR-1239 Phase B)** — whether GSD backgrounds the plan/execute orchestrator is decided from a documentation-sourced `backgroundDispatch` capability per host (via `gsd_run query dispatch-should-flatten`) instead of a hardcoded `runtime === 'codex'` check. **Cursor now backgrounds the orchestrator** (its docs document backgrounded subagent nesting); codex unchanged; all other hosts run inline. Fail-closed to inline on any uncertainty. diff --git a/.changeset/graceful-geese-click.md b/.changeset/graceful-geese-click.md deleted file mode 100644 index 6f65b9056..000000000 --- a/.changeset/graceful-geese-click.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -type: Changed -pr: 1809 ---- -**Internal: companion MCP server module (interface points 1 + 5)** — `handleMessage`/`runServer` (new `src/mcp-server.cts`) is a minimal, dependency-free stdio JSON-RPC 2.0 server exposing `gsd_invoke_command` (→ the command-routing hub) + `gsd_read_state`/`gsd_write_state` (→ the Phase 3 stateIO seam), so any MCP-consuming host can drive GSD with no bespoke plugin (ADR-1239 Phase C-2 / #1681 slice 3a). Bin entry / packaging deferred to slice 3b. No user-facing change — the server is not yet wired to a bin entry. - - diff --git a/.changeset/graceful-koalas-greet.md b/.changeset/graceful-koalas-greet.md deleted file mode 100644 index 7fad1c6a8..000000000 --- a/.changeset/graceful-koalas-greet.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Changed -pr: 2251 ---- -**`requirements mark-complete` reports a per-surface write-set** — the command now returns a per-requirement `write_set` (checkbox + traceability surfaces) and a `write_set_complete` that is true only when every surface of every requirement applied, so a partial (checkbox-only) reconcile can no longer masquerade as full success even inside a multi-ID batch. Introduces the reusable ADR-2143 §5/§6 `Result` / `WriteSet` contract. (#2251) diff --git a/.changeset/graceful-moles-gather.md b/.changeset/graceful-moles-gather.md deleted file mode 100644 index fbc0e4a1a..000000000 --- a/.changeset/graceful-moles-gather.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 1873 ---- -Executor and milestone-summary/forensics workflows now call state.* commands with named flags so the named-only router records metrics, decisions, blockers, and session continuity instead of silently dropping positional args. diff --git a/.changeset/graceful-wasps-caper.md b/.changeset/graceful-wasps-caper.md deleted file mode 100644 index a0eadf8dd..000000000 --- a/.changeset/graceful-wasps-caper.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 1927 ---- -**bug-1367 install test no longer fails on Windows CI when hooks/dist isn't pre-built** — the test ran install.js without building its hooks/dist precondition (a gitignored build artifact the unit lane doesn't build), so on a lane without pre-built hooks the installer hit "Failed to install hooks: directory is empty" and the before-hook threw. The test now builds hooks in its own before() (mirroring golden-install-parity). (#1926) diff --git a/.changeset/happy-birds-chatter.md b/.changeset/happy-birds-chatter.md deleted file mode 100644 index 414063327..000000000 --- a/.changeset/happy-birds-chatter.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Added -pr: 1755 ---- -**GSD now warns when a stale global CLI (e.g. a retired @gsd-build/sdk canary) shadows your project-local install** — the gsd-tools CLI startup detects when the running binary is outside the project root while a project-local install exists, and prints a remediation warning to stderr (non-blocking). (#1754) diff --git a/.changeset/happy-jays-travel.md b/.changeset/happy-jays-travel.md deleted file mode 100644 index c580ce023..000000000 --- a/.changeset/happy-jays-travel.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -type: Changed -pr: 1803 ---- -**Internal: the imperative embedding adapter now composes the capability registry behind the same `HostIntegrationInterface`** — `createImperativeAdapter({runtime})` (new `src/adapter-imperative.cts`) calls `loadRegistry({includeInstalled:true})` (first-party-wins + consent + fail-closed — identical trust semantics to the CLI) and binds the engine surface behind the same contract the declarative adapter (AC1) satisfies, plus a `registry` accessor for an in-process host to bind its primitives to (ADR-1239 Phase C-1 / #1680 AC2). Concrete host binding is deferred to Phase 5. No user-facing change — the adapter is not yet wired to any runtime path. - - diff --git a/.changeset/happy-seals-roam.md b/.changeset/happy-seals-roam.md deleted file mode 100644 index 10d8f7d65..000000000 --- a/.changeset/happy-seals-roam.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2214 ---- -**`/gsd-fast` now appends Quick Task rows to STATE.md again** — the log_to_state column-count guard used an off-by-one awk formula (`NF-1`) that was always one too high, so the schema gate rejected the very table quick.md creates and silently skipped the STATE.md update. Also now supports the 6-column validate-mode table. (#2133) diff --git a/.changeset/hooks-dist-scoped-ci-race.md b/.changeset/hooks-dist-scoped-ci-race.md deleted file mode 100644 index 906946dfd..000000000 --- a/.changeset/hooks-dist-scoped-ci-race.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 1968 ---- -Build the gitignored `hooks/dist/` artifact once upfront in `scripts/run-tests.cjs` (the same chokepoint as `ensureBuiltArtifacts`), before any concurrent install test spawns `install.js`. Closes the scoped-CI first-build empty-dir race that intermittently failed install tests with `Failed to install hooks: directory is empty` (e.g. `bug-3683-workflow-colon-namespace-leak`). (#1967) diff --git a/.changeset/humble-dogs-gather.md b/.changeset/humble-dogs-gather.md deleted file mode 100644 index 6a0cc0e60..000000000 --- a/.changeset/humble-dogs-gather.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 1916 ---- -**workstream progress no longer reports shipped milestones as `executing`** — `gsd-tools workstream progress` now derives each workstream's status from authoritative shipped signals (an archived milestone snapshot under milestones/, or a SHIPPED marker in the workstream ROADMAP) instead of trusting the mutable STATE.md `Status` field, so a stale field can never hide a shipped/archived milestone. The output adds `status_source` (`field` | `derived`) and `status_conflict` (true when the derived value disagrees with the stale field). (#1913) diff --git a/.changeset/humble-geese-roam.md b/.changeset/humble-geese-roam.md deleted file mode 100644 index a3789d05a..000000000 --- a/.changeset/humble-geese-roam.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -type: Changed -pr: 1804 ---- -**Internal: the model adapter seam exposes `passive` + `active` adapters selected by `modelMode`** — `createModelAdapter({modelMode})` (new `src/model-adapter.cts`): `passive` formalizes today's tier routing (delegates to `model-resolver.resolveModelForTier`), `active` is a host-supplied `sendRequest` seam (VS Code `vscode.lm` / pi providers), fail-closed until Phase 5 binds a concrete provider (ADR-1239 Phase C-1 / #1680 AC3). No user-facing change — the seam is not yet wired to any runtime path. - - diff --git a/.changeset/humble-seals-rest.md b/.changeset/humble-seals-rest.md deleted file mode 100644 index e5392f53a..000000000 --- a/.changeset/humble-seals-rest.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Added -pr: 1810 ---- -**`gsd-mcp-server` — companion MCP server (interface points 1 + 5)** — a new bin command (`npx @opengsd/gsd-core gsd-mcp-server`) runs a stdio JSON-RPC 2.0 MCP server exposing `gsd_invoke_command` (→ the GSD command-routing hub) + `gsd_read_state` / `gsd_write_state` (→ `.planning/` state), so any MCP-consuming host (Claude Code, Codex, OpenCode, VS Code, Gemini CLI, Cursor, Cline, Hermes) can drive GSD with no bespoke plugin (ADR-1239 Phase C-2 / #1681). Dependency-free (hand-rolled JSON-RPC). How-to: `docs/how-to/connect-gsd-mcp-server.md`. diff --git a/.changeset/humble-sloths-jump.md b/.changeset/humble-sloths-jump.md deleted file mode 100644 index 88e081286..000000000 --- a/.changeset/humble-sloths-jump.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 1742 ---- -**Windows install/upgrade/state-write operations no longer fail on transient antivirus/indexer file locks** — the fs.renameSync atomic-publish sites (install state, hooks config, capability ledger/lifecycle, phase/workstream/milestone dirs, roadmap, planning/state locks) now retry EPERM/EBUSY/EACCES via retryRenameSync instead of propagating the transient lock; enforced by the new local/require-fs-op-fallback lint rule (ADR-1703 Phase 6). (#1740) diff --git a/.changeset/humble-tunas-munch.md b/.changeset/humble-tunas-munch.md deleted file mode 100644 index 0c5430279..000000000 --- a/.changeset/humble-tunas-munch.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 1807 ---- -reconstructFrontmatter now emits valid YAML for scalars and block-array items that were previously serialized unescaped. Values carrying a YAML indicator plus a literal quote/backslash, embedded control characters, the empty string, a leading YAML indicator, or leading/trailing whitespace are now routed through a properly escaped double-quoted form, so frontmatter round-trips through strict parsers (js-yaml, PyYAML) instead of corrupting the block on the next state sync. diff --git a/.changeset/humble-tunas-travel.md b/.changeset/humble-tunas-travel.md deleted file mode 100644 index 0b4cc9104..000000000 --- a/.changeset/humble-tunas-travel.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2253 ---- -**`phase remove` no longer destroys the Progress table when removing the last phase** — deleting a phase used a whole-document regex whose scan, on the final phase, ran past the section and swept away the `## Progress` heading and its entire tracking table; the deletion is now structurally bounded to the phase’s own section. (#2253) diff --git a/.changeset/humble-zebras-zip.md b/.changeset/humble-zebras-zip.md deleted file mode 100644 index 593da8622..000000000 --- a/.changeset/humble-zebras-zip.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 1919 ---- -**`phases clear` archives phase directories instead of destroying them** — at a milestone switch, committed phase directories were hard-deleted (`rmSync`) with no archive, silently losing browsable phase history (the #1447 dirty-tree guard was a no-op for the common committed case). Phase directories are now moved to `milestones/-phases/` (collision-safe; timestamp fallback when no version resolves), so history survives the switch. The #1447 uncommitted-changes guard is retained as a secondary backstop. (#1871) diff --git a/.changeset/jolly-jays-hop.md b/.changeset/jolly-jays-hop.md deleted file mode 100644 index e820a2bf6..000000000 --- a/.changeset/jolly-jays-hop.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2226 ---- -**Cross-AI review no longer silently drops the Codex/Claude/Gemini lanes on large plan sets** — the prompt-fed reviewer blocks in review.md invoked each CLI with no explicit timeout, so a slow source-grounded review was killed at the host default (~2 min) and the lane was silently lost. The workflow now directs a high Bash timeout and frames an empty output as a timeout (not the crash it was misdiagnosed as). (#2194) diff --git a/.changeset/jolly-jays-march.md b/.changeset/jolly-jays-march.md deleted file mode 100644 index 430f1cd44..000000000 --- a/.changeset/jolly-jays-march.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Added -pr: 2174 ---- -**Opt-in absolute token count on the statusline context meter** — new `statusline.show_context_tokens` config (default `false`). When enabled, the meter shows the absolute context total after the percentage, e.g. "████░░░░░░ 46% (156k)", summing input, cache-creation, cache-read, and output tokens from the hook payload (a broader basis than the meter's percentage, which is derived from `used_percentage` and excludes output tokens — the two figures can diverge slightly). Default meter output is unchanged. (#2161) diff --git a/.changeset/kind-lynx-munch.md b/.changeset/kind-lynx-munch.md deleted file mode 100644 index d9190ea41..000000000 --- a/.changeset/kind-lynx-munch.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -type: Changed -pr: 1728 ---- -**Internal: derive the non-Claude runtime list from the capability registry** — `NON_CLAUDE_RUNTIMES` is now computed from the capability registry instead of a hand-maintained literal, so it can no longer drift from the per-runtime descriptors. No user-visible behavior change (the list is identical). - - diff --git a/.changeset/kind-tigers-romp.md b/.changeset/kind-tigers-romp.md deleted file mode 100644 index 7ff5f7fc5..000000000 --- a/.changeset/kind-tigers-romp.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Added -pr: 1998 ---- -**Long-running compute can now be externalized as async external jobs instead of blocking the agent turn** — a default-off external-job capability lets executors submit SLURM jobs, commit a .planning/async-jobs manifest, defer SUMMARY.md, and return external_job_waiting; the core loop already reconciles these manifests (#1165), so this adds the producer half (SLURM adapter, pure manifest module, planner/executor fragments, operation policy). (#1105) diff --git a/.changeset/lively-lynx-snooze.md b/.changeset/lively-lynx-snooze.md deleted file mode 100644 index 084679130..000000000 --- a/.changeset/lively-lynx-snooze.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 1918 ---- -**`/gsd-progress` no longer reports a stale root milestone in workstream mode** — in a multi-workstream project with no active workstream set, `gsd-tools query init.progress` silently fell back to root `.planning/STATE.md` (often stale) and reported it confidently. It now fails safe with an actionable error naming the available workstreams and the `--ws`/`workstream set` fix, so a stale root value is never reported. Flat mode and `--ws ` are unchanged. (#1912) diff --git a/.changeset/lucky-quails-greet.md b/.changeset/lucky-quails-greet.md deleted file mode 100644 index 5ef8dc1ea..000000000 --- a/.changeset/lucky-quails-greet.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 1746 ---- -Windows: stop double-quoting $CLAUDE_PROJECT_DIR-anchored managed node hook paths during the #2979 legacy rewrite, which produced "\"$CLAUDE_PROJECT_DIR\"/..." and broke every node managed hook with MODULE_NOT_FOUND (PreToolUse-guard deadlock). diff --git a/.changeset/lucky-tigers-leap.md b/.changeset/lucky-tigers-leap.md deleted file mode 100644 index ee7b80a21..000000000 --- a/.changeset/lucky-tigers-leap.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -type: Added -pr: 1966 ---- - -**GSD now ships a repo-local VS Code extension** — a buildable extension (`vscode/extension.js` + `vscode/package.json`) that registers `gsd.invoke` (dispatches through the GSD command-routing hub) in the VS Code command palette. A reachability test proves the handler dispatches through the engine (keystone wired). Not Marketplace-published; mirrors the OpenCode plugin's bar. (#1966) diff --git a/.changeset/merry-hawks-swim.md b/.changeset/merry-hawks-swim.md deleted file mode 100644 index 9f795dd85..000000000 --- a/.changeset/merry-hawks-swim.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2168 ---- -**phase complete now updates STATE progress on milestone-grouped roadmaps** — deriveProgressFromRoadmap parses the ## Progress table by header (column-by-name) instead of a fixed 4-column layout, so the 5-column milestone-grouped shape is no longer silently unparsed. diff --git a/.changeset/merry-mice-travel.md b/.changeset/merry-mice-travel.md deleted file mode 100644 index 544e94c8e..000000000 --- a/.changeset/merry-mice-travel.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Changed -pr: 1738 ---- -**Honest verifier — verify-phase now abstains on non-inferable `backstop` truths instead of confidently false-passing them (#1154).** When the spec's edge-probe marks a truth non-inferable (`verification: backstop`) and the verifier cannot confirm it with explicit evidence (a passing wired held-out/property test, or a directly-observed behavior), it now reports `human_needed` with reason `insufficient_spec` ("unverified — held-out test recommended") rather than a silent `passed`. Autonomous runs complete with "N unverified non-inferable checks"; interactive runs route to the end-of-phase human checkpoint. Inferable truths are never abstained (over-abstention guard); abstention is exogenous (driven by the tag, not self-judgment). Truth-axis mirror of the prohibition judgment-tier (ADR-550 D4). diff --git a/.changeset/merry-newts-travel.md b/.changeset/merry-newts-travel.md deleted file mode 100644 index a87a5b1b8..000000000 --- a/.changeset/merry-newts-travel.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2261 ---- -**Windows Claude Code hooks now work under PowerShell** — when Claude Code's hook runner resolves to PowerShell (not Git Bash), every GSD-installed hook failed with `Unexpected token` because the installer emitted bare quoted paths with no PowerShell call operator. The fix adds a `hookShell` parameter to the hook-command projection chain; when `hookShell='powershell'`, the `&` call operator is prepended. Default behavior (Git Bash, no prefix) is unchanged. (#2236) diff --git a/.changeset/merry-tigers-parade.md b/.changeset/merry-tigers-parade.md deleted file mode 100644 index a790c738a..000000000 --- a/.changeset/merry-tigers-parade.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Added -pr: 2193 ---- -**Discover third-party GSD Embeddable Orchestration System (EoS) integrations in a new EoS Registry.** — A non-endorsing discoverability catalog where host-integration authors register via a documentation PR; each entry declares its Host-Integration interface points, negotiated axes, and protocol version, with a live release badge and a per-entry GitHub Discussion for ranking and comments. (#2193) diff --git a/.changeset/nimble-ibex-tumble.md b/.changeset/nimble-ibex-tumble.md deleted file mode 100644 index d9665dbae..000000000 --- a/.changeset/nimble-ibex-tumble.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -type: Changed -pr: 1922 ---- -Document Claude Code's advisor-tool inheritance in the model-profiles reference: the session-level advisor is inherited by all GSD subagents and composes with per-agent tiering, with candidate executor/advisor pairings, when it is worth enabling, and the session-level (no per-agent control) constraint. - - diff --git a/.changeset/nimble-jays-roar.md b/.changeset/nimble-jays-roar.md deleted file mode 100644 index 104f03d4d..000000000 --- a/.changeset/nimble-jays-roar.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Added -pr: 1861 ---- -GSD Core ships a `.claude-plugin/marketplace.json` marketplace manifest so Claude-plugin-compatible runtimes (ZCODE et al.) can discover and install gsd-core from a custom marketplace source. Additive — the existing `.claude-plugin/plugin.json` and the Claude Code install path are unchanged. The catalog version (`plugins[0].version`) tracks `package.json` via the release version-sync. diff --git a/.changeset/noble-foxes-purr.md b/.changeset/noble-foxes-purr.md deleted file mode 100644 index e53da8a32..000000000 --- a/.changeset/noble-foxes-purr.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2051 ---- -**`capability state` and `loop render-hooks` now accept `--runtime` to override the auto-detected runtime** — previously both commands parsed only `--config-dir`, so the runtime config dir was derived from the persisted `.planning/config.json` runtime (precedence `GSD_RUNTIME` → `config.runtime` → `claude`). A repo that persisted `runtime:"codex"` resolved the config dir to `~/.codex`, where the Claude skill isn't installed, so every skill-bearing capability reported `surfaced:false` and `execute:post`/`verify:post` hooks silently no-op'd when the operator drove GSD from Claude Code. `--runtime ` (canonicalized, so aliases like `codex-app` work) now bypasses that fallback so the config dir resolves to the explicitly-named runtime's home. Behavior without the flag is unchanged. (#2003) diff --git a/.changeset/noble-wasps-greet.md b/.changeset/noble-wasps-greet.md deleted file mode 100644 index c89e3b5ca..000000000 --- a/.changeset/noble-wasps-greet.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2234 ---- -**`phase complete` no longer false-reports REQ-IDs as missing when the traceability table leads with a status column** — the parser required the REQ-ID in the first column, so a table shaped `| ☐ | REQ-01 | …` matched zero rows and every body REQ-ID was reported missing. It now matches REQ-IDs in any column. (#2203) diff --git a/.changeset/patient-geese-howl.md b/.changeset/patient-geese-howl.md deleted file mode 100644 index 8a1bb8eb3..000000000 --- a/.changeset/patient-geese-howl.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Changed -pr: 1584 ---- -**Extraction discipline for strict-format agents (LLM-playbook principle 8)** — gsd-doc-classifier and gsd-doc-synthesizer apply taxonomy/precedence rules directly without inventing content, reducing reasoning-induced format drift. Based on arXiv 2504.05081 (few-shot beats CoT for pattern tasks), 2506.00069 (terminal instruction placement), 2505.14810, 2505.11423. diff --git a/.changeset/patient-mice-greet.md b/.changeset/patient-mice-greet.md deleted file mode 100644 index efd8cba58..000000000 --- a/.changeset/patient-mice-greet.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 1843 ---- -**`init milestone-op` now ignores backlog `999.x` headings when counting milestone phases** — parked backlog items no longer inflate `phase_count` or pin `all_phases_complete` false for an otherwise finished milestone. (#1843) diff --git a/.changeset/patient-otters-wave.md b/.changeset/patient-otters-wave.md deleted file mode 100644 index a6800caef..000000000 --- a/.changeset/patient-otters-wave.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Changed -pr: 1735 ---- -**Internal: extracted the runtime-artifact install engine from `bin/install.js`** — `installRuntimeArtifacts`/`uninstallRuntimeArtifacts`/`installOpencodeFamilySkills` and their helpers now live in a dedicated `gsd-core/bin/lib/install-engine.cjs` module (ADR-1239 Phase B), so adapters can import the install pipeline instead of reaching into the 12k-line installer. Install output is byte-identical for all 16 runtimes (golden-parity asserted); no user-facing behaviour change. diff --git a/.changeset/patient-voles-chatter.md b/.changeset/patient-voles-chatter.md deleted file mode 100644 index f26c07e8e..000000000 --- a/.changeset/patient-voles-chatter.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Changed -pr: 2010 ---- -**MemPalace `memory_mode` `kg_backend` and `replace` are now functional** — selecting either mode now routes recall through the palace instead of silently behaving like `augment`: `kg_backend` treats the palace temporal KG as the primary knowledge-graph source (native `.planning/graphs/` as fallback), and `replace` resolves recall through the palace as the source of truth. Every mode stays default-resilient — an unreachable palace falls back to native memory and no memory is lost. (#2010) diff --git a/.changeset/phase-id-redos-hardening.md b/.changeset/phase-id-redos-hardening.md deleted file mode 100644 index df9878105..000000000 --- a/.changeset/phase-id-redos-hardening.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Security -pr: 2141 ---- -**Hardened phase/roadmap/plan markdown parsing against quadratic-time (ReDoS) CPU exhaustion** — a crafted `ROADMAP.md`, `STATE.md`, or `PLAN.md` with large runs of unclosed `(`, `[`, ``, ` diff --git a/.changeset/plucky-sloths-forage.md b/.changeset/plucky-sloths-forage.md deleted file mode 100644 index e69b9210d..000000000 --- a/.changeset/plucky-sloths-forage.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2224 ---- -**`state update-progress` no longer mangles the frontmatter and discards the progress suffix** — its Progress: regex matched the raw STATE.md including frontmatter, so the YAML `progress:` key was hit first (corrupting the frontmatter) while the body line stayed stale and was silently reverted on the next write, and any descriptive suffix after the progress bar was destroyed. It now targets the body line only and preserves the suffix. (#2177) diff --git a/.changeset/plucky-wasps-sprint.md b/.changeset/plucky-wasps-sprint.md deleted file mode 100644 index c0a10e0cb..000000000 --- a/.changeset/plucky-wasps-sprint.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Added -pr: 2210 ---- -**GSD now drives VS Code through the Embeddable Orchestration System** — the VS Code extension is rewired through the negotiated imperative Host-Integration adapter (active `vscode.lm` model, engine hook bus, sandboxed storage), gains native Language Model Tools (GSD skills as `#gsd-*` tools) and `#runSubagent` dispatch, and runs as a Web Extension (no Node APIs). (#2103) diff --git a/.changeset/plucky-zebras-jump.md b/.changeset/plucky-zebras-jump.md deleted file mode 100644 index 4e59eb443..000000000 --- a/.changeset/plucky-zebras-jump.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2217 ---- -**`/gsd-ship` no longer silently drops the ship-status note from STATE on merge** — the track_shipping step committed the STATE ship-note after creating the PR but never pushed it, so on a fast merge the note stayed local-only and never reached the default branch. The ship-note is now pushed onto the PR branch with a `[ci skip]` trailer so it lands on merge without a redundant pipeline. (#2138) diff --git a/.changeset/proud-bears-purr.md b/.changeset/proud-bears-purr.md deleted file mode 100644 index d59c07316..000000000 --- a/.changeset/proud-bears-purr.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Added -pr: 1798 ---- -**`/gsd:next` smart-entry workflow** — adds a state-aware entry point that classifies the current project situation (no-project, blocked, verify-failed, planning, executing, verify-pending, complete, and more) and recommends the right next GSD command. The `gsd-tools smart-entry [--json]` classifier handles phase ordering including decimal phase IDs; the `/gsd:next` skill surfaces the workflow with tiered fallback behavior. diff --git a/.changeset/proud-bears-roam.md b/.changeset/proud-bears-roam.md deleted file mode 100644 index 69728b6ee..000000000 --- a/.changeset/proud-bears-roam.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Added -pr: 1923 ---- -OpenCode now runs GSD's lifecycle safety hooks (prompt-injection guard, read-before-edit guard, injection scanner, worktree/workflow guards, context monitor) via a native plugin installed to `~/.config/opencode/plugins/gsd-core.js`. OpenCode declares `hooksSurface: 'none'`, so these hooks were previously inert; the plugin bridges OpenCode's event bus onto GSD's existing hook scripts. Installed automatically by `npx @opengsd/gsd-core --opencode` and removed on uninstall. diff --git a/.changeset/proud-cranes-click.md b/.changeset/proud-cranes-click.md deleted file mode 100644 index 81133bff2..000000000 --- a/.changeset/proud-cranes-click.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Changed -pr: 2173 ---- -**Long-context model names render compactly in the statusline** — the verbose " (1M context)" suffix Claude Code appends to the model display name now collapses to a compact " (1M)" badge (tolerant of future window sizes and the abbreviated "ctx" variant: "(500K context)" → "(500K)", "(1M ctx)" → "(1M)"). Lossless — the long-context signal stays, the 12 characters of width don't. (#2160) diff --git a/.changeset/proud-geese-caper.md b/.changeset/proud-geese-caper.md deleted file mode 100644 index d925cf412..000000000 --- a/.changeset/proud-geese-caper.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2227 ---- -**`/gsd-debug` no longer stalls on a phantom background handoff** — the orchestrator treated the foreground session-manager spawn as a background task and queried its agent ID via TaskOutput (which needs a task ID), then waited on a handoff that was never queryable. The workflow now states the spawn is foreground/blocking, forbids passing an agent ID to TaskOutput, and gives a lost-handoff recovery path. (#2196) diff --git a/.changeset/proud-rams-greet.md b/.changeset/proud-rams-greet.md deleted file mode 100644 index ac8930ac3..000000000 --- a/.changeset/proud-rams-greet.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 1845 ---- -**Roadmap phase lookup now ignores fenced examples and the backlog sentinel lane** — `roadmap get-phase` and `init plan-phase` no longer return fenced sample headings as real phases or treat `999.x` backlog items as active milestone work. (#1845) diff --git a/.changeset/proud-ravens-jump.md b/.changeset/proud-ravens-jump.md deleted file mode 100644 index 94beacdfd..000000000 --- a/.changeset/proud-ravens-jump.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2229 ---- -**`phase complete` no longer checks the wrong ROADMAP checkbox or writes the plan count into a shipped milestone** — the roadmap mutators ran unanchored and un-milestone-scoped, so they could flip a bullet inside a backticked prose literal or a Backlog entry instead of the closing phase's, and write the plan count into a same-numbered phase in a shipped milestone. The checkbox flip is now line-anchored and both writers are scoped to the current milestone. (#2200) diff --git a/.changeset/quick-seals-parade.md b/.changeset/quick-seals-parade.md deleted file mode 100644 index 37b152184..000000000 --- a/.changeset/quick-seals-parade.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2139 ---- -**`roadmap get-phase` resolves project-code-prefixed headings by bare number** — a bare-number query (e.g. `29`) now resolves a drifted `### Phase AB-29:` heading, matching the internal resolver used by `init.phase-op`; previously the CLI returned empty. A bare sibling (`### Phase 29:`) still takes precedence. A project-code-prefixed heading present only as a summary/checklist line (no matching detail section) now reports a `malformed_roadmap` diagnostic — for both prefixed and bare-number queries — instead of a silent empty result. (#2114) diff --git a/.changeset/rapid-orcas-sing.md b/.changeset/rapid-orcas-sing.md deleted file mode 100644 index 1689b63e7..000000000 --- a/.changeset/rapid-orcas-sing.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -type: Changed -pr: 1934 ---- -**Lazy-split `plan-phase.md` into a `steps/` directory** — ~4.7 KB lighter eager context per `/gsd-plan-phase` call via byte-invariant progressive disclosure (ADR-1610). (#1852) - - diff --git a/.changeset/rapid-pumas-click.md b/.changeset/rapid-pumas-click.md deleted file mode 100644 index 6b057bcb7..000000000 --- a/.changeset/rapid-pumas-click.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 1917 ---- -**`milestone complete --ws` now archives into the workstream instead of root** — the archive paths (MILESTONES.md, the milestones/ archive dir, and the per-version MILESTONE-AUDIT.md) were hardcoded to root `.planning/`, so a workstream milestone close scattered its artifacts into root and never produced a workstream-local archive. They now derive from the workstream-aware planning base (`planningPaths(cwd).planning`); flat-mode (no --ws) is unchanged. (#1911) diff --git a/.changeset/serene-birds-rest.md b/.changeset/serene-birds-rest.md deleted file mode 100644 index b5ecf5a08..000000000 --- a/.changeset/serene-birds-rest.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Added -pr: 1946 ---- -**Host-integration descriptors now carry an `extensionEvents` vocabulary** — the extension-system event surface (OpenCode, pi) is a separate descriptor field from managed `hookEvents`, so OpenCode declares `extensionEvents:opencode` without conflicting with the hooksSurface:none invariant. (#1946) diff --git a/.changeset/serene-lemurs-march.md b/.changeset/serene-lemurs-march.md deleted file mode 100644 index 8f2b0a678..000000000 --- a/.changeset/serene-lemurs-march.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Changed -pr: 1868 ---- -**GSD subagents now self-load configured agent_skills regardless of orchestrator bash** — projects that map skills via `.planning/config.json` `agent_skills.` no longer silently lose them on `/gsd-autonomous` or Cursor, where `Skill()`-delegated workflow bash init did not reliably run. Each of the 22 consumer agents queries its own type at init and reads the listed skills, with a dedup guard so runtimes that also inject orchestrator-side (Claude Code) never carry two copies. (#1866) diff --git a/.changeset/sharp-otters-romp.md b/.changeset/sharp-otters-romp.md deleted file mode 100644 index 24193c9cc..000000000 --- a/.changeset/sharp-otters-romp.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Added -pr: 1766 ---- -**`/gsd-review` now supports custom reviewer instances** — run one model-capable adapter (e.g. OpenCode) as several independent reviewer identities via a bounded `review.reviewer_instances` config, so two different models can review in a single pass without manually swapping config or hand-merging REVIEWS.md. (#1517) diff --git a/.changeset/silly-moles-romp.md b/.changeset/silly-moles-romp.md deleted file mode 100644 index b8f463969..000000000 --- a/.changeset/silly-moles-romp.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Added -pr: 2183 ---- -**Opt-in git branch and working-state segment in the statusline** — the shell prompt's branch/dirty-state signal is hidden for the whole session under the Claude Code TUI, so wrong-branch commits and ship-time push rejections surface only after the fact. New `statusline.show_git` config (default `false`) renders the branch name plus staged/unstaged/untracked/ahead/behind markers (or ✓ when clean and in sync) after the directory segment. When disabled, no git subprocess is spawned and output is unchanged. (#2163) diff --git a/.changeset/silly-pandas-gather.md b/.changeset/silly-pandas-gather.md deleted file mode 100644 index 075f7e276..000000000 --- a/.changeset/silly-pandas-gather.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2248 ---- -**`phase complete` now reads milestone-grouped ROADMAP progress tables** — progress reported 0% on projects whose Progress table carries a Milestone column, because the reader assumed a fixed column position; it now resolves progress columns by name so both flat and milestone-grouped tables work (#2137). Quick Tasks logging via `/gsd:fast` also appends schema-correct, lock-safe rows instead of guessing the column count in shell (#2133). (#2248) diff --git a/.changeset/steady-ibex-run.md b/.changeset/steady-ibex-run.md deleted file mode 100644 index bf1b37a3b..000000000 --- a/.changeset/steady-ibex-run.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2049 ---- -**Skill-bearing capabilities now surface correctly on flat command-layout installs** — on an install using the flat `commands/gsd-.md` source layout (e.g. a Claude Code local project install with no `commands/gsd/` subdir), every skill-bearing capability (`nyquist`, `code-review`, `security`, `ui`, `mempalace`, `ai-integration`, `profile-pipeline`) was silently reported `surfaced:false`/`enabled:false`/`active:false`, so their loop hooks (`verify:post`, `execute:post`, etc.) never fired even with the corresponding `workflow.*` toggle on. The skill-manifest resolver now detects the flat layout and produces the same stems the nested `commands/gsd/*.md` loader does. (#1858) diff --git a/.changeset/steady-lynx-fly.md b/.changeset/steady-lynx-fly.md deleted file mode 100644 index ef8bc0678..000000000 --- a/.changeset/steady-lynx-fly.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2253 ---- -**Roadmap, requirements, and state table edits are confined to the right table** — the last ad-hoc table writers (phase completion updating roadmap progress, `requirements mark-complete`, and `state record-metric`/velocity) now route through the shared markdown-table seam, so a stray decoy table elsewhere in a document can no longer swallow a phase-progress update, a single ragged neighbouring row no longer silently aborts the whole edit, and per-plan metric recording no longer drops trailing section content or duplicates the section. (#2253) diff --git a/.changeset/steady-mice-frolic.md b/.changeset/steady-mice-frolic.md deleted file mode 100644 index d5bb4f8d6..000000000 --- a/.changeset/steady-mice-frolic.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Added -pr: 1994 ---- -**`/gsd:onboard` guides brownfield setup** — existing repos now have a top-level onboarding command that routes through codebase mapping, docs ingest, project initialization, and an onboarding summary without silently overwriting planning files. diff --git a/.changeset/sturdy-voles-dart.md b/.changeset/sturdy-voles-dart.md deleted file mode 100644 index 608c1b962..000000000 --- a/.changeset/sturdy-voles-dart.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -type: Changed -pr: 1800 ---- -**Internal: install/uninstall runtime labels are now sourced from a single `getRuntimeLabel` lookup** — the two duplicated `runtimeLabel` assignment chains in `bin/install.js` (uninstall + install) are collapsed into one curated label table in `runtime-name-policy.cts`, sibling to the registry-derived `getDirName` (ADR-1239 Phase B, #1679). Install output is byte-identical for all 16 runtimes (golden-parity asserted). Two console-label inconsistencies are normalized as a side effect: `kimi` shows 'Kimi CLI' in both sites, and `cline` uninstall no longer falls through to 'Claude Code'. - - diff --git a/.changeset/sturdy-voles-tumble.md b/.changeset/sturdy-voles-tumble.md deleted file mode 100644 index 0a6c36ead..000000000 --- a/.changeset/sturdy-voles-tumble.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2250 ---- -**ROADMAP phase edits can no longer escape their section** — completing a phase updated its plan count and per-plan checkboxes with whole-document regexes that could bleed into a neighbouring phase; those per-phase writes are now structurally bounded to the phase own section via a new `withSection` / `withPhaseSection` seam (#2130, #2067, #2080). (#2250) diff --git a/.changeset/sturdy-wolves-gather.md b/.changeset/sturdy-wolves-gather.md deleted file mode 100644 index ec4efcef9..000000000 --- a/.changeset/sturdy-wolves-gather.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2253 ---- -**STATE.md `## Session` fields now resolve on Windows** — the session-section reader used a `\n`-only heading regex that silently failed on a CRLF `## Session` heading, nulling all session state on Windows checkouts; it now reads through the CRLF-safe section seam. (#2253) diff --git a/.changeset/sturdy-yaks-caper.md b/.changeset/sturdy-yaks-caper.md deleted file mode 100644 index f453fcf0d..000000000 --- a/.changeset/sturdy-yaks-caper.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2228 ---- -**Bullet/em-dash ROADMAP phases no longer resolve to `Phase null`** — the roadmap phase lookup matched only ATX headings with a colon, so a bullet entry like `- [ ] **Phase N — Name**` (which the roadmapper emits) failed to resolve and `Phase null` landed in STATE.md; a bullet-only ROADMAP also broke the milestone phase count. Phase lookup and the milestone filter now accept bullet/checkbox entries with an em-dash/en-dash/hyphen/colon separator. (#2199) diff --git a/.changeset/tidy-badgers-caper.md b/.changeset/tidy-badgers-caper.md deleted file mode 100644 index e94bdb89c..000000000 --- a/.changeset/tidy-badgers-caper.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2225 ---- -**Linuxbrew users no longer lose all GSD-managed hooks after `brew upgrade node`** — normalizeNodePath only recognized macOS Homebrew Cellar paths, so on Linux the version-pinned node path stayed baked into hook commands and 404'd after a node bump (and reinstall couldn't repair it). It now rewrites any Homebrew Cellar path — Intel, Apple Silicon, Linuxbrew, custom HOMEBREW_PREFIX — to the stable `/bin/node` symlink. (#2185) diff --git a/.changeset/tidy-bears-swim.md b/.changeset/tidy-bears-swim.md deleted file mode 100644 index a20786cd2..000000000 --- a/.changeset/tidy-bears-swim.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2131 ---- -**`milestone complete` no longer corrupts the recorded phase** — closing a milestone (e.g. `v0.5`) previously overwrote `current_phase` in STATE.md with the version's minor digit, and a follow-up `state complete-phase` mined a bogus `0.5` token and rewrote the file; phase resolution is now anchored so the real phase is preserved and a milestone-closure line is rejected. (#2111) diff --git a/.changeset/tidy-elks-sing.md b/.changeset/tidy-elks-sing.md deleted file mode 100644 index 3a5ca61c0..000000000 --- a/.changeset/tidy-elks-sing.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2260 ---- -**Headless MemPalace capture no longer fails silently** — the headless invocation `mempalace mine --wing --room ` used a `--room` flag that does not exist on the `mine` subcommand (only `search` accepts `--room`), causing every headless/no-MCP capture run to fail with `unrecognized arguments: --room` and silently skip (onError: skip). The fix replaces the flag with MemPalace's documented room-assignment mechanism: stage the artifact under a room-named subfolder with a `mempalace.yaml` taxonomy so `detect_room()` assigns it via folder-path match. (#2220) diff --git a/.changeset/tidy-mice-cheer.md b/.changeset/tidy-mice-cheer.md deleted file mode 100644 index 7bb88d225..000000000 --- a/.changeset/tidy-mice-cheer.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Added -pr: 1767 ---- -**Plural/optional/chosen assumption-delta checkpoint during planning** — when a phase makes something plural, optional, or chosen that used to be singular, required, or derived, the planner is now prompted to re-ask whether the primary key / identity model still names the right thing, preventing silent architectural drift from accumulating into a later user-facing bug. Advisory (non-blocking); fires only on a detected signal. Toggle with workflow.assumption_delta. (#1561) diff --git a/.changeset/tidy-pumas-munch.md b/.changeset/tidy-pumas-munch.md deleted file mode 100644 index 5fa63d5a3..000000000 --- a/.changeset/tidy-pumas-munch.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 1909 ---- -Fixed: a hand-authored non-inferable backstop truth with a stray trailing space or surrounding quotes no longer silently grades green — it correctly abstains (insufficient_spec), restoring the #1154 honest-verifier guarantee. diff --git a/.changeset/tidy-tunas-click.md b/.changeset/tidy-tunas-click.md deleted file mode 100644 index 68724cb7e..000000000 --- a/.changeset/tidy-tunas-click.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Security -pr: 1725 ---- -**Installer writes are now confined to the declared config home** — the workflow/skill emit path (`copyWithPathReplacement`) and the Codex config writer (`installCodexConfig`) now reject any destination that escapes the install root: crafted or absolute paths, path-separator agent names, and pre-existing symlinks are refused before any delete or write. Fail-closed: an install write with no declared root is rejected rather than written unconfined. diff --git a/.changeset/tidy-voles-glide.md b/.changeset/tidy-voles-glide.md deleted file mode 100644 index 92bd662ce..000000000 --- a/.changeset/tidy-voles-glide.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2235 ---- -**`commit_docs` no longer silently disables on CRLF `.gitignore` repos** — git check-ignore falsely reports a trailing-slash path (e.g. `.planning/`) as ignored when the .gitignore has CRLF line endings with blank lines. isGitIgnored now strips trailing slashes before querying, so the false positive cannot occur. (#2206) diff --git a/.changeset/tidy-zebras-hum.md b/.changeset/tidy-zebras-hum.md deleted file mode 100644 index 53dcfd099..000000000 --- a/.changeset/tidy-zebras-hum.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2262 ---- -**Phase-directory resolution fails loud on cross-project collisions** — when two unrelated GSD projects share a `.planning/phases/` tree, a bare phase number silently resolved to the first `0N-*` directory found. The fix detects multiple matches and surfaces an `ambiguous_matches` result. (#2237) diff --git a/.changeset/vivid-foxes-click.md b/.changeset/vivid-foxes-click.md deleted file mode 100644 index e814c6865..000000000 --- a/.changeset/vivid-foxes-click.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Removed -pr: 1996 ---- -**Removed the sunset Gemini CLI runtime — use Antigravity CLI instead** — Google discontinued Gemini CLI on 2026-06-18, so `npx gsd-core --gemini` now prints a deprecation notice and points you to Antigravity CLI (the official successor), which GSD already ships as a first-class runtime. (#1928) diff --git a/.changeset/vivid-goats-run.md b/.changeset/vivid-goats-run.md deleted file mode 100644 index 7cf65dbbc..000000000 --- a/.changeset/vivid-goats-run.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2263 ---- -**`scanPhasePlans` no longer counts PLAN-REVIEW artifacts as executable plans** — `*-PLAN-REVIEW.md` files were counted by the loose `/PLAN/i` fallback. The fix adds a `PLAN_REVIEW_RE` exclusion before the fallback. (#2252) diff --git a/.changeset/vivid-orcas-chatter.md b/.changeset/vivid-orcas-chatter.md deleted file mode 100644 index f04fbade6..000000000 --- a/.changeset/vivid-orcas-chatter.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Added -pr: 1979 ---- -**`/gsd-ui-phase` now probes UI state coverage** — a new `ui-consideration-probe` (the third `probe-core` adapter) enumerates the shape-rooted UI states a UI-SPEC must resolve (empty/loading/error/populated/partial/overflow/zero-one-many/long-text). After the UI checker approves, the probe surfaces applicable considerations for each element, records a `## UI Considerations` section in the UI-SPEC, and plan-phase lifts each resolved consideration into `must_haves` — so a purely-visual state with no wired test routes to `insufficient_spec → human_needed` at verify rather than a silent pass. diff --git a/.changeset/vivid-seals-purr.md b/.changeset/vivid-seals-purr.md deleted file mode 100644 index 63c2649d7..000000000 --- a/.changeset/vivid-seals-purr.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Added -pr: 1690 ---- -**Host-Integration Interface (ADR-1239 Phase A)** — a versioned, negotiated capability contract (`runtime.hostIntegration`) over the six host-integration points (command, dispatch, model, hooks, state, artifact). Adds an in-process `negotiateHostCapabilities` handshake that fail-closes on undeclared/unknown/`undocumented` values (`effective ⊆ host-declared ∩ engine-known`), a typed degradation ladder, host-capability profiles, and a documentation-sourced per-CLI capability matrix for all 16 runtimes. Interface-definition only — no change to install behaviour. diff --git a/.changeset/wise-elks-caper.md b/.changeset/wise-elks-caper.md deleted file mode 100644 index 6fe2c999f..000000000 --- a/.changeset/wise-elks-caper.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -type: Changed -pr: 1806 ---- -**Internal: external-descriptor trust gate — load-time `configHome` confinement** — `assertDescriptorConfined(descriptor, configHome)` (new `src/external-descriptor-trust.cts`) fail-closed rejects any installed third-party host-plugin descriptor whose declared `destSubpath` resolves outside the user-approved `configHome`, before its install plan runs (ADR-1239 Phase C-2 / #1681 slice 1). Defense-in-depth load-time twin of Phase 2's install-time `assertDestWithinConfigHome`. Not yet wired into the loader (slice 2). No user-facing change. - - diff --git a/.changeset/witty-dogs-hop.md b/.changeset/witty-dogs-hop.md deleted file mode 100644 index 98c5f1d13..000000000 --- a/.changeset/witty-dogs-hop.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Fixed -pr: 2209 ---- -**Milestone audit no longer flags a not-yet-validated phase as a Nyquist failure** — a phase that was planned but never run through `validate-phase` now reports as NOT-VALIDATED (a "run validate-phase" TODO) instead of collapsing into PARTIAL alongside phases whose validation genuinely failed. (#2117) diff --git a/.changeset/witty-seals-snooze.md b/.changeset/witty-seals-snooze.md deleted file mode 100644 index 31d48e0d7..000000000 --- a/.changeset/witty-seals-snooze.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -type: Changed -pr: 1801 ---- -**Internal: the installer's runtime → global-config-home hook-pathogen fragment is now a single `getGlobalConfigHomeFragment` lookup** — the 14-branch `if (runtime === 'x') return "'...'"` chain in `getConfigDirFromHome` (`bin/install.js`, the hook `path.join()` codegen mapping) is collapsed into one table in `runtime-name-policy.cts`, sibling to `getRuntimeLabel` (ADR-1239 Phase B, #1679 AC2 slice 2). Generated hook output is byte-identical for all 16 runtimes (golden-parity asserted); antigravity's dynamic env-overridable resolution is preserved in the caller. No user-facing change. - - diff --git a/.changeset/zcode-runtime-1925.md b/.changeset/zcode-runtime-1925.md deleted file mode 100644 index 16adbc0e4..000000000 --- a/.changeset/zcode-runtime-1925.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Added -pr: 2039 ---- -**ZCode (Z.ai) is now an installable runtime** — a desktop Agentic Development Environment for the GLM-5.2 model can now be targeted with `--zcode`, landing GSD skills at `~/.zcode/skills//SKILL.md` plus slash commands and subagents. ZCode ships as a pure declarative capability descriptor (`capabilities/zcode/capability.json`) with zero hardcoded `runtime === 'zcode'` branches, reusing the Claude skill converter — the de-hardcoded, data-driven runtime path that 1.7.0 (ADR-1016 / ADR-1239) enables. (#1925) diff --git a/.changeset/zesty-rams-march.md b/.changeset/zesty-rams-march.md deleted file mode 100644 index 1b66f6a2e..000000000 --- a/.changeset/zesty-rams-march.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: Security -pr: 1706 ---- -**Install write-confinement (ADR-1239 Phase B)** — the installer now rejects any runtime-descriptor `destSubpath` that would write or delete outside the user's config home (path traversal, the config root itself, NUL bytes) and refuses to follow a pre-existing symlink that escapes it. Hardening only; no change to legitimate installs. diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a64f2189..2506e0619 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,214 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). ## [Unreleased] +## [1.7.0] - 2026-07-15 + +### Added + +- **A default-off, BETA, claude-only "Claude orchestration" capability** — adopts Claude Code's Workflow tool (`/effort ultracode`, Agent SDK ≥ v0.3.149) as an optional parallel-execution backend for the GSD loop, restoring the wave parallelism + plan-checker + verifier that the #853 backgrounded-agent nesting limitation forces inline on Claude Code, and folding the existing `gsd-ultraplan-phase` plan-offload under the same runtime gate. When `claude_orchestration.enabled` is on AND the runtime is Claude AND the Workflow tool is detected AND the Agent SDK meets the floor (`claude_orchestration.min_agent_sdk_version`, default `0.3.149`), `execute-phase` emits a generated Workflow script (`waves → parallel() barriers`, `plans → agent({ agentType: 'gsd-executor', isolation: 'worktree' })`, `files_modified overlap → separate sequential stages`, `resumeFromRunId` wired to the phase run id, shared `budget` pool) that composes the SAME executor agent + worktree isolation the inline path uses, so artifacts/commits are produced identically. Detection is pure and fail-closed (any miss → inline), so on any runtime lacking the Workflow tool behaviour is byte-identical to today. Adds a pure module `gsd-core/bin/lib/claude-orchestration.cjs` (`detectWorkflowBackend`, `emitWorkflowScript`), the `capabilities/claude-orchestration/` declaration with two gated loop contributions (`execute:wave:post`, `plan:post`) and a `claude-orchestration` command family (`gsd-tools claude-orchestration detect-backend|emit-workflow`), federated config keys, and an ADR-1143 implementation amendment. (#1143) (#2044) +- **Phases that integrate an external API/SDK/service can no longer seal without a decided coverage matrix** — a new `api-coverage` gate on the `ai-integration` capability blocks `/gsd:verify-work` until the phase produces a `COVERAGE.md` enumerating the API's full capability surface, with every non-integrated capability an explicit, reasoned opt-out. Full coverage is the default; the matrix is the subtraction record, so "we integrated the API" can no longer silently mean "we integrated whatever the first use case exercised." Toggleable via `workflow.api_coverage_gate` (on by default). (#1562) (#2065) +- +**OpenCode installs now auto-register the GSD companion MCP server (`mcp.gsd`)** — `--opencode` install writes a `mcp.gsd` entry (local stdio → `gsd-mcp-server`) into `opencode.json`, so OpenCode drives GSD's command + planning-state surface over MCP with no bespoke plugin (ADR-1239 Phase D / #1682). Idempotent and non-clobbering; a user-defined `mcp.gsd` is preserved. (#1682) (#1929) +- +**OpenCode plugin handles `session.idle` + the `opencode-subset` hook dialect is implemented** — the GSD OpenCode plugin now recognizes `session.idle` (↔ Claude `Stop` lifecycle point), completing the compaction/idle pair (#1914 shipped compaction). The reserved `opencode-subset` dialect gains a consumer — `hookEventSurfaceFor()` in `host-integration.cts` — describing OpenCode's session/tool/file event subset (no workflow-phase events; the engine owns phase sequencing, ADR-1239 §OpenCode binding). Adds a Claude-parity test asserting the plugin covers the full declared subset. (#1682) (#1930) +- **GSD now warns when model config changed without re-running the installer on static-frontmatter runtimes** — on `codex` and `opencode`, editing `model_overrides` or `model_profile_overrides` or `model_policy.runtime_tiers` in `.planning/config.json` or `~/.gsd/defaults.json` previously had no effect until the user re-ran `gsd install `, and the failure was silent: the sub-agent kept using the base model. Workflow entry points like `gsd-tools init *` now emit a one-line stderr warning naming the changed config file and the exact remediation command when they detect the config is newer than the baked agent files. The guard is read-only and warning-only by default, dedup'd per session, and skipped entirely on Claude Code because Claude Code resolves models at spawn time. Resolves #1688 as the structural follow-up to #1650. (#1692) +- **`gsd-tools state rebuild`** — new subcommand that re-derives STATE.md body structure from canonical sources (frontmatter + `.planning/phases/` disk scan), reconciling drifted `## Current Position` prose, dropping orphaned rows from the `**By Phase:**` table, clearing template-placeholder field values, and de-duplicating `## Session Continuity Archive` blocks. Every mutation is recorded in a `## Rebuild Log` audit section. Idempotent (running twice on a clean file is a no-op). Supports `--dry-run` (preview) and `--verbose` (tee log to stderr). Heavier, manual counterpart to the lightweight auto-triggered `state sync`. (#1830) +- **`graphify.graph_path` makes the knowledge-graph location configurable so one umbrella graph can serve multiple projects** — a new `.planning/config.json` key (path relative to project root, or absolute) overrides where `/gsd-graphify query|status|diff` read the graph, letting a single curated cross-repo umbrella graph serve every sibling sub-project without N drifting ~5 MB mirror copies. Previously the graph location was hardcoded to `/.planning/graphs/` with no override; the only workaround was copying the umbrella `graph.json` into each project (which drifted, wasted disk, and could be silently overwritten by an in-project build). The diff snapshot travels with the configured graph; build stays project-scoped; unset → byte-identical default; a configured-but-missing file yields an actionable error naming the path. (#1825) (#2013) +- **Claude Sonnet 5 is now the `standard` (sonnet) tier model.** The model catalog and provider presets resolve the sonnet/standard tier to `claude-sonnet-5` (GA 2026-06-30) across the Anthropic-backed runtimes (`claude`, `copilot`, and the `anthropic`/`anthropic-fable` presets), plus the OpenRouter-style `anthropic/claude-sonnet-5` for `opencode`/`hermes`, replacing the superseded `claude-sonnet-4-6`. Opus and Haiku tier defaults are unchanged (the `haiku` high-effort preset's escalation slot tracks the current sonnet model). Shipped in 1.6.1. (#1847) (#1848) +- **Third-party capability gates now actually fire via a generic `command-exit-zero` predicate.** — a capability's declared `check.predicate` gate was rendered for display but never evaluated (only built-in `check.query` gates were enforced, and the `security` capability's gate worked solely via a hard-coded `ship.md` branch). A new generic evaluator (`gsd_run check predicate`) now evaluates `check.predicate` blocks by `kind`; the first built-in kind `command-exit-zero` runs a bounded `sh -c` command at the project root and blocks the loop on non-zero exit (timeout → block, fail-closed). The `execute:wave:post`, `execute:post`, and `plan:post` gate-dispatch sites route `predicate` gates to the new evaluator automatically. (#2008) (#2011) +- **GSD's lifecycle hooks now run under Kimi CLI** — installing GSD into Kimi wires its session-state, phase-boundary, graphify, and guard hooks into Kimi's own native `config.toml` `[[hooks]]` bus (Beta on Kimi's side) instead of silently no-op'ing, and GSD's Kimi subagents can now run in the background. Kimi's install is driven by its negotiated capability descriptor instead of hardcoded runtime special-cases. (#2095) (#2159) +- **GSD is now installable on pi** — `npx @opengsd/gsd-core --pi` installs the GSD extension to `~/.pi/agent/extensions/gsd.cjs`, and `/gsd ` now dispatches real commands through the embedded engine (the reference binding previously could only run `query help`). Drives pi through the negotiated imperative Host-Integration adapter, with active-model steering and the full pi lifecycle-event surface. (#2102) (#2205) +- +**GSD now ships a pi extension** — a real, jiti-loadable ExtensionAPI module (`pi/gsd.cjs`) that registers `/gsd` (dispatches through the GSD command-routing hub) + `gsd_invoke` tool + `tool_call` event, installable at `~/.pi/agent/extensions/`. A reachability test proves the `/gsd` handler dispatches through the engine (keystone wired, not just registered on a mock). (#1965) (#1965) +- `plan-phase` now authors edge and prohibition predicates into PLAN.md `must_haves` when a phase SPEC omits `## Edge Coverage` / `## Prohibitions`, so goal-backward verification still has predicates to check on a spec-less phase (ADR-857 Phase 6). Gated by the new default-on `workflow.specless_probe_fallback` toggle — disable it to skip the fallback (the skip is recorded visibly in the plan). Spec-less prohibitions are authored descriptor-less and disposed flagged/unverified (honest verifier #1154), never a silent pass. (#1835) +- **Discover third-party GSD Capabilities in a new Community Capability Registry.** — A non-endorsing discoverability catalog where authors register a Capability via a documentation PR; each entry carries a live latest-release badge and a per-entry GitHub Discussion for community ranking and comments. (#2188) (#2188) +- **GSD now warns when a stale global CLI (e.g. a retired @gsd-build/sdk canary) shadows your project-local install** — the gsd-tools CLI startup detects when the running binary is outside the project root while a project-local install exists, and prints a remediation warning to stderr (non-blocking). (#1754) (#1755) +- **`gsd-mcp-server` — companion MCP server (interface points 1 + 5)** — a new bin command (`npx @opengsd/gsd-core gsd-mcp-server`) runs a stdio JSON-RPC 2.0 MCP server exposing `gsd_invoke_command` (→ the GSD command-routing hub) + `gsd_read_state` / `gsd_write_state` (→ `.planning/` state), so any MCP-consuming host (Claude Code, Codex, OpenCode, VS Code, Gemini CLI, Cursor, Cline, Hermes) can drive GSD with no bespoke plugin (ADR-1239 Phase C-2 / #1681). Dependency-free (hand-rolled JSON-RPC). How-to: `docs/how-to/connect-gsd-mcp-server.md`. (#1810) +- **Opt-in absolute token count on the statusline context meter** — new `statusline.show_context_tokens` config (default `false`). When enabled, the meter shows the absolute context total after the percentage, e.g. "████░░░░░░ 46% (156k)", summing input, cache-creation, cache-read, and output tokens from the hook payload (a broader basis than the meter's percentage, which is derived from `used_percentage` and excludes output tokens — the two figures can diverge slightly). Default meter output is unchanged. (#2161) (#2174) +- **Long-running compute can now be externalized as async external jobs instead of blocking the agent turn** — a default-off external-job capability lets executors submit SLURM jobs, commit a .planning/async-jobs manifest, defer SUMMARY.md, and return external_job_waiting; the core loop already reconciles these manifests (#1165), so this adds the producer half (SLURM adapter, pure manifest module, planner/executor fragments, operation policy). (#1105) (#1998) +- +**GSD now ships a repo-local VS Code extension** — a buildable extension (`vscode/extension.js` + `vscode/package.json`) that registers `gsd.invoke` (dispatches through the GSD command-routing hub) in the VS Code command palette. A reachability test proves the handler dispatches through the engine (keystone wired). Not Marketplace-published; mirrors the OpenCode plugin's bar. (#1966) (#1966) +- **Discover third-party GSD Embeddable Orchestration System (EoS) integrations in a new EoS Registry.** — A non-endorsing discoverability catalog where host-integration authors register via a documentation PR; each entry declares its Host-Integration interface points, negotiated axes, and protocol version, with a live release badge and a per-entry GitHub Discussion for ranking and comments. (#2193) (#2193) +- GSD Core ships a `.claude-plugin/marketplace.json` marketplace manifest so Claude-plugin-compatible runtimes (ZCODE et al.) can discover and install gsd-core from a custom marketplace source. Additive — the existing `.claude-plugin/plugin.json` and the Claude Code install path are unchanged. The catalog version (`plugins[0].version`) tracks `package.json` via the release version-sync. (#1861) +- **GSD now drives VS Code through the Embeddable Orchestration System** — the VS Code extension is rewired through the negotiated imperative Host-Integration adapter (active `vscode.lm` model, engine hook bus, sandboxed storage), gains native Language Model Tools (GSD skills as `#gsd-*` tools) and `#runSubagent` dispatch, and runs as a Web Extension (no Node APIs). (#2103) (#2210) +- **`/gsd:next` smart-entry workflow** — adds a state-aware entry point that classifies the current project situation (no-project, blocked, verify-failed, planning, executing, verify-pending, complete, and more) and recommends the right next GSD command. The `gsd-tools smart-entry [--json]` classifier handles phase ordering including decimal phase IDs; the `/gsd:next` skill surfaces the workflow with tiered fallback behavior. (#1798) +- OpenCode now runs GSD's lifecycle safety hooks (prompt-injection guard, read-before-edit guard, injection scanner, worktree/workflow guards, context monitor) via a native plugin installed to `~/.config/opencode/plugins/gsd-core.js`. OpenCode declares `hooksSurface: 'none'`, so these hooks were previously inert; the plugin bridges OpenCode's event bus onto GSD's existing hook scripts. Installed automatically by `npx @opengsd/gsd-core --opencode` and removed on uninstall. (#1923) +- **Host-integration descriptors now carry an `extensionEvents` vocabulary** — the extension-system event surface (OpenCode, pi) is a separate descriptor field from managed `hookEvents`, so OpenCode declares `extensionEvents:opencode` without conflicting with the hooksSurface:none invariant. (#1946) (#1946) +- **`/gsd-review` now supports custom reviewer instances** — run one model-capable adapter (e.g. OpenCode) as several independent reviewer identities via a bounded `review.reviewer_instances` config, so two different models can review in a single pass without manually swapping config or hand-merging REVIEWS.md. (#1517) (#1766) +- **Opt-in git branch and working-state segment in the statusline** — the shell prompt's branch/dirty-state signal is hidden for the whole session under the Claude Code TUI, so wrong-branch commits and ship-time push rejections surface only after the fact. New `statusline.show_git` config (default `false`) renders the branch name plus staged/unstaged/untracked/ahead/behind markers (or ✓ when clean and in sync) after the directory segment. When disabled, no git subprocess is spawned and output is unchanged. (#2163) (#2183) +- **`/gsd:onboard` guides brownfield setup** — existing repos now have a top-level onboarding command that routes through codebase mapping, docs ingest, project initialization, and an onboarding summary without silently overwriting planning files. (#1994) +- **Plural/optional/chosen assumption-delta checkpoint during planning** — when a phase makes something plural, optional, or chosen that used to be singular, required, or derived, the planner is now prompted to re-ask whether the primary key / identity model still names the right thing, preventing silent architectural drift from accumulating into a later user-facing bug. Advisory (non-blocking); fires only on a detected signal. Toggle with workflow.assumption_delta. (#1561) (#1767) +- **`/gsd-ui-phase` now probes UI state coverage** — a new `ui-consideration-probe` (the third `probe-core` adapter) enumerates the shape-rooted UI states a UI-SPEC must resolve (empty/loading/error/populated/partial/overflow/zero-one-many/long-text). After the UI checker approves, the probe surfaces applicable considerations for each element, records a `## UI Considerations` section in the UI-SPEC, and plan-phase lifts each resolved consideration into `must_haves` — so a purely-visual state with no wired test routes to `insufficient_spec → human_needed` at verify rather than a silent pass. (#1979) +- **Host-Integration Interface (ADR-1239 Phase A)** — a versioned, negotiated capability contract (`runtime.hostIntegration`) over the six host-integration points (command, dispatch, model, hooks, state, artifact). Adds an in-process `negotiateHostCapabilities` handshake that fail-closes on undeclared/unknown/`undocumented` values (`effective ⊆ host-declared ∩ engine-known`), a typed degradation ladder, host-capability profiles, and a documentation-sourced per-CLI capability matrix for all 16 runtimes. Interface-definition only — no change to install behaviour. (#1690) +- **ZCode (Z.ai) is now an installable runtime** — a desktop Agentic Development Environment for the GLM-5.2 model can now be targeted with `--zcode`, landing GSD skills at `~/.zcode/skills//SKILL.md` plus slash commands and subagents. ZCode ships as a pure declarative capability descriptor (`capabilities/zcode/capability.json`) with zero hardcoded `runtime === 'zcode'` branches, reusing the Claude skill converter — the de-hardcoded, data-driven runtime path that 1.7.0 (ADR-1016 / ADR-1239) enables. (#1925) (#2039) + +### Changed + +- +**The GSD CLI now self-heals a missing runtime build.** The compiled `gsd-core/bin/lib/*.cjs` modules are gitignored build artifacts (ADR-457) that ship prebuilt in the npm tarball but are absent on a Claude Code plugin-marketplace / git-clone install, which never runs `npm run build:lib`. Previously every command died at load with `Cannot find module './lib/cli-exit.cjs'`. The `gsd-tools` entrypoint now detects the missing output and compiles it once, on demand (lock-guarded so parallel invocations don't race), then proceeds — a single no-op check on the already-built npm path. When TypeScript is genuinely unavailable it prints an actionable `npm install && npm run build:lib` message instead of crashing. (#2036) +- **Internal: Claude Code's installer is now driven through the public Host-Integration Interface (ADR-1239 / EoS).** `bin/install.js` routes `claude` install/uninstall through the imperative adapter (`createImperativeAdapter`) instead of calling the engine directly, and its 13 hardcoded `runtime === 'claude'` / `runtime !== 'claude'` branches are folded into descriptor-driven `runtime.hostBehaviors` on `capabilities/claude/capability.json` (permission schema, `settings.local.json` scope routing, `.gsd-source` marker, effort frontmatter, canonical-workflow authorship, and more). Install/uninstall output is **byte-identical** for both the global skills layout and the local legacy layout (golden-parity asserted for both scopes); no other runtime changes. Removes the "add-a-host tax" of scattered string-equality checks for the tier-1 reference host. No user-facing change. (#2086) (#2106) +- **OpenCode is now driven through the public Host-Integration Interface, with two capability upgrades (ADR-1239 / EoS).** OpenCode and its Kilo sibling previously installed via a bespoke `runtime === 'opencode'`/`isOpencode` branch in `bin/install.js`; its commands+skills+plugin install now runs through the imperative adapter → the engine's combined-family install path (`installRuntimeArtifacts`), and every hardcoded `runtime === 'opencode'` branch is folded into descriptor-driven `runtime.hostBehaviors`. Install/uninstall output is **byte-identical** (golden parity asserted for all 16 runtimes). Two Context7-verified upgrades land: (1) **background dispatch** — OpenCode shipped experimental background subagents in v1.15 and made them default-on in v1.17, so `dispatch.background`/`backgroundDispatch` flip to `true`; GSD no longer force-flattens OpenCode-hosted wave dispatch (`shouldFlattenDispatch` now returns `false`), letting agents run concurrently where the host supports it. (2) **expanded event surface** — the OpenCode plugin now subscribes to `permission.asked`, `permission.replied`, and `session.error` (added to `EXTENSION_EVENT_SURFACES.opencode`), wiring the declared surface for future permission/error-aware bindings. (#2087) (#2108) +- **Codex is now driven through the public Host-Integration Interface, with three capability upgrades (ADR-1239 / EoS).** Codex previously installed via hardcoded `runtime === 'codex'`/`isCodex` projection in `bin/install.js`; its `config.toml` / agent-`.toml` / `hooks.json` install now runs through the declarative embedding adapter and descriptor-driven `runtime.hostBehaviors`, with **zero** positive `isCodex` gates and **zero** `runtime === 'codex'` branches remaining (source-guarded). Install/uninstall output stays byte-parity-gated (`tests/fixtures/golden-install-parity/codex.json`). Three Context7-verified upgrades land, each with a test driving the user-reachable surface: (1) **skill root** — GSD skills now install to Codex's canonical `$HOME/.agents/skills` (via a skills-kind `home` override) instead of the deprecated `$CODEX_HOME/skills` fallback, and pre-move installs are migrated (stale `~/.codex/skills/gsd-*` cleaned on both install and uninstall, user-owned content preserved); (2) **hook events** — GSD registers the six documented Codex lifecycle events it previously skipped (`PreToolUse`, `PermissionRequest`, `PreCompact`, `PostCompact`, `SubagentStop`, `UserPromptSubmit`, in addition to the existing `SessionStart`/`SubagentStart`/`Stop`/`PostToolUse`) in `hooks.json`, so `gsd-context-monitor` fires at the same points as in Claude Code, and the descriptor `extendedHookEvents` is reconciled from `[]` to the schema-valid wired subset; (3) **dispatch tuning** — `[agents] max_depth = 1` is written explicitly into the managed `config.toml` block to pin the negotiated `dispatch.maxDepth: 1` axis (`degradationFor` flattens GSD-hosted waves to single-level), and `validateCodexConfigSchema` now permits a known-scalar-only `[agents]` AgentsToml table (coexisting with the flattened `[agents.gsd-*]` role sub-tables) while still rejecting the `[[agents]]` and unknown-key break-forms from #2760. (#2088) (#2110) +- **Cursor is now driven through the public Host-Integration Interface, with two capability upgrades (ADR-1239 / EoS).** Cursor previously installed via hardcoded `runtime === 'cursor'`/`isCursor` branches in `bin/install.js`; its install/uninstall now runs through the imperative adapter, and every hardcoded cursor branch is folded into descriptor-driven `runtime.hostBehaviors` (reapplyCommand, frontmatterDialect, hooksJsonSurface, skipSharedHooksInstall, reportCommandsDir, managedHookEvents). Install/uninstall output is **byte-identical** (golden parity asserted for all 16 runtimes). Two Context7-verified upgrades land: (1) **expanded hook-bus coverage** — GSD registers all 6 managed lifecycle events in Cursor's `hooks.json` (`preToolUse`, `stop`, `subagentStart`, `subagentStop` in addition to the original `sessionStart`/`postToolUse`), driven by a new descriptor-driven adapter module (`src/host-integration-adapters/imperative-hook-bus.cts`) that reads `hostBehaviors.managedHookEvents` instead of a hardcoded event pair; cite https://cursor.com/docs/hooks. (2) **named/background nested subagent dispatch** — Cursor's `dispatch.background`/`backgroundDispatch`/`nested` are all `true` with `maxDepth: 2`, so `shouldFlattenDispatch(cursor)` returns `false` and GSD's wave-based execution drives Cursor's native background + depth-2 nested subagent invocation instead of flattening to inline sequential calls; cite https://cursor.com/docs/subagents + https://cursor.com/docs/sdk/typescript. (#2089) (#2120) +- **Cline is now driven through the public Host-Integration Interface, with two capability upgrades (ADR-1239 / EoS).** Cline previously installed via hardcoded `runtime === 'cline'`/`isCline` branches in `bin/install.js`; its install/uninstall now runs through the imperative adapter, and every hardcoded cline branch is folded into descriptor-driven `runtime.hostBehaviors` (reapplyCommand, frontmatterDialect, skipSharedHooksInstall, localTargetIsProjectRoot, clineRulesSurface, localCommandsViaRules). Install/uninstall output is **byte-identical** (golden parity asserted for cline + claude/cursor/codex/opencode). Two Context7-verified upgrades land: (1) **`AgentPlugin.hooks.beforeTool` planning guard** — the `.clinerules/hooks/PreToolUse` file-convention hook (#787) is re-implemented as a real Cline SDK `AgentPlugin` that cancels write-class calls targeting `.planning/` (same fail-open semantics), driven by a new descriptor-driven adapter module (`src/host-integration-adapters/cline-sdk-binding.cts`); cite https://github.com/cline/cline/blob/main/docs/sdk/plugins.mdx. (2) **`createAgentModel` model overrides** — `DefaultGateway.createAgentModel({providerId, modelId})` is wired so GSD's per-subagent `model_overrides`/`model_profile_overrides` resolution applies to Cline subagents (`modelMode: active`); cite https://github.com/cline/cline/blob/main/docs/sdk/reference/gateway.mdx. Cline's dispatch deliberately stays **degraded/flat** (`maxDepth: 1`, read-only, no nested spawning) per the documented host restriction — never silently upgraded to full nested/background. (#2090) (#2132) +- **Hermes Agent is now driven through the public Host-Integration Interface, with three capability upgrades (ADR-1239 / EoS).** Hermes previously installed via hardcoded `runtime === 'hermes'`/`isHermes` branches in `bin/install.js`; its install/uninstall now runs through the imperative adapter, and every hardcoded hermes branch is folded into descriptor-driven `runtime.hostBehaviors`. Three upgrades land: (1) **real plugin hook vocabulary** — GSD registers a new `extensionEvents: "hermes"` dialect carrying the 13 documented Hermes plugin events (`pre_tool_call`, `post_tool_call`, `pre_llm_call`, `post_llm_call`, `on_session_start`, `on_session_end`, `on_session_finalize`, `on_session_reset`, `subagent_start`, `subagent_stop`, `pre_gateway_dispatch`, `pre_approval_request`, `transform_tool_result`), replacing the borrowed `hookEvents: "claude"` 6-event surface that silently never fired; cite https://github.com/nousresearch/hermes-agent/blob/main/website/docs/user-guide/features/hooks.md. (2) **dispatch posture** — Hermes' `dispatch.nested: true` with `maxDepth: 1` is correctly negotiated (not silently flattened). (3) **branding/category metadata** — `DESCRIPTION.md` category descriptions, `version:` frontmatter, and branding rewrites are now descriptor-driven rather than hardcoded. Install/uninstall output is byte-identical (golden parity asserted for all runtimes). (#2091) (#2134) +- **Qwen Code now projects GSD's specialist agents as native subagents** — installing GSD into Qwen Code writes `~/.qwen/agents/gsd-*.md` files you can invoke directly (planner, executor, code-reviewer, …) instead of reaching them only through skill prose, and a `SubagentStart` hook now fires alongside `SubagentStop`. Qwen's install is driven by its negotiated capability descriptor instead of hardcoded runtime special-cases. (#2092) (#2153) +- **Kilo Code now supports native hooks, active-model routing, and named subagent dispatch** — installing GSD into Kilo wires a lifecycle-hook plugin, keeps each agent's requested model instead of dropping it, projects GSD's specialist agents as invokable subagents, and documents the GSD MCP companion. Kilo's install is driven by its negotiated capability descriptor instead of hardcoded runtime special-cases. (#2093) (#2156) +- **GSD skills installed for Trae now carry SOLO stage metadata** — Trae's SOLO Agent can recognize GSD skills as workflow-stage skills for auto-invocation instead of requiring manual triggering. Several of Trae's install branches (shared-hooks gating, path rewrites) also move onto its capability descriptor. Note: the stage-metadata field is a best-effort/inferred shape — Trae publishes no formal schema. (#2094) (#2157) +- **Installing GSD into Antigravity now writes the `permissions.allow` rules its CLI documents** — so GSD's own reads and hooks aren't stuck on interactive prompts — and registers GSD's companion MCP server via a standalone `mcp_config.json` (best-effort: Antigravity's raw config schema isn't published, so this uses the Gemini-CLI-successor format). Antigravity's install is now driven by its negotiated capability descriptor instead of hardcoded runtime special-cases. (#2096) (#2165) +- +**Augment Code now installs through its capability descriptor, with a native MCP companion** — installing GSD into Augment registers the GSD companion server in Augment's `settings.json` `mcpServers` and drives command/skill/agent conversion from Augment's negotiated descriptor instead of hardcoded runtime special-cases. (#2097) (#2166) +- +**CodeBuddy now wires GSD's full extended lifecycle hook set and is driven by its capability descriptor** — installing GSD into CodeBuddy now registers `SubagentStart`, `SubagentStop`, `Stop`, and `PreCompact` hooks in its `settings.json` (it previously had none of these), matching the coverage Qwen/Kimi already ship, and CodeBuddy's install is fully descriptor-driven instead of via residual hardcoded runtime branches. (#2098) (#2169) +- +**GitHub Copilot now wires GSD's full lifecycle hook bus and is driven by its capability descriptor** — installing GSD into Copilot registers `preToolUse`, `postToolUse`, `userPromptSubmitted`, and `sessionEnd` handlers in its `hooks/gsd-session.json` (beyond today's `sessionStart`-only advisory), and Copilot's residual hardcoded runtime branches are folded onto descriptor-driven `hostBehaviors`. (#2099) (#2172) +- **Windsurf now enforces GSD's write/command safety guards through Cascade's native hook bus** — installing GSD into Windsurf registers blocking `pre_write_code`/`pre_run_command` hooks in `.windsurf/hooks.json` (exit-code-2 blocking) and drives Windsurf's install from its capability descriptor instead of hardcoded runtime branches. (#2100) (#2190) +- **ZCode's install is now driven and regression-tested through its capability descriptor** — ZCode joins the dogfooded declarative-adapter reference hosts with a byte-identical install, and its shared-hooks exclusion is folded onto `hostBehaviors` instead of a hardcoded runtime branch. (Hook-automation and MCP upgrades remain blocked on ZCode publishing its on-disk config formats.) (#2101) (#2195) +- **Codex/OpenAI default models advance to the GPT-5.6 family (Sol/Terra/Luna)** — the Codex runtime tier defaults and the `openai` provider preset now resolve to current-generation model IDs instead of the superseded GPT-5.4/5.5 line, so Codex users on default profiles get improved agentic coding (Sol) and lower costs (Terra/Luna) without changing any config. (#2122) (#2146) +- **Internal: the installer's `program` (display-name) + `command` (slash-invocation) chains are now single-source lookups** — the 14-line `program` chain (an exact duplicate of `runtimeLabel`) → `getRuntimeLabel`, and the 14-line `command` chain (the per-runtime `/gsd-new-project` syntax: gemini `/gsd:`, codex `$`, cursor skill-mention, kimi `/skill:`, default `/gsd-new-project`) → new `getRuntimeNewProjectCommand(runtime)` helper (ADR-1239 Phase B / #1679 AC2 slice 4). `runtime ===` count in `bin/install.js`: 53 → 25 (cumulative this session: 129 → 25). Stdout strings preserved byte-for-byte; no install-output change (golden-parity 16/16). No user-facing change. (#1813) +- **Internal: the installer's per-function `is` flag-declaration blocks are now a single `runtimeFlags` lookup** — the four duplicated `const isX = runtime === 'x'` blocks in `bin/install.js` (uninstall / writeManager / install / a fourth helper — 48 branches) are collapsed into one `runtimeFlags(runtime)` helper in `runtime-name-policy.cts` (ADR-1239 Phase B / #1679 AC2 slice 3). The add-a-host tax for flags is removed (one `RUNTIME_FLAG_IDS` entry, not four declaration blocks). Install output is byte-identical for all 16 runtimes (golden-parity asserted); `runtime ===` count in `bin/install.js`: 101 → 53. No user-facing change. (#1811) +- **Internal: third-party descriptor loader enforces `configHome` write-confinement at load time** — `loadRegistry({includeInstalled:true, configHome})` now rejects (skip + warn, fail-closed) any installed third-party host-plugin descriptor whose declared `destSubpath` resolves outside the supplied `configHome`, before it is composed into the registry (ADR-1239 Phase C-2 / #1681 slice 2). The `configHome` option is optional and backward-compatible (omitted → no load-time check; install-time gate still bounds writes). No user-facing change for existing flows. (#1808) +- **Internal: agent install for cursor/windsurf/augment/trae/codebuddy now flows through the descriptor path** — ADR-1235 step 1 routes the trivial-converter runtime group's agents off the inline install() loop onto the descriptor-driven `installRuntimeArtifacts` path, applying the cross-cutting steps uniformly (pre-converter, no workflow-stamp). Agent output is byte-identical for all 16 runtimes (golden-parity asserted, global + local verified); no user-facing change. (#1764) +- **gsd-ui-checker gains an adversarial FORCE stance (LLM-playbook principle 16)** — the only verdict-producing critic that lacked one now resists rubber-stamping UI-SPEC contracts, with BLOCK/FLAG/PASS classification. Based on arXiv 2505.23840 (third-person objective persona), 2506.04975 (objective-not-hostile persona). (#1584) +- **Internal: the declarative embedding adapter is now named + bound behind a minimal `HostIntegrationInterface`** — `createDeclarativeAdapter({runtime})` (new `src/adapter-declarative.cts`) delegates in-process to `install-engine`'s `installRuntimeArtifacts`/`uninstallRuntimeArtifacts`, formalizing today's projection path as one of the two embedding adapters behind a common contract (ADR-1239 Phase C-1 / #1680 AC1). Output is byte-identical to today's install (gated by `golden-install-parity`). The full 6-point interface binding surface is deferred until the imperative adapter (AC2) fixes the shape (ADR-1239 open wire-shape question). No user-facing change — the adapter is not yet wired to any runtime path. (#1802) +- **Internal: getDirName is now derived from a documented `runtime.localConfigDir` descriptor field** — each runtime's local content-rewrite directory (e.g. `cursor`→`.cursor`, `copilot`→`.github`) moved from a hand-maintained if-chain into its capability descriptor (ADR-1239 Phase B), so it can no longer drift from the registry. Install output is byte-identical for all 16 runtimes (golden-parity asserted); no user-facing change. (#1757) +- **Internal: copyWithPathReplacement converter selection is now data-driven** — the installer's back-compat content-copy path replaced its 13 hardcoded `runtime === 'x'` flag chains with a single per-runtime dispatch table (ADR-1239 Phase B). Install output is byte-identical for all 16 runtimes (golden-parity asserted); no user-facing change. (#1759) +- **Phase-completion now writes `Status: All phases complete` instead of the overloaded bare `Milestone complete`** — the phase-level completion verb (`completePhaseCore`) was writing the same bare 'Milestone complete' string that the milestone-close verb uses for terminal state, causing a phase-level verb to own a milestone-level field. Per ADR-2207, phase-completion now writes the existing intermediate value 'All phases complete' (already used in gsd2-import.cts); milestone termination (' milestone complete' / 'Awaiting next milestone') remains solely with the milestone-close verb. (#2204) (#2259) +- **#853 dispatch-flatten is now data-driven (ADR-1239 Phase B)** — whether GSD backgrounds the plan/execute orchestrator is decided from a documentation-sourced `backgroundDispatch` capability per host (via `gsd_run query dispatch-should-flatten`) instead of a hardcoded `runtime === 'codex'` check. **Cursor now backgrounds the orchestrator** (its docs document backgrounded subagent nesting); codex unchanged; all other hosts run inline. Fail-closed to inline on any uncertainty. (#1719) +- **Internal: companion MCP server module (interface points 1 + 5)** — `handleMessage`/`runServer` (new `src/mcp-server.cts`) is a minimal, dependency-free stdio JSON-RPC 2.0 server exposing `gsd_invoke_command` (→ the command-routing hub) + `gsd_read_state`/`gsd_write_state` (→ the Phase 3 stateIO seam), so any MCP-consuming host can drive GSD with no bespoke plugin (ADR-1239 Phase C-2 / #1681 slice 3a). Bin entry / packaging deferred to slice 3b. No user-facing change — the server is not yet wired to a bin entry. (#1809) +- **`requirements mark-complete` reports a per-surface write-set** — the command now returns a per-requirement `write_set` (checkbox + traceability surfaces) and a `write_set_complete` that is true only when every surface of every requirement applied, so a partial (checkbox-only) reconcile can no longer masquerade as full success even inside a multi-ID batch. Introduces the reusable ADR-2143 §5/§6 `Result` / `WriteSet` contract. (#2251) (#2251) +- **Internal: the imperative embedding adapter now composes the capability registry behind the same `HostIntegrationInterface`** — `createImperativeAdapter({runtime})` (new `src/adapter-imperative.cts`) calls `loadRegistry({includeInstalled:true})` (first-party-wins + consent + fail-closed — identical trust semantics to the CLI) and binds the engine surface behind the same contract the declarative adapter (AC1) satisfies, plus a `registry` accessor for an in-process host to bind its primitives to (ADR-1239 Phase C-1 / #1680 AC2). Concrete host binding is deferred to Phase 5. No user-facing change — the adapter is not yet wired to any runtime path. (#1803) +- **Internal: the model adapter seam exposes `passive` + `active` adapters selected by `modelMode`** — `createModelAdapter({modelMode})` (new `src/model-adapter.cts`): `passive` formalizes today's tier routing (delegates to `model-resolver.resolveModelForTier`), `active` is a host-supplied `sendRequest` seam (VS Code `vscode.lm` / pi providers), fail-closed until Phase 5 binds a concrete provider (ADR-1239 Phase C-1 / #1680 AC3). No user-facing change — the seam is not yet wired to any runtime path. (#1804) +- **Internal: derive the non-Claude runtime list from the capability registry** — `NON_CLAUDE_RUNTIMES` is now computed from the capability registry instead of a hand-maintained literal, so it can no longer drift from the per-runtime descriptors. No user-visible behavior change (the list is identical). (#1728) +- **Honest verifier — verify-phase now abstains on non-inferable `backstop` truths instead of confidently false-passing them (#1154).** When the spec's edge-probe marks a truth non-inferable (`verification: backstop`) and the verifier cannot confirm it with explicit evidence (a passing wired held-out/property test, or a directly-observed behavior), it now reports `human_needed` with reason `insufficient_spec` ("unverified — held-out test recommended") rather than a silent `passed`. Autonomous runs complete with "N unverified non-inferable checks"; interactive runs route to the end-of-phase human checkpoint. Inferable truths are never abstained (over-abstention guard); abstention is exogenous (driven by the tag, not self-judgment). Truth-axis mirror of the prohibition judgment-tier (ADR-550 D4). (#1738) +- Document Claude Code's advisor-tool inheritance in the model-profiles reference: the session-level advisor is inherited by all GSD subagents and composes with per-agent tiering, with candidate executor/advisor pairings, when it is worth enabling, and the session-level (no per-agent control) constraint. (#1922) +- **Extraction discipline for strict-format agents (LLM-playbook principle 8)** — gsd-doc-classifier and gsd-doc-synthesizer apply taxonomy/precedence rules directly without inventing content, reducing reasoning-induced format drift. Based on arXiv 2504.05081 (few-shot beats CoT for pattern tasks), 2506.00069 (terminal instruction placement), 2505.14810, 2505.11423. (#1584) +- **Internal: extracted the runtime-artifact install engine from `bin/install.js`** — `installRuntimeArtifacts`/`uninstallRuntimeArtifacts`/`installOpencodeFamilySkills` and their helpers now live in a dedicated `gsd-core/bin/lib/install-engine.cjs` module (ADR-1239 Phase B), so adapters can import the install pipeline instead of reaching into the 12k-line installer. Install output is byte-identical for all 16 runtimes (golden-parity asserted); no user-facing behaviour change. (#1735) +- **MemPalace `memory_mode` `kg_backend` and `replace` are now functional** — selecting either mode now routes recall through the palace instead of silently behaving like `augment`: `kg_backend` treats the palace temporal KG as the primary knowledge-graph source (native `.planning/graphs/` as fallback), and `replace` resolves recall through the palace as the source of truth. Every mode stays default-resilient — an unreachable palace falls back to native memory and no memory is lost. (#2010) (#2010) +- **`/gsd:surface` and `--materialize` now produce byte-identical agent output to a fresh install** — surface-path agents for descriptor-driven runtimes (cursor, windsurf, augment, trae, codebuddy, copilot, antigravity) now receive the same path-prefix rewrite, Co-Authored-By attribution, runtime-specific conversion, and body normalization as the install path. Copilot and Antigravity agents are now installed via the descriptor-driven path (copilot agents get the `.agent.md` filename rename). Cline remains on the inline loop (rules-only local branch). (#1575) (#2040) +- **Internal: hook-bus + stateIO adapter seams** — `createHookBus({bus})` (new `src/hook-bus.cts`, `host`/`engine`/`none` — engine is in-process pub/sub, host fail-closed, none silent) + `createStateIO({io})` (new `src/state-io.cts`, `filesystem`/`sandboxed-storage`/`session-log-append` — filesystem delegates to fs, the rest are fail-closed seams) (ADR-1239 Phase C-1 / #1680 AC4). Completes the Phase 3 adapter seam layer; concrete host binding is Phase 5. No user-facing change. (#1805) +- **Long-context model names render compactly in the statusline** — the verbose " (1M context)" suffix Claude Code appends to the model display name now collapses to a compact " (1M)" badge (tolerant of future window sizes and the abbreviated "ctx" variant: "(500K context)" → "(500K)", "(1M ctx)" → "(1M)"). Lossless — the long-context signal stays, the 12 characters of width don't. (#2160) (#2173) +- **Lazy-split `plan-phase.md` into a `steps/` directory** — ~4.7 KB lighter eager context per `/gsd-plan-phase` call via byte-invariant progressive disclosure (ADR-1610). (#1852) (#1934) +- **GSD subagents now self-load configured agent_skills regardless of orchestrator bash** — projects that map skills via `.planning/config.json` `agent_skills.` no longer silently lose them on `/gsd-autonomous` or Cursor, where `Skill()`-delegated workflow bash init did not reliably run. Each of the 22 consumer agents queries its own type at init and reads the listed skills, with a dedup guard so runtimes that also inject orchestrator-side (Claude Code) never carry two copies. (#1866) (#1868) +- **Internal: install/uninstall runtime labels are now sourced from a single `getRuntimeLabel` lookup** — the two duplicated `runtimeLabel` assignment chains in `bin/install.js` (uninstall + install) are collapsed into one curated label table in `runtime-name-policy.cts`, sibling to the registry-derived `getDirName` (ADR-1239 Phase B, #1679). Install output is byte-identical for all 16 runtimes (golden-parity asserted). Two console-label inconsistencies are normalized as a side effect: `kimi` shows 'Kimi CLI' in both sites, and `cline` uninstall no longer falls through to 'Claude Code'. (#1800) +- **Internal: external-descriptor trust gate — load-time `configHome` confinement** — `assertDescriptorConfined(descriptor, configHome)` (new `src/external-descriptor-trust.cts`) fail-closed rejects any installed third-party host-plugin descriptor whose declared `destSubpath` resolves outside the user-approved `configHome`, before its install plan runs (ADR-1239 Phase C-2 / #1681 slice 1). Defense-in-depth load-time twin of Phase 2's install-time `assertDestWithinConfigHome`. Not yet wired into the loader (slice 2). No user-facing change. (#1806) +- **Internal: the installer's runtime → global-config-home hook-pathogen fragment is now a single `getGlobalConfigHomeFragment` lookup** — the 14-branch `if (runtime === 'x') return "'...'"` chain in `getConfigDirFromHome` (`bin/install.js`, the hook `path.join()` codegen mapping) is collapsed into one table in `runtime-name-policy.cts`, sibling to `getRuntimeLabel` (ADR-1239 Phase B, #1679 AC2 slice 2). Generated hook output is byte-identical for all 16 runtimes (golden-parity asserted); antigravity's dynamic env-overridable resolution is preserved in the caller. No user-facing change. (#1801) + +### Removed + +- **Removed the sunset Gemini CLI runtime — use Antigravity CLI instead** — Google discontinued Gemini CLI on 2026-06-18, so `npx gsd-core --gemini` now prints a deprecation notice and points you to Antigravity CLI (the official successor), which GSD already ships as a first-class runtime. (#1928) (#1996) + +### Fixed + +- The `verify-work` security-blocked presentation no longer offers next-phase planning. When security enforcement blocks phase advancement (no `SECURITY.md` produced), the workflow now routes only to the current-phase fix instead of competing `/gsd:plan-phase {next}` and `/gsd:execute-phase {next}` options. (#1687) +- `milestone complete` and `roadmap analyze` now exclude the Phase 0 / Phase 999 backlog sentinels. A milestone whose only directory-less ROADMAP heading is a backlog sentinel can be completed without `--force`, and `roadmap analyze` no longer counts the sentinel in `phase_count` or routes `next_phase` into it. Completes the `^999` exclusion #1445 added to the progress denominators. (#1691) +- **`config-set` no longer silently coerces values into something the disk never sees** — `Number.isFinite` replaced `!isNaN` in the value parser so `Infinity`/`-Infinity` are no longer coerced to non-finite numbers that `JSON.stringify` then renders as `null` on disk while the CLI echoes `Infinity` (output ≠ disk). `context_window` now has a per-key validator requiring a finite positive integer (rejects `Infinity`, `0`, negatives, non-integers with a non-zero exit), and `project_code` is always persisted as a string so a leading-zero code like `007` survives verbatim instead of collapsing to `7`. Numeric coercion for genuine numeric keys (e.g. `granularity 42`) is unchanged. (#1581) (#2023) +- **`phase.complete` no longer reports a false `is_last_phase` on a `
`-wrapped checkbox checklist (#1591, #1752)** — when the active milestone's phase checklist was written as `- [ ] Phase N:` checkbox items inside a `
` block and the next phase had no directory on disk yet (still in planning), `phase.complete`'s `isLastPhase` roadmap-enumeration fallback used a heading-only pattern (`/#{2,4}\s*Phase…/`) that never matched checkbox items. It returned `is_last_phase: true, next_phase: null` on a mid-milestone phase and — via the milestone-complete cascade — wrongly flipped STATE.md to `Milestone complete` and decremented `progress.total_phases` (e.g. 8 → 7). The pattern now matches heading-style (`### Phase N:`), plain checkbox-list phases (`- [ ] Phase N:` / `- [x] Phase N:`), and the canonical **bold** checklist form the roadmap template emits (`- [ ] **Phase N: Name**`); `extractCurrentMilestone` already surfaces the `
`-wrapped checklist correctly, so no parser change was needed. Only the reproduced `phase.complete` fallback is changed; the heading-only sibling patterns elsewhere in `phase.cts` are untouched. + (#1819) +- The `` block emitted by `gsd init` no longer leaks backslash paths into `@`-reference skill paths on Windows. The global skill directory (a native `path.join` result) was interpolated into the generated markdown without POSIX normalization, producing references like `@C:\…\skills\name/SKILL.md`; the reference is now normalized at the emit site so skill references use forward slashes on every platform. (#1736) +- **`/gsd-settings` no longer warns about four search-provider keys on fresh projects (#1747)** — `buildNewProjectConfig` emits seven search-provider availability flags and `research-provider.cts` `providerAvailability()` consumes all seven, but only three were registered in `VALID_CONFIG_KEYS` (`config-schema.manifest.json`). Running `/gsd-settings` on a freshly generated `.planning/config.json` printed `unknown config key(s) … tavily_search, ref_search, perplexity, jina — these will be ignored` even though the user never hand-edited the config. The four missing keys are now registered alongside `brave_search`/`firecrawl`/`exa_search` and documented in `docs/CONFIGURATION.md`; a drift guard in `tests/bug-2530-valid-config-keys.test.cjs` now requires every config-driven research-provider flag to be in the schema, so a future provider addition cannot reintroduce the drift. (#1814) +- **`gsd-tools state json` no longer reports conflated progress for an unversioned milestone (#1761)** — the ADR-1769 Phase 7 fix (#1794) taught `state sync` to leave Progress untouched when a milestone version is asserted but the ROADMAP has no versioned heading for it, but the `state json` **read** path still rebuilt progress via `buildStateFrontmatter`, whose phase-heading count fell back to the whole document and summed sibling milestones. `state json` therefore reported a conflated `total_phases` (e.g. 8 = 4+4 across two milestones) plus a derived `percent`, contradicting the sync guard on the very same project. The read path now mirrors the sync guard: when the asserted milestone cannot be bounded to a versioned ROADMAP heading, `total_phases` falls back to the on-disk phase-dir count and `percent` is omitted. Bounded milestones (versioned ROADMAP, or no milestone asserted) are unchanged; the signal rides on the existing `_diskScanCache` so `extractCurrentMilestone`'s return contract and its other callers are untouched. (#1818) +- **`gsd-graphify-update.sh` now reads the full multi-line command in Gate 2 (#1772)** — the PostToolUse auto-update hook joined `tool_name` + `\n` + `tool_input.command` and extracted the command with `sed -n '2p'` (line 2 only). Agent runtimes (Claude Code's Bash tool among them) routinely emit HEAD-advancing commits as multi-line scripts (`cd /path`, then `git add`, then `git commit …`), so line 2 was the `cd`, Gate 2's `*"git commit"*` match failed, and the rebuild silently no-op'd on real commits even with `graphify.auto_update: true`. The failure was invisible in manual probes because a single-line `git commit -m x` passes line 2 verbatim. The hook now captures line 2 through EOF (`sed -n '2,$p'`) so the `case` glob sees the full command string; single-line behavior is unchanged and multi-line commands without a HEAD-advancing op still no-op cleanly. (#1815) +- **`/gsd-thread close|resume` now writes the thread status/updated frontmatter (#1778)** — the thread workflow's CLOSE and RESUME branches invoked `frontmatter.set` with the pre-1.6 fully-positional shape (`frontmatter.set `), but since 1.6 the dispatcher parses the file positionally and reads `field`/`value` from the named flags `--field`/`--value` via `parseNamedArgs`. The positional form left `field`/`value` undefined, `cmdFrontmatterSet` errored `file, field, and value required`, and the writes were silently skipped — so closing a thread never marked it `status: resolved` and resuming never marked it `status: in_progress`, with the error scrolling past on every thread command. All four sites (CLOSE `status`+`updated`, RESUME `status`+`updated`) now use the 1.6 hybrid form that `verify-work.md` already uses (`frontmatter.set --field --value `). (#1816) +- **The installer no longer copies dead lifecycle hook scripts for Kilo and ZCode** — both declare `hooksSurface: 'none'` and have no plugin surface, so the staged `hooks/*.js`, `hooks/*.sh`, `hooks/lib/` and the CommonJS `package.json` marker were dead weight in `~/.kilo/` and `~/.zcode/`. The two hook-copy guards in `install.js` now exclude Kilo and ZCode alongside the other no-hook runtimes. OpenCode, which also declares `hooksSurface: 'none'`, is deliberately kept: its native plugin adapter (#1914) spawns those staged hooks via OpenCode's event bus and needs both them and the marker. (#2057) +- **Test gates can no longer hang forever on a watch-mode test runner.** vitest defaults to watch mode in an interactive terminal (exactly where `gsd-execute-phase` runs), so a resolved `npm test` / `pnpm test` that maps to vitest never exited and the orchestrator waited indefinitely until the user manually intervened. Every GSD test-command gate — the regression gate, the post-merge gate, the audit-fix gate, and the verify-phase gate — now routes the resolved command through a shared `normalize-test-command` helper that rewrites it to a one-shot form (direct vitest → `vitest run`; jest `--watch` → `--watchAll=false`; a package-manager `test` script backed by watch-vitest → `CI=true` prefix; already-one-shot commands are left unchanged). The three gates that previously hung or silently continued — the regression, post-merge, and audit-fix gates — additionally bound execution with a configurable `workflow.test_gate_timeout` (default 600s), aborting or surfacing the cause on timeout instead of hanging; the verify-phase gate was already bounded (a fixed 5-minute limit) and keeps it, now naming watch mode on timeout. The normalizer only rewrites a runner named as a standalone command token (so paths/targets like `run-vitest.js` are never mangled), is length-capped and linear-time on adversarial input, and only reads a regular-file `package.json`. (#2060) +- **`settings-advanced.md` no longer has an orphan `` around §8 Model Policy** — the §8 Model Policy block ended with a closing `` but had no matching opening tag (5 opens / 6 closes), leaving its content as loose inter-step prose that could fail to execute reliably. Added the missing `` opener so the section is a proper step. A new workflow ``-tag-balance regression guard (fenced-code-stripped) now blocks any future orphan tag across all top-level workflows. (#1864) (#2014) +- **The runtime launcher now honors `CLAUDE_CONFIG_DIR`** — the `gsd_run` preamble embedded in every workflow/agent resolved the Claude global install only at `$HOME/.claude/gsd-core/bin/`, while the installer honored `CLAUDE_CONFIG_DIR`, so a global install redirected via `CLAUDE_CONFIG_DIR` was invisible to every `gsd_run` call (every GSD command failed with `gsd-tools.cjs not found`). The Claude resolver arm now uses `${CLAUDE_CONFIG_DIR:-$HOME/.claude}` — matching the installer and the other runtimes' `${VAR:-default}` pattern — so a custom `CLAUDE_CONFIG_DIR` is found and the default `$HOME/.claude` path is unchanged. Re-synced into all 95 workflows/agents; two capped workflows trimmed to stay under their byte budgets. (#1865) (#2024) +- **Node-test prohibition proofs now require a clean-fixture causation control** — a `node-test` prohibition's fail-first proof no longer accepts a deceptive content-independent negative test (one that reds merely because `GSD_PROHIB_SUBJECT` is *set*, ignoring the subject's content). The `check_clean_fixture` control is now **mandatory** for the `node-test` kind: a descriptor that omits it is un-provable and hard-gates, rather than greening on the violation alone. **Breaking (Hyrum):** a previously-green node-test prohibition with no clean fixture now hard-gates — blast radius is zero in-tree (no `node-test` prohibition ships today). The `lint-rule` kind is unchanged (its subject IS the linted file, no `GSD_PROHIB_SUBJECT` indirection). (#1906) (#2001) +- **Third-party capabilities now work on installed layouts.** `capability install` no longer rejects capabilities with a real `engines.gsd` range as "incompatible with GSD 0.0.0" — the host version is now read from the authoritative `gsd-core/VERSION` file across every runtime and the `capability install` CLI. The installer also now ships the registry generator scripts (`gen-capability-registry.cjs`, `gen-loop-host-contract.cjs`), so installed third-party capabilities actually compose into the loop instead of being silently discarded. (#1938) +- **`/gsd:verify-work` preserves verification state across gap-closure execution and no longer auto-promotes deferred follow-ups into blocking gaps** — resuming after `/gsd:execute-phase --gaps-only` used to lose the verification state: the UAT `## Gaps` still read `status: failed` even after their fix plans executed, so verify-work re-diagnosed them as fresh blockers, spawned a new gap plan, and reported only the new plan as verified. A state contract now links each gap to its fix plan: every UAT gap carries a stable `gap_id` (`G-{phase}-{N}`), gap-closure plans tag the ids they address in their frontmatter (`gap_ids: […]`), and a new `reconcile_gaps` step on resume marks a gap `status: resolved` when its plan has a matching `*-SUMMARY.md` — so fixed gaps aren't re-diagnosed and the phase can close. Separately, a deferred-follow-up branch captures future-work ideas (signals like "later", "next version", "out of scope") into a `## Deferred Follow-Ups` section instead of creating a blocking gap/plan. (#1921) (#2025) +- **`roadmap update-plan-progress` no longer counts stray non-plan `*-SUMMARY.md` files against phase completion** — remediation/gap-closure summaries (e.g. `30-FIX-CR02-SUMMARY.md`, `30-GAPCLOSURE-SUMMARY.md`) inflated `summary_count`, and once `summary_count >= plan_count` the phase silently flipped to `Complete` (checkbox checked, date stamped) even though several plans had no summary. A new `countMatchedSummaries` helper (core-utils) pairs summaries to plans via the `PLAN→SUMMARY` marker swap + the `-SUMMARY.md` form (layout-agnostic across root, bare, and nested layouts), so only a summary that corresponds to a real plan counts. Wired into `scanPhasePlans` (fixing roadmap listing, state sync, verification, workstream inventory at once) and `cmdRoadmapUpdatePlanProgress`. (#1988) (#2016) +- **`milestone complete --ws` requirements archive header now points at the workstream REQUIREMENTS.md** — the archive header string hardcoded the root path (`` `…see .planning/REQUIREMENTS.md` ``), so a workstream archive directed readers at the wrong file even though #1917 had already fixed the archive *locations* to land inside the workstream. The display path is now derived from the same workstream-aware `reqPath` the writer uses (`path.relative(cwd, reqPath)`), so root behavior is byte-identical and the workstream case correctly reads `.planning/workstreams//REQUIREMENTS.md`. (#1993) (#2015) +- **Load-failed capability gates now fail open with a loud warning instead of blocking the whole project** — when an installed overlay (third-party) capability failed to load (e.g. an incompatible `engines.gsd` range) but had declared a `gate`-kind loop hook, the loop resolver injected a blocking synthetic gate (`blocking:true`, `onError:halt`) at every point where that capability declared a gate. A single incompatible capability therefore halted every `ship:pre` and `verify:post` in the project — unrelated to what the gate would have checked, and with no remediation surfaced. The resolver now injects no gate and instead emits a loud warning — to stderr and in the `loop render-hooks` envelope's `warnings` array — naming the load-failure reason and the exact `gsd capability remove ` remediation, and the loop proceeds (fail open). The capability id embedded in that remediation is validated against the canonical id shape first, so a malformed overlay directory name cannot inject shell metacharacters into the surfaced command. The loader still records `_overlay.blockedGates`; only the consequence changes from block to warn. `step`/`contribution` overlays were already skip-open. (#2009) (#2075) +- **`phase.complete` now updates the `## Progress` rollup row even when an earlier phase-numbered table precedes it** — the Progress-row writer used a non-global regex that matched *any* table row starting with the phase number, so it bound to the first such row (e.g. a `| Phase | Requirements | Count |` coverage table), no-op'd on the wrong 3-column row, and never reached the real Progress row. The regex is now scoped to the `## Progress` section so it binds to the correct table. The command still returned `roadmap_updated: true` (that field is `fs.existsSync(ROADMAP.md)`), masking the silent failure. (#2012) (#2032) +- **context7 now works for plugin-marketplace installs (8 agents regained doc lookup)** — the agents granted only `mcp__context7__*`, which matches a standalone context7 MCP server but not the official Claude Code plugin-marketplace install (`context7@claude-plugins-official`), whose tools are named `mcp__plugin_context7_context7__*`. The grant never matched, so advisor/ai/domain/phase/project/ui-researcher + planner + executor silently lost documentation lookup and fell back to WebSearch. All 8 agents now grant both forms, the researcher profile table is updated, and a parity guard asserts no agent grants the standalone form without the plugin form. (#2017) (#2029) +- **`applySurface` no longer deletes every `gsd-*` agent when the skills manifest resolves empty** — the agent-prune loop in `_syncGsdDir` deleted any `gsd-*.md` not in the staged set, and when the manifest was empty/unresolvable (null manifest, no array entries, no `files` key, or an unresolvable install source root), the staged set was empty → every agent was pruned. Skills were guarded by `pruneSkillDirs`'s manifest-membership check (conservative preservation on empty manifest); agents had no equivalent. The agent-prune loop is now skipped when the manifest is empty/absent, so agents are preserved while copy (adding genuinely new agents) still runs. (#2018) (#2031) +- **`planning-config.md` global-learnings path corrected to `~/.gsd/knowledge/`** — the `features.global_learnings` row directed users to `~/.gsd/learnings/`, but the implementation (`src/learnings.cts`, `execute-phase.md`) stores and reads global learnings from `~/.gsd/knowledge/`. Anyone following the docs to inspect, back up, or seed their global learnings looked in a directory the code never touches. (#2019) (#2026) +- **Removed dead SDK file references from runtime-loaded markdown that triggered an infinite `find.exe` storm on Windows** — `agents/gsd-executor.md` pointed at `sdk/src/query/QUERY-HANDLERS.md` and `gsd-core/workflows/reapply-patches.md` at `sdk/dist/cli.js`, both retired with the SDK package (ADR-0174). AI runtimes that resolve doc references by filesystem search ran `find / -iname …`; on Git Bash for Windows `/` maps to the drive root, so `find.exe` traversed the whole disk (14h+, orphaned processes, 4M+ open handles each, unkillable). The references now resolve to live paths, and a new regression guard asserts no `sdk/src|sdk/dist|sdk/handlers` file references remain in agents/workflows/references markdown. (#2020) (#2027) +- **`roadmap update-plan-progress` no longer checks the phase checkbox without verification** — the command stamped the phase-level ROADMAP checkbox and completion date the moment the last plan summary landed (called routinely after every wave and every plan), with **no verification gate** — unlike `phase.complete` which correctly requires `readVerificationStatus(...).status === 'passed'`. Now `isComplete` requires both all plan summaries AND a passed verification, matching the `cmdPhaseComplete` contract, so the checkbox only fires after `gsd-verifier` has confirmed the phase. (#2022) (#2030) +- **`phase complete` no longer marks a milestone done out of order, nor silently writes root state in workstream mode.** Completing the numerically-highest phase while an earlier phase was still outstanding wrongly flipped STATE.md to `Status: Milestone complete` (the milestone-end check only looked for higher-numbered phases, so an out-of-order completion — e.g. Phase 10 before Phase 9 — read as the end). It now reports milestone-end only when every lower-numbered phase in the milestone is checked complete. Separately, in workstream mode with no active workstream, `phase complete` previously fell back to root `.planning` and wrote STATE.md/ROADMAP.md (and the mislabel) into the shared root other workstreams read; it now fails safe — asking for `--ws ` or an active workstream — mirroring the existing `init progress` guard. (#2066) (#2066) +- **Phase directories whose slug begins with a single digit now resolve correctly.** A phase like `46-6-rs-pipeline-orchestrator` (roadmap name "6 Rs Pipeline Orchestrator") had its phase token over-collected as `46-6` instead of `46`, so `gsd-tools` phase-by-number lookups resolved `phase_dir=null` / `has_context=false` (breaking `init.plan-phase`, `init.phase-op`, and downstream execute/verify/ship). Numeric phase-token components must now be zero-padded (≥2 digits), so a single-digit slug word is no longer absorbed into the token. Fixed consistently across every same-class implementation — `extractPhaseToken`, `PHASE_TOKEN_FROM_DIR_RE` and `canonicalPlanStem` (health checks / plan pairing), `isDirInMilestone`'s numeric matcher (milestone filtering), and `extractCanonicalPlanId` — so the health-check and milestone-filter subsystems are fixed alongside phase resolution. (#2059) +- **`gsd-tools config-set null` now clears (removes) the key instead of persisting the literal string `"null"`.** The documented "Clear" action previously fell through the value parser and stored `"null"` — a truthy value — so "cleared" keys stayed set and `config-get` returned `"null"`; for secret keys (`brave_search`/`firecrawl`/`exa_search`) a masked success line hid a truthy value on disk that integrations could pass along as a real credential. `config-set null` now deletes the key (short-circuiting the typed per-key validators so clearing an enum/boolean/number key removes it rather than being rejected), making the "Clear" flows in `settings-integrations.md` / `settings-advanced.md` actually clear. (#2058) +- **`init plan-phase` no longer collapses foreign-prefixed task/workstream IDs into numeric phases** — a query like `MEM-01` (where `MEM` is not the configured `project_code`) used to have its prefix stripped and resolve to the unrelated numeric Phase 01; it now reports `phase_found: false` unless a phase directory or roadmap entry literally carries that prefix. The configured `project_code`'s own prefixed phases (e.g. `LKML-01` under `project_code: LKML`) continue to resolve as before. (#2056) (#2105) +- **`phase complete` no longer ticks the wrong phase's ROADMAP checkbox** — completing a phase whose number also appears in a later phase's description (e.g. an idempotent re-run of an already-complete phase) used to mark the *wrong* phase done, because the checkbox-matching regex greedily spanned from `]` to any later "Phase N" mention instead of only the immediately-following phase title. (#2067) (#2079) +- **`gsd-tools effort sync` no longer crashes in an installed runtime.** In any global install (e.g. `~/.claude/gsd-core/`), `effort sync` threw `Cannot find module '../../../bin/install.js'` — the command reached into the package-root `bin/install.js` for its install-time effort resolvers, but the installer only copies the `gsd-core/` subtree into a runtime home, so that file is never present there. As a result, `effort` config changes (`routing_tier_defaults` / `agent_overrides`) silently never reached installed agents without a full reinstall. The two resolvers (`readGsdEffectiveEffortConfig` + `resolveInstallTimeEffort`, with their helpers) are now extracted into a shipped `gsd-core/bin/lib/install-effort-resolver.cjs` that both `effort sync` and the installer import — a single source of truth that is always present in the installed tree. (#2076) (#2076) +- **`model_overrides` and per-phase-type models now actually apply to the assumptions-analyzer, code-reviewer, and code-fixer agents on Claude Code.** Previously `model_overrides["gsd-code-reviewer"]` / `["gsd-assumptions-analyzer"]` / `["gsd-code-fixer"]` (and `models.verification` / `models.discuss` / `models.execution`) were accepted and resolved but silently dropped — the workflows spawned these agents with no model, so they inherited the session model and the configured routing never took effect (no warning). Every spawn now threads its resolved model: `discuss-phase-assumptions`, `code-review`, and `code-review-fix` (both the re-review and the two fixer spawns) resolve it inline, and `quick`'s review step uses the code-reviewer's own resolved model instead of the executor's. The stale "`discuss` — reserved, no subagent" model-profile docs are corrected to list `gsd-assumptions-analyzer`, and the `verification` row now includes `gsd-code-reviewer`. (#2074) (#2074) +- **`/gsd-review`'s Antigravity CLI reviewer no longer fails silently on large prompts, unavailable pinned models, or pre-session stalls** — the `agy` invocation now uses a file-reference prompt to avoid exec arg-list overflow, is wrapped in an external wall-clock `timeout` paired with `--print-timeout` because `--print-timeout` cannot fire before `agy` creates a session, passes `--model` from `review.models.agy` when set as an escape hatch for a 404'd pinned model, and its empty-output stub now surfaces an `agy` cli.log diagnostic instead of a bare generic message. Supersedes the #687 "no external killer / inline `$(cat)`" contract, which predated `agy` gaining `--model` and predated its own guidance to pair `--print-timeout` with a terminal timeout. (#2073) (#2109) +- **`init execute-phase`, `init verify-work`, and `init phase-op` no longer collapse foreign-prefixed task IDs to numeric phases** — `MEM-01` under `project_code: LKML` was silently stripped to `01` and resolved to the unrelated numeric Phase 01, because the #2056 guard was applied only to `init plan-phase`. The guard is now extracted into shared helpers (`guardedFindPhase` / `guardedGetRoadmapPhase`) that delegate to the canonical `isForeignPrefixedPhaseQuery` from `phase-id.cts`, and all four init commands route through them. (#2104) (#2149) +- **`commit --files` now commits only the declared paths** — `gsd-tools commit --files A B` previously ran a bare `git commit` that absorbed the entire staged index, silently sweeping in unrelated files the caller never named. The commit now appends a pathspec (`-- `) so only the staged subset of `--files` lands in the commit; the no-`--files` default path is unchanged. Missing tracked files are still skipped (not committed as deletions, #2014), and when all declared files are missing the function short-circuits to `nothing_to_commit` instead of absorbing the index. (#2112) (#2148) +- **Fixed unresolvable bare `require('gsd-core/...')` in `gsd-surface` command doc** — the four `require()` examples now derive the engine path from `runtimeConfigDir` (resolvable at runtime), and the reinstall hint corrects `npm i -g gsd-core` to `npm i -g @opengsd/gsd-core`. (#2116) (#2213) +- **`milestone complete --dry-run` now prints a preview plan instead of silently mutating** — `gsd-tools milestone complete --dry-run` was neither parsed nor rejected, so a caller expecting a preview triggered the full destructive mutation (archive phases, move audit artifacts, rewrite STATE.md) with no way to back out. The `--dry-run` flag is now honored: it returns a JSON plan listing `would_archive` (roadmap, requirements, audit, phase dirs) and `would_update` (MILESTONES.md, STATE.md) targets with zero filesystem mutations. (#2118) (#2155) +- **`/gsd-secure-phase` now has a single SECURITY.md writer** — the `gsd-security-auditor` subagent previously held `Write`/`Edit` tools and was instructed to "write SECURITY.md" with no padded `-` prefix and no template frontmatter, while the orchestrator's Step 6 also wrote the phase-scoped `-SECURITY.md` from `templates/SECURITY.md`. The auditor is now return-only (drops `Write`/`Edit`, returns a structured verdict with `threats_open`); the orchestrator is the sole file writer. The workflow's Step 5 spawn constraints explicitly forbid the auditor from writing SECURITY.md. (#2119) (#2154) +- **Dead security scan exports removed; injection-scan docs corrected to match reality** — `scanEntropyAnomalies` and `shannonEntropy` were dead code with zero production callers (live hooks inline their own patterns for independence). REQ-SCAN-INJ-02/-03 now accurately describe what runs live (injection patterns, invisible Unicode) vs CI-only (base64-decode, codebase scan). (#2198) (#2211) +- **Custom STATE.md frontmatter keys are no longer dropped on every mutating verb** — syncStateFrontmatter rebuilt the frontmatter from a fixed schema, silently dropping any custom key. It now carries forward existing keys the schema does not own. (#2202) (#2233) +- **Non-frontend phases with `UI hint: no` are no longer blocked by the UI-SPEC gate** — the UI safety gate's token list included the bare token `UI`, which matched GSD's own `**UI hint**: no` metadata line and false-detected a UI, blocking backend/infra phases at /gsd-plan-phase. An explicit `UI hint: yes|no` is now authoritative and the hint line is no longer token-sniffed. (#2150) (#2222) +- **OpenCode reviewer no longer silently yields an empty review on large prompts** — `/gsd-review --opencode` now invokes `opencode run --format json` and reconstructs the review from the assistant text parts, so a large-prompt run where the default `build` agent ends its turn with zero output tokens no longer produces an empty stub. When the agent genuinely emits no text, the stub now reports the stop reason, output-token count, and captured stderr instead of a generic message. (#1936) (#1992) +- **`stale-bake-guard` hermeticity fix (test-isolation)** — the readGsdEffectiveModelOverrides subtest no longer reads the developer's real `~/.gsd/defaults.json`; the resolver now accepts a homedir seam so the test sandboxes HOME. (#2152) (#2223) +- **`/gsd-surface` (`list`/`status`) works on Claude Code global installs** — the installer now writes a `.gsd-source` marker pointing at its `commands/gsd` source, so `findInstallSourceRoot` resolves on the global skills layout (which ships no `commands/gsd` tree) instead of throwing `could not locate commands/gsd`. (#1487) (#1487) +- **`phase complete --phase N` now works alongside the positional form** — the phase verb family treated the first positional as the phase number, so `--phase 12` was passed as the literal phase name and failed with 'Phase --phase not found'. The phase family now accepts the --phase flag consistently with the state family, and unrecognized flags yield a usage error. (#2201) (#2231) +- **Third-party capability skills now surface correctly after install** — a skills-only `role: feature` capability installed `active` but its skills never reached the runtime surface, `capability enable`/`set` rejected it as `unknown capability`, and `capability list` disagreed with `capability state`. `resolveSurface` now unions the composed registry's `capabilityClusters` into the surfaced skill set (no on-disk linking), the writer validates against the composed overlay-aware registry, and `capability list` carries a `surfaced` field matching `capability state`. (#2054) +- Fixed: probe-core's runProbeCli now fails closed on per-item adapter garbage inside a well-shaped report envelope, matching its documented 'fails closed on adapter garbage' contract. (#1910) +- **`/gsd:verify-work` no longer silently terminates when all remaining UAT tests are blocked** — sessions with `blocked_count > 0` and `pending_count == 0` now route to `complete_session` as expected, enabling the zero-issues auto-transition path. (#1722) +- **state record-metric no longer appends per-plan rows into the By-Phase velocity table** — it now maintains its own Per-Plan Metrics table (self-created on first use), and its auto-create scaffold header is corrected. (#2253) (#2253) +- Codex reviewer now captures the review via codex's --output-last-message flag instead of redirecting stdout, so Windows process-teardown output no longer pollutes the review file and slips past the empty-output guard. (#1709) +- **`last_activity` now shows your local calendar day** — the clock seam derived the date by slicing a UTC instant, so in negative-UTC-offset zones during UTC's early evening the date-only `last_activity` field jumped a day ahead of the operator's actual date (and of `last_updated`'s local date). Operator-facing date fields now use a host-local calendar day while internal/cosmetic stamps stay UTC. (#2136) (#2216) +- **`milestone_name` is no longer clobbered with a delimiter-led fragment** — getMilestoneInfo's `##` heading regex was unanchored, so it matched a heading quoted inside backticks in the Milestones bullet and wrote garbage like `— Active Milestone` over the curated milestone name on every phase transition. Now consults the 🚧 marker first, anchors the regex to line start, strips the leading delimiter, and widens the preserve guard so a bad derive keeps the existing name. (#2135) (#2215) +- **`init milestone-op` now counts project_code-prefixed phase directories correctly** — fully shipped milestones using the standard prefixed directory layout no longer report `completed_phases: 0` or stay falsely incomplete. (#1844) (#1844) +- **`/gsd-quick` no longer halts with a stale-base worktree mismatch** — the worktree executor now degrades to sequential execution when its fork base has diverged from origin/HEAD, instead of spawning a worktree guaranteed to fail the base-mismatch guard. (#1991) +- **Setting `external_job.submit_timeout_ms` / `poll_timeout_ms` / `artifact_dir` in `.planning/config.json` now actually configures the SLURM adapter** — the keys were declared by the external-job capability but the adapter only read env vars, so config edits silently had no effect. The adapter now resolves them through the canonical capability-config seam (env override > config > registry default), surfaces the resolved `artifact_dir` in `submit` output, documents why the contribution registers at `execute:wave:post` (#1164 asks for `wave:pre`, which `execute-phase.md` does not dispatch today; wiring it is a core-loop change #1164 explicitly defers), and gains unit coverage for the CLI surface (`parseFlags`, `findPlanningDir`, `resolveExternalJobSettings`, `formatShowReport`). (#1164) (#2006) +- **The Antigravity reviewer in `/gsd-review` no longer reviews blind** — `agy -p` never granted the agent the repo under review, so it frequently anchored on its own scratch directory and returned plan-text-only verdicts counted at full consensus weight. The reviewer is now granted the repo (capability-probed `--add-dir`) and anchored to the absolute repo root; a review that still runs without repo access is stamped `[reviewed-without-repo-access]` and down-weighted in the Consensus Summary. The cursor-agent prompt gains the same absolute-root anchor. (#2176) (#2184) +- **Autonomous reruns now skip phases with deferred verification until you resume them explicitly** — if a prior `/gsd-autonomous` run recorded `verification_deferred_human` or `verification_deferred_gaps`, later reruns no longer drop back into the same prompt loop and instead point you at the saved resume command. (#1846) (#1846) +- **`requirements mark-complete` no longer reports silent success when the traceability row is missing** — it OR-ed its checkbox and table-row writes into one flag, so a checkbox-only reconcile returned a payload byte-identical to a full reconcile while the traceability row stayed Pending (and re-run masked it as already-complete). It now surfaces `table_unmatched` for IDs whose checkbox reconciled but whose table row is absent, and treats a checked box with no table row as partial rather than done. (#2140) (#2219) +- state prune now resolves the current phase from the canonical location — frontmatter current_phase, the Current Phase field, or the prose Phase: line scoped to the ## Current Position section — instead of extracting Phase over the whole document, where stateExtractField's pipe-table fallback could latch onto an unrelated | Phase | N | row (e.g. a historical verification table) and compute a wrong prune cutoff. (#1832) +- **`model_overrides` Claude model IDs now resolve to Agent-tool aliases on the claude runtime** — a full Claude model ID (e.g. `claude-sonnet-5`) in `model_overrides` was returned verbatim and silently dropped by the Claude Agent tool (whose `model` parameter documents only tier aliases), causing the spawned subagent to inherit the parent session model instead of the configured one. It now maps to the tier alias (`sonnet`/`opus`/`haiku`/`fable`), consistent with the `model_policy` path (#1144). Bare aliases, non-Claude values, and non-Claude runtimes are unchanged; a Claude ID with no alias warns once and falls through to tier resolution. (#2041) (#2048) +- Phase headers that place a parenthetical tag before the colon (`### Phase 26 (Cluster B): Title`) now resolve and enumerate the same as untagged headers. Previously the resolver returned not-found and `roadmap analyze`/listing silently dropped the phase (wrong phase_count, progress, and next_phase). Tag tolerance is applied at every phase-header read site; untagged and all existing header formats parse unchanged. (#1765) +- Executor and milestone-summary/forensics workflows now call state.* commands with named flags so the named-only router records metrics, decisions, blockers, and session continuity instead of silently dropping positional args. (#1873) +- **bug-1367 install test no longer fails on Windows CI when hooks/dist isn't pre-built** — the test ran install.js without building its hooks/dist precondition (a gitignored build artifact the unit lane doesn't build), so on a lane without pre-built hooks the installer hit "Failed to install hooks: directory is empty" and the before-hook threw. The test now builds hooks in its own before() (mirroring golden-install-parity). (#1926) (#1927) +- **`/gsd-fast` now appends Quick Task rows to STATE.md again** — the log_to_state column-count guard used an off-by-one awk formula (`NF-1`) that was always one too high, so the schema gate rejected the very table quick.md creates and silently skipped the STATE.md update. Also now supports the 6-column validate-mode table. (#2133) (#2214) +- Build the gitignored `hooks/dist/` artifact once upfront in `scripts/run-tests.cjs` (the same chokepoint as `ensureBuiltArtifacts`), before any concurrent install test spawns `install.js`. Closes the scoped-CI first-build empty-dir race that intermittently failed install tests with `Failed to install hooks: directory is empty` (e.g. `bug-3683-workflow-colon-namespace-leak`). (#1967) (#1968) +- **workstream progress no longer reports shipped milestones as `executing`** — `gsd-tools workstream progress` now derives each workstream's status from authoritative shipped signals (an archived milestone snapshot under milestones/, or a SHIPPED marker in the workstream ROADMAP) instead of trusting the mutable STATE.md `Status` field, so a stale field can never hide a shipped/archived milestone. The output adds `status_source` (`field` | `derived`) and `status_conflict` (true when the derived value disagrees with the stale field). (#1913) (#1916) +- **Windows install/upgrade/state-write operations no longer fail on transient antivirus/indexer file locks** — the fs.renameSync atomic-publish sites (install state, hooks config, capability ledger/lifecycle, phase/workstream/milestone dirs, roadmap, planning/state locks) now retry EPERM/EBUSY/EACCES via retryRenameSync instead of propagating the transient lock; enforced by the new local/require-fs-op-fallback lint rule (ADR-1703 Phase 6). (#1740) (#1742) +- reconstructFrontmatter now emits valid YAML for scalars and block-array items that were previously serialized unescaped. Values carrying a YAML indicator plus a literal quote/backslash, embedded control characters, the empty string, a leading YAML indicator, or leading/trailing whitespace are now routed through a properly escaped double-quoted form, so frontmatter round-trips through strict parsers (js-yaml, PyYAML) instead of corrupting the block on the next state sync. (#1807) +- **`phase remove` no longer destroys the Progress table when removing the last phase** — deleting a phase used a whole-document regex whose scan, on the final phase, ran past the section and swept away the `## Progress` heading and its entire tracking table; the deletion is now structurally bounded to the phase’s own section. (#2253) (#2253) +- **`phases clear` archives phase directories instead of destroying them** — at a milestone switch, committed phase directories were hard-deleted (`rmSync`) with no archive, silently losing browsable phase history (the #1447 dirty-tree guard was a no-op for the common committed case). Phase directories are now moved to `milestones/-phases/` (collision-safe; timestamp fallback when no version resolves), so history survives the switch. The #1447 uncommitted-changes guard is retained as a secondary backstop. (#1871) (#1919) +- **Cross-AI review no longer silently drops the Codex/Claude/Gemini lanes on large plan sets** — the prompt-fed reviewer blocks in review.md invoked each CLI with no explicit timeout, so a slow source-grounded review was killed at the host default (~2 min) and the lane was silently lost. The workflow now directs a high Bash timeout and frames an empty output as a timeout (not the crash it was misdiagnosed as). (#2194) (#2226) +- **`/gsd-progress` no longer reports a stale root milestone in workstream mode** — in a multi-workstream project with no active workstream set, `gsd-tools query init.progress` silently fell back to root `.planning/STATE.md` (often stale) and reported it confidently. It now fails safe with an actionable error naming the available workstreams and the `--ws`/`workstream set` fix, so a stale root value is never reported. Flat mode and `--ws ` are unchanged. (#1912) (#1918) +- Windows: stop double-quoting $CLAUDE_PROJECT_DIR-anchored managed node hook paths during the #2979 legacy rewrite, which produced "\"$CLAUDE_PROJECT_DIR\"/..." and broke every node managed hook with MODULE_NOT_FOUND (PreToolUse-guard deadlock). (#1746) +- **phase complete now updates STATE progress on milestone-grouped roadmaps** — deriveProgressFromRoadmap parses the ## Progress table by header (column-by-name) instead of a fixed 4-column layout, so the 5-column milestone-grouped shape is no longer silently unparsed. (#2168) +- **Windows Claude Code hooks now work under PowerShell** — when Claude Code's hook runner resolves to PowerShell (not Git Bash), every GSD-installed hook failed with `Unexpected token` because the installer emitted bare quoted paths with no PowerShell call operator. The fix adds a `hookShell` parameter to the hook-command projection chain; when `hookShell='powershell'`, the `&` call operator is prepended. Default behavior (Git Bash, no prefix) is unchanged. (#2236) (#2261) +- **`capability state` and `loop render-hooks` now accept `--runtime` to override the auto-detected runtime** — previously both commands parsed only `--config-dir`, so the runtime config dir was derived from the persisted `.planning/config.json` runtime (precedence `GSD_RUNTIME` → `config.runtime` → `claude`). A repo that persisted `runtime:"codex"` resolved the config dir to `~/.codex`, where the Claude skill isn't installed, so every skill-bearing capability reported `surfaced:false` and `execute:post`/`verify:post` hooks silently no-op'd when the operator drove GSD from Claude Code. `--runtime ` (canonicalized, so aliases like `codex-app` work) now bypasses that fallback so the config dir resolves to the explicitly-named runtime's home. Behavior without the flag is unchanged. (#2003) (#2051) +- **`phase complete` no longer false-reports REQ-IDs as missing when the traceability table leads with a status column** — the parser required the REQ-ID in the first column, so a table shaped `| ☐ | REQ-01 | …` matched zero rows and every body REQ-ID was reported missing. It now matches REQ-IDs in any column. (#2203) (#2234) +- **`init milestone-op` now ignores backlog `999.x` headings when counting milestone phases** — parked backlog items no longer inflate `phase_count` or pin `all_phases_complete` false for an otherwise finished milestone. (#1843) (#1843) +- **Phase archival is now wired end-to-end across the milestone lifecycle** — finishes the #1871 follow-up: `phases archive` is now a real command (the half-wired alias is routed, no longer errors Unknown), `milestone complete` archives phase dirs by default (`--no-archive-phases` opts out), and `new-milestone` §6 stages the archive move + source removal in the same commit so history is preserved atomically rather than left as orphaned uncommitted deletions. (#1871) (#1924) +- **`state update-progress` no longer mangles the frontmatter and discards the progress suffix** — its Progress: regex matched the raw STATE.md including frontmatter, so the YAML `progress:` key was hit first (corrupting the frontmatter) while the body line stayed stale and was silently reverted on the next write, and any descriptive suffix after the progress bar was destroyed. It now targets the body line only and preserves the suffix. (#2177) (#2224) +- **`/gsd-ship` no longer silently drops the ship-status note from STATE on merge** — the track_shipping step committed the STATE ship-note after creating the PR but never pushed it, so on a fast merge the note stayed local-only and never reached the default branch. The ship-note is now pushed onto the PR branch with a `[ci skip]` trailer so it lands on merge without a redundant pipeline. (#2138) (#2217) +- **`/gsd-debug` no longer stalls on a phantom background handoff** — the orchestrator treated the foreground session-manager spawn as a background task and queried its agent ID via TaskOutput (which needs a task ID), then waited on a handoff that was never queryable. The workflow now states the spawn is foreground/blocking, forbids passing an agent ID to TaskOutput, and gives a lost-handoff recovery path. (#2196) (#2227) +- **Roadmap phase lookup now ignores fenced examples and the backlog sentinel lane** — `roadmap get-phase` and `init plan-phase` no longer return fenced sample headings as real phases or treat `999.x` backlog items as active milestone work. (#1845) (#1845) +- **`phase complete` no longer checks the wrong ROADMAP checkbox or writes the plan count into a shipped milestone** — the roadmap mutators ran unanchored and un-milestone-scoped, so they could flip a bullet inside a backticked prose literal or a Backlog entry instead of the closing phase's, and write the plan count into a same-numbered phase in a shipped milestone. The checkbox flip is now line-anchored and both writers are scoped to the current milestone. (#2200) (#2229) +- **`roadmap get-phase` resolves project-code-prefixed headings by bare number** — a bare-number query (e.g. `29`) now resolves a drifted `### Phase AB-29:` heading, matching the internal resolver used by `init.phase-op`; previously the CLI returned empty. A bare sibling (`### Phase 29:`) still takes precedence. A project-code-prefixed heading present only as a summary/checklist line (no matching detail section) now reports a `malformed_roadmap` diagnostic — for both prefixed and bare-number queries — instead of a silent empty result. (#2114) (#2139) +- **`milestone complete --ws` now archives into the workstream instead of root** — the archive paths (MILESTONES.md, the milestones/ archive dir, and the per-version MILESTONE-AUDIT.md) were hardcoded to root `.planning/`, so a workstream milestone close scattered its artifacts into root and never produced a workstream-local archive. They now derive from the workstream-aware planning base (`planningPaths(cwd).planning`); flat-mode (no --ws) is unchanged. (#1911) (#1917) +- **`phase complete` now reads milestone-grouped ROADMAP progress tables** — progress reported 0% on projects whose Progress table carries a Milestone column, because the reader assumed a fixed column position; it now resolves progress columns by name so both flat and milestone-grouped tables work (#2137). Quick Tasks logging via `/gsd:fast` also appends schema-correct, lock-safe rows instead of guessing the column count in shell (#2133). (#2248) (#2248) +- **Skill-bearing capabilities now surface correctly on flat command-layout installs** — on an install using the flat `commands/gsd-.md` source layout (e.g. a Claude Code local project install with no `commands/gsd/` subdir), every skill-bearing capability (`nyquist`, `code-review`, `security`, `ui`, `mempalace`, `ai-integration`, `profile-pipeline`) was silently reported `surfaced:false`/`enabled:false`/`active:false`, so their loop hooks (`verify:post`, `execute:post`, etc.) never fired even with the corresponding `workflow.*` toggle on. The skill-manifest resolver now detects the flat layout and produces the same stems the nested `commands/gsd/*.md` loader does. (#1858) (#2049) +- **Roadmap, requirements, and state table edits are confined to the right table** — the last ad-hoc table writers (phase completion updating roadmap progress, `requirements mark-complete`, and `state record-metric`/velocity) now route through the shared markdown-table seam, so a stray decoy table elsewhere in a document can no longer swallow a phase-progress update, a single ragged neighbouring row no longer silently aborts the whole edit, and per-plan metric recording no longer drops trailing section content or duplicates the section. (#2253) (#2253) +- **ROADMAP phase edits can no longer escape their section** — completing a phase updated its plan count and per-plan checkboxes with whole-document regexes that could bleed into a neighbouring phase; those per-phase writes are now structurally bounded to the phase own section via a new `withSection` / `withPhaseSection` seam (#2130, #2067, #2080). (#2250) (#2250) +- **STATE.md `## Session` fields now resolve on Windows** — the session-section reader used a `\n`-only heading regex that silently failed on a CRLF `## Session` heading, nulling all session state on Windows checkouts; it now reads through the CRLF-safe section seam. (#2253) (#2253) +- **Bullet/em-dash ROADMAP phases no longer resolve to `Phase null`** — the roadmap phase lookup matched only ATX headings with a colon, so a bullet entry like `- [ ] **Phase N — Name**` (which the roadmapper emits) failed to resolve and `Phase null` landed in STATE.md; a bullet-only ROADMAP also broke the milestone phase count. Phase lookup and the milestone filter now accept bullet/checkbox entries with an em-dash/en-dash/hyphen/colon separator. (#2199) (#2228) +- **Linuxbrew users no longer lose all GSD-managed hooks after `brew upgrade node`** — normalizeNodePath only recognized macOS Homebrew Cellar paths, so on Linux the version-pinned node path stayed baked into hook commands and 404'd after a node bump (and reinstall couldn't repair it). It now rewrites any Homebrew Cellar path — Intel, Apple Silicon, Linuxbrew, custom HOMEBREW_PREFIX — to the stable `/bin/node` symlink. (#2185) (#2225) +- **`milestone complete` no longer corrupts the recorded phase** — closing a milestone (e.g. `v0.5`) previously overwrote `current_phase` in STATE.md with the version's minor digit, and a follow-up `state complete-phase` mined a bogus `0.5` token and rewrote the file; phase resolution is now anchored so the real phase is preserved and a milestone-closure line is rejected. (#2111) (#2131) +- **Headless MemPalace capture no longer fails silently** — the headless invocation `mempalace mine --wing --room ` used a `--room` flag that does not exist on the `mine` subcommand (only `search` accepts `--room`), causing every headless/no-MCP capture run to fail with `unrecognized arguments: --room` and silently skip (onError: skip). The fix replaces the flag with MemPalace's documented room-assignment mechanism: stage the artifact under a room-named subfolder with a `mempalace.yaml` taxonomy so `detect_room()` assigns it via folder-path match. (#2220) (#2260) +- Fixed: a hand-authored non-inferable backstop truth with a stray trailing space or surrounding quotes no longer silently grades green — it correctly abstains (insufficient_spec), restoring the #1154 honest-verifier guarantee. (#1909) +- **`commit_docs` no longer silently disables on CRLF `.gitignore` repos** — git check-ignore falsely reports a trailing-slash path (e.g. `.planning/`) as ignored when the .gitignore has CRLF line endings with blank lines. isGitIgnored now strips trailing slashes before querying, so the false positive cannot occur. (#2206) (#2235) +- **Phase-directory resolution fails loud on cross-project collisions** — when two unrelated GSD projects share a `.planning/phases/` tree, a bare phase number silently resolved to the first `0N-*` directory found. The fix detects multiple matches and surfaces an `ambiguous_matches` result. (#2237) (#2262) +- **`scanPhasePlans` no longer counts PLAN-REVIEW artifacts as executable plans** — `*-PLAN-REVIEW.md` files were counted by the loose `/PLAN/i` fallback. The fix adds a `PLAN_REVIEW_RE` exclusion before the fallback. (#2252) (#2263) +- **Milestone audit no longer flags a not-yet-validated phase as a Nyquist failure** — a phase that was planned but never run through `validate-phase` now reports as NOT-VALIDATED (a "run validate-phase" TODO) instead of collapsing into PARTIAL alongside phases whose validation genuinely failed. (#2117) (#2209) + +### Security + +- **`gate="blocking-human"` checkpoints are no longer auto-approved by the execute-phase orchestrator** — the package-legitimacy gate (#2827) spans two layers: `gsd-executor` refuses to auto-approve a `gate="blocking-human"` checkpoint and escalates it via `checkpoint_return_format` so a human can vet the package, and `execute-phase`'s `checkpoint_handling` step decides what happens next. That step dispatched purely on checkpoint *type* and never read `gate`, so under `--auto` / `--chain` it immediately auto-approved the very checkpoint the executor had just refused to auto-approve (`human-verify → {user_response} = "approved"`). The slopsquatting defence was therefore inert in exactly the unattended mode where nobody is watching: an `[ASSUMED]`/`[SUS]` package reached install with no human ever seeing the verification prompt. `checkpoint_handling` now carves out `gate="blocking-human"` (and the package-legitimacy `what-built` markers) ahead of every auto-mode branch, routing those checkpoints to the standard present-to-user flow regardless of type. `references/checkpoints.md` documents the `gate` attribute and its two values for the first time — previously `blocking-human` appeared nowhere outside `agents/gsd-executor.md`, so no planner had a documented way to author a checkpoint that auto-mode could not bypass. The existing regression test asserted the executor half only; it now asserts the orchestrator half too, which is why it stayed green while the gate was open. (#2107) (#2113) +- **Hardened phase/roadmap/plan markdown parsing against quadratic-time (ReDoS) CPU exhaustion** — a crafted `ROADMAP.md`, `STATE.md`, or `PLAN.md` with large runs of unclosed `(`, `[`, ``, `