Skip to navigation

How it works

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.

rivet facts(on the host) rivet compile(anywhere) HCL configuration+ assets + inputs bundle rivet plan(read-only) rivet apply(on the host) journal

The machine that compiles is the controller. It can be your laptop, a CI job, the host itself, or the 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.
  • Inventory: CPUs, memory, disks, mounts, network interfaces, cloud metadata, and any custom 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, for_each and count expansion, functions, templates, and data hierarchies. 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.

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.

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.

Terms

TermMeaning
CatalogThe evaluated desired configuration for one host: resources, relationships, and outputs.
BundleA catalog plus every asset it needs, in one verified file.
FactsA snapshot of a host’s platform, identity, capabilities, and inventory, used during compilation.
CapabilityA versioned token, such as file.native.v1, saying a host supports a resource implementation.
ControllerWherever compilation happens.
RunnerThe program that plans and applies a bundle on the host.
Agentrivet run on a host: it fetches or compiles a catalog, then runs the runner.
Source releaseAn immutable snapshot of configuration published to storage.
EnvironmentA named pointer, such as production, to one source release.
RefreshA restart, reload, or refresh-only command requested by a verified change.
JournalThe on-host record of in-flight work used to recover from interruptions.