Skip to content

Architecture

sshdw edited this page Oct 15, 2026 · 2 revisions

Architecture

Layered, local-first desktop app. Stack: Tauri v2, React 19 + TypeScript (strict) frontend in src/, Rust backend in src-tauri/src/, SQLite via rusqlite (bundled, FTS5).

Layers (dependency strictly downward)

  1. React UI (src/) — presentational only; no business logic. Data access goes through typed wrappers in src/lib/ around Tauri invoke.
  2. Commands layer (src-tauri/src/commands/) — thin IPC translation only. Validates args, maps errors to secret-free classified CommandError, clones managed state (Database, AgentRunRegistry, TaskRegistry, TerminalRegistry, ConfirmationRegistry) into worker threads, streams agent-run-event / task-event frames. No business logic, no repository/SQL access.
  3. Application layer (src-tauri/src/application/) — use cases and the agent subsystem: deterministic ReAct runner, run bridge, bounded plan → act → verify → report task loop, three-tier approval gate, autonomy modes, permission evaluation, spend/budget enforcement, governance checkpoints and audit log, context assembly/compaction, snapshots, injection hardening, self-audit, read-only inspector. Also owns the provider-independent execution boundary (application/execution.rs).
  4. Domain layer (src-tauri/src/domain/) — entities and business rules, UI-independent.
  5. Infrastructure layer (src-tauri/src/infrastructure/) — SQLite (database.rs, migrations v1–v14, WAL + FK + busy-timeout), per-table repositories, provider executors (providers/), filesystem, OS integration, logging.

AI providers are external services reached only through backend executors behind the execution boundary. Nothing above infrastructure touches SQLite or the network directly; nothing below commands handles Tauri IPC.

Data flow

User action (React) → Tauri invoke with typed args → commands (validate, map errors, acquire state) → application logic (use case / runner, approvals, budgets) → persistence or AI request (repositories / provider executors) → result plus streamed event frames for long-running work → UI update.

Key rules

  • invoke args are camelCase ({ conversationId }) mapping to snake_case Rust params (conversation_id); returned structs and event payloads stay snake_case.
  • New Tauri commands must be registered in the generate_handler![...] list in src-tauri/src/lib.rs; a missed registration compiles but fails at invoke time.
  • Errors are classified, logged without secrets, and shown to users in clear form; unexpected failures must not corrupt user data.
  • unsafe_code = "forbid"; clippy pedantic warnings deny CI.

See also: Database, Providers-and-Models, Agent-Runs, Security-and-Credentials.

Clone this wiki locally