- name
- execute-phase
- description
- Execute all plans in a phase using wave-based parallel execution. Orchestrator delegates plan execution to subagents, manages waves and checkpoints.
<purpose>
Execute all plans in a phase using wave-based parallel execution. Orchestrator stays lean by delegating plan execution to subagents.
</purpose>
<core_principle>
The orchestrator's job is coordination, not execution. Each subagent loads the full execute-plan context itself. Orchestrator discovers plans, analyzes dependencies, groups into waves, spawns agents, handles checkpoints, collects results.
</core_principle>
<required_reading>
Read STATE.md before any operation to load project context.
Read config.json for planning behavior settings.
</required_reading>
<process>
<step name="resolve_model_profile" priority="first">
Read model profile for agent spawning:
```bash
MODEL_PROFILE=$(cat .gsd/config.json 2>/dev/null | grep -o '"model_profile"[[:space:]]*:[[:space:]]*"[^"]*"' | grep -o '"[^"]*"$' | tr -d '"' || echo "balanced")
```
Default to "balanced" if not set.
**Model lookup table:**
| Agent | quality | balanced | budget |
| --------------- | ------- | -------- | ------ |
| gsd-executor | opus | sonnet | sonnet |
| gsd-verifier | sonnet | sonnet | haiku |
| general-purpose | — | — | — |
Store resolved models for use in Task calls below.
</step>
<step name="load_project_state">
Before any operation, read project state:
```bash
cat .gsd/STATE.md 2>/dev/null
```
**If file exists:** Parse and internalize:
- Current position (phase, plan, status)
- Accumulated decisions (constraints on this execution)
- Blockers/concerns (things to watch for)
**If file missing but .gsd/ exists:**
```
STATE.md missing but planning artifacts exist.
Options:
1. Reconstruct from existing artifacts
2. Continue without project state (may lose accumulated context)
```
**If .gsd/ doesn't exist:** Error - project not initialized.
**Load planning config:**
```bash
# Check if planning docs should be committed (default: true)
COMMIT_PLANNING_DOCS=$(cat .gsd/config.json 2>/dev/null | grep -o '"commit_docs"[[:space:]]*:[[:space:]]*[^,}]*' | grep -o 'true\|false' || echo "true")
# Auto-detect gitignored (overrides config)
git check-ignore -q .gsd 2>/dev/null && COMMIT_PLANNING_DOCS=false
```
Store `COMMIT_PLANNING_DOCS` for use in git operations.
**Load git branching config:**
```bash
# Get branching strategy (default: none)
BRANCHING_STRATEGY=$(cat .gsd/config.json 2>/dev/null | grep -o '"branching_strategy"[[:space:]]*:[[:space:]]*"[^"]*"' | sed 's/.*:.*"\([^"]*\)"/\1/' || echo "none")
# Get templates
PHASE_BRANCH_TEMPLATE=$(cat .gsd/config.json 2>/dev/null | grep -o '"phase_branch_template"[[:space:]]*:[[:space:]]*"[^"]*"' | sed 's/.*:.*"\([^"]*\)"/\1/' || echo "gsd/phase-{phase}-{slug}")
MILESTONE_BRANCH_TEMPLATE=$(cat .gsd/config.json 2>/dev/null | grep -o '"milestone_branch_template"[[:space:]]*:[[:space:]]*"[^"]*"' | sed 's/.*:.*"\([^"]*\)"/\1/' || echo "gsd/{milestone}-{slug}")
```
Store `BRANCHING_STRATEGY` and templates for use in branch creation step.
</step>
<step name="handle_branching">
Create or switch to appropriate branch based on branching strategy.
**Skip if strategy is "none":**
```bash
if [ "$BRANCHING_STRATEGY" = "none" ]; then
# No branching, continue on current branch
exit 0
fi
```
**For "phase" strategy — create phase branch:**
```bash
if [ "$BRANCHING_STRATEGY" = "phase" ]; then
# Get phase name from directory (e.g., "03-authentication" → "authentication")
PHASE_NAME=$(basename "$PHASE_DIR" | sed 's/^[0-9]*-//')
# Create slug from phase name
PHASE_SLUG=$(echo "$PHASE_NAME" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/--*/-/g' | sed 's/^-//;s/-$//')
# Apply template
BRANCH_NAME=$(echo "$PHASE_BRANCH_TEMPLATE" | sed "s/{phase}/$PADDED_PHASE/g" | sed "s/{slug}/$PHASE_SLUG/g")
# Create or switch to branch
git checkout -b "$BRANCH_NAME" 2>/dev/null || git checkout "$BRANCH_NAME"
echo "Branch: $BRANCH_NAME (phase branching)"
fi
```
**For "milestone" strategy — create/switch to milestone branch:**
```bash
if [ "$BRANCHING_STRATEGY" = "milestone" ]; then
# Get current milestone info from ROADMAP.md
MILESTONE_VERSION=$(grep -oE 'v[0-9]+\.[0-9]+' .gsd/ROADMAP.md | head -1 || echo "v1.0")
MILESTONE_NAME=$(grep -A1 "## .*$MILESTONE_VERSION" .gsd/ROADMAP.md | tail -1 | sed 's/.*- //' | cut -d'(' -f1 | tr -d ' ' || echo "milestone")
# Create slug
MILESTONE_SLUG=$(echo "$MILESTONE_NAME" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/--*/-/g' | sed 's/^-//;s/-$//')
# Apply template
BRANCH_NAME=$(echo "$MILESTONE_BRANCH_TEMPLATE" | sed "s/{milestone}/$MILESTONE_VERSION/g" | sed "s/{slug}/$MILESTONE_SLUG/g")
# Create or switch to branch (same branch for all phases in milestone)
git checkout -b "$BRANCH_NAME" 2>/dev/null || git checkout "$BRANCH_NAME"
echo "Branch: $BRANCH_NAME (milestone branching)"
fi
```
**Report branch status:**
```
Branching: {strategy} → {branch_name}
```
**Note:** All subsequent plan commits go to this branch. User handles merging based on their workflow.
</step>
<step name="validate_phase">
Confirm phase exists and has plans:
```bash
# Match both zero-padded (05-*) and unpadded (5-*) folders
PADDED_PHASE=$(printf "%02d" ${PHASE_ARG} 2>/dev/null || echo "${PHASE_ARG}")
PHASE_DIR=$(ls -d .gsd/phases/${PADDED_PHASE}-* .gsd/phases/${PHASE_ARG}-* 2>/dev/null | head -1)
if [ -z "$PHASE_DIR" ]; then
echo "ERROR: No phase directory matching '${PHASE_ARG}'"
exit 1
fi
PLAN_COUNT=$(ls -1 "$PHASE_DIR"/*-PLAN.md 2>/dev/null | wc -l | tr -d ' ')
if [ "$PLAN_COUNT" -eq 0 ]; then
echo "ERROR: No plans found in $PHASE_DIR"
exit 1
fi
```
Report: "Found {N} plans in {phase_dir}"
</step>
<step name="discover_plans">
List all plans and extract metadata:
```bash
# Get all plans
ls -1 "$PHASE_DIR"/*-PLAN.md 2>/dev/null | sort
# Get completed plans (have SUMMARY.md)
ls -1 "$PHASE_DIR"/*-SUMMARY.md 2>/dev/null | sort
```
For each plan, read frontmatter to extract:
- `wave: N` - Execution wave (pre-computed)
- `autonomous: true/false` - Whether plan has checkpoints
- `gap_closure: true/false` - Whether plan closes gaps from verification/UAT
Build plan inventory:
- Plan path
- Plan ID (e.g., "03-01")
- Wave number
- Autonomous flag
- Gap closure flag
- Completion status (SUMMARY exists = complete)
**Filtering:**
- Skip completed plans (have SUMMARY.md)
- If `--gaps-only` flag: also skip plans where `gap_closure` is not `true`
If all plans filtered out, report "No matching incomplete plans" and exit.
</step>
<step name="group_by_wave">
Read `wave` from each plan's frontmatter and group by wave number:
```bash
# For each plan, extract wave from frontmatter
for plan in $PHASE_DIR/*-PLAN.md; do
wave=$(grep "^wave:" "$plan" | cut -d: -f2 | tr -d ' ')
autonomous=$(grep "^autonomous:" "$plan" | cut -d: -f2 | tr -d ' ')
echo "$plan:$wave:$autonomous"
done
```
**Group plans:**
```
waves = {
1: [plan-01, plan-02],
2: [plan-03, plan-04],
3: [plan-05]
}
```
**No dependency analysis needed.** Wave numbers are pre-computed during `/plan-phase.md`.
Report wave structure with context:
```
## 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} |
| 2 | 01-03 | {from plan objectives} |
| 3 | 01-04 [checkpoint] | {from plan objectives} |
```
The "What it builds" column comes from skimming plan names/objectives. Keep it brief (3-8 words).
</step>
<step name="execute_waves">
Execute each wave in sequence. Autonomous plans within a wave run in parallel.
**For each wave:**
1. **Describe what's being built (BEFORE spawning):**
Read each plan's `<objective>` section. Extract what's being built and why it matters.
**Output:**
```
---
## Wave {N}
**{Plan ID}: {Plan Name}**
{2-3 sentences: what this builds, key technical approach, why it matters in context}
**{Plan ID}: {Plan Name}** (if parallel)
{same format}
Spawning {count} agent(s)...
---
```
**Examples:**
- 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. **Read files and spawn all autonomous agents in wave simultaneously:**
Before spawning, read file contents. The `@` syntax does not work across Task() boundaries - content must be inlined.
```bash
# Read each plan in the wave
PLAN_CONTENT=$(cat "{plan_path}")
STATE_CONTENT=$(cat .gsd/STATE.md)
CONFIG_CONTENT=$(cat .gsd/config.json 2>/dev/null)
```
Use Task tool with multiple parallel calls. Each agent gets prompt with inlined content:
```
<objective>
Execute plan {plan_number} of phase {phase_number}-{phase_name}.
Commit each task atomically. Create SUMMARY.md. Update STATE.md.
</objective>
<execution_context>
../execute-plan/SKILL.md
@.gsd/templates/summary.md
../../instructions/checkpoints.instructions.md
Ver no GitHub