Back to Blog
· 7 min read · EN

I Taught My 10-Year-Old Product to Dream

Every night at 2:30am my appointment system consolidates what it learned, then forgets on schedule. The four steps to give any product a memory.

AI Memory Architecture WhatsApp BuildingInPublic
I Taught My 10-Year-Old Product to Dream

2:00am in Bogotá

Every clinic that runs on Appcitas is dark right now. The receptionists are asleep. The patients are asleep.

The system is not.

At 2:00am it walks through the day’s leftovers: WhatsApp conversations that went quiet more than two hours ago, web sessions abandoned days back. It closes them, writes down what happened in each one, and queues the night’s homework. At 2:30 a second job wakes up and the system starts to dream. It turns the day’s summaries into vectors. On Mondays it distills a week of conversations into patterns per clinic. And on the first of every month it does the strangest thing I’ve ever asked software to do.

It forgets. On purpose. On a schedule.

I shipped this in July into a product I’ve been running since 2015. The core of it went live in a single day, on boring infrastructure, for cents a night. This article is the how, because the how is the part nobody shows, and because whatever your excuse is, it’s about to get thinner.

The Anchor You’re Probably Stuck On

If you run a product, you already know it “should use AI”. Everyone has told you so. And the only concrete idea anyone ever proposes is a chatbot in the corner, which is how a product tells the world it ran out of ideas.

I was stuck there too, sitting on 107,750 booked appointments and nine years of conversations my system had never once read back. Typing that sentence is embarrassing. The part that should worry you is that it probably describes your product too, and it doesn’t feel embarrassing at all.

The way out of the anchor is realizing this was never an AI problem. It’s a memory problem, and memory is a layer you can build in steps. Four of them, in the order I’d do them again, with the real numbers from my production system so you can calibrate yours.

Step 1: Decide What a Memory Is

Not “store more data”. You already store everything. The question is what unit of experience is worth remembering as one thing.

In Appcitas the answer was the closed conversation. When a WhatsApp thread goes quiet, the system writes an episode: a two-sentence summary, an outcome (booked, cancelled, abandoned), the patient’s sentiment, and the intents it saw. One model call per conversation, temperature 0, capped at 700 output tokens. Cheap and boring by design.

In your product the unit is whatever closes: the completed order, the resolved ticket, the churned account, the abandoned cart. If your domain has a natural moment where a story ends, that story is your episode. Write it down at that moment, because that’s when the context still exists.

Step 2: Distill Facts, Not Logs

An episode says what happened. A memory says what stays true afterward. Those are different tables.

My patient memory rows are five columns that would port to any domain: a type, a key from a controlled vocabulary, a value, a confidence score, and a mention count. “Prefers Saturday mornings, confidence 0.7, mentioned 3 times.” The extraction step pulls at most five of these per conversation, and every value it writes starts life clamped between 0.3 and 0.9 confidence.

The controlled vocabulary is the part I’d defend in a fight. Let the model invent keys and you get forty spellings of “preferred schedule” that can never reinforce each other. Constrain the keys and repetition becomes signal: every time a patient mentions the same fact again, confidence climbs 0.05 and the counter ticks up. The system doesn’t believe things because a model said them once. It believes things patients keep saying.

Step 3: Give It a Circadian Rhythm

Here’s the counterintuitive one: almost none of this runs in real time, and that’s a feature.

Nightly, the dream cycle embeds the day’s episodes for semantic search, capped at 100 per night. Weekly, on Monday, it reads each clinic’s last seven days (only clinics with five or more episodes, at most twenty clinics per run) and distills up to five patterns each: recurring questions, complaints, gaps in what the clinic’s knowledge base can answer. Monthly, it decays: any memory not confirmed in thirty days loses 0.05 confidence.

The decay design is my favorite detail in the whole system. Decayed memories fall toward a floor of 0.30, and the retrieval threshold is 0.40. They don’t get deleted; they go dormant, below the line where the agent can see them. If the patient ever mentions that preference again, reinforcement wakes the seed instead of learning the fact from scratch. Forgetting isn’t destruction. It’s demotion.

And the batch rhythm is what makes the economics work. The nightly sweep processes at most 200 conversations, the queue runs with a concurrency of 2 so it never stampedes my database, and the consolidation math is plain SQL that costs nothing. A brain does not need to be expensive. Mine dreams for cents.

Step 4: Build the Brakes Before the Muscle

This is healthcare, so I built the limits first and I’d tell you to do the same in any domain.

The scope rule: when the agent searches past episodes, the SQL hard-filters to that patient’s phone and that clinic. The model never gets to decide whose memories it reads, because trust boundaries don’t belong to the prompt.

The data rule: the extraction prompt refuses clinical information outright. No diagnoses, no symptoms, no reason for the visit. Any run of six or more digits gets masked before storage, so document numbers and phone numbers can’t leak into memory values.

The humility rule: everything memory contributes to a conversation is advisory. The context pack injected into the agent is at most eight memories and one past summary, budgeted to roughly 600 tokens, and it carries its own rules text: never recite memories verbatim, never use memory as a source for prices or availability, and if the patient contradicts a memory, the patient wins. Prices and appointments come from tools or they don’t come at all.

There’s also a kill switch. One environment variable turns the whole layer off. When you’re bolting memory onto a system people depend on, you want the off button before you want the feature.

What’s Still Missing

The weekly patterns pile up as candidates in a table, waiting for an approval queue I haven’t built yet. Nobody reviews them today, which means the most interesting output of the dream cycle currently has an audience of zero.

Patient memories are retrieved by recency and confidence, not by meaning. Episodes get embeddings; the distilled facts don’t yet. And on the first nights after launch, the embedding backlog meant semantic search quietly degraded to “most recent three”, and no user noticed, which tells you something about how much of this layer is bet and how much is proven.

I also shipped phase 1 and phase 2 on the same day, about two hours apart. I’m telling you that so you don’t romanticize the process: this wasn’t a research program. It was a Monday.

Your Product Already Keeps a Diary

The uncomfortable part of this whole project was realizing the data was always there. Ten years of people telling my system who they are, one message at a time, and the system nodding and writing it into a table it would never open again.

Your product has been keeping a diary for years too. Step 1 is deciding what an entry is. You could do that this week.

Mine starts dreaming at 2:30. Yours is still just asleep.


I’ve built this layer twice in production now, and the second time is another article. If your product is sitting on years of history it never reads back, I want to hear what’s in the diary. Find me on LinkedIn or GitHub.

Related posts