Rig Getting started Docs Images GitLab Hub

Docs

Lookup for the Nix options and the rig commands. The first session is on Getting started. Webhook HTTP is on Triggers. Coding agents should fetch /llms.txt then the matching /raw/ page. Retrieval rules are on For agents.

A workspace is a flake that calls rig.lib.workspace. rig new workspace writes one. Build, catalog lists, and rig add need it. Pulled images do not. The longer write path is Create an agent.

If you want

Glossary

WordMeaning
add rig add. Pull a published layer and add its flake input to the workspace. Does not edit agent files.
agent A name and a compose list of layer modules. Composed into one image.
attach rig attach. Stdin and stdout on the session agent process. Disconnect does not stop the agent.
compose Layer modules in order. Later entries override on conflict. If a layer named base exists, you do not list it.
harness OpenCode or Claude Code, generated from the same composed agent.
image A published agent or layer at a host, name, and tag.
layer One reusable slice. The file is layers/<name>/default.nix, or a published flake with a layer output.
sandbox Default deny. Layers grant domains, CIDRs, and write paths.
secretspec Secret keys declared on layers. The image holds the manifest, not the tokens.
session A running agent instance with its own root and sandbox.
trigger A webhook subscription. Provider plus kind, then exactly one of prompt or handler.
workspace A flake that calls rig.lib.workspace. rig new workspace writes one. Build, catalog lists, and rig add need it. Pulled images do not.

Raw: /raw/glossary.md.

agent

An agent is a name and a compose list of layer modules. The file lives at agents/<name>/default.nix. Do not list base. Eval prepends it.

{ layers, ... }:
{
  name = "writer";
  description = "What this agent is for.";
  compose = [
    layers.notes
    layers.git
  ];
}
FieldTypeDefaultMeaning
name string default Agent identity.
description string empty What this agent is for.
avatar string empty Public HTTPS URL. Empty falls back to assets/avatars/avatar-<name>.png or a generated SVG.
compose list of module [] Layer modules in order. Later entries override on conflict.
dir string .agent Output directory for materialized artifacts.
triggers attrs of trigger {} Agent-level triggers. Applied after the layer compose. Later name wins.
disableNativeTools bool false Deny built-in harness tools and keep collected layer tools. ORed with any layer that sets it.

If a layer named base exists, the resolved compose list is base plus compose. You do not list base.

Invariants

Failure modes

How to check

Needs a workspace whose flake calls rig.lib.workspace. rig inspect writer prints a block that starts with === agent: writer === and includes compose (declared) and compose (resolved).

Raw: /raw/agent.md. How-to: /raw/create-agent.md.

Layer

One reusable slice. The file is layers/<name>/default.nix. The name is the directory or the rig add input. The file is the module body.

{ pkgs, ... }:
{
  description = "What this slice is for.";
  packages = [ pkgs.jq ];
  files."AGENTS.md" = {
    source = ./AGENTS.md;
    mergeable = true;
  };
}

A layer that needs another layer lists modules, not strings:

{ layers, pkgs, ... }:
{
  description = "GitLab CLI and forge conventions.";
  compose = [ layers.git ];
  packages = [ pkgs.glab ];
}

compose = [ layers.git ] fails eval unless git is a workspace input or a local layer. rig add does not add those dependencies for you.

