8.1 KiB
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.rsandcrates/api-contracts/src/chat.rs - Keep inference logic behind a single engine/session boundary in
crates/inference-core/src/engine.rsandcrates/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.tsxandtauri-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:
tauri-app/src/components/ChatView.tsxbuilds message history from local sql.js storage and posts to${server}/v1/chat/completionscrates/inference-server/src/routes.rsvalidates auth/model/mode, prepares the prompt throughcrates/inference-server/src/compat.rs, and locks the sharedInferenceEnginecrates/inference-core/src/session.rstokenizes, pre-fills, samples, and returns streamed or buffered content back through Axum SSE/JSONtauri-app/src/components/ChatView.tsxparses<think>...</think>, stores assistant content plus usage metrics intauri-app/src/lib/db.ts, and updates the UI
Runtime management flow:
tauri-app/src/features/runtime/useRuntimeManager.tsbootstraps aRuntimeSnapshotfromtauri-app/src/features/runtime/api.tstauri-app/src-tauri/src/lib.rsroutes invoke calls intotauri-app/src-tauri/src/runtime/mod.rstauri-app/src-tauri/src/runtime/process.rsfinds and spawns thelocalllmbinary, thentauri-app/src-tauri/src/runtime/health.rsprobes/healthtauri-app/src/features/runtime/components/RuntimeStatusCard.tsxandtauri-app/src/features/runtime/components/RuntimeSettingsDrawer.tsxrender and mutate the runtime state
State Management:
- Backend API state is a single shared
AppStatewithArc<Mutex<InferenceEngine>>incrates/inference-server/src/routes.rs - Desktop runtime state is a single
RuntimeState(pub Mutex<RuntimeInner>)intauri-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, andtauri-app/src/features/runtime/useRuntimeManager.ts - Chat persistence is local-first and browser-backed via
localStorage+ sql.js intauri-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-serveror 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.tsxandtauri-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+ErrorResponsewith HTTP status mapping incrates/inference-server/src/routes.rs - Desktop runtime stores recoverable errors in
last_erroronRuntimeSnapshotintauri-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.tsxandtauri-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 concernscrates/inference-server/should stay the public backend boundary and not own chat persistence or desktop statecrates/localllm-cli/should stay an operator/client surface and not become the runtime itselftauri-app/src-tauri/should own process/config/filesystem concerns for desktop onlytauri-app/src/should stay a consumer/orchestrator over backend contracts and local chat persistence
Architecture analysis: 2026-03-28