Files
AirCoding/AirPlan/docs/architecture/decisions-round-1.md
AirCoding 33a76a1ebc Move project from external drive to local NVMe
迁移路径: /run/media/airlongdian/EasyU/AirCoding -> /home/airlongdian/DataDevices/AirWorkSpace/AirCoding

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-02 09:51:49 +08:00

135 lines
9.2 KiB
Markdown
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Architecture Decisions — Round 1
Date: 2026-05-25
Source: idea.md discussion, questions 118
## 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.