Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Content addressing & the CAS

Everything in zut is addressed by the hash of its bytes. This is the substrate that makes caching correct and sharing safe.

Digests

A digest is the BLAKE3 hash of some bytes plus their length. zut’s digest type and hashing live in src/core/digest.zig. The hash function is recorded in a REAPI-compatible way (the CLI banner shows digest: blake3, REAPI #9), so the store knows which function produced a given address.

The CAS (content-addressed store)

The CAS (src/core/cas.zig) is a key→bytes store where the key is the content’s digest. Properties that fall out of that:

  • Deduplication — identical bytes are stored once, regardless of how many actions produce or consume them.
  • Integrity — a blob read back is verified against the digest it was asked for; corruption or a lying remote is detected.
  • Immutability — an address never changes meaning, which is why a cached result computed elsewhere is trustworthy here.

The CAS is tiered: a read misses locally, falls through to the remote cache if configured, verifies the blob, and populates the local tier. Writes go through to the remote (write-through). A remote failure degrades to local-only rather than breaking the build.

Trees (Merkle directories)

A directory is content-addressed as a Tree (src/core/merkle.zig): a node listing names → child digests (files or sub-trees). The digest of a Tree is therefore a hash of its entire recursive content. This is how:

  • a crate’s unpacked source is grafted into a build as a single immutable input (crate_tree(...)), and
  • an action’s input set is named by one root digest.

The action cache

An action (src/core/action_cache.zig) is keyed by the digest of its command + input Tree + environment. The action cache maps that key to the action result (output digests, exit code, captured stdout/stderr). Because the key is a content hash:

  • the same action never runs twice, and
  • the cache is valid across machines, which is exactly what the remote cache exploits.

This shape mirrors the Bazel Remote Execution API, so the same store backs both local incrementality and remote caching without a second code path.

See docs/ARCHITECTURE.md §3 for the precise encodings and the REAPI mapping.