* feat(#4906): migrate the ROADMAP.md **Plans:** line onto the PlanningDoc seam Phase 2 of epic #4906. Migrates the two writers of ROADMAP.md's Plans field onto the seam ADR-4910 locks, and deletes both bespoke regexes per Decision 2 — a correct copy of a rule the seam now owns is the same divergence risk as an incorrect one. src/phase.cts's mutateMilestonePhase carried planCountBodyPattern, one capture group, replace-to-end-of-line: this is #4852, still live before this change. src/roadmap.cts's cmdRoadmapUpdatePlanProgress carried the correct three-arm sibling (the #2853/#3584 correction) that phase.cts never adopted. Both now call findField/setFieldValue/serialize against a PlanningDoc parsed from the same milestone/phase-confined substring their existing withPhaseSection / replaceInCurrentMilestone wrappers already compute — those confinement wrappers are unchanged, only the field-write mechanism inside them moved. Verified end-to-end through the real commands against real fixtures, not against an isolated reimplementation of the classification logic: cmdRoadmapUpdatePlanProgress and cmdPhaseComplete both preserve a trailing human annotation across a real count rewrite, and both leave a bracketed human annotation (the #3584 Finding A discriminator) untouched. Found and fixed inline, in the already-merged src/planning-document.cts, rather than deferred: BOLD_FIELD_RE recognized only **Label:** (colon inside the closing bold). gsd-core/templates/roadmap.md ships every field, Plans included, as **Label**: (colon outside) -- migrating roadmap.cts onto the seam as it stood would have silently regressed real generated ROADMAP.md files back to the bug this migration exists to remove. Widened to recognize both spellings; deliberately NOT widened to a bare unbolded Label: form, which would register ordinary prose as a spurious field. roadmap.cts's writer also recognizes a bare singular/plural count (1 plan / 3 plans, no fraction) as an existing count token to overwrite, not template- placeholder or freeform prose -- the template's own single-plan-phase shape and #3584 Finding B's fix. Preserved exactly; this shape is easy to drop by only porting the more common fraction form. Two of Phase 2's three originally-cited defects turned out to be already fixed on next, independent of this epic, and are struck via a dated ADR amendment rather than silently narrowed: #4862 (stateReplaceField's own anchoring hardening already preserves sibling fields) and #4499 (spliceFrontmatter's per-key preservation already keeps block sequences byte-identical). Both reproduced against the built module before being struck, not assumed. STATE.md's field-write engine is re-scoped out of this phase entirely -- not because of its get_impact rating alone (measured the same way, the two sites THIS phase keeps are also CRITICAL, and an earlier draft of the amendment claimed otherwise without checking; corrected) but because updateCore is a multi-field transaction with frontmatter sync and preservation reconciliation that does not map onto PlanningDoc's node model, where migrating it would mean designing that model, not calling an existing seam function. Refs #4852 Refs #4906 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * fix(#4906): preserve a trailing annotation with no em-dash separator Test authoring surfaced a real regression against an existing #3584 fixture: `**Plans**: 0/1 plans executed (11-16 are gap closure from VERIFICATION)` -- a parenthetical annotation glued on with a bare space, no em-dash -- was left completely untouched by the migrated code instead of being rewritten with the count updated and the parenthetical preserved. Root cause: planning-document.cts's parseBoldFieldLine splits a field's value from its trailing annotation only on the literal " -- " separator. An em-dash-separated annotation already lives outside `value` in `trailingSpan`, untouched by setFieldValue regardless -- that path was never broken. A parenthetical with no em-dash has nowhere to go but inside `value`, and the migrated classification required the WHOLE value to match a count-token shape exactly, so this case fell into "leave untouched." Fixed in the migrated call sites, not in the seam: prefix-match the count token against the field's current value, then re-glue whatever textual suffix follows WITHIN that value onto the new count text before writing. Correct for both shapes with no special-casing -- the em-dash case's suffix-within-value is empty by construction (the annotation already lives outside value), the parenthetical case's suffix is exactly the glued content, preserved verbatim. Deliberately not fixed by widening planning-document.cts's separator grammar to also recognize a bare-space-then-parenthesis: that seam is already-merged and already-tested, and guessing at an open-ended set of annotation shapes at the seam level is exactly what isTemplatePlaceholder already avoids by staying caller-side. "What counts as a Plans-field count token" is domain knowledge about this one field. phase.cts's writePlansField had no arm-2/arm-3 classification before this migration -- its original regex unconditionally overwrote whatever value was present. That unconditional-overwrite behavior is preserved exactly for values with no recognizable count-token prefix; only the recognized-count case gained suffix preservation, matching what phase.cts actually did before. Verified end-to-end via the real cmdRoadmapUpdatePlanProgress and cmdPhaseComplete commands against real fixtures for both the parenthetical and em-dash shapes at both sites. Refs #4906 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * test(#4906): cover the migrated Plans-line writers at both sites 15 cases across tests/phase.test.cjs and tests/roadmap.test.cjs, one per row of the phase test matrix, extending the existing describe blocks and helper functions those files already use for these two commands rather than building parallel fixtures. Covers: trailing-prose preservation on a real count rewrite at both sites (the #4852 regression, and the #2853/#3584 non-regression); zero-trailing- content boundary; the bracketed-template-placeholder vs bracketed-human- annotation discriminator (#3584 Finding A); a missing Plans field not crashing either command; an unrelated unreadable sibling node in the same confined section surfacing rather than corrupting the field; confinement holding across sibling phases and milestones; a round trip through the command's own read path; CRLF safety; and a parity assertion that both sites now produce identical Plans-line text for identical inputs, proving one shared mechanism rather than source-grepping for the deleted regex literals. Authoring caught a real regression before it could land silently: an existing #3584 fixture using a parenthetical annotation with no em-dash separator failed against the first version of the migration. Reported rather than edited to match the broken behavior -- see the paired fix commit. That existing test needed no changes once the fix landed; its assertion was verified independently against the real CLI before this commit. Refs #4906 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * fix(#4906): give phase.cts's Plans writer the same arm-2/arm-3 classification as roadmap.cts Isolated adversarial review (mandatory orthogonal review pass) executed writePlansField against `[Deferred pending re-scope]` and the fresh-template placeholder wording and found the first version of this migration kept phase.cts's OLD unconditional-overwrite behavior for the no-count-prefix case instead of adopting the same isTemplatePlaceholder / arm-3-untouched classification roadmap.cts's sibling site already uses. A bracketed human annotation was being silently rewritten to a new count -- a real content-destroying regression against this phase's own design-doc behavior table, not an accepted trade-off, and exactly the kind of divergence between the two sites Decision 2's parity requirement exists to eliminate. writePlansField now runs the same template-placeholder check and "no count prefix and not a placeholder => leave untouched" branch before ever calling setFieldValue. Added two site-1 tests (rows 4 and 6 of the phase test matrix) mirroring the existing site-2 coverage for this exact discriminator. Refs #4906 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * fix(#4906): restore plain (non-bold) Plans: line support and fix a test helper mismatch gsd-test (mandatory verification, run before every push) surfaced two real defects the migration's manual CLI checks had not caught: 1. #1163 regression: a hand-edited/pre-template ROADMAP.md can carry a PLAIN (non-bold) `Plans:` line rather than the canonical `**Plans**:`/ `**Plans:**` bold field. The old deleted regexes tolerated this shape; the seam's BOLD_FIELD_RE is deliberately bold-only (widening it would register ordinary prose like "Note: see below" as a spurious field seam-wide), so the migrated writers silently no-op'd on it instead of updating the count -- a real, previously-tested behavior lost. Fixed with a caller-side fallback in both src/roadmap.cts (where the failing #1163 test lives) and src/phase.cts (added for parity, per Decision 2 -- the two sites should not diverge on which legacy shapes they tolerate): when findField finds no boldField Plans node, look for a plain `Plans:` line directly and apply the same arm-1/2/3 classification against it. This is domain knowledge about one field's legacy tolerated shape, the same class of thing isTemplatePlaceholder already keeps caller-side rather than seam grammar. 2. tests/roadmap.test.cjs's new rows 4/5 (site 2) seeded the colon-outside spelling (`**Plans**: ...`) but their plansLineIn() helper only matched colon-inside (`**Plans:**`), so both assertions compared against `undefined` regardless of whether the write logic was correct -- a test-authoring bug, not a source defect. Fixed the helper to recognize both BOLD_FIELD_RE spellings, matching what the production code actually supports. Verified via a real gsd-test run before this fix (outcome: failed, 5 failures, all in tests/roadmap.test.cjs) and will be re-verified via a real gsd-test run on this commit before push, per this repo's non-rationalization rule: a red gate is fixed, never explained away. Refs #4906 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * chore(#4906): backfill the Phase 2 changeset fragment's PR number pr:0 -> pr:4933, now that gh api POST /pulls has returned the real number. Refs #4906 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> --------- Co-authored-by: sim <sim@local> Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
GSD Core documentation
Documentation is organised into four quadrants: tutorials help you learn by doing, how-to guides solve specific tasks, reference states authoritative facts, and explanation explores concepts and design decisions.
Language versions: English · Português (pt-BR) · 日本語 · 简体中文
Tutorials
- Your first project — install to first shipped phase, one guaranteed path
- Onboarding an existing codebase — bring GSD Core to a brownfield repo
- Build your first capability — author a tiny declarative capability and watch it act in the loop
- Install your first capability — install a third-party capability end-to-end: consent, verify, check for updates, remove
How-to guides
- Install on your runtime — runtime-specific install steps for all 16 supported runtimes
- Install a minimal GSD and add skills later — install only the core skills, then grow the surface with profiles and
/gsd-surface - Attach a plugin-provided skill to a GSD agent — use the
global:plugin:skillentry form to load Claude Code plugin skills into agent prompts - Discuss a phase — capture implementation decisions before planning begins
- Resolve edge-coverage findings — turn the spec phase's surfaced domain-boundary edges into covered, dismissed, or backstopped spec decisions
- Probe edges in a non-English project — get real edge coverage on a spec written in another language, and tell "no edges here" apart from "the probe could not read it"
- Resolve prohibition findings — turn the spec phase's surfaced must-NOT constraints into resolved, dismissed, or deferred spec decisions
- Resolve an unreachable-workflow finding — wire or fully sweep a shipped workflow that no command, agent, or skill references
- Acknowledge emitted-artifact drift — declare a deliberate emitted-byte ripple or workflow/agent growth in a commit trailer, and migrate an older ack fragment
- Change the STATE.md schema — add, change or remove a STATE.md frontmatter key and keep the template and all five reference documents in step
- Resolve verify-command path findings — fix an
<automated>verify command whose target directory does not resolve from the executor's cwd - State a failing direction — say what output constitutes failure for an
<automated>verify command, and migrate a phase planned before the rule - Resolve a contract-drift finding — bring an agent's completion contract, read-tag gate, or deleted-file test reference back into agreement with the registry
- Resolve unreachable-guard findings — fix shell guards whose fallback arm cannot run, and tell "nothing to report" apart from "could not look"
- Declare a hook's crash policy — terminate a GSD hook with
allow/deny/crash, declare itsON_CRASHpolicy, and tell a hook's own crash apart from a check that could not run at all - Resolve a skipped capability probe — act on a coverage gate that held your phase for an unestablished scope, or a planning checkpoint that reported
skippedinstead of a verdict - Diagnose which gsd-tools is running — tell this package's tool apart from the predecessor's colliding binary and from a gsd-core too old to identify itself
- Resolve an ESLint glob-coverage finding — bring a source file that matches no lint rule under coverage, or record a reasoned exemption
- Resolve a raw-terminator finding — pick
runMain/ExitError,terminateNow, orprocess.exitCodefor alocal/require-registered-exitfinding, and know the two allowlist entries and the rule's documented evasions - Adopt the v2 exit contract — turn on
gsd-tools's versioned exit-code projection, read the code table including what80(DEGRADED) means, and migrate a CI gate that treats any non-zero exit as fatal - Read the statusline freshness marker — turn on
state ~N commits back, and tell "STATE.md is fresh" apart from "freshness could not be established" - Consume the planning snapshot — read
planning inspectfrom a dashboard or harness, and tell "nothing to report" apart from "could not look" - Read CI timeout budget signals — find the near-cap warning on a run, read the accumulated
tests/ci-timeout-budget-history.jsonltrend, and know which lever (cap, shard balance, shard-1 contents) a repeatedly-near-cap lane calls for - Consume the state contract — read
.planning/state.jsonfrom a workbench or editor extension, gate on the contract version, and tell "nothing to show" apart from "could not look" - Keep planning docs out of a shared repo — make
.planning/local-only, including untracking files git already tracks (the step.gitignorealone cannot do) - Publish PRs without planning artifacts — keep
.planning/committed locally, so worktrees and/gsd-undokeep working, whileplanning.pr_strictkeeps every planning path out of the branch you push - Plan a phase — run research, decompose work, and verify plan quality
- Verify a dependency-compatibility claim — act on a compatibility claim the researcher left
[ASSUMED], and tell "nothing declared" apart from "a constraint is declared" and "the lookup failed" - Execute a phase — run plans in parallel waves with fresh-context subagents
- Enable parallel reviewer lanes — cut a multi-reviewer
/gsd-reviewpass toward its slowest lane, and tell a rate-limited lane apart from one that was never selected - Enable concurrent per-plan planners in chunked mode — dispatch chunked
/gsd-plan-phase's per-plan Tasks together within one outline Wave instead of one at a time, and know when the setting has no effect - Verify and ship — walk through completed work, diagnose failures, and create the PR
- Catch complexity before it compounds — enable the post-execute refactor hook, read a proposal's score vs. anchor delta, and accept or decline it
- Run phases autonomously — use autonomous mode for unattended phase execution
- Handle quick and fast tasks — use
/gsd-quickand/gsd-fastfor ad-hoc work outside the phase loop - Batch quick tasks — run several
/gsd-quick-shaped tasks together with/gsd-quick-batch, understand capacity/isolation, and recover a failed or interrupted batch - Configure model profiles — switch between quality, balanced, and budget model tiers
- Control which host runtime GSD reports — read the
agent_runtimeladder, understand what host detection looks at, and pin the runtime when detection is not what you want - Set up cross-AI review — configure a second AI to review code produced by the primary agent
- Scope code review depth by path — escalate
/gsd-code-reviewtodeepfor sensitive directories while the rest of the repo stays at the default depth - Work in parallel with workstreams — run independent lines of work simultaneously using workstreams
- Isolate work with workspaces — use workspaces to sandbox experimental or risky changes
- Debug a failed execution — diagnose and recover from broken or incomplete phase execution
- Interpret scope-conformance warnings — read the advisory the worktree-wave merge emits when a plan branch commits outside its declared scope
- Interpret install-shadow warnings — read the advisory GSD Core emits when a
/gsd-*trigger is installed at both scopes and one silently wins, and tell "nothing to report" apart from "could not look" - Interpret
state validateresults — read thescopereason codes and tell "nothing to report" apart from "could not look" - Spike and sketch — use
/gsd-spikeand/gsd-sketchfor exploratory work before committing to a plan - Design a UI phase — use the UI phase loop for frontend and visual work
- Enable live-DOM verification — opt a project into browser-backed UI acceptance checks during execution, handle the browser-profile lock, and tell "nothing to report" apart from "could not look"
- Enable UI interaction capture — let
/gsd-ui-review's auditor capture hover, focus, open-menu and filled-form states through thechrome-devtoolsCLI from Bash, with no MCP server - Develop a Capability for GSD 1.5+ — add feature Capabilities, hook fragments, and registry entries
- Develop a task-content resolver capability — declare a
taskContentResolversoexecute-plan.mdresolves per-task content from your external issue tracker instead ofPLAN.md - Ship a reviewer lane in your capability — declare a
reviewerbody so/gsd-reviewdiscovers, invokes, and renders your external review CLI or model endpoint - List your reviewer lane in the registry — publish a lane you have built to the Reviewer Lane Registry so other people can find and install it
- Take over a capability or EoS integration — assume maintainership of an existing third-party capability, reviewer lane, or EoS host integration through a handoff, an adoption fork, first-party absorption, or a de-listing
- Add or update a host's integration — set a host's documentation-sourced
runtime.hostIntegrationaxes (ADR-1239 Phase A), with theundocumentedsentinel rule - Migrate an install test to the executed plan — convert an
fs.existsSync-probing install test group to a value assertion againstinstallRuntimeArtifacts's executed-plan return, and test against a fake fs adapter - Vendor a dependency — add a third-party package
gsd-core/bin/**needs at runtime as a verbatim vendored artifact, keep it out ofdependencies, and pick the right upstream bundle - Turn a capability off (and keep it off) — disable a capability via the surface, or gate individual hooks off without removing the capability
- Drive GSD from a tracker issue — start a phase from a GitHub, Linear, or Jira issue
- Migrate from GSD 2 — upgrade an existing GSD 2 project to GSD Core
- Update GSD — re-run the installer to pick up the latest release
- Clean up get-shit-done-cc — remove leftover old-package artifacts that cause a spurious
⬆ /gsd-updateindicator after migrating to@opengsd/gsd-core - Fix the worktree base-mismatch (exit 42) error — resolve the branch-divergence condition that halts parallel phase execution
- Recover and troubleshoot — fix common problems, rebuild context, and uninstall
Reference
- Commands — every command with flags and examples
- Configuration — full config schema, model profiles, git branching strategies
- CLI tools —
gsd-tools.cjsprogrammatic API for workflows and agents - JSON error mode —
gsd-toolsfailure channels: faults (stderr, exit 1) vs degraded results (stdout, exit 0), and the reason-code taxonomy - Features — complete feature index
- Inventory — installed skills and surface map
- STATE.md schema — field-by-field reference for
.planning/STATE.md - CONTEXT.md schema — field-by-field reference for
.planning/phases/<N>/CONTEXT.md - PLAN.md schema — field-by-field reference for
.planning/phases/<N>/PLAN.md - Planning artifacts — all
.planning/files and their roles - Review and verification capabilities — code review, security, and Nyquist capability ownership and hook contracts
- Gate predicates — canonical specification of the phase-gate predicate vocabulary
- Capability matrix — generated catalogue of every capability's role, tier, extension points, hook kinds, and
engines.gsd - Exit code reference — generated catalogue of every registered process exit code, its name, meaning, and owning module, plus the reserved bands and the v1/v2 exit contract
- Capability manifest — the full
capability.jsonschema and validation rules gsd capabilitycommand — install / update / remove / list reference for third-party capabilities- Workflow fragments — in-file
<!-- gsd:section -->marker grammar for fragmentizing workflow markdown at emission time - Partition rules for compact-content splits — the protected-content list, sentinel syntax, and the five CI checks a
workflow.compact_contentspine/detail split must obey - Reviewer Lane Registry — generated catalogue of third-party reviewer lanes, with their flags, transport, and install commands
Explanation
- Context engineering — how context rot forms and how GSD Core prevents it
- The phase loop — design rationale for the Discuss → Plan → Execute → Verify → Ship cycle
- Multi-agent orchestration — how subagents are spawned, scoped, and coordinated
- Security model — trust boundaries, permissions, and safe automation
- The capability trust model — why third-party capabilities are gated by consent + integrity + reversibility, not a sandbox
- How overlay capabilities compose — why first-party always wins and how the loader resolves precedence, conflicts, and fail-open load-failure warnings
- Architecture — system architecture, agent model, and data flow
- The Embeddable Orchestration System — one public, versioned contract for embedding GSD across many hosts
- Discuss modes — assumptions mode vs interview mode for
/gsd-discuss-phase - Context monitoring — context window monitoring hook architecture
- Issue-driven orchestration — recipe for driving GSD from a tracker issue using existing primitives
Related
- What's new in 1.7.0 — curated highlights of the 1.7.0 release
- Root README — landing page, quickstart, and documentation overview
- Changelog — release history