FieldTypeDefaultMeaning
description string empty Human-readable description.
image null or string null Canonical published image as host/name:tag.
compose list of module [] Layer modules composed before this one. A cycle fails eval.
packages list of package [] Nix packages on PATH in the session root. Unioned in compose order.
skills list of skill [] Native skills. Later compose entries win on the same skill name. First-seen order is kept.
models submodule empty default and providers.<id>. Later compose entries override the same provider id and a non-null default.
mcp attrs {} stdio servers. Later compose entries win on the same server name.
services attrs of service {} Session processes. Later compose entries win on the same name. See Services.
skillLinks list of string [] Relative paths under the agent root. Each path becomes a symlink to skills/.
secrets attrs of secret {} SecretSpec keys. See Secrets.
privileged list of string [] Process ids such as harness:, service:, mcp: that get real secret env. Only agent.layers.secretGuard.privileged is consumed. Other layers append. lib.mkForce replaces.
sandbox.network.allow list of attr [] Egress allows. Each item has exactly one of domain, ip, or cidr. Default deny.
sandbox.network.deny list of attr [] Egress denies. Applied after allows. A deny removes a matching allow key.
sandbox.fs.writeAllow list of string [] Filesystem write allow prefixes. Default deny.
sandbox.fs.writeDeny list of string [] Filesystem write denies. A deny removes a matching allow path.
files attrs {} Files in the agent home. Each value has source path and mergeable bool, default false. Same path with different bytes fails the build unless the path is mergeable. AGENTS.md is mergeable even when unset. Mergeable files concatenate with a <!-- rig:layer:<name> --> marker. Paths under triggers/ are rejected.
hooks list [] id plus command. Concatenated in compose order. Each harness maps the ids it knows.
tools attrs {} Harness tools. Attr key is the tool name and must match [a-zA-Z0-9_-]+. Each value has description and a TypeScript source path. Later compose entries win on the same name. The opencode layer writes .opencode/tools/<name>.ts.
disableNativeTools bool false Deny built-in harness tools. ORed across the compose list and the agent.
triggerProvider null or submodule null Webhook ingress. See Triggers.
triggers attrs of trigger {} Triggers this layer contributes. Later compose entries win on the same name.
scripts attrs {} devenv scripts.<name>.exec when this layer is composed.
module deferred module empty Extra devenv module. Not auto-imported.

Sandbox

Default deny. Layers grant domains, CIDRs, and write paths. No grant, no access. Each network allow or deny item has exactly one of domain, ip, or cidr.

Invariants

Failure modes

How to check

Needs a workspace whose flake calls rig.lib.workspace. rig inspect <name> prints === layer: <name> === or === agent: <name> ===.

Raw: /raw/layer.md. How-to: /raw/create-agent.md.

Skill

FieldTypeDefaultMeaning
name string required Directory and display name under skills/<name>/.
path null or path null Local SKILL.md or skill directory.
repo null or string null owner/repo or https://github.com/owner/repo. Built with fetchFromGitHub.
skill null or string null Subdirectory in the repo, skills/<name> or <name>.
rev null or string null Git revision. Required when repo is set.
hash null or string null SRI hash. Required when repo is set. A changed tree fails the build.

Models

FieldTypeDefaultMeaning
default null or string null Default model id.
providers.<id>.name string the attr key Display name.
providers.<id>.kind enum openai-compatible Only openai-compatible.
providers.<id>.baseURL null or string null Provider base URL.
providers.<id>.apiKeyEnv null or string null Environment variable that holds the API key.
providers.<id>.models.<id>.name string required Display name for that model id.

MCP

FieldTypeDefaultMeaning
command string required Executable that speaks MCP over stdio.
args list of string [] Arguments.
secretsScope null or string null secretspec scope for the process wrapper.
env attrs of string {} Extra environment.
description string empty Human-readable description.

Services

The attr is services.<id> on a layer. Later compose entries win on the same <id>. Only the last composed service that sets work keeps it. Earlier work is dropped. A non-empty collected set writes services.json. A collected work also writes harness.json with mode set to service. The runtime starts each command inside the session root. The process id is service:<id>.

FieldTypeDefaultMeaning
command list of string required argv started inside the session root.
env attrs of string {} Extra environment.
ready null or submodule null Optional TCP wait before the session is ready.
ready.tcp string required when ready is set Listen address as host:port.
ready.timeoutMs positive integer 60000 Milliseconds to wait for ready.tcp.
work null or submodule null How session prompts reach this process.
work.kind enum required when work is set acp or http.
work.url null or string null Required when kind is http.

work.kind = "http" posts the prompt to work.url. work.kind = "acp" sends the prompt over the child stdin and stdout.

Triggers

A trigger subscribes to a provider kind. Exactly one of prompt or handler must be set. Eval throws otherwise. A trigger whose provider or kind is missing from the collected providers fails eval. Two providers on one agent may not share a route path. HTTP is on Triggers.

triggerProvider = {
  id = "hooks";
  auth = {
    env = "WEBHOOK_SECRET";
    header = "x-webhook-token";
  };
  routes = [{ path = "webhooks/hooks/:trigger"; }];
  kinds.ping = {
    match.headers."x-event" = "ping";
  };
};

