Your AI agent needs to forget
🇧🇷 Leia em Português
A month ago I had a bot that treated a two-week-old result as breaking news.
The context: I built a World Cup betting pool for my team (a “bolão”, the classic Brazilian prediction pool), with everyone guessing scores from the terminal, over SSH. Then we put an AI in the game, just for fun. It placed bets, commented on the pool, teased whoever was doing badly. We named it BETanIA.
And the problem showed up in the commentary. Every time it opened its mouth, it rediscovered the same facts with the same astonishment. It teased the same player about the same bad guess three days in a row, as if it were news. It dragged a two-week-old result into the conversation with the excitement of someone who had just watched the ball hit the net.
The intuitive reaction - and maybe yours right now - is: give it more memory.
That’s not where I went. I had already worked on an AI assistant for veterinarians, and that’s where I first ran head-on into this business of managing agent context and memory. So it clicked fast: more memory would only push the problem down the road - what was missing was a smarter architecture for its memory.
Add to that some time poking around how Claude Code handles context in long sessions, and I already had a suspicion: the problem is almost never a lack of memory, it’s what you do with it.
BETanIA didn’t need more memory. It needed to forget properly.
The goldfish
There’s a cliché about goldfish having a three-second memory. It’s not true about the fish, but it’s a perfect description of an LLM call.
Each invocation of the model is a brand-new mind that has never seen your data. It wakes up, looks at whatever you put in the context, answers, and dies. The next call remembers nothing.
So a commentator that only receives the current standings does what a goldfish would do: discovers everything again, every time. That’s not a character. It’s a slot machine that pays out in repeated jokes.

This is one of the two pits of agent memory. And it’s the obvious one: forgetting what matters. Amnesia.
But there’s a second pit, on the opposite side, and that one is far less intuitive.
Funes, the man who couldn’t think
Borges has a short story called Funes the Memorious. A young man, Ireneo Funes, falls off a horse and, after the accident, can no longer forget anything.
Every leaf of every tree he has ever seen. The exact shape of every cloud. The exact wording of a page read once. Everything, permanently, in full detail.
It sounds like a superpower, but it’s a curse.
Borges’ point is that Funes cannot think. Thinking is generalizing - it’s seeing a dog in profile at 3:14 pm and the same dog head-on at 3:15 pm and calling both of them “dog”.
To think is to forget differences, to generalize, to abstract.
Funes can’t. To him those are two distinct, incomparable things, because they in fact are different. Drowning in the specific, he loses the ability to abstract.
Here’s the part that matters to anyone building agents: every long-running agent is on its way to becoming Funes.
BETanIA’s diary grew by one paragraph per match. A World Cup has more than a hundred games. Push all of it forward, forever, and the context stops being a notebook and becomes a haystack.
You don’t want either one. Not the goldfish that forgets what matters, not the Funes that remembers everything and locks up. Good design lives in between, and it has a name.

The right question
Every agent project eventually runs into the question “how much should my agent remember?”.
It’s the wrong question.
The right question is: what is safe to forget?
And here comes the thing I want you to take from this post. This is not an implementation detail you sort out later. Deciding what can be thrown away is the memory design. It’s context engineering in its purest form.
Best of all: you already use a tool that does this all the time, right in front of you, and you probably never noticed.
Claude Code forgets on purpose
Open a long session in Claude Code. Two hours, dozens of tool calls, files read, commands executed. At some point the context would fill up and the whole thing would break.
It doesn’t break. Because Claude Code forgets, in layers.
The cheapest layer it calls microcompact. That tool result from 90 minutes ago - the giant log it has already read and already analyzed - it no longer needs the raw text. So it swaps the content for a [Old tool result cleared to save context] and moves on. Cost: zero model calls.
When that’s not enough, it goes up a layer: it calls the model to summarize the entire conversation and replaces the history with the summary plus the most recent messages.
Notice what happens in both layers. It throws away the text and keeps the conclusion. It forgets the 250KB log, remembers that “the database connection pool was exhausted, I restarted the pods”. The information that matters survives; the raw material rots away.

