Skip to content

OpenRig v0.6.5

Latest

Choose a tag to compare

@mvschwarz mvschwarz released this 04 Oct 10:39
· 133 commits to main since this release
5ea35e9

OpenRig 0.6.5

0.6.5 collects what was merged to main since 0.6.4: new features, many repairs, and a large share of community contributions.

npm install -g @openrig/cli

It is built from main at b345706b (after #651), plus eight changes merged to main afterwards: #652, #653, #654, #656, #657, #658, #679 and #681 (ported as #687). Work merged to main after that point isn't in this release. If something breaks for you, please open an issue.

Before you upgrade

Check CODEX_HOME first. If your shell rc sets a CODEX_HOME different from the daemon's, align them (or unset the daemon's explicit selection) before upgrading. Managed resume now uses the daemon-selected home and does not search the other home for an earlier thread, so a Codex seat whose earlier conversation lives in the other home won't find it. Choosing a home is opt-in: with CODEX_HOME unset, a second install still shares ~/.codex. To give an install its own Codex home, set an absolute CODEX_HOME when you start its daemon. Running sessions aren't moved, and no login, history or settings are copied (#638).

Restart the daemon after upgrading the CLI. The running daemon keeps its old build until it restarts: run rig daemon stop, then rig daemon start. On its first start the daemon updates its database, including two new indexes on usage samples; how long that takes on a very large usage history hasn't been measured (#569). It also replaces the bundled openrig-core hooks and skills, now at plugin version 0.1.3. Running seats pick them up when they next launch (#568, #591).

Codex seats get network inside their sandbox. See the highlight below. To keep it off, set network_access = false under [sandbox_workspace_write] in your Codex config (#608).

Shell startup files no longer change a seat's OpenRig settings. Each launch now re-applies the daemon's OPENRIG_URL, OPENRIG_HOME and related settings, and puts the rig that matches the running daemon first on PATH, even if your shell rc sets something else (#618). A classic Claude launch now runs from a staged script; see Known issues for the shells where a claude alias or function still doesn't resolve.

Highlights

Reasoning effort per seat. Rig and agent specs accept effort on a pod member, in a profile's preferences, or in an agent's defaults. OpenRig passes it to Claude as --effort and to Codex as model_reasoning_effort on fresh launch, resume and fork. A spec without it launches exactly as before. OpenRig doesn't check the value, and Pi seats ignore it (#320). A Claude seat launched with effort passes OpenRig's exact identity check, so messages to it carry no unverified-identity warning and rig seat clear-attention can verify it behind a shell wrapper (#681).

Codex seats can reach the daemon under the default sandbox. On OpenRig's default workspace-write sandbox, Codex seats now get network access inside the sandbox, so they can reach the local daemon and do their queue work. Before each such launch, OpenRig reads your Codex configuration and adds the network setting only when you haven't made your own choice and no managed requirement restricts it. That read takes about 0.1 to 1.5 seconds; if it takes longer than 4 seconds, that launch keeps network off. Seats launched with a named Codex profile, full bypass or an explicit approval policy are unchanged. This hasn't been checked with real logins, managed policy bundles or on Linux (#608, toward #275). When something does block a rig command from reaching the daemon, the error now says the connection was blocked and the daemon may still be running, instead of telling the agent to start another one (#504).

Claude seats come back with the right conversation.

  • After /clear, rig down and rig up bring back the current conversation, not the one from before the clear. At shutdown, OpenRig reads the live Claude process's session file and saves its current ID. When you shut down an archived rig whose seat name a live rig now uses, the refresh skips that live namesake, and the archived rig keeps its own saved conversation in its snapshot. Shutdown can take a little longer: it adds two process checks and a small file read, and a stalled process listing or file system can delay it. A /clear followed immediately by rig down, with no new message, was checked with a real Claude session on Linux: after rig up the seat came back to the empty post-clear conversation, not the earlier one. A conversation change in the moment between that read and shutdown hasn't been verified (#658).
  • A fresh Claude launch records the session ID OpenRig assigned, so seats that share a Claude config folder no longer pick up each other's conversation. Forks still look the session up by name (#656).
  • Managed Claude seats behind a shell wrapper or a native install are now confirmed from the native Claude process and the exact saved conversation ID, during restore, readiness checks, identity checks and rig seat clear-attention (#264, #335, #520, #554). Acknowledging a seat's attention no longer reports its conversation as resumed: continuity shows "unverified" unless there is strict restore proof (#652, #651).
  • rig send and queue wakes reach a Claude seat whose launcher shim starts the real Claude binary (#567), and a seat whose conversation changed with /clear (#607; see Behaviour changes).

Compaction waits for a restore map. Managed Claude compaction now asks the seat to write a restore map for that attempt and waits for it before sending /compact. Automatic compaction waits up to 25 minutes. If no map arrives, that attempt stops and automatic compaction stays off for the seat until you run rig compact again, so an unprepared seat can reach its context limit instead. rig compact gains --state, --cancel and --skip-map (#610, #633). If OpenRig can't tell which occupant a seat holds, compaction stops with occupant_generation_unavailable and points to rig reconcile-session <session> --no-launch (#645). The bundled restore skill now writes a ranked map before compacting and reads down it afterwards, and the daemon's post-compaction prompts ask for the map's top entries instead of every packet file (#591). A post-compaction profile without a seat recap now loads with a warning instead of failing (#597). Automatic compaction acts only on fresh context readings (#464). These changes weren't tested against a real Claude compaction.

See what transcript capture costs your host. rig ps --resources (with --json and --host <id>) shows load per CPU, running seats and what transcript capture costs. Idle panes are captured less often, backing off to once every 6 seconds, so an idle seat's transcript can trail its pane by up to about 6 seconds. Changes to transcripts.lines and transcripts.poll_interval_seconds now reach running seats without a daemon restart (#556, #624, #536). Load average isn't CPU use, and capture time is time spent waiting for tmux.

Large fleets stay responsive. Activity, identity and structural sweeps read tmux in a few batched calls instead of one or more per seat (#293, #309). Slack sweeps skip building expensive queue views for items with nothing to post. On a synthetic 200-row queue, that was much faster when few items needed a post, and about 11% slower when none had been posted; it is still a scan of active rows. Based on korallis/agent-stack#139 by korallis and Lee (#642). Each seat's latest usage sample is found through an index instead of by sorting its history, based on korallis/agent-stack#137 (#569). Execution views no longer freeze the daemon while their Git checks run (#557), the refocus hook starts fewer processes per prompt (#499), and a repeated session-boundary line no longer grows a transcript on every capture (#545).

Slack decisions with buttons, and threaded updates. A decision sent to a person can carry one to four questions, each shown as a row of buttons; a typed reply in the thread still works. A Slack app created from an older manifest must turn on Interactivity by hand, or the buttons do nothing (#195). rig queue create --human-intent update --reply-to <id> posts a follow-up into the earlier item's thread (#155). Local evidence files reach the thread again, and video and PDF files up to 50 MiB are attached (#298, #305). Both features were tested against a simulated Slack, not a live workspace.

Oh My Pi seats. A rig spec can declare runtime: omp to run Oh My Pi seats, each with its own home, config, skills and sessions under $OPENRIG_HOME/state/omp/<seat>. No live authenticated session against a real provider was run, and rig seat clear-attention can't yet recover an OMP seat after a full restore (#41); use rig up --existing <rig> --fresh <seat> instead (#35).

Restore checks that match restore. rig restore-check now checks the real queue store and each seat's selected Claude hooks (#328), runs the same pre-checks a restore would run against the snapshot it would use (#636), and reports a rig spec it can't locate as a yellow "not checked" instead of red, because restores never read that spec (#631).

Queue writes you can recover. rig queue create picks the item's ID before sending and prints it to stderr, so after a timeout or dropped connection you can check that exact item and retry with the same ID instead of creating a duplicate. A same-ID retry with a different body warns that the new body wasn't saved (#495). --source now works from a plain shell outside a seat, recorded as a self-declared source (#440). A missing queue ID names the daemon that was asked and how to read from another host (#654).

Agents learn the route to your project's context. The onboarding text and the bundled restore and reorientation skills now teach rig context work-install. It lists what the current project declares (its intent, context files and skills), and the agent reads what its task needs; --deliver prints everything. When several projects are declared, it stops with project_required, --json lists the project IDs, and --project <id> picks one. The placement skill gains guidance on where project knowledge belongs (#679).

Validate a spec without a daemon. rig spec validate now runs locally, with the same validators the daemon uses; rig spec preflight still needs the daemon (#566).

Behaviour changes to know about

  • One mismatched Claude launch token no longer blocks a send. After /clear or another in-place conversation reset, rig send and queue wakes deliver with a warning that the current conversation is unverified. This applies to every case where the only objection is a single mismatched launch token, and some of those can be a different conversation. A different runtime, a changed process, a binding change or an idle shell are still refused, and a restore can still report attention (#607).
  • @ is refused in pod and member IDs, because it would shift where the rig name starts in a seat's address. rig spec validate can still pass such a spec, so run rig spec preflight (#473).
  • Every rig queue create prints a request-ID line to stderr. With --json, stdout is still one JSON document (#495).
  • Failed reads now fail. These commands used to print an empty or successful result when the daemon refused the request, and now exit 1 or 2: rig bootstrap and rig requirements (#202), rig env status (#382), rig plugin list, rig agent-image list, rig context list and rig specs ls (#577), rig start --all (#578), rig mode cite (#426), rig chatroom history and rig chatroom wait (#476), and rig config reset when the file can't be removed (#284). rig compact-plan refuses a failed inventory read, and prints a labelled partial plan with exit 1 when one rig can't be read (#579). rig gateway human remove refuses when its queue lookup fails (#531). rig plugin used-by exits 1 for an unknown plugin (#262).
  • rig chatroom wait --timeout refuses blank, non-numeric or negative values. A number with a suffix still counts as seconds: 30s is 30 seconds, but 2m is 2 seconds, so use plain seconds (#355, #650). rig ask --wake-timeout refuses values it can't use (#356).
  • rig down keeps a rig it can't confirm is gone. If tmux can't be reached, for example "no server running", rig down reports that it couldn't confirm the session is absent, keeps the rig record, and blocks --delete (#513).
  • Ending a seat's session detaches any terminal viewing it, instead of switching that terminal to another session, even when your tmux config sets detach-on-destroy off (#187).
  • Claude config files. With an explicit permission mode and CLAUDE_CONFIG_DIR set, OpenRig writes onboarding and folder trust to <CLAUDE_CONFIG_DIR>/.claude.json instead of ~/.claude.json (#565). A classic launch writes both files when the daemon has CLAUDE_CONFIG_DIR set (#592). A file that already has both settings isn't rewritten (#595), and a malformed one is left alone with a warning (#565).
  • Your own Claude status line is kept. OpenRig no longer replaces a custom status line command in .claude/settings.local.json, or wipes that file when it doesn't parse. A seat that keeps its own status line doesn't run OpenRig's collector, so its context usage reads as unknown and resume-token capture is skipped (#497, #500).
  • Seat environments. Claude seats launched with a permission mode take their terminal and locale variables from their own pane instead of the daemon (#326). Seats now get USER and LOGNAME from the daemon (#564).
  • rig restore-check verdicts move. The check seat.<s>.queue-file is renamed seat.<s>.queue-store (#328). A rig whose spec can't be located moves from red to yellow (#631). A new rig.<name>.restore-preconditions check can mark a rig not restorable, or unknown when its restore inputs can't be read (#636).
  • New warnings and findings. The standing stuck sweep flags rows closed to a seat with handed_off_to and no linked successor, in a fixed 24-hour window so an upgrade doesn't raise findings about old history (#604, #341). A claimed row past its closure deadline gets one closure-overdue transition per claim (#593). A queue write to a seat that doesn't exist in a known local rig succeeds with a warning that names the likely typo (#337).
  • rig health above 200 families evaluates the 200 busiest and marks the result PARTIAL instead of failing (#357). A health source that fails is named as unavailable while the others still report (#626).
  • Notification URLs. An invalid ntfy or webhook URL turns notifications off with a logged warning, and a username and password in the URL move into a Basic Authorization header (#149).
  • Bundles. rig bundle create refuses a culture, docs or startup file whose symlink resolves outside the rig folder (#507), and bundle unpacking refuses entries with backslash traversal or Windows drive paths and skips links (#292). A declared skill that is missing or unreadable now produces a warning instead of being left out silently (#259, #274).
  • TUI. A second TUI on the same OpenRig home binds its own control socket and shows its path, instead of taking over the first one's (#205). Only a primary click activates controls (#549).
  • Smaller changes: rig context add reads a local pack's name the way a YAML parser does (#370). rig file copy treats my.host:/path as remote when my.host is a registered host (#368). A Slack token in single quotes in the secrets file now resolves; an unmatched quote is kept as a literal character (#376). Workflow specs with a colon in their version get new Library IDs (#441). Kernel seats launched after the upgrade no longer write their role into a shared CLAUDE.md or AGENTS.md (#562). rig transcript keeps blank lines (#639). rig ps --full prints full rig names in aligned columns (#600).

Everything else since 0.6.4

Messaging and delivery. OpenRig submits typed and pasted text with tmux's named Enter key, so text no longer sits unsubmitted when extended-keys is on (#540). Waits for an idle seat retry an unreadable observation until their deadline instead of refusing on the first bad sample (#603). The producer-link: advisory reports only what it observed (#606). The text OpenRig pastes into a pane goes through an owner-only temporary file (#292). A seat whose working folder contains | is still found (#216). Live event consumers receive events triggered by other events once each and in order (#527). Malformed JSON request bodies get a 400 instead of a 500 (#587). rig chatroom history --since compares times correctly (#208). Long ntfy titles are delivered again (#217).

Queue. Prompt-blocked work is escalated as one alert to the orchestrator or operator without typing into the blocked seat, and its wake retries resume once the prompt clears. Missing human bindings, unreadable registries and refused dispatches now stay unresolved and are retried on the existing cadence instead of being marked undeliverable (#619, #644). An unclaimed handed-off item whose wake was held back at a prompt keeps its bounded retries and then escalates (#623). A watchdog attached to a parked row survives the other row's claim, completion or re-park (#505), and fired receipts count only the latest park (#210). A decision already posted to its person gets no stuck finding (#518). A plain update closed with handed_off_to and no local successor carries a handoffAdvisory (#341). A remote response cut off mid-body is reported as an unknown outcome (#336). Writes addressed to this daemon's own host ID stay local (#588). A person's reply that closes an alerted row reports the alert as posted (#296). A stopped seat no longer shows as idle with high confidence (#288). rig queue whoami --recent-limit refuses a non-number with a clear error (#647).

Seats, launch and restore. Restore skips damaged snapshots (#207) and picks the newest of snapshots or checkpoints saved in the same second (#206, #601). A seat that becomes ready after about 20 seconds starts within the 30-second readiness allowance (#530). A rig's last seat relaunches after rig seat stop ended the tmux server (#325). rig shrink finishes when a member's session already exited (#431). OpenRig addresses tmux sessions by exact name, so a seat whose session ended can't be confused with another whose name starts the same way (#449, #614, #625), and a session literally named =name stays separate from name (#515). Shutdown reports failed Docker Compose teardown (#533) and keeps transcript capture for a seat it couldn't stop (#538). A periodic snapshot interval longer than about 24.8 days waits as configured (#548). rig seat handover reports a timeout as an unknown outcome (#198). rig seat status finds a seat by its canonical name before launch and after stop (#340). rig restore-packet write skips non-object transcript lines (#291). A failed rig context recap-write keeps the previous recap (#209). The session-identity hook reports whether its token was actually stored (#40).

Claude. OpenRig presses Enter once more when a Claude startup prompt is still visibly staged, and starts the seat with a warning instead of failing the launch (#598). Startup warnings distinguish an unrecognized input box from a text mismatch (#634, #617). Provider usage reports the later reset time when both Claude limits are used up (#455).

Codex. Codex 0.157 and 0.158 seats showing the empty-composer placeholder are recognized as idle, and a busy seat whose status row sits far above the composer isn't misread as idle (#295).

Pi. Long Pi launch, fork and resume commands run from a temporary script instead of being cut off by the terminal's line limit (#212). A failed Pi startup check no longer shows the seat as ready (#213). Preflight no longer reports Pi, Oh My Pi, Claude or Codex as missing when the daemon's working folder was deleted, and says why a check failed (#471).

Slack. Ordinary https evidence links show as links instead of breaking the message (#89). Retries search up to 10 pages of history for an earlier post with an unknown outcome (#395). rig slack verify warns about missing optional scopes (#334). rig slack enable explains a missing person registry (#332). Upload titles are redacted like message text (#302). Private downloads stop at their size limit (#333). Messages in different channels with the same timestamp are both delivered (#452). Concurrent retry passes keep each failed message once (#377), and stopping Slack while it waits to reconnect completes (#387).

TUI. Live activity updates back off when the stream keeps dropping (#380), retry when the stream is slow to open (#546), follow standard SSE line endings (#535), and close refused or late connections (#204, #543). Arrow keys work in application-cursor mode (#429). Commands keep the exact spacing in their argument (#443), and the control socket keeps multi-byte characters intact (#203). The local reader keeps its selection in range after a refresh (#434). Execution and proof views label retired and deferred slices (#350), show the wave map's real source (#428), show daemon adoption as N/A for a selected project (#552), and list current evidence before older proof rounds (#553).

CLI and hosts. rig ps counts a seat stuck at a pane-only permission prompt in the rig's attention total (#180). rig status (#349), rig start (#437) and four other commands (#439) say when the daemon didn't respond instead of calling it stopped. Kernel readiness waits stop at their deadline (#363). rig workflow run and watch stop waiting for a stream that never sends headers (#381). rig host doctor keeps a remote daemon's health verdict (#396). Remote rig up failures show the remote error (#329), rig terminal open prints HTTP errors (#229), and remote terminal views keep session names with spaces or quotes intact (#369). rig usage top refuses an out-of-range window (#483) and lists seats with missing counters as unknown instead of zero (#582). rig scope refuses self-dependencies (#286), refuses a stale mission edit instead of dropping another edit (#339), warns about dependencies left dangling by a slice move (#263), and reads frontmatter with Windows line endings (#378). New slices' PROGRESS.md points to rig proof show instead of seeding checkboxes (#338).

Files, transfer and context. Config writes replace the file in one step where the folder allows it (#576), and rig export keeps the saved rig.yaml intact if a write fails (#640). rig context add stages a local pack before publishing it (#583). Context addresses recognize headings indented by up to three spaces (#584), and the bundled Markdown address script keeps fenced examples intact (#388). Context roots that are symlinks to each other no longer duplicate a pack (#436). Profile errors call a source a dangling symlink only when it is one (#585). Agent images are written manifest-last, so a failed install leaves nothing behind (#580). Transcript tail reads can't hang on damaged UTF-8 (#581). The refocus hook explains a missing work node and falls back to the project chain (#484), and the bundled compose.py finds your topology through topology.root (#486).

Specs, bundles, proof and workflows. rig bundle create keeps file modes (#321), handles read-only sources (#575) and creates missing output folders (#258). rig plugin used-by searches the built-in spec libraries too (#262). Agent specs can point at a plugin with openrig-home:plugins/<name> (#620), and built-in agents load openrig-core from a custom OPENRIG_HOME (#627). A startup file can be marked orientation: role, and rig queue whoami --json and the refocus hook tell a seat where its role file is (#562). Lifecycle compilation (#211), proof evidence (#394) and the proof watcher (#373) work with nested mission folders, a mission's status change refreshes readiness (#366), review records added to a slice count toward its reviewed step (#427), execution views include README.md nodes (#438), and a failed proof write leaves no temporary file (#383). The workflow library keeps cached versions through a parse error (#508) and while unfinished work uses them (#512), recovers repaired specs in place (#442), notices same-second edits (#435, #572), and no longer removes a neighbouring folder's specs (#433). Service readiness accepts bracketed IPv6 targets (#215) and requires every Compose replica to be healthy (#218). Folders whose names start with two dots count as inside their parent (#459, #524).

Platform and setup. CLI commands (#461), the daemon's own endpoints (#509) and rig host list (#398) work with an IPv6 daemon host. rig daemon stop ends open event streams after a short grace period instead of timing out on them (#324). Pairing requests trim and sanitize the requester's name, and expired requests are pruned after an hour (#149).

Docs and skills. The npm page shows the README (#272), and the package descriptions call OpenRig a network of agents (#297, #304). The help guide's known-problems list, the capability page and the rig-spec runtime list match the code (#468). The rig-spec reference documents Pi seat folders, custom models and environment (#469) and HTTP readiness (#214). Shipped skills no longer point to skills that don't ship (#467, #510), route simple seat additions to rig grow (#406), and explain attention checks and token correction (#651). Help text is clearer for rig seat handover (#351), rig gateway human add (#354), rig broadcast --pod (#322) and rig context trace --seat (#323). The README explains why rig setup changes cmux's socket mode (#609). Contributors get architecture maps, a developing-openrig skill and a roadmap (#282, #539).

Web UI (maintenance mode, off by default). The terminal view keeps multi-byte characters intact (#456). Completing a mission updates its mission.yaml (#386). Mission Control shows the newest observations (#506), reports CLI versions it never observed as unknown (#523), and rejects unknown audit verbs with a 400 (#501).

How it was tested

  • The final package: one build of the exact release commit and one fresh install, with an ordinary CLI and daemon check. Every file that differs from the build validated below is accounted for (the project-context text, the effort identity fix and the version), and a content scan of the package found nothing unexpected. Its SHA-256 is 1d579fd61f349270ecf09d9f9646d20a1f4deb441a6c31bd775f5583f3d407f9.
  • Before the version change: 181 automated checks across six test files, with simulated runtimes, all passing; and six fresh installs of the bundled CLI, two of them with deliberately planted failures, which the checks caught.
  • Real Claude Code on Linux: restore, both plain and after /clear, after /clear and a reconcile, and after /clear then rig down with no new message; two fresh seats with the same name; launches in fish; and a seat launched with --effort high, on the earlier build and on the final one. On the final build, the identity warning seen on the earlier one is gone, and a restore without effort still resumes the same conversation.
  • Not tested: real Claude Code on macOS, and real Codex or Pi runs; the transcript and capture installed scenarios on the exact build; fish before 3.1, which was judged from the code only; Windows. The two same-name seats were checked for fresh session assignment, not for collisions on restore.
Run Platform Versions
Real Claude Code Linux Claude Code 2.1.220, fish 4.2.1

Known issues

  • Don't answer a numbered menu with a typed digit through rig send --dangerously-interact. In 0.6.5 it can confirm the option that has focus instead of the one you typed (#519).
  • A claude alias or function defined only in a nushell rc doesn't resolve for classic Claude launches. It also doesn't resolve on fish versions without command-scoped assignment, for fish launch commands that contain a backslash, or when the longer launch wrapper exceeds 512 bytes. 0.6.4 typed the command into the pane, so it worked there. Bash, zsh, sh, dash, ksh and newer fish are repaired. On fish 4.2.1 on Linux, a real Claude session launched both when claude was only a fish function and when it was on PATH. The other shells were checked in real tmux with Bash and with test stand-ins, not with a real Claude session (#618, #628, #657).- A restore can report a problem with a seat that works. Several fixes in this release target it, but they haven't been confirmed on a live seat (#273).
  • Codex network inside the sandbox hasn't been checked with real logins, managed policy bundles or on Linux (#608, #275).
  • After a reboot the daemon doesn't come back on its own. Start it with rig daemon start, then bring your rig back with rig up <name>.
  • Setup's optional cmux step can report an error.
  • The web UI's file preview runs scripts. As in 0.6.4, rendered HTML previews and SVG files opened directly can run scripts with the same browser access as the web UI's own pages. The web UI is off by default; preview only files you trust.
  • Browser access protects against unknown web pages and names. It isn't complete browser isolation, so keep the daemon on loopback or your tailnet.
  • Windows wasn't tested.

Thanks

To the people whose pull requests are in this release: @1solomonwakhungu, @amyrmahdy, @Coder8124, @dajiaohuang, @DeryFerd, @ege-arhan, @Essator, @korallis, @lab1207, @MelonSmasher, @Nikhi00718, @NishilRathod, @nvtoan0201-swe, @oodadoudou, @rudycelekli, @sahiljadhav7, @shravansumanthanan, @Totopo27, @Vaishnavi220506, @vanducng, @xiangzuodalao and @zichen0116.

And to korallis and Lee for korallis/agent-stack#139, which the Slack sweep change is based on, and to korallis for the query-plan finding in korallis/agent-stack#137 and the handover timeout report in korallis/agent-stack#32.