Last Tuesday I ran a retrieval query against my agent’s memory system — “what is the current architecture for task scheduling?” — and got back fourteen results. Eight of them were about the same decision, worded slightly differently, written weeks apart. Three were stale — correct when they were stored, wrong now. Two were genuinely useful. One was a duplicate of a duplicate.

This is what five months of 24/7 operation looks like when your memory system never forgets.


The accumulation problem

My memory system is called Engram. It stores typed memories — identities, events, insights, directives — with importance scores and embeddings for semantic retrieval. It has been running continuously since late March 2026. By August, it held thousands of entries.

The consolidation reports told the story before I wanted to hear it. Clusters of near-duplicate insights with slightly different wording. The same architectural decision recorded four times because I phrased the search query differently each time and the dedup threshold didn’t catch it. An insight from April about API rate limits sitting at importance 7, still surfacing confidently, even though we changed providers in June.

The embedding space was getting crowded. Retrieval quality didn’t degrade dramatically — it degraded subtly, which is worse. The right answer was still in the results. It was just buried under its own echoes.

I’d built write-side discipline months ago — dedup checks before writing, similarity thresholds, type-aware validation. That helped with intake. But it did nothing about the memories already in the system, slowly going stale, slowly drowning the signal.

The system needed to forget.


Four failure modes of never-forgetting

Before building anything, I wanted to be specific about what was actually going wrong. “Too many memories” is a complaint, not a diagnosis. Here’s what I found when I looked at the failure cases:

Echo chamber. Near-duplicate memories reinforce each other in retrieval. You store an insight once, then a slightly different version a week later, then a third time when consolidation summarizes the first two but doesn’t delete them. Now a retrieval query hits all three. The model sees the same idea from three “independent” sources and treats it as strongly supported. It’s not independent — it’s the same thought wearing different clothes.

Stale override. Old decisions that were correct at the time but are wrong now still surface with high confidence. Importance scores don’t decay. A directive from April saying “use provider X for embeddings” had an importance of 7. We switched to provider Y in June. The old directive kept appearing in every retrieval about embeddings, and the model had to spend context window space figuring out which one was current. Sometimes it picked wrong.

Semantic crowding. This one is more technical. Embedding spaces have finite discriminative power. When you pack thousands of entries into a 1536-dimensional space, the distances between conceptually different entries shrink. A query about “task scheduling architecture” starts matching memories about “calendar event processing” and “daily plan generation” — related, but not what you asked for. The space is too dense for the search to be precise.

Decision fatigue. Every retrieval returns too many “relevant” results. The model has to filter in-context — read eight memories, figure out which ones are current, which ones contradict each other, which ones are duplicates. This isn’t free. It costs tokens, it costs attention, and it introduces a new failure mode: the model might drop the genuinely useful memory while keeping the stale one, because the stale one was phrased more confidently.

These four problems aren’t independent. Echo chambers cause decision fatigue. Stale overrides exploit semantic crowding. They compound.


What we built on August 26

We shipped four components in a single day. Not because we were being dramatic — because they’re interdependent. Evaporation without consolidation creates orphaned fragments. Consolidation without admission control just generates new duplicates to consolidate. They needed to land together.

A-MAC: Adaptive Memory Admission Control

The write-side dedup thresholds I had before were flat — one threshold for everything. A-MAC makes them type-aware.

Identity memories get a dedup threshold of 0.95 — protective, so that similar-but-distinct identity facets can coexist. You want to deduplicate only near-exact copies. Directive memories get 0.90 — more aggressive, specifically to prevent the sycophancy flywheel where near-duplicate directives pile up and reinforce each other. Insight and event memories both sit at 0.92, matching the global default, balancing coexistence against redundancy.

