Orchestrator stays lean: discover plans, analyze dependencies, group into waves, spawn subagents, collect results. Each subagent loads the full execute-plan context and handles its own plan.
Context budget: ~15% orchestrator, 100% fresh per subagent. </objective>
<execution_context> @./references/ui-brand.md @./references/planning-config.md @./references/phase-execute.md </execution_context>
<context> Phase: $ARGUMENTSFlags:
--gaps-only— Execute only gap closure plans (plans withgap_closure: truein frontmatter). Use after phase-verify creates fix plans.
@.planning/ROADMAP.md @.planning/STATE.md </context>
<process>- Resolve Model Profile
Read model profile for agent spawning:
MODEL_PROFILE=$(node scripts/kata-lib.cjs read-config "model_profile" "balanced")
Default to "balanced" if not set.
0.5. Read Workflow Config
Read workflow config for executor injection:
EXEC_POST_TASK_CMD=$(node scripts/kata-lib.cjs read-pref "workflows.execute-phase.post_task_command" "")
EXEC_COMMIT_STYLE=$(node scripts/kata-lib.cjs read-pref "workflows.execute-phase.commit_style" "conventional")
EXEC_COMMIT_SCOPE_FMT=$(node scripts/kata-lib.cjs read-pref "workflows.execute-phase.commit_scope_format" "{phase}-{plan}")
Store these three variables for injection into executor prompts in the <wave_execution> Task() calls.
0.6. Read GitHub Config
GITHUB_ENABLED=$(node scripts/kata-lib.cjs read-config "github.enabled" "false")
ISSUE_MODE=$(node scripts/kata-lib.cjs read-config "github.issue_mode" "never")
Store for use in PR creation and issue checkbox updates.
0.7. Check Worktree and PR Config
Read worktree and PR workflow configuration for conditional lifecycle:
WORKTREE_ENABLED=$(node scripts/kata-lib.cjs read-config "worktree.enabled" "false")
PR_WORKFLOW=$(node scripts/kata-lib.cjs read-config "pr_workflow" "false")
Store WORKTREE_ENABLED and PR_WORKFLOW for use in steps 1.5, 4, 10, and 10.5. When WORKTREE_ENABLED=false (default), plan-level worktree operations are skipped. When PR_WORKFLOW=false, all branch/worktree/PR operations are skipped and execution proceeds on the current branch.
Model lookup table:
| Agent | quality | balanced | budget |
|---|---|---|---|
| general-purpose (executor) | opus | sonnet | sonnet |
| general-purpose (mapper) | haiku | haiku | haiku |
| kata-verifier | sonnet | sonnet | haiku |
| kata-code-reviewer | opus | sonnet | sonnet |
| kata-*-analyzer | sonnet | sonnet | haiku |
Note: Review agents (kata-code-reviewer, kata--analyzer) are spawned by the kata-review-pull-requests skill, which handles its own model selection based on the agents' frontmatter. The table above documents expected model usage for cost planning.*
Store resolved models for use in Task calls below.
-
Pre-flight: Check roadmap format (auto-migration)
If ROADMAP.md exists, check format and auto-migrate if old:
if [ -f .planning/ROADMAP.md ]; then node scripts/kata-lib.cjs check-roadmap 2>/dev/null FORMAT_EXIT=$? if [ $FORMAT_EXIT -eq 1 ]; then echo "Old roadmap format detected. Running auto-migration..." fi fiIf exit code 1 (old format):
Invoke kata-doctor in auto mode:
Skill("kata-doctor", "--auto")Continue after migration completes.
If exit code 0 or 2: Continue silently.
# Validate config and template overrides node scripts/kata-lib.cjs check-config 2>/dev/null || true node scripts/kata-lib.cjs check-template-drift 2>/dev/null || true
1.1. Validate phase exists Find phase directory using the discovery script:
bash "scripts/find-phase.sh" "$PHASE_ARG"
Outputs PHASE_DIR, PLAN_COUNT, and PHASE_STATE as key=value pairs. Exit code 1 = not found, 2 = no plans. Parse the output to set these variables for subsequent steps.
1.25. Move phase to active (state transition)
# Move from pending to active when execution begins
# PHASE_STATE is from find-phase.sh output (step 1)
if [ "$PHASE_STATE" = "pending" ]; then
DIR_NAME=$(basename "$PHASE_DIR")
mkdir -p ".planning/phases/active"
mv "$PHASE_DIR" ".planning/phases/active/${DIR_NAME}"
PHASE_DIR=".planning/phases/active/${DIR_NAME}"
echo "Phase moved to active/"
fi
1.5. Create phase branch and commit activation changes
If PR_WORKFLOW=false: Skip to step 2.
If PR_WORKFLOW=true:
Create the phase branch FIRST. Uncommitted activation changes from step 1.25 float to the new branch via git checkout -b. Then commit on the phase branch (not main — respects branch protection).
if ! BRANCH_OUTPUT=$(bash "scripts/create-phase-branch.sh" "$PHASE_DIR"); then
echo "Error: Failed to create phase branch" >&2
exit 1
fi
eval "$BRANCH_OUTPUT"
# Outputs: WORKSPACE_PATH, BRANCH, BRANCH_TYPE, MILESTONE, PHASE_NUM, SLUG
Store WORKSPACE_PATH and PHASE_BRANCH for steps 4 and 10.5.
WORKSPACE_PATH=$WORKSPACE_PATH
PHASE_BRANCH=$BRANCH
Now commit the activation changes on the phase branch. The orchestrator runs from workspace/, so plain git commands work directly. This ensures worktrees branch from a clean state and prevents merge conflicts on STATE.md.
if [ -n "$(git status --porcelain .planning/)" ]; then
git add .planning/ && git commit -m "docs(${PHASE_NUM}): activate phase"
fi
-
Discover plans
- List all *-PLAN.md files in phase directory
- Check which have *-SUMMARY.md (already complete)
- If
--gaps-only: filter to only plans withgap_closure: true - Build list of incomplete plans
-
Group by wave
- Read
wavefrom each plan's frontmatter - Group plans by wave number
- Read
3.5. Display execution banner
Display stage banner and wave structure:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Kata ► EXECUTING PHASE {X}: {Phase Name} ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
{N} plans, {M} waves:
| Wave | Plans | Description |
|---|---|---|
| 1 | 01, 02 | {plan names from frontmatter} |
| 2 | 03 | {plan name} |
Model profile: {profile} (executor → {model}) {If WORKTREE_ENABLED=true: Worktree isolation: enabled (each plan gets isolated worktree)}
-
Execute waves For each wave in order:
-
Create plan worktrees (if enabled): If
WORKTREE_ENABLED=trueandPR_WORKFLOW=true, create a worktree for each plan in the wave, forking from the phase branch:if [ "$WORKTREE_ENABLED" = "true" ] && [ "$PR_WORKFLOW" = "true" ]; then for plan_num in $WAVE_PLAN_NUMBERS; do WT_OUTPUT=$(bash "scripts/manage-worktree.sh" create "$PHASE_NUM" "$plan_num" "$PHASE_BRANCH") eval "$WT_OUTPUT" # Stores WORKTREE_PATH, WORKTREE_BRANCH, STATUS for each plan # Save per-plan: WORKTREE_PATH_${plan_num}=$WORKTREE_PATH done fi -
Spawn
general-purposeexecutor for each plan in wave (parallel Task calls) -
Wait for completion (Task blocks)
IMPORTANT: The remaining post-wave steps are SEQUENTIAL. Do not run them in parallel.
-
Merge plan worktrees (if enabled) — do this FIRST: When plan worktrees are enabled, SUMMARYs and code live in the worktree directories until merged into the phase branch. Merge BEFORE checking SUMMARYs or updating issue checkboxes.
if [ "$WORKTREE_ENABLED" = "true" ] && [ "$PR_WORKFLOW" = "true" ]; then for plan_num in $WAVE_PLAN_NUMBERS; do MERGE_OUTPUT=$(bash "scripts/manage-worktree.sh" merge "$PHASE_NUM" "$plan_num" "$PHASE_BRANCH" "$WORKSPACE_PATH") eval "$MERGE_OUTPUT" if [ "$STATUS" != "merged" ]; then echo "Warning: Worktree merge failed for plan $plan_num" >&2 fi done fiMerge happens ONCE per wave after all agents complete. This ensures all plan branches are integrated before the next wave starts.
If merge fails: Report the failure but continue. User can resolve merge conflicts manually and re-run. The worktree and branch remain for inspection.
-
Verify SUMMARYs created: After merge (or directly if worktrees disabled), verify each plan has a SUMMARY.md in the phase directory:
for plan_num in $WAVE_PLAN_NUMBERS; do if ! find "$PHASE_DIR" -maxdepth 1 -name "*-${plan_num}-SUMMARY.md" 2>/dev/null | grep -q .; then echo "Warning: No SUMMARY.md found for plan $plan_num" >&2 fi done -
Update GitHub issue checkboxes (if enabled):
Build completed plan numbers from SUMMARY.md files created this wave, then update issue checkboxes:
COMPLETED_PLANS_IN_WAVE="" for summary in $(find "${PHASE_DIR}" -maxdepth 1 -name "*-SUMMARY.md" 2>/dev/null); do plan_num=$(basename "$summary" | sed -E 's/^[0-9]+-([0-9]+)-SUMMARY\.md$/\1/') if echo "${WAVE_PLANS}" | grep -q "plan-${plan_num}"; then COMPLETED_PLANS_IN_WAVE="${COMPLETED_PLANS_IN_WAVE} ${plan_num}" fi done bash "scripts/update-issue-checkboxes.sh" "$PHASE" "$PHASE_DIR" $COMPLETED_PLANS_IN_WAVEThis update happens ONCE per wave (after all plans in wave complete), not per-plan, avoiding race conditions.
-
Open Draft PR (first wave only, pr_workflow only):
After first wave completion, commit any remaining uncommitted planning changes in workspace/:
if [ "$PR_WORKFLOW" = "true" ]; then if [ -n "$(git status --porcelain .planning/)" ]; then git add .planning/ && git commit -m "docs(${PHASE_NUM}): update planning state" fi fiThen push and create the draft PR:
if [ "$PR_WORKFLOW" = "true" ]; then # Push from workspace/ (already on the phase branch) git push -u origin "$PHASE_BRANCH" 2>/dev/null || \ git push -u --force-with-lease origin "$PHASE_BRANCH" 2>/dev/null if ! PR_OUTPUT=$(bash "scripts/create-draft-pr.sh" "$PHASE_DIR" "$PHASE_BRANCH"); then echo "Error: Failed to create draft PR" >&2 else eval "$PR_OUTPUT" # Outputs: PR_NUMBER (and possibly EXISTING_PR) fi fiStore PR_NUMBER for step 10.5.
Note: PR body checklist items remain unchecked throughout execution. The PR body is static after creation. The GitHub issue (updated after each wave above) is the source of truth for plan progress during execution.
-
- Proceed to next wave
-
Aggregate results
- Collect summaries from all plans
- Report phase completion status
-
Commit any orchestrator corrections Check for uncommitted changes before verification:
git status --porcelainIf changes exist: Orchestrator made corrections between executor completions. Commit them:
git add -u && git commit -m "fix({phase}): orchestrator corrections"If clean: Continue to test suite.
6.5. Run project test suite
Before verification, run the project's test suite to catch regressions early:
TEST_SCRIPT=$(cat package.json 2>/dev/null | grep -o '"test"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1)
If package.json has a test script:
- Run
npm test - If tests pass: proceed to step 7
- If tests fail: report test failures, still proceed to step 7
If no test script detected:
- Skip this step, proceed to step 7
Skip for gap phases: If mode is gap_closure, skip test suite
-
Verify phase goal (automated codebase check — NOT user-facing UAT)
Check config:
WORKFLOW_VERIFIER=$(node scripts/kata-lib.cjs read-config "workflow.verifier" "true")If
workflow.verifierisfalse: Skip to step 8 (treat as passed).Otherwise: Spawn a Task subagent with verifier instructions inlined. Do NOT invoke
/kata-verify-work— that is a different skill for interactive user testing.Read the verifier instructions file:
verifier_instructions_content = Read("references/verifier-instructions.md")Read intel summary for convention compliance checking:
intel_summary_content = Read(".planning/intel/summary.md") if exists, else ""Read the phase goal from ROADMAP.md and all SUMMARY.md files in the phase directory.
Spawn the verifier:
Task( prompt="<agent-instructions> {verifier_instructions_content} </agent-instructions> Verify phase goal achievement for: {PHASE_DIR} PHASE_DIR={PHASE_DIR} PHASE_NUM={PHASE_NUM} Phase goal: {goal from ROADMAP.md} Plan summaries: {summary contents from phase directory} Codebase conventions (if available): {intel_summary_content} Return your verification results as structured text. Do NOT write any files.", subagent_type="general-purpose", model="{verifier_model from model lookup table}" )Create VERIFICATION.md from the verifier's returned text. The verifier returns structured text with
VERIFICATION_FRONTMATTERandVERIFICATION_BODYsections. Parse these and write to{PHASE_DIR}/{phase_num}-VERIFICATION.md:--- {content from VERIFICATION_FRONTMATTER section} --- {content from VERIFICATION_BODY section}If the verifier's output doesn't follow the expected format, extract the status (
passed/gaps_found/human_needed), score, and any gap details from whatever text was returned, and construct the VERIFICATION.md yourself.Parse the verification status:
passed→ continue to step 8human_needed→ present items to user, get approval or feedbackgaps_found→ present gaps, offer/kata-plan-phase {X} --gaps
7.25. Update codebase index (smart scan)
If .planning/intel/index.json exists or .planning/codebase/ directory exists, run staleness detection, determine scan mode, update summary, and check conventions. All operations are non-blocking.
if [ -f ".planning/intel/index.json" ] || [ -d ".planning/codebase" ]; then
# Locate scan script
SCAN_SCRIPT=""
[ -f "scripts/scan-codebase.cjs" ] && SCAN_SCRIPT="scripts/scan-codebase.cjs"
[ -z "$SCAN_SCRIPT" ] && SCAN_SCRIPT=$(find skills/kata-map-codebase/scripts -name "scan-codebase.cjs" -type f 2>/dev/null | head -1)
# --- Staleness detection (MAINT-01) ---
STALE_SCRIPT=""
[ -f "scripts/detect-stale-intel.cjs" ] && STALE_SCRIPT="scripts/detect-stale-intel.cjs"
[ -z "$STALE_SCRIPT" ] && STALE_SCRIPT=$(find skills/kata-map-codebase/scripts -name "detect-stale-intel.cjs" -type f 2>/dev/null | head -1)
STALE_COUNT=0
STALE_PCT="0"
OLDEST_COMMIT=""
if [ -n "$STALE_SCRIPT" ]; then
STALE_JSON=$(node "$STALE_SCRIPT" 2>/dev/null || echo "{}")
STALE_COUNT=$(echo "$STALE_JSON" | grep -o '"staleCount"[[:space:]]*:[[:space:]]*[0-9]*' | grep -o '[0-9]*' || echo "0")
STALE_PCT=$(echo "$STALE_JSON" | grep -o '"stalePct"[[:space:]]*:[[:space:]]*[0-9.]*' | grep -o '[0-9.]*' || echo "0")
if [ "${STALE_COUNT:-0}" -gt 0 ] 2>/dev/null; then
OLDEST_COMMIT=$(echo "$STALE_JSON" | grep -o '"oldestStaleCommit"[[:space:]]*:[[:space:]]*"[^"]*"' | sed 's/.*"oldestStaleCommit"[[:space:]]*:[[:space:]]*"//; s/"$//')
fi
# --- Brownfield staleness fields (MAINT-02 gap closure) ---
BROWNFIELD_STALE="false"
BROWNFIELD_STALE=$(echo "$STALE_JSON" | node -e "try{const d=JSON.parse(require('fs').readFileSync('/dev/stdin','utf8'));console.log(d.brownfieldDocStale===true?'true':'false')}catch{console.log('false')}" 2>/dev/null || echo "false")
BROWNFIELD_ANALYSIS_DATE=$(echo "$STALE_JSON" | node -e "try{const d=JSON.parse(require('fs').readFileSync('/dev/stdin','utf8'));console.log(d.brownfieldAnalysisDate||'')}catch{console.log('')}" 2>/dev/null || echo "")
fi
# --- Brownfield doc auto-refresh (MAINT-02 gap closure) ---
if [ "$BROWNFIELD_STALE" = "true" ]; then
echo "Brownfield docs stale (Analysis Date: $BROWNFIELD_ANALYSIS_DATE). Triggering auto-refresh..." >&2
Read mapper instructions from the kata-map-codebase skill. Use the Read tool:
- Plugin mode:
${CLAUDE_PLUGIN_ROOT}/skills/kata-map-codebase/references/codebase-mapper-instructions.md - Skills mode:
skills/kata-map-codebase/references/codebase-mapper-instructions.md
Store the content as mapper_instructions_content.
Spawn 4 mapper agents in parallel via Task():
Task(prompt="<agent-instructions>\n{mapper_instructions_content}\n</agent-instructions>\n\nFocus area: tech\n\nMap the codebase for the tech focus area. Write STACK.md and INTEGRATIONS.md to .planning/codebase/.\n\nProject root: {project_root}", subagent_type="general-purpose", model="haiku")
Task(prompt="<agent-instructions>\n{mapper_instructions_content}\n</agent-instructions>\n\nFocus area: arch\n\nMap the codebase for the arch focus area. Write ARCHITECTURE.md and STRUCTURE.md to .planning/codebase/.\n\nProject root: {project_root}", subagent_type="general-purpose", model="haiku")
Task(prompt="<agent-instructions>\n{mapper_instructions_content}\n</agent-instructions>\n\nFocus area: quality\n\nMap the codebase for the quality focus area. Write CONVENTIONS.md and TESTING.md to .planning/codebase/.\n\nProject root: {project_root}", subagent_type="general-purpose", model="haiku")
Task(prompt="<agent-instructions>\n{mapper_instructions_content}\n</agent-instructions>\n\nFocus area: concerns\n\nMap the codebase for the concerns focus area. Write CONCERNS.md to .planning/codebase/.\n\nProject root: {project_root}", subagent_type="general-purpose", model="haiku")
All 4 run in parallel. Task tool blocks until complete.
After mapper agents complete, run intel pipeline:
# Run generate-intel.js (doc-derived summary)
GENERATE_SCRIPT=""
[ -f "scripts/generate-intel.js" ] && GENERATE_SCRIPT="scripts/generate-intel.js"
[ -z "$GENERATE_SCRIPT" ] && GENERATE_SCRIPT=$(find skills/kata-map-codebase/scripts -name "generate-intel.js" -type f 2>/dev/null | head -1)
if [ -n "$GENERATE_SCRIPT" ]; then
node "$GENERATE_SCRIPT" 2>/dev/null || true
fi
# Run scan-codebase.cjs (full scan, overwrites code-derived artifacts)
if [ -n "$SCAN_SCRIPT" ]; then
node "$SCAN_SCRIPT" 2>/dev/null || true
fi
# Stage refreshed brownfield docs and intel artifacts
git add .planning/codebase/ .planning/intel/ 2>/dev/null || true
SCAN_RAN="true"
echo "Brownfield auto-refresh complete." >&2
fi
# --- Unified scan decision tree (greenfield / staleness / incremental) ---
TOTAL_FILES=$(node -e "try{const j=JSON.parse(require('fs').readFileSync('.planning/intel/index.json','utf8')); console.log(j.stats?.totalFiles ?? 0)}catch{console.log(0)}" 2>/dev/null || echo "0")
SCAN_RAN=${SCAN_RAN:-"false"}
if [ "$SCAN_RAN" != "true" ] && [ -n "$SCAN_SCRIPT" ]; then
if [ "$TOTAL_FILES" -eq 0 ]; then
# Greenfield first population: full scan
node "$SCAN_SCRIPT" 2>/dev/null || true
SCAN_RAN="true"
elif [ "${STALE_COUNT:-0}" -gt 0 ] 2>/dev/null && [ -n "$OLDEST_COMMIT" ]; then
# Staleness-triggered incremental re-scan (MAINT-02)
echo "Detected $STALE_COUNT stale intel entries, re-scanning from $OLDEST_COMMIT..." >&2
node "$SCAN_SCRIPT" --incremental --since "$OLDEST_COMMIT" 2>/dev/null || true
SCAN_RAN="true"
else
# Phase-start incremental scan
PHASE_START_COMMIT=$(git log --oneline --all --grep="activate phase" --grep="${PHASE_NUM}" --all-match --format="%H" | tail -1)
if [ -n "$PHASE_START_COMMIT" ]; then
node "$SCAN_SCRIPT" --incremental --since "$PHASE_START_COMMIT" 2>/dev/null || true
SCAN_RAN="true"
fi
fi
fi
# --- Summary update (only when a scan ran) ---
if [ "$SCAN_RAN" = "true" ]; then
SUMMARY_SCRIPT=""
[ -f "scripts/update-intel-summary.cjs" ] && SUMMARY_SCRIPT="scripts/update-intel-summary.cjs"
[ -z "$SUMMARY_SCRIPT" ] && SUMMARY_SCRIPT=$(find skills/kata-execute-phase/scripts -name "update-intel-summary.cjs" -type f 2>/dev/null | head -1)
if [ -n "$SUMMARY_SCRIPT" ]; then
node "$SUMMARY_SCRIPT" 2>/dev/null || true
fi
fi
# --- Doc gardening warning (only if auto-refresh did not run) ---
if [ "$BROWNFIELD_STALE" != "true" ] && [ -d ".planning/codebase/" ] && [ -n "$STALE_PCT" ]; then
STALE_HIGH=$(node -e "console.log(Number('${STALE_PCT}') > 0.3 ? 'yes' : 'no')" 2>/dev/null || echo "no")
if [ "$STALE_HIGH" = "yes" ]; then
echo "Warning: >30% of intel is stale (stalePct=$STALE_PCT). Recommend running /kata-map-codebase to refresh codebase knowledge." >&2
fi
fi
# --- Convention enforcement (MAINT-03) ---
CONV_SCRIPT=""
[ -f "scripts/check-conventions.cjs" ] && CONV_SCRIPT="scripts/check-conventions.cjs"
[ -z "$CONV_SCRIPT" ] && CONV_SCRIPT=$(find skills/kata-execute-phase/scripts -name "check-conventions.cjs" -type f 2>/dev/null | head -1)
if [ -n "$CONV_SCRIPT" ]; then
PHASE_START_COMMIT=${PHASE_START_COMMIT:-$(git log --oneline --all --grep="activate phase" --grep="${PHASE_NUM}" --all-match --format="%H" | tail -1)}
if [ -n "$PHASE_START_COMMIT" ]; then
CHANGED_FILES=$(git diff --name-only "$PHASE_START_COMMIT..HEAD" 2>/dev/null | tr '\n' ' ')
if [ -n "$CHANGED_FILES" ]; then
CONV_JSON=$(node "$CONV_SCRIPT" --files $CHANGED_FILES 2>/dev/null || echo "{}")
CONV_VIOLATIONS=$(echo "$CONV_JSON" | node -e "try{const d=JSON.parse(require('fs').readFileSync('/dev/stdin','utf8'));console.log((d.violations||[]).length)}catch{console.log(0)}" 2>/dev/null || echo "0")
if [ "${CONV_VIOLATIONS:-0}" -gt 0 ] 2>/dev/null; then
echo "Convention violations detected ($CONV_VIOLATIONS):" >&2
echo "$CONV_JSON" | node -e "try{const d=JSON.parse(require('fs').readFileSync('/dev/stdin','utf8'));(d.violations||[]).forEach(v=>console.error(' - '+v.file+': '+v.export+' (found '+v.found+', expected '+v.expected+')'))}catch{}" 2>/dev/null || true
fi
fi
fi
fi
fi
Non-blocking: all scan, staleness, summary, and convention operations use || true or 2>/dev/null. Failures never block phase completion.
7.5. Validate completion and move to completed
After verification passes, validate completion artifacts before moving phase to completed:
# Validate completion artifacts
PLAN_COUNT=$(find "$PHASE_DIR" -maxdepth 1 -name "*-PLAN.md" 2>/dev/null | wc -l | tr -d ' ')
MISSING=""
if [ "$PLAN_COUNT" -eq 0 ]; then
MISSING="${MISSING}\n- No PLAN.md files found"
fi
for plan in $(find "$PHASE_DIR" -maxdepth 1 -name "*-PLAN.md" 2>/dev/null); do
plan_id=$(basename "$plan" | sed 's/-PLAN\.md$//')
[ ! -f "$PHASE_DIR/${plan_id}-SUMMARY.md" ] && MISSING="${MISSING}\n- Missing SUMMARY.md for ${plan_id}"
done
# Non-gap phases require VERIFICATION.md
IS_GAP=$(find "$PHASE_DIR" -maxdepth 1 -name "*-PLAN.md" -exec grep -l "gap_closure: true" {} + 2>/dev/null | head -1)
if [ -z "$IS_GAP" ] && ! find "$PHASE_DIR" -maxdepth 1 -name "*-VERIFICATION.md" 2>/dev/null | grep -q .; then
MISSING="${MISSING}\n- Missing VERIFICATION.md (required for non-gap phases)"
fi
if [ -z "$MISSING" ]; then
DIR_NAME=$(basename "$PHASE_DIR")
mkdir -p ".planning/phases/completed"
mv "$PHASE_DIR" ".planning/phases/completed/${DIR_NAME}"
PHASE_DIR=".planning/phases/completed/${DIR_NAME}"
echo "Phase validated and moved to completed/"
else
echo "Warning: Phase incomplete:${MISSING}"
fi
-
Update roadmap and state
ROADMAP.md — two updates:
a. Collapse phase detail section: Remove the completed phase's
#### Phase N:block (header, goal, requirements, success criteria) from the Current Milestone section. The- [x]checklist entry below already captures completion status. Only uncompleted phases keep their detail blocks.b. Update checklist entry: Change
- [ ] Phase N: Name (X/Y plans)to- [x] Phase N: Name (Y/Y plans) — completed YYYY-MM-DD. Mark each sub-item[x]too.STATE.md — Re-read
.planning/STATE.mdbefore editing (executors modify it during plan execution, so your initial read is stale). Update current position, phase status, and progress bar. -
Update requirements Mark phase requirements as Complete:
- Read ROADMAP.md, find this phase's
Requirements:line (e.g., "AUTH-01, AUTH-02") - Read REQUIREMENTS.md traceability table
- For each REQ-ID in this phase: change Status from "Pending" to "Complete"
- Write updated REQUIREMENTS.md
- Skip if: REQUIREMENTS.md doesn't exist, or phase has no Requirements line
- Read ROADMAP.md, find this phase's
-
Commit phase completion Check
COMMIT_PLANNING_DOCSfrom config.json (default: true). If false: Skip git operations for .planning/ files. If true: Bundle all phase metadata updates in one commit:DIR_NAME=$(basename "$PHASE_DIR") # Stage deletions from previous locations (safe to try both) git add ".planning/phases/pending/${DIR_NAME}" 2>/dev/null || true git add ".planning/phases/active/${DIR_NAME}" 2>/dev/null || true # Stage additions at current (completed) location git add "$PHASE_DIR" # Stage planning files git add .planning/ROADMAP.md .planning/STATE.md # Stage REQUIREMENTS.md if updated git add .planning/REQUIREMENTS.md 2>/dev/null || true # Commit git commit -m "docs(${PHASE_NUM}): complete ${PHASE_NAME} phase"
10.5. Push and ensure PR exists (pr_workflow only)
After phase completion commit, push from workspace/ and finalize the PR:
```bash
if [ "$PR_WORKFLOW" = "true" ]; then
# Commit any remaining planning changes in workspace/
if [ -n "$(git status --porcelain .planning/)" ]; then
git add .planning/
git commit -m "docs(${PHASE_NUM}): update planning state"
fi
# Push from workspace/ (already on the phase branch)
git push -u origin "$PHASE_BRANCH"
# Check if draft PR was created earlier
PR_NUMBER=$(gh pr list --head "$PHASE_BRANCH" --json number --jq '.[0].number' 2>/dev/null)
if [ -z "$PR_NUMBER" ]; then
# Draft PR creation failed earlier — create PR now
PR_OUTPUT=$(bash "scripts/create-draft-pr.sh" "$PHASE_DIR" "$PHASE_BRANCH" 2>&1) || true
PR_NUMBER=$(gh pr list --head "$PHASE_BRANCH" --json number --jq '.[0].number' 2>/dev/null)
fi
# Mark PR ready for review (if it exists)
if [ -n "$PR_NUMBER" ]; then
gh pr ready "$PR_NUMBER" 2>/dev/null || true
PR_URL=$(gh pr view "$PR_NUMBER" --json url --jq '.url' 2>/dev/null)
echo "PR #${PR_NUMBER} marked ready: $PR_URL"
else
echo "Warning: Could not create or find PR for branch $PHASE_BRANCH" >&2
fi
fi
```
Store PR_NUMBER and PR_URL for offer_next output.
**Note:** Workspace cleanup happens after PR merge, not here. The workspace stays on the phase branch so the PR remains valid. Users clean up after merge via:
```bash
bash "scripts/manage-worktree.sh" cleanup-phase "$WORKSPACE_PATH" "$PHASE_BRANCH"
```
11. Offer next steps - Route to next action (see <offer_next>)
</process>
<offer_next> Output this markdown directly (not as a code block). Route based on status:
| Status | Route |
|---|---|
gaps_found | Route C (gap closure) |
human_needed | Present checklist, then re-route based on approval |
passed + more phases | Route A (next phase) |
passed + last phase | Route B (milestone complete) |
Route A: Phase verified, more phases remain
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Kata ► PHASE {Z} COMPLETE ✓ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Phase {Z}: {Name}
{Y} plans executed Goal verified ✓ {If github.enabled: GitHub Issue: #{issue_number} ({checked}/{total} plans checked off)} {If PR_WORKFLOW: PR: #{pr_number} ({pr_url}) — ready for review}
───────────────────────────────────────────────────────────────
▶ Next Up
Walk through deliverables — conversational acceptance testing
/kata-verify-work {Z}
<sub>/clear first → fresh context window</sub>
───────────────────────────────────────────────────────────────
Also available:
/kata-review-pull-requests— automated code review- {If PR_WORKFLOW and WORKTREE_ENABLED:
gh pr merge --mergethengit -C main pullandbash "scripts/manage-worktree.sh" cleanup-phase workspace $PHASE_BRANCH— merge PR (worktree-safe)} - {If PR_WORKFLOW and not WORKTREE_ENABLED:
gh pr merge --merge --delete-branchthengit checkout main && git pull— merge PR directly}
- {If PR_WORKFLOW and WORKTREE_ENABLED:
/kata-discuss-phase {Z+1}— gather context for next phase (optional)/kata-plan-phase {Z+1}— plan next phase directly
───────────────────────────────────────────────────────────────
Route B: Phase verified, milestone complete
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Kata ► MILESTONE COMPLETE 🎉 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
v1.0
{N} phases completed All phase goals verified ✓ {If PR_WORKFLOW: Phase PR: #{pr_number} ({pr_url}) — ready for review}
───────────────────────────────────────────────────────────────
▶ Next Up
Walk through deliverables — conversational acceptance testing
/kata-verify-work {Z}
<sub>/clear first → fresh context window</sub>
───────────────────────────────────────────────────────────────
Also available:
/kata-review-pull-requests— automated code review- {If PR_WORKFLOW and WORKTREE_ENABLED:
gh pr merge --mergethengit -C main pullandbash "scripts/manage-worktree.sh" cleanup-phase workspace $PHASE_BRANCH— merge PR (worktree-safe)} - {If PR_WORKFLOW and not WORKTREE_ENABLED:
gh pr merge --merge --delete-branchthengit checkout main && git pull— merge PR directly}
- {If PR_WORKFLOW and WORKTREE_ENABLED:
/kata-audit-milestone— skip UAT, audit directly/kata-complete-milestone— skip audit, archive directly
───────────────────────────────────────────────────────────────
Route C: Gaps found — need additional planning
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Kata ► PHASE {Z} GAPS FOUND ⚠ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Phase {Z}: {Name}
Score: {N}/{M} must-haves verified Report: .planning/phases/{phase_dir}/{phase}-VERIFICATION.md
What's Missing
{Extract gap summaries from VERIFICATION.md}
───────────────────────────────────────────────────────────────
▶ Next Up
Plan gap closure — create additional plans to complete the phase
/kata-plan-phase {Z} --gaps
<sub>/clear first → fresh context window</sub>
───────────────────────────────────────────────────────────────
Also available:
- cat .planning/phases/{phase_dir}/{phase}-VERIFICATION.md — see full report
- /kata-verify-work {Z} — manual testing before planning
───────────────────────────────────────────────────────────────
After user runs /kata-plan-phase {Z} --gaps:
- Planner reads VERIFICATION.md gaps
- Creates plans 04, 05, etc. to close gaps
- User runs /kata-execute-phase {Z} again
- phase-execute runs incomplete plans (04, 05...)
- Verifier runs again → loop until passed </offer_next>
<wave_execution> Parallel spawning:
Before spawning, read file contents using Read tool. The @ syntax does not work across Task() boundaries - content must be inlined in the Task prompt.
Read these files:
- Each plan file in the wave (e.g.,
{plan_01_path},{plan_02_path}, etc.) .planning/STATE.mdreferences/executor-instructions.md(relative to skill base directory) — store asexecutor_instructions_content.planning/intel/summary.md(if exists) — store asintel_summary_content
Working directory injection (two cases):
Resolve the <working_directory> block per-plan before spawning the Task() subagent. Two cases based on WORKTREE_ENABLED (set in step 0.7):
# Resolve working directory block for this plan's subagent prompt
WORKING_DIR_BLOCK=""
if [ "$PR_WORKFLOW" = "true" ] && [ "$WORKTREE_ENABLED" = "true" ]; then
# Case 1: Plan has its own worktree — use the plan-specific path
PLAN_WT_PATH="WORKTREE_PATH_${plan_num}"
WORKING_DIR_BLOCK="\n<working_directory>${!PLAN_WT_PATH}</working_directory>"
fi
# Case 2: No plan worktrees — agent works in workspace/ (or project root if no PR workflow)
# No working_directory block needed — default behavior
Then append $WORKING_DIR_BLOCK to the Task() prompt template for each plan.
# Build codebase intelligence block (empty string if no intel)
INTEL_BLOCK=""
if [ -f ".planning/intel/summary.md" ]; then
INTEL_BLOCK="\n<codebase_intelligence>\n${intel_summary_content}\n</codebase_intelligence>"
fi
Spawn all plans in a wave with a single message containing multiple Task calls, with inlined content:
Task(prompt="<agent-instructions>\n{executor_instructions_content}\n</agent-instructions>\n\nExecute plan at {plan_01_path}\n\n<plan>\n{plan_01_content}\n</plan>\n\n<project_state>\n{state_content}\n</project_state>\n\n<workflow_config>\npost_task_command: {EXEC_POST_TASK_CMD}\ncommit_style: {EXEC_COMMIT_STYLE}\ncommit_scope_format: {EXEC_COMMIT_SCOPE_FMT}\n</workflow_config>{WORKING_DIR_BLOCK}{INTEL_BLOCK}", subagent_type="general-purpose", model="{executor_model}")
Task(prompt="<agent-instructions>\n{executor_instructions_content}\n</agent-instructions>\n\nExecute plan at {plan_02_path}\n\n<plan>\n{plan_02_content}\n</plan>\n\n<project_state>\n{state_content}\n</project_state>\n\n<workflow_config>\npost_task_command: {EXEC_POST_TASK_CMD}\ncommit_style: {EXEC_COMMIT_STYLE}\ncommit_scope_format: {EXEC_COMMIT_SCOPE_FMT}\n</workflow_config>{WORKING_DIR_BLOCK}{INTEL_BLOCK}", subagent_type="general-purpose", model="{executor_model}")
Task(prompt="<agent-instructions>\n{executor_instructions_content}\n</agent-instructions>\n\nExecute plan at {plan_03_path}\n\n<plan>\n{plan_03_content}\n</plan>\n\n<project_state>\n{state_content}\n</project_state>\n\n<workflow_config>\npost_task_command: {EXEC_POST_TASK_CMD}\ncommit_style: {EXEC_COMMIT_STYLE}\ncommit_scope_format: {EXEC_COMMIT_SCOPE_FMT}\n</workflow_config>{WORKING_DIR_BLOCK}{INTEL_BLOCK}", subagent_type="general-purpose", model="{executor_model}")
All three run in parallel. Task tool blocks until all complete.
No polling. No background agents. No TaskOutput loops. </wave_execution>
<checkpoint_handling>
Plans with autonomous: false have checkpoints. The phase-execute.md workflow handles the full checkpoint flow:
- Subagent pauses at checkpoint, returns structured state
- Orchestrator presents to user, collects response
- Spawns fresh continuation agent (not resume)
See @./references/phase-execute.md step checkpoint_handling for complete details.
</checkpoint_handling>
<deviation_rules> During execution, handle discoveries automatically:
- Auto-fix bugs - Fix immediately, document in Summary
- Auto-add critical - Security/correctness gaps, add and document
- Auto-fix blockers - Can't proceed without fix, do it and document
- Ask about architectural - Major structural changes, stop and ask user
Only rule 4 requires user intervention. </deviation_rules>
<commit_rules> Per-Task Commits:
After each task completes:
- Stage only files modified by that task
- Commit with format:
{type}({phase}-{plan}): {task-name} - Types: feat, fix, test, refactor, perf, chore
- Record commit hash for SUMMARY.md
Plan Metadata Commit:
After all tasks in a plan complete:
- Stage plan artifacts only: PLAN.md, SUMMARY.md
- Commit with format:
docs({phase}-{plan}): complete [plan-name] plan - NO code files (already committed per-task)
Phase Completion Commit:
After all plans in phase complete (step 7):
- Stage: ROADMAP.md, STATE.md, REQUIREMENTS.md (if updated), VERIFICATION.md
- Commit with format:
docs({phase}): complete {phase-name} phase - Bundles all phase-level state updates in one commit
NEVER use:
git add .git add -Agit add src/or any broad directory
Always stage files individually. </commit_rules>
<success_criteria>
- All incomplete plans in phase executed
- Each plan has SUMMARY.md
- Phase goal verified (must_haves checked against codebase)
- VERIFICATION.md created in phase directory
- STATE.md reflects phase completion
- ROADMAP.md updated
- REQUIREMENTS.md updated (phase requirements marked Complete)
- GitHub issue checkboxes updated per wave (if github.enabled)
- User informed of next steps </success_criteria>