<purpose>

Drive milestone phases autonomously — all remaining phases, a range via `--from N`/`--to N`, or a single phase via `--only N`. For each incomplete phase: discuss → plan → execute using Skill() flat invocations. Pauses only for explicit user decisions (grey area acceptance, blockers, validation requests). Re-reads ROADMAP.md after each phase to catch dynamically inserted phases.

</purpose>

<critical_rules priority="absolute">

These rules apply throughout autonomous execution. Violations broke the
interpos audit (issue #221) — DO NOT regress.

1. **NEVER modify `.rcode/config.yaml`.** Specifically: never write
   `mode: yolo`, never call `rcode-tools config-set mode`, never `sed`
   the file. The user's mode preference is sacred. Autonomous behavior
   is governed by the workflow's own internal flags + the `--auto`
   invocation flag, NOT by mutating persistent config.

2. **NEVER skip the methodology chain on greenfield projects.** Before
   the phase loop runs, the prerequisite check (next step) MUST verify:
   - `.planning/prd.md` exists (else halt → /rcode-create-prd)
   - ROADMAP.md has milestone structure (else halt → /rcode-new-milestone)
   - `.planning/epics.md` exists (else halt → /rcode-create-epics-and-stories)
   See issue #219 + #229.

3. **NEVER write SPRINT.md directly.** Sprint creation MUST go through
   the `rcode-sprint-planning` skill so the capacity gate (#127) fires.
   If autonomous needs a sprint, invoke the skill — don't shortcut.

4. **ALWAYS call `state sync --from-disk` after writing any
   .planning/ artifact.** Otherwise state.json drifts and downstream
   workflows lie. See `_shared/state-sync-rule.md` (#198).

5. **ALWAYS record decisions via `rcode-tools state add-decision`.**
   Never write decision prose to STATE.md. See #224.

</critical_rules>

<required_reading>

@.rcode/references/output-format.md
@.rcode/references/workstream-flag.md
@.rcode/references/output-realism.md
@rcode/brain/best-practices/no-autonomous-bypass.md
@rcode/brain/best-practices/state-sync-rule.md
@.rcode/references/karpathy-guidelines.md

Read all files referenced by the invoking prompt's execution_context before starting.

</required_reading>

<step name="prerequisite_check" priority="before-everything">

## 0. Prerequisite check (greenfield guard)

Before any phase work, verify the methodology chain has run:

```bash
HAS_PRD=$( ( ls .planning/prd.md .planning/PRD.md .planning/prds/*.md .planning/milestones/*/PRD.md 2>/dev/null | head -1 ) && echo true || echo false)
HAS_ROADMAP_MILESTONES=$(grep -qE "^## Milestone\s+M[0-9]+" .planning/ROADMAP.md 2>/dev/null && echo true || echo false)
HAS_EPICS=$( ( ls .planning/epics.md .planning/EPICS.md .planning/epics/*.md .planning/milestones/*/EPICS.md 2>/dev/null | head -1 ) && echo true || echo false)
SKIP_FLAG=$(echo "$ARGUMENTS" | grep -qE "\-\-skip-prerequisites" && echo true || echo false)
```

If `SKIP_FLAG=false` AND any prerequisite is missing, HALT with a clear message:

```
⚠ Cannot run autonomous: missing prerequisite — {what}.

The autonomous flow assumes a project that has already gone through:
  1. /rcode-create-prd               → produces .planning/prd.md
  2. /rcode-new-milestone         → produces ROADMAP.md with M1..Mn
  3. /rcode-create-epics-and-stories → produces .planning/epics.md
  4. THEN /rcode-autonomous           ← you are here

Suggested first step: /rcode-{first-missing-command}

If you genuinely want to skip these (rare — usually inverted methodology),
re-invoke with: /rcode-autonomous --skip-prerequisites
```

If `SKIP_FLAG=true`: print a warning that downstream workflows may produce low-quality output without upstream artifacts, then proceed.

</step>

<step name="prepare_branch">

## 1b. Prepare Branch

Autonomous mode MUST NOT run directly on `main` or `master` without explicit opt-in.
This prevents accidental commits to the default branch during long autonomous runs.

```bash
CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "unknown")
ALLOW_MAIN=""
if echo "$ARGUMENTS" | grep -q '\-\-allow-main'; then
  ALLOW_MAIN="true"
fi
```

**If `CURRENT_BRANCH` is `main` or `master` AND `ALLOW_MAIN` is NOT set:**

Create a working branch:

```bash
BRANCH_NAME="rcode/autonomous-${milestone_version}-$(date +%Y%m%d-%H%M%S)"
git checkout -b "${BRANCH_NAME}"
```

Display:

```
🔀 Created branch: ${BRANCH_NAME}
   (autonomous mode does not run on main/master — use --allow-main to override)
```

**If `CURRENT_BRANCH` is `main` or `master` AND `ALLOW_MAIN` is set:**

Display warning:

```
⚠ Running on ${CURRENT_BRANCH} — --allow-main override active
```

Proceed without branch creation.

**If `CURRENT_BRANCH` is any other branch:** Proceed silently — user intentionally set up a working branch.

Store `CURRENT_BRANCH` for the lifecycle step — if autonomous created the branch, it will suggest a PR at completion.

</step>

<step name="initialize" priority="first">

## 1. Initialize

Parse `$ARGUMENTS` for `--from N`, `--to N`, `--only N`, and `--interactive` flags:

```bash
FROM_PHASE=""
if echo "$ARGUMENTS" | grep -qE '\-\-from\s+[0-9]'; then
  FROM_PHASE=$(echo "$ARGUMENTS" | grep -oE '\-\-from\s+[0-9]+\.?[0-9]*' | awk '{print $2}')
fi

TO_PHASE=""
if echo "$ARGUMENTS" | grep -qE '\-\-to\s+[0-9]'; then
  TO_PHASE=$(echo "$ARGUMENTS" | grep -oE '\-\-to\s+[0-9]+\.?[0-9]*' | awk '{print $2}')
fi

ONLY_PHASE=""
if echo "$ARGUMENTS" | grep -qE '\-\-only\s+[0-9]'; then
  ONLY_PHASE=$(echo "$ARGUMENTS" | grep -oE '\-\-only\s+[0-9]+\.?[0-9]*' | awk '{print $2}')
  FROM_PHASE="$ONLY_PHASE"
fi

INTERACTIVE=""
if echo "$ARGUMENTS" | grep -q '\-\-interactive'; then
  INTERACTIVE="true"
fi
```

When `--only` is set, also set `FROM_PHASE` to the same value so existing filter logic applies.

When `--interactive` is set, discuss runs inline with questions (not auto-answered), while plan and execute are dispatched as background agents. This keeps the main context lean — only discuss conversations accumulate — while preserving user input on all design decisions.

Bootstrap via rcode-tools init + state:

```bash
INIT=$(node .rcode/bin/rcode-tools.cjs init milestone-op 2>/dev/null || node .rcode/bin/rcode-tools.cjs init)
if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
STATE=$(node .rcode/bin/rcode-tools.cjs state read 2>/dev/null || echo '{}')
```

Parse JSON for: `milestone_version`, `milestone_name`, `phase_count`, `completed_phases`, `roadmap_exists`, `state_exists`, `commit_docs`, `response_language`.

**If `response_language` is set:** include `Respond in {response_language}.` in all spawned subagent prompts.

**If `roadmap_exists` is false:** Error — "No ROADMAP.md found. Run `/rcode-new-milestone` first."
**If `state_exists` is false:** Error — "No STATE.md found. Run `/rcode-new-milestone` first."

Display startup banner:

```
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 rcode ► AUTONOMOUS
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

 Milestone: {milestone_version} — {milestone_name}
 Phases: {phase_count} total, {completed_phases} complete
```

If `ONLY_PHASE` is set, display: `Single phase mode: Phase ${ONLY_PHASE}`
Else if `FROM_PHASE` is set, display: `Starting from phase ${FROM_PHASE}`
If `TO_PHASE` is set, display: `Stopping after phase ${TO_PHASE}`
If `INTERACTIVE` is set, display: `Mode: Interactive (discuss inline, plan+execute in background)`

</step>

<step name="discover_phases">

## 2. Discover Phases

Parse ROADMAP.md directly (rcode-tools does not expose `roadmap analyze`):

```bash
cat .planning/ROADMAP.md
# For per-phase detail, inspect .planning/phases/<phase_slug>/ directory for SPRINT.md, SUMMARY.md presence
```

Build an internal `phases` array with: `number`, `name`, `goal`, `disk_status` (complete if SUMMARY.md exists, partial if SPRINT.md exists without SUMMARY.md, planned if neither), `has_ui_hint`.

**Filter to incomplete phases:** Keep only phases where `disk_status !== "complete"`.

**Apply `--from N` filter:** If `FROM_PHASE` was provided, additionally filter out phases where `number < FROM_PHASE` (use numeric comparison — handles decimal phases like "5.1").

**Apply `--to N` filter:** If `TO_PHASE` was provided, additionally filter out phases where `number > TO_PHASE` (use numeric comparison). This limits execution to phases up through the target phase.

**Apply `--only N` filter:** If `ONLY_PHASE` was provided, additionally filter OUT phases where `number != ONLY_PHASE`. This means the phase list will contain exactly one phase (or zero if already complete).

**If `TO_PHASE` is set and no phases remain:**

```
All phases through ${TO_PHASE} are already completed. Nothing to do.
```

Exit cleanly.

**If `ONLY_PHASE` is set and no phases remain:**

```
Phase ${ONLY_PHASE} is already complete. Nothing to do.
```

Exit cleanly.

**Sort by `number`** in numeric ascending order.

**If no incomplete phases remain:**

```
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 rcode ► AUTONOMOUS ▸ COMPLETE 🎉
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

 All phases complete! Nothing left to do.
```

Exit cleanly.

**Display phase plan:**

```
## Phase Plan

| # | Phase | Status |
|---|-------|--------|
| 5 | Skill Scaffolding & Phase Discovery | In Progress |
| 6 | Smart Discuss | Not Started |
| 7 | Auto-Chain Refinements | Not Started |
| 8 | Lifecycle Orchestration | Not Started |
```

For each phase, extract `phase_name`, `goal`, `success_criteria` by reading its section in ROADMAP.md. Store for use in execute_phase and transition messages.

Use TaskCreate to register a task per incomplete phase.

</step>

<step name="execute_phase">

## 3. Execute Phase

**Before displaying the banner, re-derive T from disk** (compaction guard — same
logic as iterate step 4.0):

```bash
PROGRESS_REFRESH=$(node .rcode/bin/rcode-tools.cjs progress init 2>/dev/null)
```

Update `phase_count` and `completed_phases` from the refresh. This ensures
the banner always shows the correct total, even after context compaction.

For the current phase, display the progress banner:

```
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 rcode ► AUTONOMOUS ▸ Phase {N}/{T}: {Name} [████░░░░] {P}%
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
```

Where N = current phase number (from the ROADMAP, e.g., 63), T = total milestone phases (from `phase_count` parsed in initialize step, e.g., 67). **Important:** T must be `phase_count` (the total number of phases in this milestone), NOT the count of remaining/incomplete phases. P = percentage of all milestone phases completed so far — (number of phases with SUMMARY.md / T × 100). Use █ for filled and ░ for empty segments in the progress bar (8 characters wide).

**Alternative display when phase numbers exceed total** (multi-milestone projects where phases are numbered globally): If N > T, use the format `Phase {N} ({position}/{T})` where `position` is the 1-based index among incomplete phases being processed. This prevents confusing displays like "Phase 63/5".

### 3a. Smart Discuss

Check if CONTEXT.md already exists for this phase:

```bash
PHASE_SLUG="<zero-padded-phase-number>-<phase-slug>"
PHASE_DIR=".planning/phases/${PHASE_SLUG}"
HAS_CONTEXT=$([ -f "${PHASE_DIR}/${PADDED_PHASE}-CONTEXT.md" ] || [ -f "${PHASE_DIR}/CONTEXT.md" ] && echo true || echo false)
```

**If has_context is true:** Skip discuss — context already gathered. Display:

```
Phase ${PHASE_NUMBER}: Context exists — skipping discuss.
```

Proceed to 3b.

**If has_context is false:** Check if discuss is disabled via settings:

```bash
SKIP_DISCUSS=$(node .rcode/bin/rcode-tools.cjs config 2>/dev/null | grep -oE '"skip_discuss"[^,}]*' | grep -oE 'true|false' || echo "false")
```

**If SKIP_DISCUSS is `true`:** Skip discuss entirely — the ROADMAP phase description is the spec. Display:

```
Phase ${PHASE_NUMBER}: Discuss skipped (workflow.skip_discuss=true) — using ROADMAP phase goal as spec.
```

Write a minimal CONTEXT.md so downstream plan-phase has valid input. Extract `goal` and `requirements` from ROADMAP.md for this phase. Write `${PHASE_DIR}/${PADDED_PHASE}-CONTEXT.md` with:

```markdown
# Phase {PHASE_NUMBER}: {Phase Name} - Context

**Gathered:** {date}
**Status:** Ready for planning
**Mode:** Auto-generated (discuss skipped via workflow.skip_discuss)

<domain>
## Phase Boundary

{goal from ROADMAP phase description}

</domain>

<decisions>
## Implementation Decisions

### Claude's Discretion
All implementation choices are at Claude's discretion — discuss phase was skipped per user setting. Use ROADMAP phase goal, success criteria, and codebase conventions to guide decisions.

</decisions>

<canonical_refs>
## Canonical References

No external specs pre-gathered — discuss phase skipped. Planner will extract canonical refs from ROADMAP.md during research.

</canonical_refs>

<code_context>
## Existing Code Insights

Codebase context will be gathered during plan-phase research.

</code_context>

<specifics>
## Specific Ideas

No specific requirements — discuss phase skipped. Refer to ROADMAP phase description and success criteria.

</specifics>

<deferred>
## Deferred Ideas

None — discuss phase skipped.

</deferred>
```

Commit the minimal context (guarded for gitignored `.planning/`):

```bash
git add "${PHASE_DIR}/${PADDED_PHASE}-CONTEXT.md" 2>/dev/null \
  && git commit -m "docs(${PADDED_PHASE}): auto-generated context (discuss skipped)" 2>/dev/null \
  || echo "ℹ .planning/ gitignored — context written, not committed"
```

Proceed to 3b.

**If SKIP_DISCUSS is `false` (or unset):**

**IMPORTANT — Discuss must be single-pass in autonomous mode.**
The discuss step in autonomous mode MUST NOT loop. If CONTEXT.md already exists after discuss completes, do NOT re-invoke discuss for the same phase. The has_context check below is authoritative.

**If `INTERACTIVE` is set:** Run the standard discuss-phase skill inline (asks interactive questions, waits for user answers):

```
Skill(skill="rcode-discuss-phase", args="${PHASE_NUMBER}")
```

**If `INTERACTIVE` is NOT set:** Execute the smart_discuss step for this phase (batch table proposals, auto-optimized — see smart_discuss step below).

After discuss completes (either mode), verify context was written by checking for CONTEXT.md. If not present → go to handle_blocker: "Discuss for phase ${PHASE_NUMBER} did not produce CONTEXT.md."

### 3a.5. UI Design Contract (Frontend Phases)

Check if this phase has frontend indicators and whether a UI-SPEC already exists:

```bash
PHASE_SECTION=$(sed -n "/^## Phase ${PHASE_NUMBER}/,/^## Phase /p" .planning/ROADMAP.md)
echo "$PHASE_SECTION" | grep -iE "UI|interface|frontend|component|layout|page|screen|view|form|dashboard|widget" > /dev/null 2>&1
HAS_UI=$?
UI_SPEC_FILE=$(ls "${PHASE_DIR}"/*-UI-SPEC.md 2>/dev/null | head -1)
UI_PHASE_CFG=$(node .rcode/bin/rcode-tools.cjs config 2>/dev/null | grep -oE '"ui_phase"[^,}]*' | grep -oE 'true|false' || echo "true")
```

**If `HAS_UI` is 0 (frontend indicators found) AND `UI_SPEC_FILE` is empty AND `UI_PHASE_CFG` is not `false`:**

Display:

```
Phase ${PHASE_NUMBER}: Frontend phase detected — generating UI design contract...
```

```
Skill(skill="rcode-ui-phase", args="${PHASE_NUMBER}")
```

Verify UI-SPEC was created. If still empty after ui-phase, display a non-blocking warning and proceed to 3b.

**Otherwise:** Skip silently to 3b.

### 3b. Plan

**If `INTERACTIVE` is set:** Dispatch plan as a background Task agent to keep the main context lean:

```
Task(
  description="Plan phase ${PHASE_NUMBER}: ${PHASE_NAME}",
  subagent_type="rcode-planner",
  run_in_background=true,
  prompt="Run plan-phase for phase ${PHASE_NUMBER}: Skill(skill=\"rcode-plan\", args=\"${PHASE_NUMBER}\")"
)
```

Store the agent task_id. After discuss for the next phase completes (or if no next phase), wait for the plan agent to finish before proceeding to execute.

**If `INTERACTIVE` is NOT set (default):** Run plan inline as before.

```
Skill(skill="rcode-plan", args="${PHASE_NUMBER}")
```

Verify plan produced output — check `${PHASE_DIR}` for `*-PLAN.md` or `SPRINT.md`. If none → go to handle_blocker: "Plan phase ${PHASE_NUMBER} did not produce any plans."

### 3c. Execute

**If `INTERACTIVE` is set:** Wait for the plan agent to complete (if not already), verify plans exist, then dispatch execute as a background agent:

```
Task(
  description="Execute phase ${PHASE_NUMBER}: ${PHASE_NAME}",
  subagent_type="rcode-executor",
  run_in_background=true,
  prompt="Run execute-phase for phase ${PHASE_NUMBER}: Skill(skill=\"rcode-execute\", args=\"${PHASE_NUMBER} --no-transition\")"
)
```

Store the agent task_id. The workflow can now start discussing the next phase while this phase executes in the background. Before starting post-execution routing for this phase, wait for the execute agent to complete.

**If `INTERACTIVE` is NOT set (default):** Run execute inline as before.

```
Skill(skill="rcode-execute", args="${PHASE_NUMBER} --no-transition")
```

### 3c.5. Code Review and Fix

Auto-invoke code review and fix chain. Autonomous mode chains both review and fix.

**Config gate:**
```bash
CODE_REVIEW_ENABLED=$(node .rcode/bin/rcode-tools.cjs config 2>/dev/null | grep -oE '"code_review"[^,}]*' | grep -oE 'true|false' || echo "false")
```
If `"false"`: display "Code review skipped (workflow.code_review=false)" and proceed to 3d.

```
Skill(skill="rcode-review", args="${PHASE_NUMBER}")
```

Parse status from REVIEW.md frontmatter. If "clean" or "skipped": proceed to 3d. If findings found: auto-invoke:
```
Skill(skill="rcode-review-fix", args="${PHASE_NUMBER} --auto")
```

**Error handling:** If either Skill fails, catch the error, display as non-blocking, and proceed to 3d.

### 3d. Post-Execution Routing

**If `INTERACTIVE` is set:** Wait for the execute agent to complete before reading verification results.

After execute returns, read the verification result:

```bash
VERIFY_STATUS=$(grep "^status:" "${PHASE_DIR}"/*-VERIFICATION.md 2>/dev/null | head -1 | cut -d: -f2 | tr -d ' ')
```

**If VERIFY_STATUS is empty** (no VERIFICATION.md or no status field):

Go to handle_blocker: "Execute phase ${PHASE_NUMBER} did not produce verification results."

**If `passed`:**

Display:
```
Phase ${PHASE_NUMBER} ✓ ${PHASE_NAME} — Verification passed
```

Proceed to iterate step.

**If `human_needed`:**

Read the human_verification section from VERIFICATION.md to get the count and items requiring manual testing.

Display the items, then ask user via AskUserQuestion:
- **question:** "Phase ${PHASE_NUMBER} has items needing manual verification. Validate now or continue to next phase?"
- **options:** "Validate now" / "Continue without validation"

On **"Validate now"**: Present the specific items from VERIFICATION.md. After user reviews, ask:
- **question:** "Validation result?"
- **options:** "All good — continue" / "Found issues"

On "All good — continue": Display `Phase ${PHASE_NUMBER} ✓ Human validation passed` and proceed to iterate step.

On "Found issues": Go to handle_blocker with the user's reported issues as the description.

On **"Continue without validation"**: Display `Phase ${PHASE_NUMBER} ⏭ Human validation deferred` and proceed to iterate step.

**If `gaps_found`:**

Read gap summary from VERIFICATION.md (score and missing items). Display:
```
⚠ Phase ${PHASE_NUMBER}: ${PHASE_NAME} — Gaps Found
Score: {N}/{M} must-haves verified
```

**If `INTERACTIVE` is set:** Ask via AskUserQuestion:
- **question:** "Gaps found in phase ${PHASE_NUMBER}. How to proceed?"
- **options:** "Run gap closure" / "Continue without fixing" / "Stop autonomous mode"
- On "Stop": go to handle_blocker

**If `INTERACTIVE` is NOT set (default autonomous):** Auto-select "Run gap closure" — display `⚙ Phase ${PHASE_NUMBER}: auto-running gap closure` and proceed.

Execute gap closure cycle (limit: 1 attempt):

```
Skill(skill="rcode-plan", args="${PHASE_NUMBER} --gaps")
```

Verify gap plans were created. If none → go to handle_blocker: "Gap closure planning for phase ${PHASE_NUMBER} did not produce plans."

Re-execute:
```
Skill(skill="rcode-execute", args="${PHASE_NUMBER} --no-transition")
```

Re-read verification status. If `passed` or `human_needed`: route normally. If still `gaps_found` after this retry:
- **If `INTERACTIVE`:** ask "Continue anyway / Stop autonomous mode"
- **Otherwise:** display `⏭ Phase ${PHASE_NUMBER}: gaps persist after closure — continuing` and proceed to iterate step.

This limits gap closure to 1 automatic retry to prevent infinite loops.

### 3d.5. UI Review (Frontend Phases)

> Run after any successful execution routing (passed, human_needed accepted, or gaps deferred/accepted) — before proceeding to the iterate step.

```bash
UI_SPEC_FILE=$(ls "${PHASE_DIR}"/*-UI-SPEC.md 2>/dev/null | head -1)
UI_REVIEW_CFG=$(node .rcode/bin/rcode-tools.cjs config 2>/dev/null | grep -oE '"ui_review"[^,}]*' | grep -oE 'true|false' || echo "true")
```

**If `UI_SPEC_FILE` is not empty AND `UI_REVIEW_CFG` is not `false`:**

Display:

```
Phase ${PHASE_NUMBER}: Frontend phase with UI-SPEC — running UI review audit...
```

```
Skill(skill="rcode-ui-review", args="${PHASE_NUMBER}")
```

Display the review result summary (score from UI-REVIEW.md if produced). Continue to iterate step regardless of score — UI review is advisory, not blocking.

**Otherwise:** Skip silently to iterate step.

</step>

@rcode/workflows/autonomous-smart-discuss.md


<step name="iterate">

## 4. Iterate

### 4.0. Refresh Phase Count From Disk (MANDATORY — Compaction Guard)

**This step is NON-NEGOTIABLE.** LLM context compaction loses in-memory
variables. Re-derive `phase_count` and `completed_phases` from disk at the
START of every iteration — never rely on values held from the initialize step.

```bash
# Re-read the authoritative progress snapshot from the CLI
PROGRESS_REFRESH=$(node .rcode/bin/rcode-tools.cjs progress init 2>/dev/null)
```

Parse `PROGRESS_REFRESH` JSON and update:
- `phase_count` ← `PROGRESS_REFRESH.phase_count`
- `completed_phases` ← `PROGRESS_REFRESH.completed_count`
- `T` (for banner display) ← `phase_count`

If `PROGRESS_REFRESH` fails or is empty, fall back to direct ROADMAP.md parsing:

```bash
# Fallback: count phases directly from ROADMAP.md
PHASE_COUNT_DISK=$(grep -cE '^\|\s*\d{1,3}' .planning/ROADMAP.md 2>/dev/null || echo "0")
COMPLETED_DISK=$(find .planning/phases/ -name '*SUMMARY.md' 2>/dev/null | wc -l)
```

**Sanity check:** If `current_phase_number > phase_count`, this is a drift
symptom. Log a warning and re-derive from disk:

```
⚠ Phase drift detected: current phase ${N} > total ${T}. Re-reading from ROADMAP.md.
```

**If `ONLY_PHASE` is set:** Do not iterate. Proceed directly to lifecycle step (which exits cleanly per single-phase mode).

**If `TO_PHASE` is set and current phase number >= `TO_PHASE`:**

```
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 rcode ► AUTONOMOUS ▸ --to ${TO_PHASE} REACHED
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

 Completed through phase ${TO_PHASE} as requested.
 Remaining phases were not executed.

 Resume with: /rcode-autonomous --from ${next_incomplete_phase}
```

Proceed directly to lifecycle step (which handles partial completion). Exit cleanly.

**Otherwise:** After each phase completes, re-read ROADMAP.md to catch phases inserted mid-execution (decimal phases like 5.1):

```bash
cat .planning/ROADMAP.md
```

Re-filter incomplete phases using the same logic as discover_phases.

Read STATE.md fresh:

```bash
cat .planning/STATE.md
node .rcode/bin/rcode-tools.cjs state read
```

Check for blockers in the Blockers/Concerns section. If blockers are found, go to handle_blocker.

If incomplete phases remain: proceed to next phase, loop back to execute_phase.

**Token cost report and /clear offer (closes #586):**

After each phase completes, display a cost summary:

```
Phase {N} ✓ {name} — {sprint_count} sprints, {revision_count} revision(s)
```

Track `PHASES_COMPLETED` (increment after each iterate). Every 3 completed phases:

```
⚠ Context growing — {PHASES_COMPLETED} phases done in this session.
  Tip: /clear now and resume to keep remaining phases lean:
  /rcode-autonomous --from {next_phase} --to {TO_PHASE}
  Continue anyway? [Yes, keep going] / [I'll clear now — show resume command]
```

In `mode: yolo`: skip the offer and just print the resume command as an info line.

**Interactive mode overlap:** When `INTERACTIVE` is set, the iterate step enables pipeline parallelism:
1. After discuss completes for Phase N, dispatch plan+execute as background agents
2. Immediately start discuss for Phase N+1 while Phase N builds
3. Before starting plan for Phase N+1, wait for Phase N's execute agent to complete and handle its post-execution routing

This means the user is always answering discuss questions (lightweight, interactive) while the heavy work runs in the background.

If all phases complete, proceed to lifecycle step.

</step>

<step name="lifecycle">

## 5. Lifecycle

**If `ONLY_PHASE` is set:** Skip lifecycle. Display:

```
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 rcode ► AUTONOMOUS ▸ PHASE ${ONLY_PHASE} COMPLETE ✓
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

 Phase ${ONLY_PHASE}: ${PHASE_NAME} — Done
 Mode: Single phase (--only)

 Lifecycle skipped — run /rcode-autonomous without --only
 after all phases complete to trigger audit/complete/cleanup.
```

Exit cleanly.

**Otherwise:** After all phases complete, run the milestone lifecycle sequence: audit → complete → cleanup.

Display lifecycle transition banner:

```
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 rcode ► AUTONOMOUS ▸ LIFECYCLE
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

 All phases complete → Starting lifecycle: audit → complete → cleanup
 Milestone: {milestone_version} — {milestone_name}
```

### 5a. Audit

```
Skill(skill="rcode-audit-milestone")
```

After audit completes, detect the result:

```bash
AUDIT_FILE=".planning/v${milestone_version}-MILESTONE-AUDIT.md"
[ -f "$AUDIT_FILE" ] || AUDIT_FILE=".planning/MILESTONE-AUDIT.md"
AUDIT_STATUS=$(grep "^status:" "${AUDIT_FILE}" 2>/dev/null | head -1 | cut -d: -f2 | tr -d ' ')
```

**If AUDIT_STATUS is empty:** Go to handle_blocker: "Audit did not produce results — audit file missing or malformed."

**If `passed`:**

```
Audit ✓ passed — proceeding to complete milestone
```

Proceed to 5b.

**If `gaps_found`:**

Read the gaps summary from the audit file. Display:
```
⚠ Audit: Gaps Found
```

**If `INTERACTIVE`:** Ask via AskUserQuestion:
- **question:** "Milestone audit found gaps. How to proceed?"
- **options:** "Continue anyway — accept gaps" / "Stop — fix gaps manually"
- On "Stop": Go to handle_blocker.

**Otherwise (autonomous):** Display `Audit ⏭ Gaps accepted — continuing` and proceed to 5b.

**If `tech_debt`:**

Show the summary, then:

**If `INTERACTIVE`:** Ask via AskUserQuestion:
- **options:** "Continue with tech debt" / "Stop — address debt first"
- On "Stop": Go to handle_blocker.

**Otherwise (autonomous):** Display `Tech debt noted — continuing` and proceed to 5b.

### 5b. Complete Milestone

```
Skill(skill="rcode-complete-milestone", args="${milestone_version}")
```

After complete-milestone returns, verify archive output:

```bash
ls .planning/milestones/v${milestone_version}-ROADMAP.md 2>/dev/null || true
```

If the archive file does not exist, go to handle_blocker: "Complete milestone did not produce expected archive files."

### 5c. Cleanup

```
Skill(skill="rcode-cleanup")
```

Cleanup shows its own dry-run and asks user for approval internally — this is an acceptable pause since it's an explicit decision about file deletion.

### 5d. Final Completion

```
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 rcode ► AUTONOMOUS ▸ COMPLETE 🎉
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

 Milestone: {milestone_version} — {milestone_name}
 Status: Complete ✓
 Lifecycle: audit ✓ → complete ✓ → cleanup ✓

 Ship it! 🚀
```

**If autonomous created a branch** (i.e., `BRANCH_NAME` was set in the prepare_branch step):

Display:

```
🔀 Branch: ${BRANCH_NAME}
   All work is on this branch. When ready, merge to main:
     git checkout main && git merge ${BRANCH_NAME}
   Or create a PR for review.
```

</step>

<step name="handle_blocker">

## 6. Handle Blocker

When any phase operation fails or a blocker is detected, present 3 options via AskUserQuestion:

**Prompt:** "Phase {N} ({Name}) encountered an issue: {description}"

**Options:**
1. **"Fix and retry"** — Re-run the failed step (discuss, plan, or execute) for this phase
2. **"Skip this phase"** — Mark phase as skipped, continue to the next incomplete phase
3. **"Stop autonomous mode"** — Display summary of progress so far and exit cleanly

**On "Fix and retry":** Loop back to the failed step. If the same step fails again after retry, re-present these options.

**On "Skip this phase":** Log `Phase {N} ⏭ {Name} — Skipped by user`. Record in state:

```bash
node .rcode/bin/rcode-tools.cjs state add-decision "Skipped phase ${PHASE_NUMBER} in autonomous mode"
```

Proceed to iterate.

**On "Stop autonomous mode":**

```
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 rcode ► AUTONOMOUS ▸ STOPPED
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

 Completed: {list of completed phases}
 Skipped: {list of skipped phases}
 Remaining: {list of remaining phases}

 Resume with: /rcode-autonomous ${ONLY_PHASE ? "--only " + ONLY_PHASE : "--from " + next_phase}${TO_PHASE ? " --to " + TO_PHASE : ""}
```

Record blocker in state:

```bash
node .rcode/bin/rcode-tools.cjs state add-blocker "Autonomous mode stopped at phase ${PHASE_NUMBER}: ${DESCRIPTION}"
```

</step>

</process>

<success_criteria>
- [ ] All incomplete phases executed in order (smart discuss → ui-phase → plan → execute → ui-review each)
- [ ] Smart discuss proposes grey area answers in tables, user accepts or overrides per area
- [ ] Progress banners displayed between phases
- [ ] Execute invoked with --no-transition (autonomous manages transitions)
- [ ] Post-execution verification reads VERIFICATION.md and routes on status
- [ ] Passed verification → automatic continue to next phase
- [ ] Human-needed verification → user prompted to validate or skip
- [ ] Gaps-found → user offered gap closure, continue, or stop
- [ ] Gap closure limited to 1 retry (prevents infinite loops)
- [ ] Plan and execute failures route to handle_blocker
- [ ] ROADMAP.md re-read after each phase (catches inserted phases)
- [ ] STATE.md checked for blockers before each phase
- [ ] Blockers handled via user choice (retry / skip / stop)
- [ ] Final completion or stop summary displayed
- [ ] After all phases complete, lifecycle step is invoked (not manual suggestion)
- [ ] Lifecycle transition banner displayed before audit
- [ ] Audit invoked via Skill(skill="rcode-audit-milestone")
- [ ] Audit result routing: passed → auto-continue, gaps_found → user decides, tech_debt → user decides
- [ ] Complete-milestone invoked via Skill() with ${milestone_version} arg
- [ ] Cleanup invoked via Skill() — internal confirmation is acceptable
- [ ] Final completion banner displayed after lifecycle
- [ ] Progress bar uses phase number / total milestone phases, with fallback when phase numbers exceed total
- [ ] Frontend phases get UI-SPEC generated before planning (step 3a.5) if not already present
- [ ] Frontend phases get UI review audit after successful execution (step 3d.5) if UI-SPEC exists
- [ ] UI phase and UI review respect workflow.ui_phase and workflow.ui_review config toggles
- [ ] UI review is advisory (non-blocking)
- [ ] `--only N` restricts execution to exactly one phase
- [ ] `--only N` skips lifecycle step
- [ ] `--only N` exits cleanly after single phase completes
- [ ] `--only N` on already-complete phase exits with message
- [ ] `--to N` stops execution after phase N completes
- [ ] `--to N` filters out phases with number > N during discovery
- [ ] `--to N` displays "Stopping after phase N" in startup banner
- [ ] `--to N` on already completed target exits with "already completed" message
- [ ] `--to N` compatible with `--from N`
- [ ] `--to N` skips lifecycle when not all milestone phases complete
- [ ] `--interactive` runs discuss inline (asks questions, waits for user)
- [ ] `--interactive` dispatches plan and execute as background agents
- [ ] `--interactive` enables pipeline parallelism: discuss Phase N+1 while Phase N builds
- [ ] `--interactive` main context only accumulates discuss conversations
- [ ] `--interactive` waits for background agents before post-execution routing
- [ ] `--interactive` compatible with `--only`, `--from`, and `--to` flags
- [ ] No `git push` issued by the workflow (per AGENTS.md)
- [ ] Branch created when on main/master (unless --allow-main override)
- [ ] Branch name follows `rcode/autonomous-{version}-{timestamp}` pattern
- [ ] --allow-main flag skips branch creation with warning
- [ ] Non-main/master branches used as-is without branch creation
- [ ] PR/merge suggestion displayed at lifecycle completion when branch was created
- [ ] Phase count T re-derived from disk at start of every iteration (compaction guard)
- [ ] Phase count T re-derived from disk before execute_phase banner display
- [ ] Drift warning logged when current phase number exceeds total
- [ ] Progress bar always accurate after LLM context compaction
</success_criteria>

## Next Up

- `/rcode-ship` — push the branch and open a PR after autonomous run completes
- `/rcode-complete-milestone` — mark the milestone done once all phases shipped
