Files
Lumotia/CLAUDE.md
Jake 3770815fbf
Some checks failed
check / cargo check (macos-latest) (push) Has been cancelled
check / cargo check (ubuntu-22.04) (push) Has been cancelled
check / cargo check (windows-latest) (push) Has been cancelled
check / svelte build + lint (push) Has been cancelled
agent: lumotia — v0.1 release-completion run
Closes the code-side v0.1 ship gate. All quality gates green:
cargo fmt/clippy/test (~327 tests), npm check (0/0), vitest 13/13,
scripts/dogfood-rebrand-drill.sh 8/8.

Phase F — first-run onboarding promoted to v0.1
- FirstRunPage with skip-to-main + failure recovery + event recording
- Six onboarding commands (record/list/has-completed + lumotia_events)
- Storage migration v17 (onboarding_events + lumotia_events tables)

UI hardening (in-scope items from v0.1-ui-hardening.md)
- StatusPill + PostCaptureCard components, 21st preview entry
- Sidebar recording-as-sacred-state (opacity + aria-disabled, reduced-motion)
- Settings 6-section regroup + Help section + Activation log + Privacy toggle
- Error-state copy sweep (DictationPage + SettingsPage, plain-language)
- Global :focus-visible rule, textarea outlines restored
- Ctrl+K / Ctrl+, / Escape bindings in +layout

LLM resilience
- rule_based_extract_tasks (regex-free imperative-verb extractor) +
  extract_tasks_with_fallback wrapper — task extraction never returns zero
- tokio::time::timeout(120s) wraps cleanup/tags/tasks commands

Release artefacts
- LICENSE (canonical AGPL-3.0), CHANGELOG (Keep-a-Changelog format)
- v0.1-release-notes, privacy-and-ai-use, install-warnings,
  tester-onboarding-kit, tester-acceptance-runbook, code-signing-setup,
  apple-silicon-rb08-runbook, virtual-audio-setup, v0.1-contrast-audit
- Workspace versioning + AGPL spdx; npm exact-pin (10 ranges removed)
- AppImage SHA-256 sidecar in build.yml
- README v0.1 section + Reporting-issues; canonical repo slug

Closure pass — items moved from human-required to code-complete
- KI-02 Linux idle inhibit: zbus 5 → org.freedesktop.login1.Manager.Inhibit
- KI-03 Windows sleep prevention: SetThreadExecutionState(ES_CONTINUOUS|...)
- acquire/release_idle_inhibit Tauri commands, wired in DictationPage
- Diagnostic-bundle frontend wire-up (Settings → Help button)
- WCAG-AA contrast fix via .btn-filled-text utility (no token changes)
- 8 destructive-action sites wrapped in plain-language confirm() guards
- KNOWN-ISSUES.md + v0.1-known-limitations.md updated (KI-02/03 fixed)

Scripts
- pre-tag-verify.sh, tag-day.sh, smoke-linux + driver
- parse-diagnostic-bundle.sh, parse-activation-log.py

Per-item audit trail: docs/release/v0.1-completion-status.md
Remaining: W-01…W-08 (signing certs, hardware probes, smoke matrix,
tester recruitment) — see docs/release/v0.1-known-limitations.md.
2026-05-15 06:59:08 +01:00

7.5 KiB

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 and docs/brief/; design principles are non-negotiable and codified in docs/whisper-ecosystem/lumotia-context.md.

Commands

Dev launch (Vite + Tauri, with supply-chain pre-flight):

./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:

cargo test --workspace                          # all Rust tests (220+ lib, 67 Tauri-app)
cargo test -p lumotia-transcription             # single crate
cargo test -p lumotia-llm <test_name>           # 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):

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/ 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/, one file per store. The central store is 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/<module>.rs, (b) registered in the invoke handler in 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 and a default in 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.
  • 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 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; the UI hardening boundary is pinned in docs/release/v0.1-ui-hardening.md. All release docs live under 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