---
name: build-feature
description: Autonomous build loop for implementing products from scratch or improving existing apps. Use when launching a builder loop, managing the build lifecycle, or understanding how the autobuilder works. Triggers on "build feature", "launch builder", "start build loop", "run autobuilder", or when orchestrating the review→plan→execute cycle.
---

# Build Feature — Autonomous Build Loop

You are the **Builder Agent**: a unified product + planning + execution agent that takes a project and autonomously implements it through iterative cycles of review, planning, and execution.

## Core Concepts

| Concept | Owner | Description |
|---------|-------|-------------|
| **Project** | User | An application to build or improve. Defined with scope, constraints, and acceptance criteria. |
| **Initiative** | User / Builder | A bounded, high-level product spec. An initiative has its own `spec.md`, optional `constraints.md`, and a set of tasks. |
| **Task** | Builder | A granular, one-commit work item inside an initiative. Created, planned, and executed by the builder loop. |

The user defines the **what** (project scope + initiative specs). The builder figures out the **how** (tasks).

## Project Structure

All autobuilder data lives in `<project_dir>/.autobuilder/`:

```
<project_root>/
  .env                        # API keys and credentials (gitignored)
  AGENTS.md                   # Symlink → AGENTS.md (gitignored)
  .cursor/skills/autobuilder   # Symlink → skills/ (gitignored)
  .autobuilder/
    PRODUCT.md                # Project-level context (optional, created by create-initiative)
    backlog.md                # User feedback (consumed on read)
    active-initiative         # Currently active initiative dir name
    status.md                 # Loop status (auto-updated, gitignored)
    loop.log                  # Daemon log (gitignored)
    stop                      # Touch to halt the loop (gitignored)
    initiatives/
      0001-my-app/
        spec.md               # Initiative product spec (primary scope)
        constraints.md        # Optional per-initiative rules
        tasks/
          0001-root.md        # Root task
          0002-scaffold.md    # Sub-tasks (builder-generated)
          ...
      0002-screener-v2/
        spec.md
        tasks/
          0001-root.md
          ...
  skills/                     # Per-project skills (optional)
```

## How to Use

### 1) Create a project

Use the **create-project** skill. The user defines:
- **Goal:** What does "done" look like?
- **Target users:** Who is this for?
- **Platform:** web / mobile / desktop
- **Scope:** must-have vs nice-to-have, explicit non-goals

This produces the first initiative at `.autobuilder/initiatives/0001-<project_id>/` with its `spec.md` and root task.

### 2) Launch the builder loop

After the user agrees, start the autonomous daemon from the project root:

```bash
nohup python3 .cursor/skills/autobuilder/build-feature/builder_loop.py \
  > /dev/null 2>&1 &
```

To use Codex CLI instead of Cursor:

```bash
nohup python3 .cursor/skills/autobuilder/build-feature/builder_loop.py \
  --executor codex \
  > /dev/null 2>&1 &
```

To use the Claude Code CLI (`claude`):

```bash
nohup python3 .cursor/skills/autobuilder/build-feature/builder_loop.py \
  --executor claude \
  > /dev/null 2>&1 &
```

To use OpenCode (`opencode`):

```bash
nohup python3 .cursor/skills/autobuilder/build-feature/builder_loop.py \
  --executor opencode \
  > /dev/null 2>&1 &
```

Tell the user: "Project launched! Talk to me anytime to check status, steer direction, or stop it."

### 3) Steer the project

Use the **steer** skill. Quick summary:
- Edit initiative `spec.md` / `constraints.md` for initiative-scoped changes
- Edit `.autobuilder/PRODUCT.md` for project-wide direction changes (exists after 2nd initiative)
- Write `.autobuilder/backlog.md` for one-shot feedback (highest priority, consumed on read)
- Read `.autobuilder/status.md` for progress
- `touch .autobuilder/stop` to halt the loop
- Use the **create-initiative** skill for new initiatives

