Commands¶
This page lists every command, what it does, and its flags.
rig <command> --help is the documentation of record. This page is the map.
Overview¶
| Command | Path | Description |
|---|---|---|
lock |
cold | Resolve the workspace, hash every artifact, write deps.lock. |
update [coord [version]] |
cold | Re-resolve, or bump/pin one requirement (shared propagation). |
add <coord> [version] |
cold | Add a requirement (shared by default). |
remove <coord> |
cold | Remove a requirement (shared, from all modules). |
verify |
hot | Check every lock artifact against the cache. The CI security gate. |
check |
cold+hot | Lock-vs-manifest consistency + namespace load and AOT-compile per module. Never re-locks. |
test [opt value…] |
hot | Run the modules' test exec-fns on locked classpaths. |
run [args…] |
hot | Run the module's :rig/main on the (alias) classpath. |
launch [jar] [args…] |
hot | Launch the built artifact with Rig's production JVM flags (G1 + AlwaysPreTouch, exit-on-OOM, loopback JMX on 10101), overridable via :rig/launch-opts and the RIG_LAUNCH_OPTS env var. Replaces its own process with the JVM (process exec) — the app is the container's PID 1. The jar's baked launch plan, or the lock, supplies the main. Never re-locks, never uses the network. |
repl |
hot | clojure.main REPL on the (alias) classpath. |
exec <cmd> [args…] |
hot | Run a command with the locked classpath as CLASSPATH. |
build [--uber \| --native] |
cold | Jar / uberjar / native-image binary via the locked classpath. |
install |
cold | Install module jars into the local Maven repository. |
publish |
cold | Deploy module jars to their remote repository. |
outdated [--breaking] |
cold | Pinned vs available versions. |
tree [--alias a] |
cold | Dependency tree for a module. |
clean |
hot | Remove build-output directories. |
lint |
hot | clj-kondo on the module (no lock needed). |
fmt [--check] |
hot | cljfmt on the module, pinned version (no lock needed). |
new <group/name> |
— | Scaffold a new project. |
new-module <name> |
cold | Scaffold a module in the workspace, add it, re-lock. |
migrate [--dry-run] |
cold | Convert a legacy (:exoscale.* / :slipset.*) or Leiningen (project.clj) workspace to :rig/* in place. |
jvm install <major> |
— | Install the newest Temurin JDK for a major version into the Rig state dir. |
jvm list |
— | Installed JDKs + the system java. |
jvm path <major> |
— | Print the JAVA_HOME of an installed JDK (scripts/CI). |
jvm uninstall <version> |
— | Remove an installed JDK. |
jvm update |
— | Update the rig-managed JDK for the pinned major to the newest release. |
graalvm install <major> |
— | Install the newest GraalVM community JDK for a major version into the Rig state dir. |
graalvm list |
— | Installed GraalVMs. |
graalvm path <major> |
— | Print the GRAALVM_HOME of an installed GraalVM (scripts/CI). |
graalvm uninstall <version> |
— | Remove an installed GraalVM. |
graalvm update |
— | Update the rig-managed GraalVM for the pinned major to the newest build. |
crac install |
— | Install the rig-pinned Zulu CRaC JDK (kernel checkpointing). |
crac status |
— | Pinned CRaC JDK, installed?, active override. |
crac clean |
— | Prune checkpoint chains that can no longer be restored. |
self-update [--check] |
— | Update the Rig binary from the GitHub releases. |
auth get [gate\|url] |
— | Print the bearer token of an OIDC gate (env, cache, or negotiated). |
version |
hot | Print the project version. |
info |
hot | Project and tool summary. |
Hot commands run from the lock (lock → hash-check → launch). They re-lock
only when the lock is stale and --frozen is not set. Cold commands do
deeper kernel work (resolve, build, publish, edit). They can write the lock
or the manifests. launch is hot because it never touches the kernel. It
treats the lock as inert data: it never checks staleness, never re-locks,
and never uses the network. clean, version and info read the
workspace and the lock — they never write the lock, stale or not.
Locking and dependency changes¶
rig lock¶
Resolve every module of the workspace, fetch and sha256-hash every
artifact, and write deps.lock. The command prints skipped version
selections (cooldowns, forces) and a summary:
rig lock refuses --frozen (exit 2): writing the lock is its whole
job. CI modes that must not modify the lock belong on the commands that
consume it. --frozen on rig lock used to be silently ignored while
the command rewrote the lock anyway.
When a cooldown refuses a requirement, the command aborts with exit 5:
refused org.clojure/tools.logging (cooldown 48h)
1 requirement(s) refused by cooldowns (retry with --force)
Requests to an :auth :oidc repository are routed through a local proxy
that injects the gate's bearer token; tools.deps itself never talks to
an authenticated repo. An artifact Maven already downloaded into
~/.m2/repository is accepted at lock time without refetching — Rig
verifies it against the published SHA1. A cold m2 therefore locks as
well, and every request that does go out bears the token. See
authenticated
repositories.
rig update¶
| Form | Effect |
|---|---|
rig update |
Full re-resolve: floating requirements re-select the newest eligible version (cooldown-gated). Exact versions declared in the manifests stay put; the lock's current pins do not. |
rig update <coord> <version> |
Pin the exact version (explicit, recorded in the lock). |
rig update <coord> |
Newest eligible version (cooldown-gated, exit 5 if refused). |
Flags: --alias <a> targets the :extra-deps of an alias, and
--shared-only updates only :rig/deps. The global --force flag
bypasses cooldowns.
rig add / rig remove¶
add flags: --alias <a> adds the requirement under the :extra-deps
of an alias, and --shared defaults to true; --shared=false keeps
the requirement local. -p <module> chooses which module supplies the
:deps to edit. Shared propagation still applies unless you set
--shared=false.
rig migrate¶
rig migrate converts a legacy workspace into :rig/*, in place. A legacy
workspace uses the :exoscale.project/*, :exoscale.deps/*, and
:slipset.deps-deploy/* key namespaces (the output of tools.project and
deps-modules). The command reports every manifest:
What it does, mechanically:
- Renames the
:exoscale.project/*keys to:rig/*, including the inverted:exoscale.project/bypass-test?→:rig/test?. - Materializes
:exoscale.deps/managed-dependenciesinto the:depsof every module that inherits from it, then drops the pool with a warning. Rig does not carry the pool as a:rig/depsshared requirement.:exoscale.deps/inherit(:allor a subset) marks which coords inherit. The managed entry fills the keys a module leaves undeclared. When a module declares a version or source key, that key wins over the managed entry, and Rig reports each such case as a per-dep warning. Rig never rewrites such a key. - Drops
:exoscale.deps/managed-aliases(only the:projectalias exists; Rig has no alias inheritance) and the:projectaliases themselves. - Rewrites
:slipset.deps-deploy/exec-argsinto:rig/publish(:repo); publish enablement comes from the:exoscale.project/deploy?→:rig/publish?rename. A deploy repo with ans3p://URL is a blocking problem (Rig publishes to http/https repositories only).
--dry-run runs the same analysis and reports per-file changes without
writing anything. A blocking problem aborts the whole migration with exit
1, and Rig writes nothing. Blocking problems are, for example, an
inherit-only coord that is absent from the managed map, or
:sign-releases? true.
The same verb also converts a Leiningen workspace: project.clj →
root and per-module deps.edn — profiles become :aliases,
:deploy-repositories becomes :rig/publish, ~var version shorthands
resolve, :sub monorepos decompose into sibling
:local/root modules. See
Migrating from Leiningen for the full key
mapping.
After rig migrate, run rig lock and rig check. The check reports the
remaining drift between the module requirements and the lock (cross-module
conflicts, stale pins).
Inspection¶
rig verify¶
Re-check every lock artifact against the cache.
The command exits 4 on any hash mismatch. Under --frozen, the command
exits 3 when the lock is absent or stale. It is the intended first CI
gate.
rig check¶
Two stages, one exit code:
- Consistency (workspace-wide, read-only) checks:
stale-lock(a requirement the pin does not satisfy).conflict(incompatible requirements).drift(a module requirement differs from the workspace requirement — a warning).floating-version(RELEASE/LATESTin a manifest — an error; fix it withrig update <coord>).no-lib(publish without:rig/lib).unknown-repo(the lock pins via a repo that no manifest declares).pool-unpinned(a:rig/depsentry the lock does not pin — a warning). - Namespace load and AOT-compile: Rig preloads the non-project
requires on the locked base classpath of each target module, then
AOT-compiles its namespaces in dependency order. A failing load or
compile produces a
load-failerror; a source the AOT plan left out — a data file without annsform, a namespace whose name does not match its path — is aplan-skipwarning. Rig reports a module that pinsorg.clojure/clojurebelow the 1.8.0 floor asclojure-floor, before it launches any JVM (the runner entry point cannot load on Clojure 1.7.x). Stage 2 launches on the locked classpath as-is: on Clojure ≥ 1.9 the runtime itself requiresorg.clojure/spec.alphato be present (it loadsclojure.core.serverat init). A module that declares no spec (directly or transitively) therefore fails with aspec/alphaclass-not-found — a missing project dependency, not a Rig failure.
check: error [stale-lock] modules/app org.clojure/clojure: manifest requires "1.11.0"; lock pins "1.12.5" — run rig update
check: 1 error(s), 0 warning(s)
or, clean:
A missing lock is the exception: one message, exit 3.
-p restricts stage 2 only. check never re-locks and never exits 3 for
a stale lock — it reports staleness as a problem and exits 1.
rig outdated¶
--breaking lists only breaking updates. The command prints up to date
when it finds none.
rig tree¶
Print the resolved dependency tree for a module (-p), one line per
occurrence with ├─/└─ connectors. Rig marks an occurrence that is not
in the classpath (conflict, exclusion, duplicate) with its reason.
--alias <a> includes the extra-deps of the alias.
rig info / rig version¶
info prints the workspace summary: modules, lock state (and staleness),
JVM, cache dir, Rig and kernel versions. version prints the project
version from the VERSION file (module dir, then root) or the locked
module version.
Running¶
rig test¶
Run the test exec-fn of each target module (from the lock) on its locked
test classpath. Without -p, every module with a test exec-fn runs, in
the declaration order of :rig/modules. The arguments are EDN literals,
and Rig forwards them to the runner:
When a runner fails, Rig exits 1 and names the failing modules. A hung
run does not wedge CI: rig test kills a runner that has not finished
in 30 minutes and fails — --timeout <dur> configures the watchdog,
0 disables it. A module that pins org.clojure/clojure below the
1.8.0 floor fails before anything runs (the same clojure-floor gate as
check).
rig run¶
Launch the :rig/main of the module on the (alias) classpath. Program
flags after -- pass through: rig run -p modules/app -- --env dev.
--alias <a> selects the classpath. No main → usage error.
rig launch¶
Launch the built artifact with the production JVM flags of Rig — the
entrypoint for a deployed app. rig launch replaces its own process with
the JVM (process exec): the app is the process itself. In a container,
the app is PID 1. Signals reach the JVM directly, and the exit code of
the JVM is the exit code of the process. On Windows, where there is no
process exec, rig forks the JVM and waits. Flags, in order:
- The production defaults of Rig: G1 garbage collection
(
-XX:+UseG1GC, with-XX:+AlwaysPreTouch), exit on out-of-memory (-XX:+ExitOnOutOfMemoryError, plus-XX:+HeapDumpOnOutOfMemoryError), and loopback-only JMX on port 10101 (-Dcom.sun.management.jmxremotewithauthenticate=falseandssl=false). Rig pins the RMI port to 10101, and-Djava.rmi.server.hostname=127.0.0.1keeps JMX to same-host clients. - The
:rig/launch-optsof the module — later flags override the defaults (last JVM flag wins). A garbage collector in:rig/launch-opts, for example-XX:+UseZGC, replaces the G1 default: the JVM refuses to start with two collectors, so Rig drops its own rather than pass both. RIG_LAUNCH_OPTS(env var) — per-deployment JVM flags, whitespace-separated, appended last; the same rules apply (last JVM flag wins; a collector in it replaces any earlier selection).-jar <uberjar>, or-cp <locked classpath> <main>for the plain jar.
The first positional is the jar when it names an existing file. Otherwise (in a workspace) all positionals go to the main. The jar is then the build output of the target module from the lock (the uberjar when the module declares one).
The launch plan (main, :rig/launch-opts, build JVM) comes from
META-INF/rig/launch.json — the descriptor rig build bakes into the
jar of a module that declares a main (uberjars carry it too) — so
rig launch <jar> works outside the workspace (a standalone container).
Without the descriptor, the lock is the plan.
rig launch is offline by definition: it runs what is already in the
cache, from a previous build. The lock is inert data for it: it ignores a
stale lock, and --frozen has no effect. Classpath artifacts must already
be in the cache. The major version of the launch JVM must exactly match
the major version of the build JVM; a different major fails with exit 2.
A missing artifact fails too — it is not fetched — as a plain error
(exit 1).
rig repl¶
clojure.main REPL on the (alias) classpath, in the module directory.
rig exec¶
Run any command with the locked classpath that Rig exports as CLASSPATH
(and JAVA_OPTS from the module/alias JVM options), in the module
directory. --alias <a> selects the classpath. Rig exits with the exit code of the command. Use it for
scripts and tools Rig has no verb for.
Authentication¶
rig auth get¶
Print the bearer token of an OIDC gate to stdout. The gate comes from the
gate config (~/.config/rig/auth.yaml): pass a gate name or a repository
URL the gate fronts, or nothing when the config holds a single gate. Rig
uses the RIG_TOKEN_<GATE> environment variable of the gate when you set
it, else the cached token of the gate, else a fresh negotiation with the
issuer of the gate. Rig verifies a freshly negotiated token against the
JWKS before caching it; a token you supply in the environment is used as
you supplied it. The output is machine-friendly: script it into a curl, or pipe it anywhere a
bearer belongs. See
authenticated repositories.
Building and publishing¶
rig build¶
Build the jar of the module. --uber builds the uberjar (requires
:rig/uberjar?), and --native builds the native-image binary (requires
:rig/native? and the :rig/jvm pin of the workspace; the entry point
of the binary is :rig/main). Every build runs on the locked classpath.
With the :rig/jvm pin of the workspace, Rig scans every jar the build
produces against it as the bytecode floor. A class that would not load on
the pinned JVM fails the build (see JVMs).
The command prints built <path> on success. See
Native images.
rig install¶
Install the module jar(s) into the local Maven repository — every module
with a :rig/lib without -p.
rig publish¶
Deploy the module jar(s) to the remote repository from :rig/publish.
Rig deploys only the :rig/publish? modules, and Rig requires the
network. The repo (:repo is a :mvn/repos id or clojars) must be an
http/https Maven repository. Rig uploads the jar and the POM with
credentials from ~/.m2/settings.xml. For a repo marked :auth :oidc,
Rig uploads instead with the bearer of the gate that fronts its :url
(the RIG_TOKEN_<GATE> variable of the gate, the cached token, or a
negotiated token).
Hygiene and scaffolding¶
rig clean¶
Remove the target directories of the target modules (one cleaned <dir>
line each).
rig lint¶
Run clj-kondo (from PATH, with the config of the project itself) on the module. No lock needed.
rig fmt¶
Format the module with the cljfmt version pinned in the kernel jar —
everyone formats identically. --check reports without fixing. No lock
needed.
rig new / rig new-module¶
rig new com.example/demo # scaffold a project (workspace + module)
rig new-module reporting # add a module to the current workspace, re-lock
new creates <name>/deps.edn (root, :rig/modules),
<name>/modules/<name>/deps.edn, a runnable src, and a test. new-module
scaffolds under modules/, adds the entry to :rig/modules, and
re-locks.
rig self-update¶
Update the Rig binary from the GitHub releases (hash-verified against the
release SHA256SUMS, atomic replace). --check reports only;
--version vX.Y.Z targets an exact release. Release builds only. GitHub
limits unauthenticated release lookups to 60 requests per hour per IP
address; when you set GH_TOKEN or GITHUB_TOKEN, Rig authenticates the
lookup with it.
JVM management¶
rig manages local Temurin (Eclipse Adoptium) JDKs, one per major
version. The requirement of the project is :rig/jvm in the root
deps.edn — a major (feature) version, for example 21. The rig-managed
JDK takes precedence over the system java. A system JDK whose feature
version matches the pin serves only when no managed JDK exists. When
neither exists and rig is online, it installs the newest matching
release on demand.
rig jvm install¶
<major> is a major (feature) version. The command resolves the release
through the Adoptium API, downloads the archive for the current platform,
and verifies the sha256 against the published checksum of the API. It
extracts the JDK to the state dir
(~/.local/share/rig/jdks/temurin-<version>/). Rig keeps one JDK per
major version. When a JDK for the major already exists, this command
exits without changes — use rig jvm update to move it to the newest
release. --offline refuses (installing needs the network).
rig jvm list¶
Installed managed JDKs, then the system java (from JAVA_HOME and
PATH):
installed:
temurin 21.0.12.1+1 linux/x64 /home/…/.local/share/rig/jdks/temurin-21.0.12.1+1
system:
21.0.5 /usr/lib/jvm/java-21-openjdk/bin/java (JAVA_HOME)
rig jvm path¶
Prints the home directory of the newest installed managed JDK satisfying
<major> — the JAVA_HOME value Rig exports for launched processes — as a
bare path on stdout, for scripts and CI. The state dir is read only: the
command never installs or downloads and needs no network. When no installed
JDK satisfies <major>, it fails (exit 2) with the install hint.
rig jvm uninstall¶
rig jvm uninstall 21 # the installed 21.x
rig jvm uninstall 21.0.12.1+1 # exact, or unique prefix (rig jvm uninstall 21.0.12)
rig jvm update¶
rig jvm update is a workspace command (it needs a :rig/jvm pin in the
lock). It updates the rig-managed JDK for the pinned major to the newest
release, and replaces the installed one. Rig keeps one JDK per major
version. When no JDK for the major exists, the command installs the
newest release. The command does not touch the manifest or the lock.
--offline refuses (updating needs the network).
Kernel checkpointing (CRaC)¶
Cold kernel forks cost 1–3 seconds per command. On Linux, Rig can instead restore the kernel JVM from a checkpoint of a warmed run (~0.3 s) and refresh the checkpoint with every command, so it stays warm with use. Checkpointing is opportunistic: without a CRaC-capable JVM every command takes the cold path, unchanged. See Configuration — Kernel checkpointing.
rig crac install¶
Downloads the exact CRaC JDK build (Azul Zulu) pinned by the Rig
release into the state dir
(~/.local/share/rig/jdks/zulu-crac-<version>/), verifying the sha256
against the pin. The kernel picks it up automatically for
checkpointing; nothing else changes. --offline refuses (installing
needs the network).
rig crac status¶
The pinned build, whether it is installed, and whether RIG_CRAC_JDK
currently overrides the managed install.
rig crac clean¶
Image chains are keyed to the kernel jar bytes, the JVM build and the
CPU features: after a kernel or JDK rotation the old chains can never
restore again. This prunes them, plus interrupted-run leftovers.
Chains rebuild themselves — pruning one that was still live costs one
cold command. Old-kernel chains actually clean themselves up: a daily
boot sweep prunes chains bootstrapped from a different kernel jar.
clean covers what that sweep cannot see (JVM rotations, leftovers).
It refuses to run while RIG_KERNEL_JAR is set.
GraalVM management¶
rig manages GraalVM community JDKs, one per major version, for
native-image builds (rig build --native). Rig derives the requirement
from the :rig/jvm pin. You install missing GraalVMs explicitly:
rig build --native never downloads, it fails with a hint until
rig graalvm install has run.
rig graalvm install¶
<major> is a major (feature) version. The command resolves the build
through the graalvm/graalvm-ce-builds GitHub releases, downloads the
archive for the current platform, and verifies the sha256 against the
.sha256 sidecar of the release. It extracts the GraalVM to the state dir
(~/.local/share/rig/graal/graalvm-<version>/graal). Rig keeps one
GraalVM per major version. When a GraalVM for the major already exists,
this command exits without changes — use rig graalvm update to move it
to the newest build. --offline refuses (installing needs the network).
rig graalvm list¶
Installed managed GraalVMs:
rig graalvm path¶
Prints the home directory of the newest installed managed GraalVM
satisfying <major> — the GRAALVM_HOME rig build --native uses — as a
bare path on stdout, for scripts and CI. The state dir is read only: the
command never installs or downloads and needs no network. When no installed
GraalVM satisfies <major>, it fails (exit 2) with the install hint.
rig graalvm uninstall¶
rig graalvm uninstall 21 # the installed 21.x
rig graalvm uninstall 21.0.2 # exact, or unique prefix (rig graalvm uninstall 21.0)
rig graalvm update¶
rig graalvm update is a workspace command. It needs a graalvm block in
the lock, so the workspace needs a :rig/jvm pin and a :rig/native?
module. It updates the rig-managed GraalVM for the pinned major to the
newest community build, and replaces the installed one. Rig keeps one
GraalVM per major version. When none exists, the command installs the
newest build. The command does not touch the manifest or the lock.
--offline refuses (updating needs the network).
Global flags¶
| Flag | Meaning |
|---|---|
-p, --path <module> |
Target one module (default: all workspace modules, in :rig/modules order; . = root module). One module per command — a repeated -p is a usage error (exit 2). |
--offline |
Never use the network. Artifacts come from the cache or a checksum-checked ~/.m2; fail if in neither. |
--frozen |
Never modify the lock; fail (exit 3) if it is missing or stale. The CI mode. rig lock refuses it — writing the lock is its whole job. |
--force |
Bypass cooldowns (the decision is recorded in the lock). |
--cache-dir <dir> |
State directory (artifact cache + kernel jars). Default ~/.local/share/rig; honors $XDG_DATA_HOME. |
-v, --verbose |
Debug logging. |
--autocomplete [shell] |
Print the shell completion script to stdout: bash, zsh, fish or powershell; no value = detect the running shell. |
Shell completion (detects your shell; -p completes module paths,
--alias completes the aliases of the module):
eval "$(rig --autocomplete)" # bash
source <(rig --autocomplete) # zsh
rig --autocomplete | source # fish
rig --autocomplete | Invoke-Expression # PowerShell
Exit codes¶
| Code | Meaning |
|---|---|
| 0 | success |
| 1 | failure — build/test/publish/resolve error, or a check error |
| 2 | usage error — bad flag, missing main, module not in the lock, … |
| 3 | lock problem — missing lock, or stale under --frozen |
| 4 | security failure — artifact hash mismatch / not in the lock |
| 5 | cooldown refused — retry with --force |
Commands that launch a child process (run, repl, exec, lint,
fmt) propagate the exit code of the child verbatim, above these.
launch is the purest form of it: it execs the JVM, so the exit code of
the JVM is the exit code of the process. test and check interpret
their runner instead: a failing runner makes Rig exit 1 with its own
message; any other runner exit code becomes a plain Rig error (exit 1).