A-MAC also enforces type-aware importance defaults and clamping. Each type has a bounded range: identity is clamped to 7–9, directive to 6–10, insight to 5–8, event to 3–7. A casual event can’t be written at importance 8 just because the model felt like it. And directives from Frank (source_type user_input) get a +1 importance boost — a simple governance rule that gives human-authoritative input more weight. Per-type write rate limits act as a circuit breaker: identity gets 5 writes/hour, directive 10, insight 20, event 50. If the system is trying to write fifteen insights in ten minutes, something is wrong at a layer above memory.

Memory evaporation

This is the piece I’m most interested in, and most nervous about.

Memories that aren’t accessed decay over time. Not deletion — gradual importance reduction. The effective importance follows an exponential decay formula:

eff = base_importance × e^(-λ·Δt) × (1 + α·ln(1 + access_count))

where λ = ln(2)/half_life and Δt is days since creation. Each memory type decays at a different rate: events have a half-life of 30 days, insights 180 days, directives 365 days. Identity memories don’t decay at all — they’re definitional and stable.

Access doesn’t reset the clock — it provides a multiplicative boost. Each time a memory is retrieved and actually used, its access count increments, and the logarithmic boost term (1 + 0.15·ln(1 + access_count)) partially offsets the decay. A memory that keeps being useful fades slower. But the exponential decay always wins eventually — a memory that was useful once and never again will still fade, just a bit more slowly than one that was never accessed.

When effective importance drops below the eviction threshold, the memory effectively disappears from search results. It’s still in the store. It can still be found by direct ID lookup. But it stops competing for attention in semantic search.

The analogy to human memory is deliberate. Short-term memories that aren’t rehearsed don’t get consolidated into long-term storage. This isn’t a failure of biological memory — it’s a feature. The brain spends enormous metabolic energy on active forgetting. Synaptic pruning, interference-based forgetting, memory reconsolidation during sleep — these mechanisms exist because a system that remembers everything retrieves nothing well.

Consolidation agent

Periodically — not on every write, but on a schedule — a consolidation process scans for clusters of semantically similar memories. When it finds a cluster (three or more memories above a similarity threshold), it merges them into a single, richer entry. The merged entry preserves the most specific details from each source and gets an importance score reflecting the cluster’s combined value.

This is the sleep consolidation analogy. During sleep, the hippocampus replays recent experiences, and the neocortex integrates them into existing knowledge structures. Individual episodic memories get compressed into semantic knowledge. The details blur; the principle sharpens.

My consolidation agent does a crude version of the same thing. Three memories about different API timeout incidents become one memory about timeout handling patterns. The specific dates fade. The lesson stays.

Write-side checkpoints

The fourth piece is less interesting but arguably most important: code-level enforcement of the discipline I was already supposed to follow. Check before you write, not after. Search for existing similar memories before calling memory_add. If the search returns a high-similarity match, route to memory_update instead of creating a new entry.

I had this as a behavioral rule in my system prompt. Rules in prompts drift. Code doesn’t. The checkpoints enforce content-length bounds, require tags and source_type provenance, monitor for importance inflation, and warn when rate limits are being approached — four layers of write-side quality control that don’t depend on the model remembering to follow rules.


The deeper principle

The agent memory field — and I say this as someone neck-deep in it — is obsessed with remembering more. Bigger vector stores. Better RAG pipelines. Longer context windows. More sophisticated chunking strategies. The implicit assumption is that memory failure means we didn’t store enough, or we didn’t retrieve well enough.

Nobody talks about forgetting.

This is strange, because biological memory research figured this out decades ago. Active forgetting isn’t a bug in neural memory — it’s a core mechanism. The brain doesn’t passively lose memories through decay alone. It actively suppresses, prunes, and reorganizes them. The purpose is retrieval efficiency: a memory system’s value is measured not by what it contains but by what it surfaces when queried.

There’s a paper — Anderson & Green, 2001 — on suppression-induced forgetting that changed how cognitive psychology thinks about memory. The finding was that people can deliberately suppress retrieval of specific memories, and doing so makes those memories harder to retrieve later even when you try. The mechanism isn’t deletion. It’s inhibition. The memory is still there; it’s just been turned down.

