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

# CLI

> Every rivet command, flag, and exit code.

Run `rivet --help` or `rivet COMMAND --help` for built-in help. Commands are listed in workflow order: preparing and compiling configuration, working with hosts, then releases and agents.

## Global options

`--plugin-lock FILE` works with every command. It selects the approved [plugin](/contributing/plugins) installations; without it, Rivet reads `/etc/rivet/plugins.lock.json` if it exists. The lock pins each plugin's executable path, checksum, release, and descriptor. It never downloads anything.

```sh
rivet plugin-inspect ALIAS /absolute/path/to/BINARY
rivet --plugin-lock /absolute/path/to/plugins.lock.json compile ./site --facts facts.json --out host.bundle
```

`plugin-inspect` runs the named binary and prints a proposed lock entry. Review it before installing. Plugin binaries and locks must be in protected locations, and root runs require root-owned files. Invalid locks, checksum mismatches, unsupported protocols, and conflicting registrations fail before any plugin runs. Over SSH, the host uses its own lock; the controller's `--plugin-lock` doesn't apply there.

## init

```sh
rivet init DIRECTORY
```

Downloads and verifies [remote module](/guides/remote-modules) sources, including those of nested modules, into `.rivet/modules`, and writes `rivet.lock.json`. Commit the lockfile and ignore the cache. Needs Git for Git sources and curl for HTTPS archives. `validate` and `compile` never fetch modules; they require `init` to have run.

## validate

```sh
rivet validate DIRECTORY [--facts FILE] [--vars-file FILE] [--data-hierarchy FILE] \
  [--explain-inputs [--explain-skipped-layers]]
```

Checks configuration without writing a bundle. Without `--facts`, it uses the built-in Ubuntu baseline. Cloud file sources are downloaded to check their checksums, and SOPS layers are decrypted.

* `--vars-file FILE` supplies variable values from one YAML or JSON file (`.json` selects JSON; anything else is YAML).
* `--data-hierarchy FILE` selects a [data hierarchy](/guides/data-hierarchy) manifest. Values from `--vars-file` replace hierarchy values.
* `--explain-inputs` shows where each input value came from, without printing values. Sensitive variables are shown by name only.
* `--explain-skipped-layers` also lists optional hierarchy layers that were missing. It requires `--explain-inputs`.

## compile

```sh
rivet compile DIRECTORY --facts FILE --out BUNDLE [--vars-file FILE] [--data-hierarchy FILE]
```

Evaluates configuration against facts and writes a bundle with mode 0600. `--facts` takes a snapshot from `rivet facts` or a target assumptions file. `--out` must not exist; Rivet never overwrites a bundle. Input flags work as for `validate`. Functions, file reads, templates, SOPS decryption, and cloud downloads all happen here.

## test

```sh
rivet test [DIRECTORY] [--recursive] [--filter TEXT] [--format text|json] [--allow-empty]
```

Runs the `tests/*.rivettest.hcl` suites in DIRECTORY (default `.`) against compiled catalogs, without touching any host. `--recursive` includes suites in child directories. `--filter` selects cases whose `suite > test [variant]` name contains TEXT. An empty run fails unless `--allow-empty` is set. See [testing configurations](/guides/testing).

## graph

```sh
rivet graph BUNDLE [--format text|json]
```

Verifies the bundle and prints resources in execution order, followed by each ordering edge and its reason. Values, outputs, and file contents are never printed. JSON output for configurations with modules also includes module boundary nodes and edges.

## Host commands

`facts`, `plan`, `apply`, and `journal` run on a host. Choose it with exactly one of:

* `--local`: this machine, which must be Linux.
* `--target DESTINATION`: a remote host over SSH, such as `user@example.org` or a `Host` alias. Works from macOS.

| SSH flag                 | Meaning                                                                                         |
| ------------------------ | ----------------------------------------------------------------------------------------------- |
| `--sudo`                 | Run as root through passwordless sudo on the host.                                              |
| `--ssh-user USER`        | Log in as USER.                                                                                 |
| `--ssh-port PORT`        | Connect to PORT (1 to 65535).                                                                   |
| `--ssh-config FILE`      | Use this OpenSSH config file for every connection.                                              |
| `--runner-binary FILE`   | Upload this Linux binary as the runner, even if a compatible one is installed.                  |
| `--runner-manifest FILE` | Select runner artifacts from this release metadata file.                                        |
| `--installed-only`       | Require an already-installed runner and never upload one. Conflicts with the two options above. |

These flags require `--target`. `--timeout-seconds N` limits the runner session (1 to 86400 seconds, default 86400) and also works with `--local`. Over SSH, `--facts-dir` and `--state-dir` are paths on the remote host. See [SSH from a controller](/operations/ssh).

Applying changes requires root on the host. With SSH, log in as root or add `--sudo`.

### facts

```sh
rivet facts (--local | --target DESTINATION) [--facts-dir DIR]
```

Prints a JSON snapshot of the host: platform, hashed identity, capabilities, built-in inventory, and custom facts from DIR (default `/etc/rivet/facts.d`). Executable custom facts run as the runner's user. See [facts](/language/facts).

### plan

```sh
rivet plan BUNDLE (--local | --target DESTINATION) [--format text|json] [--detailed-exitcodes]
```

Predicts changes without writing anything to managed objects or runner state. Over SSH, it may still upload a runner; add `--installed-only` to prevent that. See [plan and apply](/reference/plan-and-apply).

