What happens while you're not looking
Dreaming
Every day you work, the ship's log gets longer. Dreaming is the pass that reads what piled up, folds what belongs together into one theme, and leaves the originals archived underneath. It runs on your machine — and it folds memories from every assistant you use, not one at a time.
Preview ·--dry-run only, the write path is not shipped
The problem
A log that only grows stops being a log.
Memory systems are graded on what they remember. They should be graded on what they can still find.
Month one
You fix a webhook bug. Three observations get written. You search "webhook" and get exactly those three. The system looks perfect.
Month nine
You've fixed webhooks eleven times. You search "webhook" and get forty rows — eight of which are the same conclusion, written eight different ways, by four different assistants, none aware of the others. The answer is in there. So is everything else.
The obvious answer — expire old memories, cap the corpus, drop the least-used rows — throws away the thing you kept them for. The observation you touch once a year is often the most expensive one to re-derive. Dreaming does the opposite: it makes a summary the thing search hits first, and moves the detail out of the way without destroying it.
The originals do not vanish when a theme forms. They are pressed into the record underneath it — dimmed, out of the way of search, and still there when you need the detail back.
The mechanic
Fold the group, archive the parts.
One pass, four steps: read the window, find which observations keep getting recalled together, collapse each group into a theme, archive the members inside it.
--min-pts, deliberately left alone.
The signal
Grouped by what you recall together — not by what shares words.
This is the part that makes dreaming worth doing, and it is the part most systems get wrong. Cluster on text similarity and you get groups that use the same vocabulary. That is not the same as groups that are about the same thing.
Worth being precise about, because it sounds like an omission and is actually the point: the v1 dry-run scores pairs on co-retrieval and recency only. The semantic layer is specified, weighted, and deliberately switched off until the simpler signals are validated against real data. A pass that never looks at the words cannot produce a group that merely shares vocabulary.
Worked cases
Three groups a similarity search would not have made.
Illustrative examples, in the shape the dry-run reports them: the members that came in, the theme that would come out, and why the grouping happened.
CASE 01 The same bug in four vocabularies
Over nine days you hit one root cause — a payment webhook rejecting live traffic — from four directions, in three different tools. No two observations share a distinctive word. Every time you searched, they came back together.
- webhook returns 400 on live keys only
- signature check reads the parsed body
- express.json() runs before the route
- test mode passes because secret differs
Stripe signature verification must run on the raw request body — mount the raw parser before the JSON one, or live keys fail while test keys pass.
Why it grouped: co-retrieval 0.60 (surfaced together 9 of 15 combined surfacings), created within 3 days. Word overlap between members: essentially zero. A similarity clusterer had no way to see this group.
CASE 02 Two assistants, one conclusion
You debugged a deploy problem in Claude Code on Monday and re-hit it in Codex on Thursday, in a different editor, with no shared session. Both wrote observations. Neither knew the other existed — but your searches kept pulling both.
- CSS deployed but browser shows old file
- @import version pin inside components file
- curl returns new, browser returns stale
A CSS deploy needs three version bumps, not one — outer link tag, inner @import, and the global deploy version. curl hitting the inner URL proves nothing about what the browser fetched.
Why it matters: the theme is built from evidence no single assistant had. Codex contributed the middle observation; the retrievals that bound it to the other two came from Claude Code sessions. Neither tool could have written this theme alone.
CASE 03 The group that was correctly left alone
Three observations from the same afternoon, all about the same file, all sharing vocabulary. A similarity clusterer folds them instantly. Dreaming does not — and it is right not to.
- invoice total rounds at line 412
- invoice PDF margin is 14mm
- invoice list query needs an index
Reported as noise. Three facts that share a filename and a Tuesday, and nothing else. Folding them would produce a summary no one could ever use.
Why it didn't group: they were never recalled together. Same file, same day, same words — but in nine months of retrievals, no query ever wanted two of them at once. That absence is a signal, and only a co-retrieval pass can read it.
Under the hood
Two numbers, one threshold.
No magic, and nothing you can't check by hand. Every pair of observations gets a distance; DBSCAN groups anything closer than --eps.
Co-retrieval similarity
How often two observations surface together, normalised against how often each surfaces at all — so a popular row can't drag everything into its orbit.
Surfaced 100 times each, never together → 0. Surfaced 5 times each, always together → 1.
Temporal similarity
Smooth exponential decay on the gap between when the two were written. Default τ is 7 days.
Same day → ≈1. A week apart → 0.37. A month apart → 0.01.
Worked pair — clusters.
surfaced 12 and 12 times, together 9 → coRet = 9 / (12+12−9) = 0.600created 2 days apart → temp = e^(−2/7) = 0.751
similarity = 0.625·0.600 + 0.375·0.751 = 0.657 → distance = 0.343
0.343 < eps 0.35 → same cluster ✓
Same two observations, never co-retrieved.
coRet = 0, temp unchanged at 0.751similarity = 0.625·0 + 0.375·0.751 = 0.282 → distance = 0.718
0.718 > eps 0.35 → left alone ✗
Written on the same afternoon, about the same file — and still not grouped. Proximity in time is not enough on its own. Co-retrieval is doing the work.
Tunables
--eps 0.35 distance threshold · --min-pts 3 smallest group · --tau-days 7 decay constant · --since 14d look-back window. Loosen with --eps 0.45 --min-pts 2 if a run reports no clusters.
Raise τ when you widen the window
The two interact, and not obviously. At τ=7d and eps=0.35, even a perfect co-retrieval score of 1.0 can only bridge a gap of about 19 days — so a --since 30d run cannot cluster across its own window edges however strong the evidence, unless you raise --tau-days to match. The dry-run prints that ceiling on every run rather than leaving you to work out why the extra fortnight produced nothing.
The pooled corpus
One dream, every assistant.
Ten assistants write into one local corpus through one MCP server. The dream pass runs over all of it at once — so a theme can be built from evidence that no single assistant ever held.
origin_agent tag so you can see who wrote what — the dream pass deliberately ignores it.The retrievals pool too
The co-retrieval log records what surfaced together, not who asked. So when Cursor pulls two observations in one search, that pair strengthens — and the theme it eventually produces is one Claude Code will read tomorrow. The assistants shape each other's memory without ever talking to each other.
Cross-vendor is the default, not a mode
There is no flag to scope a dream to one assistant, because the corpus was never split by assistant in the first place. The only partition is --project. That falls out of the architecture rather than being bolted onto it.
Where the name comes from
We took the name from Anthropic. And moved the idea onto your machine.
Credit where it is due: Dreams shipped in Claude Managed Agents in May 2026 as a research preview — the first time the word named an actual API resource, though Letta and Supermemory use "dreaming" for their own background passes too, so the metaphor is by now a crowded one. A dream reads an agent's memory store alongside its past session transcripts and produces a new, reorganised store — duplicates merged, stale or contradicted entries replaced, fresh insights surfaced — leaving the input untouched. Their framing is the clean one: memory captures what an agent learns as it works; dreaming refines it between sessions.
| Anthropic Dreams | Captain Memo Dreaming | |
|---|---|---|
| Runs | Anthropic's cloud, via Managed Agents | Your machine. Reads local SQLite files directly |
| Reads | One memory store + 1–100 of that agent's session transcripts | Your whole corpus + the local co-retrieval log |
| Scope | One agent at a time | Every assistant that writes to the corpus, pooled |
| Grouping signal | A model re-reads the transcripts and synthesises | DBSCAN over co-retrieval + recency. The text is never re-read |
| Output | A new memory store; keep it or discard it | Themes in place, members archived, not deleted |
| Cost | API tokens per dream, scaling with transcript volume | Zero. The shipped v1 calls no model at all |
| Status | Research preview — request access | Dry-run preview — already in the box |
The two are not competitors so much as the same idea at different altitudes. Anthropic's version has the enormous advantage of a model actually reading your transcripts, and it will surface insights a distance metric never could. Ours has the advantage of seeing every tool you use, running for free, and never sending a transcript anywhere. If you use one assistant and live in the cloud, theirs fits. If you use six and want the corpus on your own disk, that is the gap this fills.
Where this actually sits
Local, cross-assistant consolidation is not rare. The signal is.
It would be easy to claim more here than is true, so here is the honest version. Several projects already run a consolidation pass locally over a corpus shared by many assistants — mcp-memory-service, SuperLocalMemory, shodh-memory, and ByteRover V4 (which also calls its pass "Dream"). That combination is not the differentiator.
What we have not found in any shipped system is a pass that decides what belongs together from which memories actually surface together in real use. Every one we could read the source or docs of groups by re-reading the text — with a model, with embeddings, or with token overlap. (Closed products publish no mechanism, so treat this as "we looked hard and found none", not a proof.)
And the technique itself is old — it is only new here. Grouping things by how often they are fetched together is standard practice elsewhere: co-citation analysis in bibliometrics since 1973, item-to-item collaborative filtering since Amazon's 2003 paper, co-click clustering over search logs since 2000. None of that is our invention. Applying it to an agent's memory is the part nobody had shipped.
| System | Runs | Pooled across assistants | What decides the grouping |
|---|---|---|---|
| Anthropic Dreams | cloud | no — one agent | a model re-reads the transcripts |
| mcp-memory-service | local | yes | DBSCAN / agglomerative on embeddings |
| SuperLocalMemory | local | yes | entity overlap + temporal proximity |
| ByteRover V4 "Dream" | local | yes | Jaccard token overlap of title + body |
| shodh-memory | local | yes | Jaccard over stemmed tokens |
| MemoryOS | local | partial | write-time content similarity |
| Mem0 · Zep · Cognee · CORE | mixed | partial | an LLM reconciles extracted facts |
| HeLa-Mem (paper) | partial | no — one conversation | co-retrieval, as a Hebbian graph |
| Captain Memo | local | yes | co-retrieval + recency |
The closest anyone gets
Two systems come genuinely close, and both deserve naming. SuperLocalMemory already records pairwise co-retrieval on every recall — the telemetry is there — but its consolidation pass never reads it, clustering on entity overlap instead. And HeLa-Mem, a 2026 paper, builds exactly this: edges that strengthen only when two memories appear in the same retrieval result. It is single-conversation and research-stage, not a cross-assistant tool. The idea is not ours alone; the shipped implementation is.
The signal is collected everywhere. It's just thrown away.
This is the genuinely odd part. Three of the systems above already record co-retrieval on every recall — SuperLocalMemory increments pairwise edges, shodh-memory has a CoRetrieved relation type, mcp-memory-service persists the result set of each query. Then none of them lets it decide a grouping. In one case the consumer is dead code that fails on a missing column; in another it is deliberately restricted to strengthening edges that content similarity already created. The data is sitting there, unused, in three separate projects.
What it reads today
Three files, no network.
The Dream block in captain-memo stats shows the inputs the pass would read — not its output. If the audit log is off, dreaming has no co-retrieval signal to work with and falls back to recency alone.
observations.db
The corpus. Non-archived rows inside the look-back window, optionally filtered to one project.
recall-audit.jsonl
One line per retrieval, listing what surfaced together. The co-retrieval signal is built from this. Opt-in: set CAPTAIN_MEMO_RECALL_AUDIT=1.
meta.sqlite3
The index that joins audit entries back to observation ids, so a surfacing event can be attributed to a row.
--dry-run is required. The write path — theme insertion plus member archival — is deliberately not shipped until the dry-run output has been validated against real co-retrieval data. The command never contacts the worker, never writes to the database, and never calls the summarizer. It is safe to run at any time, including while the worker is busy.
That is a deliberate order of operations: a pass that rewrites your memory should be one you have read the output of, several times, before it is allowed to touch anything.
DREAM — DRY RUN ───────────────────────────────────────── cluster preview — no writes, no Haiku Observations 10103 Without co-recall 9445 (93.5% of input — high % means audit log is thin) eps / minPts / τ 0.35 / 3 / 7d Signal weights semantic=0.000 temporal=0.375 coRet=0.625 Max pair age gap 19.0d (pairs further apart cannot cluster at any co-retrieval) RESULT ─────────────────────────────────────────────────── Clusters discovered 87 Would-archive total 454 Noise (singletons) 9649 Cluster 1 · 18 members · coOcc=98 Cluster 2 · 20 members · coOcc=91 Cluster 3 · 15 members · coOcc=73 …
A real run over one busy week. Note the shape: 95% of observations are noise, and the pass proposes archiving 454 of 10,103. Dreaming is meant to fold the few groups that genuinely earned it, not to reorganise everything it can reach. The 93.5% without co-recall is the honest cost of a young audit log — those rows simply have no signal yet, and the pass says so rather than guessing.
Questions
The ones worth asking before you let anything rewrite your memory.
Does dreaming delete my observations?
No. Members of a folded cluster are archived — flagged and linked to the theme that replaced them, still on disk, still readable. The design treats deletion as the one operation a memory system must never perform silently. And today the write path isn't shipped at all, so nothing is modified under any circumstances.
What if I never turned the audit log on?
Then there is no co-retrieval signal and clustering falls back to recency alone, which is a weak grouping on its own — you'll see most observations reported as noise. Set CAPTAIN_MEMO_RECALL_AUDIT=1 in worker.env and give it a couple of weeks of real use before expecting much. The log is opt-in because retrieval queries can contain sensitive text.
Does anything leave my machine?
No. The dry-run opens three local files read-only and does its own arithmetic. There is no network call, no worker contact, and no model invocation — not even to your own local model. It runs identically on a laptop with the network cable pulled out.
Isn't someone else already doing this?
Partly, and it's worth being straight about which part. Local consolidation over a corpus shared by several assistants is already done by mcp-memory-service, SuperLocalMemory, shodh-memory and ByteRover V4. What none of them does is group by co-retrieval — they cluster on embeddings, entity overlap or token overlap. The closest anyone comes is SuperLocalMemory, which records pairwise co-retrieval on every recall but never feeds it to its consolidator, and HeLa-Mem, a research paper that builds precisely this signal as a Hebbian graph for a single conversation. See the comparison.
Why not just use embedding similarity? It's simpler.
Because it answers a different question. Embedding similarity tells you which memories are worded alike; that reliably groups three unrelated notes that all happen to say "cache", and reliably misses the two that describe one bug in different words. Co-retrieval tells you which memories your actual work treats as one topic. The semantic layer is specified and weighted at 0.2 for when it's switched on — as a tiebreaker, not the primary signal.
Can I dream over just one assistant's memories?
No, and that's deliberate. The corpus isn't partitioned by assistant, so there's nothing to scope to — the only filter is --project. Pooling is the feature: a theme built from what Codex saw and what Claude Code saw is worth more than either tool's half of it.
How is this different from Anthropic's Dreams?
Same name, same intent, different altitude. Theirs runs in the cloud, reads one agent's transcripts with a model, and bills per dream. Ours runs on your disk, reads the whole multi-assistant corpus with a distance metric, and costs nothing. See the comparison above — they're complementary more than competing.