Repository navigation
What this release is about
When you change universe, your brain only tells you it still remembers what it actually read.
A universe is one sphere of your working life, such as a client or an employer. When you switch from one to another, your brain searches in the new one from that moment on. What it cannot do is forget what it already read earlier in the same conversation, so it says so: that one sentence is what keeps an answer from looking scoped to the new universe when it is not.
The sentence did not know what the conversation had read. It only knew which universe was active before, often left there by an earlier conversation. So a brand-new conversation whose very first message was /switch could be told "I still have everything I read in 'acme'" about a universe it had never touched. Nothing from that universe was loaded and nothing cost an extra token: the sentence itself was the whole mistake. It was also silent in one case where it should have spoken, when the universe read in was left two switches earlier.
This release makes the sentence true. Your brain now keeps a small private record of which universes each conversation actually read notes from, and the switch reads it.
What you get
Every time you switch universe (/switch)
- 🤐 A conversation that has read nothing is told nothing. Start a fresh conversation, switch, and the confirmation no longer claims a memory it does not have.
- 🧠 A conversation that has read something is told exactly what. The sentence names every universe whose notes you read that is now out of scope, even one you left two switches ago, and never names the one you are arriving in.
- 🔍 Only what really came back counts. A search that found nothing read nothing, and a search across all your universes names the universes its answers came from, not all of them.
- 🤔 When your brain cannot know, it says it conditionally. A conversation that was already open when you updated (even one you reopen after the restart) has no record yet, so until its next
/clearor a new conversation it says "if I read anything in 'acme' earlier in this conversation, it is still in my memory", which is true either way.
What you have to do
Ask your brain to update its engine (/update-engine), then restart Claude once. Your notes, your keys and your constitution are untouched, as always.
Under the hood
A recorder, not a guess. A new recorder answers two moments. When a conversation begins with an empty window (a new conversation, or /clear), it opens an empty entry under that conversation's session id. After every search_vault and get_document, it adds the universe of each note the tool actually returned, read from that note's own frontmatter (the indexer's rule), so an answer with no citation adds nothing and an all-universes search adds only what it found. It never speaks, never blocks, and always exits 0. Each conversation gets its own append-only file in the brain's gitignored .cache/conversation-reads/, one universe per line: two reads landing at once can at worst write the same line twice, never erase each other. The fifty most recent conversations are kept, nothing travels with the brain, a single-universe brain records nothing, and renaming a universe renames it in these records too.
The switch knows which conversation it is in. Claude Code exports the same session id to the shell a skill runs (CLAUDE_CODE_SESSION_ID) that it hands every hook, and it changes on /clear. The switch reads the entry for that id only; another conversation's reads are never counted.
The record only vouches for a window it saw begin. A conversation with an entry is known: the reminder names the named universes it read, minus the destination and the cross-cutting scope, or says nothing. A conversation without one is not: it started before the hook was active (the gap between an update and the restart), or it was resumed after its entry was pruned. A read there is not recorded either, since a partial list would name some universes and hide others. Those conversations, and a shell with no session id, get the conditional sentence, under the same rule as before: silent when leaving the cross-cutting scope, spoken when leaving a named universe.
It reaches existing brains through the usual door. Two entry points, one per event: scripts/session-reads.mjs opens the record at SessionStart, scripts/conversation-reads.mjs fills it after a read. Both are added to settings.json by the update's additive hook reconcile. They are two files rather than one script on two events because the update report is printed by the engine already in the brain, which names a script once per event: one script on two events would read "conversation-reads, conversation-reads". Rehearsed on copies of two real brains, one installed at v3.4.0 and one at v5.5.2 with 720 notes: both report the two hooks as newly wired, each named once, and the owner's territory stays byte-identical.
Left out on purpose. A vault note opened with the plain Read tool is not recorded, since the brain reads through its own search.
Proof. The reported case is a test that was red first: a fresh conversation, /switch, no search, no residue sentence, run end to end through the real command with a real session id. Beside it, the reads being named, the two-switches-ago case, an empty answer, an all-universes search, a note opened in another universe, a rename, and both fallbacks. The hook's trigger was checked against a live Claude Code: it fires on the vault tools' real names, which is what the first version of this fix got wrong before any release. Mutation pass on what the branch wrote, after the code review's redesign: 95.26 % (the pure core at 98.39 %, every changed hunk at 98–100 %); the twelve mutants left alive are equivalent, and the redundant guards the passes pointed at were deleted rather than tested.
Thanks to @chrisdeniaud for reporting it, with the exact sentence and the question that made the fix obvious: does this cost tokens? It did not, and now it does not say anything untrue either.