Agent entry point: https://rig.slopkit.dev/docs/for-agents/ Site map: https://rig.slopkit.dev/llms.txt Raw source: /raw/.md ==== https://rig.slopkit.dev/raw/index.md ==== # SlopKit Rig Compose an agent from layers, attach a session, push the image. Same agent on this machine or anyone who pulls the URL. Install: ``` curl -fsSL https://rig.slopkit.dev/install.sh | bash ``` First run is on [Getting started](https://rig.slopkit.dev/start/). Language and commands are on [Docs](https://rig.slopkit.dev/docs/). Published images live at [repo.slopkit.dev](https://repo.slopkit.dev). Do not catalog those images here. ## Commands named on the homepage `rig build` : Compose an agent from predefined layers. `rig pull` : Pull agents and layers from a repository. `rig attach` : Attach into an interactive session. ## Agent image An agent is a composition of layers. A layer is a reusable slice: packages, files, skills, MCP, secrets, sandbox grants, hooks. Order matters on conflict and merge. Each layer caches on its own. The public repository is a cache and a registry. Browse it at https://repo.slopkit.dev. ## Check - Getting started: https://rig.slopkit.dev/start/ - Docs: https://rig.slopkit.dev/docs/ - For agents: https://rig.slopkit.dev/docs/for-agents/ - Site map: https://rig.slopkit.dev/llms.txt ==== https://rig.slopkit.dev/raw/for-agents.md ==== # Fetch Rig docs from a coding agent Use this page to retrieve Rig language and CLI facts without inventing fields. ## Outcome You can name the raw URLs to fetch, write only documented Nix fields, and name the command that checks the result. ## Prerequisites A network fetch to https://rig.slopkit.dev. HTML pages are for humans. Raw markdown is the source for machine consumers. ## Steps 1. Read https://rig.slopkit.dev/llms.txt and pick the pages that match the task. 2. Fetch those pages from their `/raw/` URLs. 3. Keep the field names, types, defaults, and eval failures from those pages. Do not add Nix fields that are absent there. 4. Do not catalog published agents or layers. Samples live at https://repo.slopkit.dev. 5. Before you claim a layer or agent is correct, run the check named on that page. ## Which raw page | Task | Fetch | | --- | --- | | Write `agents//default.nix` | https://rig.slopkit.dev/raw/agent.md | | Write `layers//default.nix` | https://rig.slopkit.dev/raw/layer.md | | Create a workspace, add layers, compose, build | https://rig.slopkit.dev/raw/create-agent.md | | Secrets stay out of the image | https://rig.slopkit.dev/raw/secrets.md | | Webhook HTTP or trigger Nix | https://rig.slopkit.dev/raw/triggers.md | | A `rig` command | https://rig.slopkit.dev/raw/cli.md | | First run for a human | https://rig.slopkit.dev/raw/start.md | | Word meanings | https://rig.slopkit.dev/raw/glossary.md | One-shot bundle: https://rig.slopkit.dev/llms-full.txt. Use it for indexing or a cross-cutting audit. Prefer the smaller pages for a focused edit. ## Check After a layer or agent change, one of these must match the page you used: - `rig inspect ` prints `=== agent:` or `=== layer:` - `rig secrets ` runs `secretspec check` - `rig build ` prints a `build :` line Build and catalog lists need a workspace whose flake calls `rig.lib.workspace`. `rig inspect` also accepts a path. Pulled images do not need that tree. `rig new workspace` writes one. ## Do not - Invent `rig` flags, Nix fields, HTTP status codes, or install URLs. - Treat the homepage PTY, BOM cards, or repo stats as the language spec. - Pull on a webhook. The image must already be on that runtime. ==== https://rig.slopkit.dev/raw/glossary.md ==== # Glossary Short meanings used on this site. Language details are in the raw language pages. 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. `rig build --harness` checks that harness's files exist. image : A published agent or layer at a host, name, and tag. Pull and push talk in image refs. layer : One reusable slice. The file is `layers//default.nix`, or a published flake with a `layer` output. pull : `rig pull`. Download a published agent or layer into the local dest store. Does not edit the workspace flake. push : `rig push`. Publish a local agent or layer to an image repo. repository : A cache and a registry of third-party agents. Public default is https://repo.slopkit.dev. sandbox : Default deny. Layers grant domains, CIDRs, and write paths. No grant, no access. secretspec : Secret keys declared on layers. The image holds the manifest, not the tokens. Injected at process start. session : A running agent instance with its own root and sandbox. `rig session create` starts one. 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. ==== https://rig.slopkit.dev/raw/start.md ==== # Getting started This path installs the CLI, pulls `agency-tester`, starts a session, and opens it in the browser. Then it creates a workspace, writes a notes layer and agent, `rig build`, and `rig push`. You need `curl`. The first success is a running session you can open. Write, build, and push come after that. ## Install the CLI Run: ``` curl -fsSL https://rig.slopkit.dev/install.sh | bash ``` The script writes `~/.local/bin/rig`. Match this last line on Linux x64: ``` rig: installed ~/.local/bin/rig (rig-linux-x64) ``` Then run: ``` rig version ``` Sample: ``` version: 0.4.36 built: 2026-09-19T05:51:05Z commit: 689fb117788b951b5a6ffecc83f2290825372fb1 ``` `rig update` re-runs that installer. ## Run an agent 1. Pull `agency-tester`. ``` rig pull https://repo.slopkit.dev/agents/agency-tester@latest ``` Match a last line that starts with `pulled` and names that image. 2. Create a session and send the first message. ``` rig session create --agent agency-tester --prompt "Hello." ``` Create starts a local runtime when one is not already up. Match `running`. The login query is a one-time token. Your ticket, session name suffix, and id will differ. ``` agency-tester running https://127.0.0.1:7443/sessions/agency-tester?login= ``` ## Open the session Open the printed URL in a browser. You can chat with the agent there. ## Check the files ``` ~/.local/bin/rig ~/.local/share/rig/rigdb.sqlite ~/.local/share/rig/store ~/.local/share/rig/sessions ``` ## Create a workspace A workspace is a flake that calls `rig.lib.workspace`. Build, catalog lists, and `rig add` need it. Pulled images do not. Run: ``` rig new workspace ``` Match: ``` created workspace → rig-workspace ``` Then: ``` cd rig-workspace ``` The command writes only `flake.nix`. A destination that exists and is not empty exits 1. ## Write a layer From that directory, run: ``` rig new layer notes ``` Match a line that starts with `created layer notes`. The file is `layers/notes/default.nix`. The name is the directory. The file is the module body. There is no `agent.layers.notes` wrapper. ``` { pkgs, ... }: { description = "What this slice is for."; packages = [ pkgs.jq ]; files."AGENTS.md" = { source = ./AGENTS.md; mergeable = true; }; } ``` Then: ``` rig new agent notes ``` Match a line that starts with `created agent notes`. Replace `agents/notes/default.nix` with: ``` { layers, ... }: { name = "notes"; description = "What this agent is for."; compose = [ layers.notes ]; } ``` Do not list `base`. Eval prepends it. Add a published layer with `rig add git@latest`, then list `layers.git` on that compose list. The longer path is in https://rig.slopkit.dev/raw/create-agent.md. Paste-ready prompt for a coding agent after the session runs: ``` You are writing a Rig layer or agent. 1. Fetch https://rig.slopkit.dev/llms.txt 2. Fetch only the raw docs for agent, layer, and the command you need. 3. Use documented fields only. If a field is missing from those docs, ask. 4. Do not catalog published images. Those live at repo.slopkit.dev. ``` ## Build the agent Needs Nix with flakes. From the workspace directory that is `nix build .#agents-notes -o .agent`. ``` rig build notes ``` Match the first line: ``` build notes: base → notes (flake .#agents-notes) ``` Then a materialized line with `.agent`, a store path, and counts. Unknown harness exits 1. Missing name exits 1 with `error: build requires an agent name`. ## Push the image Needs a workspace or an agent or layer path, and secretspec credentials for `scopes.s3`. ``` rig push ``` `image` is required. `path` is an optional agent or layer directory. If you omit it, Rig searches the current working directory. Image ref forms and session flags are in https://rig.slopkit.dev/raw/cli.md. ==== https://rig.slopkit.dev/raw/create-agent.md ==== # Create an agent Create a workspace, write a local layer, add published layers, compose them, build, run, and push. This path needs a `rig` whose `rig help` lists `rig new` and `rig add`, Nix with flakes, and network access to https://repo.slopkit.dev. Install the CLI on [Getting started](https://rig.slopkit.dev/start/) if you do not have it. `rig update` re-runs that installer. Do not catalog published images. `git` and `unslop` here are samples. Browse others at https://repo.slopkit.dev. ## Create a workspace In an empty directory, run: ``` rig new workspace ``` Match: ``` created workspace → rig-workspace ``` Then: ``` cd rig-workspace ``` The flake is: ``` { description = "rig workspace"; inputs.rig.url = "git+https://gitlab.techtailors.net/slopkit/rig?ref=main"; inputs.nixpkgs.follows = "rig/nixpkgs"; outputs = args: args.rig.lib.workspace args; } ``` A destination that exists and is not empty exits 1 with `exists and is not empty`. ## Write a layer Run: ``` rig new layer notes ``` Match a line that starts with `created layer notes`. The file is `layers/notes/default.nix`. The name is the directory. The file is the module body. There is no `agent.layers.notes` wrapper. Replace that file with: ``` { pkgs, ... }: { description = "Scratch notes conventions."; packages = [ pkgs.jq ]; files."AGENTS.md" = { source = ./AGENTS.md; mergeable = true; }; } ``` Create `layers/notes/AGENTS.md`: ``` Keep notes in markdown. Prefer short sentences. ``` `packages` puts Nix packages on PATH. `files` writes into the agent home. `AGENTS.md` is mergeable even when `mergeable` is unset. Later compose entries override on conflict. Mergeable files concatenate. `skills` pin a local path or a GitHub repo. Sandbox, MCP, secrets, triggers, services, harness tools, hooks, and models are in https://rig.slopkit.dev/raw/layer.md. Run: ``` rig inspect ./layers/notes ``` Match: ``` === layer: notes === source: local workspace path: …/layers/notes description: Scratch notes conventions. depends: (none) skills: (none) mcp: (none) sandbox: allowNet=0 denyNet=0 writeAllow=0 files: AGENTS.md hooks: (none) ``` The `path` line is the absolute directory. ## Add published layers `rig add` pulls the image and adds a flake input. It does not edit agent files. It does not add layers named in that layer's own `compose` list. Run: ``` rig add git@latest rig add unslop@latest ``` Match: ``` added layer git → https://repo.slopkit.dev/layers/git@latest/flake.tar.gz added layer unslop → https://repo.slopkit.dev/layers/unslop@latest/flake.tar.gz ``` The card must include a flake archive. If it does not, add exits with `layer '' has no flake archive; rig pull still works for run`. `git` is a CLI and a git skill. `unslop` is a pinned skill and an `AGENTS.md` slice. Run: ``` rig inspect git ``` Match a block that starts with `=== layer: git ===` and includes `source: local workspace` and `skills: git`. ## Compose the agent Run: ``` rig new agent writer ``` Match a line that starts with `created agent writer`. The scaffold already lists every local `layers/*/default.nix` name. It does not list flake inputs. Replace `agents/writer/default.nix` with: ``` { layers, ... }: { name = "writer"; description = "What this agent is for."; compose = [ layers.notes layers.git layers.unslop ]; } ``` `compose` is a list of modules. Later entries override on conflict. Do not list `base`. Eval prepends it. Run: ``` rig inspect writer ``` Match: ``` === agent: writer === source: local workspace description: What this agent is for. compose (declared): notes → git → unslop compose (resolved): base → notes → git → unslop skills: agentfile-base, git, unslop harnesses: claude, flue layers: base: skills=1 mcp=0 hooks=0 notes: skills=0 mcp=0 hooks=0 git: skills=1 mcp=0 hooks=0 unslop: skills=1 mcp=0 hooks=0 ``` ## Build the agent From the workspace directory: ``` rig build writer ``` That is `nix build .#agents-writer -o .agent`. Match: ``` build writer: base → notes → git → unslop (flake .#agents-writer) ``` Then a materialized line with `.agent`, a store path, and counts. Observed: `files=13 skills=3 mcp=0`. Unknown harness exits 1. Missing name exits 1 with `error: build requires an agent name`. ## Run the agent From the same workspace: ``` rig session create --agent writer --backend nix --prompt "Hello." ``` Create starts a local runtime when one is not already up. Match `running` on the session print. The login query is a one-time token. Your ticket, id, and session name may differ. ``` writer running https://127.0.0.1:7443/sessions/writer?login= agent writer backend nix id ``` Open the printed URL in a browser. ## Push the image Needs secretspec credentials for `scopes.s3`. ``` rig push repo.slopkit.dev/writer:latest ``` `image` is required. Image ref forms are in https://rig.slopkit.dev/raw/cli.md. ## Check ``` rig list-agents ``` Match: ``` Agents: writer compose: base notes git unslop ``` ``` rig list-layers ``` includes `base`, `git`, `notes`, and `unslop`. ## Undo Delete the `rig-workspace` directory. That removes the flake, local modules, and added inputs. `rig add` does not create those directories. Removing only the `inputs."git".url` and `inputs."unslop".url` lines from `flake.nix` drops those layers from the workspace catalog. The dest-store pull stays until `rig layer remove`. A session keeps running after you delete the workspace. `rig session list` still shows it. ==== https://rig.slopkit.dev/raw/agent.md ==== # agent An agent is a name and a compose list of layer modules. ``` { layers, ... }: { name = "writer"; description = "What this agent is for."; compose = [ layers.notes layers.git ]; } ``` The file lives at `agents//default.nix`. Do not list `base`. Eval prepends it. ## Fields | Field | Type | Default | Meaning | | --- | --- | --- | --- | | 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-.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. | ## Invariants - If a layer named `base` exists, the resolved compose list is `base` plus `compose`. You do not list `base`. - `disableNativeTools` is ORed with any layer that sets it. ## Failure modes - A cycle in layer `compose` fails eval. - A missing `layers.git` fails eval with `layer 'git' is not in this workspace`. Add it with `rig add git@latest` or `rig new layer git`. - Two providers on one agent may not share a route path. See triggers. ## How to check Needs a workspace whose flake calls `rig.lib.workspace`. ``` rig inspect writer rig build writer ``` `rig inspect` prints a block that starts with `=== agent: ===` and includes `compose (declared)`, `compose (resolved)`, skills, harnesses, and per-layer counts. ## Related - Layer: https://rig.slopkit.dev/raw/layer.md - Create an agent: https://rig.slopkit.dev/raw/create-agent.md - Triggers: https://rig.slopkit.dev/raw/triggers.md - `rig build`: https://rig.slopkit.dev/raw/cli.md ==== https://rig.slopkit.dev/raw/layer.md ==== # Layer One reusable slice. The file is `layers//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. ## Fields | Field | Type | Default | Meaning | | --- | --- | --- | --- | | 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.`. 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. | | skillLinks | list of string | `[]` | Relative paths under the agent root. Each path becomes a symlink to `skills/`. | | secrets | attrs of secret | `{}` | SecretSpec keys. | | 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 `` marker. Paths under `triggers/` are rejected. | | hooks | list | `[]` | `id` plus `command`. Concatenated in stack 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/.ts`. | | disableNativeTools | bool | `false` | Deny built-in harness tools. ORed across the stack and the agent. | | triggerProvider | null or submodule | `null` | Webhook ingress. | | triggers | attrs of trigger | `{}` | Triggers this layer contributes. Later compose entries win on the same name. | | scripts | attrs | `{}` | devenv `scripts..exec` when this layer is composed. | | module | deferred module | empty | Extra devenv module. Not auto-imported. | ## Skill | Field | Type | Default | Meaning | | --- | --- | --- | --- | | name | string | required | Directory and display name under `skills//`. | | 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/` or ``. | | 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 | Field | Type | Default | Meaning | | --- | --- | --- | --- | | default | null or string | `null` | Default model id. | | providers..name | string | the attr key | Display name. | | providers..kind | enum | `openai-compatible` | Only `openai-compatible`. | | providers..baseURL | null or string | `null` | Provider base URL. | | providers..apiKeyEnv | null or string | `null` | Environment variable that holds the API key. | | providers..models..name | string | required | Display name for that model id. | ## MCP | Field | Type | Default | Meaning | | --- | --- | --- | --- | | 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.` on a layer. Later compose entries win on the same ``. 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:`. | Field | Type | Default | Meaning | | --- | --- | --- | --- | | 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. ## Invariants - Default deny for network and filesystem writes. No grant, no access. - Each sandbox.network allow or deny item has exactly one of `domain`, `ip`, or `cidr`. - `AGENTS.md` is mergeable even when `mergeable` is unset. - Paths under `triggers/` in `files` are rejected. - Tool names must match `[a-zA-Z0-9_-]+`. - `rev` and `hash` are required when `repo` is set. ## Failure modes - A cycle in `compose` fails eval. - Same `files` path with different bytes fails the build unless the path is mergeable. - A changed skill tree fails the build when `hash` no longer matches. - Later compose entries win on the same skill name, MCP server name, service id, and trigger name. - Only the last composed service that sets `work` keeps it. ## How to check Needs a workspace whose flake calls `rig.lib.workspace`. ``` rig inspect notes rig build notes ``` A layer block from `rig inspect` starts with `=== layer: ===`. ## Related - agent: https://rig.slopkit.dev/raw/agent.md - Create an agent: https://rig.slopkit.dev/raw/create-agent.md - Secrets: https://rig.slopkit.dev/raw/secrets.md - Triggers: https://rig.slopkit.dev/raw/triggers.md ==== https://rig.slopkit.dev/raw/secrets.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"; }; ``` ## Fields | Field | Type | Default | Meaning | | --- | --- | --- | --- | | 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. | ## Invariants - The image holds the manifest, not the tokens. Injected at process start. - Session processes start with a cleared environment. - `RIG_BWRAP_KEEP_ENV=1` keeps the host environment. - `rig shell --raw-secrets` skips the secret wrap. ## Failure modes - `rig secrets ` runs `secretspec check` against the catalog agent. - Catalog `session create` refuses when required keys are empty. - Pulled images skip that CLI check. ## How to check Needs a workspace. ``` rig secrets notes ``` ## Related - Layer `secrets` and `privileged`: https://rig.slopkit.dev/raw/layer.md - `rig secrets` and `rig session`: https://rig.slopkit.dev/raw/cli.md ==== https://rig.slopkit.dev/raw/triggers.md ==== # 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. ``` 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 | Field | Type | Default | Meaning | | --- | --- | --- | --- | | 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..match.headers | attrs | `{}` | Header name to string or list of strings. Names are case-insensitive. | | kinds..match.payload | attrs | `{}` | JSON path to string or list of strings. | | kinds..dedup.header | null or string | `null` | Dedup key from a request header. | | kinds..dedup.payload | null or string | `null` | Dedup key from a JSON path when the header is absent. | | kinds..respond.contentType | string | `text/plain` | Immediate response Content-Type. Stops trigger dispatch. | | kinds..respond.body | string | required when respond is set | Mustache response body. | ## trigger | Field | Type | Default | Meaning | | --- | --- | --- | --- | | provider | string | required | Provider id from a `triggerProvider` on the compose list. | | 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 ` 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. ## HTTP `POST /v1/agents/:agent/:route` Not behind the API bearer token. The provider secret is the credential. `:agent` is the pulled image name or `name:tag`. `:route` is a provider `routes[].path`, which may include `:trigger`. ``` POST /v1/agents/agency-tester/webhooks/hooks/hello ``` The body is the vendor payload. JSON is parsed when Content-Type is empty or includes `json`. HMAC already ran on the raw body. ### Query Session and workdir ride on the query string so HMAC of the body stays valid. | Name | Meaning | | --- | --- | | session | Session name to reuse or create. A pinned stopped or failed session stays 409. An unpinned dead name may take a live NATO sibling of the image name. | | workdir | Persistent workdir name under `$RIG_DATA_DIR/workdirs/`. | | workdirHost | Host bind path. The path must exist. | | workdirClone | Git URL. Same scheme rules as `--workdir-clone`. | | workdirRef | Clone ref. Used with `workdirClone`. | ``` POST /v1/agents/agency-tester/webhooks/hooks/hello?session=notes&workdirHost=/home/me/proj ``` ### Status | Code | Meaning | | --- | --- | | 200 | A matched kind has `respond`. Body is the rendered template. Content-Type is `respond.contentType`, or `application/json` if that field is unset in the HTTP writer. | | 202 | Accepted. JSON `{ ok: true }`, plus `session` when a session was resolved. Also returned when the provider declares no kinds. | | 204 | No kind matched, or the request is a duplicate dedup key. | | 401 | Token or HMAC failed. JSON `{ error: "unauthorized" }`. | | 404 | Agent home missing, no trigger routes, or no matching route. Errors are `agent not found`, `no trigger routes for agent`, or `no matching route`. | | 409 | Prompt target session is stopped or failed. JSON `{ error: "session is not running" }`. | | 503 | The provider `auth.env` key is missing. JSON `{ error: "missing secret: " }`. | A handler that exits non-zero is logged and does not change a 202. ### Dispatch order 1. Resolve the agent home. 2. Match a provider route. 3. Read the provider secret. Missing is 503. 4. Verify token or HMAC. Fail is 401. 5. Parse JSON when the content type allows it. 6. Match kinds. None is 204. No kinds declared is 202. 7. Render a `respond` kind and return 200. 8. Drop duplicates. Duplicate is 204. 9. Resolve the prompt session when any matching trigger has `prompt` or `session`. 10. Run matching handlers as `bun` children, 10 second cap, stdin JSON `{ headers, query, payload, body }`. 11. Queue rendered prompts on that session, one at a time, in order. Return 202 once queued, or 409. The image must already be on that runtime. Rig does not pull on a webhook. ## Invariants - Exactly one of `prompt` or `handler`. - At least one of `auth.header` or `hmac`. - `triggerProvider.id` matches `[a-z0-9][a-z0-9-]*`. - Two providers on one agent may not share a route path. ## Failure modes - Both `prompt` and `handler` set, or neither, throws at eval. - Missing provider or kind on the collected providers fails eval. - Missing `auth.env` at request time is 503. - HMAC of the body stays valid only if session and workdir stay on the query string. ## How to check Nix fields: https://rig.slopkit.dev/docs/#triggers HTTP: https://rig.slopkit.dev/docs/triggers/ ==== https://rig.slopkit.dev/raw/cli.md ==== # CLI Lookup for `rig` commands. First session is on Getting started. Webhook HTTP is in https://rig.slopkit.dev/raw/triggers.md. 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. `RIG_ROOT` can point at one. This page matches slopkit/rig VERSION 0.4.36 for the commands that page installed. `rig update` re-runs the installer. `rig help` prints the full usage. `rig --help` prints one command. ## rig pull Download a published agent or layer into the local dest store. ``` rig pull ``` `image|ref` is one of: - `https://host/agents/name@tag` or `https://host/layers/name@tag` - `s3://bucket[/prefix]/agents/name@tag` - `host/name:tag` - `name@tag`, which walks `https://repo.slopkit.dev` then `repositories` in user config 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/…-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 new Create an empty workspace, or scaffold a layer or agent module. ``` rig new workspace [directory] rig new layer rig new agent ``` `rig new workspace` writes `flake.nix` that calls `rig.lib.workspace`. Default directory is `rig-workspace` in the current directory. ``` created workspace → rig-workspace ``` A destination that exists and is not empty exits 1 with `exists and is not empty`. A destination that starts with `-` exits 1. 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. Unknown kind exits 1 with `error: usage: rig new workspace [dir] | rig new layer|agent `. ## 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 ``` 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 '' has no flake archive; rig pull still works for run`. Missing argument exits 1 with `error: rig add requires a published layer ref`. ## rig push Publish a local agent or layer to an image repo. ``` rig push [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 [--system SYSTEM] rig publish --all [--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 storePath= cache= uploaded= layers= ``` ## rig agent ``` rig agent list rig agent remove [--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 [--force] [--runtime URL] ``` Same inventory and remove rules for pulled layers. Empty inventory prints `No pulled layers.` ## rig build Materialize a catalog agent to `.agent`. ``` rig build [--harness opencode|claude] [--system SYSTEM] ``` Needs a workspace. That is `nix build .#agents- -o .agent`. Cross is `.#cross..agents-`. `--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: compose: ``` ## rig list-layers List layers from the local flake catalog. Alias: `rig layers`. Needs a workspace. Pulled inventory is `rig layer list`. ``` Layers: ``` ## rig inspect ``` rig inspect ``` 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: ===` and includes `compose (declared)` and `compose (resolved)`. A layer block starts with `=== layer: ===`. Missing name exits 1 with `error: inspect requires a layer or agent name`. ## rig secrets ``` rig secrets ``` 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 [options] rig session list [--runtime URL] rig session get [--runtime URL] rig session suspend [--runtime URL] rig session resume [--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. | Option | Meaning | | --- | --- | | --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/`. | | --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//` 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 [--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 [--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 [--name ] [--token ] 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) → ` 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 → (current)` on stderr. `switch` with no name opens a picker. A named switch prints `rig: current runtime: ()`. `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 | Name | Meaning | | --- | --- | | 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 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: https://analytics.slopkit.dev.