Captain Memo

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
A ship captain's night cabin — the log book closed beside a brass lamp and compass, its memories rising as golden filaments that gather into three glowing constellation rosettes beneath a crescent moon

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.

Deleting is not the fix

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.

Scattered star-nodes on the left drawn along golden threads into three burning rosette constellations on the right; below them the same rosettes appear again as colourless impressions embossed into the paper — the originals archived, not erased

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.

How dreaming folds memories from several AI assistants into one theme Scattered dots represent observations written by different AI assistants. Lines appear between pairs that get recalled together. Each connected group collapses into a single theme ring, with the original observations dimmed but preserved inside it. Three unconnected observations stay where they are. theme · 6 archived theme · 5 archived
Claude Code Codex Cursor Gemini CLI Lines are co-retrievals — thicker means recalled together more often. The three loners are DBSCAN noise: below --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.

Similarity clustering versus co-retrieval clustering on the same six observations On the left, clustering by word overlap groups three observations that all mention the word cache but solve unrelated problems, and misses two that describe the same bug in different words. On the right, clustering by co-retrieval groups the observations that are actually recalled together, regardless of wording. GROUPED BY WORDS "cache" appears in all three CDN cache purge needs the zone id opcache stale until boot.php touched Smarty cache self-heals, don't rm it left out — no shared vocabulary: webhook returns 400 on live keys signature check reads parsed body GROUPED BY CO-RETRIEVAL surfaced together 9 of 12 times webhook returns 400 on live keys signature check reads parsed body THEME Stripe signature checks must use the raw request body, not the parsed one
Same six observations, two grouping signals. The word-based grouping is confidently wrong three times and misses the one pairing that mattered.
The shipped pass never reads the text

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
Theme

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
Theme

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
No theme

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.

coRet(a,b) = co / (surfa + surfb − co)

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.

temp(a,b) = e^(−Δt / τ)

Same day → ≈1. A week apart → 0.37. A month apart → 0.01.

distance(a,b) = 1 − ( 0.625·coRet + 0.375·temp ) // v1: semantic layer off, weights renormalised

Worked pair — clusters.

surfaced 12 and 12 times, together 9    coRet = 9 / (12+12−9) = 0.600
created 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.751
similarity = 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.

Ten assistants writing into one local corpus that a single dream pass consolidates Ten AI assistant names feed into one local store on your machine, which a single dreaming pass reads and folds into themes that all ten assistants can then read back. Claude CodeCodexCursor Gemini CLIAntigravityKimi opencodeMistral VibeVS CodeJetBrains YOUR MACHINE observations.db recall-audit.jsonl dream one pass, whole corpus themeseverytool reads Nothing leaves the box. No account, no cloud store, no per-vendor silo.
Rows carry an 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.

A tall ship at anchor on still water under a night sky whose stars are joined into constellation networks mirrored in the water below

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 DreamsCaptain Memo Dreaming
RunsAnthropic's cloud, via Managed AgentsYour machine. Reads local SQLite files directly
ReadsOne memory store + 1–100 of that agent's session transcriptsYour whole corpus + the local co-retrieval log
ScopeOne agent at a timeEvery assistant that writes to the corpus, pooled
Grouping signalA model re-reads the transcripts and synthesisesDBSCAN over co-retrieval + recency. The text is never re-read
OutputA new memory store; keep it or discard itThemes in place, members archived, not deleted
CostAPI tokens per dream, scaling with transcript volumeZero. The shipped v1 calls no model at all
StatusResearch preview — request accessDry-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.

SystemRunsPooled across assistantsWhat decides the grouping
Anthropic Dreamscloudno — one agenta model re-reads the transcripts
mcp-memory-servicelocalyesDBSCAN / agglomerative on embeddings
SuperLocalMemorylocalyesentity overlap + temporal proximity
ByteRover V4 "Dream"localyesJaccard token overlap of title + body
shodh-memorylocalyesJaccard over stemmed tokens
MemoryOSlocalpartialwrite-time content similarity
Mem0 · Zep · Cognee · COREmixedpartialan LLM reconciles extracted facts
HeLa-Mem (paper)partialno — one conversationco-retrieval, as a Hebbian graph
Captain Memolocalyesco-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.

Preview only — and it means it

--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.

 captain-memo dream --dry-run
  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.