# Architecture

The autobuilder is a Python daemon that orchestrates AI agents in an iterative loop to build and improve software applications autonomously.

## System Overview

```
┌─────────────────────────────────────────────────────┐
│                  builder_loop.py                     │
│              (daemon entry point)                    │
│                                                      │
│  ┌─── arg parsing ──── config resolution ───┐       │
│  │  CLI flags → config.json → .env fallback │       │
│  └──────────────┬───────────────────────────┘       │
│                 ▼                                    │
│  ┌──────────────────────────────────────────┐       │
│  │           Iteration Loop                  │       │
│  │  ┌──────┐  ┌──────┐  ┌─────────┐        │       │
│  │  │Review│→ │ Plan │→ │ Execute │→ push   │       │
│  │  └──────┘  └──────┘  └─────────┘        │       │
│  │       ↕         ↕          ↕             │       │
│  │    hooks     hooks      hooks            │       │
│  └──────────────────────────────────────────┘       │
└─────────────────────────────────────────────────────┘
         │                        │
         ▼                        ▼
   ┌───────────┐          ┌──────────────┐
   │  AI Agent │          │  Project Dir │
   │ (Cursor/  │          │ .autobuilder/│
   │  Codex)   │          │  initiatives/│
   └───────────┘          │  tasks/      │
                          └──────────────┘
```

## Module Dependency Graph

```
builder_loop.py  (entry point, CLI, main loop)
├── iteration.py (single iteration orchestration)
│   ├── prompt.py    (prompt construction, strategy selection, memory index)
│   │   ├── common.py   (constants, strategies, logging)
│   │   ├── tasks.py     (task CRUD, topology, area grouping)
│   │   └── status.py    (journal, PID, stop signal)
│   ├── project.py   (config, skills sync, gitignore, credentials)
│   ├── process.py   (agent subprocess management, browser cleanup)
│   ├── hooks.py     (optional hook execution)
│   ├── git_ops.py   (git push, branch detection)
│   └── initiative.py (initiative resolution, spec/constraints loading)
├── config.py    (config.json project registry)
└── frontmatter.py (YAML frontmatter parsing for task files)
```

All modules are **stdlib-only Python** (no pip dependencies). The daemon is a single long-running process — no web server, no database, no message queue.

**Shared executor registry.** The per-CLI knowledge (binary, env override, default model, command shape, session handling, model listing for cursor/codex/claude/opencode) lives in `hook-helpers/autobuilder_hook_helpers/executors.py`. The daemon adds `hook-helpers/` to its `sys.path` (in `common.py`) and imports it as `autobuilder_hook_helpers.executors`; project-side hook scripts get the same path via `hooks.build_hook_env`. One file, two consumers — adding a new executor is a single registry entry, no edits in either codebase.

## Key Design Decisions

### Single Agent Per Iteration

Each iteration invokes exactly one AI agent call that covers all phases (review → plan → execute). This is intentional: it gives the agent full context of the entire cycle and avoids coordination overhead between separate agent calls.

### Phase Selection is Automatic

The daemon decides which phases to run based on the current task state:

| State | Phases |
|---|---|
| No pending tasks | review → plan → execute |
| Unplanned tasks exist | plan → execute |
| Planned-but-unexecuted exist | execute only |

### Skills as Symlinks

Agent skills are stored in `skills/` and symlinked into each project's `.cursor/skills/autobuilder/`. This means all projects share the same skill definitions, and updating a skill immediately affects all projects.

### Journal-Driven Strategy Selection

The iteration journal (`journal.jsonl`) records every iteration's outcome. The strategy selection algorithm uses this data to weight strategies: productive strategies get higher probability, unused strategies get a recency bonus. This creates a self-optimizing review system.

### Config is Hot-Reloadable

`.autobuilder/config.yaml` is read every iteration, not just at startup. This means you can change review strategies, task limits, or polish/feature weight while the daemon is running — changes take effect on the next iteration.

## Data Flow

### Per-Iteration Data Flow

```
1. Load project config (config.yaml)
2. Determine phases from task state
3. Select review mode (polish/feature) using config weight
4. Select review strategy (journal-weighted random from config pool)
5. Compute effective max_tasks (mode default → strategy override)
6. Run hooks (pre-iteration, augment-*)
7. Build prompt (project info + backlog + execution steps + reference material)
8. Invoke AI agent (cursor/codex CLI)
9. Parse agent output (detect created/executed tasks)
10. Run hooks (post-agent, pre-push, post-push)
11. Record to journal
12. Update memory index
```

### Prompt Structure

The prompt is organized for optimal agent comprehension:

```
1. HEADER (role, project context)
2. BACKLOG (user feedback — highest priority)
3. EXECUTION PLAN
   - Step 1: Review (with browser/screenshot instructions)
   - Step 2: Plan (task prioritization)
   - Step 3: Execute (implementation)
4. CRITICAL RULES
5. REFERENCE MATERIAL (spec, constraints, memory index — at the end)
```

Action items come first, lengthy reference material last. This structure was optimized through production experience — the agent performs better when it reads the instructions before the context.

## Process Management

### PID File

The daemon writes its PID to `.autobuilder/daemon.pid`. On startup, it kills any previous daemon using this PID file to prevent duplicate instances.

### Stop Signal

Creating `.autobuilder/stop` causes the daemon to exit gracefully after the current iteration completes. The file is deleted on detection.

### Crash Recovery

The daemon uses exponential backoff for three categories of failures:

| Failure Type | Max Consecutive | Backoff Range | Reset On |
|---|---|---|---|
| Agent failures | 5 | 60s → 30min | Any success |
| General crashes | 10 | 30s → 10min | Any success |
| Process restarts | 50 | — | — |
| Idle (nothing to do) | Unlimited | 2min → 30min | New tasks found |

## File System Layout

```
├── README.md                         # Main documentation
├── AGENTS.md                         # Agent instructions (symlinked into projects)
├── config.json                       # Project registry
├── docs/                             # Documentation
├── skills/                           # AI agent skills
│   ├── build-feature/                # Orchestrator + daemon code
│   │   ├── builder_loop.py           # Entry point
│   │   ├── iteration.py              # Single iteration logic
│   │   ├── prompt.py                 # Prompt construction
│   │   ├── project.py                # Project config & context
│   │   ├── common.py                 # Shared constants
│   │   ├── tasks.py                  # Task management
│   │   ├── status.py                 # Status & journal
│   │   ├── process.py                # Subprocess management
│   │   ├── hooks.py                  # Hook system
│   │   ├── git_ops.py                # Git operations
│   │   ├── initiative.py             # Initiative management
│   │   ├── config.py                 # config.json parser
│   │   └── frontmatter.py            # YAML frontmatter parser
│   ├── product-review/               # Review phase skill
│   ├── plan-task/                    # Plan phase skill
│   ├── execute-task/                 # Execute phase skill
│   ├── create-project/               # Project bootstrapping
│   ├── create-initiative/            # Initiative creation
│   ├── steer/                        # Runtime steering
│   ├── agent-browser/                # Browser automation
│   ├── react-doctor/                 # React code quality (execute phase)
│   ├── thermo-nuclear-code-quality-review/ # Plan-phase code-quality gate
│   └── dogfood/                      # QA methodology
├── hook-helpers/                     # Python helpers for hooks (+ shared executor registry)
│   └── autobuilder_hook_helpers/
│       ├── executors.py              # Per-CLI registry — imported by daemon AND hooks
│       ├── fix_agent.py              # CI/deploy fix agent (uses the registry)
│       ├── ci.py / deploy.py / github.py / vercel.py
├── hook-templates/                   # Ready-to-use hook templates
└── tests/                            # Test suite
```

### Per-Project Layout (`.autobuilder/`)

```
<project_root>/
├── .autobuilder/
│   ├── config.yaml               # Project review configuration
│   ├── .env                      # Credentials (PORT, TEST_USERNAME, TEST_PASSWORD)
│   ├── PRODUCT.md                # Project-level context (after 2nd initiative)
│   ├── active-initiative         # Name of current initiative directory
│   ├── status.md                 # Loop status (auto-updated)
│   ├── journal.jsonl             # Iteration outcome log
│   ├── memory-index.md           # Generated context for the agent
│   ├── loop.log                  # Daemon log
│   ├── daemon.pid                # Process ID file
│   ├── backlog.md                # One-shot user feedback (consumed on read)
│   ├── stop                      # Touch to halt the loop
│   ├── hooks/                    # Optional hook scripts
│   └── initiatives/
│       ├── 0001-my-feature/
│       │   ├── spec.md           # Initiative specification
│       │   ├── constraints.md    # Optional constraints
│       │   ├── review-screenshots/ # Review phase screenshots
│       │   └── tasks/
│       │       ├── 0001-root.md  # Root task
│       │       ├── 0002-auth.md  # Generated tasks
│       │       └── ...
│       └── 0002-v2-redesign/
│           ├── spec.md
│           └── tasks/
├── .cursor/skills/autobuilder    # Symlink → skills/
├── AGENTS.md                     # Symlink → AGENTS.md
└── .gitignore                    # Auto-populated by daemon
```
