Skip to main content

rig

One tool. One config. The whole dev culture of the coding-agent era — installed.

rig is the single front door to an entire ecosystem of agent-native tooling. From one committed, declarative rig.yaml it sets up a repository — and a developer's machine — wiring in the skills, agent-hooks, global git-hook dispatcher, CI gates, and MCP servers that keep a team's engineering discipline intact when most of the code is written by agents. One command, the same guardrails, every time, on every machine.

In the coding-agent era the bottleneck isn't writing code — it's keeping a hundred parallel agent sessions on-culture: tests first, secrets never committed, review before merge, an auto-mode that's actually safe. rig installs and reconciles that culture from the portable catalog in agent-tools — the WHAT (the content) to rig's HOW (apply it, reconcile it, prove it).

It's a peer to the rest of the ecosystem — tg-cli, review-cli, draw-cli, 3d-cli, task-cli — composable, agent-native CLIs that share one config-and-skills backbone. agent-tools is the WHAT (portable skills, guards, CI gates, MCP); rig is the HOW — it reads your rig.yaml, converges the repo and the machine to it (idempotently, with backups), and surfaces drift in both directions.

rig apply converges the repo to rig.yaml; rig status reports drift both ways

One development culture, from one control plane

Rig treats development setup and engineering policy as one declarative system rather than a pile of unrelated dotfiles. A global machine layer can establish defaults; committed rig.yaml files make repository-specific differences reviewable and reproducible. The same engine previews, applies, verifies, and reports drift.

That control plane already spans coding-agent skills and hooks, git hooks, CI gates, MCP servers, harness permissions/auto-mode, GitHub/repository settings, project-tool integrations, model/tool maintenance, and now JS/TS lint/format policy through Oxlint/Oxfmt + anti-slop. The intent is that humans and coding agents encounter the same constraints and preferred practices instead of each harness or repository inventing its own culture.

Where the surrounding tool exposes a preventative boundary, Rig installs a guardrail; where it cannot, CI/status/verification can still detect drift or unsafe state. The next cross-domain enforcement/advise model is tracked in #225, with consistent better-practice recommendations in #229.

This is useful for a team, but also for one developer with many repos and several agents: one policy source reduces setup drift, makes a new checkout predictable, and makes agent behavior less dependent on whichever harness happened to start the session. A dedicated onboarding/attestation command is tracked in #228.

Today Rig already has machine-wide global defaults plus per-repository overrides. The broader “change once everywhere” layer is explicit roadmap work rather than a hidden promise: fleet reconciliation #222, repository/stack/tag targeting #227 and #233, shareable team policy packs #223, and cross-domain rig rules / explain #224. The goal is to change lint, CI, hooks, agent capabilities, skills, MCP and other development policy globally—or only for the relevant stacks/projects—with one previewable operation.

Install

Pick one — each ends with rig on your PATH:

# 1. uv — recommended; macOS, Linux and Windows (incl. Cygwin / Git Bash)
uv tool install hyper-rig

# 2. pipx
pipx install hyper-rig

# 3. one-liner — clones to ~/.local/share/rig-cli, links rig into ~/.local/bin, registers the agent skill
curl -fsSL https://git.hyperide.ai/ultrabricks/rig-cli/raw/branch/main/install.sh | bash

# 4. from a clone — to hack on rig; `git pull` updates the installed tool
git clone https://git.hyperide.ai/ultrabricks/rig-cli && cd rig-cli && ./install.sh
  • After 1 or 2, run rig install-skill once so coding agents discover rig (3 and 4 do it for you).
  • Unreleased main: uv tool install git+https://git.hyperide.ai/ultrabricks/rig-cli (or the same with pipx install).
  • Update: uv tool upgrade hyper-rig · pipx upgrade hyper-rig · re-run the one-liner · git pull.
  • Installed before the rename (as rig-cli, from git)? Remove that first — uv tool uninstall rig-cli or pipx uninstall rig-cli — or two installs both claim rig.
  • Run without installing: uvx --from git+https://git.hyperide.ai/ultrabricks/rig-cli rig doctor, or from a checkout uv run bin/rig … / python3 bin/rig ….

On PyPI as hyper-rig (the command is still rig). rig-cli on PyPI is an unrelated project — pipx install rig-cli would install that. The canonical repo is git.hyperide.ai/ultrabricks/rig-cli; github.com/alex-mextner/rig-cli is a frozen, archived mirror.

textual (the rig init setup wizard) and rich (the rig stats report) are core dependencies — every install above brings them, so rig init from a terminal launches the wizard with no extra install step and no "go install textual" prompt.

Windows (Cygwin, Git Bash, PowerShell)

Use uv (option 1; get uv with winget install astral-sh.uv). ./install.sh and the one-liner detect Cygwin/MSYS and do the same thing for you (uv tool install --editable from a clone, from git otherwise).

  • uv puts a native rig.exe into %USERPROFILE%\.local\bin, which is already on PATH in every Windows shell. The POSIX symlink install can't work there: Python is a native Windows program, it can't run a #!/usr/bin/env python3 script, and Cygwin's own ~/.local/bin is not on PATH.
  • rig's home is your Windows profile (%USERPROFILE%), not Cygwin's ~: the global config is %USERPROFILE%\.config\rig\config.yaml, skills go to %USERPROFILE%\.agents\skills.
  • rig install-skill links the skill into ~/.claude/skills as a directory junction when Windows refuses a symlink. rig apply makes many more symlinks — turn on Developer Mode (Windows 10: Settings → Update & Security → For developers; Windows 11: Settings → System → For developers) so Windows lets you create them without admin rights.
  • mintty (the Cygwin / Git Bash terminal) isn't a Windows console, so rig init prints the non-destructive preview instead of the wizard: use rig init --yes, or run rig init from Windows Terminal / PowerShell for the TUI.
  • Keep an agent-tools checkout where rig looks for one (~/work/agent-tools, ~/xp/agent-tools, ~/agent-tools), or point at it: rig config set --global agent_tools_source <path> --commit.

