Overview
Every cloud notetaker has the same architecture: your microphone uploads to someone else’s server. Notova inverts that. Audio is captured, transcribed and summarized on the device, and the backend is scoped so tightly that it has no capability to receive audio even if it wanted to.
That constraint drives the whole design. If the server cannot do the AI work, the client has to do it, on three platforms, without writing the pipeline three times.
Architecture
- One shared core, three shells. Domain models, the
PipelineService, and the on-deviceTranscriber/Summarizerseams live in local Swift packages. iOS (SwiftUI) and macOS (aNavigationSplitViewapp) both depend on that core; only the platform plumbing differs, such asMacAudioRecorderwrapping AVAudioEngine for capture and file import. - Android is a parallel implementation in Kotlin and Jetpack Compose, matching the same record → transcribe → summarize contract.
- Model seams, not model calls. Transcription and summarization sit behind protocols, so a real engine drops in without touching a single call site. Today those are stub implementations; the intended engines are Whisper for transcription and Gemma 3n E4B for summarization.
- Generated project files. The Xcode project is produced by XcodeGen from
project.ymlrather than committed, so the build configuration is reviewable as source and merge conflicts in a binary project file stop existing. - Swift 6 with strict concurrency across the app, targeting iOS 17 and up.
The backend is defined by what it refuses to do
- Accounts with JWT access and refresh tokens. Passwords hashed with argon2id; refresh tokens stored only as SHA-256 hashes so they can be revoked without ever holding the secret.
- An OAuth2 token broker for Google, Notion, Slack and Salesforce, using Authorization Code with PKCE. Third-party tokens are encrypted at rest with AES-256-GCM.
- Metadata-only sync. Title, duration, source, status and timestamps cross devices. No audio, no transcripts, no summaries are stored at rest.
- Export as pass-through. A note bound for a connected service transits device → backend → third party. It is forwarded, never persisted.
- Built on Node 22+ and TypeScript ESM with Hono, Drizzle ORM over better-sqlite3, zod for validation, jose for JWT, and Vitest.
What this bought
- A privacy claim that is structural rather than promissory: there is no code path by which audio reaches the server.
- One behavioural contract to test instead of three, because the shared core owns the pipeline and the shells own only capture and presentation.
- A model upgrade path that costs nothing at the call sites, since the engines sit behind protocol seams.
Honest status
The iOS, macOS and Android shells, the shared core, and the backend are working. The transcription and summarization engines are still stubs behind their protocols: the seams are real and tested, the models are not yet dropped in. Meeting Bot, below, is where the on-device Whisper pipeline actually runs today.