Jake 6881aa800a v0.3 Phase 4l: semantic palette revision — Tiger Flame / Banana Cream / Sea Green / Steel Azure
Wren palette pass on 2026/05/15. Splits the role tokens away from
the prior bright/neon set toward a more grounded warm-and-cool
quartet, with explicit FILL + TEXT (signal + ink) pairs in light
mode so AA-on-cream stays cheap to consume.

Dark mode signals
  --color-info-signal     #6EA8FF  →  #064789  Steel Azure
  --color-danger-signal   #FF5A52  →  #F26430  Tiger Flame
  --color-success-signal  #00FF56  →  #519872  Sea Green
  --color-caution-signal  #FFCD00  →  #FCEC52  Banana Cream

Light mode (FILL = signal, TEXT = ink)
  --color-info-signal     #000AFF  →  #217AD5  +ink #1F73C9
  --color-danger-signal   #FF0700  →  #D55121  +ink #C54B1F
  --color-success-signal  #00D94A  →  #21D575  +ink #148348
  --color-caution-signal  #FFCD00  →  #D5A021  +ink #7E7414

Unchanged on purpose
  --color-bg              Coffee Bean #1F0812 was tried live and
                          rejected — R/G/B channels (31/8/18) read
                          as aubergine, not brown. Bg + grain held
                          at #12100E / 0.06 pending a true warm-brown
                          candidate.
  --color-*-border        Hue family unchanged from Phase 4j.
  --color-*-bg            Hand-tuned surface tints unchanged.
  HC variants             Out of scope for this pass.