Forgejo (fj) — log in with one click

The ecosystem lives on Forgejo at git.hyperide.ai; its CLI is fj (forgejo-cli). Put the host in the global config once — rig config set --global fj.host git.hyperide.ai --commit, or keep it in your .rig-profile — and rig apply:

  • installs fj — brew install forgejo-cli on macOS; on Linux and Windows the sha256-pinned release binary into rig's own dir ~/.local/share/rig/fj/<version>/ (not on PATH — see below);
  • adds fj ship — the same ship gate as gh ship: fj on PATH is a thin rig wrapper in ~/.local/bin whose fj ship <PR> runs exactly what the gh ship alias runs (the repo's .claude/scripts/pr-ship.sh, else agent-tools' ci/ship/ship.sh, else exit 127), and whose every other fj … runs the real fj with the arguments, stdin and exit code untouched;
  • turns fj auth login into a browser login — every Forgejo instance ships built-in public OAuth apps; rig lists one for the host in fj's client_ids, so there is no token to mint and no app for an admin to register. fj refreshes the token itself;
  • does the same for git — with Git Credential Manager (bundled with Git for Windows) rig adds its OAuth settings for https://<host>: the first git push opens the browser once;
  • drops --host — FJ_FALLBACK_HOST=https://<host> in every shell (the env area on macOS/Linux, a user environment variable on Windows). Inside a clone fj still follows its remote.

Then, once per machine:

fj auth login      # browser opens → Authorize

A repo whose rig.yaml names another instance (fj: { host: … }) gets that host set up too when you rig apply in it. Headless machines: fj auth add-token with a token from https://<host>/user/settings/applications. rig status shows anything not yet set up. Full reference: docs/config-schema.md.

