agent: lumotia-rebrand — docs, scripts, root config, residuals
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

Phase 9 of the rebrand cascade. Sweep covers everything the Phase 8
frontend pass deliberately skipped: docs/, root markdown, scripts,
Cargo.toml descriptions, code comments that survived earlier
word-boundary sed, plus a handful of identifiers caught on the final
verify pass.

transcription-app changes:
- README.md, HANDOVER.md, KNOWN-ISSUES.md, run.sh — magnotia/Magnotia
  -> lumotia/Lumotia.
- docs/ — sweep across all subdirs except docs/handovers/ (preserved
  as immutable audit trail). Includes architecture-map references
  to magnotia_core::*, magnotia_storage::*, etc. now pointing at
  lumotia_*; dev-setup.md tracing output examples (lumotia_startup
  target); brief/ + superpowers/ + issues/ + whisper-ecosystem/ +
  audit/.
- Cargo.toml descriptions on 9 crates (core, audio, cloud-providers,
  hotkey, llm, mcp, plus referenced others).
- crates/core/src/{error,hardware,recommendation,paths}.rs +
  crates/audio/src/wav.rs + crates/llm/src/model_manager.rs +
  crates/cloud-providers/src/keystore.rs + crates/mcp/src/lib.rs —
  doc comments and a model-manager user-agent string.
- Caught on final pass: BroadcastChannel("magnotia_task_sync") -> ...
  ("lumotia_task_sync"); magnotia_locale i18n localStorage key
  renamed + migration shim added; CSS keyframe names
  magnotiaPulse / magnotiaBar / magnotiaFade renamed in the design-
  system kit; magnotia_viewer_item / magnotia_viewer_mode handoff
  keys renamed in HistoryPage + viewer/+page.svelte; src/assets/
  wordmark.svg text.
- src-tauri/src/lib.rs comment cleanup ("magnotia era" was sed'd
  to "lumotia era" earlier — restored).

Preserved (intentional):
- crates/core/src/paths.rs — keeps "magnotia" / "Magnotia" / ".magnotia"
  legacy detection strings in legacy_and_target_paths() so the
  migration shim can still find user data from the magnotia era.
- src/lib/stores/{page,focusTimer}.svelte.ts + src/lib/i18n/index.ts
  — migration call sites reference the legacy magnotia keys
  deliberately.
- docs/handovers/ — historical audit trail.

cargo build --workspace passes. npm run check: 0 errors / 0 warnings
(3958 files). cargo test --workspace: 339 pass / 0 fail.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-13 12:38:03 +01:00
parent 681a9b26dc
commit 26c7307607
213 changed files with 1175 additions and 1170 deletions

View File

@@ -87,7 +87,7 @@ tempfile = "3"
tauri = { version = "2", features = ["tray-icon"] }
tauri-plugin-global-shortcut = "2"
tauri-plugin-window-state = "2"
# Phase 5 rituals: register Magnotia as a login-time autostart entry.
# Phase 5 rituals: register Lumotia as a login-time autostart entry.
# Handles platform differences (.desktop file on Linux, LaunchAgents plist
# on macOS, registry Run key on Windows) behind a single API.
tauri-plugin-autostart = "2"

View File

