# Architecture Decisions — Round 1

Date: 2026-05-25
Source: idea.md discussion, questions 1–18

## D-001: Bun as JS Runtime

- **Decision**: Bun.
- **Why**: Both OpenCode and Claude Code use Bun; built-in SQLite removes native addon dependency; native TSX support simplifies build config; C++ modules communicate via subprocess, not native addons.
- **Distribution**: Bundle Bun runtime with AirCoding.

## D-002: @opentui/solid as TUI Framework

- **Decision**: `@opentui/solid` (MIT licensed, standalone project, not coupled to OpenCode).
- **Why**: OpenTUI is an independent library consumed by OpenCode as a regular npm dependency. The TUI rendering layer is cleanly separated from OpenCode's business logic. Reference OpenCode's TUI component patterns for interaction design.
- **Reuse strategy**: Direct npm dependency on `@opentui/solid @opentui/core @opentui/keymap`. AirCoding TUI components reference OpenCode patterns but are independently implemented.

## D-003: Bun Monorepo

- **Decision**: Monorepo with Bun workspaces + Turborepo.
- **MVP packages**:
  - `packages/tui` — AirCoding TUI components on top of `@opentui/solid`
  - `packages/runtime` — Agent Loop, Session, Scheduler, Tool Registry, EventBus
  - `packages/llm` — Provider/Model abstraction (reference `@opencode-ai/llm`, but may fork/adapt)
  - `packages/toolchain` — C++ BuildTool, DiagnosticParser, TestRunner
  - `packages/cli` — Entry point, assembles all packages
- **Later**: Plugin SDK, debug knowledge, Python worker bridge.

## D-004: Python as Subprocess-Only Tooling

- **Decision**: Python workers are called via `Bun.spawn` with JSON-over-stdio. No long-lived Python server. No bundled Python environment.
- **Scope**: Python only wraps existing C++ toolchain scripts and Python-specific libraries. Experience mining, context assembly, and memory management stay in TS runtime.
- **Re-evaluated from idea.md**: idea.md assigned Python for Hermes-style learning and AirContext compression, but these are LLM + text + SQLite operations that Bun/TS handles natively. Keeping them in TS avoids unnecessary language bridging.

## D-005: Event-Driven Agent Architecture

- **Decision**: Event-driven. Main Agent subscribes to EventBus for agent/task/tool events and renders progress to TUI/HUD.
- **Main Agent state machine** (see `AirPlan/docs/architecture/main-agent-state-machine.md`):
  - IDLE → CLASSIFYING → DELEGATING → CONFIRMING → EXECUTING → SUMMARIZING → IDLE
  - INTERRUPTING for mid-execution user requirement changes (classified via LLM)
  - Error handling: Main Agent handles what it can, escalates to user only when necessary
- **Key constraint**: Main Agent must remain idle-ready for user intervention. Background tasks (ExperienceMiner, DebugKnowledge indexing) are dispatched to sub-agents.

## D-006: Sub-Agent Loops Are Independent

- **Decision**: Executor, Reviewer, and Debugger each have their own agent loop implementation. Not a shared generic loop engine.
- **Executor loop**: LOADING → THINKING → ACTING → OBSERVING → (loop with debugging sub-loop on failure) → FINALIZING
- **Reviewer loop**: LOADING → REVIEWING → DECIDING (approved / changes_requested / blocked)
- **Debugger loop**: GATHERING → ANALYZING → FIXING → (RECORDING or ESCALATING)
- **Sub-agent execution quality**: Claude Code is the behavioral benchmark (read-first, small edits, verify before return, follow Project Rules).

## D-007: Independent Processes for Sub-Agents

- **Decision**: Each Executor/Reviewer/Debugger is an independent Bun process spawned by Scheduler. IPC via stdio + JSON (same mechanism as Python workers).
- **Why**: Crash isolation, context isolation, natural worktree support. Single-process approach excluded due to context explosion and lack of fault isolation.
- **Communication**: Scheduler passes TaskSpec (worktree path, tool set, permission level) on spawn; sub-agent returns structured WorkerResult JSON on completion.

## D-008: Push Heartbeat + Soft/Hard Timeout

- **Decision**: Sub-agents push `AgentHeartbeat` events (status, turn count, tokens) every N seconds. Scheduler subscribes and detects stalls.
- **Heartbeat**: Push model. Sub-agent proactively reports state.
- **Timeout**: Hybrid. Hard timeout kills on expiration. Soft timeout warns and allows extension requests (sub-agent can justify need for more time). Scheduler decides per-task.
- **Loop detection**: Same error signature appearing N+ times triggers escalation to Main Agent (not auto-kill).

