- No hosted AI APIs. Only Ollama and LM Studio. Never introduce OpenAI, Anthropic, ElevenLabs, or any remote-provider client — this includes TTS (only local OS speech synthesis is supported).
- No PHI in logs. Transcripts, SOAP content, medications, allergies, and conditions must never appear in
tracing::*,println!,eprintln!, orconsole.log. Log counts, lengths, IDs — never content. - No telemetry / phone-home. The app must not contact any remote endpoint other than user-configured AI/STT provider URLs. Exception: update checks may contact
github.com/cortexuvula/rustMedicalAssistant(GitHub Releases) to fetch the update manifest (latest.json) and binary. This is an anonymous GET — no patient data, tokens, cookies, or identifying headers are transmitted. The user can disable automatic update checks in Settings → About or during onboarding.
# Backend tests (lib only — integration tests are crate-scoped)
cargo test --workspace --lib
# Sharing integration tests (needs FERRISCRIBE_MDNS_TEST=1 only on Linux)
cargo test -p medical-sharing
# Frontend tests
npx vitest run
# Type-check (runs svelte-check, NOT SvelteKit)
npm run check
# Dev
npm run tauri devThere is no top-level lint command wired up. Run crate-specific checks with cargo clippy --workspace if needed.
npm run check runs svelte-check — an earlier version invoked svelte-kit sync; that prefix was removed because this is not a SvelteKit project. The README's mention of "SvelteKit" is stale; treat Svelte 5 + Vite as the truth.
crates/— 13 library crates, all namedmedical-*(medical-core,medical-db,medical-security,medical-audio,medical-ai-providers,medical-stt-providers,medical-tts-providers,medical-agents,medical-rag,medical-processing,medical-export,medical-translation,medical-sharing)src-tauri/— Tauri app shell; Cargo package name isrust-medical-assistant(notmedical-tauri). Usecargo build -p rust-medical-assistant/cargo test -p rust-medical-assistant.src/— Svelte 5 frontend (runes mode). Frontend tests live alongside source as*.test.tsand run under vitest with jsdom.- Front↔back boundary:
src-tauri/src/commands/(~80#[tauri::command]functions called byinvoke()from Svelte).
Version is kept in sync across three files — bump all three together:
src-tauri/Cargo.tomlpackage.jsonsrc-tauri/tauri.conf.json
Release tags: vX.Y.Z (stable) or vX.Y.Z-beta.N (any tag with - is a prerelease). release.yml builds installers on tag push.
- Edition 2024,
rust-version = "1.85". Use Rust 1.85+. whisper-rs/whisper.cpprequires CMake + Clang at build time.- Windows CI is excluded from the test matrix because
cpaldevice-enumeration crashes on headless runners (no audio hardware). Linux CI needslibwebkit2gtk-4.1-dev libgtk-3-dev libasound2-dev libssl-dev pkg-config.
recordings.metadataJSON column holds both freeformcontext(string) and structuredpatient_context(PatientContextshape). New metadata keys are non-breaking.- The SOAP system prompt has hardened anti-fabrication rules. Background-supplied facts populate only historical Subjective fields — never alter today's Assessment or Plan.
- vitest config mirrors the
dictionary-enasset resolver fromvite.config.ts; the plugin is duplicated in both files intentionally (Vitest strips Vite's strict-exports check differently). Keep them in sync if you change one. - Branch hygiene: isolated git worktrees live under
.worktrees/(gitignored). Never start implementation directly onmaster.
These features are load-bearing for HIPAA compliance. Do not regress them:
- Database: SQLCipher (AES-256) via
rusqlite'sbundled-sqlcipher-vendored-openssl. Keys live in the OS keychain (medical-security/src/keychain.rs). TheAppState::initializefunction refuses to silently fall back to a plaintext DB when patient data exists — it surfacesInitError::EncryptionUnavailableinstead. - Audio recordings at rest: WAV files are encrypted with AES-256-GCM via
medical-security/src/file_crypto.rs. The on-disk format is[magic "FE1" (3 bytes)] [nonce (12 bytes)] [ciphertext]. The key is derived from the DB key via SHA-256 with a domain separator.encrypt_file_in_placeis atomic (temp + fsync + rename). Legacy plaintext WAVs are auto-detected (no magic) and read as-is. - Orphaned transcripts: Written as encrypted
.encfiles (samefile_cryptohelper), with a.txtfallback only if the keychain is unavailable. - Webview CSP:
tauri.conf.jsonhas a strict CSP (default-src 'self'). Do not set it tonull. Theconnect-srcincludesipc:,asset:, andhttp://asset.localhostfor Tauri IPC + asset protocol. - TTS: Only local TTS (
"local"). Cloud TTS providers (ElevenLabs etc.) were removed — AGENTS.md's "no hosted AI" rule applies to TTS too.SUPPORTED_TTS_PROVIDERSinsettings.rsis the allowlist. - ICD-9 billing codes: The SOAP generator constrains code selection to the bundled BC MSP ICD-9 list (7,122 codes in
crates/core/icd9_codes.json). The selector uses a pre-computed inverted index for performance. Post-generation validation flags off-list codes as amber chips in the frontend. Do not change the default from ICD-9 to ICD-10 — BC MSP bills ICD-9.
These items remain from various reviews and are tracked for a future effort:
- Dependency version pins —
printpdf0.7 (lopdf advisory is parse-only; 0.9 is a major API rewrite, deferred),rusqlite0.32 (blocked by SQLCipher/libsqlite3-sys conflict — newer rusqlite requires a different libsqlite3-sys that conflicts with bundled-sqlcipher),ort2.0.0-rc.12 (the latest available; no stable 2.x exists yet). All are ecosystem-blocked, not neglect.
General.svelte split— done in v0.29; now 32 lines, delegates tosettings/sections/components.Recording soft-delete/undo— done in v0.29; m009 migration,soft_delete,restore_recording, Undo toast, and 30-day tombstone sweeper (with RAG vector cleanup) are all wired.Template handlers typed AppError— done in v0.24.3.— done in v0.30.26; tombstone sweeper indelete_rag_vectors_best_effortorphan sweeperstate.rsnow cleans RAG vectors before purging.