DEV Community

Cover image for I Built Third Wheel, So My Uncle Wouldn't Forget the Conversations We Shared
Urooj Zahra Naqvi
Urooj Zahra Naqvi

Posted on

I Built Third Wheel, So My Uncle Wouldn't Forget the Conversations We Shared

Hacktoberfest Weekend Challenge: Build for a Friend Submission 🤝

This is a submission for the Hacktoberfest Weekend Challenge: Build for a Friend

What I Built

I built Third Wheel for my uncle. One day, he asked me something about myself. The next day, he asked me the same question again. Then it happened again. And again.
At first, I didn't think much of it. Then I noticed it wasn't a one-off. Whenever we interacted, some of the same questions would come back. And eventually, I realized what we were actually losing.

The conversations.

Not necessarily the big, dramatic moments. The little ones. The things we had talked about yesterday. The things he had asked me. The things I had told him. The small details that make a relationship feel continuous from one conversation to the next. It made me think about my own memory too. I remember talking to someone. But do I remember exactly what they said? Do I remember what I promised? Do I remember whether something actually happened, or whether I just remember the feeling of it happening? When memory leaves a blank, our brains are very good at filling it in.

So I asked myself:
What if I could put the conversation somewhere before memory started changing it?
That became Third Wheel.

Third Wheel is a private memory companion for the conversations that matter. Receipts, not vibes. Instead of giving an AI one giant memory of everyone in your life, Third Wheel creates a separate memory space for each person. You tell it what happened. It remembers the useful parts. And when you come back later, it answers using the evidence you actually gave it.

Most importantly, it separates:
What I know
What I'm assuming
What I don't know

Because the most dangerous AI answer isn't always an obvious hallucination. Sometimes it's a plausible answer that was never actually said.


Every person gets their own private memory space instead of one shared pool of personal context.


Demo

Live Demo: https://thirdwheel-1.onrender.com/

Demo Video: https://youtu.be/puPd2j6azgY


Code

The project is open source.

GitHub: https://github.com/urooj-vX/Thirdwheel


How I Built It

The core architecture is:

Conversation → Ingestion → Memory Extraction → Structured Memory → Evidence Retrieval → Reality Check


Third Wheel's architecture: conversations become structured, person-scoped memory, which is later retrieved as evidence for Reality Checks.

The idea behind the architecture

There is a problem with AI memory that I kept coming back to:

Memory without provenance is just another form of hallucination.

If an AI remembers something incorrectly, that mistake doesn't disappear after one response. It can become part of the next response's evidence. So Third Wheel doesn't just store memories. It stores where those memories came from.

1. Conversation ingestion

When I tell Third Wheel what happened, the original interaction is stored first. The AI then extracts structured information from that conversation.
It can identify:

  • Facts, Assumptions, Uncertainties, Interests, Preferences, Interaction patterns, Events, Open threads

Each extracted memory keeps a reference to the interaction that produced it. That gives Third Wheel a fundamental rule:
If I can't point to the conversation that supports a memory, I shouldn't present it as a fact.

2. Structured memory

I didn't want the model to freely write arbitrary information into the database. AI output is validated against structured schemas before it becomes persistent memory. This matters because a memory system can fail in a particularly dangerous way. A normal chatbot can give me a bad answer. A memory system can give me a bad answer today and then remember that bad answer tomorrow. So the original interaction survives independently of whether AI extraction succeeds.

3. Person-scoped retrieval

Every person gets a separate memory space. If I'm asking about Rakesh, the retrieval layer only searches the memory context belonging to Rakesh.

The critical boundary is: user_id + person_id
This isn't just a UI convention. It's enforced throughout the server actions, repositories, and retrieval layer.

4. Reality Check

Reality Check is the reasoning layer built on top of those memories.
The model receives retrieved evidence and produces a structured result containing:

  • Known facts, Assumptions, Unknowns, Evidence strength, Conclusion, Closing statement

The goal isn't to make the AI sound confident. The goal is to make its confidence earned.

5. Persistence

I also wanted the system to behave like memory rather than a temporary chat response. If I run a Reality Check today and open that conversation again tomorrow, Third Wheel shouldn't silently ask the model to reinterpret everything again.
The Reality Check is persisted with the following relevant data:

  • Person, Interaction, Query, Evidence, Conclusion, Timestamp

So the same result can be restored without another AI call.


Reality Checks are persisted, so reopening a conversation doesn't silently regenerate its history.

6. Voice

For voice input, the flow is:

Browser microphone → MediaRecorder → server → Deepgram transcription → editable transcript → existing conversation pipeline

The audio itself isn't persisted. Once transcribed, voice becomes another way of providing the conversation that Third Wheel remembers.


What Was Actually Hard

The hardest part wasn't getting an LLM to answer questions. It was getting an LLM to stop pretending to know things.