## D-009: Per-Session SQLite with Anthropic-Native Storage

- **Decision**: 
  - `~/.air/sessions/<session-id>/session.db` per session
  - `~/.air/projects/<project-id>/debug-records.db` cross-session
  - `~/.air/projects/<project-id>/learned-memory.db` cross-session
- **Message format**: Anthropic-native content blocks (TextBlock, ThinkingBlock, ToolUseBlock, ToolResultBlock), following Claude Code's approach.
- **Provider switching**: Same-provider switching (e.g., Opus → Sonnet) is zero-cost. Cross-provider switching converts at API boundary (Anthropic format → target provider format → response → back to Anthropic format for storage).
- **Event persistence**: 
  - High-frequency events (TokenDelta, StdoutChunk) → EventBus only, not persisted
  - Durable events (TaskCompleted, ToolRunCompleted) → SQLite, synchronous write on main thread
  - WAL mode for concurrent read/write

## D-010: Full Context Dump on Session Exit

- **Decision**: On session exit, dump complete context to session storage. On resume, load from full dump, not reconstruct from summaries.
- **Recovery**:
  - Compaction is internal projection optimization, not data removal
  - Structured summaries serve as index for fast historical lookup
  - Scheduler rebuilds task queue from AgentTask table; running tasks judged by heartbeat timestamp
  - User sees full conversation history transparently

## D-011: Build System Auto-Detection

- **Priority**: CMake (built-in) > Meson/Bazel/XMake (capability plugin) > Makefile/.sln
- **Conflict handling**: When multiple build system files exist (e.g., CMakeLists.txt + meson.build), ask user to choose.
- **Generator**: Ninja first, fall back to Make if Ninja fails.
- **Config failure**: BuildTool built-in logic attempts fix first (install missing deps, adjust CMake args); if unresolved, hand off to Debugger.

## D-012: compile_commands.json — On-Demand Generation, No Caching

- **Decision**: Detect and generate `compile_commands.json` on demand via `cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON`. No persistence/caching between sessions.

## D-013: clangd CLI Mode for MVP

- **Decision**: CLI mode (`clangd --check=<file>` or equivalent) for MVP. Spawn on tool call, exit on completion. LSP daemon mode deferred to later phase if CLI latency proves unacceptable.

## D-014: LLM-Based Diagnostic Parsing

- **Decision**: All compiler/linker output parsed via LLM (not regex). LLM extracts structured `Diagnostic` records and generates semantic error signatures.
- **Error signature**: LLM computes semantic signature that normalizes across GCC/Clang/MSVC wording differences (e.g., "use of undeclared identifier" and "was not declared in this scope" map to same signature).
- **Linker errors**: Separately categorized from compiler diagnostics.

## D-015: LLM-Driven Project Initialization — Loose Acceptance

- **Decision**: Scanner collects facts → LLM infers `ProjectProfile` → loose schema acceptance (missing fields marked as `unknown`, not rejected) → user confirms/corrects → incremental field update with "may affect related inferences" hint.
- **No LLM retry loop** on schema mismatch. User correction is single-pass.

## D-016: Classification by LLM

- **Decision**: Main Agent uses LLM to classify user messages (chat, direct-mode, simple-task, needs-planning).

## D-017: Confirmation Gating

- **Decision**: Implementation-level changes that don't affect interfaces or architecture → silently proceed to EXECUTING. Architecture-level changes → Arc assessment required. Low permission: user confirms. High permission: auto-proceed with results displayed to user for immediate intervention.

## D-018: Interruption via LLM Intent Detection

- **Decision**: User interruption during execution detected via LLM intent classification, not Ctrl+C (ineffective with multi-process architecture).

## D-019: Scheduler — Full Dependency Handling

- **Decision**: Scheduler handles both hard dependencies (topological sort) and soft dependencies (optimization hints). Write-area conflict detection: different areas → parallel; same area but different code blocks → git worktree parallel then merge; same area, same code block → serial.
- **Concurrency**: Dynamic, API-rate-limit-aware, machine-resource-aware.
- **Failure**: Retry 3-5 times. Solvable failures block hard dependents only. Unsolvable failures (e.g., kernel limitation) go back to Architecture Designer. Repeated failures after max retries → Main Agent evaluates (silent resolution vs. user escalation).
- **Model selection**: Scheduler decides whether to force a specific model per task or let Executor choose.

## D-020: Memory System — Claude Code Style

- **Decision**: Claude Code's persistent memory system (MEMORY.md + frontmatter + typed layers) is the primary reference for memory design, alongside Hermes-style experience mining as a candidate layer.