### apply

```sh
rivet apply BUNDLE (--local | --target DESTINATION) [--noop] [--state-dir PATH] \
  [--format text|json] [--detailed-exitcodes]
```

Converges the host. `--noop` behaves like `plan`. `--state-dir` uses a different private journal directory (default `/var/lib/rivet`); the host lock is always `/run/rivet/apply.lock`. Work left pending by an interrupted earlier run is always recovered first. See [recovery](/reference/recovery).

### journal

```sh
rivet journal (--local | --target DESTINATION) [--state-dir PATH]
```

Prints unresolved intents and refreshes as JSON, opening the journal read-only. Root's journal is in `/var/lib/rivet`; an unprivileged user's default is in their XDG state directory. To read root's journal, run as root, use `--sudo`, or pass a `--state-dir` you can read.

## Releases

```sh
rivet release publish DIRECTORY --store URI
rivet release validate --store URI --cache-dir PATH [--environment NAME] [--facts FILE]
rivet release compile --store URI --cache-dir PATH --facts FILE --out BUNDLE [--environment NAME]

rivet environment promote NAME --release DIGEST --store URI [--expected-generation N]
rivet environment show NAME --store URI --cache-dir PATH
```

* `release publish` uploads an immutable snapshot and prints its `sha256:` digest. It doesn't change any environment.
* `release validate` compiles the environment's release without downloading asset contents. Without `--facts`, it uses the built-in Ubuntu baseline.
* `release compile` also downloads and verifies every asset, and writes a standalone bundle.
* `environment promote` points an environment at a release after checking the release is complete. `--expected-generation 0` requires a new environment; a positive value requires that current generation. Concurrent promotions are detected either way.
* `environment show` prints the environment's current release and generation as JSON.

The environment defaults to `production`. Digests can be given with or without the `sha256:` prefix. See [releases and environments](/operations/distribution).

## run

```sh
rivet run [--config PATH] [--environment NAME] \
  [--source URI | --server URL] [--auth gcp] \
  [--cache-dir PATH] [--facts-dir PATH] [--offline] \
  [--noop] [--state-dir PATH] [--format text|json] [--detailed-exitcodes]

rivet run [--config PATH] [--environment NAME] \
  [--source URI | --server URL] [--auth gcp] [--cache-dir PATH] [--offline] \
  --prepare-only [--facts FILE] --out BUNDLE [--format text|json]
```

The [agent](/operations/agent): gets a catalog, verifies its assets, then applies it locally. Applying requires Linux and root. `--prepare-only` writes the bundle instead and works on macOS.

| Flag                   | Meaning                                                                                                                    |
| ---------------------- | -------------------------------------------------------------------------------------------------------------------------- |
| `--config PATH`        | Read this agent config instead of `/etc/rivet/agent.hcl`.                                                                  |
| `--environment NAME`   | Use this environment instead of the configured one (default `production`).                                                 |
| `--source URI`         | Use source mode with this store, ignoring configured server settings.                                                      |
| `--server URL`         | Use the compile service at URL, ignoring configured source settings.                                                       |
| `--auth gcp`           | Authenticate to the server with GCP instance identity. mTLS and OIDC are configured in the file. Not valid in source mode. |
| `--cache-dir PATH`     | Artifact cache (default `/var/cache/rivet`).                                                                               |
| `--facts-dir PATH`     | Custom facts directory (default `/etc/rivet/facts.d`).                                                                     |
| `--offline`            | Apply the last fully prepared catalog without contacting storage or the server.                                            |
| `--noop`               | Acquire and prepare normally, then predict changes without making them. The cache may still be written.                    |
| `--state-dir PATH`     | Runner state directory.                                                                                                    |
| `--format text\|json`  | JSON adds the environment, release, generation, cache statistics, and offline status.                                      |
| `--detailed-exitcodes` | Exit 3 when changes were made or predicted.                                                                                |
| `--prepare-only`       | Write a verified bundle instead of applying. Requires `--out`.                                                             |
| `--facts FILE`         | With `--prepare-only`, compile for these facts instead of the built-in baseline.                                           |
| `--out BUNDLE`         | With `--prepare-only`, the new bundle path.                                                                                |

`--source` and `--server` can't be combined. Releases don't support `--vars-file` or data hierarchies.

## rivet-server

```sh
rivet-server --config PATH [--plugin-lock FILE]
```

The separate compile service binary. It needs a source store, TLS certificate and key, one authentication method (GCP, mTLS, or OIDC), and at least one `allow` rule. See [compile service](/operations/compile-service).

## Exit codes

| Code | Meaning                                                                                                              |
| ---- | -------------------------------------------------------------------------------------------------------------------- |
| `0`  | Success. Without `--detailed-exitcodes`, also returned when changes were made.                                       |
| `1`  | A resource or operation failed, or real-apply work was left unresolved. Also I/O, SOPS, and cloud download failures. |
| `2`  | Invalid arguments, configuration, inputs, bundle, or checksum.                                                       |
| `3`  | Success with changes made or predicted, when `--detailed-exitcodes` is set. `--prepare-only` returns 0.              |

A failure always takes precedence over 3. In automation, treat 3 as success with changes. `rivet test` returns 0 when all cases pass, 1 for failed cases, and 2 for invalid definitions, setup errors, or an empty run.