> 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.

# How it works

> Facts, compilation, bundles, the runner, notifications, and the journal.

A Rivet run has two halves. **Compilation** turns configuration and host facts into a bundle and never touches the host. **Application** runs on the host, compares each resource with its current state, and changes what differs.

```mermaid
flowchart LR
  F["rivet facts<br />(on the host)"] --> C["rivet compile<br />(anywhere)"]
  S["HCL configuration<br />+ assets + inputs"] --> C
  C --> B[("bundle")]
  B --> P["rivet plan<br />(read-only)"]
  B --> A["rivet apply<br />(on the host)"]
  A <--> J[("journal")]
```

The machine that compiles is the **controller**. It can be your laptop, a CI job, the host itself, or the [compile service](/operations/compile-service). The program that applies a bundle on the host is the **runner**. The same runner is used whether you apply locally, over SSH, or through an agent.

## Facts

`rivet facts` collects a JSON snapshot of one host:

* **Platform:** distribution, version, architecture, and init system.
* **Identity:** a hash of the machine ID.
* **Capabilities:** which resource implementations the host can support, such as `service.systemd.v1` when systemd is running or `package.apt.v1` when apt is installed. See [capabilities](/reference/capabilities).
* **Inventory:** CPUs, memory, disks, mounts, network interfaces, cloud metadata, and any [custom facts](/language/facts#custom-json-facts) you add.

Configuration reads these as `facts.os.name`, `facts.processors.count`, and so on. Compiling against a host's real facts binds the bundle to that host. Apply refuses a bundle compiled for a different machine, or one that needs a capability the host lacks.

## Compilation

`rivet compile` loads every `*.hcl` file in a directory and evaluates it: variables, [modules](/guides/modules), `for_each` and `count` expansion, [functions](/language/functions), [templates](/language/templates), and [data hierarchies](/guides/data-hierarchy). The result is a **catalog**, a list of resources with fully evaluated values and the relationships between them.

Relationships come from three places:

* **Explicit metadata:** `depends_on`, `before`, `notify`, and `subscribe` in a resource's `meta` block.
* **References:** using `file.config.path` in another resource makes `file.config` its prerequisite.
* **Resource rules:** a file's declared parent directory is ordered first, and a user is ordered after the groups it belongs to.

Compilation then collects every asset (inline content, local files, objects from S3 or GCS, `.deb` archives), verifies checksums, and writes the catalog and assets into a **bundle**. The bundle is an uncompressed tar archive written with mode 0600. `rivet graph` shows the order resources will run in and why.

Bundles can contain secrets in plain text. Marking values `sensitive` keeps them out of reports and diagnostics; it does not encrypt the bundle. See [catalogs and bundles](/reference/bundles).

## Plan and apply

`rivet plan` inspects each resource on the host and reports what would change, without writing anything. It cannot always predict everything. If a package install would change, for example, a dependent file is reported as `deferred` because its outcome depends on the package.

`rivet apply` visits resources one at a time in dependency order. For each one it:

1. Inspects the current state.
2. Records its intent in the journal.
3. Makes the change.
4. Inspects again to verify the result.
5. Marks the work complete and queues any notifications.

If a resource fails, resources that depend on it are blocked, and unrelated resources continue. There is no host-wide transaction and no automatic rollback. The report says which resources changed, which failed, and which may have partially changed. See [plan, apply, and reports](/reference/plan-and-apply).

## Notifications and refreshes

When a resource with `notify` makes a verified change, Rivet queues a **refresh** for each target: a service restart or reload, or a command marked `refresh_only`. Several changes notifying the same service result in one restart, after all of them have finished.

Pending refreshes are stored in the journal. If a run changes a config file and then crashes before restarting the service, the next run performs the restart. As a result, a refresh can occasionally run twice; Rivet prefers that to skipping one.

## The journal and recovery

The journal is a SQLite database in `/var/lib/rivet`. It records runs, in-flight changes, and pending refreshes. It is not an inventory: Rivet always re-inspects the host and never trusts the journal's view of current state.

After an interruption, the next apply removes Rivet's own temporary files, re-inspects the affected resources, and converges them again. Commands re-check their guards, so one without a guard (`always = true`) runs again. `rivet journal` shows unresolved work without changing anything. Don't delete the journal to force a clean run. See [recovery and the journal](/reference/recovery).

## Terms

| Term           | Meaning                                                                                          |
| -------------- | ------------------------------------------------------------------------------------------------ |
| Catalog        | The evaluated desired configuration for one host: resources, relationships, and outputs.         |
| Bundle         | A catalog plus every asset it needs, in one verified file.                                       |
| Facts          | A snapshot of a host's platform, identity, capabilities, and inventory, used during compilation. |
| Capability     | A versioned token, such as `file.native.v1`, saying a host supports a resource implementation.   |
| Controller     | Wherever compilation happens.                                                                    |
| Runner         | The program that plans and applies a bundle on the host.                                         |
| Agent          | `rivet run` on a host: it fetches or compiles a catalog, then runs the runner.                   |
| Source release | An immutable snapshot of configuration published to storage.                                     |
| Environment    | A named pointer, such as `production`, to one source release.                                    |
| Refresh        | A restart, reload, or refresh-only command requested by a verified change.                       |
| Journal        | The on-host record of in-flight work used to recover from interruptions.                         |