Catalogs and bundles
A catalog is the evaluated configuration for one host: resources, relationships, asset references, metadata, and outputs. A bundle is a catalog plus every asset it needs, in one file.
Once compiled, a bundle needs nothing from the original configuration: no HCL, local files, cloud objects, or compile-time credentials. The host still needs the commands and tools its resources use, apt repositories for apt packages, and any plugin runtimes the catalog requires, installed and approved locally.
Confidentiality
Bundles can contain secrets in plain text: file contents, password hashes, decrypted SOPS values, and sensitive outputs. SOPS protects your source, not the compiled bundle. Marking a value sensitive keeps it out of reports and diagnostics; it doesn’t encrypt anything.
Rivet writes bundles with mode 0600, atomically, and never overwrites an existing file. Use umask 077 when handling facts, configuration, and bundles, and store and transfer them privately. rivet graph is safe to share: it verifies the bundle without printing values, outputs, or file contents.
Host binding
Compiling against facts collected from a host binds the bundle to that host’s hashed machine identity. Apply checks the identity, platform, and required capabilities against fresh facts before changing anything. Bundles compiled against a baseline with no identity, such as examples/file/target.json, aren’t bound to any host.
Inventory such as free memory is recorded at collection time and isn’t rechecked during apply.
Format
A bundle is an uncompressed tar archive containing exactly catalog.json and one assets/<sha256> file per asset. Rivet reads it without extracting to disk and rejects anything unexpected: extra or missing members, links, special files, corrupt asset bytes, or unknown JSON fields. Bundles can be at most 256 MiB, with a catalog of at most 16 MiB, and are read into memory.
On receipt, Rivet re-validates the catalog with its own resource definitions, recomputing capabilities and ownership claims rather than trusting what the bundle says.
Each catalog records one catalog schema version and one language version. A bundle with any other version is rejected; there is no migration. Templates, data hierarchies, and plugin functions don’t add versions of their own, since only their results are in the catalog.
Digest
Every catalog has a semantic digest: a SHA-256 of its canonical JSON, excluding source locations. Reordering or moving declarations in your source doesn’t change it. Anything that changes desired state does: resource values, metadata, assets, outputs, target assumptions, compiler version, and the facts actually used. Collection time and unused facts don’t.
Modules
rivet init downloads and verifies remote module sources for compilation. The module cache isn’t part of the bundle; the bundle contains only the evaluated result and its assets. Only root outputs are stored; child module outputs exist only during compilation.
Named and numbered instances, such as file.config["a"] and file.config[0], are distinct identities. Removing an instance from a later catalog doesn’t remove its host objects. See expansion.
Plugins
A catalog records the exact plugin implementations it was compiled with. Before changing anything, the host checks that its installed plugins match. A bundle can’t supply an executable path or approve an installation. Function-only plugins need nothing on the host. See plugin platforms.
Releases and agents
The agent receives a catalog with external asset locations, then downloads and verifies every asset into an ordinary bundle before applying it. Download URLs, tokens, and the release’s provenance (environment, release, generation) are kept separately and don’t affect the catalog digest. Trusted claims affect the digest only when configuration uses them.