active
Murmur
A voice-first notes app designed for fast, calm thought capture. Press and hold to record, release to transcribe.
Web AppNext.jsAIVoiceProductivity
Overview
Murmur is a voice-first mobile app for capturing fleeting thoughts in under 5 seconds. The core experience: hold a button, speak, release. No typing, no menus, no setup. Recordings upload instantly and sync across devices via Clerk authentication.
Built as an Android-first Flutter client with a Node.js backend, private Cloudflare R2 audio storage, and async AI for semantic search.
One gesture capture: press-and-hold → recording starts in under 200ms → release → auto-upload → saved. The user remembers the thought, not the app.
Core Features
- Ultra-low latency capture — Press-and-hold maps directly to the recorder; no countdown or confirmation
- Invisible sync — Failed uploads retry with exponential backoff; local file retained until success
- Future Capsules — Time-lock a memo to unlock later (1 hour to 50 years) with lazy unlock + notifications
- Semantic search — OpenAI embeddings over voice memos; cosine similarity ranking without a separate vector DB
- Private by default — R2 bucket is private; playback uses signed URLs with a 1-hour TTL
Architecture
Flutter App ──► Clerk SDK ──► Clerk (Auth)
│
└──► Dio API Client ──► Nginx (SSL) ──► Express API (EC2)
│
┌─────────────────┼─────────────────┐
▼ ▼ ▼
PostgreSQL Cloudflare R2 Clerk API
(Prisma) (Private Bucket) (JWT Verify)
- Client: Flutter + Riverpod + Clerk Flutter SDK;
recordfor capture,just_audiofor playback - API: Node.js + Express on AWS EC2 (PM2 + Nginx); Clerk session JWTs only — no app-issued tokens
- Storage: Cloudflare R2 (private); server normalizes AAC/M4A/Opus to MP3 via ffmpeg
- Data: PostgreSQL + Prisma; compound index
(userId, createdAt DESC)for instant library loads - AI: Async Whisper +
text-embedding-3-small; never blocks the upload response
Audio Pipeline
- Client starts recording on press (
<200ms) - On release, multipart upload to Express
- Server validates MIME/size, converts to MP3 (128kbps mono),
PutObjectto R2 - Memo row created only after R2 succeeds (atomic — no partial records)
- Library updates optimistically on the client; AI embedding runs fire-and-forget
Outcomes
- Sub-5s end-to-end capture path from gesture to saved memo
- Zero custom auth stack — Clerk owns session lifecycle end to end
- Dual upload paths: server-mediated (MVP) and presigned client→R2 (implemented, behind flag)
Reliability first: failed uploads retry silently in the background — no data loss, no friction.