|
| 1 | +# Iteratr Architecture |
| 2 | + |
| 3 | +## Overview |
| 4 | + |
| 5 | +**iteratr** is a TUI-based orchestration tool that manages AI coding agents (via opencode) in iterative development loops. It enables autonomous or semi-autonomous software development by: |
| 6 | + |
| 7 | +- Running AI agents in persistent sessions across multiple iterations |
| 8 | +- Managing tasks, notes, and session state through event sourcing |
| 9 | +- Providing real-time monitoring via a full-screen terminal UI |
| 10 | +- Persisting all data in embedded NATS JetStream |
| 11 | +- Allowing user intervention through TUI input or lifecycle hooks |
| 12 | + |
| 13 | +## Architectural Layers |
| 14 | + |
| 15 | +``` |
| 16 | +┌─────────────────────────────────────────────────────┐ |
| 17 | +│ CLI Layer (Cobra) │ |
| 18 | +│ Commands: build, setup, config, doctor, tool │ |
| 19 | +└──────────────────┬──────────────────────────────────┘ |
| 20 | + │ |
| 21 | +┌──────────────────▼──────────────────────────────────┐ |
| 22 | +│ Orchestrator (Core Controller) │ |
| 23 | +│ - Manages iteration loop lifecycle │ |
| 24 | +│ - Coordinates all components │ |
| 25 | +│ - Handles pause/resume/context cancellation │ |
| 26 | +└─────┬──────────┬──────────┬──────────┬──────────┬───┘ |
| 27 | + │ │ │ │ │ |
| 28 | +┌─────▼────┐ ┌──▼────┐ ┌───▼────┐ ┌───▼────┐ ┌───▼────┐ |
| 29 | +│ TUI │ │ Agent │ │ NATS │ │ MCP │ │ Hooks │ |
| 30 | +│(Bubbletea│ │Runner │ │JetStrm │ │Server │ │ System │ |
| 31 | +│ v2) │ │ (ACP) │ │(Store) │ │(Tools) │ │ │ |
| 32 | +└──────────┘ └───────┘ └────────┘ └────────┘ └────────┘ |
| 33 | + │ │ │ │ │ |
| 34 | +┌─────▼──────────▼──────────▼──────────▼──────────▼───┐ |
| 35 | +│ Session Store (Event Sourcing) │ |
| 36 | +│ - Tasks, Notes, Iterations, Control Events │ |
| 37 | +│ - Event-driven state reconstruction │ |
| 38 | +└─────────────────────────────────────────────────────┘ |
| 39 | +``` |
| 40 | + |
| 41 | +## Core Packages |
| 42 | + |
| 43 | +| Package | Path | Responsibility | |
| 44 | +|---------|------|----------------| |
| 45 | +| orchestrator | `internal/orchestrator/` | Core iteration loop, component coordination | |
| 46 | +| agent | `internal/agent/` | ACP protocol, subprocess management, file tracking | |
| 47 | +| session | `internal/session/` | Event sourcing, state reconstruction | |
| 48 | +| tui | `internal/tui/` | Bubbletea v2 TUI with Ultraviolet layouts | |
| 49 | +| mcpserver | `internal/mcpserver/` | Embedded HTTP server for MCP tools | |
| 50 | +| nats | `internal/nats/` | Embedded NATS JetStream server | |
| 51 | +| config | `internal/config/` | Viper-based configuration management | |
| 52 | +| hooks | `internal/hooks/` | Lifecycle hooks execution | |
| 53 | +| template | `internal/template/` | Prompt template engine | |
| 54 | +| logger | `internal/logger/` | Structured file + stderr logging | |
| 55 | +| errors | `internal/errors/` | Error types, panic recovery, retry logic | |
| 56 | + |
| 57 | +## Bootstrap Flow |
| 58 | + |
| 59 | +Entry: `cmd/iteratr/build.go:runBuild()` |
| 60 | + |
| 61 | +1. **Config Loading** - Viper loads from files + ENV vars + CLI flags |
| 62 | +2. **Orchestrator Creation** - Creates orchestrator with config |
| 63 | +3. **NATS Setup** - Connect to existing or start embedded server |
| 64 | +4. **JetStream Setup** - Create stream "iteratr_events" |
| 65 | +5. **MCP Server Start** - Start HTTP server on random port |
| 66 | +6. **Session State Check** - Check if session complete, prompt for restart |
| 67 | +7. **TUI Initialization** - Create Bubbletea app (if not headless) |
| 68 | +8. **Hooks Loading** - Load `.iteratr.hooks.yml` if present |
| 69 | +9. **Agent Runner Creation** - Create runner with callbacks |
| 70 | + |
| 71 | +## Iteration Loop |
| 72 | + |
| 73 | +Location: `internal/orchestrator/orchestrator.go` |
| 74 | + |
| 75 | +``` |
| 76 | +1. Check context cancellation / iteration limit |
| 77 | +2. Clear file tracker |
| 78 | +3. Log iteration start (NATS event) |
| 79 | +4. Send IterationStartMsg to TUI |
| 80 | +5. Execute pre_iteration hooks |
| 81 | +6. Build prompt with current state (template.BuildPrompt) |
| 82 | +7. Run agent iteration with panic recovery |
| 83 | + - runner.RunIteration(ctx, prompt, hookOutput) |
| 84 | + - Agent callbacks update TUI in real-time |
| 85 | +8. Log iteration complete (NATS event) |
| 86 | +9. Execute post_iteration hooks |
| 87 | +10. Run auto-commit if enabled and files modified |
| 88 | +11. Check if session marked complete |
| 89 | +12. Process queued user messages |
| 90 | +13. Check if paused - block until resume |
| 91 | +14. Increment iteration count |
| 92 | +15. GOTO 1 |
| 93 | +``` |
| 94 | + |
| 95 | +## TUI Architecture |
| 96 | + |
| 97 | +See `component-tree.md` for the full component tree. |
| 98 | + |
| 99 | +### Stack |
| 100 | + |
| 101 | +- **Bubbletea v2** - Core TUI framework (model-update-view) |
| 102 | +- **Ultraviolet** - Rectangle-based layout management |
| 103 | +- **Lipgloss v2** - Styling and content composition |
| 104 | +- **Bubbles v2** - Pre-built components (viewport, textinput, spinner) |
| 105 | +- **Glamour v2** - Markdown rendering |
| 106 | + |
| 107 | +### Component Hierarchy |
| 108 | + |
| 109 | +``` |
| 110 | +App (root) |
| 111 | +├── StatusBar - Session info, git status, duration, pause state |
| 112 | +├── Dashboard - Main content area with focus management |
| 113 | +│ └── AgentOutput - Conversation display with ScrollList + textinput |
| 114 | +├── Sidebar - Tasks/notes lists with logo |
| 115 | +└── Modals (overlay, priority-based) |
| 116 | + ├── Dialog - Simple confirmation |
| 117 | + ├── LogViewer - Event history |
| 118 | + ├── TaskModal - Task detail viewer |
| 119 | + ├── NoteModal - Note detail viewer |
| 120 | + ├── TaskInputModal - Task creation |
| 121 | + ├── NoteInputModal - Note creation |
| 122 | + └── SubagentModal - Subagent session replay |
| 123 | +``` |
| 124 | + |
| 125 | +### Layout Modes |
| 126 | + |
| 127 | +| Mode | Condition | Layout | |
| 128 | +|------|-----------|--------| |
| 129 | +| Desktop | width >= 100, height >= 25 | Status (1 row) \| Main (flex) \| Sidebar (45 cols) | |
| 130 | +| Compact | below thresholds | Status (1 row) \| Main (full), sidebar toggles as overlay | |
| 131 | + |
| 132 | +### Keyboard Routing Priority |
| 133 | + |
| 134 | +1. Dialog visible - Dialog.Update() |
| 135 | +2. Global keys (ctrl+c quit) |
| 136 | +3. Prefix mode (ctrl+x + key) |
| 137 | +4. Modal overlays (ESC closes) |
| 138 | +5. Dashboard focus routing |
| 139 | + |
| 140 | +## Event Sourcing |
| 141 | + |
| 142 | +All session state is stored as append-only events in NATS JetStream. |
| 143 | + |
| 144 | +### Event Structure |
| 145 | + |
| 146 | +```go |
| 147 | +type Event struct { |
| 148 | + ID string // NATS sequence ID |
| 149 | + Timestamp time.Time |
| 150 | + Session string // Session name |
| 151 | + Type string // task, note, iteration, control |
| 152 | + Action string // add, status, priority, etc. |
| 153 | + Meta json.RawMessage // Action-specific metadata |
| 154 | + Data string // Primary content |
| 155 | +} |
| 156 | +``` |
| 157 | + |
| 158 | +### Subject Pattern |
| 159 | + |
| 160 | +- `iteratr.{session}.task` - Task events |
| 161 | +- `iteratr.{session}.note` - Note events |
| 162 | +- `iteratr.{session}.iteration` - Iteration events |
| 163 | +- `iteratr.{session}.control` - Session control events |
| 164 | + |
| 165 | +### State Reconstruction |
| 166 | + |
| 167 | +```go |
| 168 | +// Load all events for session, apply in order |
| 169 | +state := &State{Tasks: map[string]*Task{}} |
| 170 | +for event := range events { |
| 171 | + state.Apply(event) // Reducer pattern |
| 172 | +} |
| 173 | +``` |
| 174 | + |
| 175 | +## Agent Integration |
| 176 | + |
| 177 | +### ACP Protocol |
| 178 | + |
| 179 | +Communication with opencode via JSON-RPC 2.0 over stdio. |
| 180 | + |
| 181 | +Location: `internal/agent/acp.go` |
| 182 | + |
| 183 | +### Runner Lifecycle |
| 184 | + |
| 185 | +```go |
| 186 | +// 1. Start subprocess (once per session) |
| 187 | +runner.Start(ctx) // Spawns: opencode acp |
| 188 | + |
| 189 | +// 2. Per-iteration (fresh ACP session each time) |
| 190 | +runner.RunIteration(ctx, prompt, hookOutput) |
| 191 | + |
| 192 | +// 3. Cleanup |
| 193 | +runner.Stop() |
| 194 | +``` |
| 195 | + |
| 196 | +### Callbacks |
| 197 | + |
| 198 | +| Callback | Purpose | |
| 199 | +|----------|---------| |
| 200 | +| `OnText(string)` | Assistant text output | |
| 201 | +| `OnToolCall(ToolCallEvent)` | Tool execution lifecycle | |
| 202 | +| `OnThinking(string)` | Reasoning content | |
| 203 | +| `OnFinish(FinishEvent)` | Iteration complete | |
| 204 | +| `OnFileChange(FileChange)` | File modifications for auto-commit | |
| 205 | + |
| 206 | +## MCP Tools Server |
| 207 | + |
| 208 | +Embedded HTTP server exposes tools to the AI agent. |
| 209 | + |
| 210 | +Location: `internal/mcpserver/` |
| 211 | + |
| 212 | +### Available Tools |
| 213 | + |
| 214 | +| Tool | Purpose | |
| 215 | +|------|---------| |
| 216 | +| `task-add` | Create task | |
| 217 | +| `task-batch-add` | Create multiple tasks | |
| 218 | +| `task-status` | Update task status | |
| 219 | +| `task-priority` | Set task priority | |
| 220 | +| `task-depends` | Add dependency | |
| 221 | +| `task-list` | List tasks by status | |
| 222 | +| `task-next` | Get next unblocked task | |
| 223 | +| `note-add` | Record note | |
| 224 | +| `note-list` | List notes | |
| 225 | +| `iteration-summary` | Record iteration summary | |
| 226 | +| `session-complete` | Mark session complete | |
| 227 | + |
| 228 | +## Configuration |
| 229 | + |
| 230 | +Viper-based with layered precedence: CLI flags > ENV vars > project config > global config > defaults |
| 231 | + |
| 232 | +### Config Locations |
| 233 | + |
| 234 | +- Global: `~/.config/iteratr/iteratr.yml` |
| 235 | +- Project: `./iteratr.yml` |
| 236 | + |
| 237 | +### Options |
| 238 | + |
| 239 | +| Key | ENV Var | Default | Description | |
| 240 | +|-----|---------|---------|-------------| |
| 241 | +| `model` | `ITERATR_MODEL` | (required) | LLM model ID | |
| 242 | +| `auto_commit` | `ITERATR_AUTO_COMMIT` | `true` | Auto-commit files | |
| 243 | +| `data_dir` | `ITERATR_DATA_DIR` | `.iteratr` | Data directory | |
| 244 | +| `log_level` | `ITERATR_LOG_LEVEL` | `info` | Log level | |
| 245 | +| `log_file` | `ITERATR_LOG_FILE` | `""` | Log file path | |
| 246 | +| `iterations` | `ITERATR_ITERATIONS` | `0` | Max iterations (0=infinite) | |
| 247 | +| `headless` | `ITERATR_HEADLESS` | `false` | No TUI mode | |
| 248 | +| `template` | `ITERATR_TEMPLATE` | `""` | Template path | |
| 249 | + |
| 250 | +## Design Patterns |
| 251 | + |
| 252 | +| Pattern | Usage | |
| 253 | +|---------|-------| |
| 254 | +| Event Sourcing | Session state as append-only events | |
| 255 | +| Observer | NATS pub/sub for async communication | |
| 256 | +| Command | Bubbletea messages encapsulate actions | |
| 257 | +| MVC | Model/Update/View in Bubbletea TUI | |
| 258 | +| Callback | Agent runner streams events | |
| 259 | +| Repository | Session store abstracts data access | |
| 260 | +| Factory | Component creation (NewRunner, NewApp) | |
| 261 | + |
| 262 | +## Directory Structure |
| 263 | + |
| 264 | +``` |
| 265 | +cmd/iteratr/ # CLI commands (entry point) |
| 266 | +internal/ |
| 267 | +├── agent/ # Agent subprocess management |
| 268 | +├── config/ # Viper config |
| 269 | +├── errors/ # Error utilities |
| 270 | +├── git/ # Git info |
| 271 | +├── hooks/ # Lifecycle hooks |
| 272 | +├── logger/ # Logging |
| 273 | +├── mcpserver/ # MCP tools server |
| 274 | +├── nats/ # Embedded NATS |
| 275 | +├── orchestrator/ # Core controller |
| 276 | +├── session/ # Event sourcing |
| 277 | +├── template/ # Prompt templates |
| 278 | +└── tui/ # Bubbletea UI |
| 279 | + ├── theme/ # Color themes |
| 280 | + └── wizard/ # Setup wizard |
| 281 | +specs/ # Feature specifications |
| 282 | +.iteratr/ # Runtime data (gitignored) |
| 283 | +├── data/ # NATS JetStream storage |
| 284 | +└── server.port # Server port file |
| 285 | +``` |
| 286 | + |
| 287 | +## Runtime Data |
| 288 | + |
| 289 | +- `.iteratr/data/jetstream/` - NATS event stream storage |
| 290 | +- `.iteratr/data/server.port` - NATS server port number |
| 291 | +- `.iteratr.hooks.yml` - Lifecycle hooks configuration |
| 292 | +- `iteratr.yml` - Project config |
0 commit comments