Inspiration
Everyone already has a chat with themselves. Telegram's Saved Messages, a WhatsApp group with one member, emailing a link to yourself. It's the fastest way to capture anything, because there is nothing to learn: you just send it.
But those chats were built for talking, not for finding things again. Months later you scroll forever looking for "that PDF about the apartment" or a screenshot you know you saved. And getting a file from your phone to your computer still means AirDrop roulette or a cloud-drive folder you never clean up.
I wanted that same habit, made deliberate: send anything to yourself, and find it later by what you meant, not the exact words you typed. That's Muem.
What it does
- One familiar timeline for everything: notes, links with previews, photos and albums, voice notes, PDFs, documents and code. Reply, react and edit like any messenger.
- Search by meaning: type "my apartment contract" and get Lease.pdf. Type "colorful" and the album with the bright photos comes up, with the most relevant photos shown first. Search works inside one chat or across all of them, with filters for media, files, links, code and audio.
- Phone to computer, instantly: send something from your iPhone and it's on the web app and the Mac app a second later.
- A real Mac app: photos and PDFs open in Quick Look, voice notes play natively, and you can drag any photo or file out of a chat straight into Finder, Mail or Slack.
- Separate chats for work, clients and ideas, plus disappearing chats that delete themselves after anything from an hour to 30 days.
Muem is free for one chat. Muem Plus adds up to 10 chats, disappearing chats and far more smart searches. One subscription works everywhere.
How I built it
Muem is a TypeScript monorepo with three clients and one backend:
- iPhone: Expo and React Native, with Reanimated, FlashList, iOS 26 Liquid Glass, haptics, and native Sign in with Apple and Google.
- Web: TanStack Start and HeroUI on Cloudflare Workers, at web.muem.app.
- Mac: native SwiftUI for macOS 26, sharing the same API and message format.
- API: Hono on Cloudflare Workers, Postgres on Neon (with pgvector) through Hyperdrive, R2 for attachments, and Durable Objects for realtime sync.
- Encryption: messages and files are encrypted with XChaCha20-Poly1305 before they leave the device.
- Billing: RevenueCat is the single source of truth.
- App Store subscriptions and RevenueCat Web Billing (Stripe) map to one
muem_plusentitlement. - A webhook writes each customer's plan to the server, so Plus bought on the iPhone unlocks the web and the Mac.
- Limits are enforced on the server, never trusted from the client.
- App Store subscriptions and RevenueCat Web Billing (Stripe) map to one
- Sign-in: passwordless (email code, Google, Apple), protected by Cloudflare Turnstile, disposable-email blocking and rate limits.
- Languages: 11 at launch.
The search engine
Search is the heart of Muem, and no single technique was good enough on its own. Embeddings understand meaning but miss exact filenames and codes. Keyword search is the other way round. So every query runs several lanes in parallel, each with a deadline and each allowed to fail without breaking the result:
- BM25 keyword search: exact words, then word stems.
- Text vectors (Voyage) for meaning.
- Multimodal vectors, so the words in a query can match what's actually in a photo.
- An intent pass that turns "PDFs from last week" into filters.
- Structure: media, files, links, code and audio.
The ranked lists are merged with Reciprocal Rank Fusion, where a document's score is the sum over every lane that found it:
$$ \text{score}(d) = \sum_{\ell \,\in\, \text{lanes}} \frac{1}{60 + \text{rank}_\ell(d)} $$
Then a cross-encoder reranks the top results. Albums are indexed photo by photo, so a search can tell you which photos in a 10-photo album matched and show those first.
Challenges I faced
- Time. The first commit was on September 21. The production backend, App Store review, subscription setup and three clients all had to move in parallel to make the September 30 deadline.
- Voice notes recorded in Chrome wouldn't play on Apple devices. Browsers record Opus audio inside a WebM container, which AVFoundation can't open. I wrote a small Matroska parser in Swift that pulls out the Opus packets, decodes them with Apple's own Opus decoder, and plays the result as WAV.
- Changing the API without breaking the app that was already in review. The iPhone app validates server responses strictly, so new search features (like photo ranking inside albums) had to be opt-in fields that older clients never receive.
- Encrypted photo albums on a phone. Decrypting a 10-photo album without freezing scrolling meant decrypting in chunks, with one shared decrypt per album.
- Making three platforms feel like one product. The same message grouping, rounded corners, search behaviour and paywall had to feel native on iPhone, web and Mac, not like a port.
What I learned
- The interface people already know is the best onboarding. Nobody needs a tutorial to send a message to themselves. Structure can come after capture, automatically.
- Hybrid search beats clever search. Most of the quality came from combining simple lanes well, giving each a deadline, and letting any lane fail without breaking the result.
- Monetization works best when it's honest. Meter the expensive things (chats and AI search) and never the basics. RevenueCat made "buy once, unlocked everywhere" almost free to build.
- Ship clients defensively. Once an app is in the App Store, every API change has to be backwards compatible.
What's next
- A Share Extension, so you can send anything to a Muem chat from any app.
- An assistant that answers questions from your own saved content.
- Global search on iPhone, matching the web and Mac.
- Optional extra privacy: an app lock, passkeys and client-held keys for people who want them.
Log in or sign up for Devpost to join the conversation.