@@ -1,7 +1,7 @@
fn main() {
// INTERIM: both llama-cpp-sys-2 and whisper-rs-sys statically link
// their own copy of ggml, so GNU ld / lld see duplicate symbols when
// linking the magnotia binary and its lib-tests. --allow-multiple-definition
// linking the lumotia binary and its lib-tests. --allow-multiple-definition
// makes the linker pick the first definition; safe while both crates
// pin compatible ggml revisions. Replace with a system-ggml shared-lib
// setup as a follow-up.
@@ -16,7 +16,7 @@ fn main() {
/// Regression guard for brief item #2 (pre-emptive loopback LLM scope).
///
/// Magnotia's bundled llama.cpp server and any BYO Ollama install speak HTTP
/// Lumotia's bundled llama.cpp server and any BYO Ollama install speak HTTP
/// on `127.0.0.1:*`. If the `connect-src` CSP ever drops those entries,
/// `fetch()` from the webview to the local LLM silently 404s with an
/// opaque scope error (Vibe #438 / #487). We keep the current permit

View File

@@ -1,6 +1,6 @@
# Windows bundle resources
Files in this directory ship side-by-side with `magnotia.exe` to avoid the
Files in this directory ship side-by-side with `lumotia.exe` to avoid the
DLL-hell failure modes reported in Whispering #840 / #829 and Buzz
#1459. They are **not** committed to the repo.

View File

@@ -65,7 +65,7 @@ fn recording_filename() -> String {
}
/// Process-lifetime monotonic counter for `recording_filename`. Starts
/// at 0 on each Magnotia launch; wall-clock secs/nanos still advance across
/// at 0 on each Lumotia launch; wall-clock secs/nanos still advance across
/// restarts, so cross-launch collisions are already impossible — the
/// counter is the last-mile guarantee against within-launch same-tick
/// collisions.

View File

@@ -1,7 +1,7 @@
//! Diagnostics: panic hook, frontend error capture, and the manual
//! diagnostic-report bundler used by Settings → About.
//!
//! Privacy posture (matches Magnotia's local-first positioning):
//! Privacy posture (matches Lumotia's local-first positioning):
//! - All capture is to disk only. Nothing is transmitted.
//! - The manual report bundler shows the user exactly what would be
//! shared and lets them choose to copy/save/email it.
@@ -49,7 +49,7 @@ pub fn install_panic_hook() {
let path = crashes_dir().join(format!("{ts}-{short:04x}.crash"));
let payload = format!(
"Magnotia crash dump\n\
"Lumotia crash dump\n\
==============\n\
Version: {ver}\n\
Timestamp: {ts} (UTC seconds)\n\
@@ -311,7 +311,7 @@ async fn generate_diagnostic_report_inner(
let opts = options.unwrap_or_default();
let mut out = String::new();
out.push_str("# Magnotia diagnostic report\n\n");
out.push_str("# Lumotia diagnostic report\n\n");
out.push_str(&format!("- Version: `{}`\n", LUMOTIA_VERSION));
out.push_str(&format!(
"- OS / arch: `{} / {}`\n",
@@ -405,7 +405,7 @@ async fn generate_diagnostic_report_inner(
if opts.include_log_tail {
out.push_str("## Log tail\n\n");
let log_path = logs_dir().join("magnotia.log");
let log_path = logs_dir().join("lumotia.log");
match read_tail(&log_path, 8000) {
Ok(tail) if tail.is_empty() => {
out.push_str("_(log file empty or not yet written)_\n\n");
@@ -421,7 +421,7 @@ async fn generate_diagnostic_report_inner(
out.push_str("---\n\n");
out.push_str(
"Generated by Magnotia. To share, copy the entire markdown above \
"Generated by Lumotia. To share, copy the entire markdown above \
and paste it into an email or issue. Email: jake@corbel.consulting.\n",
);

View File

@@ -358,7 +358,7 @@ impl LiveSessionRuntime {
let _ = self.status_channel.send(LiveStatusMessage::Overload {
session_id: self.session_id,
dropped_audio_ms: self.state.dropped_audio_ms,
message: "Magnotia dropped older audio to keep live dictation responsive".into(),
message: "Lumotia dropped older audio to keep live dictation responsive".into(),
});
}
@@ -660,7 +660,7 @@ fn run_live_session(
// is a no-op. Keeping the guard in scope ties the assertion's
// lifetime to the session — when the function returns, the Drop
// impl lifts it. Item #9 in docs/whisper-ecosystem/brief.md.
let _power_guard = PowerAssertion::begin("magnotia live dictation session");
let _power_guard = PowerAssertion::begin("lumotia live dictation session");
LiveSessionRuntime::new(
session_id,
engine,

View File

@@ -182,7 +182,7 @@ pub struct LlmTestResult {
/// The point is that the user sees "Not enough GPU memory — pick a
/// smaller tier" rather than a raw C++ exception bubbled up from
/// llama.cpp. Mirrors OpenWhispr's "Test connection" UX for cloud
/// LLMs, adapted to Magnotia's local stack.
/// LLMs, adapted to Lumotia's local stack.
#[tauri::command]
pub async fn test_llm_model(
window: tauri::WebviewWindow,
@@ -293,7 +293,7 @@ fn classify_llm_load_error(raw: &str) -> (&'static str, &'static str) {
} else if lower.contains("permission denied") || lower.contains("access is denied") {
(
"load-failed-permission",
"Permission denied reading the model file. Check ownership of ~/.magnotia/models/llm/.",
"Permission denied reading the model file. Check ownership of ~/.lumotia/models/llm/.",
)
} else {
(
@@ -391,7 +391,7 @@ pub async fn cleanup_transcript_text_cmd(
// macOS: pin a power assertion for the duration of the LLM
// generation so App Nap can't decide to throttle us mid-token.
// No-op on every other OS. Item #9.
let _power_guard = PowerAssertion::begin("magnotia LLM cleanup");
let _power_guard = PowerAssertion::begin("lumotia LLM cleanup");
llm_cleanup_text(&engine, &transcript, &profile_terms, resolved_preset)
})
.await
@@ -414,7 +414,7 @@ pub async fn extract_content_tags_cmd(
}
let engine = state.llm_engine.clone();
tokio::task::spawn_blocking(move || {
let _power_guard = PowerAssertion::begin("magnotia LLM content-tag extraction");
let _power_guard = PowerAssertion::begin("lumotia LLM content-tag extraction");
engine.extract_content_tags(&transcript)
})
.await

View File

@@ -94,7 +94,7 @@ pub fn load_model_from_disk(model_id: &ModelId) -> Result<Box<dyn Transcriber +
}
#[cfg(not(feature = "whisper"))]
Engine::Whisper => Err(format!(
"Whisper backend not compiled in this build (magnotia built without the \"whisper\" feature); \
"Whisper backend not compiled in this build (lumotia built without the \"whisper\" feature); \
cannot load {model_id}"
)),
Engine::Parakeet => {

View File

@@ -56,7 +56,7 @@ pub fn deliver_nudge(
app.notification()
.builder()
.title(if title.is_empty() { "Magnotia" } else { title })
.title(if title.is_empty() { "Lumotia" } else { title })
.body(body)
.show()
.map_err(|e| format!("notification delivery failed: {e}"))

View File

@@ -11,7 +11,7 @@
//! ydotool / osascript / SendKeys), so we probe and fall back.
//!
//! NOTE: focus must already be on the target window when the keystroke
//! fires. The global hotkey flow preserves this naturally; clicking Magnotia's
//! fires. The global hotkey flow preserves this naturally; clicking Lumotia's
//! window does not. The frontend surfaces this caveat next to the toggle.
use std::process::Command;
@@ -57,10 +57,10 @@ pub struct PasteOutcome {
/// focused window. Returns a structured result so the frontend can surface
/// partial success (clipboard set, paste failed).
///
/// Wayland compositor quirk: if Magnotia's always-on-top preview overlay is
/// Wayland compositor quirk: if Lumotia's always-on-top preview overlay is
/// visible when the keystroke fires, KWin / Mutter may resolve the keystroke
/// against the overlay (even with `focused: false` set at build time) and
/// the paste lands inside Magnotia instead of the previously-focused app. We hide
/// the paste lands inside Lumotia instead of the previously-focused app. We hide
/// the preview window and give the compositor a beat to re-focus the real
/// target before dispatching. Matches OpenWhispr's PR #246 fix on GNOME.
#[tauri::command]

View File

@@ -322,7 +322,7 @@ pub async fn decompose_and_store(
let engine = state.llm_engine.clone();
let parent_text = parent.text.clone();
let steps = tokio::task::spawn_blocking(move || {
let _power_guard = PowerAssertion::begin("magnotia LLM micro-step decomposition");
let _power_guard = PowerAssertion::begin("lumotia LLM micro-step decomposition");
engine.decompose_task_with_feedback(&parent_text, &examples)
})
.await
@@ -366,7 +366,7 @@ pub async fn extract_tasks_from_transcript_cmd(
let engine = state.llm_engine.clone();
tokio::task::spawn_blocking(move || {
let _power_guard = PowerAssertion::begin("magnotia LLM task extraction");
let _power_guard = PowerAssertion::begin("lumotia LLM task extraction");
engine.extract_tasks_with_feedback(&transcript, &examples)
})
.await

View File

@@ -203,7 +203,7 @@ pub async fn transcribe_file(
{
if duration_secs > MAX_FILE_TRANSCRIPTION_SECS {
return Err(format!(
"File is {:.1} hours long. Magnotia imports up to 2 hours at a time.",
"File is {:.1} hours long. Lumotia imports up to 2 hours at a time.",
duration_secs / 3600.0
));
}

View File

@@ -54,7 +54,7 @@ pub async fn open_task_window(app: tauri::AppHandle) -> Result<(), String> {
let mut builder =
WebviewWindowBuilder::new(&app, "tasks-float", WebviewUrl::App("/float".into()))
.title("Magnotia Tasks")
.title("Lumotia Tasks")
.inner_size(480.0, 520.0)
.min_inner_size(360.0, 480.0)
.always_on_top(true)
@@ -107,7 +107,7 @@ pub async fn open_preview_window(app: tauri::AppHandle) -> Result<(), String> {
"transcription-preview",
WebviewUrl::App("/preview".into()),
)
.title("Magnotia — Preview")
.title("Lumotia — Preview")
.inner_size(420.0, 200.0)
.min_inner_size(360.0, 140.0)
.max_inner_size(520.0, 360.0)
@@ -161,7 +161,7 @@ pub async fn open_viewer_window(app: tauri::AppHandle) -> Result<(), String> {
let mut builder =
WebviewWindowBuilder::new(&app, "transcript-viewer", WebviewUrl::App("/viewer".into()))
.title("Magnotia - Transcription Editor")
.title("Lumotia - Transcription Editor")
.inner_size(600.0, 700.0)
.min_inner_size(560.0, 520.0)
.decorations(use_native_decorations)

View File

@@ -141,7 +141,7 @@ fn warn_if_x11_env_unset_on_wayland() {
// burns ~10pp idle GPU and ~10pp idle CPU compared to the legacy
// renderer for no visible quality difference. Empirically (env-var
// matrix on Ryzen 5 4650U / Vega 6, May 2026) toggling this dropped
// magnotia idle CPU 12.30% → 2.80% of one core and idle GPU 17% → 10%.
// lumotia idle CPU 12.30% → 2.80% of one core and idle GPU 17% → 10%.
// Applies to both X11 and Wayland sessions; users can opt back in by
// setting WEBKIT_DISABLE_DMABUF_RENDERER=0 explicitly.
warn_if_unset(
@@ -224,7 +224,7 @@ pub fn run() {
builder
.setup(|app| {
// One-shot legacy data-dir migration: rename ~/.local/share/magnotia
// One-shot legacy data-dir migration: rename ~/.local/share/lumotia
// (and macOS/Windows equivalents) to the convention-preserving
// lumotia path on first launch after the rebrand. Idempotent —
// safe to call on every boot. A migration error is fatal: silently
@@ -238,7 +238,7 @@ pub fn run() {
from = %from.display(),
to = %to.display(),
renamed_db,
"migrated legacy magnotia data dir to lumotia"
"migrated legacy lumotia data dir to lumotia"
),
Ok(MigrationStatus::TargetAlreadyExists { .. }) => {}
Ok(MigrationStatus::NoLegacyFound) => {}
@@ -539,5 +539,5 @@ pub fn run() {
commands::update::check_for_update,
])
.run(tauri::generate_context!())
.expect("error while running Magnotia");
.expect("error while running Lumotia");
}

View File

@@ -4,7 +4,7 @@ use tauri::tray::TrayIconBuilder;
use tauri::{Emitter, Manager};
pub fn setup(app: &tauri::App) -> Result<(), Box<dyn std::error::Error>> {
let show = MenuItemBuilder::with_id("show", "Show Magnotia").build(app)?;
let show = MenuItemBuilder::with_id("show", "Show Lumotia").build(app)?;
let status = MenuItemBuilder::with_id("status", "Ready")
.enabled(false)
.build(app)?;
@@ -32,7 +32,7 @@ pub fn setup(app: &tauri::App) -> Result<(), Box<dyn std::error::Error>> {
let _tray = TrayIconBuilder::new()
.icon(icon)
.tooltip("Magnotia — Ready")
.tooltip("Lumotia — Ready")
.menu(&menu)
.on_menu_event(move |app, event| match event.id().as_ref() {
"show" => {