sanctuAIry — Private Mental-Health Companion
A mental-health companion that runs entirely on your phone. No cloud inference, no telemetry, no network transmission of user data. Privacy is enforced by architecture rather than policy — the usage-metrics type has no method that accepts a string, making content leakage structurally impossible.
sanctuAIry is a mental-health companion that runs entirely on your phone. There is no cloud inference, no telemetry, and no network transmission of user data. All processing happens locally through Gemma 4 E2B running on Google's LiteRT-LM runtime, with roughly 2.06 GB resident during inference.
The privacy guarantee is structural rather than policy-based. The
UsageMetrics class deliberately has no method that accepts a string,
so leaking conversation content through metrics is not something a future change
can accidentally introduce — it would not compile. Aggregate numbers only:
hours open, session counts, message counts.
Retrieval without embeddings. A two-tier memory system loads up to 12 durable facts permanently while BM25 searches diary episodes over SQLite FTS5. This handles queries like “what is my name” that pure lexical matching fails, and avoids the 100–250 MB overhead an embedding model would add on a device already holding a 2 GB LLM in memory.
Memory extraction is deterministic. Four components handle it: FactExtractor pulls durable facts from conversations and diary entries, NoteDigester produces extractive summaries capped at four sentences per entry, SessionSummarizer compresses conversations during backgrounding, and SentimentAnalyzer derives valence and arousal with negation handling. All of it runs on regex and lexicon work — never a generative model — which means memory recall cannot hallucinate.
Safety. CrisisGuard implements tiered triage, and LexicalGuard screens for false human or medical claims before they reach the user. Proactive check-ins are timing-constrained rather than free-running. The diary is passcode-protected with selective sharing into conversation context.
Four production lessons worth recording. Quantization settings
drove an 8× runtime memory expansion — switching from
weight_only_wi4_afp32 to dynamic_wi4_afp32 cut peak RSS
from 7.4 GB to 1.5 GB. Gradle needed LiteRT-LM 0.13.1 forced across every
subproject; overriding only in :app left compiled bytecode pointing at
outdated signatures. Prompt templates live inside the LlmMetadataProto rather than
the app, so handwritten Gemma-2/3 tags corrupted prompts. And sampler seed pinning
at zero produced byte-identical replies, which required vendoring
flutter_litert_lm to forward the native seed parameter.
Ships with 214 passing tests under an MIT license. The model (~2.41 GB) is hosted separately on Cloudflare R2 with resumable, SHA-256-verified downloads. Android 7.0+; authentication is required on Android and optional on iOS per App Store guidelines.