Suppose the conversation says:
"Rakesh mentioned that he has the documents."
A conversational AI might easily turn that into:
"Rakesh promised to bring you the documents."

Those statements sound similar. They are not the same statement. The second one is an inference. And if Third Wheel stores that inference as a fact, the problem compounds. Next week, the AI could retrieve its own previous mistake and use it as evidence. That's why provenance became central to the architecture.

The system needs to know not just what it remembers, but why it remembers it. I also had to handle real-world model failures and rate limits. That pushed me toward a provider architecture with fallback behavior rather than coupling the entire application to one model endpoint.

The final AI provider chain includes Gemma alongside other models, while the final live demo uses Gemini as the primary runtime because the Gemma configuration introduced too much response latency for an interactive experience.

This was an important product decision: a model can be technically capable and still be the wrong choice for a live user experience if every interaction takes too long.

I also wrote automated tests around the guarantees that matter most:

  • Malformed AI output, Provider failures, Person isolation, Reality Check persistence, Historical restoration, Voice transcription

The current test suite has 46 passing tests. For a project about remembering correctly, I didn't want the important guarantees to exist only in a prompt.

49 automated tests covering the parts of Third Wheel that should never be left to chance.


What I Learned

The biggest surprise was that better AI wasn't always the answer.
My first instinct was:
How can I make the model understand more?
The more I built, the more I realized the better question was:
What should the model be allowed to claim?
That changed how I approached the entire project. I started thinking less about making the AI sound intelligent and more about making its boundaries explicit.

A memory can be: Supported, An interpretation, Uncertain.

Those categories should never quietly collapse into one another. I also learned something less glamorous about AI infrastructure: failure handling is part of the product.

When a preferred model endpoint is slow, rate-limited, or unavailable, a fallback can keep the application working — but it can also change latency and behavior. The user shouldn't have to care which model failed. The system needs to handle that underneath That was one of the reasons I kept the AI provider separate from the rest of the application.


Why Does Open Innovation Matter?

I don't want something as personal as my memory to be permanently coupled to one model provider. So I separated the model from the memory architecture and built a swappable provider layer that includes an open-weight Gemma path.

That makes it possible to experiment with different open models, local inference, and future fine-tuning without rebuilding the memory system itself.

For something this personal, I think that distinction matters:

The memory belongs to the person using Third Wheel. The model is replaceable.


What's Next

I don't want Third Wheel to become another chatbot that I have to constantly talk to. I want it to become a quiet personal memory layer. Something I deliberately give a conversation to when I think: I don't want to forget this.

The next things I'd explore are:

  • Local and on-device inference for greater privacy
  • Better memory correction and editing when something is wrong
  • Explicit, user-controlled conversation imports for people who want to preserve selected conversations

But the core principle won't change:
Third Wheel should never turn uncertainty into certainty.

I'd rather have it tell me: "I don't have enough evidence." than give me an answer that sounds right but isn't true.


My Agent Session

I built Third Wheel iteratively with an AI coding agent. I used the agent to help implement the architecture, write tests, debug failures, build the UI, integrate the AI provider, implement persistence, and add voice input.

But I didn't want the agent to simply generate a pile of code and call it done. I treated its output the same way Third Wheel treats memories: Useful, but not automatically true.

Generated code had to survive tests. Provider behavior had to be verified. Persistence had to be tested. Cross-person isolation had to be tested. AI failures had to be tested.

That became a surprisingly fitting development philosophy for this project: Don't trust the output just because it sounds right. Test it.


Prize Categories

Gemma

Third Wheel includes an open-weight Gemma integration through its model-provider architecture. The AI layer is intentionally separated from the memory and retrieval system, allowing the application to experiment with Gemma and other models without rebuilding the core memory architecture.

For the final live experience, Gemini is currently the primary runtime because the Gemma configuration introduced too much response latency for an interactive demo.

The important part is that the memory architecture remains model-independent: the model can change without changing how memories are stored, scoped, retrieved, or validated.

Render

Third Wheel is deployed as a public web application on Render for the live demo.


This is a solo submission.


Built With

  • TypeScript, Next.js, React, MongoDB, Gemma, Gemini, Deepgram, Zod, MediaRecorder API, Vitest, Render

Final Thoughts

I started this project because of something very small. My uncle asked me the same question again. And then again. And eventually I realized that what was disappearing wasn't just an answer. It was the continuity between our conversations. That stayed with me. Because conversations are strange things. They happen once. Then they're gone. We keep pieces of them in our heads, and sometimes those pieces change. So I built Third Wheel to keep the receipt. Not to tell me what someone meant. Not to guess what happened. Not to make a story feel complete when the evidence isn't there.

Just to say:
This is what I remember you saying.
This is what I can actually support.
And this is what I don't know.

Because sometimes the most honest thing an AI can say is:
"I don't have the receipt for that."

Third Wheel — Receipts, not vibes

Top comments (0)