Known issue
  Steel Azure #064789 on the dark bg sits around 2.06:1 — fails AA
  as text/icon. The role-token model has --color-info-ink (currently
  #9CC6FF, light blue) for that use case, but consumers reaching for
  --color-info-signal directly will read muddy. Retune of the info
  ink/signal split is owed separately. Documented inline.

npm run check: 0 errors.
2026-05-15 21:18:43 +01:00

Lumotia

Think out loud. Keep working.

Lumotia is a local-first, cognitive-load-aware dictation and task-capture desktop app. Every transcription, LLM cleanup, and task extraction runs on the user's machine. No telemetry, no analytics, no cloud dependency. The app is designed around a single observation: people who think in bursts lose ideas faster than they can type, and the tool's job is to get out of the way.


Status

Status: v0.1 release candidate. See docs/release/ for the ship checklist + known limitations. Actively dogfooded on Linux (KDE Plasma 6 on Wayland). macOS and Windows targets are in scope and exercised by CI, but not yet beta-ready.

  • Current main: see commit log
  • 9 library crates plus the Tauri app crate; 220+ lib tests plus 67 Tauri-app tests, all passing
  • Cross-platform CI (Linux / macOS / Windows) via GitHub Actions
  • Tracked limitations live in KNOWN-ISSUES.md

Design principles (non-negotiable)

  1. Local-first is the floor, not a feature. No voice, transcript, or task ever leaves the user's machine unless they explicitly send it. No telemetry.
  2. Cognitive load is the limiting resource. Every new setting must earn its mental real estate. Every interaction should reduce, not add, decisions.
  3. Composable, not monolithic. Lumotia is a dictation primitive: via MCP, CLI, and filesystem export, it slots into whatever workflow the user already has (Obsidian, Claude Desktop, Cline, any text field).
  4. LLM scope is narrow. The in-app LLM does transcription cleanup and task extraction. It is not a wake-word agent, not a chat UI, not a multi-provider cloud fan-out.
  5. Raw transcript is always recoverable. Cleanup is additive, never destructive. The user can always see and revert to what Whisper heard.

These are enforced in the codebase (where practical) and in the docs under docs/whisper-ecosystem/lumotia-context.md.


What Lumotia does today

Speech-to-text

  • Vulkan-accelerated local Whisper inference via whisper-rs 0.16 + whisper.cpp. Works on NVIDIA, AMD, Intel Arc, Apple (via MoltenVK), and integrated graphics.
  • Vulkan / CUDA-accelerated Parakeet inference via sherpa-onnx (NVIDIA's English-only model; lower latency than Whisper-Large on English).
  • Six Whisper variants shipped: Tiny, Base, Small, Distil-Small, Medium, Distil-Large v3.
  • Parakeet-as-default for English when hardware supports it; first-run hardware probe picks the fastest-accurate pair.
  • Resumable downloads with SHA-256 verification; retains audio if transcription fails.
  • Per-profile custom vocabulary fed to Whisper as initial_prompt plus to the LLM cleanup prompt; bulk import via paste.
  • Live streaming transcription with speech-gated chunking, hallucination filtering, and duplicate-boundary detection.

LLM formatting (local only)

  • Local LLM runtime via llama-cpp-2 0.1.144 with Vulkan.
  • Four Qwen tiers (Qwen3.5 2B / 4B / 9B + Qwen3.6 27B) auto-selected by hardware probe.
  • GBNF grammar-constrained output for task extraction (always-parseable JSON).
  • System prompt hardened against voice-delivered prompt injection.

Task capture

  • Automatic task extraction from any transcript.
  • MicroSteps — one-tap "break this task into 37 concrete physical actions."
  • Profile-scoped task lists with inbox / today / soon / later buckets.
  • Tasks back-link to their source transcript.

Input, paste, and window management

  • Global hotkey — evdev-based on Linux (Wayland-compatible out of the box), tauri-plugin-global-shortcut on macOS / Windows. Per-OS capability matrix rejects invalid key combinations.
  • Platform-aware paste matrixwtype / xdotool / ydotool on Linux, AppleScript on macOS, SendKeys on Windows. Clipboard snapshot + 300 ms restore after paste.
  • Wayland-hardened transcription preview overlay (/preview): pinned across virtual desktops, hidden from Alt+Tab via WindowTypeHint::Utility, never steals focus, focus-gated open.
  • Meeting auto-capture (opt-in, default off): single-signal process-list watcher, user-editable app list, surfaces a non-modal reminder. No mic-activity heuristics, no calendar integration.
  • FTS5-indexed transcript search over SQLite.
  • YAML-frontmatter markdown export one-click into Obsidian vault.
  • Per-transcript metadata: starred, manual tags, template, language, duration.
  • Transcript editor window (/viewer) with debounced autosave.

External integration

  • MCP stdio server (Lumotia-mcp) exposing read-only transcripts and tasks to any Model Context Protocol client (Claude Desktop, Cline, Cursor, etc.). No authentication, read-only, local-only.

Accessibility

  • Dyslexia-friendly fonts bundled: Lexend, Atkinson Hyperlegible Next, OpenDyslexic.
  • Bionic reading mode.
  • Per-region font size, letter spacing, line height, transcript-specific sizing.
  • System-aware reduce-motion.
  • i18n: English, Spanish, German (svelte-i18n scaffold).

Privacy, deployment, reliability

  • Zero telemetry. Zero analytics. No crash reports leave the machine unless explicitly bundled.
  • Auto-update via Tauri updater plugin (signed, user-approved).
  • Per-window size + position persistence (tauri-plugin-window-state).
  • Crash + panic capture stored locally; user-bundleable for support.

Architecture

Lumotia is a Tauri 2 desktop app with three layers:

┌─────────────────────────────────────────────────────────────────┐
│  Svelte 5 frontend (src/)                                       │
│  Routes: /, /float, /viewer, /preview                           │
│  Stores, i18n, Tailwind CSS                                     │
├─────────────────────────────────────────────────────────────────┤
│  Tauri 2 runtime (src-tauri/)                                   │
│  Commands: audio, clipboard, diagnostics, feedback, fs,         │
│            hardware, hotkey, intentions, live, llm, meeting,    │
│            models, nudges, paste, profiles, rituals, tasks,     │
│            transcription, transcripts, tts, update, windows     │
│  Utility modules (no commands): mod, power, security            │
│  Plugins: global-shortcut, dialog, opener, updater,             │
│           window-state                                          │
├─────────────────────────────────────────────────────────────────┤
│  Rust workspace (crates/)                                       │
│  Lumotia-core, Lumotia-audio, Lumotia-transcription, Lumotia-llm,               │
│  Lumotia-ai-formatting, Lumotia-storage, Lumotia-hotkey,                    │
│  Lumotia-cloud-providers, Lumotia-mcp                                   │
└─────────────────────────────────────────────────────────────────┘

The Rust workspace is the brain; Tauri is the OS integration surface; Svelte is the UI. The MCP server (Lumotia-mcp) is a separate binary that opens Lumotia's SQLite store read-only — it's Lumotia-as-primitive for external agents.

Repository layout

Lumotia/
├── Cargo.toml              # workspace root
├── src-tauri/              # Tauri app (main binary + commands)
│   ├── src/
│   │   ├── commands/       # 22 Tauri command modules + 3 utility modules (`mod`, `power`, `security`)
│   │   ├── lib.rs          # app entry, setup, command registration
│   │   ├── tray.rs
│   │   └── main.rs
│   ├── capabilities/       # Tauri ACL capability files
│   ├── gen/schemas/        # auto-generated ACL schemas
│   ├── tauri.conf.json     # base Tauri config
│   ├── tauri.linux.conf.json  # Linux overlay (native decorations)
│   └── resources/windows/  # Windows-specific bundled assets
├── crates/                 # workspace Rust crates
│   ├── ai-formatting/      # post-processing pipeline + LLM cleanup client
│   ├── audio/              # capture, resampling, decoding, WAV I/O
│   ├── cloud-providers/    # BYOK cloud STT stubs (empty scaffolding)
│   ├── core/               # types, hardware probe, model registry, process watch
│   ├── hotkey/             # Linux evdev hotkey listener
│   ├── llm/                # llama-cpp-2 engine + model manager
│   ├── mcp/                # MCP stdio server binary
│   ├── storage/            # SQLite + FTS5 + file storage
│   └── transcription/      # Whisper + Parakeet wrappers, model mgmt
├── src/                    # Svelte frontend
│   ├── routes/             # SvelteKit routes
│   │   ├── +page.svelte    # main dictation UI
│   │   ├── +layout.svelte  # shell (sidebar, tray sync, hotkey wiring)
│   │   ├── float/          # tasks float window
│   │   ├── viewer/         # transcript editor window
│   │   └── preview/        # transcription preview overlay
│   ├── lib/
│   │   ├── pages/          # DictationPage, SettingsPage, HistoryPage, TasksPage, FilesPage, FirstRunPage
│   │   ├── components/     # reusable Svelte components
│   │   ├── stores/         # $state stores (page, preferences, profiles, toasts)
│   │   ├── actions/        # Svelte actions (bionic reading, etc.)
│   │   ├── utils/          # frontmatter, textMeasure, errors, storage helpers
│   │   ├── types/          # TS type definitions
│   │   └── i18n/           # svelte-i18n setup + en/es/de locales
│   ├── fonts/              # bundled accessibility fonts
│   ├── design-system/      # design tokens + UI kit references (not live code)
│   └── app.css
├── docs/                   # all project documentation (see below)
├── .github/workflows/      # CI (check.yml, build.yml)
├── package.json
├── HANDOVER.md             # latest session handover
└── run.sh                  # dev launcher (starts Vite then Tauri)

Rust crates

Crate Responsibility
Lumotia-core Shared types (Segment, Transcript, Megabytes, ModelId), constants, the Engine / SpeedTier / AccuracyTier enums, hardware probe (sysinfo-based), model registry (Whisper + Parakeet entries), hardware-aware recommendation scoring, process_watch for meeting detection.
Lumotia-audio cpal-based microphone capture with device hotplug + error forwarding, VAD, rubato streaming resampler to 16 kHz mono, symphonia file decoding, hound WAV I/O.
Lumotia-transcription whisper-rs backend (WhisperRsBackend) that owns a WhisperContext and supports set_initial_prompt. LocalEngine wraps both Whisper and Parakeet (via transcribe-rs ONNX) behind a common Transcriber trait. Streaming primitives (VadChunker, LocalAgreement, buffer trim) live in the streaming/ module. Model manager handles downloads, paths, and disk checks.
Lumotia-llm llama-cpp-2 engine with a four-tier Qwen3.5 / Qwen3.6 model manager. Three high-level surfaces: cleanup_text (formatting), decompose_task (37 micro-steps, GBNF-constrained JSON array), extract_tasks (optional-array, GBNF-constrained). Resumable HTTP downloads with SHA-256 verify.
Lumotia-ai-formatting Post-processing pipeline: filler removal, British English conversion, anti-hallucination filter, smart paragraph breaks on long pauses, optional LLM cleanup. Also hosts the llm_client::CLEANUP_PROMPT constant (prompt-injection-hardened).
Lumotia-storage SQLite via sqlx 0.8. Migrations, CRUD for transcripts / tasks / subtasks / profiles / profile terms / settings / error log, FTS5 search, file-storage paths.
Lumotia-hotkey Linux evdev hotkey listener with device hotplug. Parses Tauri-style hotkey strings (Ctrl+Shift+R), emits Pressed / Released events. Works natively on Wayland (no X11 dependency). Checks /dev/input/event* access on startup; surfaces a clear "add yourself to the input group" error when missing.
Lumotia-cloud-providers BYOK cloud-STT provider stubs. Currently empty scaffolding. When populated: OpenAI-compatible endpoint + Anthropic (ceiling for scope).
Lumotia-mcp Standalone Lumotia-mcp binary implementing the MCP stdio protocol (2024-11-05). Read-only tools: list_transcripts, get_transcript, search_transcripts, list_tasks. Opens Lumotia's SQLite store.

Tauri commands (src-tauri/src/commands/)

Module What it exposes
audio Device enumeration, native capture start/stop, audio-samples persistence
clipboard Cross-platform clipboard write (arboard)
diagnostics Panic hook, frontend error log, crash file listing, diagnostic report bundler
feedback Thumbs / correction capture on AI-generated output; few-shot example store for prompt conditioning
fs Thin filesystem write for the OS save-dialog path (UTF-8 text, dialog-constrained)
hardware probe_system, rank_models
hotkey start_evdev_hotkey, update_evdev_hotkey, stop_evdev_hotkey, check_hotkey_access, is_wayland_session
intentions Implementation-intention rule CRUD (if-then automation: time-of-day, task-completed, morning-triage triggers)
live Live streaming transcription session lifecycle + speech-gate tuning
llm Tier recommend, model check / download / load / unload / delete, status, cleanup_transcript_text_cmd, extract_tasks_from_transcript_cmd
meeting detect_meeting_processes (process-list poll)
models Whisper + Parakeet model download / load / check / default-id resolution, runtime capabilities API, pre-warm
nudges Margot soft-touch nudge delivery via tauri-plugin-notification; main-window-only guard
paste paste_text (copy + keystroke), detect_paste_backends, Wayland focus-race mitigation against the preview overlay
profiles Profile CRUD, profile-terms CRUD, learn-terms-from-edit
rituals Start- and shutdown-ritual sentinels (last-shown date for the morning-triage modal)
tasks Task CRUD, subtask CRUD, decompose_and_store, extract_tasks_from_transcript_cmd
transcription transcribe_pcm, transcribe_file, transcribe_pcm_parakeet
transcripts Transcript CRUD + FTS5 search
tts Platform-native Read Page Aloud (spd-say / say / PowerShell), with cancellable child-process tracking
update Tauri-plugin-updater check / install
windows open_task_window, open_viewer_window, open_preview_window, close_preview_window

Utility modules in the same directory (no #[tauri::command] attributes; helpers consumed by the command modules above): mod (registry), power (macOS PowerAssertion guard against App Nap during long sessions), security (ensure_main_window guard).

Frontend (src/)

  • SvelteKit + Svelte 5 runes ($state, $derived, $effect).
  • Tailwind CSS 4 for styling, with a Lexend/Atkinson/OpenDyslexic type system.
  • Secondary windows (/float, /viewer, /preview) use named layouts (+layout@.svelte) to skip the main shell and run chrome-free.
  • Reactive stores (src/lib/stores/, one file per store): page.svelte.ts (central app state; transcripts, profiles, taskLists, templates, etc. live as fields here), preferences.svelte.ts, profiles.svelte.ts, toasts.svelte.ts, focusTimer.svelte.ts, llmStatus.svelte.ts, nudgeBus.svelte.ts, implementationIntentions.svelte.ts, completionStats.svelte.ts, speaker.svelte.ts.
  • i18n: svelte-i18n with en/es/de locales at src/lib/i18n/locales/. Scaffolding only — strings migrate to translation keys incrementally.

Runtime stack

Layer Technology Version
Desktop framework Tauri 2.10.3
Frontend Svelte 5 + SvelteKit + Vite latest
Styling Tailwind CSS 4.x
Speech-to-text (primary) whisper.cpp via whisper-rs 0.16 (Vulkan feature)
Speech-to-text (Parakeet) sherpa-onnx via transcribe-rs 0.3
Local LLM llama-cpp-2 0.1.144 (openmp + vulkan)
Database SQLite via sqlx 0.8
Async runtime tokio 1.x
Audio capture cpal current
Resampling rubato current
File decode symphonia current

Platform support

Platform Status Notes
Linux Wayland (KDE Plasma, GNOME Mutter, Hyprland, Sway) Primary target, daily-dogfooded on KDE evdev hotkey, GTK 3 via webkit2gtk, Vulkan, all paste backends; idle inhibit not wired (see KI-02)
Linux X11 Supported xdotool paste path, GTK 3; idle inhibit not wired (see KI-02)
macOS In CI, untested runtime osascript paste, Metal via MoltenVK, App Nap guard pending Apple Silicon verification (see KI-01)
Windows In CI, untested runtime SendKeys paste, Vulkan-first GPU path, bundled DLLs for CPU fallback; sleep prevention not wired (see KI-03)

CI runs cargo check --workspace --all-targets + svelte-check on all three on every push and PR.


Build + development

Prerequisites

Linux (Fedora/RHEL listed; adjust for your distro):

sudo dnf install libclang-devel clang \
    webkit2gtk4.1-devel libappindicator-gtk3-devel librsvg2-devel \
    alsa-lib-devel systemd-devel cmake \
    vulkan-headers vulkan-loader-devel glslc

macOS:

brew install cmake llvm vulkan-headers vulkan-loader molten-vk shaderc

Windows:

choco install cmake llvm vulkan-sdk

See docs/dev-setup.md for the authoritative per-platform dependency list and for how LIBCLANG_PATH should be set.

Installing npm dependencies

Use npm ci --ignore-scripts rather than bare npm install. --ignore-scripts blocks the postinstall script vector that npm-worm attacks (Shai-Hulud, mini-Shai-Hulud) rely on. ci installs strictly from package-lock.json, refusing to mutate the lockfile silently.

npm ci --ignore-scripts

run.sh runs npm audit signatures automatically whenever package-lock.json is newer than the last successful audit, and refuses to launch on signature mismatch. Skip with LUMOTIA_SKIP_AUDIT=1 for offline dev.

Dev launch

Canonical full-stack dev launch — starts Vite, waits for port 1420, then launches Tauri:

npm run dev:tauri

Direct shell equivalent:

./run.sh

For pure frontend iteration without Tauri:

npm run dev:frontend

Build

npm run tauri build    # release build, produces .AppImage / .deb / .dmg / .msi / .exe

CI also builds release installers on tag push (see .github/workflows/build.yml).

Testing

cargo test --workspace          # all Rust tests (lib + integration)
npm run check                   # svelte-check (type-checks .svelte files)
npm run test                    # vitest run (frontend unit tests)
npm run test:watch              # vitest watch mode
cargo check --workspace --all-targets

Frontend test files live alongside source (src/**/*.test.ts) and run in jsdom by default. See vite.config.js for the vitest configuration.

Rebrand-migration dogfood drill

End-to-end probe that launches the real target/debug/lumotia binary against synthetic legacy magnotia state planted on disk, then verifies both migration paths produced the expected on-disk outcome.

cargo build -p lumotia                          # need the binary first
scripts/dogfood-rebrand-drill.sh                # sandbox mode (Linux only)
scripts/dogfood-rebrand-drill.sh --keep         # leave sandbox dir for inspection
scripts/dogfood-rebrand-drill.sh --against-real-home  # run against real $HOME

Sandbox mode is faithful only on Linux — Tauri 2 on macOS uses NSSearchPathForDirectoriesInDomains which ignores HOME overrides. The drill refuses to start in sandbox mode on macOS. Real-home mode refuses to start if any lumotia data already exists at your real paths, so it can roll back cleanly on exit.


Project documentation

Beyond this README, the repo ships extensive internal documentation:

Product + strategy — docs/brief/

Research briefs, competitive analysis, and strategic framing. Start with:

Brand — docs/brand/

Technical research — docs/whisper-ecosystem/

Cross-repo survey of 10 OSS Whisper projects, the Lumotia-specific atomic task backlog, and the two Cursor workstream plans.

GPU tuning — docs/gpu-tuning/

  • plan.md — MVP plan for GGML env-var panel + Lumotia-bench auto-tuner + Lumotia-configs community repo

Session handovers

  • HANDOVER.md — latest session summary
  • Dated historical handovers under docs/handovers/: HANDOVER-2026-04-17.md, HANDOVER-2026-04-18.md, HANDOVER-2026-04-19.md, HANDOVER-2026-04-24.md

Dev reference


Roadmap

The shipped code represents Phases 13 and a partial Phase 4.

Pinned roadmap items (scoped in docs and session memory):

  • Phase 4 — remaining items from workstream-A.md + workstream-B.md
  • Voice calibration — three-tier plan replacing the hardcoded speech-gate with per-user baselines
  • GPU community tuning — see docs/gpu-tuning/plan.md; five-phase roadmap from settings panel to agentic auto-tuner + community config repo
  • Cloud endpoint contract test — when Lumotia-cloud-providers grows a real provider
  • ggml dedup — replace the interim -Wl,--allow-multiple-definition link flag with a proper shared-lib setup; unblocks custom shader / backend work
  • Mobile (iOS / Android) — long-horizon, gated on the single-binary Rust stack scaling

Explicitly shelved (not coming without specific community signal):

  • Wake-word / always-listening agent
  • Chat-style LLM UI
  • Multi-provider cloud fan-out beyond OpenAI-compatible + Anthropic
  • Second notes-editing surface (transcripts leave Lumotia via frontmatter to Obsidian)
  • Speaker diarization
  • Dragon-style passage-based speaker fine-tuning (Whisper has no speaker adaptation)

Contributing

Pre-alpha status; contribution process TBD before public beta. For now:

  • Every Tauri command change must register in both src-tauri/src/lib.rs (invoke handler) and in the invoking frontend code.
  • Every Settings-visible setting must have 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.
  • Tests: add at least a smoke test per new Tauri command or crate module. The workspace test floor is "no regressions on main."
  • Wayland compatibility is a first-class concern — don't assume X11. The preview overlay and paste matrix live-document what this looks like in practice.

Licence

AGPL-3.0-or-later. See LICENSE for the full text. The implementation is AI-assisted; the trust + audit framing is in docs/release/how-lumotia-is-built.md.


Reporting issues

File issues at https://github.com/jakeadriansames/lumotia/issues — please include your platform, the Lumotia version (Settings → About), what you did, what you expected, and what actually happened. Crash dumps live at <app-data-dir>/crashes/; attaching the most recent one helps a lot.


Contact

Jake Samesjakeadriansames@gmail.com Repo: github.com/jakejars/Lumotia · git.corbel.consulting/jake/Lumotia

Description
No description provided
Readme AGPL-3.0 12 MiB
Languages
Rust 56.1%
Svelte 26.8%
TypeScript 7.8%
Shell 3.2%
HTML 2.4%
Other 3.7%