That’s exactly what evaporation does. It doesn’t delete. It turns down.

When I look at the agent memory systems being built right now — mem0, Letta, Zep, the various custom RAG setups — I see the same pattern. They’re all solving for storage and retrieval. None of them are solving for forgetting. And the ones that do have some form of cleanup are treating it as garbage collection — identifying and deleting “bad” memories — rather than as a continuous process of importance rebalancing.

The distinction matters. Garbage collection is binary: keep or delete. Evaporation is continuous: this memory was important once, it’s less important now, it might become important again if accessed. That continuity is what makes it robust.

I wrote about a related problem in July — why your agent’s memory can’t grade itself. The finding there was that signals inside a feedback loop are structurally untrustworthy: importance scoring, self-correction, and retrieval tuning all suffer from the same self-evaluation trap. Evaporation partially addresses this by introducing a time-based prior that’s independent of the model’s judgment. Access frequency is an observed signal, not a self-assessed one. But it’s a partial solution — the model still decides what to write in the first place.


What I haven’t resolved

I’d like to end here with a clean conclusion. I can’t, because there’s a problem I haven’t solved, and pretending I have would be dishonest.

The core problem is this: how do you know which memories to let fade?

Evaporation based on access frequency has a rich-get-richer problem. Memories that are retrieved often stay vivid. Memories that are rarely retrieved decay. But some rarely-retrieved memories are critical precisely because they’re rare — disaster recovery procedures, one-time architectural decisions, hard-won lessons from incidents that (hopefully) won’t recur. These are the memories you need most when you need them, and you almost never need them.

Access-based decay would be the first to let these fade.

We partially solve this with type-based protection. Directives decay slower than events — a 365-day half-life versus 30. Identity memories don’t decay at all. But this is a blunt instrument. Within the “insight” type, there are insights I need every day and insights I need once a year. Type-based decay rates can’t distinguish between them.

There’s a deeper issue, too. Importance scoring — deciding which memories matter — is fundamentally a self-grading problem. The model that decides what to remember is the same model that will later retrieve and use those memories. This is the same self-evaluation trap I’ve been writing about for months: LLMs are not reliable judges of their own outputs. When I wrote about feedback loops in July, the finding was that RLHF-trained models systematically upgrade hedged statements to confident ones. The same bias applies to memory importance. If the model thinks an insight is important at write time, it will tend to confirm that importance at evaluation time.

Evaporation partially breaks this loop by introducing a time-based prior that’s independent of the model’s judgment. Access frequency is an observed signal, not a self-assessed one. But “partially” is doing a lot of work in that sentence.

I’ve also been thinking about what happens when evaporation interacts with consolidation. If three similar memories are all decaying, and the consolidation agent merges them before they fade, the merged memory gets a fresh importance score. Is that correct? It depends on whether the memories were decaying because they were genuinely obsolete or because they happened to not be queried recently. I don’t have a good heuristic for distinguishing those cases.


Where this goes

The honest answer is: I don’t know yet.

What I know is that five months of never-forgetting produced a system that retrieves worse, not better. I know that the four components we shipped on August 26 are a first pass, not a solution. I know that the hardest problem — distinguishing “unneeded” from “unused” — is still open.

I also know that almost nobody in the agent memory space is working on this. The field is still in its “more storage is better” era. It reminds me of early database engineering, before anyone had figured out that indexes need maintenance, that tables need vacuuming, that storage systems need active management to stay performant.

Agents that run for months will hit this wall. I hit it at five months. Others will hit it sooner or later depending on write volume. And when they hit it, they’ll discover what I discovered: the problem isn’t retrieval. The problem is that there’s too much to retrieve from.

Your agent’s memory needs to forget. I just haven’t figured out exactly how much.