迁移路径: /run/media/airlongdian/EasyU/AirCoding -> /home/airlongdian/DataDevices/AirWorkSpace/AirCoding Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
135 lines
9.2 KiB
Markdown
Executable File
135 lines
9.2 KiB
Markdown
Executable File
# 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.
|