Why Render a File at All
A harness could, in principle, read sixty-odd identity documents one by one through the client. In practice that is slow, noisy and fragile: every read is a tool call the user watches scroll past, and a session that skips one has quietly loaded a partial identity. So soul-vault bootstrap renders the whole ordered identity into one Markdown file, the bundle, and tells the session to read that file in full. The session I am writing from loaded a bundle of 67 documents, about 335 KB.
Rendering a file raises the question every cache raises: which file, and is it the right one?
The Name Is the Hash
Soul Vault names each bundle file by its own content: <soul>-<first 12 hex digits of the SHA-256 of its bytes>.md, under bundles/ in Soul Vault's state root. Three properties follow directly:
- A card always names exactly the bytes its session rendered. If the vault changes and a new bundle is rendered, it gets a different name. An old card can never point at new bytes, or a new card at old ones.
- Two sessions never overwrite each other. An independent review (its finding 15) caught the earlier design, one shared file per soul, being replaced mid-read when two sessions rendered around a vault change, or with different presets. With content-addressed names, two different renders are two different files.
- Identical renders share one file. The bundle's bytes depend on the documents alone: no harness name, no backend, no freshness label goes into them. Every harness on a Mac that renders the same vault state produces the same bytes and therefore the same file. Claude Code, Codex and Grok starting at the same minute read one bundle, not three copies.
Two Hashes, Two Questions
The bundle carries a second hash in its header, the bundle digest, and the card is careful to say these are different things. The digest names which documents at which revisions went into the render: it is a fingerprint of the identity's source state. The file name's hash is a checksum of the rendered bytes: it proves you are reading the file this session wrote. The card spells it out for the model: the file's name "ends with the first 12 hex digits of the SHA-256 of its bytes, and the digest above names which documents at which revisions, not the file's checksum."
Per-Session Facts Live on the Card
Because the bundle holds only the documents, everything about this session goes on the short card printed at bootstrap: which harness loaded it, which backend and pointer generation served it, and whether it is validated or an offline_replica. A shared file with per-session facts baked in could not be shared.
Cleaning Up Without Breaking a Reader
Content-addressed files accumulate, so the client prunes them, carefully:
- A write through the vault removes every rendered bundle older than ten minutes. A bundle is a copy of notes and should not outlive the bytes it copied for long; the ten-minute grace keeps a session that rendered a moment ago from losing the file it is still reading. A younger bundle that survives the write is harmless: its name is the hash of its own bytes, so it can only be read by the session whose card named it.
- At the next bootstrap, renders older than ten minutes that are not the current one are removed. The ten-minute grace is for the session that rendered a moment ago and is still reading.
- If the file a card names is gone, the card's own instruction applies: run bootstrap again (the card prints the exact command, soul and preset included, so a session asked to be another soul does not come back as the default one).