### 4) Check status

Read `<project_dir>/.autobuilder/status.md`
Or tail `<project_dir>/.autobuilder/loop.log`

### 5) Stop

```bash
touch <project_dir>/.autobuilder/stop
```

## How the Builder Loop Works

The loop is driven by `builder_loop.py` (in this skill directory). Each iteration runs the active phases as **separate, chained agent requests** — review → plan → execute — sharing memory through one chat session per iteration:

1. **Push** — push commits from previous iteration to the current branch
2. **Product Review** — review the app within the active initiative's scope, create tasks
3. **Plan Tasks** — research & plan unplanned tasks (architecture, one-week decision, splits)
4. **Execute Tasks** — implement planned tasks via TDD, commit changes

### Initiative Resolution

Each iteration resolves the **active initiative** from `.autobuilder/active-initiative`. If unset, the first available initiative (by directory number) is auto-selected. If the active initiative has no tasks yet, a root task is auto-bootstrapped from the initiative's `spec.md`.

### Phase Selection Logic

The loop determines which phases to run based on task state in the active initiative:

- **Unplanned tasks exist** → skip review, run plan + execute
- **Planned-but-unexecuted tasks exist** → skip review + plan, execute only
- **No pending tasks** → full cycle: review → plan → execute

### Review Strategy Rotation

When the review phase finds nothing to improve, subsequent reviews automatically rotate through 9 different testing angles (surface sweep, error handling, edge cases, UX flows, visual polish, performance, deep dive, fresh eyes, competitor comparison) to avoid repeating the same surface-level check. Strategy selection is journal-weighted: historically productive strategies receive higher priority.

### Skills Chain

Each phase invokes a specific skill. Skills are synced to the project's `.cursor/skills/autobuilder/` (single symlink) before each agent call:

| Phase | Skill | Purpose |
|-------|-------|---------|
| Review | `product-review` | Test the app, find issues, create task PRDs |
| Plan | `plan-task` | Research, architect, decide one-week scope, split if needed |
| Plan (gate) | `thermo-nuclear-code-quality-review` | Reject plans that move complexity, push files past 1k lines, add thin wrappers, or leave code messier (on by default; toggle via `plan_quality_review` in `.autobuilder/config.yaml`) |
| Execute | `execute-task` | Implement via strict TDD, commit per task |
| Execute (gate) | `react-doctor` | Scan for security, performance, correctness issues |

### Task Lifecycle

Tasks flow through these states via YAML frontmatter:

```
created (planned:false, executed:false)
  → planned (planned:true, executed:false)
    → executed (planned:true, executed:true) ← LOCKED, never modify
```

If a task is too large (>1 week), it gets split:
- Parent: `split:true`, `planned:true`
- Children: `planned:false`, with `parent:` and `deps:[]` set

Execution order respects dependency topology (topological sort on `deps`).

### Production Ready Handling

When the product-review phase finds nothing to improve and declares the app production-ready, the loop does NOT permanently stop. It deletes the `.autobuilder/PRODUCTION_READY.md` file and enters idle backoff, continuing to run and check for improvements periodically.

### Early-Complete Mode

When `.autobuilder/config.yaml` sets `early_complete: true`, the loop converges instead of running forever:

- **Review stance** — the review prompt restricts findings to (1) broken functionality, (2) critical UX blockers, (3) data/security hazards. Visual polish, performance tweaks, and new features are explicitly suppressed.
- **Polish-only** — `review_mode` is forced to `polish` (no feature-mode iterations).
- **Convergence** — after `early_complete_idle_threshold` consecutive idle iterations (default 1), the daemon writes `.autobuilder/COMPLETE.md` with a summary of when/why it stopped and exits cleanly with code 0.

To resume work on a converged project, delete `.autobuilder/COMPLETE.md` and re-launch. Setting `early_complete: false` returns to forever-mode.

### Crash Recovery

The loop is resilient with exponential backoff:

- **Consecutive crashes** (up to 10): backoff 30s → 600s cap
- **Agent failures** (up to 5): backoff 60s → 1800s cap
- **Idle cycles** (no improvements): backoff 120s → 1800s cap, with strategy rotation
- **Process restarts** (up to 50): for fatal unrecoverable errors

### Per-Phase Executors and Models

Each phase (review / plan / execute) can use its own `executor` and `model` via `phase_executors` in `.autobuilder/config.yaml`:

```yaml
phase_executors:
  - phase: review
    executor: claude
    model: sonnet
  - phase: execute
    executor: cursor
    model: claude-opus-4-7-thinking-xhigh
```

Phases not listed inherit the daemon's `--executor` / `--model`. A typical use is a "two-tier" setup: a small/cheap model for review (mostly observation), a strong model for execution (heavy code generation) — often a 50–70% cost reduction with negligible review-quality loss.

When the executor differs between consecutive phases, the chat session is restarted for the new executor and the iteration header is re-sent. On-disk state (tasks, memory-index, status, journal) carries context across the switch — chat memory does not. This is fine in practice: the agent re-reads the source-of-truth files each phase anyway.

The daemon validates the executor/model configuration at startup — both the daemon defaults (`--executor` / `--model`) and every per-phase override. Validation checks:

1. Executor name is one of `cursor` / `codex` / `claude` / `opencode`.
2. The executor's CLI binary is on `$PATH` (or the matching `$CURSOR_CMD` / `$CODEX_CMD` / `$CLAUDE_CMD` / `$OPENCODE_CMD` env var points at an absolute binary).
3. **Model**: for `cursor`, the validator runs `cursor agent --list-models` and rejects any model that isn't in the live list (with near-match suggestions on miss). For `opencode`, the validator runs `opencode models` and applies the same check (models are in `provider/model` form, e.g. `anthropic/claude-sonnet-4-5-20250929`). `claude` and `codex` don't expose a model-list command, so the model is passed through and the executor itself rejects it at first invocation.

Any failure prints every detected issue at once and exits with code 2 *before* killing previous daemons or writing pid files, so a typo never disrupts a running loop. Set `$AUTOBUILDER_SKIP_MODEL_QUERY=1` to skip the cursor list query (useful for offline/CI runs).

### Per-Task Fanout (opt-in)

By default the **plan** and **execute** phases bundle every pending task into **one agent call per phase** (`plan_batch_size: null`, `execute_batch_size: null`). Set them to `1` for one-call-per-task, or to a positive integer to bundle up to N tasks per call.

When fanned out, sub-calls inside the phase share one chat session and chain via `--resume`. The status line shows progress as `running execute (2/4: 0007-foo)`. Per-call exit codes are recorded in the journal as `phase_rcs["execute:2/4"]`. Review is always one call regardless — there's only one review per iteration.

Tune it in `.autobuilder/config.yaml`:

```yaml
plan_batch_size: null    # default: every pending task in one prompt
execute_batch_size: null
# plan_batch_size: 1     # one task per prompt — strongest checkpoints
# execute_batch_size: 3  # up to 3 tasks per prompt
```

### Cost Mechanics (per-token billing)

The autobuilder runs phases as resumed agent calls. Every resumed call replays the **entire chat history** (system prompt + prior user/assistant turns + tool outputs) as input tokens. This makes phasing cheap when each chained call is short, and expensive when many short calls each replay a large prior context.

Concrete impact for a five-task iteration on a typical project (~1.2K-token header):

| Mode | Calls | Approx input tokens (no caching) | With Anthropic-style caching |
|---|---|---|---|
| Combined (legacy `--combined-prompt`, removed) | 1 | ~3K | ~3K |
| Phased + `batch_size: null` (default) | 3 | ~7.5K | ~3.5K |
| Phased + `batch_size: 1` (per-task) | ~11 | ~100K+ | ~15–25K |

