Fully offline voice recorder, live transcriber, journal & meeting synthesizer, and personal mind map for Android — powered 100% by on-device AI.
I wanted a way to capture thoughts on the go with a quick double-press of a physical hardware key—without unlocking my phone or getting pulled into a screen—and have those notes accumulate over time into a living mind map.
I use Satori every day for journaling, quick thoughts, ideas, self-development, local AI and engineering notes, and transcribing meetings. I didn't have the time to audition a dozen different note-taking apps, and I refused to pay recurring subscriptions just to hand my private voice recordings and personal reflections over to someone else's cloud servers. Instead, I built this.
Every stage of Satori runs 100% offline on the phone:
- Live speech recognition while you walk or sit in a meeting (
NVIDIA Parakeet v3/v2,Cohere Transcribe,AI4Bharat IndicConformer, andSilero VADviasherpa-onnxand ONNX Runtime1.28.2). - First-person note synthesis, session naming, to-do extraction, and mind-map linking via local instruction-tuned language models (
Gemma 3 1B,Gemma 4 E2B,Qwen 3.5 0.8B) running on custom-patchedllama.cppARM64 kernels. - Neural reading & translation bridges for liveEnglish ↔ German conversation translation and an internalMalayalam → English reading pass (
AI4Bharat IndicTrans2 200M) so Malayalam voice notes receive the same structured English notes, reminders, and mind-map connections. - Zero accounts, zero cloud servers, zero telemetry. The network is touched only when down model weights directly from Hugging Face.
I am sharing Satori as open source hoping it will be useful to anyone who wants to clone, customize, and build a private voice companion for themselves or for the people they love.
Built around the Grille typographic design system (Space Grotesk + Doto dot-matrix tabular counters + #D71921 recording red on #000000 OLED black), Satori is engineered for both standard Android displays (1080×2640) and the Motorola razr 70 plus external cover screen ( 1080×1272, 480×410 dp), including hardware power-key double-press capture over the lock screen and automatic layout clearance around the 232 px physical camera band.
Double-pressing the physical power key wakes the folded phone straight into recording (QuickKeyActivity), keeping all interactive controls clear of the 232 px hardware camera and flash band in both standard (ROTATION_0) and tent/flipped ( ROTATION_180) postures.
| Cover View | Use Case & What It Shows |
|---|---|
Quick Power-Key Capture (cover-recording.png ) |
Capturing an evening walk reflection without unfolding the phone: Doto dot-matrix timer,Voice note category selector,EN language key, streamingParakeet v3 transcript, and the tactileGrilleStop button positioned above the camera band. |
Cover Home (cover-home.png ) |
Browsing recent Journal ,Voice note , andMeeting sessions on the folded display with tabularDoto durations, search/mind-map/settings actions, and one-tapGrille recording. |
Live Translation (cover-translate.png ) |
Real-time German → English translation (Record as → Translate ), pairing the spoken German transcript with live English translations on the cover display. |
Cover Mind Map (cover-mindmap.png ) |
Interactive radial knowledge graph centered on You (10 recordings acrossJournaling ,Local LLMs & AI ,Self-dev ,Quick Ideas ,Meetings ,Deep Work , andHabits ), adapted for the square cover viewport. |
Each recording belongs to a category—Voice note, Meeting, Idea, To-do, or custom categories like Journal—that governs how the on-device LLM structures your notes and whether spoken action items become scheduled reminders or ideas.
| Inner View | Use Case & What It Shows |
|---|---|
Home (inner-home.png ) |
Open To do list (Block 2 hours for deep work before 10 AM ),1 suggested inbox link,1 idea link, chronologicalRecordings acrossJournal ,Idea ,Meeting , andVoice note , and the dockedGrille record bar. |
Active Recording (inner-recording.png ) |
Real-time streaming transcription ( Parakeet v3 ) with live partial utterance tracking and instantRecord as / language switching. |
Record as Sheet (inner-record-as.png ) |
Switching category ( Voice note ,Meeting ,Idea ,To-do ,Translate ) or spoken language (English or German ,Malayalam ) before or during a recording. |
Categories Manager (inner-categories.png ) |
Built-in categories plus custom user categories ( Journal — Daily reflections, habits and self-dev notes ), each mapped to a note-synthesis style (Short notes and to-dos ,Decisions, facts and to-dos , orSections for a long meeting ). |
Journaling & Self-Dev (inner-journal.png ) |
First-person journal synthesis ( Evening journal: deep work and focus ) distilled from an evening walk reflection, with expandable transcript provenance (Show what was said ). |
Technical & LLM Notes (inner-details.png ) |
Structured engineering notes ( On-device LLM latency and KV cache ) capturing concrete numbers and trade-offs in first-person voice without generic AI filler. |
Meeting Transcript & Player (inner-transcript.png ) |
Timestamped meeting transcript ( Architecture sync: local LLM latency ) with the built-in audio player (Play from here on any line) and file size readout. |
To-Dos & Suggested Inbox (inner-todos-suggested.png ) |
Calendar-grounded open To do reminders alongside theSuggested to-dos review sheet (Keep ,Dismiss ,Move to ideas ,Keep all ) for tasks inferred from meetings and journal reflections. |
Over days and weeks, Satori connects your recordings into a two-level knowledge graph (Themes and per-recording Topics) and gathers spoken wishes into a dedicated Ideas collection.
| Inner View | Use Case & What It Shows |
|---|---|
Mind Map Overview (inner-mindmap.png ) |
Ego-centric knowledge graph centered on You (Core ,Recent ,All filters, theme search, and recording counts acrossJournaling ,Local LLMs & AI ,Self-dev ,Quick Ideas ,Meetings ,Deep Work ,Streaming STT , andHabits ). |
Theme Node Drill-Down (inner-mindmap-node.png ) |
Inside the Journaling theme node (4 recordings · Pinned in Core ): radial sub-graph of child topics (Deep work ,Morning walk ,Evening review ,Attention ,Sleep & energy ,Weekly reset ,Reading habit ,Stoic notes ), AI-writtenSummary across recordings , and linkedTopics in this theme . |
Ideas Collection (inner-ideas.png ) |
Every spoken wish or idea extracted across your Journal andMeeting recordings, grouped by source session and convertible into a scheduled to-do in one tap. |
On-Device Model Manager (inner-models.png ) |
Local model manager ( Parakeet v3 ,Parakeet v2 ,Cohere Transcribe ,Malayalam (AI4Bharat) ,Better transcript after Stop , and custom recognition vocabulary). |
-
100% Offline & Private : Every byte of audio, every transcript segment, every synthesized note, and your entire mind map live in a local Room SQLite database (
AppDatabasev13) on your phone. Nothing is ever uploaded to a server. -
"The Recorder Wins" Preemption : Starting a recording—from the Home screen, the cover screen, or a double-press of the physical power key over the lock screen—opens the microphone immediately and preempts any running background AI task within milliseconds.
-
First-Person Notes, Zero AI Slop : Generic meeting bots write third-person filler ("The speaker discusses..." ). Satori's prompts and GBNF grammar schemas force the local LLM to write direct, first-person notes ("Pre-faulting GGUF weights at 120 MB/s prevents audio underruns" ), verified by
PromptEchofilters. -
Calendar-Accurate To-Dos without LLM Math : Small language models hallucinate calendar arithmetic. Satori spots relative dates and times deterministically (
TodoTimeResolverfor English/German andMalayalamTodoCuesfor Malayalam) relative to the recording's start timestamp, passing verifiedT1/T2tokens to the model and grounding every extracted item against the cited segment (TodoGrounding). -
Engineered for Real Phone Memory Limits : Multi-gigabyte GGUF models are pre-faulted at a paced
120 MB/s(0 MB/sduring active recording) withMAP_POPULATEdisabled,/proc/meminfo(MemAvailable) safety floors, and immediate page-cache reclamation (madvise(MADV_PAGEOUT)) on unload. -
Zero-wait microphone capture :
RecordingServiceopensAudioRecord(16 kHz mono PCM) the instant you tapRecord , buffering audio while the speech recognizer loads in the background so the first words you speak are never lost. -
Categories &
Record as:- Ships with four starter categories—Voice note ,Meeting ,Idea , andTo-do —plus custom user-defined categories (
Settings → Categories, such asJournal ). Each category maps to a recording style (SIMPLE_LISTENING,SHORT_MEETING, orLONG_MEETING) that governs how its notes and action items are structured. - Switch categories before recording, mid-recording via the top
Record aschip, or retroactively on any finished recording viaChange type (which rewrites the notes in the new category's style while preserving your title and to-dos).
- Ships with four starter categories—Voice note ,Meeting ,Idea , andTo-do —plus custom user-defined categories (
-
Ships with four starter categories—
-
Spoken languages & mid-recording switching :
- English and German out of the box via
NVIDIA Parakeet TDT 0.6B v3(~670 MB). - Malayalam (
മലയാളം) viaAI4Bharat IndicConformer 120M INT8(~140 MB). WhenLanguage in Record as is enabled, you can switch betweenEnglish or GermanandMalayalammid-recording between two sentences.
- English and German out of the box via
-
Custom vocabulary (
Words to recognize) : Add names, acronyms, and domain terms (one per line) inAdvanced settings to boost their recognition inParakeet v3during live capture andTranscribe again . -
Double-press power key (
QuickKeyActivity) : Binds to Motorola's hardware double-tap power gesture (com.motorola.mykey), debouncing accidental bounce presses within1,000 ms(QuickKeyRepeatFilter) and waking over the lock screen (Hold to stop,Hold to changefor pocket safety). -
Selecting Translate in
Record as(REAL_TIME_TRANSLATION) transcribes spoken English or German and translates finished sentences into the target language configured underSettings → Translate into(EnglishorGerman). -
Automatically detects the spoken language (
German into English, orAlready English: nothing to translatewhen input and target match). -
Displays a dedicated Translation tab, running either live every few sentences (
As you speak) or in one batch after stopping (After recording).
When you press Stop, the microphone closes and RecordingFinisher processes finished recordings sequentially in LlmProcessingService while leaving the recorder free for your next thought:
flowchart LR
Stop["Stop Recording"] --> Lines["1. Lines\n(Flush streaming STT)"]
Lines --> Redo{"2. Better transcript\nafter Stop?"}
Redo -- "Parakeet v2 / Cohere /\nIndicConformer" --> Retranscribe["Re-transcribe WAV\n(Making a better transcript)"]
Redo -- "Off / Skipped" --> IsMl{"3. Malayalam\nrecording?"}
Retranscribe --> IsMl
IsMl -- "Yes" --> Reader["IndicTrans2 200M Reader\n(Malayalam -> segment_readings)"]
IsMl -- "No (EN / DE)" --> Notes["4. Final Notes\n(Gemma 4 E2B or Gemma 3 1B)"]
Reader --> Notes
Notes --> Name["5. Auto-Name\n(2-5 word title)"]
Name --> Todos["6. To-Dos & Ideas\n(Time resolver + LLM + Grounding)"]
Todos --> Map["7. Mind Map\n(Topics -> Themes & Summaries)"]
Compact 1B language models (Gemma 3 1B) struggle to parse Malayalam script directly, while a 3.3 GB model (Gemma 4 E2B) on every voice note is too heavy when phone RAM is tight. Satori solves this with a dedicated internal reading stage:
-
Visible transcript stays in Malayalam : Your recording'sTranscript tab displays the Malayalam script (
മലയാളം) produced byIndicConformer. -
Under-the-hood IndicTrans2 bridge : BetweenLines andNotes ,
:feature-reader(:lib-reader-onnx) runsAI4Bharat IndicTrans2 Distilled 200M INT8 (242 MB, 3 ONNX graphs on the bundled ONNX Runtime1.28.2+ SentencePiecemodel.SRC/model.TGT+ IndicNLP normalization and Malayalam-to-Devanagari offset transliteration, beam size 5) to write internal English readings into Room (segment_readings, DB v13). -
Unified downstream synthesis :Notes ,Auto-naming ,To-dos & Ideas , andMind Map topics read
segment_readings, giving Malayalam recordings the same English notes, date resolution, and grounding quality as English recordings. -
Idle backfill (
ReadingBackfill) : Malayalam recordings that do not yet havesegment_readingsare quietly upgraded when the phone is idle, without overwriting any title, note, or to-do edited by the owner. -
Open To-Dos vs. Suggested Inbox (
TodoCapture) :- Explicit reminders (
explicit), first-person promises (commitment), and recordings made in theTo-do category go straight to yourTo do list on Home (TodoStatus.OPEN) and schedule an exact Android alarm (AndroidReminderAlarm, withDone andSnooze 1 hr notification actions). - Tasks asked of you by someone else (
asked), implied tasks (inferred), andappointmentitems land in the**N suggested** review sheet (TodoSuggestionsSheet) where you canKeep ,Dismiss ,Move to ideas , orKeep all .
- Explicit reminders (
-
Explicit reminders (
-
Ideas (
IdeasScreen) :- Wishes or suggestions mentioned in a recording ("there should be an option to..." ,"it would be nice if..." ) and recordings made in theIdea category are collected on theIdeas page (
%d ideas, %d newon Home). - Ideas link back to their source recording and segment, outlast deleted recordings (Without a recording ), and convert into scheduled to-dos in one tap (
Make it a to-do).
- Wishes or suggestions mentioned in a recording ("there should be an option to..." ,"it would be nice if..." ) and recordings made in theIdea category are collected on theIdeas page (
-
Wishes or suggestions mentioned in a recording (
-
Two-level knowledge graph centered on
You:- Themes (
MindNodeKind.THEME) : Recurring subjects across your recordings (e.g.,Journaling ,Local LLMs & AI ,Deep Work ). When multiple recordings link to a theme,RefreshThemeSummariesUseCasewrites a 2–4 sentence cross-recording summary of what is known and decided (newest recording wins when facts change). - Topics (
MindNodeKind.TOPIC) : What an individual recording said about a theme (1–4 grounded words + up to 3 bullet points), linking directly back to the recording.
- Themes (
-
Interactive Canvas & Accessible List : Toggle between the 2D radial graph (Show as map ) and a structured list (Show as list ), filter byCore (pinned + top themes),Recent (last 7 days), orAll , and batch-index older recordings viaMap N older recordings .
-
Audio player & seek-to-line : , scrub bar, file size &
Compressedbadge, and tap any transcript line (Play from here) to jump playback to that segment's timestamp. -
Transcribe again : Re-run speech recognition on any saved recording's audio with any installed model (Parakeet v3 ,Parakeet v2 ,Cohere Transcribe , orMalayalam (AI4Bharat) ).
-
Automatic AAC compression & retention (
AudioRetentionJob) : ConfigureCompress older audio (After N days, shrinking~2 MB/minWAV files to~0.25 MB/minAAC/M4A while keeping them playable and re-transcribable) andDelete older audio (After N days, removing audio while keeping transcripts, notes, to-dos, ideas, and mind-map links). Per-recordingKeep this audio exempts important recordings. -
Offline GPS place naming (
places.bin) : OptionalSave the placeresolves a recording's starting GPS fix offline against a bundled GeoNames KD-tree (app/src/main/assets/places.bin, e.g.,BerlinorNear Berlin) with zero network requests.
Models are downloaded on demand inside the app (Settings → Models and storage and Settings → Advanced) and verified by byte size and SHA-256 ( ModelChecksums) before use.
| Model | Role | Languages | Size | Runtime |
|---|---|---|---|---|
Silero VAD (silero_vad.onnx ) |
Voice activity detection (bundled in APK assets; tunable length, max phrase, and threshold) | Language-agnostic | 1.8 MB |
ONNX Runtime 1.28.2 |
Parakeet v3 (PARAKEET_V3 ) |
Default live streaming speech recognizer & Transcribe again (supports custom hotwords viabpe.vocab ) |
English & German (multilingual TDT 0.6B v3 INT8) | ~670 MB |
sherpa-onnx |
Parakeet v2 (PARAKEET_V2_EN ) |
Optional Better transcript after Stop &Transcribe again for lower English WER | English | ~660 MB |
sherpa-onnx |
Cohere Transcribe (COHERE_TRANSCRIBE ) |
Optional high-accuracy Better transcript after Stop &Transcribe again | English & German | ~2.9 GB |
sherpa-onnx |
Malayalam (AI4Bharat) (INDICCONFORMER_ML ) |
Live streaming, post-stop second pass, and Transcribe again for Malayalam speech (IndicConformer 120M INT8 ) |
Malayalam ( ml ) |
~140 MB |
sherpa-onnx |
| Model | Role | Direction | Size | Runtime |
|---|---|---|---|---|
| IndicTrans2 Distilled 200M INT8 | Internal post-stop reading stage ( segment_readings ) so downstream LLM steps read English instead of raw Malayalam script |
Malayalam → English ( mal_Mlym →eng_Latn ) |
~242 MB |
ONNX Runtime 1.28.2 C API + SentencePiece |
| Model | Setting Name | Role | Size | Quantization |
|---|---|---|---|---|
| Gemma 3 1B IT | Standard (default) | Live notes, post-stop notes, auto-naming, to-dos & ideas, live/post-stop EN↔DE translation, and mind map | ~1.0 GB |
Q8_0 GGUF |
| Gemma 3 1B IT | Efficient | Lower-memory alternative for live and post-stop tasks | ~650 MB |
IQ4_NL GGUF |
| Qwen 3.5 0.8B | Qwen 3.5 0.8B | Compact alternative model in Advanced settings | ~870 MB |
Q8_0 GGUF |
| Gemma 4 E2B IT | Gemma 4 E2B | Optional higher-capacity model dedicated to AI for finished recordings (post-stop notes, naming, to-dos, and mind map when free RAM permits) | ~3.3 GB |
Q4_0 QAT GGUF |
- Paced Pre-Faulting (
ModelLoadPacing) : Custom patches onllama.cpp(0001-load-progress-bytes.patch,0002-map-populate-switch.patch,0003-mapped-hook.patch) disableMAP_POPULATEand pre-fault GGUF pages at a capped120 MB/s(0 MB/swhile a recording is active) so disk reads never starve the UI thread or audio capture buffer. - Page-Cache & Arena Reclamation : Releasing a model calls
madvise(MADV_PAGEOUT)/posix_fadvise(POSIX_FADV_DONTNEED)on mapped weight pages and purges native allocator arenas. - Live
/proc/meminfoGuards (MemoryFloor,AnswerFloor,ParseRoom) : BeforeCohere Transcribe,Gemma 4 E2B, orIndicTrans2, Satori checksMemAvailableagainst model-specific headroom floors and falls back gracefully (e.g., fromGemma 4 E2BtoGemma 3 1B) when memory is tight. - Disk-Cached System Prompts (
forgetPromptCache) : All note, to-do, and mind-map system prompts are static and placeholder-free (strings_grille_ai.xml,strings_grille_todo_ai.xml,strings_grille_mindmap_ai.xml), allowing:lib-llama-androidto serialize their evaluated KV state to disk once and reload it across sessions without re-evaluating the system prompt on every recording.
Satori is organized as a 10-module Gradle project with strict Clean Architecture boundaries (:domain is pure Kotlin with zero Android dependencies):
flowchart TD
app[":app\nCompose Grille UI, Cover Screen, QuickKey, Foreground Services"]
presentation[":presentation\nViewModels, RecordingFinisher, HomeStrip, MindMap, Audio/Todo/Idea State"]
domain[":domain\nUse Cases, Entities, Time Resolver, Malayalam Reading Prep, Grounding"]
data[":data\nRoom DB (v13), Model Downloads, Memory Pacing, Offline Places, Retention"]
feature_stt[":feature-stt\nStreaming & Offline STT + Silero VAD"]
feature_llm[":feature-llm\nGGUF Inference, Prompt Cache & Grammar Constrained Output"]
feature_reader[":feature-reader\nIndicTrans2 200M Malayalam-to-English Reader"]
lib_sherpa[":lib-sherpa-onnx\nJNI Bridge to sherpa-onnx + ONNX Runtime 1.28.2"]
lib_llama[":lib-llama-android\nCMake / JNI Bridge to llama.cpp (ARMv8.0 - ARMv9.2)"]
lib_reader[":lib-reader-onnx\nCMake / JNI Bridge to ORT C API + SentencePiece"]
app --> presentation
app --> domain
app --> data
app --> feature_stt
app --> feature_llm
app --> feature_reader
presentation --> domain
data --> domain
feature_stt --> domain
feature_stt --> data
feature_stt --> lib_sherpa
feature_llm --> domain
feature_llm --> data
feature_llm --> lib_llama
feature_reader --> domain
feature_reader --> data
feature_reader --> lib_reader
lib_reader --> lib_sherpa
| Module | Responsibility |
|---|---|
:app |
Jetpack Compose UI ( Grille ),MainActivity (singleTask cover/inner handoff),QuickKeyActivity ,RecordingService ,LlmProcessingService , and Hilt DI wiring. |
:presentation |
MainViewModel ,RecordingFinisher ,SessionsViewModel ,SessionDetailsViewModel ,RecordingAudioViewModel ,MindMapViewModel ,IdeasViewModel ,SettingsViewModel , andFirstRunCoordinator state flows. |
:domain |
Pure Kotlin business logic: FinishRecordingUseCase ,ExtractTodosUseCase ,TodoTimeResolver ,TodoGrounding ,MapRecordingUseCase ,RefreshThemeSummariesUseCase ,com.satori.domain.reading Malayalam preprocessing, and repository interfaces. |
:data |
Room database ( AppDatabase v13: sessions, segments,segment_readings , insights, to-dos, ideas, mind nodes/edges, categories), resumable Hugging Face down,ModelLoadPacing ,AudioRetentionJob (WAV→M4A compression & cleanup), and offlineplaces.bin geocoder. |
:feature-stt |
SherpaOnnxDataSource managing Silero VAD segmentation, streamingParakeet v3 /IndicConformer recognition, custom hotword boosting, and offline re-transcription (Parakeet v2 ,Cohere Transcribe ). |
:feature-reader |
OnnxReaderDataSource driving the 3-session IndicTrans2 200M beam-search translator for Malayalam recordings. |
:feature-llm |
LlamaCppDataSource managing GGUF , system-prompt KV disk cache, GBNF grammar enforcement, and token streaming. |
:lib-sherpa-onnx |
Prebuilt arm64-v8a`` libsherpa-onnx-jni.so andlibonnxruntime.so (1.28.2 ) with Kotlin/JNI bindings. |
:lib-reader-onnx |
Native C++ JNI bridge ( reader_jni.cpp ) linking against:lib-sherpa-onnx 'slibonnxruntime.so (OrtGetApiBase ) and static SentencePiece (model.SRC /model.TGT ). |
:lib-llama-android |
Native CMake build of llama.cpp compiling per-microarchitecture ARM64 libraries (armv8.0 througharmv9.2 with dotprod, i8mm, and FP16 acceleration) loaded dynamically at runtime via/proc/cpuinfo detection. |
- JDK 17
- Android SDK : Platform
android-35(compile/target SDK 35,minSdk29), Build-Tools34.0.0 - Android NDK :
29.0.13113456andCMake3.31.6+(for:lib-llama-androidand:lib-reader-onnx) - Git submodules :
third_party/llama.cppandthird_party/sentencepiecemust be initialized before building.
git submodule update --init --recursive
./gradlew testDebugUnitTest
./gradlew lintDebug
./gradlew assembleDebug
The compiled debug APK is written to app/build/outputs/apk/debug/app-debug.apk.
GLOSSARY.md— Domain, hardware, and on-device inference terminology across the codebase.docs/GRILLE_DESIGN.md— Complete specification of theGrillevisual system, color tokens, typography, and cover/inner screen layouts.docs/QUICK_KEY.md— Hardware power-key double-press (com.motorola.mykey) integration and lock-screen capture behavior.docs/MODEL_UX_SPEC.md— First-run onboarding, background download state machine, storage checks, andHomeStripnudges.docs/PRIVACY_AND_TERMS.md— Privacy architecture and local-only data storage guarantees.docs/THIRD_PARTY_NOTICES.md— Licenses and attributions for bundled libraries, fonts, GeoNames data, and downloadable models.