Inspiration
In real life, the people who look out for you aren't the ones who wait to be asked. They're the ones who notice. A friend who remembers your bill is due, that your mum is waiting on a call, that your exam is tonight. I kept coming back to one idea: nobody narrates their life to an assistant. You don't sit down and tell an app "I bank with HDFC, my mother is Amma, I have a maths exam at 11:50." So most AI assistants stay shallow. They answer when asked and forget you the moment you close them. Pulse was inspired by the opposite premise: an agent that observes your phone, learns who you are, and reminds you of what you'd forget, like a trustworthy well-wisher who has everything of that one person. Less chatbot, more someone who has your back.
What it does
Pulse is a phone-first, proactive AI life agent.
Perceives your phone. A native Android service reads the notifications any app posts (a bank alert, a friend's message, a delivery) and feeds them to the agent. It ignores OTPs and spam, and keeps only what matters. Learns you, quietly. From those signals it extracts durable facts ("uses an HDFC card", "close to their mother Amma", "is a Senior Engineer") into a compact, growing memory. No forms, no setup. Reminds you, unasked. It surfaces proactive, explainable reminders ("Pay HDFC card bill, due June 5", "Call Amma back", "Maths exam tonight at 11:50") with the reason it flagged each one. Connects across your whole life. A Context Engine reasons across documents, email, calendar, health, money, relationships, learning, and travel at once. For example, it computes what money is actually yours to spend. Answers anything. One place to ask across your entire life ("what did I spend on food?", "when is Asha's birthday?"), grounded in your data, in your language (English or Hindi). Helps you grow. A Learning Companion with spaced repetition, plus health, money, people, and travel modules.
How I built it
One loop, reused everywhere: signal -> understand (Gemini) -> store with context (MongoDB) -> connect (Context Engine) -> act (nudge).
Backend: Node.js and NestJS in TypeScript. Each life domain is its own module on a shared platform, so adding a feature is never a rewrite. AI: Google Gemini 2.5 Pro for reasoning (with gemini-2.5-flash as a fallback), and gemini-embedding-001 for semantic search, all behind a resilience layer (error classifier, jittered backoff, model fallback, a cross-process rate breaker, and a deterministic mock so it runs with no key). Data: MongoDB Atlas, with vector search for documents. Similarity is plain cosine.
When the Atlas vector index isn't present, it falls back to in-app cosine so search still works. Mobile: React Native and Expo (SDK 54), React 19, React Navigation, and TanStack Query. The senses: a custom Expo native module written in Kotlin, built around Android's NotificationListenerService. The phone streams signals to the backend, and a perception pass uses Gemini to both learn facts and write reminders. Spaced repetition for learning follows an SM-2-lite schedule, where a correct recall grows the interval. Trust: AES-256-GCM encrypted tokens, consent-gated capture, full export and delete, helmet, CORS, and rate limiting. Quality and delivery: Jest (45 tests), GitHub Actions CI, and EAS Build for the Android dev build.
Challenges I ran into
Phones sandbox apps on purpose. Reading other apps' notifications meant leaving Expo Go for a custom native module, which only runs in a compiled dev build. The "well-wisher who sees your phone" is realistically an Android first capability, since iOS does not allow it. A stale dependency vs a modern stack. The popular notification-listener package only supports React 18, but the app is on React 19. Rather than force it, I wrote my own native module so nothing is throwaway. The gitignore that ate the native code. A blanket android/ rule (meant for the generated project) silently excluded my module's Kotlin source, so the cloud build shipped without it. The app kept reporting the module as "not available" until I traced it to version control. A Kotlin return-type error. The Expo function DSL expected a value, and a bare early return broke the build. A small fix, found only by reading the Gradle log line by line. Embeddings. The first model returned 404 for my key, so I moved to gemini-embedding-001, kept the vector dimension consistent with the offline embedder, and added self-healing so older vectors get re-embedded on demand. Reactive vs proactive. My first version batched signals and waited for a tap. A well-wisher should not wait to be asked, so I made the agent perceive on its own.
Accomplishments that I'm proud of
It genuinely perceives, learns, and reminds. Given a real bank alert, a message from mum, and an OTP, Pulse ignored the OTP, created "Pay HDFC card bill" and "Call Amma back", and learned durable facts about the user. End to end, on a real phone. A real, permanent stack, live. Gemini 2.5 Pro and MongoDB Atlas both running, not a mock demo. Explainability built in. Every reminder shows why it fired and which source caused it. Honest engineering. Demo-mode fallbacks everywhere, 45 passing tests, and a resilience layer so the agent degrades gracefully instead of failing.
What I learned
The real line between "an app that calls an LLM" and an "agent": perception, memory, and acting unasked, not just answering. How mobile platforms gate sensitive data, and how to build a custom Expo native module in Kotlin the right way. How vector search actually behaves: embedding dimensions must match, and a graceful fallback beats a hard dependency on a cloud index. That trust is the product. An agent that sees your life is only acceptable if it minimizes what it keeps, explains itself, and lets you delete everything.
What's next for Untitled
Push the proactivity all the way: Pulse sends its own notifications so it reaches you even when the app is closed. Go live on the cloud: deploy the backend to Cloud Run so it runs without a laptop. Connect real feeds: Gmail and Google Calendar through Google OAuth. More superpowers: free and budget-friendly course suggestions for students, news and price intelligence, and call and conversation intelligence. The web companion: a memory window to review everything Pulse has done for you.
Built With
- aes-256-gcm
- expo.io
- gemini-embedding
- google-cloud
- javascript
- kotlin
- llms
- machine-learning
- mongodb
- nestjs
- node.js
- python
- react-native
- react-navigation
- tool-calling
- typescript
- vector