Codex independent review found 11 blockers post-cascade. All addressed.
CRITICAL (data-loss / crash):
10. crates/core/src/paths.rs — migrate_legacy_data_dir_inner used
fs::rename which fails with EXDEV when source + target are on
different filesystems (encrypted-home, bind mounts, separate
$XDG_DATA_HOME partition). Combined with the Phase 5 QC fix that
made migration errors fatal, this would crash on first launch
for any user whose data dir spans filesystems. Added
rename_or_copy_tree() that falls back to copy_dir_recursive +
remove_dir_all on CrossesDevices / errno 18 (EXDEV). Symlinks
preserved verbatim. Same fallback applied to magnotia.db ->
lumotia.db inside the dir.
11. Added 4 unit tests: copy_dir_recursive preserves nested
structure, rename_or_copy_tree same-filesystem happy path,
is_cross_device classifies CrossesDevices kind + raw errno 18.
Doc residuals (blockers 1-9):
1. crates/cloud-providers/Cargo.toml — "Wyrdnote pending rebrand"
description.
2. crates/cloud-providers/src/provider.rs — module docs + test
fixture Wyrdnote refs.
3. crates/transcription/src/orchestrator.rs — module docs + test
fixture Wyrdnote refs.
4. docs/roadmap/2026-05-10-pkm-phase-tooling-shortlist.md — phase
name + outputs/wyrdnote path refs.
5. docs/architecture-map/04-llm-formatting-mcp/llm-tests.md —
MAGNOTIA_LLM_TEST_MODEL env var.
6. .../cloud-providers-stubs.md — MAGNOTIA_API_KEY_*.
7. docs/architecture-map/03-audio-transcription/tests-and-fixtures.md
— MAGNOTIA_WHISPER_*.
8. docs/gpu-tuning/plan.md — MAGNOTIA_BENCH_RUN.
9. docs/superpowers/specs/2026-05-09-battery-gpu-aware-thread-tuning-
design.md + corresponding plan — MAGNOTIA_POWER_STATE_OVERRIDE,
MAGNOTIA_INFERENCE_THREADS.
cargo test --workspace: 343 pass / 0 fail (up from 339; +4 EXDEV
fallback tests).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
name, type, slice, last_verified
| name | type | slice | last_verified |
|---|---|---|---|
| Slice 4 — LLM, AI Formatting, MCP, Cloud Providers | architecture-map-page | 04-llm-formatting-mcp | 2026/05/09 |
Slice 4: LLM, AI Formatting, MCP, Cloud Providers
Where you are: Architecture map → LLM, Formatting, MCP
Plain English summary. This slice covers how Lumotia turns raw audio output into clean prose, surfaces the local LLM that powers cleanup and task extraction, exposes the user's transcripts to external agents over MCP, and reserves a stub crate for future bring-your-own-key cloud providers. Four crates, all on the inference / post-processing edge of the app.
At a glance
- Crates: four.
lumotia-llm,lumotia-ai-formatting,lumotia-mcp(binary + lib),lumotia-cloud-providers. - Total LOC: ~3,520 (LLM 1,250, formatting 1,290, MCP 580, cloud-providers 80).
- llama-cpp-2 version:
0.1.144(default features off, thenvulkanandopenmpre-enabled by Cargo features). - MCP protocol version:
2024-11-05, JSON-RPC 2.0 over stdio. - Model registry: four-tier Qwen3.5 / Qwen3.6 family (2B / 4B / 9B / 27B, all Q4_K_M GGUF) with resumable HTTP download and SHA-256 verification.
- Three high-level LLM surfaces:
cleanup_text(freeform),decompose_task(3–7 micro-steps under GBNF),extract_tasks(optional array under GBNF). Plus the Phase 9extract_content_tags(one{topic, intent}pair under a closed-set GBNF). - Formatting pipeline stages: anti-hallucination filter → filler removal → British English conversion → repetition collapse and basic capitalisation → smart paragraph breaks on long pauses → optional LLM cleanup with prompt-injection-hardened system prompt.
- MCP tools:
list_transcripts,get_transcript,search_transcripts,list_tasks. Read-only at the SQLite connection layer. - Cloud providers: scaffolding only. A process-local API key store with
MAGNOTIA_API_KEY_<PROVIDER>env-var fallback. No transports, no STT calls.
Map of this slice
LLM crate:
- LLM engine and llama-cpp-2 lifecycle
cleanup_textsurfacedecompose_tasksurfaceextract_taskssurfaceextract_content_tagssurface- Prompts and grammars catalogue
- Model manager (four-tier Qwen, downloads, SHA verification)
- Cargo features (gpu-vulkan, openmp)
- Tests (smoke, content_tags_smoke, gating)
AI formatting crate:
- Pipeline overview
- Filler removal and British English
- Anti-hallucination filter
- Plain-text pre-formatter for LLM cleanup
- LLM cleanup bridge (
llm_client) - Correction learning (HITL → custom dictionary)
MCP crate:
Cloud providers crate:
How this slice connects to others
- From slice 3 (audio + transcription): transcription emits
Vec<Segment>(alumotia-core::types::Segment).lumotia-ai-formatting::pipeline::post_process_segmentsis the immediate consumer. Slice 4 has no compile-time dependency on the transcription crates; the contract is theSegmenttype alone. - To slice 4 internally:
lumotia-ai-formattingdepends onlumotia-llm, never the other way. The LLM cleanup bridge (llm_client) lives in the formatting crate so the LLM crate stays free of post-processing concerns. - From slice 5 (core, storage, hotkey, build):
lumotia-llmconsumeslumotia_core::tuning::{inference_thread_count, Workload}for thread sizing andlumotia_core::paths::app_paths().llm_models_dir()for the on-disk model store.lumotia-ai-formattingconsumeslumotia_core::types::Segmentandlumotia_core::constants::SMART_PARAGRAPH_GAP_SECS.lumotia-mcpopenslumotia_storage::database_path()vialumotia_storage::init_readonly()and callslist_transcripts,get_transcript,search_transcripts,list_tasksfromlumotia_storage. - To slice 2 (Tauri runtime): the Tauri commands at
src-tauri/src/commands/llm.rs,src-tauri/src/commands/tasks.rs,src-tauri/src/commands/transcription.rs,src-tauri/src/commands/live.rs,src-tauri/src/commands/profiles.rs, andsrc-tauri/src/commands/models.rsare the only callers of this slice's public surfaces from inside the Tauri process. Each per-surface page lists its best-guess Tauri command for slice 2 reconciliation.
Existing in-repo docs
docs/issues/llm-prompt-preflight.md— RB-10 release-blocker write-up for the prompt token-budget preflight inLlmEngine::generate. Resolved 2026-04-22. Cross-referenced fromllm-engine.md.- The 2026-04-22 code review is referenced from several MCP comments in
crates/mcp/src/lib.rs. The review document lives atdocs/code-review-2026-04-22.md(slice 5 territory).
Open questions, debt, drift
- Empty cloud-providers crate. Only a process-local in-memory keystore is wired. No HTTP transports, no OpenAI / Anthropic clients, no STT calls. Documented in
cloud-providers-stubs.md. The keystore TODO targets thekeyringcrate or platform-native credential storage. - Content-tags trivial-true cross-check observability gap.
LlmEngine::generatederivesgpu_offloadedfromuse_gpu && gpu_layers >= model.n_layer(), which is trivially true today (gpu_layersisu32::MAXwheneveruse_gpuis set). True residency observability — parsing llama.cpp's "offloaded N/M layers" log line — is tracked indocs/superpowers/specs/2026-05-09-battery-gpu-aware-thread-tuning-design.md(§ Out of scope). Per commit052265b, the explicit comparison is left in place to document intent. Seellm-engine.mdfor the call site. - Prompt versioning. All system prompts and GBNF grammars live as
pub const &strwith no version tag. A change toCLEANUP_PROMPT,DECOMPOSE_TASK_SYSTEM,EXTRACT_TASKS_SYSTEM, orCONTENT_TAGS_SYSTEMis invisible to downstream callers and to any cached LLM output. Worth introducing aPROMPT_VERSIONconstant and stamping it onto persisted output once cached cleanup re-runs become a feature. - Model registry drift.
LlmModelId::sha256()andLlmModelId::hf_url()are pinned to specific Hugging Face revisions. Upstream re-uploads (rare but they happen) silently invalidate the SHA. There is no automated check that the registered URL still matches the registered SHA. Manual verification expected at upgrade time. - GBNF schema drift between content-tags GBNF and the closed set.
INTENT_CLOSED_SET(inprompts.rs) and theintentrule inCONTENT_TAGS_GRAMMAR(ingrammars.rs) duplicate the same six values. They are kept in sync by hand. A drift would let the model emit a value that parses through the GBNF but failsis_valid_intent(the current code path) — or, worse, the other way round (GBNF blocks a value the closed set considers valid). A test that asserts the two stay in lock-step would close this gap. - Token-budget preflight is upper-bounded at the constant
MAX_CONTEXT_TOKENS = 8192. The 27B tier ships with a much larger native context but the engine never advertises it. Lifting the cap requires either per-model context windows in the registry or a probe of the loaded model'sn_ctx_train. Tracked inllm-engine.md. - MCP server has no auth, no transport-level scoping. Stdio-only by design. Anyone with stdio access to the binary has read access to every transcript. Documented in
mcp-server.md. Cloud / HTTP transports would need an auth layer — out of scope today.