I wanted to build something that actually accumulates a picture of you over time. That's 1in100, a mobile-first speaking practice app I built for the Supermemory Local hackathon: pick a category, spin for a random topic, choose your difficulty, and speak for 15 to 60 seconds. Simple enough. The interesting part is what happens on your third attempt in the same category, not your first.
The comparison that shaped the whole build
There's an existing app, Magnetic, that does random topic + timer + per-session scoring really well. That's a good baseline. It's not a differentiator. If I built the same thing with a nicer UI, I'd have a worse version of something that already exists.
The actual question I kept coming back to: what can a memory layer do here that a single stateless API call can't? Not "your confidence score is 72 today." That's just a number. The interesting version is: "every time you get a finance topic, you hedge about three times more than your average, and here's the exact phrase you used last time and the time before that." That requires real retrieval across sessions. That's the whole reason this is built on Supermemory Local instead of just calling an LLM once per attempt and calling it a day.
How the loop actually works
Every completed round goes through a real pipeline, not a mockup:
Recording: browser MediaRecorder, captures the full clip for your chosen duration
Transcription: Groq Whisper (whisper-large-v3-turbo), transcript back in a few seconds
Scoring: words-per-minute from the transcript, a filler-word regex pass, and a Groq call (llama-3.3-70b-versatile) judging hedging language and structure
Memory write: the full round, topic, category, duration, scores, transcript, timestamp, gets written to Supermemory Local as a structured event
Memory retrieval: before showing you results, the app searches your past attempts in the same category and looks for a real, specific, repeatable pattern, not a vibe
That last step is where the actual product lives.
The rule I refused to cut: never invent a pattern
Here's the thing about LLM-generated "insights": they're extremely good at sounding confident whether or not there's anything real underneath. If I let the model generate a callback every single time regardless of whether the retrieved memory actually supported one, I'd have built a very convincing lie generator, not a memory feature.
So the hard rule from day one: if there's no real pattern across at least two past attempts, the app says exactly that, plainly, and never fabricates a callback to fill the silence. This was the one thing on my cut list I marked as non-negotiable, everything else, the leaderboard, auth polish, a second speaking mode, was allowed to slip if time ran out. This wasn't.
Getting the pattern-detection prompt itself right took a few iterations. Early versions produced technically-true but useless output, "you tend to hedge sometimes," which is the kind of feedback that's forgettable because it isn't falsifiable or specific. The fix was forcing the retrieval prompt to demand a single, quotable, specific behavior, an exact repeated phrase, an exact structural habit, tied to which past attempts it showed up in, or nothing at all. Specific-or-silent, no middle ground.
What Supermemory Local specifically bought me here
A few things that would've been genuinely painful to hand-roll:
Structured event storage without standing up my own vector DB and retrieval pipeline. I write a structured JSON event per round, category, topic, transcript, scores, timestamp, and query it back by category later. That's the whole integration surface.
Local-first meant zero latency anxiety during development. No round-trip to a hosted service while I was iterating on the retrieval prompt dozens of times in a single afternoon.
It made the "no pattern found" case cheap to implement correctly, instead of every past attempt at any cost, because the retrieval step is fast enough that checking "do we actually have 2+ relevant past events" before even calling the pattern-generation prompt was a trivial gate to add, not an expensive one to skip.
What I'd tell someone starting the same build
Verify constantly, and don't trust a green checkmark. The single most useful habit in this build was refusing to accept "it should work" as a substitute for actually opening the database and looking at a real row, or actually reading the real transcript output instead of assuming the pipeline behaved. More than once, a "this is done" turned out to be infrastructure working in isolation, a seed script inserting fake rows, a test confirming a table existed, without the actual end-to-end user flow ever being exercised. The bugs that matter hide exactly there.
And build the failure state on purpose. Whisper will occasionally return grammatically coherent nonsense from mumbled or noisy audio, not an empty string, actual plausible-sounding fabricated sentences. If you only guard against empty transcripts, that kind of hallucinated input sails straight through to scoring and memory, and it's worse than a missing guard because it looks like a legitimate result instead of a caught error.
Try it
Demo video: https://youtu.be/soZ6ogp4JgQ?si=O5Z2nMClBA2NRDP5
Repo: https://github.com/CoderOtakuX/1-in-100
Built with Next.js, Groq (Whisper + Llama 3.3), Supermemory Local, Supabase, and Clerk, over the course of a very caffeinated few days for the Supermemory Local hackathon.
If you're building anything where "does this tool remember me" is a real product question and not just a nice-to-have, I'd genuinely recommend starting with the failure case first, decide what "no real answer" looks like before you build what "a real answer" looks like. It's much harder to retrofit honesty into a feature after the fact than to design for it from the start.
Top comments (0)