agent.triggers.hello = {
  provider = "hooks";
  kind = "ping";
  prompt = ./prompts/hello.md;
};

triggerProvider

FieldTypeDefaultMeaning
id string required Must match [a-z0-9][a-z0-9-]*. Triggers set provider to this id.
auth.env string required SecretSpec key name for the token or HMAC secret. The value is not stored in the image.
auth.header null or string null Shared-token header name. At least one of header or hmac is required.
auth.hmac.header string required when hmac is set Signature header name.
auth.hmac.algorithm enum sha256 Only sha256.
auth.hmac.prefix string empty Prefix stripped from the header before compare.
auth.hmac.message string {{body}} Mustache over headers, query, payload, and body.
routes[].path string required Suffix under /v1/agents/:agent/.
kinds.<id>.match.headers attrs {} Header name to string or list of strings. Names are case-insensitive.
kinds.<id>.match.payload attrs {} JSON path to string or list of strings.
kinds.<id>.dedup.header null or string null Dedup key from a request header.
kinds.<id>.dedup.payload null or string null Dedup key from a JSON path when the header is absent.
kinds.<id>.respond.contentType string text/plain Immediate response Content-Type. Stops trigger dispatch.
kinds.<id>.respond.body string required when respond is set Mustache response body.

trigger

FieldTypeDefaultMeaning
provider string required Provider id from a triggerProvider on the stack.
kind string required Kind id on that provider.
prompt null or path null Mustache prompt file. Exactly one of prompt or handler.
handler null or path null TypeScript file. The runtime runs bun <file> for 10 seconds. Stdin is JSON { headers, query, payload, body }.
session null or string null Mustache session name over payload, headers, query, and body. Empty or null uses the image name.

Mustache does not HTML-escape. Missing paths render empty. Triggers that share a provider and kind must agree on a non-empty session template.

Invariants

Failure modes

Raw: /raw/triggers.md.

Secrets

Layers declare keys. The image holds the manifest, not the tokens.

secrets.API_TOKEN = {
  description = "What this key is for";
  required = true;
  secret = true;
};
secrets.API_HOST = {
  description = "Non-secret default";
  required = false;
  default = "example.com";
};
FieldTypeDefaultMeaning
description string required Human-readable purpose.
required bool false Required on the layer default profile.
default null or string null Optional default. Use for non-secret config such as a host.
secret bool false When the secretGuard layer is composed, unprivileged processes see a fake. Set true only when that layer is in the compose list.

rig secrets <agent> runs secretspec check against the catalog agent. Catalog session create refuses when required keys are empty. Session processes start with a cleared environment. RIG_BWRAP_KEEP_ENV=1 keeps the host environment. rig shell --raw-secrets skips the secret wrap.

Invariants

Failure modes

How to check

Needs a workspace. rig secrets <agent> runs secretspec check.

Raw: /raw/secrets.md.

rig pull

Download a published agent or layer into the local dest store.

rig pull <image|ref>

image|ref is one of:

Needs no workspace. Progress lines go to stderr when stderr is not a TTY as rig: …. The last stdout line is:

pulled https://repo.slopkit.dev/agents/agency-tester@latest storePath=/nix/store/7j5lhfm26sg9vkp2vdbcxvmh9l1h09sw-kit-agent-agency-tester-root cache=https://repo.slopkit.dev/cache

A layer with no session root prints pulled … (no session root) cache=…. Missing argument exits 1 with error: pull requires an image or layer ref.

rig push

Publish a local agent or layer to an image repo.

rig push <image> [path]

image is required. path is an optional agent or layer directory. If you omit it, Rig searches the current working directory. Needs a workspace or that path, and secretspec credentials for scopes.s3.

rig publish

Build NARs and upload to S3.

rig publish <image> [--system SYSTEM]
rig publish --all <repo> [--tag TAG]… [--system SYSTEM]

Needs a workspace. --system selects a pkgsCross output such as aarch64-linux. It does not run a foreign ELF. --all publishes every catalog layer, then every agent, once. Extra --tag values are written only when that image's store path changed versus @latest.

Stdout is one line per image:

published <website> storePath=<path> cache=<url> uploaded=<n> layers=<names>

rig agent

rig agent list
rig agent remove <name|image> [--force] [--runtime URL]

