Two gaps in the standard workflow cycle caused planning document drift:
1. PROJECT.md was never updated during discuss → plan → execute → verify.
Only transition.md (optional) and complete-milestone evolved it.
Added an 'update_project_md' step to execute-phase.md that evolves
PROJECT.md after phase completion: moves requirements to Validated,
updates Current State, bumps Last Updated timestamp.
2. cmdPhaseComplete() in phase.cjs advanced 'Current Phase' but never
incremented 'Completed Phases' counter or recalculated 'percent'.
Added counter increment and percentage recalculation based on
completed/total phases ratio.
Addresses the workflow-level gaps identified in #956:
- PROJECT.md evolution in execute-phase (gap #2)
- completed_phases counter not incremented (gap #1 table row 3)
- percent never recalculated (gap #1 table row 4)
Fixes#956
Copilot's subagent spawning (Task API) may not properly return completion
signals to the orchestrator, causing it to hang indefinitely waiting for
agents that have already finished their work.
Added <runtime_compatibility> section to execute-phase.md with:
- Runtime-specific subagent spawning guidance (Claude Code, Copilot, others)
- Fallback rule: if agent completes work but orchestrator doesn't get the
signal, treat as success based on spot-checks (SUMMARY.md exists, commits
present)
- Sequential inline execution fallback for runtimes without reliable Task API
Fixes#1128
When GSD hits a blocking decision point (AskUserQuestion, next action prompt),
external watchers have no way to detect it. Users monitoring multiple auto
sessions must visually check each terminal.
Added:
- state signal-waiting: writes .planning/WAITING.json (or .gsd/WAITING.json)
with type, question, options, timestamp, and phase info
- state signal-resume: removes WAITING.json when user answers
Signal file format:
{ status, type, question, options[], since, phase }
External tools can watch for this file via fswatch, polling, or inotify.
Complements the existing remote-questions extension (Slack/Discord).
Fixes#1034
Adds --interactive flag to /gsd:execute-phase that changes execution from
autonomous subagent delegation to sequential inline execution with user
checkpoints between tasks.
Interactive mode:
- Executes plans sequentially inline (no subagent spawning)
- Presents each plan to user: Execute, Review first, Skip, Stop
- Pauses after each task for user intervention
- Dramatically lower token usage (no subagent overhead)
- Maintains full GSD planning/tracking structure
Changes:
- execute-phase.md: new check_interactive_mode step with full interactive flow
- execute-phase command: documented --interactive flag in argument-hint and context
Use cases:
- Small phases (1-3 plans, no complex dependencies)
- Bug fixes and verification gap closure
- Learning GSD workflow
- When user wants to pair-program with Claude under GSD structure
Fixes#963
GSD executor agents ignore MCP tools (e.g. jCodeMunch) even when CLAUDE.md
explicitly instructs their use. Agents default to Grep/Glob because those
are explicitly referenced in workflow patterns.
Added MCP tool instructions to:
- execute-phase.md: <mcp_tools> section in executor agent prompt telling
agents to prefer MCP tools over Grep/Glob when available
- execute-plan.md: Step 2 in execute section with MCP tool fallback guidance
Agents now:
1. Check if CLAUDE.md references MCP tools
2. Prefer MCP tools for code navigation when accessible
3. Fall back to Grep/Glob if MCP tools are not available
Fixes#973
After /clear, Claude Code sometimes loses awareness of custom agent types
and falls back to 'general-purpose'. This happens because the model doesn't
re-read .claude/agents/ after context reset.
Added <available_agent_types> sections to:
- execute-phase.md: lists all 12 valid GSD agent types with descriptions
- plan-phase.md: lists the 3 agent types used during planning
The explicit listing in workflow instructions ensures the model always has
an unambiguous reference to valid agent types, regardless of whether
.claude/agents/ was re-read after /clear.
Fixes#949
When plan-phase invokes discuss-phase as a nested Skill call,
AskUserQuestion calls auto-resolve with empty answers — the user never
sees the question UI. This is a Claude Code runtime bug with nested
subcontexts.
Made the 'Run discuss-phase first' path explicitly exit the workflow
with a display message instead of risking nested invocation:
- Added explicit warning: do NOT invoke as nested Skill/Task
- Show the command for user to run as top-level
- Exit the plan-phase workflow immediately
Fixes#1009
Claude Code's Task tool sometimes doesn't resolve short aliases (opus,
sonnet, haiku) and passes them directly to the API, causing 404s. Tasks
then inherit the parent session's model instead of the configured one.
Added:
- MODEL_ALIAS_MAP in core.cjs mapping aliases to full model IDs
- resolve_model_ids config option (default: false for backward compat)
- resolveModelInternal() maps aliases when resolve_model_ids is true
Usage:
{ "resolve_model_ids": true }
This causes gsd-tools resolve-model to return 'claude-sonnet-4-5' instead
of 'sonnet', which the Task tool passes to the API without needing alias
resolution on Claude Code's side.
The alias map is maintained per release. Users can also use model_overrides
for full control.
All 755 tests pass.
Fixes#991
stripShippedMilestones() uses a negative heuristic: strip all <details>
blocks, assume what remains is the current milestone. This breaks when
agents accidentally wrap the current milestone in <details> for
collapsibility — all downstream consumers then see an empty milestone.
Observed failure: cmdPhaseComplete() returns is_last_phase: true and
next_phase: null for non-final phases because the current milestone's
phases were stripped along with shipped ones.
Added extractCurrentMilestone(content, cwd) — a positive lookup that:
1. Reads the current milestone version from STATE.md frontmatter
2. Falls back to 🚧 in-progress marker in ROADMAP.md
3. Finds the section heading matching that version
4. Returns only that section's content
5. Falls back to stripShippedMilestones() if version can't be determined
Updated 12 call sites across 6 files to use extractCurrentMilestone:
- core.cjs: getRoadmapPhaseInternal(), getMilestonePhaseFilter()
- phase.cjs: cmdPhaseAdd(), cmdPhaseInsert(), cmdPhaseComplete() (2 sites)
- roadmap.cjs: cmdRoadmapGetPhase(), cmdRoadmapAnalyze()
- commands.cjs: stats/progress display
- verify.cjs: phase verification (2 sites)
- init.cjs: project initialization
Kept stripShippedMilestones() for:
- getMilestoneInfo() — determines the version itself, can't use positive lookup
- replaceInCurrentMilestone() — write operations, conservative boundary
- extractCurrentMilestone() fallback — when no version available
All 755 tests pass.
Fixes#1145
* fix: hook version tracking, stale hook detection, and stdin timeout increase
- Add gsd-hook-version header to all hook files for version tracking (#1153)
- Install.js now stamps current version into hooks during installation
- gsd-check-update.js detects stale hooks by comparing version headers
- gsd-statusline.js shows warning when stale hooks are detected
- Increase context monitor stdin timeout from 3s to 10s (#1162)
- Set +x permission on hook files during installation (#1162)
Fixes#1153, #1162, #1161
* feat: add /gsd:session-report command for post-session summary generation
Adds a new command that generates SESSION_REPORT.md with:
- Work performed summary (phases touched, commits, files changed)
- Key outcomes and decisions made
- Active blockers and open items
- Estimated resource usage metrics
Reports are written to .planning/reports/ with date-stamped filenames.
Closes#1157
* test: update expected skill count from 39 to 40 for new session-report command
Prevents shipping hooks with JavaScript SyntaxError (like the duplicate
const cwd declaration that caused PostToolUse errors for all users in
v1.25.1).
The build script now validates each hook file's syntax via vm.Script
before copying to dist/. If any hook has a SyntaxError, the build fails
with a clear error message and exits non-zero, blocking npm publish.
Refs #1107, #1109, #1125, #1161
MSYS curl on Windows has SSL/TLS failures and path mangling issues.
Replaced curl references in checkpoint and phase-prompt templates with
Node.js fetch() which works cross-platform.
Changes:
- checkpoints.md: server readiness check uses fetch() instead of curl
- checkpoints.md: added cross-platform note about curl vs fetch
- checkpoints.md: verify tags use fetch instead of curl
- phase-prompt.md: verify tags use fetch instead of curl
Partially addresses #899 (patch 1 of 6)
Adds a zero-friction command that detects the current project state and
automatically invokes the next logical workflow step:
- No phases → discuss first phase
- Phase has no context → discuss
- Phase has context but no plans → plan
- Phase has plans but incomplete → execute
- All plans complete → verify and complete phase
- All phases complete → complete milestone
- Paused → resume work
No arguments needed — reads STATE.md, ROADMAP.md, and phase directories
to determine progression. Designed for multi-project workflows.
Closes#927
Runtimes like Antigravity don't have a Task tool for spawning subagents.
When the agent encounters Task() calls, it falls back to browser_subagent
which is meant for web browsing, not code analysis — causing
gsd-map-codebase to fail.
This adds:
1. A detect_runtime_capabilities step before spawn_agents
2. An explicit warning to NEVER use browser_subagent for code analysis
3. A sequential_mapping fallback step that performs all 4 mapping passes
inline using file system tools when Task is unavailable
Closes#1174
The version detection script in update.md used a space-separated string
for RUNTIME_DIRS and iterated with `for entry in $RUNTIME_DIRS`. This
relies on word-splitting which works in bash but fails in zsh (zsh does
not word-split unquoted variables by default), causing the entire string
to be treated as one entry and detection to fall through to UNKNOWN.
Fix: convert RUNTIME_DIRS and ORDERED_RUNTIME_DIRS from space-separated
strings to proper arrays, and iterate with ${array[@]} syntax which
works correctly in both bash and zsh.
Closes#1173
Users on OpenRouter or local models get unexpected API costs because
GSD's default 'balanced' profile spawns specific Anthropic models for
subagents. The 'inherit' profile exists but wasn't well-documented for
this use case.
Changes:
- model-profiles.md: add 'Using Non-Anthropic Models' section explaining
when and how to use inherit profile
- model-profiles.md: update inherit description to mention OpenRouter and
local models
- settings.md: update Inherit option description to mention OpenRouter
and local models (was only mentioning OpenCode)
Closes#1036
Before this PR, Step 5 derived nyquist_validation from depth !== "quick"
(now granularity !== "coarse"). The new config-new-project call omitted
it, silently defaulting to true even when the user selected "Coarse"
granularity.
Adds nyquist_validation back to the Step 5 JSON payload with an explicit
inline rule: false when granularity=coarse, true otherwise.
buildNewProjectConfig() merges ~/.gsd/defaults.json when present, so
tests asserting concrete config values (model_profile, commit_docs,
brave_search) would fail on machines with a personal defaults file.
- Pass HOME=cwd as env override in runGsdTools — child process resolves
os.homedir() to the temp directory, which has no .gsd/ subtree
- Update three tests that previously wrote to the real ~/.gsd/ using
fragile save/restore logic; they now write to tmpDir/.gsd/ instead,
which is cleaned up automatically by afterEach
- Remove now-unused `os` import from config.test.cjs
Add `config-new-project` CLI command that writes a complete,
fully-materialized `.planning/config.json` with sane defaults
instead of the previous partial template (6-7 user-chosen keys
only). Unset keys are no longer silently resolved at read time —
every key GSD reads is written explicitly at project creation.
Previously, missing keys were resolved silently by loadConfig()
defaults, making the effective config non-discoverable. Now every
key that GSD reads is written explicitly at project creation.
- buildNewProjectConfig() — single source of truth for all
defaults; merges hardcoded ← ~/.gsd/defaults.json ← user choices
- ensureConfigFile() refactored to reuse buildNewProjectConfig({})
instead of duplicating default logic (~40 lines removed)
- new-project.md Steps 2a and 5 updated to call config-new-project
instead of writing a hardcoded partial JSON template
- Test coverage for config.cjs: 78.96% → 93.81% statements,
100% functions; adds config-set-model-profile test suite
FIXES:
- VALID_CONFIG_KEYS extended with workflow.auto_advance,
workflow.node_repair, workflow.node_repair_budget,
hooks.context_warnings — these keys had hardcoded defaults
but were not settable via config-set
The workflow spawns 4 background agents but didn't tell Claude how to
wait for them. Without explicit TaskOutput instructions, the orchestrator
displays "Waiting for agents to complete..." indefinitely.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
On Windows, install.js resolves $HOME to the absolute path
(e.g. C:/Users/matte/.claude/) in all workflow .md files.
This breaks when ~/.claude is mounted into a Docker container
where the path doesn't exist — Node interprets the Windows path
as relative to CWD, producing paths like:
/workspace/project/C:/Users/matte/.claude/get-shit-done/bin/gsd-tools.cjs
For global installs, replace os.homedir() with ~ in pathPrefix
so that paths like ~/.claude/get-shit-done/bin/gsd-tools.cjs
work correctly across all environments.
Local installs keep using resolved absolute paths since they
may be outside $HOME.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add Cursor as a fifth supported runtime alongside Claude Code, OpenCode,
Gemini, and Codex. Cursor uses skills (~/.cursor/skills/gsd-*/SKILL.md)
like Codex, with tool name mappings (Bash→Shell, Edit→StrReplace),
subagent type conversion, and full Claude-to-Cursor content adaptation
including project conventions (CLAUDE.md→.cursor/rules/, .claude/skills/
→.cursor/skills/) and brand references.
Includes install, uninstall, interactive prompt, help text, manifest
tracking, and .cjs/.js utility script conversion.
Made-with: Cursor
- fix(core): getMilestoneInfo() version regex `\d+\.\d+` only matched
2-segment versions (v1.2). Changed to `\d+(?:\.\d+)+` to support
3+ segments (v1.2.1, v2.0.1). Same fix in roadmap.cjs milestone
extraction pattern.
- fix(state): stripFrontmatter() used `^---\n` (LF-only) which failed
to strip CRLF frontmatter blocks. When STATE.md had dual frontmatter
blocks from prior CRLF corruption, each writeStateMd() call preserved
the stale block and prepended a new wrong one. Now handles CRLF and
strips all stacked frontmatter blocks.
- fix(frontmatter): extractFrontmatter() always used the first ---
block. When dual blocks exist from corruption, the first is stale.
Now uses the last block (most recent sync).
Hook files (gsd-statusline.js, gsd-check-update.js, gsd-context-monitor.js)
are installed during updates but were never included in gsd-file-manifest.json.
This means saveLocalPatches() could not detect user modifications to hooks,
causing them to be silently overwritten on update with no backup.
Add hooks/gsd-*.js to writeManifest() so the existing local patch detection
system automatically backs up modified hooks to gsd-local-patches/ before
overwriting, matching the behavior already in place for workflows, commands,
and agents.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The offer_next step in execute-phase.md suggests /gsd:transition to users
when auto-advance is disabled. This command does not exist as a registered
skill — transition.md is an internal workflow only invoked inline during
auto-advance chains (line 456).
Replace with /gsd:discuss-phase and /gsd:plan-phase which are the actual
user-facing equivalents for transitioning between phases.
No impact on auto-advance path — that invokes transition.md by file path,
not as a slash command.
Co-authored-by: Piyush Rane <piyush.rane@inmobi.com>
- fix(frontmatter): handle CRLF line endings in extractFrontmatter,
spliceFrontmatter, and parseMustHavesBlock — fixes wave parsing on
Windows where all plans reported as wave 1 (#1085)
- fix(hooks): remove duplicate const cwd declaration in
gsd-context-monitor.js that caused SyntaxError on every PostToolUse
invocation (#1091, #1092, #1094)
- feat(state): add 'state begin-phase' command that updates STATUS,
Last Activity, Current focus, Current Position, and plan counts
when a new phase starts executing (#1102, #1103, #1104)
- docs(workflow): add state begin-phase call to execute-phase workflow
validate_phase step so STATE.md is current from the start
Previously, calling `mark-complete` on already-completed requirements
reported them as `not_found`, since the regex only matched unchecked
`[ ]` checkboxes and `Pending` table cells.
Now detects `[x]` checkboxes and `Complete` table cells and returns
them in a new `already_complete` array instead of `not_found`.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Three additive quality improvements to the execution pipeline:
1. Pre-wave dependency check (execute-phase): Before spawning wave N+1,
verify key-links from prior wave artifacts. Catches cross-plan wiring
gaps before they cascade into downstream failures.
2. Cross-Plan Data Contracts dimension (plan-checker): New Dimension 9
checks that plans sharing data pipelines have compatible transformations.
Flags when one plan strips data another plan needs in original form.
3. Export-level spot check (verify-phase): After Level 3 wiring passes,
spot-check individual exports for actual usage. Catches dead stores
that exist in wired files but are never called.
Three bugs preventing /gsd:profile-user from generating complete profiles:
1. Template path resolves to bin/templates/ (doesn't exist) instead of
templates/ — __dirname is bin/lib/, needs two levels up not one
2. write-profile reads analysis.projects_list and analysis.message_count
but the profiler agent outputs projects_analyzed and messages_analyzed
3. Evidence block checks dim.evidence but profiler outputs evidence_quotes
Fixes all three with fallback patterns (accepts both old and new field
names) so existing and future analysis formats both work.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
PR #1084 added profile-user command and gsd-user-profiler agent but
didn't bump the hardcoded count assertions in copilot-install tests.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>