# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project Lumotia — a local-first, cognitive-load-aware dictation + task-capture desktop app. Tauri 2 + Svelte 5 frontend, Rust workspace backend. Pre-alpha, daily-dogfooded on Linux/Wayland (KDE). Full product context lives in [README.md](README.md) and [docs/brief/](docs/brief/); design principles are non-negotiable and codified in [docs/whisper-ecosystem/lumotia-context.md](docs/whisper-ecosystem/lumotia-context.md). ## Commands Dev launch (Vite + Tauri, with supply-chain pre-flight): ```bash ./run.sh # canonical; also: npm run dev:tauri npm run dev:frontend # frontend-only iteration, no Tauri ``` Install: `npm ci --ignore-scripts` (never bare `npm install` — `--ignore-scripts` blocks the npm-worm postinstall vector). Tests + checks: ```bash cargo test --workspace # all Rust tests (220+ lib, 67 Tauri-app) cargo test -p lumotia-transcription # single crate cargo test -p lumotia-llm # single test (substring match) cargo check --workspace --all-targets # what CI runs cargo fmt --check # release gate cargo clippy --workspace --all-targets -- -D warnings # release gate npm run check # svelte-check, jsconfig-driven npm run test # vitest (jsdom; *.test.ts beside source) npm run test -- src/lib/foo.test.ts # single vitest file ``` Release build: `npm run tauri build`. CI builds installers on tag push. Rebrand-migration end-to-end probe (Linux only — Tauri 2 ignores `HOME` overrides on macOS): ```bash cargo build -p lumotia scripts/dogfood-rebrand-drill.sh # sandbox mode scripts/dogfood-rebrand-drill.sh --against-real-home # refuses if lumotia data exists ``` ## Architecture (the parts to internalise before editing) Three layers, strict dependency direction: **Svelte (UI) → Tauri commands (OS bridge) → Rust crates (brain)**. The MCP server (`lumotia-mcp`) is a separate read-only binary that opens the same SQLite store — Lumotia-as-primitive for external agents. Rust workspace (`crates/*` + `src-tauri/`) holds all logic. Tauri command modules in [src-tauri/src/commands/](src-tauri/src/commands/) are thin adapters and should not contain business logic. The 22 command modules map roughly 1:1 to a subsystem (audio, llm, transcription, profiles, tasks, hotkey, paste, windows, …). The utility-only modules in the same directory (`mod`, `power`, `security`) carry no `#[tauri::command]` attribute — don't add them to the invoke handler. Engine abstractions: `LocalEngine` in `lumotia-transcription` wraps both Whisper (`whisper-rs`) and Parakeet (`transcribe-rs` ONNX) behind a common `Transcriber` trait. LLM surfaces (`cleanup_text`, `decompose_task`, `extract_tasks`) in `lumotia-llm` use GBNF grammars to guarantee parseable JSON. Prompt-injection-hardened cleanup prompt lives in `lumotia-ai-formatting::llm_client::CLEANUP_PROMPT`. Storage is SQLite via `sqlx` 0.8 in `lumotia-storage`, with FTS5 for transcript search. The MCP binary opens this store read-only. ### Frontend state model Svelte 5 runes (`$state`, `$derived`, `$effect`) — no Svelte 3/4 store API. State lives in [src/lib/stores/](src/lib/stores/), one file per store. The central store is [page.svelte.ts](src/lib/stores/page.svelte.ts) — transcripts, profiles, taskLists, templates, etc. are fields on it. Secondary windows (`/float`, `/viewer`, `/preview`) use named layouts (`+layout@.svelte`) to skip the main shell and run chrome-free. ### Wiring contracts (enforced socially, not by the compiler) - **Every new Tauri command** must be (a) implemented in `src-tauri/src/commands/.rs`, (b) registered in the invoke handler in [src-tauri/src/lib.rs](src-tauri/src/lib.rs), and (c) called from the frontend. Forgetting (b) is the most common breakage. - **Every Settings-visible setting** needs a type field in [src/lib/types/app.ts](src/lib/types/app.ts) and a default in [src/lib/stores/page.svelte.ts](src/lib/stores/page.svelte.ts). - **Every new workspace crate** needs a `description` in its `Cargo.toml`. - Smoke test per new command or crate module; workspace floor is "no regressions on main." ## Platform notes that affect code - **Wayland is a first-class target.** Don't assume X11. The preview overlay uses `WindowTypeHint::Utility`, never steals focus, is pinned across virtual desktops, and is hidden from Alt+Tab. The paste matrix (`wtype` / `xdotool` / `ydotool` on Linux, AppleScript on macOS, SendKeys on Windows) handles the focus-race against the overlay — see [src-tauri/src/commands/paste.rs](src-tauri/src/commands/paste.rs). - **Linux hotkey is evdev**, not `tauri-plugin-global-shortcut`. Implemented in `lumotia-hotkey`. Requires the user to be in the `input` group; the crate surfaces this as a clear error when `/dev/input/event*` is inaccessible. - **`run.sh` owns Linux rendering env vars** (`LIBCLANG_PATH`, `WEBKIT_DISABLE_DMABUF_RENDERER`, `GDK_BACKEND=x11` on Wayland to dodge a webkit2gtk issue). Anything that pre-checks these in `lib.rs` is checking what the launcher set, not the user's shell. - **CI runs on all three OSes** (`.github/workflows/`) — Linux/macOS/Windows. macOS and Windows are CI-validated but not runtime-tested; see [KNOWN-ISSUES.md](KNOWN-ISSUES.md) for tracked gaps (App Nap on Apple Silicon, idle-inhibit on X11/Linux, sleep prevention on Windows). ## Privacy invariants (non-negotiable) No voice, transcript, or task data leaves the machine unless the user explicitly sends it. No telemetry, no analytics, no crash-reporting service. Cleanup is **additive** — raw Whisper transcript must always be recoverable. LLM scope is narrow: transcription cleanup + task extraction only. Not a wake-word agent, not a chat UI, not a multi-provider cloud fan-out. If a change risks any of this, surface it before implementing. ## v0.1 release scope (active gate) The v0.1 ship gate lives in [docs/release/v0.1-checklist.md](docs/release/v0.1-checklist.md); the UI hardening boundary is pinned in [docs/release/v0.1-ui-hardening.md](docs/release/v0.1-ui-hardening.md). All release docs live under [docs/release/](docs/release/) — use that folder as the source of truth. Before adding a feature, check the **Out of scope for v0.1** list — reopening a v0.2-flagged item moves the ship date. Garden Inbox, full Settings 7-group regroup, OpenAI Whisper API BYOK, OEM verification, Obsidian plugin, and the Phase B filter-chain refactor are all explicitly v0.2+. The release acceptance test is the 10-step tester flow (install → onboarding → record → cleanup → task → MicroSteps + timer → history search). Warm activation target: first real recording within 3 minutes of opening the app. UI hardening is a *hardening* pass, not a redesign — every item must be testable, not aesthetic. ## Where to look first - Latest session context: [HANDOVER.md](HANDOVER.md), then dated handovers in [docs/handovers/](docs/handovers/). - Tracked limitations + per-step failure-mode catalogue: [KNOWN-ISSUES.md](KNOWN-ISSUES.md). - Per-platform dependency reference: [docs/dev-setup.md](docs/dev-setup.md). - Product/strategy framing: [docs/brief/](docs/brief/) — especially `what-lumotia-is.md`, `design-principles.md`, `target-audience.md`. - Active workstreams + 31-item research backlog: [docs/whisper-ecosystem/brief.md](docs/whisper-ecosystem/brief.md), `workstream-A.md`, `workstream-B.md`. - GPU tuning roadmap: [docs/gpu-tuning/plan.md](docs/gpu-tuning/plan.md).