Output token cost is roughly the same across modes. Practical guidance:

- **Default (`batch_size: null`)** — cheapest; the iteration header is replayed at most twice (once per phase boundary).
- **Per-task (`batch_size: 1`)** — only enable when mid-batch crashes are catastrophic (long unattended overnight runs). Expect 5–15× input-token amplification.
- **Two-tier executor pattern** — review uses a small/cheap model (e.g. sonnet, ~⅕ Opus pricing). Review is the largest, most context-heavy phase; routing it through a cheaper model is the highest-leverage cost optimisation.
- **Header size** — kept minimal: spec, constraints, and PRODUCT.md are referenced by file path rather than inlined. The agent reads them via the `Read` tool when needed. Inlining only happens when those files don't exist (legacy projects).

### Prompt Construction

The loop opens a chat session for each contiguous run of phases that share the same executor, and sends each phase in that group as a resumed request inside the same chat:

- **cursor** — `cursor-agent create-chat` returns a UUID; later calls use `cursor-agent --resume <chatId>`.
- **codex** — first call is plain `codex exec`; the session UUID is scraped from the streamed banner and reused with `codex exec resume <SESSION_ID>`.
- **claude** — the loop generates a UUID locally and passes it to the first call as `claude --session-id <uuid>`; later calls reuse it via `claude --resume <uuid>`.
- **opencode** — first call is `opencode run --format json --dangerously-skip-permissions`; the typed session id (e.g. `ses_65b3acf58ffeLSa4dfj1RVoPpW`) is scraped from the JSON event stream and reused with `opencode run --session <ses_…>`. JSON streaming is required so the id is captured even when the call ends abruptly.

When the executor changes between phases, the loop opens a fresh session for the new executor and re-sends the iteration header.

The agent therefore keeps full memory of what review found and what planning produced when execution begins.

The **first** phase prompt contains:
1. Header (iteration number, phased autonomous mode)
2. Project info (IDs, active initiative, tasks directory)
3. Initiative map (all initiatives with status)
4. Backlog (consumed once per iteration)
5. Reference material (initiative spec, constraints, PRODUCT.md, executed task summary, credentials, recent review history)
6. The phase's STEP block (review / plan / execute)
7. Critical rules (locked tasks, no git push, UI quality)

**Subsequent** phase prompts inside the same chat just include:
1. A compact reminder line (project id, initiative, tasks dir, next task number, phase name)
2. The phase's STEP block
3. Critical rules

Per-phase `augment-review`, `augment-plan`, and `augment-execute` hook output is injected into the matching phase prompt only.

Per-phase exit codes are captured in the journal under `phase_rcs`. A non-zero phase rc stops further phases for that iteration. Each phase has its own hard timeout (`PHASE_HARD_TIMEOUT`, 90 min) — the watchdog kills hung phases independently.

## Managing Skills

**Builder skills** live in `skills/` at the repo root:
- `build-feature` — This skill (orchestrator + loop + templates)
- `product-review` — How to review apps and create task PRDs
- `plan-task` — How to research, architect, and split tasks
- `thermo-nuclear-code-quality-review` — Plan-phase quality gate (delete-don't-move, 1k-line cap, no thin wrappers, net-cleanliness)
- `execute-task` — How to implement via TDD
- `create-project` — How to create new projects from scratch
- `create-initiative` — How to add follow-up initiatives and manage PRODUCT.md
- `steer` — How to modify initiative scope, constraints, and feedback
- `react-doctor` — Code quality scanning for React projects

**Global skills** live in `skills/` at the repo root. Synced to ALL projects.

**Per-project skills** live in `<project_dir>/skills/<skill-name>/SKILL.md`.

## Running Multiple Projects

Each project runs its own daemon instance. Everything is namespaced by `<project_id>`.

## Safety

- Don't exfiltrate private data.
- Don't run destructive commands without asking.
- `trash` > `rm`
- When in doubt, ask.
