> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://rivet.chrisboulton.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://rivet.chrisboulton.com/_mcp/server.

# Architecture

> Separate portable compilation, host execution, and recovery responsibilities.

| Crate                | Responsibility                                                                                                                                                                                                                                        |
| -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `rivet-catalog`      | Typed catalog/bundle models, definition registry, attributes, assets, ownership and receipt validation.                                                                                                                                               |
| `rivet-compiler`     | HCL loading/parsing, isolated module scopes, typed inputs/outputs, YAML/hierarchy/SOPS resolution, expansion, built-in functions and templates, remote package integrity, provenance, relationships, and confined assets.                             |
| `rivet-engine`       | Resource lifecycle, deterministic convergence, reports, intent and refresh journal.                                                                                                                                                                   |
| `rivet-resources`    | Explicitly registered portable definitions, one concrete Linux runtime per resource, and the shared service and package lifecycles over pluggable providers.                                                                                          |
| `rivet-plugin`       | Executable installation locks and the `PluginPolicy` that selects them, persistent local RPC, portable plugin contracts, SDK servers, and resource/function/service/action adapters.                                                                  |
| `rivet-linux`        | Facts, protected filesystem/process primitives, account databases, host locks, systemd inspection/commands, and state safety.                                                                                                                         |
| `rivet-process`      | Bounded concurrent child-process I/O, deadlines, process-group cancellation, and safe capture policies shared by controller and runner.                                                                                                               |
| `rivet-distribution` | Immutable source publication/indexes, conditional environments, native S3/GCS/local stores, private artifact caching, catalog delivery/preparation, offline metadata, the compile-service protocol and client, and operational configuration loading. |
| `rivet-cli`          | The `rivet` binary: commands and composition of definitions, runtimes, facts, cloud acquisition, variable inputs, pinned remote module preparation, and one-shot agents. It does not link the compile server.                                         |
| `rivet-server`       | The `rivet-server` binary: authenticated HTTPS compile service, GCP/mTLS/OIDC verification, allow rules and signed-asset refresh.                                                                                                                     |
| `rivet-testing`      | Manifest and module unit tests run by `rivet test`.                                                                                                                                                                                                   |
| `rivet-transport`    | Shared private runner protocol, exact-version compatibility, local/SSH sessions, trusted discovery, transfer, and identity-aware verified bootstrap. No resource policy.                                                                              |

## Definitions and runtimes

A definition owns pure portable compilation and validation. A runtime owns host checks, application, verification, and recovery. Generic catalog/compiler/engine code does not enumerate built-in resource types. Each resource directory holds `definition.rs` and an optional `runtime.rs`, listed explicitly in `resources/mod.rs`; package providers use the same split beneath package. A test asserts every directory is registered.

Built-in definitions-only builds support controllers without linking runner contracts. The `runtime` feature enables resource runtime interfaces; native registration and helpers remain Linux-gated. `rivet-linux` supplies infrastructure and does not depend on resource registration.

## Executable extension boundary

The CLI combines built-ins with locally approved [subprocess plugins](/contributing/plugins). Definitions/functions use a portable role; target runtimes use a runtime role. A process is reused for its composition lifetime, with serialized bounded calls and deadlines. Discovery and separate phases can create additional short-lived sessions.

The host retains expression evaluation and annotations, asset acquisition, receipt validation, graph/ownership checks, host locking, durable intent, verification, and refresh delivery. Plugins return portable results and disposable work/verification handles; handles never enter catalogs or journals. Service and package backends supply native primitives to the existing service and package lifecycles.

Catalogs record pinned plugin compilation identities. External resources and service selections bind desired/recovery digests to the implementation. RPC remains local to the controller or runner; SSH still uses the separate runner transport. Installation approval is local policy and cannot come from a bundle.

## Input and evaluation boundaries

`VariableInputs` stores values and sensitivity together, exposes read-only inspection, and has no value-printing Debug. Rust callers use `CompilationRequest` and `compile_configuration_request` to combine explicit inputs, inventory facts, and independently authenticated trusted facts with one asset loader. Hierarchy callers first use `resolve_configuration_inputs`, then pass its opaque `inputs()` into the request, preserving source-derived sensitivity. Resolution and compilation validate independently; `CatalogCompilation::into_bundle` requires all bytes before producing an offline bundle.

