* 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>
26 KiB
<required_reading> Read STATE.md before any operation to load project context. Read config.json for planning behavior settings.
@~/.claude/get-shit-done/references/git-integration.md </required_reading>
<atomic_close_out_invariant>
For each executed plan, the only complete close-out order is:
production-code commit(s) -> SUMMARY commit -> STATE/ROADMAP update.
The only legal half-state is mid-production-commits while the executor is still actively working. Once production commits for a plan exist, returning without a committed SUMMARY.md is an illegal partial-plan state. The next execute-phase resume must detect that condition before dispatching another executor. </atomic_close_out_invariant>
<available_agent_types> Valid GSD subagent types (use exact names — do not fall back to 'general-purpose'):
- gsd-executor — Executes plan tasks, commits, creates SUMMARY.md </available_agent_types>
# 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
INIT=$($GSD_SDK query init.execute-phase "${PHASE}")
if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
Extract from init JSON: executor_model, commit_docs, sub_repos, phase_dir, phase_number, plans, summaries, incomplete_plans, state_path, config_path.
If .planning/ missing: error.
Find first PLAN without matching SUMMARY. Decimal phases supported (01.1-hotfix/):
PHASE=$(echo "$PLAN_PATH" | grep -oE '[0-9]+(\.[0-9]+)?-[0-9]+')
# config settings can be fetched via gsd-sdk query config-get if needed
Primary routing: task count threshold (#1979)
If INLINE_THRESHOLD > 0 AND TASK_COUNT <= INLINE_THRESHOLD: Use Pattern C (inline) regardless of checkpoint type. Small plans execute faster inline — avoids ~14K token subagent spawn overhead and preserves prompt cache. Configure threshold via workflow.inline_plan_threshold (default: 2, set to 0 to always spawn subagents).
Otherwise: Apply checkpoint-based routing below.
Checkpoint-based routing (plans with > threshold tasks):
| Checkpoints | Pattern | Execution |
|---|---|---|
| None | A (autonomous) | Single subagent: full plan + SUMMARY + commit |
| Verify-only | B (segmented) | Segments between checkpoints. After none/human-verify → SUBAGENT. After decision/human-action → MAIN |
| Decision | C (main) | Execute entirely in main context |
Pattern A: init_agent_tracking → capture EXPECTED_BASE=$(git rev-parse HEAD) → spawn Agent(subagent_type="gsd-executor", model=executor_model) with prompt: execute plan at [path], autonomous, all tasks + SUMMARY + commit, follow deviation/auth rules, report: plan name, tasks, SUMMARY path, commit hash → track agent_id → wait → update tracking → report. Include isolation="worktree" only if workflow.use_worktrees is not false (read via config-get workflow.use_worktrees). When using isolation="worktree", include a <worktree_branch_check> block in the prompt instructing the executor to: (1) FIRST assert git symbolic-ref HEAD resolves to a per-agent branch (NOT a protected ref like main/master/develop/trunk/release/*) and HALT with a blocker if not — never self-recover via git update-ref refs/heads/<protected> (#2924); (2) only after that assertion passes, run git merge-base HEAD {EXPECTED_BASE} and, if the result differs from {EXPECTED_BASE}, hard-reset the branch with git reset --hard {EXPECTED_BASE} before starting work, then verify with [ "$(git rev-parse HEAD)" != "{EXPECTED_BASE}" ] && exit 1. The HEAD assertion (Step 1) MUST run before any reset/checkout. This corrects a known issue where EnterWorktree creates branches from main instead of the feature branch HEAD (affects all platforms — #2015) and prevents the destructive HEAD-on-master self-recovery path (#2924).
Pattern B: Execute segment-by-segment. Autonomous segments: spawn subagent for assigned tasks only (no SUMMARY/commit). Checkpoints: main context. After all segments: aggregate, create SUMMARY, commit. See segment_execution.
Pattern C: Execute in main using standard flow (step name="execute").
Fresh context per subagent preserves peak quality. Main context stays lean.
```bash if [ ! -f .planning/agent-history.json ]; then echo '{"version":"1.0","max_entries":50,"entries":[]}' > .planning/agent-history.json fi rm -f .planning/current-agent-id.txt if [ -f .planning/current-agent-id.txt ]; then INTERRUPTED_ID=$(cat .planning/current-agent-id.txt) echo "Found interrupted agent: $INTERRUPTED_ID" fi ```If interrupted: ask user to resume (Task resume parameter) or start fresh.
Tracking protocol: On spawn: write agent_id to current-agent-id.txt, append to agent-history.json: {"agent_id":"[id]","task_description":"[desc]","phase":"[phase]","plan":"[plan]","segment":[num|null],"timestamp":"[ISO]","status":"spawned","completion_timestamp":null}. On completion: status → "completed", set completion_timestamp, delete current-agent-id.txt. Prune: if entries > max_entries, remove oldest "completed" (never "spawned").
Run for Pattern A/B before spawning. Pattern C: skip.
Pattern B only (verify-only checkpoints). Skip for A/C.-
Parse segment map: checkpoint locations and types
-
Per segment:
- Subagent route: spawn gsd-executor for assigned tasks only. Prompt: task range, plan path, read full plan for context, execute assigned tasks, track deviations, NO SUMMARY/commit. Track via agent protocol.
- Main route: execute tasks using standard flow (step name="execute")
-
Critical ordering — write and commit SUMMARY.md as one atomic block. Do NOT emit narrative output between the Write tool call and the commit tool call. Truncation at this boundary is a known failure mode (see #2070 rescue logic in execute-phase.md step 5.5).
After ALL segments: aggregate files/deviations/decisions → create SUMMARY.md → self-check:
- Verify key-files.created exist on disk with
[ -f ] - Check
git log --oneline --all --grep="{phase}-{plan}"returns ≥1 commit - Re-run ALL
<acceptance_criteria>from every task — if any fail, fix before finalizing SUMMARY - Re-run the plan-level
<verification>commands — log results in SUMMARY - Append
## Self-Check: PASSEDor## Self-Check: FAILEDto SUMMARY Then commit (no narrative between Write and commit).
Known Claude Code bug (classifyHandoffIfNeeded): If any segment agent reports "failed" with
classifyHandoffIfNeeded is not defined, this is a Claude Code runtime bug — not a real failure. Run spot-checks; if they pass, treat as successful. - Verify key-files.created exist on disk with
If plan contains <interfaces> block: These are pre-extracted type definitions and contracts. Use them directly — do NOT re-read the source files to discover types. The planner already extracted what you need.
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.
If previous SUMMARY has unresolved "Issues Encountered" or "Next Phase Readiness" blockers: AskUserQuestion(header="Previous Issues", options: "Proceed anyway" | "Address first" | "Review previous").
- Read @context files from prompt
- MCP tools: If CLAUDE.md or project instructions reference MCP tools (e.g. jCodeMunch for code navigation), prefer them over Grep/Glob when available. Fall back to Grep/Glob if MCP tools are not accessible.
- Per task:
- MANDATORY read_first gate: If the task has a
<read_first>field, you MUST read every listed file BEFORE making any edits. This is not optional. Do not skip files because you "already know" what's in them — read them. The read_first files establish ground truth for the task. type="auto": iftdd="true"→ TDD execution. Implement with deviation rules + auth gates. Verify done criteria. Commit (see task_commit). Track hash for Summary.type="checkpoint:*": STOP → checkpoint_protocol → wait for user → continue only after confirmation.- HARD GATE — acceptance_criteria verification: After completing each task, if it has
<acceptance_criteria>, you MUST run a verification loop before proceeding:- For each criterion: execute the grep, file check, or CLI command that proves it passes
- Log each result as PASS or FAIL with the command output
- If ANY criterion fails: fix the implementation immediately, then re-run ALL criteria
- Repeat until all criteria pass — you are BLOCKED from starting the next task until this gate clears
- If a criterion cannot be satisfied after 2 fix attempts, log it as a deviation with reason — do NOT silently skip it This is not advisory. A task with failing acceptance criteria is an incomplete task.
- MANDATORY read_first gate: If the task has a
- Run
<verification>checks - Confirm
<success_criteria>met - Document deviations in Summary
<authentication_gates>
Authentication Gates
Auth errors during execution are NOT failures — they're expected interaction points.
Indicators: "Not authenticated", "Unauthorized", 401/403, "Please run {tool} login", "Set {ENV_VAR}"
Protocol:
- Recognize auth gate (not a bug)
- STOP task execution
- Create dynamic checkpoint:human-action with exact auth steps
- Wait for user to authenticate
- Verify credentials work
- Retry original task
- Continue normally
Example: vercel --yes → "Not authenticated" → checkpoint asking user to vercel login → verify with vercel whoami → retry deploy → continue
In Summary: Document as normal flow under "## Authentication Gates", not as deviations.
</authentication_gates>
<deviation_rules>
Deviation Rules
Apply deviation rules from the gsd-executor agent definition (single source of truth):
- Rules 1-3 (bugs, missing critical, blockers): auto-fix, test, verify, track as deviations
- Rule 4 (architectural changes): STOP, present decision to user, await approval
- Scope boundary: do not auto-fix pre-existing issues unrelated to current task
- Fix attempt limit: max 3 retries per deviation before escalating
- Priority: Rule 4 (STOP) > Rules 1-3 (auto) > unsure → Rule 4
</deviation_rules>
<deviation_documentation>
Documenting Deviations
Summary MUST include deviations section. None? → ## Deviations from Plan\n\nNone - plan executed exactly as written.
Per deviation: [Rule N - Category] Title — Found during: Task X | Issue | Fix | Files modified | Verification | Commit hash
End with: Total deviations: N auto-fixed (breakdown). Impact: assessment.
</deviation_documentation>
<tdd_plan_execution>
TDD Execution
For type: tdd plans — RED-GREEN-REFACTOR:
- Infrastructure (first TDD plan only): detect project, install framework, config, verify empty suite
- RED: Read
<behavior>→ failing test(s) → run (MUST fail) → commit:test({phase}-{plan}): add failing test for [feature] - GREEN: Read
<implementation>→ minimal code → run (MUST pass) → commit:feat({phase}-{plan}): implement [feature] - REFACTOR: Clean up → tests MUST pass → commit:
refactor({phase}-{plan}): clean up [feature]
Errors: RED doesn't fail → investigate test/existing feature. GREEN doesn't pass → debug, iterate. REFACTOR breaks → undo.
See ~/.claude/get-shit-done/references/tdd.md for structure.
</tdd_plan_execution>
<precommit_failure_handling>
Pre-commit Hook Failure Handling
Your commits may trigger pre-commit hooks. Auto-fix hooks handle themselves transparently — files get fixed and re-staged automatically.
If running as a parallel executor agent (spawned by execute-phase):
Run commits normally — let pre-commit hooks run. Do NOT use --no-verify by default
(#2924). Hooks should run so issues surface at the introducing commit, and silent
bypass violates project CLAUDE.md guidance. If a project explicitly opts out via
workflow.worktree_skip_hooks=true, the orchestrator will surface that flag in the
prompt; absent that signal, hooks run normally. If a hook fails, follow the
sequential-mode handling below.
If running as the sole executor (sequential mode): If a commit is BLOCKED by a hook:
- The
git commitcommand fails with hook error output - Read the error — it tells you exactly which hook and what failed
- Fix the issue (type error, lint violation, secret leak, etc.)
git addthe fixed files- Retry the commit
- Budget 1-2 retry cycles per commit </precommit_failure_handling>
<task_commit>
Task Commit Protocol
Canonical per-task commit rules live in agents/gsd-executor.md (<task_commit_protocol>). Follow that section for staging, {type}({phase}-{plan}) messages, commit-to-subrepo when sub_repos is set, post-commit checks, and untracked-file handling — do not duplicate or paraphrase the full protocol here (single source of truth).
Orchestrator note: After each task, the spawned executor reports commit hashes; this workflow does not re-specify commit semantics beyond pointing at the executor.
</task_commit>
On `type="checkpoint:*"`: automate everything possible first. Checkpoints are for verification/decisions only.Display: CHECKPOINT: [Type] box → Progress {X}/{Y} → Task name → type-specific content → YOUR ACTION: [signal]
| Type | Content | Resume signal |
|---|---|---|
| human-verify (90%) | What was built + verification steps (commands/URLs) | "approved" or describe issues |
| decision (9%) | Decision needed + context + options with pros/cons | "Select: option-id" |
| human-action (1%) | What was automated + ONE manual step + verification plan | "done" |
After response: verify if specified. Pass → continue. Fail → inform, wait. WAIT for user — do NOT hallucinate completion.
See ~/.claude/get-shit-done/references/checkpoints.md for details.
When spawned via Task and hitting checkpoint: return structured state (cannot interact with user directly).Required return: 1) Completed Tasks table (hashes + files) 2) Current Task (what's blocking) 3) Checkpoint Details (user-facing content) 4) Awaiting (what's needed from user)
Orchestrator parses → presents to user → spawns fresh continuation with your completed tasks state. You will NOT be resumed. In main context: use checkpoint_protocol above.
If verification fails:Check if node repair is enabled (default: on):
NODE_REPAIR=$($GSD_SDK query config-get workflow.node_repair 2>/dev/null || echo "true")
If NODE_REPAIR is true: invoke @./.claude/get-shit-done/workflows/node-repair.md with:
- FAILED_TASK: task number, name, done-criteria
- ERROR: expected vs actual result
- PLAN_CONTEXT: adjacent task names + phase goal
- REPAIR_BUDGET:
workflow.node_repair_budgetfrom config (default: 2)
Node repair will attempt RETRY, DECOMPOSE, or PRUNE autonomously. Only reaches this gate again if repair budget is exhausted (ESCALATE).
If NODE_REPAIR is false OR repair returns ESCALATE: STOP. Present: "Verification failed for Task [X]: [name]. Expected: [criteria]. Actual: [result]. Repair attempted: [summary of what was tried]." Options: Retry | Skip (mark incomplete) | Stop (investigate). If skipped → SUMMARY "Issues Encountered".
DURATION_SEC=$(( PLAN_END_EPOCH - PLAN_START_EPOCH )) DURATION_MIN=$(( DURATION_SEC / 60 ))
if $DURATION_MIN -ge 60 ; then HRS=$(( DURATION_MIN / 60 )) MIN=$(( DURATION_MIN % 60 )) DURATION="${HRS}h ${MIN}m" else DURATION="${DURATION_MIN} min" fi
</step>
<step name="generate_user_setup">
```bash
grep -A 50 "^user_setup:" .planning/phases/XX-name/{phase}-{plan}-PLAN.md | head -50
If user_setup exists: create {phase}-USER-SETUP.md using template ~/.claude/get-shit-done/templates/user-setup.md. Per service: env vars table, account setup checklist, dashboard config, local dev notes, verification commands. Status "Incomplete". Set USER_SETUP_CREATED=true. If empty/missing: skip.
Create {phase}-{plan}-SUMMARY.md at .planning/phases/XX-name/. Use ~/.claude/get-shit-done/templates/summary.md.
Frontmatter: phase, plan, subsystem, tags | requires/provides/affects | tech-stack.added/patterns | key-files.created/modified | key-decisions | requirements-completed (MUST copy requirements array from PLAN.md frontmatter verbatim) | duration ($DURATION), completed ($PLAN_END_TIME date).
Title: # Phase [X] Plan [Y]: [Name] Summary
One-liner SUBSTANTIVE: "JWT auth with refresh rotation using jose library" not "Authentication implemented"
Include: duration, start/end times, task count, file count.
Next: more plans → "Ready for {next-plan}" | last → "Phase complete, ready for next step".
**Skip this step if running in parallel mode** (the orchestrator in execute-phase.md handles STATE.md/ROADMAP.md updates centrally after merging worktrees to avoid merge conflicts).Update STATE.md using gsd-sdk query (or legacy gsd-tools) state mutations:
# Auto-detect parallel mode: .git is a file in worktrees, a directory in main repo
IS_WORKTREE=$([ -f .git ] && echo "true" || echo "false")
# Skip in parallel mode — orchestrator handles STATE.md centrally
if [ "$IS_WORKTREE" != "true" ]; then
# Advance plan counter (handles last-plan edge case)
$GSD_SDK query state.advance-plan
# Recalculate progress bar from disk state
$GSD_SDK query state.update-progress
# Record execution metrics
$GSD_SDK query state.record-metric \
--phase "${PHASE}" --plan "${PLAN}" --duration "${DURATION}" \
--tasks "${TASK_COUNT}" --files "${FILE_COUNT}"
fi
# Add each decision from SUMMARY key-decisions
# Prefer file inputs for shell-safe text (preserves `$`, `*`, etc. exactly)
$GSD_SDK query state.add-decision \
--phase "${PHASE}" --summary-file "${DECISION_TEXT_FILE}" --rationale-file "${RATIONALE_FILE}"
# Add blockers if any found
$GSD_SDK query state.add-blocker --text-file "${BLOCKER_TEXT_FILE}"
$GSD_SDK query state.record-session \
--stopped-at "Completed ${PHASE}-${PLAN}-PLAN.md" \
--resume-file "None"
Keep STATE.md under 150 lines.
If SUMMARY "Issues Encountered" ≠ "None": yolo → log and continue. Interactive → present issues, wait for acknowledgment. Run this step only when NOT executing inside a git worktree (i.e. `use_worktrees: false`, the bug #2661 reproducer). In worktree mode each worktree has its own ROADMAP.md, so per-plan writes here would diverge across siblings; the orchestrator owns the post-merge sync centrally (see execute-phase.md §5.7, single-writer contract from #1486 /dcb50396).
# Auto-detect worktree mode: .git is a file in worktrees, a directory in main repo.
# This mirrors the use_worktrees config flag for the executing handler.
IS_WORKTREE=$([ -f .git ] && echo "true" || echo "false")
if [ "$IS_WORKTREE" != "true" ]; then
# use_worktrees: false → this handler is the sole post-plan sync point (#2661)
$GSD_SDK query roadmap.update-plan-progress "${PHASE}"
fi
Counts PLAN vs SUMMARY files on disk. Updates progress table row with correct count and status (In Progress or Complete with date).
$GSD_SDK query requirements.mark-complete ${REQ_IDS}
Extract requirement IDs from the plan's frontmatter (e.g., requirements: [AUTH-01, AUTH-02]). If no requirements field, skip.
Task code already committed per-task. Commit plan metadata:
# Auto-detect parallel mode: .git is a file in worktrees, a directory in main repo
IS_WORKTREE=$([ -f .git ] && echo "true" || echo "false")
# In parallel mode: exclude STATE.md and ROADMAP.md (orchestrator commits these)
if [ "$IS_WORKTREE" = "true" ]; then
$GSD_SDK query commit "docs({phase}-{plan}): complete [plan-name] plan" --files .planning/phases/XX-name/{phase}-{plan}-SUMMARY.md .planning/REQUIREMENTS.md
else
$GSD_SDK query commit "docs({phase}-{plan}): complete [plan-name] plan" --files .planning/phases/XX-name/{phase}-{plan}-SUMMARY.md .planning/STATE.md .planning/ROADMAP.md .planning/REQUIREMENTS.md
fi
FIRST_TASK=$(git log --oneline --grep="feat({phase}-{plan}):" --grep="fix({phase}-{plan}):" --grep="test({phase}-{plan}):" --reverse | head -1 | cut -d' ' -f1)
git diff --name-only ${FIRST_TASK}^..HEAD 2>/dev/null || true
Update only structural changes: new src/ dir → STRUCTURE.md | deps → STACK.md | file pattern → CONVENTIONS.md | API client → INTEGRATIONS.md | config → STACK.md | renamed → update paths. Skip code-only/bugfix/content changes.
$GSD_SDK query commit "" --files .planning/codebase/*.md --amend
(ls -1 .planning/phases/[current-phase-dir]/*-PLAN.md 2>/dev/null || true) | wc -l
(ls -1 .planning/phases/[current-phase-dir]/*-SUMMARY.md 2>/dev/null || true) | wc -l
| Condition | Route | Action |
|---|---|---|
| summaries < plans | A: More plans | Find next PLAN without SUMMARY. Yolo: auto-continue. Interactive: show next plan, suggest /gsd:execute-phase {phase} + /gsd:verify-work. STOP here. |
| summaries = plans, current < highest phase | B: Phase done | Show completion, suggest /gsd:plan-phase {Z+1} + /gsd:verify-work {Z} + /gsd:discuss-phase {Z+1} |
| summaries = plans, current = highest phase | C: Milestone done | Show banner, suggest /gsd:complete-milestone + /gsd:verify-work + /gsd-add-phase |
All routes: /clear first for fresh context.
<success_criteria>
- All tasks from PLAN.md completed
- All verifications pass
- USER-SETUP.md generated if user_setup in frontmatter
- SUMMARY.md created with substantive content
- STATE.md updated (position, decisions, issues, session) — unless parallel mode (orchestrator handles)
- ROADMAP.md updated — unless parallel mode (orchestrator handles)
- If codebase map exists: map updated with execution changes (or skipped if no significant changes)
- If USER-SETUP.md created: prominently surfaced in completion output </success_criteria>