* fix(3668): isolate --local install from global gsd-sdk - `buildGsdSdkVersionMismatchReport` now accepts `opts.isLocal`; when true it sets `fix_command` to `npx get-shit-done-cc@latest --claude --local` instead of `npm install -g …`, removing the misleading global upgrade suggestion for local installs. - Propagate `isLocal` from `installSdkIfNeeded` into the mismatch report builder so the right fix_command reaches the renderer. - Export `buildGsdSdkVersionMismatchReport` and `renderGsdSdkVersionMismatchReport` so tests can assert on the IR contract directly. - Add `command -v gsd-sdk … elif node "$GSD_TOOLS"` preflight SDK resolution block to all 69 workflow files that called bare `gsd-sdk` with no fallback, matching the pattern established in update.md, execute-phase.md, and quick.md. - Add `tests/bug-3668-local-install-sdk-soft-dep.test.cjs` with 5 tests covering Defects 1-3, including a CI lint guard that blocks future workflow regressions. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * changeset: add Fixed entry for #3668 * fix(3668): add allow-test-rule to suppress false lint-no-source-grep violation The test reads workflow .md files (product content) to assert structural invariants — not .cjs source files. The file-presence check is the only viable IR for markdown guard patterns. Add the // allow-test-rule annotation so lint-no-source-grep passes. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(3668): fix do.md false-positive and discuss-phase.md size overflow Two CI failures introduced by the 69-workflow preflight block: 1. do.md: the path `bin/gsd-tools.cjs` contains `/gsd-tools` which the bug-2954 parity test regex `/\/gsd[:-]([a-z][a-z0-9-]*)/g` mistakenly extracts as a slash command named `tools`. Fix: store the shim filename in _GSD_SHIM_NAME so the path construction no longer contains a static `/gsd-tools` literal. Also wire $GSD_SDK into the actual query call. 2. discuss-phase.md: the file was at 499 lines (the 500-line budget from #2551). Adding the 11-line preflight block pushed it to 510, failing workflow-size-budget.test.cjs. Fix: compress the 11-line preflight + 2-line invocations into 3 lines (one-liner guard + two $GSD_SDK calls) returning the file to 499 lines while retaining the command -v guard required by bug-3668-local-install-sdk-soft-dep.test.cjs. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(3668): wire \$GSD_SDK through all workflow callsites (#3797) PR #3797 introduced the resolution preflight block (setting \$GSD_SDK) in 69 workflows but left every downstream gsd-sdk callsite using the bare command. On local-only installs the preflight exits cleanly, then the very next line fails with 'command not found'. This is the structural gap the Codex review flagged. Changes: - 687 bare `gsd-sdk` callsites replaced with `\$GSD_SDK` across 75 workflow files (all bash/sh fenced blocks excluding the resolution guard blocks themselves) - execute-phase.md: was missing the preflight block entirely — added the standard 11-line resolution block at the initialize step - execute-phase.md: inline `if command -v gsd-sdk` availability guard (legacy #3384 fallback) replaced with `\$GSD_SDK` + error fallback since the new preflight guarantees SDK availability or exits 1 - 6 sub-workflow files (discuss-phase/modes/*, execute-phase/steps/*) that have no preflight of their own but use \$GSD_SDK — these are loaded by parent workflows that set the variable; callsites updated to use \$GSD_SDK so they work when variable is in scope Transformation script used: /private/tmp/fw2.js (regex-based fence parser with segment join invariant verification — preserves all blank lines and prose formatting). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * test(3668): upgrade CI guard to detect bare callsite routing (#3797) The previous Defect 3 test checked that 'command -v gsd-sdk' appeared as a string in the file — a guard-presence check, not a callsite-routing check. A workflow with the preflight block but 40 bare gsd-sdk calls below it passed the old test. This is exactly the bug state PR #3797 was supposed to fix. Upgraded test: - Parses each workflow file into markdown segments using a regex-based fence extractor (preserves all content invariantly) - Skips bash/sh blocks that contain 'command -v gsd-sdk' (those are resolution guards — bare references there are expected) - Flags any remaining bash/sh block line that invokes gsd-sdk without the \$ prefix (isBareGsdSdkInvocation predicate) - Counter-test proves the predicate correctly flags real callsite lines and correctly exempts guard assignments, comments, and \$GSD_SDK refs Also adds helper functions parseMarkdownSegments, isBareGsdSdkInvocation, and findMdFiles which are used by both the upgraded Defect 3 test and the counter-test. This test would have caught the originally-shipped bug: the preflight block was present but callsites still used bare gsd-sdk. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(tests): update workflow content tests to accept \$GSD_SDK callsite form (#3797) Six regression tests assert on the exact textual pattern of gsd-sdk calls inside workflow .md files. After the #3797 callsite replacement (687 bare `gsd-sdk` invocations replaced with `\$GSD_SDK`), these tests failed because they searched for the literal string `gsd-sdk query <cmd>` which no longer appears at callsites. Updated each test to accept both the pre-#3797 bare form and the post-#3797 variable form using `(?:\$GSD_SDK|gsd-sdk)` regex alternation (or two-branch `includes()` checks for non-regex assertions). The structural invariants each test enforces are unchanged — we're accepting the same behavioral contract through the new callsite surface. Tests fixed: - bug-2334-quick-gsd-sdk-preflight: find init.quick call via \$GSD_SDK or bare - bug-2661-roadmap-sync-parallel: roadmap.update-plan-progress call pattern - bug-3360-codex-execute-phase-worktrees: RUNTIME config-get call detection - bug-3381-verify-work-workstream: init.verify-work / phase.mvp-mode calls - enh-2433-todo-phase-linking: commit call in new-milestone.md - enh-2792-namespace-skills: validate.context invocation in context_check step Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(tests): update remaining workflow content tests to accept \$GSD_SDK form (#3797) After #3797 callsite replacement, ultraplan-phase.test.cjs and worktree-cleanup.test.cjs still assert bare gsd-sdk form. Update to accept either \$GSD_SDK or gsd-sdk. Also trim the execute-phase.md preflight comment to stay within the XL line-count budget (1810). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(3668): adopt inline-per-fence SDK resolution + restore safety semantics The brief offered three options: (a) inline preflight block per fence (b) wrapper script (c) shared shell fragment sourced at the top 71 of 72 workflow files already had inline preflight blocks (just broken ones). Option (b)/(c) would have required changes to install.js + a new shared artifact, with significant risk of breaking the install pipeline. Option (a) was the path of least resistance and least new blast radius. **BLOCKER 1+2+3 (quick.md — GSD_SDK never assigned):** - quick.md had 12 `$GSD_SDK` references but zero `GSD_SDK=` assignments. - Added proper local-first preflight block with `git rev-parse --show-toplevel` path (not the broken `CLAUDE_FILE_PATHS` which is always empty in Claude Code). - Each Bash fence in Claude Code runs as a fresh `bash -c`, so env vars don't persist. The preflight block must appear in every fence that uses $GSD_SDK. **BLOCKER 4 (execute-phase.md — || exit 1 dropped):** - Restored `|| exit 1` after every `worktree.cleanup-wave` call. SDK safety refusals (drift detection #3174, deletion block #2384) must surface, not be swallowed by the old `|| { fallback }` branch. **F5 (verify-work.md untyped fence):** - Changed bare `gsd-sdk` in an untyped fence to `$GSD_SDK`. - Changed fence tag from untyped to `bash`. **F6 (non-recursive readdirSync):** - Defect 2 test now uses `findMdFiles` (recursive) to cover workflow subdirectories, not the flat `fs.readdirSync` that missed subdirs. **F7 (lint misses untyped fences):** - `parseMarkdownSegments` now treats `lang === ''` fences as bash-fences. **F8 (missing propagation test):** - Added two propagation tests in the Defect 3 describe block. **F9 (priority inverted — global before local):** - All 72 workflow files now check `[ -f "$GSD_TOOLS" ]` before `command -v gsd-sdk`. - Path: `$(git rev-parse --show-toplevel 2>/dev/null || pwd)/get-shit-done/bin/gsd-tools.cjs` **F10/F11 (broken quoting):** - Changed `GSD_SDK="node "$GSD_TOOLS""` → `GSD_SDK="node $GSD_TOOLS"` across all files. **SDK-absence fallback removal:** - The old `|| { STATE_BACKUP=...; while IFS=...WAS_DELETED...; done }` fallback code was dead — preflight now exits if neither local nor global SDK exists. Removed from quick.md, execute-phase.md. Tests updated to verify SDK delegation rather than inline shell mechanics. **Tests updated:** - bug-2384, bug-2501, bug-2838, bug-3091, bug-3195, bug-3521, bug-3668, worktree-cleanup — all updated to reflect SDK delegation contract. - Defect 2 test now uses bash-fence scan (not raw content) to skip docs-only gsd-sdk prose references (e.g. discuss-phase/modes/text.md). Closes #3668 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(3668): restore _GSD_SHIM_NAME indirection in do.md to prevent false-positive The top commit re-introduced a literal /get-shit-done/bin/gsd-tools.cjs path in do.md, causing bug-2954 test to match /gsd-tools as an unshipped slash command. Restore the _GSD_SHIM_NAME variable indirection (from ff9939e5) to break the literal path while preserving local-first preference order. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(tests): update worktree.test.cjs to accept SDK delegation contract (#3797) Mirror the contract update already applied to worktree-cleanup.test.cjs: - pre-merge deletion check tests: accept worktree.cleanup-wave + deletion mention as valid (inline --diff-filter=D was in the removed shell fallback) - quick.md bug-2431 tests (lock-aware, unlock retry, residual warning): accept worktree.cleanup-wave delegation as sufficient (these safety behaviors are now handled internally by the SDK cleanup-wave command) execute-phase.md tests unchanged: it retains inline .git/worktrees/, locked, git worktree unlock, and Residual worktree in its cleanup-tail snippet. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * test(3668): refactor bug-2384 and bug-2838 from grep to structured assertions Replace content.includes() on readFileSync-bound variables with parser functions that split lines and return typed boolean fields, matching the project's no-source-grep contract (lint-no-source-grep rule F/G). --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
25 KiB
Start a new milestone cycle for an existing project. Loads project context, gathers milestone goals (from MILESTONE-CONTEXT.md or conversation), updates PROJECT.md and STATE.md, optionally runs parallel research, defines scoped requirements with REQ-IDs, spawns the roadmapper to create phased execution plan, and commits all artifacts. Brownfield equivalent of new-project.
<required_reading>
Read all files referenced by the invoking prompt's execution_context before starting.
</required_reading>
<available_agent_types> Valid GSD subagent types (use exact names — do not fall back to 'general-purpose'):
- gsd-project-researcher — Researches project-level technical decisions
- gsd-research-synthesizer — Synthesizes findings from parallel research agents
- gsd-roadmapper — Creates phased execution roadmaps </available_agent_types>
1. Load Context
Parse $ARGUMENTS before doing anything else:
--reset-phase-numbersflag → opt into restarting roadmap phase numbering at1- remaining text → use as milestone name if present
If the flag is absent, keep the current behavior of continuing phase numbering from the previous milestone.
- Read PROJECT.md (existing project, validated requirements, decisions)
- Read MILESTONES.md (what shipped previously)
- Read STATE.md (pending todos, blockers)
- Check for MILESTONE-CONTEXT.md (from /gsd-discuss-milestone)
2. Gather Milestone Goals
If MILESTONE-CONTEXT.md exists:
- Use features and scope from discuss-milestone
- Present summary for confirmation
If no context file:
- Present what shipped in last milestone
Text mode (workflow.text_mode: true in config or --text flag): Set TEXT_MODE=true if --text is present in $ARGUMENTS OR text_mode from init JSON is true. When TEXT_MODE is active, replace every AskUserQuestion call with a plain-text numbered list and ask the user to type their choice number. This is required for non-Claude runtimes (OpenAI Codex, Gemini CLI, etc.) where AskUserQuestion is not available.
- Ask inline (freeform, NOT AskUserQuestion): "What do you want to build next?"
- Wait for their response, then use AskUserQuestion to probe specifics
- If user selects "Other" at any point to provide freeform input, ask follow-up as plain text — not another AskUserQuestion
2.5. Scan Planted Seeds
Check .planning/seeds/ for seed files that match the milestone goals gathered in step 2.
ls .planning/seeds/SEED-*.md 2>/dev/null
If no seed files exist: Skip this step silently — do not print any message or prompt.
If seed files exist: Read each SEED-*.md file and extract from its frontmatter and body:
- Idea — the seed title (heading after frontmatter, e.g.
# SEED-001: <idea>) - Trigger conditions — the
trigger_whenfrontmatter field and the "When to Surface" section's bullet list - Planted during — the
planted_duringfrontmatter field (for context)
Compare each seed's trigger conditions against the milestone goals from step 2. A seed matches when its trigger conditions are relevant to any of the milestone's target features or goals.
If no seeds match: Skip silently — do not prompt the user.
If matching seeds found:
--auto mode: Auto-select ALL matching seeds. Log: [auto] Selected N matching seed(s): [list seed names]
Text mode (TEXT_MODE=true): Present matching seeds as a plain-text numbered list:
Seeds that match your milestone goals:
1. SEED-001: <idea> (trigger: <trigger_when>)
2. SEED-003: <idea> (trigger: <trigger_when>)
Enter numbers to include (comma-separated), or "none" to skip:
Normal mode: Present via AskUserQuestion:
AskUserQuestion(
header: "Seeds",
question: "These planted seeds match your milestone goals. Include any in this milestone's scope?",
multiSelect: true,
options: [
{ label: "SEED-001: <idea>", description: "Trigger: <trigger_when> | Planted during: <planted_during>" },
...
]
)
After selection:
- Selected seeds become additional context for requirement definition in step 9. Store them in an accumulator (e.g.
$SELECTED_SEEDS) so step 9 can reference the ideas and their "Why This Matters" sections when defining requirements. - Unselected seeds remain untouched in
.planning/seeds/— never delete or modify seed files during this workflow.
3. Determine Milestone Version
- Parse last version from MILESTONES.md
- Suggest next version (v1.0 → v1.1, or v2.0 for major)
- Confirm with user
3.5. Verify Milestone Understanding
Before writing any files, present a summary of what was gathered and ask for confirmation.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
GSD ► MILESTONE SUMMARY
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
**Milestone v[X.Y]: [Name]**
**Goal:** [One sentence]
**Target features:**
- [Feature 1]
- [Feature 2]
- [Feature 3]
**Key context:** [Any important constraints, decisions, or notes from questioning]
AskUserQuestion:
- header: "Confirm?"
- question: "Does this capture what you want to build in this milestone?"
- options:
- "Looks good" — Proceed to write PROJECT.md
- "Adjust" — Let me correct or add details
If "Adjust": Ask what needs changing (plain text, NOT AskUserQuestion). Incorporate changes, re-present the summary. Loop until "Looks good" is selected.
If "Looks good": Proceed to Step 4.
4. Update PROJECT.md
Add/update:
## Current Milestone: v[X.Y] [Name]
**Goal:** [One sentence describing milestone focus]
**Target features:**
- [Feature 1]
- [Feature 2]
- [Feature 3]
Update Active requirements section and "Last updated" footer.
Ensure the ## Evolution section exists in PROJECT.md. If missing (projects created before this feature), add it before the footer:
## Evolution
This document evolves at phase transitions and milestone boundaries.
**After each phase transition** (via `/gsd-transition`):
1. Requirements invalidated? → Move to Out of Scope with reason
2. Requirements validated? → Move to Validated with phase reference
3. New requirements emerged? → Add to Active
4. Decisions to log? → Add to Key Decisions
5. "What This Is" still accurate? → Update if drifted
**After each milestone** (via `/gsd:complete-milestone`):
1. Full review of all sections
2. Core Value check — still the right priority?
3. Audit Out of Scope — reasons still valid?
4. Update Context with current state
5. Update STATE.md
Reset STATE.md frontmatter AND body atomically via the SDK. This writes the new
milestone version/name into the YAML frontmatter, resets status to
planning, zeroes progress.* counters, and rewrites the ## Current Position
section to the new-milestone template. Accumulated Context (decisions,
blockers, todos) is preserved across the switch — symmetric with
milestone.complete.
# SDK resolution: prefer local gsd-tools.cjs, fall back to global gsd-sdk (#3668)
GSD_TOOLS="${RUNTIME_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}/get-shit-done/bin/gsd-tools.cjs"
if [ -f "$GSD_TOOLS" ]; then
GSD_SDK="node $GSD_TOOLS"
elif command -v gsd-sdk >/dev/null 2>&1; then
GSD_SDK="gsd-sdk"
else
echo "ERROR: gsd-sdk not found on PATH and $GSD_TOOLS does not exist." >&2
echo "Run: npx get-shit-done-cc@latest --claude --local" >&2
exit 1
fi
$GSD_SDK query state.milestone-switch --milestone "v[X.Y]" --name "[Name]"
The resulting Current Position section looks like:
## Current Position
Phase: Not started (defining requirements)
Plan: —
Status: Defining requirements
Last activity: [today] — Milestone v[X.Y] started
Bug #2630: a prior version of this workflow rewrote the Current Position body
manually but left the frontmatter pointing at the previous milestone, so every
downstream reader (state.json, getMilestoneInfo, progress bars) reported the
stale milestone until the first phase advance forced a resync. Always use the
SDK handler above — do not hand-edit STATE.md here.
6. Cleanup and Commit
Delete MILESTONE-CONTEXT.md if exists (consumed).
Clear leftover phase directories from the previous milestone:
$GSD_SDK query phases.clear --confirm
$GSD_SDK query commit "docs: start milestone v[X.Y] [Name]" --files .planning/PROJECT.md .planning/STATE.md
7. Load Context and Resolve Models
INIT=$($GSD_SDK query init.new-milestone)
if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
AGENT_SKILLS_RESEARCHER=$($GSD_SDK query agent-skills gsd-project-researcher)
AGENT_SKILLS_SYNTHESIZER=$($GSD_SDK query agent-skills gsd-research-synthesizer)
AGENT_SKILLS_ROADMAPPER=$($GSD_SDK query agent-skills gsd-roadmapper)
Extract from init JSON: researcher_model, synthesizer_model, roadmapper_model, commit_docs, research_enabled, current_milestone, project_exists, roadmap_exists, latest_completed_milestone, phase_dir_count, phase_archive_path, agents_installed, missing_agents.
If agents_installed is false: Display a warning before proceeding:
⚠ GSD agents not installed. The following agents are missing from your agents directory:
{missing_agents joined with newline}
Subagent spawns (gsd-project-researcher, gsd-research-synthesizer, gsd-roadmapper) will fail
with "agent type not found". Run the installer with --global to make agents available:
npx get-shit-done-redux@latest --global
Proceeding without research subagents — roadmap will be generated inline.
Skip the parallel research spawn step and generate the roadmap inline.
7.5 Reset-phase safety (only when --reset-phase-numbers)
If --reset-phase-numbers is active:
- Set starting phase number to
1for the upcoming roadmap. - If
phase_dir_count > 0, archive the old phase directories before roadmapping so new01-*/02-*directories cannot collide with stale milestone directories.
If phase_dir_count > 0 and phase_archive_path is available:
mkdir -p "${phase_archive_path}"
find .planning/phases -mindepth 1 -maxdepth 1 -type d -exec mv {} "${phase_archive_path}/" \;
Then verify .planning/phases/ no longer contains old milestone directories before continuing.
If phase_dir_count > 0 but phase_archive_path is missing:
- Stop and explain that reset numbering is unsafe without a completed milestone archive target.
- Tell the user to complete/archive the previous milestone first, then rerun
/gsd:new-milestone --reset-phase-numbers ${GSD_WS}.
8. Research Decision
Check research_enabled from init JSON (loaded from config).
If research_enabled is true:
AskUserQuestion: "Research the domain ecosystem for new features before defining requirements?"
- "Research first (Recommended)" — Discover patterns, features, architecture for NEW capabilities
- "Skip research for this milestone" — Go straight to requirements (does not change your default)
If research_enabled is false:
AskUserQuestion: "Research the domain ecosystem for new features before defining requirements?"
- "Skip research (current default)" — Go straight to requirements
- "Research first" — Discover patterns, features, architecture for NEW capabilities
IMPORTANT: Do NOT persist this choice to config.json. The workflow.research setting is a persistent user preference that controls plan-phase behavior across the project. Changing it here would silently alter future /gsd:plan-phase behavior. To change the default, use /gsd:settings.
If user chose "Research first":
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
GSD ► RESEARCHING
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
◆ Spawning 4 researchers in parallel...
→ Stack, Features, Architecture, Pitfalls
mkdir -p .planning/research
Spawn 4 parallel gsd-project-researcher agents. Each uses this template with dimension-specific fields:
Common structure for all 4 researchers:
Agent(prompt="
<research_type>Project Research — {DIMENSION} for [new features].</research_type>
<milestone_context>
SUBSEQUENT MILESTONE — Adding [target features] to existing app.
{EXISTING_CONTEXT}
Focus ONLY on what's needed for the NEW features.
</milestone_context>
<question>{QUESTION}</question>
<files_to_read>
- .planning/PROJECT.md (Project context)
</files_to_read>
${AGENT_SKILLS_RESEARCHER}
<downstream_consumer>{CONSUMER}</downstream_consumer>
<quality_gate>{GATES}</quality_gate>
<output>
Write to: .planning/research/{FILE}
Use template: ~/.claude/get-shit-done/templates/research-project/{FILE}
</output>
", subagent_type="gsd-project-researcher", model="{researcher_model}", description="{DIMENSION} research")
Dimension-specific fields:
| Field | Stack | Features | Architecture | Pitfalls |
|---|---|---|---|---|
| EXISTING_CONTEXT | Existing validated capabilities (DO NOT re-research): [from PROJECT.md] | Existing features (already built): [from PROJECT.md] | Existing architecture: [from PROJECT.md or codebase map] | Focus on common mistakes when ADDING these features to existing system |
| QUESTION | What stack additions/changes are needed for [new features]? | How do [target features] typically work? Expected behavior? | How do [target features] integrate with existing architecture? | Common mistakes when adding [target features] to [domain]? |
| CONSUMER | Specific libraries with versions for NEW capabilities, integration points, what NOT to add | Table stakes vs differentiators vs anti-features, complexity noted, dependencies on existing | Integration points, new components, data flow changes, suggested build order | Warning signs, prevention strategy, which phase should address it |
| GATES | Versions current (verify with Context7), rationale explains WHY, integration considered | Categories clear, complexity noted, dependencies identified | Integration points identified, new vs modified explicit, build order considers deps | Pitfalls specific to adding these features, integration pitfalls covered, prevention actionable |
| FILE | STACK.md | FEATURES.md | ARCHITECTURE.md | PITFALLS.md |
ORCHESTRATOR RULE — CODEX RUNTIME: After calling all 4 researcher Agent() calls above, do NOT read research files or synthesize content independently while the subagents are active. Wait for all 4 researchers to complete before spawning the synthesizer. This prevents duplicate work and wasted context.
After all 4 complete, spawn synthesizer:
Agent(prompt="
Synthesize research outputs into SUMMARY.md.
<files_to_read>
- .planning/research/STACK.md
- .planning/research/FEATURES.md
- .planning/research/ARCHITECTURE.md
- .planning/research/PITFALLS.md
</files_to_read>
${AGENT_SKILLS_SYNTHESIZER}
Write to: .planning/research/SUMMARY.md
Use template: ~/.claude/get-shit-done/templates/research-project/SUMMARY.md
Commit after writing.
", subagent_type="gsd-research-synthesizer", model="{synthesizer_model}", description="Synthesize research")
ORCHESTRATOR RULE — CODEX RUNTIME: After calling Agent() above, stop working on this task immediately. Do not read more files, edit code, or run tests related to this task while the subagent is active. Wait for the subagent to return its result. This prevents duplicate work, conflicting edits, and wasted context. Only resume when the subagent result is available.
Display key findings from SUMMARY.md:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
GSD ► RESEARCH COMPLETE ✓
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
**Stack additions:** [from SUMMARY.md]
**Feature table stakes:** [from SUMMARY.md]
**Watch Out For:** [from SUMMARY.md]
If "Skip research": Continue to Step 9.
9. Define Requirements
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
GSD ► DEFINING REQUIREMENTS
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Read PROJECT.md: core value, current milestone goals, validated requirements (what exists).
If $SELECTED_SEEDS is non-empty (from step 2.5): Include selected seed ideas and their "Why This Matters" sections as additional input when defining requirements. Seeds provide user-validated feature ideas that should be incorporated into the requirement categories alongside research findings or conversation-gathered features.
If research exists: Read FEATURES.md, extract feature categories.
Present features by category:
## [Category 1]
**Table stakes:** Feature A, Feature B
**Differentiators:** Feature C, Feature D
**Research notes:** [any relevant notes]
If no research: Gather requirements through conversation. Ask: "What are the main things users need to do with [new features]?" Clarify, probe for related capabilities, group into categories.
Scope each category via AskUserQuestion (multiSelect: true, header max 12 chars):
- "[Feature 1]" — [brief description]
- "[Feature 2]" — [brief description]
- "None for this milestone" — Defer entire category
Track: Selected → this milestone. Unselected table stakes → future. Unselected differentiators → out of scope.
Identify gaps via AskUserQuestion:
- "No, research covered it" — Proceed
- "Yes, let me add some" — Capture additions
Generate REQUIREMENTS.md:
- v1 Requirements grouped by category (checkboxes, REQ-IDs)
- Future Requirements (deferred)
- Out of Scope (explicit exclusions with reasoning)
- Traceability section (empty, filled by roadmap)
REQ-ID format: [CATEGORY]-[NUMBER] (AUTH-01, NOTIF-02). Continue numbering from existing.
Requirement quality criteria:
Good requirements are:
- Specific and testable: "User can reset password via email link" (not "Handle password reset")
- User-centric: "User can X" (not "System does Y")
- Atomic: One capability per requirement (not "User can login and manage profile")
- Independent: Minimal dependencies on other requirements
Present FULL requirements list for confirmation:
## Milestone v[X.Y] Requirements
### [Category 1]
- [ ] **CAT1-01**: User can do X
- [ ] **CAT1-02**: User can do Y
### [Category 2]
- [ ] **CAT2-01**: User can do Z
Does this capture what you're building? (yes / adjust)
If "adjust": Return to scoping.
Commit requirements:
$GSD_SDK query commit "docs: define milestone v[X.Y] requirements" --files .planning/REQUIREMENTS.md
10. Create Roadmap
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
GSD ► CREATING ROADMAP
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
◆ Spawning roadmapper...
Starting phase number:
- If
--reset-phase-numbersis active, start at Phase 1 - Otherwise, continue from the previous milestone's last phase number (v1.0 ended at phase 5 → v1.1 starts at phase 6)
Agent(prompt="
<planning_context>
<files_to_read>
- .planning/PROJECT.md
- .planning/REQUIREMENTS.md
- .planning/research/SUMMARY.md (if exists)
- .planning/config.json
- .planning/MILESTONES.md
</files_to_read>
${AGENT_SKILLS_ROADMAPPER}
</planning_context>
<instructions>
Create roadmap for milestone v[X.Y]:
1. Respect the selected numbering mode:
- `--reset-phase-numbers` → start at Phase 1
- default behavior → continue from the previous milestone's last phase number
2. Derive phases from THIS MILESTONE's requirements only
3. Map every requirement to exactly one phase
4. Derive 2-5 success criteria per phase (observable user behaviors)
5. Validate 100% coverage
6. Write files immediately (ROADMAP.md, STATE.md, update REQUIREMENTS.md traceability)
7. Return ROADMAP CREATED with summary
Write files first, then return.
</instructions>
", subagent_type="gsd-roadmapper", model="{roadmapper_model}", description="Create roadmap")
ORCHESTRATOR RULE — CODEX RUNTIME: After calling Agent() above, stop working on this task immediately. Do not read more files, edit code, or run tests related to this task while the subagent is active. Wait for the subagent to return its result. This prevents duplicate work, conflicting edits, and wasted context. Only resume when the subagent result is available.
Handle return:
If ## ROADMAP BLOCKED: Present blocker, work with user, re-spawn.
If ## ROADMAP CREATED: Read ROADMAP.md, present inline:
## Proposed Roadmap
**[N] phases** | **[X] requirements mapped** | All covered ✓
| # | Phase | Goal | Requirements | Success Criteria |
|---|-------|------|--------------|------------------|
| [N] | [Name] | [Goal] | [REQ-IDs] | [count] |
### Phase Details
**Phase [N]: [Name]**
Goal: [goal]
Requirements: [REQ-IDs]
Success criteria:
1. [criterion]
2. [criterion]
Ask for approval via AskUserQuestion:
- "Approve" — Commit and continue
- "Adjust phases" — Tell me what to change
- "Review full file" — Show raw ROADMAP.md
If "Adjust": Get notes, re-spawn roadmapper with revision context, loop until approved. If "Review": Display raw ROADMAP.md, re-ask.
Commit roadmap (after approval):
$GSD_SDK query commit "docs: create milestone v[X.Y] roadmap ([N] phases)" --files .planning/ROADMAP.md .planning/STATE.md .planning/REQUIREMENTS.md
10.5. Link Pending Todos to Roadmap Phases
After roadmap approval, scan pending todos against the newly approved phases. For each todo whose scope matches a phase, tag it with resolves_phase: N in its YAML frontmatter.
Check for pending todos:
PENDING_TODOS=$(ls .planning/todos/pending/*.md 2>/dev/null | head -50)
If no pending todos exist: Skip this step silently.
If pending todos exist:
Read the approved ROADMAP.md and extract the phase list: phase number, phase name, goal, and requirement IDs.
For each pending todo, compare:
- The todo's
titleandareafrontmatter fields - The todo body (Problem and Solution sections)
Against each phase's:
- Phase goal
- Requirement IDs and descriptions
Match criteria (best-effort — do not over-match): A todo is considered resolved by a phase if the phase's goal or requirements directly describe implementing the same feature, area, or capability as the todo. Narrow, specific todos with concrete scopes are the best candidates. Vague or cross-cutting todos should be left unlinked.
For each matched todo, add resolves_phase: [N] to the YAML frontmatter block (after the existing fields):
---
created: [existing]
title: [existing]
area: [existing]
resolves_phase: [N]
files: [existing]
---
Only modify todos that have a clear, confident match. Leave unmatched todos unmodified.
If any todos were linked:
$GSD_SDK query commit "docs: tag [count] pending todos with resolves_phase after milestone v[X.Y] roadmap" --files .planning/todos/pending/*.md
Print a summary:
◆ Linked [N] pending todos to roadmap phases:
→ [todo title] → Phase [N]: [Phase Name]
(Leave [M] unmatched todos in pending/)
11. Done
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
GSD ► MILESTONE INITIALIZED ✓
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
**Milestone v[X.Y]: [Name]**
| Artifact | Location |
|----------------|-----------------------------|
| Project | `.planning/PROJECT.md` |
| Research | `.planning/research/` |
| Requirements | `.planning/REQUIREMENTS.md` |
| Roadmap | `.planning/ROADMAP.md` |
**[N] phases** | **[X] requirements** | Ready to build ✓
## ▶ Next Up — [${PROJECT_CODE}] ${PROJECT_TITLE}
**Phase [N]: [Phase Name]** — [Goal]
`/clear` then:
`/gsd:discuss-phase [N] ${GSD_WS}` — gather context and clarify approach
Also: `/gsd:plan-phase [N] ${GSD_WS}` — skip discussion, plan directly
<success_criteria>
- PROJECT.md updated with Current Milestone section
- STATE.md reset for new milestone
- MILESTONE-CONTEXT.md consumed and deleted (if existed)
- Research completed (if selected) — 4 parallel agents, milestone-aware
- Requirements gathered and scoped per category
- REQUIREMENTS.md created with REQ-IDs
- gsd-roadmapper spawned with phase numbering context
- Roadmap files written immediately (not draft)
- User feedback incorporated (if any)
- Phase numbering mode respected (continued or reset)
- All commits made (if planning docs committed)
- Pending todos scanned for phase matches; matched todos tagged with
resolves_phase: N - User knows next step:
/gsd:discuss-phase [N] ${GSD_WS}
Atomic commits: Each phase commits its artifacts immediately. </success_criteria>