Function dispatch declares arity, implementation family, and annotation policy in `builtin_functions.rs`. `EvaluationScope` distinguishes configuration scope from isolated explicit template bindings; lexical bindings restore after errors. Source roots remain attached to declaring expressions. Functions/templates do not add runner-time evaluation.

Runtime `composition_conflicts` receives all typed declarations of one runtime explicitly. Static semantics and runtime pairings are validated at run entry. Preflight inspects every resource once; each mutation gate freshly re-inspects only the mutating resource (and its type's composition policy) against the latest claims of the others, without rerunning planning. Composition safety uses the longest declaration timeout in its group; individual safety inspection uses its declaration timeout. Ordinary planning checks have no implicit catalog/peer access. Shared-file writers retain a verified snapshot; file work keeps resolved intent separate from host observations.

## Distribution boundary

[Release publication](/operations/distribution) writes indexed plain files and changes no environment. Promotion verifies completeness before a conditional pointer update. Acquisition pins one release per run, and delivery separates desired catalog semantics from transport locations. Preparation verifies all asset bytes before local convergence; the engine does not fetch distribution objects.

`rivet-server` owns HTTPS, GCP/mTLS/OIDC verification, principal/environment allow rules, and catalog-bound signed-asset refresh. The service passes an independently authenticated `TrustedFacts` context into compilation; submitted inventory cannot populate it. Library callers supplying `CompilationRequest::trusted` or `ReleaseCompileRequest::trusted` must perform authentication themselves. Unused claims and credential lifetime fields do not affect desired-state digests.

The distribution pipeline currently stages immediate root HCL, without module/auxiliary expression-file preparation or YAML/hierarchy inputs. [Direct compilation](/reference/cli#compile) retains those features. Explicit offline runs restore a previously prepared catalog; they do not authenticate a new identity or observe current environment pointers. Cache metadata excludes signed URLs, tokens, and refresh tickets.

## Fact collectors

Each built-in fact group is collected by one file in `crates/rivet-linux/src/facts/`. To add one, add a lowercase `.rs` file to `crates/rivet-linux/src/facts/` and list it in `FACT_COLLECTORS` in `facts/mod.rs` (one `mod` line and one table entry). The filename is the fact key; a unit test fails if a collector file is not listed.

For example, `boot_id.rs`:

```rust
use super::{FactContext, ResourceError};
use serde_json::{Value, json};

pub(super) fn collect_fact(context: &FactContext) -> Result<Option<Value>, ResourceError> {
    Ok(context.optional("/proc/sys/kernel/random/boot_id")
        .map(|id| json!({"id": id})))
}
```

Return `Ok(None)` when the fact is inapplicable, `Ok(Some(value))` for any JSON shape, and `Err` when collection must fail. Use the shared context for file reads so synthetic-host tests can exercise the collector. Keep collector tests inline under `#[cfg(test)]`.

Users can add facts without rebuilding Rivet through [custom fact files](/language/facts#custom-json-facts).

## Domain terms

* **Catalog:** fully evaluated desired configuration, including relationships and outputs.
* **Bundle:** catalog plus verified configuration assets.
* **Source release:** immutable index and plain source files identified by the index digest.
* **Environment:** named mutable pointer to one complete source release, with a promotion generation.
* **Catalog delivery:** manifest, provenance, and inline/external assets to be verified into a bundle before execution.
* **Trusted facts:** credential-derived principal, node, and claims supplied independently of node inventory.
* **Fact:** captured read-only target/platform/inventory value used at compilation.
* **Observation:** current host object state read during planning or application.
* **Resource handle:** declared work carrying dependency provenance, not a runtime result.
* **Logical identity:** declaration address; **physical ownership claim:** the host object or entry it manages.
* **Expected change:** prediction from current observation; **verified change:** postcondition-confirmed managed change.
* **Refresh:** action requested by a verified change, separate from ordinary convergence.
* **Refresh obligation:** durable outstanding causal work that may repeat after interrupted acknowledgement.
* **Shared prerequisite action:** coalesced readiness work, such as the systemd definition-reload barrier.
* **Journal:** records needed to recover interrupted work, rather than inventory or rollback data.

The repository's `CONTEXT.md` is the full domain glossary, and design decisions are recorded in `docs/adr/`. `docs/specification.md` is the original design and describes features that don't exist yet; this site documents what is implemented.

Module entry/completion barriers are catalog graph nodes with no host operation or mutation intent. Module notifications attach durable obligations to descendant resource changes and gate delivery on successful completion. The journal still records resource mutations rather than treating a module as one atomic transaction.