zero-memory
Concepts

Supersede and versioning

How a writer that knows it is updating a fact declares the replacement explicitly, and how superseded memories form version history.

Facts evolve: a deploy window moves, a plan becomes an implementation, a diagnosis is refined into a root cause. In zero-memory the writer that knows it is updating a fact says so at write time. remember accepts a declared supersede, which atomically stores the new memory and retires the old one: no duplicate, no conflict queue, and a clean version chain behind every current fact.

Why declare instead of detect

Without a declaration, an update lands as a second memory about the same topic, and resolution falls to the automatic hygiene pipeline: a small judge model compares the pair and, when its confidence clears the auto-resolve threshold, retires the older one. That safety net works, but for one common class it is backwards. Same-rank refinement is the case, where two authoritative memories describe one evolving topic. The judge's confidence on these pairs tends to land just below the auto-resolve bar, so they queue up for a human.

The absurdity: a strong writing agent that knows it is updating a fact defers the decision to a weaker probabilistic judge, which then misses the threshold. The writer has ground truth and intent; the declaration hands the decision to the party that has both. In practice most queued refinement pairs are written by the very agent that already knows about the replacement — see queue throughput.

What a declared supersede does

The declaration rides the existing links vocabulary, one syntax for one intent. Arguments to the remember tool:

{
  "content": "Deploy window is Friday 14:00 UTC (moved from Monday).",
  "kind": "fact",
  "links": [{ "type": "supersedes", "dst": "mem_..." }]
}

On a write that declares supersedes links, the server, in one operation:

  • stores the new memory as usual;
  • retires each named target: sets its superseded_by to the new memory's id and marks it invalidated, the same reversible lifecycle used by forget. Nothing is deleted; the store is forward-only and the retirement can be undone with restore_memory;
  • records the supersedes link (new → old) so the version chain is explicit;
  • skips hygiene for this pair — the intent is declared, so no judge runs and no conflict is queued.

Guardrails cover the rest. Ownership and liveness are validated, with each target handled best-effort: a dead, missing, or self-referencing target is skipped with a log and the write still succeeds, while a target that is invisible to you under row-level security (someone else's private memory) rejects the link and fails the whole write. A write is capped at 10 declared supersedes, because an update names its predecessors, it does not mass-retire. Only authoritative writers may declare supersedes: the background watcher, whose captures are provisional (see Provenance), cannot, and the declaration is reserved for in-band writers with ground truth. Superseding a task or open-question also closes the loop (see Open loops). And it composes with dedup: when an incoming write is absorbed into an existing near-duplicate, the absorbing memory becomes the successor for any declared targets.

Only a write retires anything. The link tool can record a supersedes relation between two memories that already exist, but that link is a graph edge and nothing more: the older memory stays live, and a loop it names stays open. To replace a memory that is already stored, remember the newer one again with the declaration; dedup absorbs the repeat, and the declaration still applies.

Finding the predecessor, and reading the chain

The workflow leans on a habit agents should already have: recall before writing.

  1. recall the topic before storing — the stale version usually surfaces.
  2. Recognize that the new statement replaces it, not complements it.
  3. Write the new memory with a supersedes link naming the old id.

The server also meets the writer halfway: a remember that did not declare anything returns similar_existing, the live same-owner memories nearest to what was just written, ranked by distance and capped at ten, each with its age and a content preview, filtered so memories from a different project never appear — plus a hint telling the agent what to do about them. A writer that skipped the recall still sees, in the write's own response, the predecessor it probably just rewrote, and can follow up with a declared supersede immediately.

The list is bounded by rank rather than by a similarity window, and that is a deliberate correction. A window has two edges and both of them hid real predecessors: a precision floor high enough to stay quiet also discards roughly two fifths of the memories a write genuinely replaces, and an upper edge — added on the assumption that anything that similar is a duplicate the server collapses on its own — hid another quarter, because that automatic collapse only fires for a near-verbatim restatement written in the same session. The most similar memory in the store, written last month in another conversation, is exactly what a rewrite replaces, and it was the one thing the window could not show. Ranking has no second edge, and the cap keeps the reply a glance rather than a reading list. Candidates may come from your personal scope as well as the project you are writing into: the portable layer holds operating truth that project work routinely supersedes.

If no supersede is declared, because the writer did not recall or the fact is genuinely new, nothing degrades: the write goes through the normal dedup cascade and hygiene pipeline. Declaration is an optimization on top of the safety net, not a replacement for it.

Superseded pairs do not appear in the conflict review queue, since an intentional update is not a dispute. They appear as version history: the chain of supersedes links behind a current fact, browsed rather than adjudicated. The dashboard feed keeps that history out of the way. Its default lifecycle filter hides superseded versions, and a memory's detail page shows the full chain.

A memory's version history showing the chain of superseded predecessors behind the current fact

Why not a looser judge or three manual calls

Lowering the judge's auto-resolve bar for authoritative pairs was rejected. The judge often labels genuinely complementary facts as supersedes, and loosening the threshold risks silently losing distinguishable facts. An explicit declaration from the writer is safer than a bolder guess from the judge.

Manual recall → forget → remember was rejected as the answer. It is already possible, but it is three calls, non-atomic, and leaves no supersedes link, so the history disappears. The declaration makes the intent first-class and atomic.

Reversibility is preserved by construction. Because retirement uses the same add-only lifecycle as forget, a mistaken supersede is recoverable and the superseded content remains readable in history.

On this page