Files
sp80/.opencode/get-shit-done/workflows/execute-phase.md
2026-03-13 15:46:10 +08:00

17 KiB

Execute all plans in a phase using wave-based parallel execution. Orchestrator stays lean — delegates plan execution to subagents.

<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 "./.opencode/get-shit-done/bin/gsd-tools.cjs" init execute-phase "${PHASE_ARG}")
if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi

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, phase_req_ids.

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.

Sync chain flag with intent — if user invoked manually (no --auto), clear the ephemeral chain flag from any previous interrupted --auto chain. This does NOT touch workflow.auto_advance (the user's persistent settings preference). Must happen before any config reads (checkpoint handling also reads auto-advance flags):

if [[ ! "$ARGUMENTS" =~ --auto ]]; then
  node "./.opencode/get-shit-done/bin/gsd-tools.cjs" config-set workflow._auto_chain_active false 2>/dev/null
fi
Check `branching_strategy` from init:

"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 "./.opencode/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 | ... |
Execute each wave in sequence. Within a wave: parallel if `PARALLELIZATION=true`, sequential if `false`.

For each wave:

  1. 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."
  2. 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>
        @./.opencode/get-shit-done/workflows/execute-plan.md
        @./.opencode/get-shit-done/templates/summary.md
        @./.opencode/get-shit-done/references/checkpoints.md
        @./.opencode/get-shit-done/references/tdd.md
        </execution_context>
    
        <files_to_read>
        read these files at execution start using the read tool:
        - {phase_dir}/{plan_file} (Plan)
        - .planning/STATE.md (State)
        - .planning/config.json (Config, if exists)
        - ./AGENTS.md (Project instructions, if exists — follow project-specific guidelines and coding conventions)
        - .OpenCode/skills/ or .agents/skills/ (Project skills, if either 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>
      "
    )
    
  3. Wait for all agents in wave to complete.

  4. Report completion — spot-check claims first:

    For each SUMMARY.md:

    • Verify first 2 files from key-files.created exist on disk
    • Check git log --oneline --all --grep="{phase}-{plan}" returns ≥1 commit
    • Check for ## Self-Check: FAILED marker

    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."
  5. Handle failures:

    Known OpenCode bug (classifyHandoffIfNeeded): If an agent reports "failed" with error containing classifyHandoffIfNeeded is not defined, this is a OpenCode 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.

  6. Execute checkpoint plans between waves — see <checkpoint_handling>.

  7. Proceed to next wave.

Plans with `autonomous: false` require user interaction.

Auto-mode checkpoint handling:

read auto-advance config (chain flag + user preference):

AUTO_CHAIN=$(node "./.opencode/get-shit-done/bin/gsd-tools.cjs" config-get workflow._auto_chain_active 2>/dev/null || echo "false")
AUTO_CFG=$(node "./.opencode/get-shit-done/bin/gsd-tools.cjs" config-get workflow.auto_advance 2>/dev/null || echo "false")

When executor returns a checkpoint AND (AUTO_CHAIN is "true" OR 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):

  1. Spawn agent for checkpoint plan
  2. Agent runs until checkpoint task or auth gate → returns structured state
  3. Agent return includes: completed tasks table, current task + blocker, checkpoint type/details, what's awaited
  4. 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]
    
  5. User responds: "approved"/"done" | issue description | decision selection
  6. 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
  7. Continuation agent verifies previous commits, continues from resume point
  8. 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"]
**For decimal/polish phases only (X.Y pattern):** Close the feedback loop by resolving parent UAT and debug artifacts.

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 "./.opencode/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: diagnosedstatus: 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 "./.opencode/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
Verify phase achieved its GOAL, not just completed tasks.
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`

*`/new` first → fresh context window*

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.

**Mark phase complete and update all tracking files:**
COMPLETION=$(node "./.opencode/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 "./.opencode/get-shit-done/bin/gsd-tools.cjs" commit "docs(phase-{X}): complete phase execution" --files .planning/ROADMAP.md .planning/STATE.md .planning/REQUIREMENTS.md {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.

No-transition check (spawned by auto-advance chain):

Parse --no-transition flag from $ARGUMENTS.

If --no-transition flag present:

Execute-phase was spawned by plan-phase's auto-advance. Do NOT run transition.md. After verification passes and roadmap is updated, return completion status to parent:

## PHASE COMPLETE

Phase: ${PHASE_NUMBER} - ${PHASE_NAME}
Plans: ${completed_count}/${total_count}
Verification: {Passed | Gaps Found}

[Include aggregate_results output]

STOP. Do not proceed to auto-advance or transition.

If --no-transition flag is NOT present:

Auto-advance detection:

  1. Parse --auto flag from $ARGUMENTS
  2. read both the chain flag and user preference (chain flag already synced in init step):
    AUTO_CHAIN=$(node "./.opencode/get-shit-done/bin/gsd-tools.cjs" config-get workflow._auto_chain_active 2>/dev/null || echo "false")
    AUTO_CFG=$(node "./.opencode/get-shit-done/bin/gsd-tools.cjs" config-get workflow.auto_advance 2>/dev/null || echo "false")
    

If --auto flag present OR AUTO_CHAIN is true 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 ./.opencode/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 → OpenCode 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>
Re-run `/gsd-execute-phase {phase}` → discover_plans finds completed SUMMARYs → skips them → resumes from first incomplete plan → continues wave execution.

STATE.md tracks: last completed plan, current wave, pending checkpoints.