list prints pulled agents from $RIG_DATA_DIR/rigdb.sqlite. Empty inventory prints No pulled agents. A pulled row looks like:

Pulled agents:
  agency-tester    latest  compose: base flue git unslop agency chromium agent-browser osmani-browser

remove deletes a pulled agent and unused layer store paths. It refuses if a session uses the image, or if the runtime is down, unless --force.

rig layer

rig layer list
rig layer remove <name|image> [--force] [--runtime URL]

Same inventory and remove rules for pulled layers. Empty inventory prints No pulled layers.

rig new

Create an empty workspace, or scaffold a layer or agent module.

rig new workspace [directory]
rig new layer <name>
rig new agent <name>

rig new workspace writes flake.nix that calls rig.lib.workspace. Default directory is rig-workspace.

created workspace → rig-workspace

A destination that exists and is not empty exits 1 with exists and is not empty. Creating a layer or agent outside a workspace initializes the current empty directory first.

created layer notes → layers/notes
created agent writer → agents/writer

The layer file is the module body. The agent scaffold lists every local layers/*/default.nix name. It does not list flake inputs.

rig add

Pull a published layer and add its flake input to the workspace. Does not edit agent files. Does not add layers named in that layer's own compose list.

rig add <layer|image>

Needs a workspace. Match:

added layer git → https://repo.slopkit.dev/layers/git@latest/flake.tar.gz

The card must include a flake archive. If it does not, add exits with layer '<name>' has no flake archive; rig pull still works for run. Missing argument exits 1 with error: rig add requires a published layer ref.

rig build

Materialize a catalog agent to .agent.

rig build <agent> [--harness opencode|claude] [--system SYSTEM]

Needs a workspace. That is nix build .#agents-<agent> -o .agent. Cross is .#cross.<system>.agents-<agent>. --harness checks that harness's files exist. It does not build a different derivation. Unknown harness exits 1. Missing name exits 1 with error: build requires an agent name.

Stdout starts with:

build notes: base → notes (flake .#agents-notes)

Then a materialized line with outDir, storePath, and counts for files, skills, and MCP servers.

rig list-agents

List agents from the local flake catalog. Alias: rig agents. Needs a workspace. Pulled inventory is rig agent list.

Agents:
  <name>           compose: <layer names>

rig list-layers

List layers from the local flake catalog. Alias: rig layers. Needs a workspace. Pulled inventory is rig layer list.

Layers:
  <name>           <description>

rig inspect

rig inspect <name|path>

Print evaluated metadata for a local or pulled layer or agent. A workspace name looks up the catalog. A path such as ./layers/notes works without a catalog name. An agent block starts with === agent: <name> === and includes compose (declared) and compose (resolved). A layer block starts with === layer: <name> ===. Missing name exits 1 with error: inspect requires a layer or agent name.

rig secrets

rig secrets <agent>

Run secretspec check for a catalog agent manifest. Needs a workspace.

rig card serve

rig card serve [--port N]

Preview repo, agent, and layer cards from a workspace. Default port is 43191. Cards are written under .rig/cards and served at 127.0.0.1.

rig session

rig session create --agent <name|image> [options]
rig session list [--runtime URL]
rig session get <name|id> [--runtime URL]
rig session suspend <name|id> [--runtime URL]
rig session resume <name|id> [--runtime URL]

--agent is a pulled name from rig agent list, an image URL, or a local catalog name. Catalog create runs a required-secret check first. Pulled images skip that CLI check. Create starts a local runtime when the target URL is this machine. --runtime targets a remote runtime and skips the local start.

OptionMeaning
--agent Required on create. Pulled name, image URL, or catalog name.
--name Session name. Default is the image leaf, then -alpha through -zulu, then -alpha-alpha.
--prompt Initial prompt. Delivered only when the image wrote harness.json. Prompts on one session run one at a time, in order.
--workdir-host Bind a host path. The path must exist. Exactly one workdir kind is allowed.
--workdir-clone Git URL. Schemes are http, https, ssh, git, git+ssh, file, or user@host:path. A URL that starts with - is rejected.
--workdir-ref Clone ref. Requires --workdir-clone. A ref that starts with - is rejected.
--workdir-persistent Named directory under $RIG_DATA_DIR/workdirs/<name>.
--backend nix or firecracker.
--runtime Runtime base URL for this command.

If you omit a workdir, the runtime uses a persistent directory named after the session id. Create prints the session name, status, page URL, agent, backend, and id. The URL may include a one-time login query. list with no sessions prints (no sessions). get, suspend, and resume print JSON. Stopped, failed, or suspended sessions refuse shell. Resume first.

On disk the runtime keeps $RIG_DATA_DIR/sessions/<id>/ with home/, workdir/, root-path, and meta.json. Inside the root, $HOME is /home/agent and cwd is /home/agent/workdir.

rig attach

rig attach <name|id> [--runtime URL]

Attach stdin and stdout to the session agent process over WSS. Disconnect does not stop the agent. Missing name exits 1. A non-TTY prints attach info as JSON and a hint to run in a TTY. No harness.json means the runtime skips the harness process.

rig shell

rig shell <name|id> [--script 'cmd;…'] [--runtime URL] [--raw-secrets]

Bash in the session root. The runtime runs bwrap. --script splits on ;, runs those commands, then exit, and writes the output to stdout. Timeout for script mode is 15 seconds. --raw-secrets skips the secret wrap. A non-TTY without --script prints shell info as JSON.

rig runtime

rig runtime start [--port N] [--foreground|-f]
rig runtime restart|stop|status
rig runtime login <url> [--name <n>] [--token <t>]
rig runtime switch [name]
rig runtime list

Start the local runtime, or save and switch remotes. Does not need a workspace. TLS plus token dev. Default URL is https://127.0.0.1:7443. Start in the background prints runtime started (background) → <url> or that it was already up. --foreground keeps it on this terminal. Local listen details land in ~/.config/rig/runtime.json.

login saves the URL and makes it current. It needs --token or RIG_RUNTIME_TOKEN. --name labels it. Default name is the URL hostname. Saved remotes land in ~/.config/rig/runtimes.json. Login prints rig: runtime <name> → <url> (current) on stderr. switch with no name opens a picker. A named switch prints rig: current runtime: <name> (<url>). list marks the current entry with *. Empty list prints (no runtimes). rig supervisor exits 1 with unknown command: supervisor. --supervisor exits 1 with Unknown option '--supervisor'.

config.toml

User config is ~/.config/rig/config.toml, or $XDG_CONFIG_HOME/rig/config.toml. Override the file with RIG_USER_CONFIG.

repositories = [
  "https://repo.slopkit.dev",
  "s3://my-rig-cache",
]

If the file is missing, or repositories is empty, Rig uses https://repo.slopkit.dev. Project rig.toml is named flake registries only. It does not replace this list.

Environment

NameMeaning
RIG_USER_CONFIG Exact path to the user TOML file.
RIG_CONFIG_DIR Directory that holds config.toml, runtime.json, and runtimes.json.
RIG_ROOT Workspace root for build, inspect, and catalog lists.
RIG_RUNTIME_URL Runtime base URL. When unset, the current runtimes.json entry, then runtime.json, then https://127.0.0.1:7443.
RIG_RUNTIME_TOKEN Bearer token. Default dev.
RIG_RUNTIME_INSECURE_TLS 1 or true accepts a self-signed cert. 0 or false turns that off. Localhost is insecure unless turned off.
RIG_DATA_DIR Store, sessions, SQLite. Default ~/.local/share/rig.
RIG_BWRAP bubblewrap binary for session enter.
RIG_BWRAP_KEEP_ENV 1 keeps the host environment inside bwrap.
RIG_VERSION Installer package version. Default latest.

Each RIG_* name above that has a KIT_* twin also reads the KIT_* name as a fallback.

rig version

rig version
rig --version
rig -V

Prints three lines: version:, built:, and commit:. Getting started records 0.4.36.

rig help prints the full usage. rig <cmd> --help prints one command.

rig update

rig update

Downloads and runs the latest install.sh. Same installer as Getting started.

rig config analytics

rig config analytics [on|off]

Anonymous telemetry is on by default. It records sanitized command, pull, runtime, and session aggregates. It does not record prompts, responses, raw argv, URLs, tokens, paths, or environment variables. Local data is $XDG_DATA_HOME/rig/analytics.duckdb, default ~/.local/share/rig/analytics.duckdb. Dashboard: analytics.slopkit.dev.