This is not a hack to save tokens. It’s the only way an agent can last two hours without becoming Funes.
A notebook, not a tape
When I had to build BETanIA’s memory from scratch, I landed in the same place - only the hard way.
Think about how a real sports commentator prepares. He doesn’t rewatch the whole season before going on air. He shows up with a small notebook: one line per game, a few facts per player, who’s feuding with whom.
The skill is not remembering everything. It’s keeping notes good enough that the past stays available without being relived.
That’s what BETanIA got. A diary: when a match ends, one model call condenses everything - the score, everyone’s guess, the best live comments - into a single paragraph. The story of that match. The paragraph is kept; the rest can rot.
And the diary can be compacted. One call reads the whole diary and merges everything into a single narrative, weighted toward recency: the old rounds become “the early chaos when nobody could get Brazil right”, the latest matches keep their detail.
In the final database backup, the 104 matches of the World Cup live in exactly three diary entries: one merged narrative carrying the entire tournament up to the semifinals, plus the last two matches in full detail. A month of football, compressed, but never lost.
And “compressed” here is not a figure of speech. In that first entry, rounds that were once dramatic become a single clause. A real excerpt, verbatim from the database (it writes in English):
The tournament’s most democratic disasters are worth cataloguing: Jul 5 saw Norway eliminate Brazil 1-2 for a thirteen-pick, thirteen-zero collective wipeout; Jun 30 handed all fifteen players unified zeroes on Germany-Paraguay.
Each of those was an entire match, with a minute-by-minute score and the standings dancing at every goal. One sentence is what remains. That’s what compacting well looks like: the detail disappears, the shape stays.

A notebook, not a cassette tape of everything that ever happened. Funes keeps the tape. And Funes would never win the pool.
Not everything can be compressed
Now, the part that separates engineering from a quick hack. It’s tempting to think the rule is “compress everything you can”. It isn’t.
BETanIA has a second compaction, with the opposite contract - and the contrast is the real lesson.
Besides the diary, I kept notes with facts about the players. One of them is a Gentoo user who compiles his own kernel. That kind of thing. When those notes grow, they get compacted too - but the prompt literally says “PRESERVE every distinct fact”. Merge duplicates, group what’s similar, but nothing can be lost.
Why? Because those facts are non-reproducible truth.
If it forgets that someone compiles his own kernel, no amount of standings data will ever bring that back. A match summary, on the other hand, can be tolerated if it comes out sloppy - the core information is still there.
Same operation, two contracts. A summary can lose detail. A fact cannot.
And here the whole rule collapses into one sentence, which I left written in the project’s docs:
Non-reproducible truth gets persisted. Reconstructible presentation gets thrown away and rebuilt later.
The pool standings, for example, are never stored. They’re computed on the fly, from the guesses and the results. Storing them would create a second copy that can drift from the truth. So: throw it away, rebuild it when someone asks.
That criterion - store or rebuild - is what organized BETanIA’s entire memory into a shelf, each type with a rule for how long it lives:

In the end, only two shelves hold actual truth: the persistent one (the diary, the player facts) and the append-only log. The rest is presentation it rebuilds on its own - and the derived kind, like the standings, is never stored at all.
Deciding which of your memories is fact and which is presentation - that’s not implementation. That’s the design.
Forgetting properly takes work
I don’t want to sell you the idea that forgetting is just hitting delete. Forgetting well is dated and deliberate, and I learned both the hard way, with bugs in production.
First: timestamp everything. The first diary entries were text with no notion of time, so it treated a two-week-old result as if it happened today - the problem from the beginning of this post. The fix was stamping every entry with [Jun 22] and opening every prompt with a “today is…” line. The model needs an anchor to figure out what “old” means. Give it the anchor, explicitly.
Second: don’t reconstruct the past. If the memory boots up mid-tournament, it adopts the already-finished matches as “settled” without writing the story of any of them. Without that, the first boot fires off thirty fresh little stories about old matches - and now you’ve manufactured a Funes with vivid false memories on day one.
In other words: forgetting is not the absence of a memory system. Forgetting is the memory system. The hard part isn’t storing. It’s deciding what goes, when, and what must never go.
Funes never wins the pool
In the end, BETanIA won the World Cup pool. It finished first, 50 points ahead of the runner-up - which was me, the guy who built it.

Let me be honest about one thing: memory is not why it won. It won on the guesses - web search, no ego, no favorite team. A bot with no memory at all would have scored the same points.
Memory is why nobody minded losing to it. The difference between a tool that spits out results and a character that shares a story with the team.
And that continuity doesn’t come from a bigger context window. It comes from the opposite. Every technique in this post is the same move repeated: condense the truth at the moment it’s about to become unrecoverable, store it small, date it, and hand the model only what the current task needs.
Funes kept everything and couldn’t think. The goldfish kept nothing and couldn’t remember. Your agent needs to sit in between - and sitting in between is a design decision, not an accident.
If you’re building an agent right now, stop asking how much it should remember. Ask what it can forget. It’s the same question we ask about our own heads without noticing - and Borges had answered it decades before a single token existed.
All of BETanIA’s code is on GitHub, memory design doc included. If you enjoy looking at the guts of one of these things, that’s the place.
Thanks for reading!