* refactor(#56): retire legacy runtime directory helpers into runtime-homes projection
Consolidate per-runtime global config-dir resolution onto the single
canonical projection runtime-homes:getGlobalConfigDir. Extend it with the
explicitDir override (CLI --config-dir) and the opencode/kilo
OPENCODE_CONFIG/KILO_CONFIG file-path precedence the installer helpers had,
making it byte-for-behavior equivalent to the old getGlobalDir across all
15 install runtimes.
Delete bin/install.js's getGlobalDir/getOpencodeGlobalDir/getKiloGlobalDir
(and the orphaned local expandTilde), repoint all 9 call-sites, and remove
getGlobalDir from module.exports (net -242 lines in the installer). Migrate
the 5 test importers to the canonical projection; harden default/XDG
assertions against ambient *_CONFIG env vars. getAgentsDir now respects
OPENCODE_CONFIG/KILO_CONFIG consistently with the installer (intentional
convergence). Update CONTEXT.md Installer Module entry.
Completes the installer-refactor chain #58 -> #60 -> #56.
Closes#56
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* chore(#56): add changeset for runtime directory helper retirement
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* feat(#766): distribute gsd-core as a native Claude Code plugin
Add an additive .claude-plugin/plugin.json manifest plus hooks/hooks.json so gsd-core can be installed as a first-class Claude Code plugin (marketplace or zero-friction @skills-dir), with /gsd-core: namespaced commands and lifecycle management — alongside the unchanged npm/file-copy installer.
- .claude-plugin/plugin.json: validated with 'claude plugin validate --strict'
- hooks/hooks.json: mirrors the installer's always-on Claude hook wiring via ${CLAUDE_PLUGIN_ROOT}
- package.json: ship .claude-plugin in the npm tarball
- tests/issue-766-plugin-manifest.test.cjs: manifest + always-on-hook-contract drift guards
- docs: install-on-your-runtime.md + FEATURES.md
Closes#766
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* docs(#766): add ADR-766 + glossary entry for Claude Code Plugin Manifest Module
Record the plugin manifest as the Seam projecting gsd-core's artifact surfaces onto the Claude Code plugin contract (sibling of the Runtime Artifact Layout Module, ADR-3660), with the defined kind->field mapping and the always-on hook projection rule.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
test.yml had no paths filter and the ci-test-scope classifier treated docs/
and every .github/workflows/* as code_changed, so documentation edits and
product-irrelevant automation tweaks still spun up the full Linux/Windows/macOS
matrix. Narrow the heavy matrix to changes that can actually affect the product
or the test pipeline.
- ci-test-scope.cjs: drop docs/ from code_changed (docs-only -> full skip; the
required-tests fan-in still reports green). Add src/ to code_changed (it was
missing -> a source-only PR previously skipped all tests). Add INERT_WORKFLOWS
allowlist + isInertCi() + an "inert CI" rule, and a product_changed output that
gates the heavy test/coverage jobs. Fail-safe: any workflow not on the inert
allowlist defaults to the full matrix. A module-load assertion throws if a
PROTECTED_WORKFLOWS entry (test/install-smoke/mutation/security-scan/release)
is ever added to the inert set, so a weakening edit fails CI loudly.
- test.yml: keep the static 3-lane matrix (so the H1 shell-policy linter can
still statically verify the Windows lane), gate test/coverage on
product_changed, add a lightweight ubuntu-only test-inert job, and branch the
required-tests fan-in on product_changed.
- docs-required.yml: run docs-parity-live-registry (gated on docs/ changes) so
pure-docs PRs still catch live-registry drift without the matrix.
- tests: cover docs-only, inert-only, src/, pipeline, unknown-workflow fail-safe,
mixed escalation, the code_changed=false -> no-lanes invariant, and protected-
workflow tamper-evidence.
Closes#764
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* refactor(#60): make runtime config adapter registry explicit
Replace scattered inline `runtime === '...'` config-mutation branching in
bin/install.js with an explicit, typed adapter registry. The new
src/runtime-config-adapter-registry.cts maps each of the 15 supported
runtimes to a config intent { installSurface, writesSharedSettings,
finishPermissionWriter }; install()/finishInstall() dispatch by resolved
intent instead of runtime-name checks (cursor/windsurf/trae collapse to one
profile-marker-only branch).
Behavior-preserving: the same config files are written for the same runtimes
(opencode still writes both settings.json and its permissions; kilo writes
only its permissions; codex minimal-mode and opencode GSD_TEST_MODE guards
unchanged). Unknown runtimes fail loudly via TypeError, with an Object.hasOwn
barrier so prototype-chain keys (__proto__/constructor) also throw rather than
returning a bogus intent. Leads the installer-refactor chain (#58 -> #60 ->
#56), building on ADR-58.
Closes#60
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* chore(#60): add changeset for runtime config adapter registry
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* docs(#60): register Runtime Config Adapter Registry in CONTEXT.md glossary
Per docs/contributor-standards.md, every new Module/seam must get a
`### <Name>` entry under the domain glossary. Adds the entry for the
runtime-config-adapter-registry seam introduced in this PR (interface,
policy boundary, source file, ADR-58 / #60 cross-references).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* test(#339): add regression guard for gsd-sdk refs in runtime surfaces
Lock in the already-clean runtime surface so a retired `gsd-sdk`/`GSD_SDK`
reference cannot creep back into a shipped prompt or hook. Scans
gsd-core/workflows, gsd-core/references, commands/gsd, agents, and hooks
(excluding the gitignored dist/ build artifact).
Complements gsd-tools-path-refs.test.cjs, which only catches the
`gsd-sdk query` binary form; this catches any runtime reference. A second
test guards against an empty sweep so a future dir rename can't silently
turn the guard into a no-op.
Intentionally does NOT touch bin/install.js (live stale-package-detection
mechanics per #339 triage) or CI/lint scripts (legitimate stale detection).
Refs #339
* test(#339): split file content on /\r?\n/ for Windows CRLF parity
The windows-test-parity-guard lint requires test files that readFileSync +
split to use /\r?\n/, not '\n', so CRLF files don't leave a trailing \r.
New test files are not in the PR #3649 allowlist.
* test(#339): cover .sh/.json runtime files in workflows surface
Address #691 review: the gsd-core/workflows surface scanned only .md,
silently skipping two deployed runtime files — _runtime-launcher.snippet.sh
(synced into every hook) and discuss-phase/templates/checkpoint.json. Add
.sh/.json so the guard covers all 290 deployed runtime files (was 288/290),
not just the .md subset.
* test(#339): cover templates/contexts surfaces + per-ext empty-sweep guard
Address PR #691 review (trek-e):
- Add gsd-core/templates and gsd-core/contexts to RUNTIME_SURFACES —
both are deep-copied by the installer and runtime-loaded via
@~/.claude/gsd-core/templates/*.md anchors, so a reintroduced gsd-sdk
ref there would have slipped past the guard. (major)
- Reword the bin/install.js exclusion rationale: it has zero gsd-sdk refs
today (subsystem removed in #515, shim retired in #522); the real reason
it is excluded is that it is installer code, not a deployed prompt/hook
surface. (minor)
- Make the empty-sweep guard assert coverage per configured extension, not
per surface — .md files alone kept gsd-core/workflows green even if
.sh/.json were dropped, silently un-covering _runtime-launcher.snippet.sh
and discuss-phase/templates/*.json. (low)
---------
Co-authored-by: Tom Boucher <trekkie@nomorestars.com>
close-draft-prs.yml (on pull_request_target after #760) cannot close fork draft
PRs whose head branch name looks like a Git SHA — GitHub never dispatches
pull_request_target for such branches, and a pull_request run from a fork gets a
read-only token. So a draft PR on a SHA-named fork branch evades the auto-close.
Add close-draft-prs-sweep.yml: a schedule (every 6h) + workflow_dispatch sweep
running in base-repo context with pull-requests: write that paginates open PRs,
filters to non-OWNER/MEMBER/COLLABORATOR drafts, and closes + comments them with
the identical policy/message as the event-driven workflow. Re-fetches each
candidate before mutating (TOCTOU guard), closes before commenting so
enforcement is never gated on the explanatory comment, and core.setFailed on
partial failures. The per-PR workflow remains the fast path; this is the
safety net for the documented residual bypass.
Extends tests/workflow-maintainer-skip.test.cjs with structural guards locking
the triggers, write permission, maintainer carve-out, pagination, and message.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
The rc action publishes a release candidate to @next for testing but
never surfaces the curated CHANGELOG section for the version under test —
render only runs destructively at finalize (#715), so there was no safe
way to preview the upcoming notes during the RC window.
Add a --preview mode to scripts/changeset/cli.cjs cmdRender: it renders
the dated release section to stdout via the existing renderChangelog/
serializeChangelog path (with priorChangelog: null, so only the new
section is emitted), reuses the shared injectEmptyPlaceholder helper for
zero-fragment releases, and returns WITHOUT writing CHANGELOG.md or
deleting any .changeset fragment. Wire a "Preview CHANGELOG" step into
the rc job that renders to a file (standalone command, so a malformed
fragment fails the step) and cats it to the job summary and log.
Closes#759
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Record the Runtime Install Policy Module decision and ownership
boundary: install policy projects a pure, typed install plan by
composing artifact placements (ADR-3660) and command text (ADR-0009)
plus per-runtime config intentions, with no filesystem IO; runtime
adapters consume the plan and execute concrete file mutations and
format-specific config rendering. Explicitly records what stays
outside the policy module (TOML/JSON/Markdown serialization, merge
semantics, filesystem effects).
Adds the ADR index row in docs/adr/README.md and a glossary entry in
CONTEXT.md. Leads the installer-refactor chain (#58 -> #60 -> #56).
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Bare `pull_request` hands fork PRs a read-only GITHUB_TOKEN, so the
close/comment API calls 403 and a first-time/external contributor's draft
PR survives — bypassing the auto-close for exactly the population the job
targets. Switch to `pull_request_target`, which runs in the base-repo
context with a write-capable token even for fork PRs. Safe because the job
never checks out or executes PR-supplied code; it only reads event metadata
and calls the GitHub API. The minimal `permissions: pull-requests: write`
block still constrains the token.
Add a regression guard in tests/workflow-maintainer-skip.test.cjs asserting
the workflow triggers on pull_request_target and not bare pull_request.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* refactor(#651): consolidate verification-status routing into one queryable seam
The passed/gaps_found/human_needed verification status was re-encoded as
bare strings across three prose surfaces (gsd-verifier emits, execute-phase
routes, ship gates), each independently deciding the per-status next action
with no parity coupling — the DEFECT.GENERATIVE-FIX class.
Give the enum one home: src/verification.cts (-> bin/lib/verification.cjs)
exposing `gsd_run query verification.status <phaseDir>` returning a typed
{status, next_action, next_command}. ship.md and execute-phase.md now consume
the query instead of re-deriving the routing in prose; gsd-verifier.md points
at the shared vocabulary as the single emitter (values unchanged).
Also fixes the latent broad-grep status misread (DEFECT.FRONTMATTER-SCALAR-
BROAD-GREP): execute-phase.md read `grep "^status:"` over the whole report, so
a body `status:` line could misroute a valid phase. Extraction is now
frontmatter-scoped in one place. A parity test fails if a verifier status
gains no route. Lands the two CONTEXT.md DEFECT entries captured on the issue.
Closes#651
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* chore(#651): set changeset pr to 755
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* feat(#52): add agent_skills_security.trusted_global_roots allowlist
Opt-in allowlist so a global: agent skill whose SKILL.md realpath resolves
outside the default global skills base (e.g. ~/.claude/skills) is accepted
when its real target lies under a user-declared trusted root. Default [] is
byte-identical to prior behavior; the symlink-escape guard is preserved and
simply re-applied against each declared root.
- src/security.cts: loadTrustedGlobalRoots — tilde-expand (~ and ~/), reject
project-relative and dangerously broad roots (filesystem/UNC root, homedir),
realpath-canonicalize each root every run and drop non-existent ones.
- src/init.cts: on base-check failure the guard consults the trusted roots
(hoisted out of the loop); emits a stderr NOTE when a skill is accepted via
a trusted root so the widened boundary is visible.
- src/core.cts: thread agent_skills_security through loadConfig.
- config-schema.manifest.json: allow the new key path.
- docs/CONFIGURATION.md: document the option and its security model.
- tests/agent-skills.test.cjs: unit + end-to-end CLI coverage (regression,
feature, negative, broad-root hardening, stderr NOTE).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* docs(#52): add changeset fragment for trusted_global_roots (#754)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* feat(#25): scope gsd-verifier Step 7b to enumerate-or-single-test; forbid full-suite re-runs
Step 7b's lone test example (`npm test -- --grep "$PHASE_TEST_PATTERN"`) is
mocha/vitest/jest-specific, where `--grep` filters which tests *execute*. Models
generalized it to `cargo test --workspace 2>&1 | grep X` (runs the whole suite,
filters only *output*) and repeated it once per must-have, adding minutes per
verification with no new evidence after the first run.
Replace the example with language-agnostic guidance: prove a test EXISTS via
enumeration (`cargo test -- --list` / `pytest --collect-only` / `npx vitest
list` / `go test -list`), and prove it PASSES via a single named test
(`cargo test <name> -- --exact` / `pytest -k` / `npx vitest run -t`). Add a
Spot-check constraint forbidding more than one full-suite run per verification
or piping a full run through grep per must-have, while still permitting one
saved run + grep when a full run is genuinely required. docs/AGENTS.md gains a
one-line Key-behaviors note, and a new test asserts the Step 7b content.
Scoped per the maintainer decision on the issue: folded into Step 7b (no new
top-level Step 7a) with no VERIFICATION.md label changes.
Closes#25
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* chore(#25): add Changed changeset fragment for PR #753
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
CodeQL alert #26 (js/prototype-pollution-utility) kept firing on setConfigValue
because its dataflow does not trace the #663 Set-based, pre-loop keys.some(...)
forbidden-key check as a sanitising barrier on the write site.
- src/config.cts: replace the Set + pre-loop check with inline literal
comparisons (key === '__proto__' || 'prototype' || 'constructor') on the exact
key used to index `current`, immediately before each write (intermediate keys
in the descent loop, plus the final key). Same forbidden set, same error
message and ERROR_REASON.CONFIG_PARSE_FAILED — behaviour unchanged from #663,
but the barrier is now CodeQL-recognised.
- tests/config.test.cjs: add regression tests for schema-valid dynamic-prefix
keys (agent_skills.__proto__, agent_skills.constructor, agent_skills.prototype,
features.__proto__, review.models.constructor) that pass the isValidConfigKey
schema gate and reach the guard. Each asserts the guard's own message fires
(not the schema gate's "Unknown config key") and Object.prototype is not
polluted. The prior #663 tests never reached the guard — their keys are
rejected by the schema gate first — so the guard's real attack surface was
untested.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* feat(#703): add --granularity override flag to /gsd:plan-phase
Add a `--granularity <coarse|standard|fine>` flag to /gsd:plan-phase that
overrides the configured planning granularity for a single invocation.
The override is a new highest-priority tier above the existing precedence
chain (granularities[phaseType] -> granularity -> planning.granularity ->
'standard') in resolveGranularityInternal; when the flag is absent, resolution
is byte-for-byte unchanged. cmdInitPlanPhase now resolves with phaseType
'planning' so granularities.planning participates, and emits the resolved
value in the init JSON, which the plan-phase workflow forwards to the planner
prompt. Invalid values are rejected at the CLI boundary via a shared
assertValidGranularityOverride helper.
Closes#703
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* chore(#703): set changeset pr to 750
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* fix(#683): auto-degrade phase execution to sequential on worktree base mismatch
Claude Code forks worktree-isolated executors off the repository default
branch (origin/HEAD), not the orchestrator's HEAD. Running /gsd-execute-phase
on a branch diverged from the default (unmerged milestone/feature branch) left
every executor without the phase's plan files and tripped the
worktree-branch-check guard with `exit 42` — 100% reproducible, all OSes.
- New module src/worktree-base-ref.cts: HEAD-vs-fork-base drift detection
(origin/HEAD with symbolic-ref fallback) and no-clobber worktree.baseRef
management, exposed as `worktree base-check` / `worktree set-baseref`.
- execute-phase.md: pre-dispatch, for Claude Code with worktrees enabled,
auto-degrades the run to sequential on the main tree when a base mismatch
is detected, recommending worktree.baseRef:"head". The exit-42 guard stays
as a backstop.
- Installer: fresh local Claude installs set worktree.baseRef:"head" in
.claude/settings.local.json (no-clobber, respecting an explicit shared
settings.json value); upgrades print an opt-in notice pointing at
`gsd-tools worktree set-baseref`.
- Docs: how-to guide, CLI/config reference, planning-config cross-ref.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix(#683): auto-apply worktree.baseRef on upgrade; gate fresh+upgrade on use_worktrees
Per maintainer direction: on a local Claude Code UPGRADE, set
worktree.baseRef:"head" automatically (no opt-in notice) when the project's
workflow.use_worktrees is enabled, instead of merely printing a remediation
notice. For consistency the FRESH path is now gated the same way: both paths
compute worktrees-enabled once (bounded walk-up read of .planning/config.json,
default enabled unless workflow.use_worktrees === false) and apply the
no-clobber baseRef only when enabled — never overwriting an explicit value in
settings.local.json or a shared settings.json. gsd-tools worktree set-baseref
remains for manual use. Docs + changeset updated; tests hardened (file-exists
assertions, fresh+disabled case, upgrade idempotency).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix(#683): measure workflow byte-budget on LF, fixing Windows-only CI failure
The workflow-size-budget test failed only on Windows: git checks out the .md
files as CRLF (no eol=lf in .gitattributes) and byteCount used
fs.statSync().size (raw on-disk bytes), counting an extra \r per line. That
inflated execute-phase.md — the XL high-water-mark file pinned near its ceiling
by the tighten-only ratchet — from 88492 LF bytes to ~90245 on Windows, over
the 90000 XL ceiling, while passing on the LF-checkout Mac/Linux runners.
The ceilings are explicitly "calibrated against raw `wc -c`" on an LF checkout,
so the measurement should be LF-based on every platform. byteCount now reads the
file and counts Buffer.byteLength after stripping CR, making the budget
platform-independent (a no-op on LF checkouts; verified statSync === normalized
for all 88 workflow files). No ceilings changed. Added a regression test
asserting CRLF and LF content of the same file count identically.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix(#683): make worktree-base-ref test path mocks Windows-safe (path.join)
tests/worktree-base-ref.test.cjs keyed its injected readFile/writeFile mocks
(and a few expected `file` values) with forward-slash template literals like
`${claudeDir}/settings.local.json`. The module composes those paths with
path.join(), which emits backslashes on Windows, so the mock keys never matched
the module's lookup → readFile returned null → resolveEffectiveBaseRef /
cmdWorktreeBaseCheck / cmdWorktreeSetBaseRef (and the JSONC variants) failed on
the Windows full-test runner only (they passed on Mac/Linux, and the install
tests passed because they use the real filesystem). The module is correct;
only the test fixtures hardcoded '/'.
All mock keys and path assertions now use path.join(base, ...) mirroring the
module, so they match on every platform (no-op on POSIX). 19 path references
across 16 lines.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
`extractCurrentMilestone()` scoped the current-milestone window to its
`## Phases` checklist subsection and terminated at the milestone's own
`## Milestone … (Phase Details)` heading, so the `### Phase N:` detail
headers fell outside scope. Every parser-backed command — `init.phase-op`
(and thus `/gsd:discuss-phase`, `/gsd:plan-phase`), `state`, `roadmap list`,
and `validate health` (W006) — therefore could not resolve phases of any
milestone after the first until a `.planning/phases/` directory already
existed, blocking discuss/plan.
The parser now additionally includes the current milestone's `(Phase Details)`
section in scope, located via the already-computed version matches and anchored
(boundary-aware) to the selected milestone's version token so sibling
sub-milestones sharing a version prefix do not cross-pollinate. The existing
heading selection and primary window are unchanged.
Adds tests/bug-730-milestone-phase-details-scope.test.cjs covering the
two-milestone reproduction, first-milestone non-regression, direct
getRoadmapPhaseInternal resolution, validate-health W006 visibility, a
three-milestone roadmap, and the closed-sibling sub-milestone case.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* refactor(#712): replace Codex slash-command denylist lookbehind with positive-boundary match
The hyphen-style /gsd-<cmd> -> $gsd-<cmd> conversion in
convertSlashCommandsToCodexSkillMentions used a negative-lookbehind DENYLIST
enumerating characters that must NOT precede a real mention. #637 -> #704 showed
this is an unbounded treadmill: each new unanticipated preceding char (/, ., word
chars, then }, )) leaked the same path-corruption bug class, and a backtick-wrapped
path (`/gsd-core/workflows/update.md`) still leaked through.
Replace it with a POSITIVE two-boundary definition of a mention:
1. Left: opens at start-of-string, whitespace, or an inline-prose delimiter
(backtick/quote/paren/bracket).
2. Right: the command token is not followed by a path separator `/` (a path
continues, a command does not). The (?![a-z0-9/-]) lookahead also blocks
regex backtracking to a shorter command.
This closes the whole class by construction (no preceding-char denylist to
maintain) and fixes the backtick-wrapped-path corruption the #704 test
documented as a pre-existing gap, while preserving conversion of legitimate
backtick-wrapped mentions (e.g. CONTEXT.md's `/gsd-execute-phase` lists).
The colon-style /gsd: replace is intentionally left unguarded (it never appears
as a filesystem path segment) and is annotated as such.
Tests assert the regex directly (function now exported) across a convert/
don't-convert matrix plus one end-to-end pipeline assertion for the headline
backtick-path case.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* chore(#712): add changeset fragment for PR #747
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* refactor(#720): lazy-load MVP-only reference bodies (eager @-import → gated Read)
Convert eager @-imports of MVP-only reference bodies into lazy "Read" instructions
gated on MVP_MODE / WALKING_SKELETON / MVP+TDD, so non-MVP planning/execution runs
no longer pull MVP guidance into context. Covers both the workflow files and the
planner/executor agent definitions (the dominant context-cost path):
- workflows/plan-phase.md: planner-mvp-mode.md + skeleton-template.md (L146/936/937/941)
- workflows/execute-phase.md: execute-mvp-tdd.md halt-report ref, now gated on gate-trip (L191)
- agents/gsd-planner.md: planner-mvp-mode.md, user-story-template.md, skeleton-template.md
- agents/gsd-executor.md: execute-mvp-tdd.md
The dedicated always-MVP mvp-phase workflow keeps its eager imports (intentional).
Behaviour is unchanged; non-MVP runs simply carry less loaded context. Adds a
regression guard mirroring the discuss-phase lazy-load test, and documents the
conformance in docs/ARCHITECTURE.md.
Refs #720
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* docs(#720): add changeset fragment (pr #746)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Part 2 of 2 of the n/no-process-exit cleanup (completes umbrella #738; part 1
was #739/scripts). Converts the 20 flagged process.exit() calls in the three
hand-written gsd-core/bin CLI entrypoints and flips n/no-process-exit to error.
- New src/cli-exit.cts -> gsd-core/bin/lib/cli-exit.cjs (ExitError + runMain),
the gsd-core-side equivalent of scripts/lib/cli-exit.cjs; registered in
.gitignore, eslint ignores, and the inventory manifest like its siblings.
- gsd-tools.cjs: 13 apply-prompt-budget exits -> throw ExitError; main()->runMain.
- verify-reapply-patches.cjs: 6 exits -> throw ExitError / return verdict; runMain.
- check-latest-version.cjs: 1 exit -> return verdict; runMain.
- eslint.config.mjs: n/no-process-exit warn -> error.
Scope note: the gsd-core/bin/lib/*.cjs modules (core, state, profile-pipeline,
roadmap-command-router, adr-parser, ui-safety-gate) are tsc-generated and
eslint-ignored (ADR-457), so their process.exit calls were never flagged and are
intentionally left untouched. Only the linted hand-written entrypoints are in scope.
Exit codes verified unchanged for all three entrypoints.
Closes#738
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
- stage generated Kimi root and subagent YAML/prompt files under agents/
- copy and remove only GSD-owned Kimi agent files while preserving user files
- print explicit kimi --agent-file launch hint
- Wire Kimi global layout to convertClaudeCommandToKimiSkill
- Keep --kimi --local guarded as a no-op
- Add Kimi self-invocation hint without agent or tool artifacts
- Resolve Kimi global skills under the generic agents path
- Add empty Kimi layout placeholder and local install no-op guard
- Keep selection/path tests aligned without Kimi skill conversion