* fix(#3019): query --help reaches handler instead of short-circuiting to top-level usage
The query argv parser in sdk/src/cli.ts harvested -h/--help as a global
flag and main() short-circuited dispatch when args.help was true. Net
effect: every `gsd-sdk query <anything> --help` printed top-level USAGE
instead of contextual subcommand help. There was no path for users to
discover what arguments a query subcommand accepts — they had to trigger
"required" errors by trial and error.
Two-layer fix:
1. sdk/src/cli.ts (parseCliArgsQueryPermissive)
- Push -h / --help onto queryArgv instead of consuming them silently,
so the registered handler / gsd-tools.cjs fallback gets to interpret
the flag and render contextual help.
- Only honor the global help flag when there is NO real subcommand to
dispatch to (i.e. queryArgv contains only help flags). Preserves
`gsd-sdk query --help` → top-level USAGE while letting
`gsd-sdk query phase add --help` reach the handler.
2. get-shit-done/bin/gsd-tools.cjs
- Render top-level usage on --help / -h / -? / --usage instead of
erroring with "Unknown flag". The discovery hint in the usage text
points users at the working method (run without args → error names
required arguments) and references #3019 for tracking subcommand-
level help printers.
- --version remains rejected (no discovery use-case).
#1818 anti-hallucination invariant preserved: the destructive command
NEVER executes when --help is present. The new shape returns success:true
+ usage on stdout instead of the old success:false + error on stderr —
both satisfy "destructive command did not run", and the new shape also
restores discoverability.
Tests:
- sdk/src/cli.test.ts: 4 new vitest cases covering #3019 — query argv
parser keeps --help with subcommand, parses -h short flag, preserves
bare `query --help` top-level behavior, preserves --help position when
intermixed with other query flags.
- tests/bug-3019-help-passthrough.test.cjs: 5 node:test cases on the
fallback — bare gsd-tools (no args) errors with usage; --help renders
usage on stdout exit 0; -h same; subcommand --help renders usage; usage
hint mentions discovery method (without prose substring matching —
parses into typed sections).
- tests/bug-1818-unknown-flags.test.cjs: rewritten to assert the new
invariant ("destructive command did not run" + "usage was rendered")
instead of the old shape ("--help is rejected with non-zero exit").
Each destructive test seeds a sentinel artifact (phase dir, slug
output) and asserts it survives.
Verification:
- 47/47 vitest pass on sdk/src/cli.test.ts
- 5/5 pass on tests/bug-3019-help-passthrough.test.cjs
- 8/8 pass on tests/bug-1818-unknown-flags.test.cjs (rewritten)
- 6763/6763 pass on full node:test suite
- lint-no-source-grep clean (0 violations)
Closes#3019
* fix(#3019): SDK fallback forwards plain-text help, broader usage list (CR)
CodeRabbit on PR #3026 (4 findings — 1 Major outside-diff, 2 inline,
1 nitpick):
1. **Major outside-diff** — sdk/src/cli.ts:442-454. The fallback path
that delegates to gsd-tools.cjs called parseCliQueryJsonOutput
(JSON.parse) on stdout. Now that gsd-tools renders plain-text usage
on --help, JSON.parse threw "Unexpected token 'U'". Wrapped the
parse in try/catch — on parse failure, forward the plain stdout
verbatim so subcommand help reaches the user. Regression test:
tests/bug-3019-help-passthrough.test.cjs spawns the built SDK and
asserts `gsd-sdk query phase --help` exits 0, stdout contains the
gsd-tools usage, and stderr does NOT contain a JSON-parse error.
2. .changeset/help-passthrough.md:3 — `pr: TBD` → `pr: 3026`.
3. gsd-tools.cjs:346 (TOP_LEVEL_USAGE):
- Removed self-referencing `#3019` link (immediately stale after
this PR merges).
- Expanded Commands list from 17 → all 47 dispatcher cases:
agent-skills, audit-open, audit-uat, check-commit, commit, …
phase, phases, roadmap, milestone, validate, progress, intel,
graphify, learnings, etc. — the bulk of the surface that was
previously unreachable via --help discovery.
4. Nitpick: `isUsageOutput` was duplicated in bug-1818 and
bug-3019-help-passthrough tests. Moved to tests/helpers.cjs with
structural-comment, removed both duplicates.
Verification: 47/47 vitest pass, 14/14 regression tests pass,
6764/6764 full suite, lint clean.
* test(#3019): use t.skip() instead of bare return when SDK not built (CR)
CodeRabbit follow-up on PR #3026:
The integration test guarded against missing sdk/dist/cli.js with a
bare `return;` — node:test counts that as a passing test (0 assertions
exercised, 0 failures). On a CI checkout that hasn't run the SDK build,
the #3026 regression test silently green-lit and no signal ever
surfaced that the integration check was skipped.
Switched to `t.skip(...)` via the test context parameter so the
omission shows up in the test report. The unit-level fix
(sdk/src/cli.ts) is still covered by vitest, so the skip only affects
the end-to-end spawn-built-SDK check.
Verification: 6/6 pass when SDK is built; 5 pass + 1 skip when not.
* test(#2974): migrate 8 test files to typed-IR assertions
Replaces raw stdout/stderr substring matching with structured-field
assertions per CONTRIBUTING.md "Prohibited: Raw Text Matching on Test
Outputs". Adds shared infrastructure for typed error emission so this
pattern is the easy path going forward.
Shared infrastructure:
- core.cjs: ERROR_REASON frozen enum + setJsonErrorMode/getJsonErrorMode
- gsd-tools.cjs: --json-errors CLI flag, parsed before subcommand dispatch
- config.cjs: typed reasons at all 7 error sites
- graphify.cjs: GRAPHIFY_REASON enum + reason/timeout_ms in execGraphify result
- bin/install.js: pure buildSdkFailFastReport() IR builder + renderer
- hooks/gsd-session-state.sh, gsd-phase-boundary.sh: emit Claude Code
hookSpecificOutput JSON envelope with typed state_present/config_mode/
planning_modified/file_path fields (no-op when hooks.community is off)
Test migrations (all pass, 171 tests across the 8 files):
- bug-2649-sdk-fail-fast: assert on ir.reason / ir.context / ir.fix_command
- bug-2687-config-read-warning-parity: assert.equal stderr === ''
- bug-2796-arg-parsing-regression: assert on result.json.updated/.phase
- bug-2838-summary-rescue: parse rescue footer, assert mtime invariant
- bug-2943-config-get-context-window: parse JSON, assert ERROR_REASON.CONFIG_KEY_NOT_FOUND
- graphify: assert reason === GRAPHIFY_REASON.ENOENT/TIMEOUT
- hooks-opt-in: parse hookSpecificOutput, assert typed fields
- security-scan: reclassified as source-text-is-the-product (scan label
output and CI workflow YAML ARE the deployed contract)
Verification: lint-no-source-grep clean (0 violations), full suite
6741/6741 pass.
Closes#2974
* test(#2974): address CR feedback — typed code field, robust idempotency
Two CodeRabbit findings on #3016 addressed:
1. tests/hooks-opt-in.test.cjs:355 (Minor, inline) —
parsed.reason.includes('Conventional Commits') was still substring
matching after the typed-IR migration. Fixed at the source: the
gsd-validate-commit hook now emits a typed `code` field
('CONVENTIONAL_COMMITS_VIOLATION', 'COMMIT_SUBJECT_TOO_LONG')
alongside the human-readable `reason`. Test asserts strictEqual
on the code; the prose copy is no longer part of the test contract.
2. tests/bug-2838-summary-rescue-gitignored-planning.test.cjs:224-250
(Outside-diff) — mtimeMs alone can stay unchanged on coarse-grained
filesystems (HFS+, FAT) when two rewrites land within the same
timestamp tick, falsely passing the idempotency assertion.
Replaced with a full snapshot (mtimeMs, ctimeMs, size, ino, sha256
of contents) compared via assert.deepStrictEqual — the hash
catches any rewrite the timestamp would miss.
Verification: 30/30 pass on the two affected files; lint-no-source-grep
clean (0 violations across 368 test files).
After v1.39.0 skill consolidation (#2790), skills/ became a GSD-managed
root that the installer wipes on update. GSD_MANAGED_DIRS in gsd-tools.cjs
was missing 'skills', so user-added skill directories (e.g.
skills/custom-skill/SKILL.md) were never walked and silently destroyed
during /gsd-update.
- Add 'skills' to GSD_MANAGED_DIRS so the directory is walked
- Add tests/bug-2942-detect-custom-skills.test.cjs with 5 targeted tests
- Update tests/update-custom-backup.test.cjs: replace the now-incorrect
"skills/ must NOT be scanned" assertion (written pre-#2790) with a test
that verifies custom skills ARE detected and GSD-owned skills are not
falsely flagged
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Two bugs in the audit-open dispatch case in bin/gsd-tools.cjs:
1. Bare output(...) calls (only core.output is in scope) threw
ReferenceError: output is not defined on every invocation,
blocking the first step of /gsd-complete-milestone.
2. Even after switching to core.output(formattedReport, raw), the
human-readable branch JSON-stringified the formatted text because
core.output only bypasses JSON encoding when called as
core.output(null, true, rawValue).
Fix:
- --json path: core.output(result, raw) — pass the object,
let core.output JSON-stringify (don't pre-stringify).
- text path: core.output(null, true, formatAuditReport(result))
— use the rawValue form to emit verbatim section dividers and
item lists.
Adds tests/bug-2911-audit-open-output-shape.test.cjs which parses
both modes structurally — line-by-line for text mode (asserting the
report headers exist as standalone lines, not as escaped \n inside a
JSON quoted string), and JSON.parse + key-by-key shape assertions for
--json mode (matching the contract returned by auditOpenArtifacts).
* feat(#2792): namespace meta-skills retargeted at the post-#2790 surface
This branch is now based on #2790's HEAD (the consolidation PR) instead
of main, and every routing table targets the consolidated surface so a
user routed by a namespace meta-skill never lands at a deleted /
folded sub-skill.
Cross-PR inconsistencies the original PR #2825 carried (vs #2790):
- ns-ideate routed to gsd-note / gsd-add-todo / gsd-add-backlog /
gsd-plant-seed → all folded into gsd-capture by #2790. Now routes
to gsd-capture (the parent picks the mode from the user's intent).
- ns-context routed to gsd-scan and gsd-intel → folded into
gsd-map-codebase --fast / --query by #2790. Now routes to those
flag forms.
- ns-manage routed all workspace intent to gsd-list-workspaces (a
list-only entry) → CR also flagged the over-narrow target. #2790
folds into gsd-workspace; routing now points there.
- ns-workflow routed to gsd-research-phase → deleted outright by
#2790. Removed.
- ns-project routed to gsd-plan-milestone-gaps → deleted outright by
#2790. Removed.
- None of the namespaces previously surfaced #2790's new consolidated
skills (gsd-capture, gsd-phase, gsd-config, gsd-workspace,
gsd-progress). All five are now reachable through the routers.
- extract_learnings → extract-learnings (canonicalized by #2858).
Defect fixes within the namespace skills:
- Hyphen-form `name:` (gsd-workflow, …) per the canonical naming
contract — the colon-form addressed CR's drift complaint.
- `Skill` added to allowed-tools on every router. The body instructs
"Invoke the matched skill directly using the Skill tool" — without
Skill in the permission list the meta-skill cannot route at all.
New regression guard in tests/enh-2792-namespace-skills.test.cjs: every
gsd-* token in any namespace router's table column resolves to a
surviving commands/gsd/*.md file (or to a known consolidated parent for
flag-form targets like gsd-map-codebase --fast). This single test would
have caught every dead-end route the original PR shipped with.
Skill-count cap in tests/enh-2790-skill-consolidation.test.cjs now
filters out ns-*.md from its <= 63 cap. Namespace routers are
descriptor-only entries, not part of the consolidation surface that cap
is policing — they have their own contract in
tests/enh-2792-namespace-skills.test.cjs.
INVENTORY.md gains a "Namespace Meta-Skills" section with the 6 router
rows; INVENTORY-MANIFEST.json gains 6 entries; the headline count moves
59 → 65 to match.
Out of scope for this rebase: the gsd-health --context flag (PR #2825
advertised the contract but didn't implement it). That's a separate
feature concern and is left untouched here.
5908/5908 on `npm test`.
* feat(#2792): implement gsd-health --context utilization guard
The original PR #2825 advertised a `--context` flag on gsd-health with a
60%/70% utilization threshold table but never implemented the workflow
logic — CR caught it as a contract leak, the rebase deferred it. This
commit closes the gap with TDD red/green/refactor.
Math layer (pure):
- get-shit-done/bin/lib/context-utilization.cjs
classifyContextUtilization(tokensUsed, contextWindow) →
{ percent, state }
State boundaries use the exact ratio:
< 60% healthy / 60–70% warning / ≥ 70% critical (fracture point)
Display percent rounded for humans. Throws TypeError on non-integer
or out-of-range inputs.
- STATES = Object.freeze({ HEALTHY, WARNING, CRITICAL }) exported
so callers reference the names by symbol, not by literal string.
SDK CLI integration:
- get-shit-done/bin/gsd-tools.cjs
`validate context --tokens-used N --context-window M [--json]`
routes to the classifier, owns the recommendation copy (the
classifier intentionally does not — keeps the renderer free to
evolve without touching the math layer or its tests), and uses
core.output's rawValue path for the sync-flush guarantee.
- sdk/src/query/validate.ts + sdk/src/query/index.ts
TypeScript validateContext handler registered at 'validate.context'
and 'validate context'. Mirrors the CJS classifier inline (15 lines
of arithmetic; not worth a shared cross-language module).
User-facing wiring:
- commands/gsd/health.md frontmatter advertises --context, body
documents the three-state threshold table.
- get-shit-done/workflows/health.md adds a `context_check` step
that's reached only when --context is set. Step calls
`gsd-sdk query validate.context` with self-reported tokensUsed and
contextWindow, prints the SDK output verbatim, and ends. Includes
a TEXT_MODE plain-text fallback for non-Claude runtimes per #2012.
Tests:
- tests/context-utilization.test.cjs (17 tests) — pure-function
contract: state thresholds at every boundary, percent rounding,
input validation, return-shape (no recommendation field — that's
the renderer's job).
- tests/validate-context.test.cjs (9 tests) — SDK CLI plumbing:
arg parsing errors, JSON vs human rendering, recommendation copy
pinned per state.
- tests/enh-2792-namespace-skills.test.cjs (4 new tests) — markdown
contract: --context advertised in argument-hint, threshold table
in command body, context_check step exists in workflow, step
invokes gsd-sdk query validate.context with both flags.
Inventory bookkeeping:
- docs/INVENTORY.md "CLI Modules" 31 → 32; new row for
context-utilization.cjs.
- docs/INVENTORY-MANIFEST.json mirror.
5939/5939 on `npm test`.
* fix(#2801): add ingest-docs handler to gsd-tools init dispatch
The `/gsd-ingest-docs` workflow was broken because `workflows/ingest-docs.md`
called `gsd-sdk query init.ingest-docs` but the installed binary is `gsd-tools`,
and `gsd-tools init` had no `ingest-docs` case in its dispatch switch.
- Added `cmdInitIngestDocs` function to `init.cjs` and exported it; returns
`project_exists`, `planning_exists`, `has_git`, `project_path`, `commit_docs`
- Added `case 'ingest-docs'` to the `init` switch in `gsd-tools.cjs`
- Updated `workflows/ingest-docs.md` to call `gsd-tools init ingest-docs`
(line 55) and `gsd-tools commit` (line 292) instead of `gsd-sdk query ...`
- Regression test: `tests/bug-2801-ingest-docs-handler.test.cjs`
Closes#2801
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(#2801): address CodeRabbit — commit_docs assertion, broader gsd-sdk detection, bash fence
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* refactor(state): drop unused args param and lift currentPhase in cmdStateCompletePhase
Two cleanup items surfaced by CodeRabbit review of PR #2759:
1. cmdStateCompletePhase(cwd, args, raw) — args is never read inside the
function. All sibling state subcommands use the leaner (cwd, raw) shape.
Remove the unused parameter and update the dispatch call in gsd-tools.cjs.
2. output() at line 1754 called fs.readFileSync(statePath) after
readModifyWriteStateMd had already released the lock, re-extracting
Current Phase via an extra fs read. The closure already computed
currentPhase at line 1704; lifting resolvedPhase into outer scope and
capturing it in the callback eliminates the post-lock read and closes the
small race window.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* test(#2761): apply CodeRabbit nitpicks with regression tests
Two CodeRabbit nitpicks from PR #2761 review, each landed with a
regression test so a future refactor can't unwind them.
1. tests/dispatcher.test.cjs — pin the enumerated subcommand list:
the 'state unknown subcommand errors' test now also asserts that
the dispatcher's error string includes 'complete-phase'. Without
this, a future reformat of the available-subcommands enumeration
could silently drop entries and the existing
'Unknown state subcommand' substring check would still pass.
2. get-shit-done/bin/lib/state.cjs — tighten the Phase fallback in
cmdStateCompletePhase: when STATE.md is missing the canonical
'**Current Phase:**' field and the only phase signal is the
decorated body line under '## Current Position' (e.g.
'Phase: 01 (Foo) — EXECUTING'), the previous fallback returned
the entire decorated string, producing messy downstream output:
Status: Phase 01 (Foo) — EXECUTING complete
Phase: 01 (Foo) — EXECUTING — COMPLETE
The fallback now strips everything past the leading
numeric/decimal token via /^\\s*([\\w.-]+)/ so degraded inputs
produce clean output identical to the canonical path.
3. tests/state.test.cjs — two new tests in a dedicated describe block:
- decorated Phase line writes clean Phase identifier
- canonical Current Phase wins over Current Position decoration
Both run real `gsd state complete-phase` against synthetic
STATE.md fixtures and assert on the rendered Status field.
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix: parseMustHavesBlock quoted strings + gsd state complete-phase
Bug #2734: parseMustHavesBlock dropped quoted truths containing ':' because
fully-quoted strings like `"App-side UUIDv4: generated locally"` fell into
the kv-parse branch, the regex failed (value starts with '"'), and current
stayed as empty {}. Fix: detect fully-quoted strings before the ':' check
and extract them directly. Two regression tests added to frontmatter.test.cjs.
Bug #2735: `gsd state complete-phase` subcommand was missing — unknown
subcommands fell through to cmdStateLoad. Added cmdStateCompletePhase to
state.cjs (updates Status, Last Activity, and Current Position to COMPLETE),
exported it, and wired it into the case 'state': dispatch in gsd-tools.cjs.
Closes#2734Closes#2735
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(state): unknown subcommand returns explicit error instead of silent fallthrough
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
The /gsd:new-milestone workflow Step 5 rewrote STATE.md's Current Position
body but never touched the YAML frontmatter, so every downstream reader
(state.json, getMilestoneInfo, progress bars) kept reporting the stale
milestone until the first phase advance forced a resync. Asymmetric with
milestone.complete, which uses readModifyWriteStateMdFull.
Add a new `state milestone-switch` handler (both SDK and CJS) that atomically:
- Stomps frontmatter milestone/milestone_name with caller-supplied values
- Resets status to 'planning' and progress counters to zero
- Rewrites the ## Current Position section to the new-milestone template
- Preserves Accumulated Context (decisions, blockers, todos)
Wire the workflow Step 5 to invoke `state.milestone-switch` instead of the
manual body rewrite. Note the flag is `--milestone` not `--version`:
gsd-tools reserves `--version` as a globally-invalid help flag.
Red vitest in sdk/src/query/state-mutation.test.ts asserts the frontmatter
reset. Regression guard via node:test in tests/bug-2630-*.test.cjs runs
through gsd-tools end-to-end.
Fixes#2630
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat: add unified post-planning gap checker (closes#2493)
Adds a unified post-planning gap checker as Step 13e of plan-phase.md.
After all plans are generated and committed, scans REQUIREMENTS.md and
CONTEXT.md <decisions> against every PLAN.md in the phase directory and
emits a single Source | Item | Status table.
Why
- The existing Requirements Coverage Gate (§13) blocks/re-plans on REQ
gaps but emits two separate per-source signals. Issue #2493 asks for
one unified report after planning so that requirements AND
discuss-phase decisions slipping through are surfaced in one place
before execution starts.
What
- New workflow.post_planning_gaps boolean config key, default true,
added to VALID_CONFIG_KEYS, CONFIG_DEFAULTS, hardcoded.workflow, and
cmdConfigSet (boolean validation).
- New get-shit-done/bin/lib/decisions.cjs — shared parser for
CONTEXT.md <decisions> blocks (D-NN entries). Designed for reuse by
the related #2492 plan/verify decision gates.
- New get-shit-done/bin/lib/gap-checker.cjs — parses REQUIREMENTS.md
(checkbox + traceability table forms), reads CONTEXT.md decisions,
walks PHASE_DIR/*-PLAN.md, runs word-boundary coverage detection
(REQ-1 must not match REQ-10), formats a sorted report.
- New gsd-tools gap-analysis CLI command wired through gsd-tools.cjs.
- workflows/plan-phase.md gains §13e between §13d (commit plans) and
§14 (Present Final Status). Existing §13 gate preserved — §13e is
additive and non-blocking.
- sdk/prompts/workflows/plan-phase.md gets an equivalent
post_planning_gaps step for headless mode.
- Docs: CONFIGURATION.md, references/planning-config.md, INVENTORY.md,
INVENTORY-MANIFEST.json all updated.
Tests
- tests/post-planning-gaps-2493.test.cjs: 30 test cases covering step
insertion position, decisions parser, gap detector behavior
(covered/not-covered, false-positive guard, missing-file
resilience, malformed-input resilience, gate on/off, deterministic
natural sort), and full config integration.
- Full suite: 5234 / 5234 pass.
Design decisions
- Numbered §13e (sub-step), not §14 — §14 already exists (Present
Final Status); inserting before it preserves downstream auto-advance
step numbers.
- Existing §13 gate kept, not replaced — §13 blocks/re-plans on
REQ gaps; §13e is the unified post-hoc report. Per spec: "default
behavior MUST be backward compatible."
- Word-boundary ID matching avoids REQ-1 matching REQ-10 and avoids
brittle semantic/substring matching.
- Shared decisions.cjs parser so #2492 can reuse the same regex.
- Natural-sort keys (REQ-02 before REQ-10) for deterministic output.
- Boolean validation in cmdConfigSet rejects non-boolean values
matches the precedent set by drift_threshold/drift_action.
Closes#2493
* fix(#2493): expose post_planning_gaps in loadConfig() + sync schema example
Address CodeRabbit review on PR #2610:
- core.cjs loadConfig(): return post_planning_gaps from both the
config.json branch and the global ~/.gsd/defaults.json fallback so
callers can rely on config.post_planning_gaps regardless of whether
the key is present (comment 3127977404, Major).
- docs/CONFIGURATION.md: add workflow.post_planning_gaps to the Full
Schema JSON example so copy/paste users see the new toggle alongside
security_block_on (comment 3127977392, Minor).
- tests/post-planning-gaps-2493.test.cjs: regression coverage for
loadConfig() — default true when key absent, honors explicit
true/false from workflow.post_planning_gaps.
* feat: auto-remap codebase after significant phase execution (#2003)
Adds a post-phase structural drift detector that compares the committed tree
against `.planning/codebase/STRUCTURE.md` and either warns or auto-remaps
the affected subtrees when drift exceeds a configurable threshold.
## Summary
- New `bin/lib/drift.cjs` — pure detector covering four drift categories:
new directories outside mapped paths, new barrel exports at
`(packages|apps)/*/src/index.*`, new migration files, and new route
modules. Prioritizes the most-specific category per file.
- New `verify codebase-drift` CLI subcommand + SDK handler, registered as
`gsd-sdk query verify.codebase-drift`.
- New `codebase_drift_gate` step in `execute-phase` between
`schema_drift_gate` and `verify_phase_goal`. Non-blocking by contract —
any error logs and the phase continues.
- Two new config keys: `workflow.drift_threshold` (int, default 3) and
`workflow.drift_action` (`warn` | `auto-remap`, default `warn`), with
enum/integer validation in `config-set`.
- `gsd-codebase-mapper` learns an optional `--paths <p1,p2,...>` scope hint
for incremental remapping; agent/workflow docs updated.
- `last_mapped_commit` lives in YAML frontmatter on each
`.planning/codebase/*.md` file; `readMappedCommit`/`writeMappedCommit`
round-trip helpers ship in `drift.cjs`.
## Tests
- 55 new tests in `tests/drift-detection.test.cjs` covering:
classification, threshold gating at 2/3/4 elements, warn vs. auto-remap
routing, affected-path scoping, `--paths` sanitization (traversal,
absolute, shell metacharacter rejection), frontmatter round-trip,
defensive paths (missing STRUCTURE.md, malformed input, non-git repos),
CLI JSON output, and documentation parity.
- Full suite: 5044 pass / 0 fail.
## Documentation
- `docs/CONFIGURATION.md` — rows for both new keys.
- `docs/ARCHITECTURE.md` — section on the post-execute drift gate.
- `docs/AGENTS.md` — `--paths` flag on `gsd-codebase-mapper`.
- `docs/USER-GUIDE.md` — user-facing behavior note + toggle commands.
- `docs/FEATURES.md` — new 27a section with REQ-DRIFT-01..06.
- `docs/INVENTORY.md` + `docs/INVENTORY-MANIFEST.json` — drift.cjs listed.
- `get-shit-done/workflows/execute-phase.md` — `codebase_drift_gate` step.
- `get-shit-done/workflows/map-codebase.md` — `parse_paths_flag` step.
- `agents/gsd-codebase-mapper.md` — `--paths` directive under parse_focus.
## Design decisions
- **Frontmatter over sidecar JSON** for `last_mapped_commit`: keeps the
baseline attached to the file, survives git moves, survives per-doc
regeneration, no extra file lifecycle.
- **Substring match against STRUCTURE.md** for `isPathMapped`: the map is
free-form markdown, not a structured manifest; any mention of a path
prefix counts as "mapped territory". Cheap, no parser, zero false
negatives on reasonable maps.
- **Category priority migration > route > barrel > new_dir** so a file
matching multiple rules counts exactly once at the most specific level.
- **Empty-tree SHA fallback** (`4b825dc6…`) when `last_mapped_commit` is
absent — semantically correct (no baseline means everything is drift)
and deterministic across repos.
- **Four layers of non-blocking** — detector try/catch, CLI try/catch, SDK
handler try/catch, and workflow `|| echo` shell fallback. Any single
layer failing still returns a valid skipped result.
- **SDK handler delegates to `gsd-tools.cjs`** rather than re-porting the
detector to TypeScript, keeping drift logic in one canonical place.
Closes#2003
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* docs(mapper): tag --paths fenced block as text (CodeRabbit MD040)
Comment 3127255172.
* docs(config): use /gsd- dash command syntax in drift_action row (CodeRabbit)
Comment 3127255180. Matches the convention used by every other command
reference in docs/CONFIGURATION.md.
* fix(execute-phase): initialize AGENT_SKILLS_MAPPER + tag fenced blocks
Two CodeRabbit findings on the auto-remap branch of the drift gate:
- 3127255186 (must-fix): the mapper Task prompt referenced
${AGENT_SKILLS_MAPPER} but only AGENT_SKILLS (for gsd-executor) is
loaded at init_context (line 72). Without this fix the literal
placeholder string would leak into the spawned mapper's prompt.
Add an explicit gsd-sdk query agent-skills gsd-codebase-mapper step
right before the Task spawn.
- 3127255183: tag the warn-message and Task() fenced code blocks as
text to satisfy markdownlint MD040.
* docs(map-codebase): wire PATH_SCOPE_HINT through every mapper prompt
CodeRabbit (review id 4158286952, comment 3127255190) flagged that the
parse_paths_flag step defined incremental-remap semantics but did not
inject a normalized variable into the spawn_agents and sequential_mapping
mapper prompts, so incremental remap could silently regress to a
whole-repo scan.
- Define SCOPED_PATHS / PATH_SCOPE_HINT in parse_paths_flag.
- Inject ${PATH_SCOPE_HINT} into all four spawn_agents Task prompts.
- Document the same scope contract for sequential_mapping mode.
* fix(drift): writeMappedCommit tolerates missing target file
CodeRabbit (review id 4158286952, drift.cjs:349-355 nitpick) noted that
readMappedCommit returns null on ENOENT but writeMappedCommit threw — an
asymmetry that breaks first-time stamping of a freshly produced doc that
the caller has not yet written.
- Catch ENOENT on the read; treat absent file as empty content.
- Add a regression test that calls writeMappedCommit on a non-existent
path and asserts the file is created with correct frontmatter.
Test was authored to fail before the fix (ENOENT) and passes after.
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(detect-custom-files): exclude skills and command dirs not wiped by installer (closes#2505)
GSD_MANAGED_DIRS included 'skills' and 'command' directories, but the
installer never wipes those paths. Users with third-party skills installed
(40+ files, none in GSD's manifest) had every skill flagged as a "custom
file" requiring backup, producing noisy false-positive reports on every
/gsd-update run.
Removes 'skills' and 'command' from both gsd-tools.cjs and the SDK's
detect-custom-files.ts. Adds two regression tests confirming neither
directory is scanned.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(settings): warn that model profiles are no-ops on non-Claude runtimes (closes#2506)
settings.md presented Quality/Balanced/Budget model profiles without any
indication that these tiers map to Claude models (Opus/Sonnet/Haiku) and
have no effect on non-Claude runtimes (Codex, Gemini CLI, OpenRouter).
Users on Codex saw the profile chooser as if it would meaningfully select
models, but all agents silently used the runtime default regardless.
Adds a non-Claude runtime note before the profile question (shown in
TEXT_MODE, the path all non-Claude runtimes take) explaining the profiles
are no-ops and directing users to either choose Inherit or configure
model_overrides manually. Also updates the Inherit option description to
explicitly name the runtimes where it is the correct choice.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(roadmap): surface wave dependencies and cross-cutting constraints (#2447)
Adds roadmap.annotate-dependencies command that post-processes a phase's
ROADMAP plan list to insert wave dependency notes and surface must_haves.truths
entries shared across 2+ plans as cross-cutting constraints. Operation is
idempotent and purely derived from existing PLAN frontmatter.
Closes#2447
* fix(roadmap): address CodeRabbit review findings on PR #2487
- roadmap.cjs: expand idempotency guard to also check for existing
cross-cutting constraints header, preventing duplicate injection on
re-runs; add content equality check before writing to preserve
true idempotency for single-wave phases
- plan-phase.md: move ROADMAP annotation (13d) before docs commit (13c)
so annotated ROADMAP.md is included in the commit rather than left dirty;
include .planning/ROADMAP.md in committed files list
- sdk/src/query/index.ts: add annotate-dependencies aliases to
QUERY_MUTATION_COMMANDS so the mutation is properly event-wired
- sdk/src/query/roadmap.ts: add timeout (15s) and maxBuffer to spawnSync;
check result.error before result.status to handle spawn/timeout failures
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds W018 warning when .planning/milestones/vX.Y-ROADMAP.md snapshots
exist without a corresponding entry in MILESTONES.md. Introduces
--backfill flag to synthesize missing entries from snapshot titles.
Closes#2446
settings.md was reading and writing .planning/config.json directly while
gsd-tools config-get/config-set route to .planning/workstreams/<slug>/config.json
when GSD_WORKSTREAM is active, causing silent write-read drift (Closes#2282).
- config.cjs: add cmdConfigPath() — emits the planningDir-resolved config path as
plain text (always raw, no JSON wrapping) so shell substitution works correctly
- gsd-tools.cjs: wire config-path subcommand
- settings.md: resolve GSD_CONFIG_PATH via config-path in ensure_and_load_config;
replace hardcoded cat .planning/config.json and Write to .planning/config.json
with $GSD_CONFIG_PATH throughout
- phase.cjs: fix renameDecimalPhases to preserve zero-padded prefix (06.3 → 06.2
not 6.2) — pre-existing test failure on main
- tests/config.test.cjs: add config-path command tests (#2282)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
The audit-open case in gsd-tools.cjs called bare output() on both the --json
and text paths. output is never in scope at the call site — the entire core
module is imported as `const core`, so every other command uses core.output().
Two-part fix:
- Replace output(...) with core.output(...) on both branches
- Pass result (the raw object) on the --json path, not JSON.stringify(result)
— core.output always calls JSON.stringify internally, so pre-serialising
caused double-encoding and agents received a string instead of an object
Adds three CLI-level regression tests to milestone-audit.test.cjs that invoke
audit-open through runGsdTools (the same path the agent uses), so a recurrence
at the dispatch layer is caught even if lib-level tests continue to pass.
Closes#2236
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
PR #2038 added detect-custom-files to gsd-tools.cjs and the backup_custom_files
step to update.md, but commit 7bfb11b6 is not an ancestor of v1.36.0: main was
rebuilt after the merge, orphaning the change. Users on 1.36.0 running /gsd-update
silently lose any locally-authored files inside GSD-managed directories.
Root cause: git merge-base 7bfb11b6 HEAD returns aa3e9cf (Cline runtime, PR #2032),
117 commits before the release tag. The "merged" GitHub state reflects the PR merge
event, not reachability from the default branch.
Fix: re-apply the three changes from 7bfb11b6 onto current main:
- Add detect-custom-files subcommand to gsd-tools.cjs (walk managed dirs, compare
against gsd-file-manifest.json keys via path.relative(), return JSON list)
- Add 'detect-custom-files' to SKIP_ROOT_RESOLUTION set
- Restore backup_custom_files step in update.md before run_update
- Restore tests/update-custom-backup.test.cjs (7 tests, all passing)
Closes#2229Closes#1997
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix: display relative time instead of UTC in intel status output
The `updated_at` timestamps in `gsd-tools intel status` were displayed
as raw ISO/UTC strings, making them appear to show the wrong time in
non-UTC timezones. Replace with fuzzy relative times ("5 minutes ago",
"1 day ago") which are timezone-agnostic and more useful for freshness.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* test: add regression tests for timeAgo utility
Covers boundary values (seconds/minutes/hours/days/months/years),
singular vs plural formatting, and future-date edge case.
Addresses review feedback on #2132.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Parallel `phase add` invocations each read disk state before any write
completes, causing all processes to calculate the same next phase number
and produce duplicate directories and ROADMAP entries.
The new `add-batch` subcommand accepts a JSON array of phase descriptions
and performs all directory creation and ROADMAP appends within a single
`withPlanningLock()` call, incrementing `maxPhase` within the lock for
each entry. This guarantees sequential numbering regardless of call
concurrency patterns.
Closes#2165
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* test(2123): add failing tests for TDD init JSON exposure and --tdd flag
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat(2123): expose tdd_mode in init JSON and add --tdd flag override
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Adds `skill-manifest` command that scans a skills directory, extracts
frontmatter and trigger conditions from each SKILL.md, and outputs a
compact JSON manifest. This reduces per-agent skill discovery from 36
Read operations (~6,000 tokens) to a single manifest read (~1,000 tokens).
Closes#1976
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Review feedback from @trek-e — address scope gaps:
1. **--dry-run mode** — New flag that computes what would be pruned
without modifying STATE.md. Returns structured output showing
per-section counts so users can verify before committing.
2. **Resolved blocker pruning** — In addition to decisions and
recently-completed entries, now prunes entries in the Blockers
section that are marked resolved (~~strikethrough~~ or [RESOLVED]
prefix) AND reference a phase older than the cutoff. Unresolved
blockers are preserved regardless of age.
3. **Tests** — Added tests/state-prune.test.cjs (4 cases):
- Prunes decisions older than cutoff, keeps recent
- --dry-run reports changes without modifying STATE.md
- Prunes resolved blockers, keeps unresolved regardless of age
- Returns pruned:false when nothing exceeds cutoff
Scope items still deferred (to be filed as follow-up):
- Performance Metrics "By Phase" table row pruning — needs different
regex handling than prose lines
- Auto-prune via workflow.auto_prune_state at phase completion — needs
integration into cmdPhaseComplete
Also: the pre-existing test failure (2918/2919) is
tests/stale-colon-refs.test.cjs:83:3 "No stale /gsd: colon references
(#1748)". Verified failing on main, not introduced by this PR.
Add `gsd-tools state prune --keep-recent N` that moves old decisions
and recently-completed entries to STATE-ARCHIVE.md. Entries from phases
older than (current - N) are archived; the N most recent are kept.
STATE.md sections grow unboundedly in long-lived projects. A 20+ phase
project accumulates hundreds of historical decisions that every agent
loads into context. Pruning removes stale entries from the hot path
while preserving them in a recoverable archive.
Usage: gsd-tools state prune --keep-recent 3
Default: keeps 3 most recent phases
Closes#1970
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds a new command and CLI subcommand that converts a GSD-2 `.gsd/`
project back to GSD v1 `.planning/` format — the reverse of the forward
migration GSD-2 ships.
Closes#2069
Maps GSD-2's Milestone → Slice → Task hierarchy to v1's flat
Milestone sections → Phase → Plan structure. Slices are numbered
sequentially across all milestones; tasks become numbered plans within
their phase. Completion state, research files, and summaries are
preserved.
New files:
- `get-shit-done/bin/lib/gsd2-import.cjs` — parser, transformer, writer
- `commands/gsd/from-gsd2.md` — slash command definition
- `tests/gsd2-import.test.cjs` — 41 tests, 99.21% statement coverage
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(core): resolve @file: references in gsd-tools stdout (#1891)
Workflows used bash-specific `if [[ "$INIT" == @file:* ]]` to detect
when large JSON was written to a temp file. This syntax breaks on
PowerShell and other non-bash shells.
Intercept stdout in gsd-tools.cjs to transparently resolve @file:
references before they reach the caller, matching the existing --pick
path behavior. The bash checks in workflow files become harmless
no-ops and can be removed over time.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* docs(config): add missing config fields to planning-config.md (#1880)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Tibsfox <tibsfox@tibsfox.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When --default <value> is passed, config-get returns the default value
(exit 0) instead of erroring (exit 1) when the key is absent or
config.json doesn't exist. When the key IS present, --default is
ignored and the real value returned.
This lets workflows express optional config reads without defensive
`2>/dev/null || true` boilerplate that obscures intent and is fragile
under `set -e`.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(tools): add global learnings store with CRUD library and CLI support
* fix(tools): address review feedback for global learnings store
- Validate learning IDs against path traversal in learningsRead, learningsDelete, and cmdLearningsDelete
- Fix total invariant in learningsCopyFromProject (total = created + skipped)
- Wrap cmdLearningsPrune in try/catch to handle invalid duration format
- Rename raw -> content in readLearningFile to avoid variable shadowing
- Add CLI integration tests for list, query, prune error, and unknown subcommand
phases clear now checks for phase dirs before deleting. If any exist and
--confirm is absent, the command exits non-zero with a message showing the
count and how to proceed. Empty phases dir (nothing to delete) succeeds
without --confirm unchanged.
Updates new-milestone.md workflow to pass --confirm (intentional programmatic
caller). Updates existing new-milestone-clear-phases tests to match new API.
Closes#1826
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(cli): reject help/version flags instead of silently ignoring them (#1818)
AI agents can hallucinate --help or --version on gsd-tools invocations.
Without a guard, unknown flags were silently ignored and the command
proceeded — including destructive ones like `phases clear`. Add a
pre-dispatch check in main() that errors immediately if any never-valid
flag (-h, --help, -?, --version, -v, --usage) is present in args after
global flags are stripped. Regression test covers phases clear, generate-
slug, state load, and current-timestamp with both --help and -h variants.
Closes#1818
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(agents): convert gsd-verifier required_reading to inline wiring
The thinking-model-guidance test requires inline @-reference wiring at
decision points rather than a <required_reading> block. Convert
verification-overrides.md reference from the <required_reading> block
to an inline reference inside <verification_process> alongside the
existing thinking-models-verification.md reference.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(tests): resolve conflict between thinking-model and verification-overrides tests
thinking-model-guidance.test prohibited <required_reading> entirely, but
verification-overrides.test requires gsd-verifier.md to have a
<required_reading> block for verification-overrides.md between </role>
and <project_context>. The tests were mutually exclusive.
Fix: narrow the thinking-model assertion to check that the thinking-models
reference is not *inside* a <required_reading> block (using regex extraction),
rather than asserting no <required_reading> block exists at all. Restore the
<required_reading> block in gsd-verifier.md. Both suites now pass (2345/2345).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(state): add programmatic gates for STATE.md consistency
Adds four enforcement gates to prevent STATE.md drift:
- `state validate`: detects drift between STATE.md and filesystem
- `state sync`: reconstructs STATE.md from actual project state
- `state planned-phase`: records state after plan-phase completes
- Performance Metrics update in `phase complete`
Also fixes ghost `state update-position` command reference in
execute-phase.md (command didn't exist in CLI dispatcher).
Closes#1627
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(state): By Phase table regex ate next section when table body was empty
The lazy [\s\S]*? with a $ lookahead in byPhaseTablePattern would
match past blank lines and capture the next ## section header as table
body when no data rows existed. Replaced with a precise row-matching
pattern ((?:[ \t]*\|[^\n]*\n)*) that only captures pipe-delimited
lines. Added regression assertion to verify row placement.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: clear phases directory when creating new milestone (#1588)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* ci: re-run CI with Windows pointer lifecycle fix in main
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Add check-commit command to gsd-tools that acts as a pre-commit guard.
When commit_docs is false, rejects commits that stage .planning/ files
with an actionable error message including the unstage command.
Recreated cleanly on current main — previous version carried stale
shared fixes that are now upstream.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
GSD agents silently skip database schema push — verification passes but
production breaks because TypeScript types come from config, not the live
database. This adds two layers of protection:
1. Plan-phase template detection (step 5.7): When the planner detects
schema-relevant file patterns in the phase scope, it injects a mandatory
[BLOCKING] schema push task into the plan with the appropriate push
command for the detected ORM.
2. Post-execution drift detection gate: After execution completes but
before verification marks success, scans for schema-relevant file
changes and checks if a push command was executed. Blocks verification
with actionable guidance if drift is detected.
Supports Payload CMS, Prisma, Drizzle, Supabase, and TypeORM.
Override with GSD_SKIP_SCHEMA_CHECK=true.
Fixes#1381
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* docs(01-02): complete gsd-doc-writer agent skeleton plan
- SUMMARY.md for plan 01-02
- STATE.md advanced to plan 2/2, progress 50%
- ROADMAP.md updated with phase 1 plan progress
- REQUIREMENTS.md marked DOCG-01 and DOCG-08 complete
* feat(01-01): create lib/docs.cjs with cmdDocsInit and detection helpers
- Add cmdDocsInit following cmdInitMapCodebase pattern
- Add hasGsdMarker(), scanExistingDocs(), detectProjectType()
- Add detectDocTooling(), detectMonorepoWorkspaces() private helpers
- GSD_MARKER constant for generated-by tracking
- Only Node.js built-ins and local lib requires used
* feat(01-01): wire docs-init into gsd-tools.cjs and register gsd-doc-writer model profile
- Add const docs = require('./lib/docs.cjs') to gsd-tools.cjs
- Add case 'docs-init' routing to docs.cmdDocsInit
- Add docs-init to help text and JSDoc header
- Register gsd-doc-writer in MODEL_PROFILES (quality:opus, balanced:sonnet, budget:haiku)
- Fix docs.cjs: inline withProjectRoot logic via checkAgentsInstalled (private in init.cjs)
* docs(01-01): complete docs-init command plan
- SUMMARY.md documenting cmdDocsInit, detection helpers, wiring
- STATE.md advanced, progress updated to 100%
- ROADMAP.md phase 1 marked Complete
- REQUIREMENTS.md INFRA-01, INFRA-02, CONS-03 marked complete
* feat(01-02): create gsd-doc-writer agent skeleton
- YAML frontmatter with name, description, tools, color: purple
- role block with doc_assignment receiving convention
- create_mode and update_mode sections
- 9 stub template sections (readme, architecture, getting_started, development, testing, api, configuration, deployment, contributing)
- Each template has Required Sections list and Phase 3 TODO
- critical_rules prohibiting GSD methodology and CHANGELOG
- success_criteria checklist
- No GSD methodology leaks in template sections
* feat(02-01): add docs-update workflow Steps 1-6 — init, classify, route, resolve, detect
- init_context step calling docs-init with @file: handling and agent-skills loading
- validate_agents step warns on missing gsd-doc-writer without halting
- classify_project step maps project_type signals to 5 primary labels plus conditional docs
- build_doc_queue step with always-on 6 docs and conditional API/CONTRIBUTING/DEPLOYMENT routing
- resolve_modes step with doc-type to canonical path mapping and create/update detection
- detect_runtime_capabilities step with Task tool detection and sequential fallback routing
* docs(02-01): complete docs-update workflow plan — 13-step orchestration for parallel doc generation
- 02-01-SUMMARY.md: plan results, decisions, file inventory
- STATE.md: advanced to last plan, progress 100%, decisions recorded
- ROADMAP.md: Phase 2 marked Complete (1/1 plans with summary)
- REQUIREMENTS.md: marked INFRA-04, DOCG-03, DOCG-04, CONS-01, CONS-02, CONS-04 complete
* docs(03-02): complete command entry point and workflow extension plan
- 03-02-SUMMARY.md: plan results, decisions, file inventory
- STATE.md: advanced to plan 2, progress 100%, decisions recorded
- ROADMAP.md: Phase 3 marked Complete (2/2 plans with summaries)
- REQUIREMENTS.md: marked INFRA-03, EXIST-01, EXIST-02, EXIST-04 complete
* feat(03-01): fill all 9 doc templates, add supplement mode and per-package README template
- Replace all 9 template stubs with full content guidance (Required Sections, Content Discovery, Format Notes)
- Add shared doc_tooling_guidance block for Docusaurus, VitePress, MkDocs, Storybook routing
- Add supplement_mode block: append-only strategy with heading comparison and safety rules
- Add template_readme_per_package for monorepo per-package README generation
- Update role block to list supplement as third mode; add rule 7 to critical_rules
- Add supplement mode check to success_criteria
- Remove all Phase 3 TODO stubs and placeholder comments
* feat(03-02): add docs-update command entry point with --force and --verify-only flags
- YAML frontmatter with name, argument-hint, allowed-tools
- objective block documents flag semantics with literal-token enforcement pattern
- execution_context references docs-update.md workflow
- context block passes $ARGUMENTS and documents flag derivation rules
- --force takes precedence over --verify-only when both present
* feat(03-02): extend docs-update workflow with preservation_check, monorepo dispatch, and verify-only
- preservation_check step between resolve_modes and detect_runtime_capabilities
- preservation_check skips on --force, --verify-only, or no hand-written docs
- per-file AskUserQuestion choice: preserve/supplement/regenerate with fallback default to preserve
- dispatch_monorepo_packages step after collect_wave_2 for per-package READMEs
- verify_only_report early-exit step with VERIFY marker count and Phase 4 deferral message
- preservation_mode field added to all doc_assignment blocks in dispatch_wave_1, dispatch_wave_2
- sequential_generation extended with monorepo per-package section
- commit_docs updated to include per-package README files pattern
- report extended with per-package README rows and preservation decisions
- success_criteria updated with preservation, --force, --verify-only, and monorepo checks
* feat(04-01): create gsd-doc-verifier agent with claim extraction and filesystem verification
- YAML frontmatter with name, description, tools, and color fields
- claim_extraction section with 5 categories: file paths, commands, API endpoints, functions, dependencies
- skip_rules section for VERIFY markers, placeholders, example prefixes, and diff blocks
- verification_process with 6 steps using filesystem tools only (no self-consistency checks)
- output_format with exact JSON shape per D-01
- critical_rules enforcing filesystem-only verification and read-only operation
* feat(04-01): add fix_mode to gsd-doc-writer with surgical correction instructions
- Add fix_mode section after supplement_mode in modes block
- Document fix mode as valid option in role block mode list
- Add failures field to doc_assignment fields (fix mode only)
- fix_mode enforces surgical precision: only correct listed failing lines
- VERIFY marker fallback when correct value cannot be determined
* test(04-03): add docs-init integration test suite
- 13 tests across 4 describe blocks covering JSON output shape, project type
detection, existing doc scanning, GSD marker detection, and doc tooling
- Tests use node:test + node:assert/strict with beforeEach/afterEach lifecycle
- All 13 tests pass with `node --test tests/docs-update.test.cjs`
* feat(04-02): add verify_docs, fix_loop, scan_for_secrets steps to docs-update workflow
- verify_docs step spawns gsd-doc-verifier per generated doc and collects structured JSON results
- fix_loop step bounded at 2 iterations with regression detection (D-05/D-06)
- scan_for_secrets step uses exact map-codebase grep pattern before commit (D-07/D-08)
- verify_only_report updated to invoke real gsd-doc-verifier instead of VERIFY marker count stub
- success_criteria updated with 4 new verification gate checklist items
* docs(04-02): complete verification gate workflow steps plan
- SUMMARY.md: verify_docs, fix_loop, scan_for_secrets, and updated verify_only_report
- STATE.md: advanced to ready_for_verification, 100% progress, decisions logged
- ROADMAP.md: phase 4 marked Complete (3/3 plans with SUMMARYs)
- REQUIREMENTS.md: VERF-01, VERF-02, VERF-03 all marked complete
* refactor(profiles): Adds 'gsd-doc-verifier' to the 'MODEL_PROFILES'
* feat(agents): Add critical rules for file creation and update install test
* docs(05): create phase plan for docs output refinement
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(05-01): make scanExistingDocs recursive into docs/ subdirectories
- Replace flat docs/ scan with recursive walkDir helper (MAX_DEPTH=4)
- Add SKIP_DIRS filtering at every level of recursive walk
- Add fallback to documentation/ or doc/ when docs/ does not exist
- Update JSDoc to reflect recursive scanning behavior
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(05-01): update gsd-doc-writer default path guidance to docs/
- Change "No tooling detected" guidance to default to docs/ directory
- Add README.md and CONTRIBUTING.md as root-level exceptions
- Add instruction to create docs/ directory if it does not exist
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(05-02): invert path table to default docs to docs/ directory
- Invert resolve_modes path table: docs/ is primary for all types except readme and contributing
- Add mkdir -p docs/ instruction before agent dispatch
- Update all downstream path references: collect_wave_1, collect_wave_2, commit_docs, report, verify tables
- Update sequential_generation wave_1_outputs and resolved path references
- Update success criteria and verify_only_report examples to use docs/ paths
* feat(05-02): add CONTRIBUTING confirmation gate and existing doc review queue
- Add CONTRIBUTING.md user confirmation prompt in build_doc_queue (skipped with --force or when file exists)
- Add review_queue for non-canonical existing docs (verification only, not rewriting)
- Add review_queue verification in verify_docs step with fix_loop exclusion
- Add existing doc accuracy review section to report step with manual correction guidance
* docs(05-02): complete path table inversion and doc queue improvements plan
- Add 05-02-SUMMARY.md with execution results
- Update STATE.md with position, decisions, and metrics
- Update ROADMAP.md with phase 05 plan progress
* fix(05): replace plain text y/n prompts with AskUserQuestion in docs-update workflow
Three prompts were using plain text (y/n) instead of GSD's standard
AskUserQuestion pattern: CONTRIBUTING.md confirmation, doc queue
proceed gate, and secrets scan confirmation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(05): structure-aware paths, non-canonical doc fixes, and gap detection
- resolve_modes now inspects existing doc directory structure and places
new docs in matching subdirectories (e.g., docs/architecture/ if that
pattern exists), instead of dumping everything flat into docs/
- Non-canonical docs with inaccuracies are now sent to gsd-doc-writer
in fix mode for surgical corrections, not just reported
- Added documentation gap detection step that scans the codebase for
undocumented areas and prompts user to create missing docs
- Added type: custom support to gsd-doc-writer with template_custom
section for gap-detected documentation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(05): smarter structure-aware path resolution for grouped doc directories
When a project uses grouped subdirectories (docs/architecture/,
docs/api/, docs/guides/), ALL canonical docs must be placed in
appropriate groups — none left flat in docs/. Added resolution
chain per doc type with fallback creation. Filenames now match
existing naming style (lowercase-kebab vs UPPERCASE). Queue
presentation shows actual resolved paths, not defaults.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(05): restore mode resolution table as primary queue presentation
The table showing resolved paths, modes, and sources for each doc
must be displayed before the proceed/abort confirmation. It was
replaced by a simple list — now restored as the canonical queue view.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(05): use table format for existing docs review queue presentation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(05): add work manifest for structured handoffs between workflow steps
Root cause from smoke test: orchestrator forgot to verify 45 non-canonical
docs because the review_queue had no structural scaffolding — it existed
only in orchestrator memory. Fix:
1. Write docs-work-manifest.json to .planning/tmp/ after resolve_modes
with all canonical_queue, review_queue, and gap_queue items
2. Every subsequent step (dispatch, collect, verify, fix_loop, report)
MUST read the manifest first — single source of truth
3. Restructured verify_docs into explicit Phase 1 (canonical) and
Phase 2 (non-canonical) with separate dispatch for each
4. Both queues now eligible for fix_loop corrections
5. Added manifest read instructions to all dispatch/collect steps
Follows the same pattern as execute-phase's phase-plan-index for
tracking work items across multi-step orchestration.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* docs(05): update workflow purpose to reflect full command scope
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor(05): remove redundant steps from docs-update workflow
- Remove validate_agents step (if command is available, agents are installed)
- Remove agents_installed/missing_agents extraction from init_context
- Remove available_agent_types block (agent types specified in each Task call)
- Remove detect_runtime_capabilities step (runtime knows its own tools)
- Replace hardcoded flat paths in collect_wave_1/2 with manifest resolved_paths
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(05): restore available_agent_types section required by test suite
Test enforces that workflows spawning named agents must declare them
in an <available_agent_types> block. Added back with both gsd-doc-writer
and gsd-doc-verifier listed.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When GSD agents are not installed in .claude/agents/, Task(subagent_type="gsd-*")
silently falls back to general-purpose, losing specialized instructions, structured
outputs, and verification protocols.
What changed:
- Added checkAgentsInstalled() to core.cjs that validates all expected agents exist on disk
- All init commands now include agents_installed and missing_agents in their output
- Health check (validate health) reports W010 when agents are missing or incomplete
- New validate agents subcommand for standalone agent installation diagnostics
Fixes#1371
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add agent_skills config section that maps agent types to skill directory
paths. At spawn time, workflows load configured skills and inject them
as <agent_skills> blocks in Task() prompts, giving subagents access to
project-specific skill files.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add parseMultiwordArg() to collect multi-token --flag values until the next
flag. Replace manual name-collection loops in milestone complete and scaffold
cases. Also fixes a bug in scaffold where args.slice() would include trailing
flags in the name value.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- core.cjs: add filterPlanFiles, filterSummaryFiles, getPhaseFileStats,
readSubdirectories helpers; use them in searchPhaseInDir and getArchivedPhaseDirs
- gsd-tools.cjs: add parseNamedArgs() helper; replace ~50 repetitive indexOf/ternary
patterns in state record-metric, add-decision, add-blocker, record-session,
begin-phase, signal-waiting, template fill, and frontmatter subcommands
- phase.cjs: decompose 250-line cmdPhaseRemove into renameDecimalPhases(),
renameIntegerPhases(), and updateRoadmapAfterPhaseRemoval(); import readSubdirectories
- workstream.cjs: import stateExtractField from state.cjs and shared helpers from
core.cjs; replace all inline regex state parsing and readdirSync+filter+map patterns
All 1062 tests pass.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Validates workstream name at all entry points — CLI --ws flag,
GSD_WORKSTREAM env var, active-workstream file, and cmdWorkstreamSet —
blocking names that don't match [a-zA-Z0-9_-]+. Also fixes
getActiveWorkstream to use planningRoot() consistently and validates
names read from the active-workstream file before using them in path
joins.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Enable multiple Claude Code instances to work on the same codebase
simultaneously by scoping .planning/ state into workstreams.
Core changes:
- planningDir(cwd, ws?) and planningPaths(cwd, ws?) are now workstream-aware
via GSD_WORKSTREAM env var (auto-detected from --ws flag or active-workstream file)
- All bin/lib modules use planningDir(cwd) for scoped paths (STATE.md, ROADMAP.md,
phases/, REQUIREMENTS.md) and planningRoot(cwd) for shared paths (milestones/,
PROJECT.md, config.json, codebase/)
- New workstream.cjs module: create, list, status, complete, set, get, progress
- gsd-tools.cjs: --ws flag parsing with priority chain
(--ws > GSD_WORKSTREAM env > active-workstream file > flat mode)
- Collision detection: transition.md checks for other active workstreams before
suggesting next-milestone continuation (prevents WS A from trampling WS B)
- ${GSD_WS} routing propagation across all 9 workflow files ensures workstream
scope chains automatically through the workflow lifecycle
New files:
- get-shit-done/bin/lib/workstream.cjs (CRUD + collision detection)
- get-shit-done/commands/gsd/workstreams.md (slash command)
- get-shit-done/references/workstream-flag.md (documentation)
- tests/workstream.test.cjs (20 tests covering CRUD, env var routing, --ws flag)
All 1062 tests passing (1042 existing + 20 new workstream tests).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>