Get back a new store and compare by hand.
- You get a store, not a diff.
- Reviewing means eyeballing, which nobody does twice.
- A cleanup can land on top of newer memory.
worked example · dreams
Anthropic’s Dreams let Claude re-read an agent’s memory store and up to 100 past sessions, then hand back a second, reorganized store — duplicates merged, stale entries replaced, new insights surfaced, input never touched. On memseek the same idea is one bounded, cited derivation you own, and what you adopt is a classified diff rather than a store to eyeball.
Design simulation · example walkthrough. The memories, sessions, and proposed diff below are illustrative. Memseek supports the required snapshot, draft, diff, and promotion primitives, but this repository does not yet ship the exact dream catalog shown on this page.
00 · the problem
Nobody, usually — and that is the problem. You would review it if the system told you what changed. A background model re-reading an agent’s memory can genuinely merge duplicates and retire stale entries. But hand back a whole second store and nobody can see which memories moved — so nobody reviews it, and everybody hopes.
Two memories say the same thing, and one of them is out of date.
“Prefers tabs.” + “Uses tabs for indentation.”
It reads the recent sessions and proposes a tidier version.
“Prefers 4-space indentation.”Changed, and it says why: a later session standardised on four spaces.
Every slot is labelled, including the one it wants to throw away.
removed — “Debugged a flaky CI job by bumping the timeout.” kept — “Works in the payments service.”
Read the diff. One line adopts it — and only you can run that line.
review = await memseek.run(run_id) review["candidate_set"]["divergence"] # what moved await memseek.promote(...) # nothing is live until this
New to Memseek? You write one small configuration file describing what your application should remember. After that your application only appends what happened; Memseek does the deriving, keeps every conclusion linked to the evidence underneath it, and hands your agent a bounded briefing instead of a pile of text. Everything below is that file and what it produces — how it works.
The blueprint takes a bounded snapshot of recent sessions and the current heads of four memory keys. A separate policy record states what curation should value. These source records and their versions become the evidence contract for this one run.
sources:
sessions:
kind: snapshot
collections: [sessions]
max_records: 100
max_tokens: 24000
store:
kind: current
collections: [memories]
keys: [style, tools, domain, workflow]
policy:
kind: record
collection: playbooks
key: curation_policykind: snapshotResolve a stable session corpus at one checkpoint, so later messages cannot appear halfway through the rebuild.
kind: currentRead exactly the live heads the candidate proposes to replace and remember their versions for stale-write protection.
keysDefine the entire target store. The model cannot invent a fifth memory category.
A queued run and a frozen copy of its inputs: the four current memories (“Prefers tabs.” · “Uses tabs for indentation.” · “Debugged a flaky CI job by bumping the timeout.” · “Works in the payments service.”) and three recent sessions. The live memories heads do not change.
The task may merge duplicate preferences, replace a stale tabs preference with four spaces, omit a one-off CI incident, preserve a stable domain fact, and add a cited type-hint pattern. It cannot read beyond the sources or call the model indefinitely.
model: strong
limits:
max_llm_calls: 2
max_total_tokens: 40000
max_wall_s: 120
tasks:
- id: curate
use: llm
with:
output_schema: # records + citations
prompt: |
Merge duplicates, replace stale entries,
remove noise, and cite visible UUIDs.model: strongChoose a versioned model alias in catalog configuration rather than hard-coding a provider name in application logic.
limitsCap calls, tokens, and wall time before the run begins. A “dream” is not an open-ended autonomous loop.
output_schemaRequire one legal record shape with citations. A prose essay cannot accidentally become the new store.
Model-call receipts and a proposed four-key result attached to the run: style → “Prefers 4-space indentation.”, workflow → “Always adds type hints to new functions.”, tools → dropped, domain → unchanged. It is still not active memory.
The runtime compares every proposed key with the captured live head and classifies it as added, changed, removed, or unchanged. Completeness matters: a missing key must be an explicit retraction, not an ambiguous omission.
Prefers tabs.
Uses tabs for indentation.
Debugged a flaky CI job by bumping the timeout.
Works in the payments service.
Now prefers four spaces and consistently adds type hints to new functions.
Prefers 4-space indentation.
Always adds type hints to new functions.
The flaky-CI note is classified as a one-off incident, not durable memory.
Works in the payments service.
These effects exist only in the candidate until promotion succeeds.
Visible effect: every input key has an explicit disposition; nothing disappears because the model omitted it.
emit:
from: "{{curate.records}}"
collection: memories
type: memory
keys: [style, tools, domain, workflow]
complete: true
review: requiredkeysMap each output to one of the four legal current heads and reject any extra category.
complete: trueDemand that the candidate accounts for the whole store so review can distinguish “remove this” from “the model forgot it.”
review: requiredStage candidate records and divergence metadata instead of advancing live heads automatically.
One inert candidate set plus a per-key diff: the tabs duplicate merged, style changed to “Prefers 4-space indentation.”, the flaky-CI note removed, “Works in the payments service.” kept, and “Always adds type hints to new functions.” added.
A person inspects the candidate and chooses adopt or decline. Promotion rechecks the captured input heads. If another process updated style during review, the operation is rejected as stale instead of overwriting newer memory.
lifecycle: reviewed
candidate:
covered_keys: [style, tools, domain, workflow]
divergence: [added, changed,
removed, unchanged]
promotion:
precondition: captured_input_heads
on_stale: rejectcovered_keysProve the draft accounted for every store slot defined by the emission contract.
divergenceGive the reviewer semantic change classes instead of asking them to compare opaque store IDs.
on_stale: rejectThis is explanatory pseudoconfiguration for the runtime’s compare-and-set behavior—not a field in the unfinished dream.yaml.
On approval, four new current heads are promoted at once and “Prefers tabs.” moves into history. On decline or staleness, live memory still says “Prefers tabs.” and the draft stays on the record.
01 · the mapping
A dream is an async job over an existing memory store plus 1–100 sessions, producing a new store. Every part of that is already a memseek primitive: nothing here is built for dreams specifically.
llm Task under strict limits02 · run it
Steer the curation policy, pick how many sessions to mine, then open any curated memory to see the records it cites. The tally above fills as the divergence resolves.
The input store is read as a snapshot — the dream can’t alter it.
Output is staged for review; nothing goes live until you adopt it below.
03 · the lifecycle
The dream is a run you can poll or stream. When it completes, the output is a draft you explicitly adopt — or discard, leaving the original untouched and still addressable.
The run is created against a snapshot checkpoint of the input store.
The store snapshot and the windowed sessions load as cited, fenced sources.
One bounded LLM Task merges, freshens, and surfaces — under strict budgets.
Output is compared to the active heads: added / changed / removed / unchanged.
A draft candidate awaits Promotion. The input store is unchanged.
Ready to replay.
04 · how you write it
One is a research-preview endpoint you call and poll. The other shows how the same workflow can be composed from Memseek primitives in a definition you author and version.
# Anthropic Managed Agents — a hosted async dream. # Research preview, gated by dreaming-2026-04-21 alongside # managed-agents-2026-04-01. dream = client.beta.dreams.create( inputs=[ {"type": "memory_store", "memory_store_id": store_id}, {"type": "sessions", "session_ids": [session_a, session_b]}, ], model="claude-opus-4-8", instructions="Focus on coding-style preferences; ignore one-off debugging notes.", ) # typically minutes to tens of minutes, driven by input size while dream.status in ("pending", "running"): time.sleep(10) dream = client.beta.dreams.retrieve(dream.id) # the result is a whole second store, not a diff store = next(o.memory_store_id for o in dream.outputs if o.type == "memory_store")
A single hosted job: it clones the store, runs a pipeline you don’t see, and hands back a second store id. Adopting means attaching that store to future sessions; discarding means deleting or archiving it. Nothing tells you which memories moved — that comparison is yours to make.
# blueprint: derivations/dream.yaml — not checked in yet name: dream sources: sessions: # the one bounded run driver kind: snapshot collections: [sessions] statuses: [active] max_records: 100 # the "sessions window" slider max_tokens: 24000 store: # current keyed memory heads kind: current collections: [memories] statuses: [active] keys: [style, tools, domain, workflow] max_records: 4 max_tokens: 6000 policy: # steering, as one guarded current record kind: record collection: playbooks key: curation_policy max_tokens: 1500 model: strong limits: # cost is bounded, not open-ended max_llm_calls: 2 max_total_tokens: 40000 max_wall_s: 120 tasks: - id: curate use: llm with: output_schema: { ... records[] with required citations ... } prompt: | Rebuild one clean memory store for {{entity}} from the evidence below. Merge duplicates, replace stale or contradicted entries with the latest value, and surface genuinely new insights. Cite only visible UUIDs. CURATION POLICY: {{policy.rendered}} EXISTING STORE: {{store.rendered}} RECENT SESSIONS: {{sessions.rendered}} emit: from: "{{curate.records}}" collection: memories type: memory keys: [style, tools, domain, workflow] # the bounded target complete: true # a full rebuild, every key accounted for review: required # stage a draft — never auto-overwrite
This is an implementation blueprint, not a copy-paste-ready checked-in file: a real catalog must include the collection schemas, a complete output schema, the reviewed artifact, package bindings, and tests. The closest runnable pattern in this repository is the reviewed CRM profile rebuild.
# 1 · steer it: the policy is a record, so rewriting it is an ingest await memseek.records.ingest( collection="playbooks", key="curation_policy", type="playbook", entity="user:ada", text="Focus on coding-style preferences; ignore one-off debugging notes.", ) # 2 · run it — returns a job id immediately, the worker does the work queued = await memseek.run_processor("dream", entity="user:ada") while True: # queued → running → succeeded job = await memseek.job(queued["job_id"]) if job.get("successful_run_id"): break if job["state"] == "dead": raise RuntimeError(job) await asyncio.sleep(0.5) # …or don't call it at all. A cron trigger dreams nightly, and a write # trigger dreams once enough new sessions have landed.
In this blueprint, a memory rebuild is an ordinary run. A completed catalog could fire it on demand, on a schedule, or from a write trigger when enough sessions accumulate. Nothing would become live yet: the run would stage a draft.
# 3 · read the audited run — the draft carries its own classified diff review = await memseek.run(job["successful_run_id"]) candidate = review["run"]["content"]["candidate_set"] candidate["covered_keys"] # every key the rebuild accounted for candidate["divergence"] # per key: added · changed · removed · unchanged # 4 · adopt it — atomic, and only if the store hasn't moved underneath if looks_good(candidate["divergence"]): await memseek.promote( entity="user:ada", source_run_id=job["successful_run_id"], artifact="dream_candidate", # the reviewed contract it must satisfy ) # Decline by simply not promoting: the draft stays in the audit trail # forever, and live memory was never touched.
Promotion re-checks the input heads captured before the Task ran. If the store changed underneath the dream, activation is rejected as stale rather than silently clobbering newer memory — and declining costs nothing, because a draft that is never promoted simply stays a draft.
The one difference that matters: a dream hands you a second store and asks you
to eyeball it — the API reports pending → running → completed and an
output store id, but never which memories moved. memseek hands you the
classified diff: every memory labelled added, changed, removed or
kept, each one cited, over a key set the emission declared in advance — and adopting
it is a compare-and-set promotion that is refused if the store shifted while
you were reviewing.
05 · then take it further
Once the base catalog is implemented and tested, these are the next controls you can add deliberately.
write trigger that fires once a threshold of new sessions lands. New drafts can arrive without a cron; promotion can remain an explicit human decision.contradiction pass so “replace stale entries” becomes explicit: the diff shows which session overturned which prior memory, with both cited.instructions at once. Compare their divergences, promote the best, discard the rest — all against the same immutable input.start building
The necessary engine behavior already exists: bounded sources, model limits, a complete keyed candidate, a visible diff, and explicit promotion. Your catalog supplies the domain.
emit: from: "{{curate.records}}" collection: memories keys: [style, tools, domain, workflow] complete: true review: required
In a completed catalog, complete and review are the two emission flags that make the run stage a full, reviewable draft instead of overwriting live memory.
Design simulation, not a captured or checked-in run. The memories, citations, counts, and
dream.yaml model how a bounded reviewed rebuild can be implemented from supported
primitives. Use the runnable CRM rebuild as the current executable reference.