Subagents now discover and read .agents/skills/ directory: - Workflows: execute-phase, plan-phase, quick - Agents: gsd-executor, gsd-planner, gsd-phase-researcher, gsd-plan-checker Agents read SKILL.md (lightweight index) and load rules/*.md as needed, avoiding full AGENTS.md files (100KB+ context cost). Fixes: #672 Co-Authored-By: Claude <noreply@anthropic.com>
16 KiB
<core_principle> Orchestrator coordinates, not executes. Each subagent loads the full execute-plan context. Orchestrator: discover plans → analyze deps → group waves → spawn agents → handle checkpoints → collect results. </core_principle>
<required_reading> Read STATE.md before any operation to load project context. </required_reading>
Load all context in one call:INIT=$(node ~/.claude/get-shit-done/bin/gsd-tools.cjs init execute-phase "${PHASE_ARG}")
Parse JSON for: executor_model, verifier_model, commit_docs, parallelization, branching_strategy, branch_name, phase_found, phase_dir, phase_number, phase_name, phase_slug, plans, incomplete_plans, plan_count, incomplete_count, state_exists, roadmap_exists.
If phase_found is false: Error — phase directory not found.
If plan_count is 0: Error — no plans found in phase.
If state_exists is false but .planning/ exists: Offer reconstruct or continue.
When parallelization is false, plans within a wave execute sequentially.
"none": Skip, continue on current branch.
"phase" or "milestone": Use pre-computed branch_name from init:
git checkout -b "$BRANCH_NAME" 2>/dev/null || git checkout "$BRANCH_NAME"
All subsequent commits go to this branch. User handles merging.
From init JSON: `phase_dir`, `plan_count`, `incomplete_count`.Report: "Found {plan_count} plans in {phase_dir} ({incomplete_count} incomplete)"
Load plan inventory with wave grouping in one call:PLAN_INDEX=$(node ~/.claude/get-shit-done/bin/gsd-tools.cjs phase-plan-index "${PHASE_NUMBER}")
Parse JSON for: phase, plans[] (each with id, wave, autonomous, objective, files_modified, task_count, has_summary), waves (map of wave number → plan IDs), incomplete, has_checkpoints.
Filtering: Skip plans where has_summary: true. If --gaps-only: also skip non-gap_closure plans. If all filtered: "No matching incomplete plans" → exit.
Report:
## Execution Plan
**Phase {X}: {Name}** — {total_plans} plans across {wave_count} waves
| Wave | Plans | What it builds |
|------|-------|----------------|
| 1 | 01-01, 01-02 | {from plan objectives, 3-8 words} |
| 2 | 01-03 | ... |
For each wave:
-
Describe what's being built (BEFORE spawning):
Read each plan's
<objective>. Extract what's being built and why.--- ## Wave {N} **{Plan ID}: {Plan Name}** {2-3 sentences: what this builds, technical approach, why it matters} Spawning {count} agent(s)... ---- Bad: "Executing terrain generation plan"
- Good: "Procedural terrain generator using Perlin noise — creates height maps, biome zones, and collision meshes. Required before vehicle physics can interact with ground."
-
Spawn executor agents:
Pass paths only — executors read files themselves with their fresh 200k context. This keeps orchestrator context lean (~10-15%).
Task( subagent_type="gsd-executor", model="{executor_model}", prompt=" <objective> Execute plan {plan_number} of phase {phase_number}-{phase_name}. Commit each task atomically. Create SUMMARY.md. Update STATE.md and ROADMAP.md. </objective> <execution_context> @~/.claude/get-shit-done/workflows/execute-plan.md @~/.claude/get-shit-done/templates/summary.md @~/.claude/get-shit-done/references/checkpoints.md @~/.claude/get-shit-done/references/tdd.md </execution_context> <files_to_read> Read these files at execution start using the Read tool: - Plan: {phase_dir}/{plan_file} - State: .planning/STATE.md - Config: .planning/config.json (if exists) - Project skills: .agents/skills/ (if exists — list skills, read SKILL.md for each, follow relevant rules during implementation) </files_to_read> <success_criteria> - [ ] All tasks executed - [ ] Each task committed individually - [ ] SUMMARY.md created in plan directory - [ ] STATE.md updated with position and decisions - [ ] ROADMAP.md updated with plan progress (via `roadmap update-plan-progress`) </success_criteria> " ) -
Wait for all agents in wave to complete.
-
Report completion — spot-check claims first:
For each SUMMARY.md:
- Verify first 2 files from
key-files.createdexist on disk - Check
git log --oneline --all --grep="{phase}-{plan}"returns ≥1 commit - Check for
## Self-Check: FAILEDmarker
If ANY spot-check fails: report which plan failed, route to failure handler — ask "Retry plan?" or "Continue with remaining waves?"
If pass:
--- ## Wave {N} Complete **{Plan ID}: {Plan Name}** {What was built — from SUMMARY.md} {Notable deviations, if any} {If more waves: what this enables for next wave} ---- Bad: "Wave 2 complete. Proceeding to Wave 3."
- Good: "Terrain system complete — 3 biome types, height-based texturing, physics collision meshes. Vehicle physics (Wave 3) can now reference ground surfaces."
- Verify first 2 files from
-
Handle failures:
Known Claude Code bug (classifyHandoffIfNeeded): If an agent reports "failed" with error containing
classifyHandoffIfNeeded is not defined, this is a Claude Code runtime bug — not a GSD or agent issue. The error fires in the completion handler AFTER all tool calls finish. In this case: run the same spot-checks as step 4 (SUMMARY.md exists, git commits present, no Self-Check: FAILED). If spot-checks PASS → treat as successful. If spot-checks FAIL → treat as real failure below.For real failures: report which plan failed → ask "Continue?" or "Stop?" → if continue, dependent plans may also fail. If stop, partial completion report.
-
Execute checkpoint plans between waves — see
<checkpoint_handling>. -
Proceed to next wave.
Auto-mode checkpoint handling:
Read auto-advance config:
AUTO_CFG=$(node ~/.claude/get-shit-done/bin/gsd-tools.cjs config-get workflow.auto_advance 2>/dev/null || echo "false")
When executor returns a checkpoint AND AUTO_CFG is "true":
- human-verify → Auto-spawn continuation agent with
{user_response}="approved". Log⚡ Auto-approved checkpoint. - decision → Auto-spawn continuation agent with
{user_response}= first option from checkpoint details. Log⚡ Auto-selected: [option]. - human-action → Present to user (existing behavior below). Auth gates cannot be automated.
Standard flow (not auto-mode, or human-action type):
- Spawn agent for checkpoint plan
- Agent runs until checkpoint task or auth gate → returns structured state
- Agent return includes: completed tasks table, current task + blocker, checkpoint type/details, what's awaited
- Present to user:
## Checkpoint: [Type] **Plan:** 03-03 Dashboard Layout **Progress:** 2/3 tasks complete [Checkpoint Details from agent return] [Awaiting section from agent return] - User responds: "approved"/"done" | issue description | decision selection
- Spawn continuation agent (NOT resume) using continuation-prompt.md template:
{completed_tasks_table}: From checkpoint return{resume_task_number}+{resume_task_name}: Current task{user_response}: What user provided{resume_instructions}: Based on checkpoint type
- Continuation agent verifies previous commits, continues from resume point
- Repeat until plan completes or user stops
Why fresh agent, not resume: Resume relies on internal serialization that breaks with parallel tool calls. Fresh agents with explicit state are more reliable.
Checkpoints in parallel waves: Agent pauses and returns while other parallel agents may complete. Present checkpoint, spawn continuation, wait for all before next wave.
After all waves:## Phase {X}: {Name} Execution Complete
**Waves:** {N} | **Plans:** {M}/{total} complete
| Wave | Plans | Status |
|------|-------|--------|
| 1 | plan-01, plan-02 | ✓ Complete |
| CP | plan-03 | ✓ Verified |
| 2 | plan-04 | ✓ Complete |
### Plan Details
1. **03-01**: [one-liner from SUMMARY.md]
2. **03-02**: [one-liner from SUMMARY.md]
### Issues Encountered
[Aggregate from SUMMARYs, or "None"]
Skip if phase number has no decimal (e.g., 3, 04) — only applies to gap-closure phases like 4.1, 03.1.
1. Detect decimal phase and derive parent:
# Check if phase_number contains a decimal
if [[ "$PHASE_NUMBER" == *.* ]]; then
PARENT_PHASE="${PHASE_NUMBER%%.*}"
fi
2. Find parent UAT file:
PARENT_INFO=$(node ~/.claude/get-shit-done/bin/gsd-tools.cjs find-phase "${PARENT_PHASE}" --raw)
# Extract directory from PARENT_INFO JSON, then find UAT file in that directory
If no parent UAT found: Skip this step (gap-closure may have been triggered by VERIFICATION.md instead).
3. Update UAT gap statuses:
Read the parent UAT file's ## Gaps section. For each gap entry with status: failed:
- Update to
status: resolved
4. Update UAT frontmatter:
If all gaps now have status: resolved:
- Update frontmatter
status: diagnosed→status: resolved - Update frontmatter
updated:timestamp
5. Resolve referenced debug sessions:
For each gap that has a debug_session: field:
- Read the debug session file
- Update frontmatter
status:→resolved - Update frontmatter
updated:timestamp - Move to resolved directory:
mkdir -p .planning/debug/resolved
mv .planning/debug/{slug}.md .planning/debug/resolved/
6. Commit updated artifacts:
node ~/.claude/get-shit-done/bin/gsd-tools.cjs commit "docs(phase-${PARENT_PHASE}): resolve UAT gaps and debug sessions after ${PHASE_NUMBER} gap closure" --files .planning/phases/*${PARENT_PHASE}*/*-UAT.md .planning/debug/resolved/*.md
PHASE_REQ_IDS=$(node ~/.claude/get-shit-done/bin/gsd-tools.cjs roadmap get-phase "${PHASE_NUMBER}" | jq -r '.section' | grep -i "Requirements:" | sed 's/.*Requirements:\*\*\s*//' | sed 's/[\[\]]//g')
Task(
prompt="Verify phase {phase_number} goal achievement.
Phase directory: {phase_dir}
Phase goal: {goal from ROADMAP.md}
Phase requirement IDs: {phase_req_ids}
Check must_haves against actual codebase.
Cross-reference requirement IDs from PLAN frontmatter against REQUIREMENTS.md — every ID MUST be accounted for.
Create VERIFICATION.md.",
subagent_type="gsd-verifier",
model="{verifier_model}"
)
Read status:
grep "^status:" "$PHASE_DIR"/*-VERIFICATION.md | cut -d: -f2 | tr -d ' '
| Status | Action |
|---|---|
passed |
→ update_roadmap |
human_needed |
Present items for human testing, get approval or feedback |
gaps_found |
Present gap summary, offer /gsd:plan-phase {phase} --gaps |
If human_needed:
## ✓ Phase {X}: {Name} — Human Verification Required
All automated checks passed. {N} items need human testing:
{From VERIFICATION.md human_verification section}
"approved" → continue | Report issues → gap closure
If gaps_found:
## ⚠ Phase {X}: {Name} — Gaps Found
**Score:** {N}/{M} must-haves verified
**Report:** {phase_dir}/{phase_num}-VERIFICATION.md
### What's Missing
{Gap summaries from VERIFICATION.md}
---
## ▶ Next Up
`/gsd:plan-phase {X} --gaps`
<sub>`/clear` first → fresh context window</sub>
Also: `cat {phase_dir}/{phase_num}-VERIFICATION.md` — full report
Also: `/gsd:verify-work {X}` — manual testing first
Gap closure cycle: /gsd:plan-phase {X} --gaps reads VERIFICATION.md → creates gap plans with gap_closure: true → user runs /gsd:execute-phase {X} --gaps-only → verifier re-runs.
COMPLETION=$(node ~/.claude/get-shit-done/bin/gsd-tools.cjs phase complete "${PHASE_NUMBER}")
The CLI handles:
- Marking phase checkbox
[x]with completion date - Updating Progress table (Status → Complete, date)
- Updating plan count to final
- Advancing STATE.md to next phase
- Updating REQUIREMENTS.md traceability
Extract from result: next_phase, next_phase_name, is_last_phase.
node ~/.claude/get-shit-done/bin/gsd-tools.cjs commit "docs(phase-{X}): complete phase execution" --files .planning/ROADMAP.md .planning/STATE.md .planning/REQUIREMENTS.md .planning/phases/{phase_dir}/*-VERIFICATION.md
Exception: If gaps_found, the verify_phase_goal step already presents the gap-closure path (/gsd:plan-phase {X} --gaps). No additional routing needed — skip auto-advance.
Auto-advance detection:
- Parse
--autoflag from $ARGUMENTS - Read
workflow.auto_advancefrom config:AUTO_CFG=$(node ~/.claude/get-shit-done/bin/gsd-tools.cjs config-get workflow.auto_advance 2>/dev/null || echo "false")
If --auto flag present OR AUTO_CFG is true (AND verification passed with no gaps):
╔══════════════════════════════════════════╗
║ AUTO-ADVANCING → TRANSITION ║
║ Phase {X} verified, continuing chain ║
╚══════════════════════════════════════════╝
Execute the transition workflow inline (do NOT use Task — orchestrator context is ~10-15%, transition needs phase completion data already in context):
Read and follow ~/.claude/get-shit-done/workflows/transition.md, passing through the --auto flag so it propagates to the next phase invocation.
If neither --auto nor AUTO_CFG is true:
The workflow ends. The user runs /gsd:progress or invokes the transition workflow manually.
<context_efficiency> Orchestrator: ~10-15% context. Subagents: fresh 200k each. No polling (Task blocks). No context bleed. </context_efficiency>
<failure_handling>
- classifyHandoffIfNeeded false failure: Agent reports "failed" but error is
classifyHandoffIfNeeded is not defined→ Claude Code bug, not GSD. Spot-check (SUMMARY exists, commits present) → if pass, treat as success - Agent fails mid-plan: Missing SUMMARY.md → report, ask user how to proceed
- Dependency chain breaks: Wave 1 fails → Wave 2 dependents likely fail → user chooses attempt or skip
- All agents in wave fail: Systemic issue → stop, report for investigation
- Checkpoint unresolvable: "Skip this plan?" or "Abort phase execution?" → record partial progress in STATE.md </failure_handling>
STATE.md tracks: last completed plan, current wave, pending checkpoints.