--- name: Slice 5 — Core, Storage, Hotkey, Build type: architecture-map-page slice: 05-core-storage-hotkey-build last_verified: 2026/05/09 --- # Slice 5: Core, Storage, Hotkey, Build / CI > **Where you are:** [Architecture map](../README.md) → Core, Storage, Hotkey, Build **Plain English summary.** This slice is Lumotia's foundations. Three Rust crates the rest of the workspace builds on top of: `lumotia-core` (shared types, hardware probes, model registry, thread tuning), `lumotia-storage` (the SQLite database, FTS5 search, file-system paths), and `lumotia-hotkey` (a Wayland-friendly evdev hotkey listener for Linux). Plus the workspace-level glue that wires the Rust workspace together with the SvelteKit frontend: `Cargo.toml`, the GitHub Actions pipelines, the dev launcher, the static asset folder, and the package configuration files. If a new engineer wants to know where a public type comes from, where a setting is persisted, or how a release artefact gets built, the answer is somewhere in this slice. ## At a glance - **Crates:** three. `lumotia-core` (1,805 LOC), `lumotia-storage` (3,771 LOC), `lumotia-hotkey` (632 LOC). Total ~6,200 LOC. - **Workspace glue:** `Cargo.toml` (161 bytes), `package.json`, `vite.config.js`, `svelte.config.js`, `jsconfig.json`, `run.sh`, `static/`, `.gitignore`. - **CI:** three workflows — `check.yml` (per-push compile + lint + libs tests + frontend), `build.yml` (release-bundle build for tags + manual dispatch), `audit.yml` (weekly Mondays cargo-audit + npm-audit). - **Database head:** schema version **15** (commit on disk, supersedes the v14 figure quoted in `HANDOVER.md` 2026/04/25). - **Key external deps:** `sysinfo 0.35` (hardware), `libloading 0.8` (Vulkan loader probe), `sqlx 0.8` (no default features, runtime-tokio + sqlite only), `evdev 0.12` (Linux hotkeys), `notify 7` (device hotplug), `uuid 1` (v4, random). - **Targets:** Linux (primary, evdev backend), Windows, macOS. Hotkey crate is no-op on non-Linux platforms — Tauri's global-shortcut plugin handles those targets. - **Default profile UUID:** `00000000-0000-0000-0000-000000000001`. Created by migration v6, protected by SQL triggers from rename or delete. ## Map of this slice `lumotia-core`: - [Public types and enums (Segment, Transcript, Megabytes, ModelId, EngineName)](core-types-and-enums.md) - [Constants module (sample rate, VAD, RAM thresholds, chunk timing)](core-constants.md) - [Error type and Result alias](core-error.md) - [Hardware probe (sysinfo + CpuFeatures + Vulkan loader)](core-hardware-probe.md) - [Power-state probe (sysfs, 10s TTL cache, test override)](core-power.md) - [Inference thread tuning (Workload, battery halve, GPU clamp)](core-tuning.md) - [Model registry (Whisper + Parakeet entries with pinned SHA256)](core-model-registry.md) - [Recommendation scoring (rank_recommendations)](core-recommendation.md) - [Process-watch (meeting detection by process name)](core-process-watch.md) - [App paths (database, recordings, models, logs)](core-paths.md) `lumotia-storage`: - [Storage overview (sqlx config, init flow, default features rationale)](storage-overview.md) - [Schema and migrations (v1-v15 catalogue)](storage-schema-and-migrations.md) - [FTS5 transcript search](storage-fts5-search.md) - [Transcripts CRUD](storage-crud-transcripts.md) - [Tasks and subtasks CRUD](storage-crud-tasks.md) - [Profiles and profile_terms CRUD](storage-crud-profiles.md) - [Settings, error log, feedback, implementation rules](storage-crud-settings-and-misc.md) - [File storage paths (database, recordings, crashes, logs)](storage-file-paths.md) `lumotia-hotkey`: - [Linux evdev listener (devices, hotplug, modifiers, Pressed/Released)](hotkey-linux-evdev.md) Workspace and build glue: - [Workspace `Cargo.toml` (members, release profile)](workspace-cargo.md) - [CI: `check.yml`, `build.yml`, `audit.yml`](ci-pipeline.md) - [Dev launcher (`run.sh`) and root `package.json`](dev-launcher-and-scripts.md) - [Vite, SvelteKit, jsconfig](frontend-build-config.md) - [Static assets and `pcm-processor.js` worklet](static-assets.md) - [`HANDOVER.md` and root `README.md` pointer](dev-handover-pointer.md) ## How this slice connects to others - **`lumotia-core` is the universal lower bound.** Every other crate in the workspace depends on it. The shape contract is: `Segment`, `Transcript`, `ModelId`, `EngineName`, `Megabytes`, `AudioSamples`, `MagnotiaError`, `Result`, plus `paths::AppPaths`. See [`core-types-and-enums.md`](core-types-and-enums.md). - **Slice 1 (frontend)** never imports any of these crates directly. It reaches them through Tauri commands (slice 2). The single setting key the frontend cares about is `lumotia_preferences` (a JSON blob), persisted via `lumotia_storage::get_setting` / `set_setting` (slice 5) called from the Tauri preferences command (slice 2). - **Slice 2 (Tauri runtime)** is the heaviest consumer. It calls `lumotia_storage::init` at startup, registers the SQLite pool as Tauri-managed state, and every command in `src-tauri/src/commands/*.rs` reaches into `lumotia_storage` for persistence and `lumotia_core::paths` for filesystem locations. The hotkey command at `src-tauri/src/commands/hotkey.rs` is the sole consumer of `lumotia_hotkey::EvdevHotkeyListener`. - **Slice 3 (audio + transcription)** consumes `lumotia_core::types::{AudioSamples, Segment, Transcript}` and `lumotia_core::constants::{WHISPER_SAMPLE_RATE, WHISPER_CHANNELS, PARAKEET_*, CHUNK_INTERVAL_MS}`. The transcription engines also consume `lumotia_core::tuning::inference_thread_count(Workload::Whisper, gpu_offloaded)` for thread sizing. - **Slice 4 (LLM + formatting + MCP)** consumes `lumotia_core::tuning::{inference_thread_count, Workload::Llm}`, `lumotia_core::paths::AppPaths::llm_models_dir()`, `lumotia_core::types::Segment` (formatting), and `lumotia_core::constants::SMART_PARAGRAPH_GAP_SECS` (formatting). The MCP server is the only consumer of `lumotia_storage::init_readonly` — it opens the DB read-only so no MCP tool can mutate user data even if the dispatcher misroutes a request. ## Existing in-repo docs These are the critical-issue write-ups from the 2026-04-22 review that overlap with slice 5. Cross-referenced from the relevant per-page file. **Not duplicated here.** - [`docs/issues/c3-migrations-atomicity.md`](../../issues/c3-migrations-atomicity.md) — drove the v9-onwards transactional migration design. See [`storage-schema-and-migrations.md`](storage-schema-and-migrations.md). - [`docs/issues/c4-transcript-profile-fk.md`](../../issues/c4-transcript-profile-fk.md) — drove migration v9, the table rebuild that landed `transcripts.profile_id` with a real foreign key. See [`storage-schema-and-migrations.md`](storage-schema-and-migrations.md). - [`docs/issues/keystore-thread-safety.md`](../../issues/keystore-thread-safety.md) — keystore lives in `crates/cloud-providers/` (slice 4) but the lesson generalises to every shared mutable state in `lumotia-core`. Cross-referenced from the tuning page. - [`docs/issues/hotkey-linux-device-filter.md`](../../issues/hotkey-linux-device-filter.md) — the RB-12 hard-coded `KEY_A` / `KEY_R` filter that the current `device_supports_combo` replaced. See [`hotkey-linux-evdev.md`](hotkey-linux-evdev.md). - [`docs/issues/power-assertion-macos-objc2.md`](../../issues/power-assertion-macos-objc2.md) — RB-08, the only open MAJOR per `HANDOVER.md`. The implementation lives in slice 2 (`src-tauri`) but the API design lives near `lumotia-core` conceptually. Linked from the slice debt section. - [`docs/audit/phase0-cartography.md`](../../audit/phase0-cartography.md) — phase-0 codebase cartography, predates this map but covers crate-graph topology in summary form. - [`docs/code-review-2026-04-22.md`](../../code-review-2026-04-22.md) — full audit. Slice 5 work items: RB-08 (macOS power assertion), RB-12 (hotkey filter, fixed), C3 (migrations atomicity, fixed), C4 (transcript profile FK, fixed). Several MAJORs across the slice 2 / 3 / 4 surface area too — see the document. ## Open questions, debt, drift - **RB-08 still open.** macOS power assertion (`crates/.../power_assertion.rs` — surface lives in slice 2) is a non-functional stub awaiting the `objc2` rewrite plus runtime verification on Apple silicon. Per `HANDOVER.md`, gates v0.1 tagging. Tracked in [`docs/issues/power-assertion-macos-objc2.md`](../../issues/power-assertion-macos-objc2.md). - **Schema head drift in human-facing docs.** `HANDOVER.md` (2026/04/25) says v14; the migration registry on disk is v15 (commit 2026/05/09 added `idx_transcripts_profile_created`). Worth a single sweep of human-facing handovers when the next session opens. - **Hotkey is Linux-only at runtime.** macOS and Windows fall back to Tauri's global-shortcut plugin (slice 2). The crate compiles cleanly on all three OSes (the stub module is a no-op), but feature parity across platforms is provided by two different mechanisms. A single user-visible inconsistency: per-device hotplug. The Tauri plugin doesn't have it. - **Power probe is Linux-only.** macOS / Windows return `PowerState::Unknown`, which callers treat as `OnAc`. Native probes (`IOPSGetProvidingPowerSourceType`, `GetSystemPowerStatus`) are noted-deferred in [`core-power.md`](core-power.md). - **GPU probe is a stub.** `lumotia_core::hardware::probe_gpu()` returns `None`. CPU probe is wired (sysinfo + CPUID), Vulkan loader is probed via `libloading`, but the actual GPU vendor / VRAM are never populated. Recommendation scoring still works because it inspects `Some(gpu).acceleration` and gracefully scores zero-bonus when `None`. See [`core-hardware-probe.md`](core-hardware-probe.md). - **`migration_v15` test exists but no migration v15 reverse path.** Migrations are append-only; the registry's contract is forward-only and idempotent. Reverting requires a fresh DB or a `DROP INDEX` migration v16. The contract is documented in [`storage-schema-and-migrations.md`](storage-schema-and-migrations.md). - **Default profile is enforced by SQL triggers, not by code.** `00000000-0000-0000-0000-000000000001` cannot be deleted or renamed, but if a future migration drops or alters the trigger names (`trg_protect_default_profile_delete`, `trg_protect_default_profile_rename`), the protection silently disappears. No regression test asserts the triggers still exist on the head schema; today the integration tests only assert the protection at DML time. - **Code-signing not configured.** Both macOS (Apple Developer ID) and Windows (code-signing certificate) are commented out in `build.yml`. Users hit Gatekeeper / SmartScreen on first run. Documented in [`ci-pipeline.md`](ci-pipeline.md). - **`run.sh` hard-codes a Fedora-style `LIBCLANG_PATH`.** The launcher exports `/usr/lib64/llvm21/lib64`, which is correct on Jake's Monolith but breaks on a Debian/Ubuntu dev box. Worth softening to a `LIBCLANG_PATH=${LIBCLANG_PATH:-/usr/lib64/llvm21/lib64}` form. ## See also - [Slice 1 — Frontend](../01-frontend/README.md) - [Slice 2 — Tauri runtime](../02-tauri-runtime/README.md) - [Slice 3 — Audio + transcription](../03-audio-transcription/README.md) - [Slice 4 — LLM, formatting, MCP](../04-llm-formatting-mcp/README.md)