# Architecture **Analysis Date:** 2026-03-28 ## Pattern Overview **Overall:** Local-first polyglot workspace with shared contracts and three user surfaces **Key Characteristics:** - Keep API contracts in Rust shared types before exposing them to CLI and desktop consumers in `crates/api-contracts/src/lib.rs` and `crates/api-contracts/src/chat.rs` - Keep inference logic behind a single engine/session boundary in `crates/inference-core/src/engine.rs` and `crates/inference-core/src/session.rs` - Keep the desktop app as an orchestration shell that manages process lifecycle, model discovery, and chat persistence in `tauri-app/src/App.tsx` and `tauri-app/src-tauri/src/runtime/mod.rs` ## Layers **Inference Core:** - Purpose: Load GGUF models, own llama context/model pointers, and generate tokens - Location: `crates/inference-core/src/` - Contains: `EngineConfig`, `InferenceEngine`, runtime profiles, sampler config, generation session - Depends on: `crates/llama-sys`, Rust stdlib, `anyhow`, `tracing` - Used by: `crates/inference-server/src/main.rs` **HTTP Compatibility Layer:** - Purpose: Adapt OpenAI-like chat/model requests to the local engine - Location: `crates/inference-server/src/` - Contains: env-driven `ServerConfig`, auth/CORS rules, prompt preparation, routing, SSE streaming - Depends on: `crates/inference-core`, `crates/api-contracts`, `crates/metrics` - Used by: local HTTP consumers, CLI, desktop frontend **Shared API Contract Layer:** - Purpose: Keep request/response models and error shapes consistent - Location: `crates/api-contracts/src/` - Contains: chat completion structs, model list, health payload, error payloads - Depends on: `serde`, `serde_json` - Used by: server code directly; mirrored conceptually by frontend/CLI callers **CLI Surface Layer:** - Purpose: Expose operator workflows and a future control plane over HTTP/local actions - Location: `crates/localllm-cli/src/main.rs` - Contains: command parsing, planning, preview rendering, selective live transport - Depends on: `clap`, `ureq`, `serde_json` - Used by: developers/operators **Desktop Backend Layer:** - Purpose: Persist runtime config, discover model files, detect GPU, spawn/stop local API - Location: `tauri-app/src-tauri/src/` - Contains: Tauri commands, runtime state machine, health probing, file dialog integration - Depends on: Tauri runtime, native process and filesystem APIs - Used by: `tauri-app/src/features/runtime/api.ts` **Desktop Frontend Layer:** - Purpose: Present runtime controls, model selection, and persistent chat UI - Location: `tauri-app/src/` - Contains: shell layout, runtime manager hooks, chat view, sidebar, markdown rendering, local DB wrapper - Depends on: React, fetch, Tauri invoke bridge, browser storage/CDN-loaded sql.js - Used by: end users of the desktop app ## Data Flow **Local chat request flow:** 1. `tauri-app/src/components/ChatView.tsx` builds message history from local sql.js storage and posts to `${server}/v1/chat/completions` 2. `crates/inference-server/src/routes.rs` validates auth/model/mode, prepares the prompt through `crates/inference-server/src/compat.rs`, and locks the shared `InferenceEngine` 3. `crates/inference-core/src/session.rs` tokenizes, pre-fills, samples, and returns streamed or buffered content back through Axum SSE/JSON 4. `tauri-app/src/components/ChatView.tsx` parses `...`, stores assistant content plus usage metrics in `tauri-app/src/lib/db.ts`, and updates the UI **Runtime management flow:** 1. `tauri-app/src/features/runtime/useRuntimeManager.ts` bootstraps a `RuntimeSnapshot` from `tauri-app/src/features/runtime/api.ts` 2. `tauri-app/src-tauri/src/lib.rs` routes invoke calls into `tauri-app/src-tauri/src/runtime/mod.rs` 3. `tauri-app/src-tauri/src/runtime/process.rs` finds and spawns the `localllm` binary, then `tauri-app/src-tauri/src/runtime/health.rs` probes `/health` 4. `tauri-app/src/features/runtime/components/RuntimeStatusCard.tsx` and `tauri-app/src/features/runtime/components/RuntimeSettingsDrawer.tsx` render and mutate the runtime state **State Management:** - Backend API state is a single shared `AppState` with `Arc>` in `crates/inference-server/src/routes.rs` - Desktop runtime state is a single `RuntimeState(pub Mutex)` in `tauri-app/src-tauri/src/runtime/state.rs` - Frontend state is local React hook state; no global store is used in `tauri-app/src/App.tsx`, `tauri-app/src/hooks/useModels.ts`, and `tauri-app/src/features/runtime/useRuntimeManager.ts` - Chat persistence is local-first and browser-backed via `localStorage` + sql.js in `tauri-app/src/lib/db.ts` ## Key Abstractions **InferenceEngine:** - Purpose: Own one loaded model and one llama context - Examples: `crates/inference-core/src/engine.rs`, `crates/inference-core/src/session.rs` - Pattern: Single-owner, RAII-managed native resource wrapper with explicit non-concurrent use **ServerConfig / ModelCatalog:** - Purpose: Centralize runtime auth, prompt, CORS, and alias rules - Examples: `crates/inference-server/src/compat.rs` - Pattern: Env-derived compatibility adapter layered in front of the engine **RuntimeSnapshot:** - Purpose: Serialize the desktop runtime state into a frontend-safe shape - Examples: `tauri-app/src/features/runtime/types.ts`, `tauri-app/src-tauri/src/runtime/state.rs` - Pattern: Backend source of truth mirrored into a polling frontend hook **DB wrapper:** - Purpose: Hide sql.js statement handling and persistence details behind a tiny query/run API - Examples: `tauri-app/src/lib/db.ts` - Pattern: Thin synchronous local repository over browser storage ## Entry Points **HTTP API binary:** - Location: `crates/inference-server/src/main.rs` - Triggers: `cargo run -p inference-server` or spawned local desktop runtime - Responsibilities: read env, load/warm engine, build router, bind network listener **CLI binary:** - Location: `crates/localllm-cli/src/main.rs` - Triggers: `cargo run -p localllm-cli -- ...` - Responsibilities: parse commands, build execution plans, optionally perform live HTTP requests **Desktop frontend:** - Location: `tauri-app/src/main.tsx` and `tauri-app/src/App.tsx` - Triggers: Vite dev server or Tauri desktop app startup - Responsibilities: render app shell, bootstrap DB/runtime hooks, connect sidebar and chat surface **Desktop backend:** - Location: `tauri-app/src-tauri/src/lib.rs` - Triggers: Tauri app startup and frontend `invoke()` calls - Responsibilities: expose commands, manage runtime state, wire OS dialogs/plugins ## Error Handling **Strategy:** Convert most backend failures into typed user-facing snapshots/responses rather than panic paths **Patterns:** - API uses `ApiError` + `ErrorResponse` with HTTP status mapping in `crates/inference-server/src/routes.rs` - Desktop runtime stores recoverable errors in `last_error` on `RuntimeSnapshot` in `tauri-app/src-tauri/src/runtime/state.rs` - Frontend fetch and invoke failures typically degrade to fallback state or inline assistant error messages in `tauri-app/src/components/ChatView.tsx` and `tauri-app/src/features/runtime/api.ts` ## Cross-Cutting Concerns **Logging:** `tracing` on Rust services in `crates/inference-server/src/main.rs`; frontend logging is minimal and mostly absent **Validation:** request and mode validation lives in `crates/inference-server/src/compat.rs`; runtime form validation is mostly helper-based in `tauri-app/src/features/runtime/runtime-settings-form.ts` **Authentication:** optional API-key auth is enforced in `crates/inference-server/src/compat.rs`; desktop frontend forwards the configured API key from runtime config in `tauri-app/src/features/runtime/api.ts` ## Boundaries **App boundaries:** - `crates/inference-core/` should stay inference-only and not absorb HTTP/UI concerns - `crates/inference-server/` should stay the public backend boundary and not own chat persistence or desktop state - `crates/localllm-cli/` should stay an operator/client surface and not become the runtime itself - `tauri-app/src-tauri/` should own process/config/filesystem concerns for desktop only - `tauri-app/src/` should stay a consumer/orchestrator over backend contracts and local chat persistence --- *Architecture analysis: 2026-03-28*