Where the real fj lives (fj itself is always the wrapper in bin_dir, ~/.local/bin): Linux — ${XDG_DATA_HOME:-~/.local/share}/rig/fj/<version>/fj; macOS — Homebrew's, found on PATH (so ~/.local/bin must come before Homebrew on PATH — rig status says so when it doesn't); Windows — %USERPROFILE%\.local\share\rig\fj\<version>\fj.exe, with two wrappers in ~/.local/bin: fj (sh) for Cygwin / Git Bash and fj.cmd for cmd / PowerShell, where fj ship runs through the same sh gh uses for its aliases (Git for Windows'). No fj.exe stays in ~/.local/bin: cmd, PowerShell and Python would pick it over fj.cmd. An fj that an older rig put into ~/.local/bin is recognised by its pinned sha256 and moved; any other file there is left alone (and reported). fj.install: false leaves the fj command to you — no wrapper, so no fj ship.

Commands

Command One-line
rig init First-run onboarding. Scaffold rig.yaml and preview the agent-tools catalog it would wire in (with opt-out) — the front door for a repo/machine with no config yet. init never applies on its own: a bare rig init (no TUI/flags) writes nothing (pure preview); rig init --yes writes rig.yaml (config only); rig apply commit is what applies it (or rig init --yes --apply to scaffold + apply in one step).
rig apply Declarative reconcile (kubectl-style): read rig.yaml, compute the diff vs the repo's state, converge, idempotently. Preview-by-default: a bare rig apply is an alias for rig apply info — it prints the plan and mutates nothing; rig apply commit actually executes it (with per-phase progress and a ✓ applied N (C changed, M unchanged) completion line). The steady-state command you re-run on every machine; hand-edits that drift from the config are surfaced by rig status. --dry-run previews; --only skills,ci scopes; -v lists already-in-sync no-ops; a bare rig apply --yes executes (automation back-compat).
rig status Detect + report drift in both directions, grouped by GLOBAL/REPO layer and by every area rig reconciles (skills, all configured agent-hook targets, CI, MCP, symlinks, repo settings, auto-mode, tmux, model cron).
rig doctor Detect + (offer to) install every tool rig/agent-tools need, across brew / apt / dnf / pacman / zypper. --yes installs non-interactively.
rig export Write a starter rig.yaml from detected defaults without a TUI (recommends auto-mode on).
rig setup The interactive configuration wizard. In a terminal it shows what is enabled across every reconciled area, lets you change any option (with an inline hint per option) in the local rig.yaml AND the global ~/.config/rig/config.yaml, then applies. Non-interactive (piped / no TTY) it prints usage for init/apply/config get|set.
rig config get|set The headless counterpart to the wizard. get reads one nested key. set <dot.path> <value> is preview-by-default: it validates the prospective config entirely in memory, shows the config change + resulting reconcile plan, and writes nothing. Add --commit to write the change and execute that same validated plan; --no-apply is the explicit legacy write-only mode. --global targets ~/.config/rig/config.yaml.
rig env list|set|del Machine-wide env.vars keys (search API keys, COLORTERM, …). Always writes ~/.config/rig/config.yaml (the same path as rig config set --global env.vars.KEY). set/del write + reconcile by default so ~/.config/rig/env/rig.env.sh updates; omit VALUE to read stdin (keeps the secret out of argv/history). list masks values (*** + last 4); --show prints them in full. Both files are plaintext — this is not a secret store.
rig profile init|sync|status Carry your global config between machines through a private git repo (<forge>/<login>/.rig-profile) holding ~/.config/rig/config.yaml. init [URL] clones it (or seeds an empty repo with this machine's file and pushes) and records profile.repo; without a URL it uses profile.repo, else https://<host>/<fj login>/.rig-profile when fj whoami knows the login. sync is two-way: only local changed → commit + push; only remote changed → pull (the local file is backed up first); both changed → refused, nothing written — pick a side with --take local|remote. status [--fetch] says which side changed, writing nothing (exit 3 when not in sync). Once a profile is set up, rig apply commit syncs it first on every machine (non-fatal; profile.auto_sync: false turns that off). Pushes warn about env.vars secrets and are refused to a repo the forge reports as public. See below.
rig config-web A machine-wide web console — one browser tab per rig-managed repo (discovered from the repository registry) plus a Global tab for ~/.config/rig/config.yaml alone. Each tab renders every area with its live effective value, tagged with the layer an edit lands in, next to a drift panel (the same two-way engine rig status uses). An edit routes to the owning layer and is written by the same engine as rig config set/the wizard (fail-closed validation) — then the page offers an interactive apply: a plan preview (mirrors rig apply info, each action tagged with what kind of change it is — creates a file, installs a hook, changes a permission, etc.), confirm-or-skip individual actions, then live per-phase progress as the same shared engine (plan.build + run_plan) rig apply/rig init use actually applies them. A stale preview (config changed since you looked) is refused rather than silently applied; only one apply runs at a time. Lifecycle is the shared agenttools-service manager: run (foreground) / start (background daemon) / status / stop / enable (install launchd-macOS / systemd---user-Linux autostart + start) / disable. Binds 127.0.0.1 only, with a same-origin (CSRF) + Host (DNS-rebinding) guard on every mutating/compute-triggering request. A bare rig config-web prints help, never launches. --port, -C <repo>. The lifecycle verbs need the agenttools-service lib (an agent-tools nested lib, not on PyPI): uv pip install --python <rig's interpreter> -e <agent-tools>/lib/agenttools_daemon -e <agent-tools>/lib/agenttools_service (the --python target makes the libs land where rig imports them; the error message prints the exact interpreter path). Without it, rig --help and every other command still work; a lifecycle verb fails closed with that install hint.
rig evolve Project evolution portal. Serve a local browser UI with a git activity histogram, proportional file treemap, clickable selection, and provider health. The first slice is file-level and read-only; symbol/LSP/provider overlays build on the same API. Lifecycle uses the shared agenttools-service verbs: run / start / status / stop / enable / disable. A bare rig evolve prints help, never launches. --port, -C <repo>.
rig install-skill Register the rig agent skill so skills-directory harnesses auto-discover it (currently Claude Code and Codex).
rig stats show Tool-adoption and escape-hatch analytics. Parse the session logs of every agent harness on the machine and report how often each tool is invoked, bucketed into baseline / ours / review-cycles / external-advertised / other — so you can see whether the rig + agent-tools ecosystem is actually being used vs the built-in baseline. Also reads ~/.config/agent-tools/overrides.log and hatch-relevant ship-audit.jsonl bypass lines, grouping escape hatches by hook and splitting broken-gate vs lazy. `` `--format json
rig worktree create Standardized agent-worktree creation. Idempotently registers .worktrees/ in the repo's .git/info/exclude (never the committed .gitignore), THEN creates a linked git worktree at <repo>/.worktrees/<name> — the one convention rig converges every repo on, replacing the several ad hoc locations (Claude Code's own .claude/worktrees/, a bare in-repo .worktrees/, a sibling-of-repo .worktrees/) that had grown up around the ecosystem — so a freshly created worktree never dirties git status in the primary checkout, and a broken exclude file is caught before any worktree exists. --branch overrides the branch name (default: <name>); --from <ref> overrides the base ref (default: HEAD). In a bun repo with bun.enabled, it then runs bun install --frozen-lockfile in the new tree, as the repo's own bunfig configures it (bounded at 15 min; only the global config turns it on, bun.worktree_install: false turns it off globally or per repo), and rig status flags broken worktree installs — a node_modules symlink, broken links into the store — and notes off-store ones (see docs/config-schema.md bun).
rig worktree remove The inverse of create. Force-removes the linked worktree at <repo>/.worktrees/<name> (git worktree remove --force), then deletes the branch it had checked out (git branch -D) — read from git worktree list --porcelain -z, not assumed to equal <name>, since create --branch can diverge from the directory name. git worktree remove alone leaves the branch behind, so skipping this step would make a bare retry of create with the same name fail with "a branch already exists". Refuses outright (no worktree removed) if the branch can't be reliably identified first, if .worktrees/ is a symlink pointing outside the repo, or if .worktrees/<name> ITSELF is a symlink (a real worktree root is never a symlink, so this refusal never blocks legitimate use). A genuinely detached-HEAD worktree (no branch to find) is removed cleanly with no second step. Also recovers a worktree whose directory was deleted by hand (rm -rf instead of git worktree remove) but is still registered with a live branch. Requires git >= 2.36.
rig worktree gc Classify and clean up worktree sprawl. Lists every worktree git knows about for a repo — wherever it physically lives, not just the standardized .worktrees/<name> — and classifies each as live (a running claude/codex/opencode process has it as its cwd — checked FIRST, absolutely, before anything else), prunable (its directory is gone but git still has it registered), dirty (uncommitted changes — never auto-removed), merged/closed (its PR resolved via gh pr list), no-pr-stale (clean, no PR, older than --older-than-days, default 14), or active (an open PR, or recent activity). Report-only by default; --yes actually removes merged/closed/prunable (plus the branch, mirroring remove's two-step contract); no-pr-stale additionally needs --include-stale. --dry-run always forces a report even with --yes, mirroring rig apply --dry-run. --repo <path> targets one repo; omitted, it fans out over every repo the machine-local repository registry (rig config-web's same discovery) already knows about. rig status reports a cheap (no disk-size scan) stale-worktree count using the same classifier. Caveat: a merged/closed worktree is only auto-removed once its branch's commits are unreachable from no surviving ref — with squash/rebase-merge + fetch --prune (a common GitHub setup) that's never true, so merged worktrees classify dirty and are kept instead; see the module's "Known limitations" for the full trade-off.
rig daily Merged-PR "what shipped" report, ready to paste into a Slack Daily channel. Source of truth is gh pr list --state merged — never an LLM call, never a ticket status alone. Grouped into Security / Infra-CI / Performance / Product-UX / Other, one plain-language fact per line, ticket/PR reference last in parentheses. Default repos: hyperide/hyper-saas, hyperide/hyper-ext-e2e (override with repeatable --repo or ~/.config/rig/daily.yaml's repos:). Tracks a PER-REPO watermark at ~/.config/rig/daily-state.json so a plain rig daily run never repeats a PR — each repo's watermark only advances when THAT repo's own fetch succeeded and returned a complete page, so one repo's outage or a newly-added repo never borrows another repo's cursor; if every configured repo fails, the command exits non-zero instead of a misleading empty report. --since (relative 24h/7d or an ISO-8601 timestamp) and --dry-run are always read-only. rig daily install-skill registers the daily agent skill the same way rig install-skill does.
rig report HTML completion report from git history since the merge-base with main — the HyperIDE /result-report gather, as a rig command. Writes a self-contained HTML file you can open (file:// path printed on stdout) plus a text summary of commits and files. Does not publish to GitHub Pages. rig report [TASK_ID], --title, --out PATH, --base REF, -C.
rig usage Claude token/cost usage across accounts. Aggregates real per-message token usage from ~/.claude/projects and every ~/.claude-accounts/account-*/projects (the accounts managed by the separate claude-rotate tool), by model, account, and token type (input/output/cache-write/cache-read). Cost is a HYPOTHETICAL estimate at published Claude API list prices — this is a Claude.ai subscription, not pay-per-token billing, so it is never a real bill; a model ID not in the priced table is reported separately as "unpriced", never guessed at. Bare rig usage reports the current week AND current month; --period day|week|month narrows to one window. --json emits the stable, versioned contract (schema, generated_at, disclaimer, accounts_scanned, periods) that a separate, independently-built tg-cli command invokes on a schedule: rig usage --json --period week at end-of-week, rig usage --json --period month at end-of-month. Read-only; parsing is streaming/line-by-line with mtime-based file pruning, so a scheduled run only re-parses the files actually touched in the requested window, not the whole history.

Not rig subcommands, but provisioned by rig apply: gh ship <PR> (a gh alias, see ship_delegator) and fj ship <PR> (the fj wrapper the fj block installs) — one command under two names: both run the same dispatch to the repo's ship delegator / agent-tools' ship.sh, which picks GitHub or Forgejo by the origin's host (its Forgejo provider: agent-tools#793).

The Codex updater that used to be rig codex update moved to harness-cli as harness codex update (same options); rig reconciles the dev environment and no longer updates agent-harness binaries.

Quick start — init then apply

There are two commands, and they are not the same thing: rig init is first-run onboarding (no config yet → scaffold one + preview the catalog it would wire in); rig apply is the steady-state reconcile (config exists → converge the disk to it), and it too is preview-by-default — a bare rig apply prints the plan and applies nothing; rig apply commit is what actually executes. You run init once to scaffold + review the plan, then rig apply commit to apply (and re-apply forever after; rig apply alone to re-preview). The default rig.yaml init writes provisions auto-mode (the agent runs autonomously with minimum babysitting) — recommended on by default, and safe because the agent-hook guards are applied alongside it.

init does NOT apply by default — that is deliberate. A bare rig init with no TUI and no flags writes nothing and applies nothing; it prints a non-destructive PREVIEW of the plan and how to proceed (it should never "do a bunch of things" with no instruction). rig init --yes scaffolds rig.yaml (config only — still nothing applied), then you run rig apply commit. To do both in one step, use rig init --yes --apply (the explicit one-shot).

How init decides its mode (TTY + flags). A bare rig init runs the interactive TUI wizard (with Export-config-only vs Apply buttons) whenever there is a TTY — textual ships WITH rig as a core dependency, so the wizard is always available; no install step. With no TTY (piped / CI / agent), or with --no-tui / RIG_NO_TUI=1, it falls back to the non-destructive PREVIEW instead of hanging on a wizard nothing can drive. Any explicit signal (--yes / --config … --yes / --apply) is non-interactive. (rig apply is never interactive — it has no wizard; rig apply commit executes headlessly.)

rig doctor                                    # check deps; rig doctor --yes to install
rig init                                       # no config yet: scaffold rig.yaml + PREVIEW the plan
rig apply                                      # PREVIEW what apply would do (mutates nothing)
rig apply commit                               # execute it (and re-apply on every machine, identically)
rig init --yes --apply                         # or scaffold + apply in one step (the explicit one-shot)
rig status                                     # later: has the repo drifted from rig.yaml?
rig setup                                      # interactive wizard: see + change every area, then apply

To edit the config before applying: rig export -o rig.yaml, tweak it, then rig apply commit.

rig setup — the interactive config wizard. In a terminal it shows what is enabled across every reconciled area (the rig status rows), lets you toggle/change any option in the local rig.yaml AND the global ~/.config/rig/config.yaml — each option with an inline hint of how and why — then applies the change on the spot. Run from a non-TTY (a pipe/redirect) it prints usage for the core commands instead of a half-wizard. For scripted single-value edits use its headless counterpart rig config get <dot.path> / rig config set <dot.path> <value> — a dot-path editor whose writes are previewed by default. Add --commit to write + reconcile; --global targets the global config and --no-apply is explicit write-only mode.

Headless / agent path (no TUI):

rig init --yes                                 # scaffold rig.yaml (config only; nothing applied)
rig apply commit                               # apply it; re-apply identically on every machine
# or, the explicit one-shot:
rig init --yes --apply                         # scaffold rig.yaml AND apply in one step

rig stats — is the ecosystem actually being adopted?

rig apply installs the tooling; rig stats tells you whether anyone is using it. It reads the on-disk session logs of every agent harness on the machine and counts how often each tool is invoked, sorting every invocation into five buckets:

  • baseline — the harness built-ins (Bash, Read, Write, Edit/MultiEdit, Grep, Glob, NotebookEdit, Task/Agent, WebFetch/WebSearch). The yardstick.
  • ours — the agent-tools ecosystem only: the CLIs rig / tg / draw / 3d / task / dev / pm / research / harness / qa / stt (detected inside a shell command — a Bash call running tg … is pulled out of the baseline shell count and re-labelled tg (cli)), plus our skills except review. Not the review MCP.
  • review-cycles — the review CLI inside Bash (re-labelled review (cli)), mcp__review__*, and skill:review. The adoption ratio (ours / (ours+baseline)) excludes this bucket, so review volume does not inflate agent-tools adoption.
  • external-advertised — the third-party tooling we ship/recommend: MCP servers (serena, sverklo, context7, playwright, …) via the mcp__<server>__<tool> prefix, plus external skills (agent-browser, superpowers, h-*, debate-swarm, …).
  • other — everything else.
rig stats show                                  # default: rich terminal UI (tui)
rig stats show --format json                    # canonical machine-readable data
rig stats show --format web                     # self-contained local HTML dashboard
rig stats show --since 2026-06-01 --until 2026-06-15   # window + period comparison
rig stats show --harness claude-code --repo /path/to/repo   # filter by harness / repo

Harnesses parsed: Claude Code (~/.claude/projects/<enc>/<session>.jsonl — the richest source), Codex (~/.codex/sessions/.../rollout-*.jsonl, or $RIG_CODEX_HOME/sessions/.../rollout-*.jsonl), Gemini (~/.gemini/tmp/<hash>/chats/session-*.json), omp (~/.omp/agent/sessions/<enc>/**/*.jsonl, or $PI_CODING_AGENT_DIR/sessions/...), and opencode (~/.local/share/opencode/storage/). The supported-harness list is data-driven: each parser self-registers, and a harness whose logs aren't on the machine is reported as "not found" rather than failing. Adding a harness is one file in riglib/stats/sources/. Parsed session files are cached per-source under ~/.cache/rig/stats/<harness>.json, keyed by each file's (mtime, size): a closed session (the overwhelming majority) is never re-parsed once cached, so a repeat rig stats show only pays for genuinely new/changed session activity — the cache is purely an optimization and is transparent to every filter (--repo/--harness/--since); delete the directory any time to force a full rescan.

Outputs: json is the canonical shape every other renderer draws from; tui (default) is a rich table-and-bar-chart report that degrades to plain text if rich isn't installed; web serves a self-contained HTML page (inline SVG charts, no CDN, no JS deps) on a local port (--web-port, default auto). All three break the counts down by repo and by harness and render a daily trend; the json document additionally exposes the weekly series. --since yields a before/after period comparison: the selected window against the equally-long window immediately before it.

Escape hatches: the same command also reads the agent-tools hatch audit (~/.config/agent-tools/overrides.log — primary; field hatch is the hook id) and hatch-relevant lines in ~/.config/agent-tools/ship-audit.jsonl whose decision contains bypass: (mapped to ship-external-review or ship-review-quorum). Events are grouped by hook and split broken-gate (the gate fired wrong — e.g. ship-review-quorum with models: 0 / quota / 2 of 3, or orchestrator-stays-thin on a dispatched leaf worker) from lazy (the agent reached for a hatch instead of the sanctioned alternative). The same ts+hook in both files counts once (overrides.log wins); duplicate rows inside overrides.log are not collapsed. Missing files are an honest zero, never a crash. JSON exposes a first-class "hatches" key; tui/plain always print an Escape hatches section (Escape hatches: 0 when empty). --home and --since/--until apply the same way they do for tool adoption. Telegram history is not parsed separately — overrides.log is the tg-ctl hatch-question audit sink.

Config — rig.yaml

rig.yaml is committed by default. It is the reproducible source of truth: commit it, and rig apply reproduces the same install on any machine and in any agent session.

The config cascades by location (no scope flag):

  1. Global — ~/.config/rig/config.yaml (machine-wide defaults you carry across repos).
  2. Per-repo — ./rig.yaml (overrides the global layer; committed).

Dicts merge recursively (per-repo wins); lists/scalars replace wholesale. See docs/config-schema.md for every key. A worked example is rig.yaml at the repo root (this repo dogfoods its own config).

Global git settings — git:

The global config can provision git config --global too, so a fresh machine gets your identity and git defaults from the same file as everything else:

git:
  config:
    user.name: Alex Ultra
    user.email: someone@example.com
    pull.rebase: true
    init.defaultBranch: main

rig apply commit sets each key that is missing or different (bools as true/false), records the prior value of anything it overwrote, and never unsets a key you set by hand; rig status reports each drifting key. The block is global-only — a repo rig.yaml that declares git: is rejected, because keys like core.sshCommand run code. Details: docs/config-schema.md#git.

rig profile — carry your global config between machines

Your global config lives in one file, so it can travel through one private git repo:

fj repo create .rig-profile --private          # once, on the forge (rig does not create repos)
rig profile init https://git.hyperide.ai/<login>/.rig-profile   # machine A: seeds the empty repo
rig profile init https://git.hyperide.ai/<login>/.rig-profile   # machine B: adopts it
rig profile sync                                # after a change on either side
rig profile status --fetch                      # which side changed? (writes nothing)
  • Two-way, never a silent merge. rig compares the local file, the repo's copy, and the snapshot of the last sync. Only local changed → commit + push. Only the repo changed → pull, after backing the local file up as config.yaml.rig-bak-<stamp>. Both changed → refused with both paths printed; merge by hand into the local file and rig profile sync --take local, or keep the repo's with --take remote. Both files are validated before they cross, so a broken config is never pushed or adopted.
  • The repo must be private. env.vars (rig env) often holds API keys and the file is plaintext. Every push of a config with env.vars warns (naming the keys), and a push is refused when the forge reports the repo as public to an anonymous API request.
  • Commits use this machine's git identity — provision it with the git: block above. With none, the push fails and names git.config.user.name / user.email.
  • Every machine with a profile keeps it in sync: rig apply commit syncs before it builds the plan; a failure warns and applies the local file, and a pull is flagged as a warning (that plan comes from a config you did not preview). A preview never syncs. profile.auto_sync: false (rig profile init --no-auto-sync) turns this off — for every machine, since the setting travels in the synced file.
  • The checkout is ~/.config/rig/profile/repo/ (rig-owned) and the snapshot ~/.config/rig/profile/state.json (never committed). init records profile.repo through the same writer as rig config set --global, which does not keep YAML comments. The agent-tools protect-main pre-push hook is switched off in the profile checkout only (git config hooks.skipGlobal protect-main there — a one-file config repo has no PR flow); every other repo keeps it, and the secret scan still runs on profile commits.

Autonomous mode — global agent operating policy

mode.name: autonomous belongs in the global config (~/.config/rig/config.yaml). It declares how an agent should keep working before it asks for help: review/fix iterations until a clean state, review quorum for decisions, escalation through the configured framework skill, parallel worktree comparison before escalation, allowlisted development-tool flows, and limit-aware parallelism caps.

mode:
  name: autonomous
  autonomous:
    review_fix: { enabled: true, max_iterations: 5, until: clean }
    decisions:
      review_quorum: { enabled: true, min_iterations: 2, min_models: 3 }
    escalation:
      framework_skill: decision-request-discipline
      require_parallel_worktree_comparison: true
    parallel_worktree_comparison: { enabled: true, candidates: 2 }
    development_tools:
      allow: [Bash(dev:*), Bash(review:*), Bash(task:*)]
    parallelism: { max_agents: 4, max_worktrees: 4, reserve_slots: 1, limit_aware: true }

rig apply --dry-run surfaces that policy as plan notes, and the development-tool allow rules flow into the existing additive permissions.allow merge for supported harnesses. Raw development-tool allow rules are currently applied only to Claude Code's verified permission-rule dialect; unsupported harnesses get a plan note and the rules are skipped. framework_skill is a named behavioral skill for agents to follow during escalation, not a callable interface invoked by rig.

Auto-mode — provisioned by the reconciler

A harness: block tells rig apply to write the agent harness's auto/permission setting, so autonomy is part of the reproducible config — not a manual per-machine toggle:

harness:
  enabled: true
  kind: claude-code          # skills-dir: claude-code|codex · native: opencode|omp · instruction-file: pi|commandcode (codex also reads AGENTS.md)
  auto_mode: true            # RECOMMENDED: writes permissions.defaultMode=auto (user scope)
  hook_bridge: { enabled: true }   # wire the agents-hooks/v1 → harness dispatcher (default ON)

For claude-code, auto_mode: true writes permissions.defaultMode=auto to the user settings (~/.claude/settings.json) — Claude Code honors auto only at user scope (it ignores it in a repo's project settings), so auto-mode is a per-machine setting: declare the harness: block in the global config (~/.config/rig/config.yaml), not per repo. auto (a safety-classifier preview) auto-approves but a classifier blocks anything that escalates beyond your request, touches unrecognized infrastructure, or looks prompt-injected — strictly safer than bypassPermissions (which skips every check; pin mode: bypassPermissions to opt into full bypass at project scope, e.g. inside a container). rig apply merges only that one key (everything else is preserved), idempotently with a backup on conflict, and rig status flags drift. Defense-in-depth: the agent-hook guards rig installs in the same pass (block-secrets-write, block-no-verify, enforce-timeout-on-bash, block-raw-process-env, block-raw-pr-merge, block-reset-hard) catch dangerous tool calls before the side effect, complementing the classifier.

Those guards only fire because of the hook bridge. Harnesses run hooks declared in their own native config/plugin surfaces, not the descriptor files agent_hooks installs, so a bridge is required to make the descriptors actually execute (agent-tools#18). The same harness block therefore registers the matching bridge: Claude Code gets cc_hook_bridge in settings.json, Codex gets codex_hook_bridge in ~/.codex/config.toml (or $RIG_CODEX_HOME/config.toml), and opencode gets opencode_hook_bridge/plugin.js symlinked into the repo-local .opencode/plugins/zz-agent-tools-hook-bridge.js ordered plugin path. Without that bridge the guards above would be inert files. Set hook_bridge: { enabled: false } to opt out. If agent_hooks.target points at a custom descriptor directory, the bridge remains registered with that descriptor-dir override; opencode uses a small managed wrapper plugin for this case. Because that plugin path is machine-local, rig also adds it to the repo's .git/info/exclude; when upgrading from the prior global opencode bridge path, rig removes the old managed global symlink if it still points at an agent-tools opencode bridge plugin. See docs/config-schema.md for the full harness schema and the per-harness event coverage.

Model-freshness schedule — a daily cron, provisioned by the reconciler

A models: block tells rig to provision a daily cron that runs the agent-tools model-freshness checker (lib/checker/model_freshness.py) — which polls provider model-list endpoints and proposes version bumps to the model board. On rig init AND rig apply, rig checks whether the schedule is installed and installs it if missing (idempotent):

models:
  enabled: true
  schedule: { time: "12:00" }    # daily at noon (default)

Cross-platform: macOS → launchd (a ~/Library/LaunchAgents/ai.hyperide.model-freshness.plist loaded via launchctl), Linux → crontab (a sentinel-fenced managed line). rig status reports whether the schedule is installed or drifted; rig doctor flags a missing scheduler binary. See docs/config-schema.md for the full schema.

Drift — surfaced both ways, never silently reconciled

rig status reports two directions:

  • config→disk — declared in rig.yaml but missing/modified on disk. rig apply converges these.
  • disk→config — installed on disk but not declared (orphan / hand-added). These are reported, not deleted — you decide whether to adopt them into the config or remove them.

The status headline is grouped by reconciled area under the GLOBAL machine-wide layer and, when you are inside a git repository, the REPO layer from ./rig.yaml. Outside a git repository, rig status ignores any auto-discovered local rig.yaml, shows only GLOBAL areas, and prints that the repo layer / rig.yaml is N/A; it does not tell you to commit a repo config where no repo exists. An explicit --config can still declare GLOBAL areas in that mode, but repo-scoped areas remain N/A until you run status inside a git repository.

How rig consumes agent-tools (the integration seam)

rig never vendors agent-tools content. At runtime it locates an agent-tools checkout — agent_tools_source in config, else $RIG_AGENT_TOOLS_SOURCE, else ~/xp/agent-tools / ~/work/agent-tools / ~/agent-tools — and scans it live into a catalog (riglib/catalog.py):

agent-tools path becomes
skills/universal/<name>/SKILL.md a skills item (group universal)
skills/by-type/<kind>/<name>/SKILL.md a skills item (group by-type/<kind>)
agent-hooks/<name>/<name>.<point>.json an agent_hooks item
ci/<name>/{workflow.yml,*.sh} a ci item
git-hooks/global-dispatcher/ the git_hooks dispatcher item
mcp/<name>/ an mcp item

The catalog drives config validation (unknown item names fail closed), the wizard's description panes, and the install actions. Update agent-tools, and rig picks up new items on the next scan — no code change in rig.

Universal skills vs. a project's AGENTS.md

rig is the universal skill layer. Cross-project, always-apply MANDATORY skills (for example visual-proof-cycle or task-completion-selfcheck) are provisioned by rig from the agent-tools catalog and meant to reach every project and every user through the SessionStart blurb, the rig-installed skills, and each skill's own trigger description. That layer is their single source of truth.

A project's AGENTS.md (or a repo-level CLAUDE.md) is for project-specific guidance only — how this repo builds, its layout, its local conventions. Never duplicate a universal mandatory skill into an individual AGENTS.md: it pins a stale copy to one repo, hides the real source, and goes stale the moment the skill changes. The universal layer is the one place that carries these mandates — let it, and keep AGENTS.md project-specific.

Architecture

riglib/
  cli.py            argparse + subcommand dispatch (lazy imports)
  catalog.py        scan an agent-tools checkout → item registry  ← the integration seam
  config.py         cascade loader + fail-closed schema validation
  detect.py         env/project + OS/package-manager detection
  plan.py           (config + catalog) → ordered InstallPlan       ← shared by init & apply
  schedule.py       pure planning of the model-freshness cron artifact (launchd/crontab)
  drift.py          two-way drift detection
  doctor.py         dependency diagnosis + bootstrap across package managers
  state.py          SetupState ⇄ rig.yaml (the single serializer)
  install.py        install-skill (agent discovery)
  logging.py        opt-in JSONL structured logging (stdlib)
  actions/          stdlib-only install actions (the executor)
    runner.py         run_plan: copy_skill / install_agent_hook / install_dispatcher /
                      install_ci / register_mcp / apply_harness / provision_schedule —
                      idempotent, backup-noted
    fsutil.py         conflict-policy + idempotency + backup helpers
  stats/            tool-adoption analytics (`rig stats show`) — a 3-stage pipeline
    sources/          one pluggable parser per harness (@register); CC / codex / gemini /
                      omp / opencode → a normalized ToolInvocation stream
    taxonomy.py       the data-driven baseline / ours / external-advertised / other rules
    aggregate.py      pure reductions → counts / breakdowns / day+week trend series
    render/           json (canonical) / tui (rich, lazy) / web (http.server + inline SVG)
  tui/app.py        the textual wizard — a thin front-end over the same engine

setup and apply share one plan builder and one executor; the TUI just wraps the executor with a progress view. One code path, two front-ends — the wizard can't drift from apply.

Development

uv venv && . .venv/bin/activate
uv pip install -e '.[test]'             # core deps (pyyaml, textual, rich) + pytest
python -m pytest -q                     # unit suite
bash tests/smoke.sh                     # end-to-end smoke (needs an agent-tools checkout)
bash tests/smoke.sh --fast              # the seconds-cheap pre-commit subset
scripts/install-smoke-precommit.sh      # wire the fast smoke into .git/hooks (once per clone)
python docs/gen_svgs.py                 # regenerate the diagrams

Run scripts/install-smoke-precommit.sh once after cloning to gate your commits on the fast smoke locally — a commit that breaks the real rig status flow is then blocked before push, not just in CI.

How rig compares

Most setup tools fall into three buckets. Dotfile managers (chezmoi, yadm) version a person's config across machines — ~/.gitconfig, shell rc, secrets. Scaffolders (cookiecutter) stamp a project once from a template and walk away. Config-as-code (Projen, Nix home-manager) regenerate managed files from a typed/declarative source and keep them in sync.

rig is config-as-code, but aimed at a different target: a repository's agent guardrails — skills, agent-hooks, the global git-hook dispatcher, CI gates, and MCP registrations — sourced live from the agent-tools umbrella. It is declarative + idempotent (one rig.yaml, re-apply identically on any machine), it detects drift in both directions (config→disk and orphan disk→config, reported not silently overwritten), and it bootstraps the dependencies those guards need across brew/apt/dnf/pacman/zypper.

Tool Target Declarative config Idempotent re-apply Bidirectional drift Agent skills / hooks / CI gates Dep bootstrap
rig a repo's agent guardrails ✓ (rig.yaml) ✓ ✓ (both ways, reported) ✓ ✓ (multi-PM)
chezmoi personal dotfiles ✓ ✓ ~ (diff vs source) — —
yadm personal dotfiles ~ (git + alt files) ✓ ~ (git status) — —
cookiecutter new project from template — (prompts once) — (one-shot) — — —
Projen project build/CI config ✓ (typed JS) ✓ (synth) — (overwrites) — —
Nix home-manager a user's whole env ✓ (Nix) ✓ ~ (rebuild) — ✓ (Nix store)

~ = partial. Dotfile managers and home-manager are per-user; cookiecutter is one-shot; Projen reconciles build config but overwrites rather than reporting drift and knows nothing of agent skills/hooks. rig is the only one of these whose unit of work is a repo's agent-facing guardrails — and the only one that surfaces hand-added orphans instead of clobbering them.

Ecosystem

Part of the HyperIDE.ai agent toolchain. Sibling tools that already solve adjacent problems — check before building your own:

  • rig-cli — sets up a repo (and a dev machine) from a committed rig.yaml: skills, agent-hooks, git-hook dispatcher, CI gates, MCP, and the agent harness's auto/permission mode
  • tg-cli — simple Telegram CLI to send messages, photos & files, and a two-way agent bridge (reports, Q -> buttons, voice/rich)
  • review-cli — multi-model read-only code review from one command: diff review, cited quorum, brainstorm, visual review, and interactive spec-review tooling
  • agent-tools — the shared catalog rig applies: portable agent skills, agent-hooks, the global git-hook dispatcher, CI gates, and MCP servers
  • draw-cli — text-to-image via Hugging Face
  • 3d-cli — scriptable CLI for the full 3D FDM lifecycle: modeling, mesh repair, slicing, and print monitoring
  • task-cli — enforced ticket-system CLI for agents (GitHub Issues / Linear): acceptance criteria, motivation, and user-impact gates before work starts
  • dev-cli — project-scoped dev/e2e process runner: start/list/stop dev servers and e2e jobs
  • hyperide.ai — Figma replacement inside VS Code — edit React components directly through AST/LSP without AI hallucinations, token waste, or context-window limits

This section is kept in sync by rig apply from a canonical registry — edit it in rig-cli's riglib/ecosystem_readme.py, not here; a hand-edit here does not survive the next apply that reconciles this block.

Each CLI registers a skill into your agent harnesses (<tool> install-skill) so agents know it exists — see Install.

A machine opts into provisioning these tools with a global tools: block (see the config), and rig apply runs each tool's own install.sh. It also keeps them fresh: if a tool's repo ships a scripts/deploy.sh, rig apply runs it (a safe fast-forward-only git pull) on every apply — even when the tool is already installed — so a provisioned checkout doesn't silently drift behind origin. Freshness is opt-in per tool (no deploy.sh → skipped) and non-fatal (an offline/dirty/diverged tree is a warning, never an apply error). Both install.sh and deploy.sh run under the RIG_TOOL_INSTALL_TIMEOUT_S budget (default 300s) so a hung script can't wedge apply; raise it for a slow network fetch.

License

MIT — see LICENSE.

Release files for hyper-rig 0.53.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for hyper-rig 0.53.0
File Size Uploaded
hyper_rig-0.53.0.tar.gz 1.7 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for hyper-rig 0.53.0
File Interpreter ABI Platform
hyper_rig-0.53.0-py3-none-any.whl Python 3 none any Details

Total release size: 2.7 MB

Release files / hyper_rig-0.53.0.tar.gz

Download URL hyper_rig-0.53.0.tar.gz
Size 1.7 MB
Tags Source
SHA-256 checksum
How to use checksums
1e99386d31e7ff30ea204a0b63a5f91a88f0a77e11e38b6e325c0bbcf0036c77
BLAKE2b-256 checksum
How to use checksums
69bd74f6993a49b943e2773edf3eaed8211dd4272d27ba680b3d39c04f1b1bf6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / hyper_rig-0.53.0-py3-none-any.whl

Download URL hyper_rig-0.53.0-py3-none-any.whl
Size 1.0 MB
Tags Python 3
SHA-256 checksum
How to use checksums
25bace63059868367d857c0f99e8d769c6b3fee7fd66ceb8f0b11a703d9155a7
BLAKE2b-256 checksum
How to use checksums
efb85210777c17a3d103a64b484691fa53ef8ce6f158290781efa30a1bc846f0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release history Release notifications | RSS feed

This release

0.53.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page