Blocks
A block is a small immutable record with apayload wrapped in an envelope. The envelope is what
block_id is computed over, and it has exactly five keys:
Compositions
AComposition is an immutable set of block identities committed by a single Merkle root. Deriving one
returns a new one:
composition.json). Without it a snapshot would identify a version it could not reopen.
Modules
AModule is one memory module at one version: a composition, the store its bytes live in, and its
indices.
with_blocks and without_blocks derive new versions. Module exposes no write method at all —
extending a brain goes through commit, which is the only write path.
Snapshots
ASnapshot is the state of a brain: one ModuleRef per installed module, plus a parent pointer that
forms an auditable chain of versions.
ModuleRef carries the module’s root, the composition digest, the block_count, the Merkle
layout identifier, and the embedding_model behind a travelling vector index when one ships with it.
A brain may hold a subset of modules. Selective installation is the point of packaging each module
separately, so “not installed” is a legitimate state — and therefore an error rather than an empty
module when you ask for one you do not have.
The store
Blocks live in aBlockStore. Two ship with the SDK:
A store must not normalize: bytes that are not canonical do not decode, and bytes that do not hash to
the digest they are filed under are refused. A redacted block is tombstoned, never silently missing —
a removed block must never look like a corrupted one.