Repository navigation
feat(rex): add a Rex plugin and clauth rex install - #149
Open
harrisrobin wants to merge 8 commits into
Open
harrisrobin wants to merge 8 commits into
harrisrobin wants to merge 8 commits into
Conversation
rex-plugin/ gives Rex (superlogical.com/rex, in beta) what herdr-plugin/
gives herdr: actions that open Claude Code through `clauth start --auto
--with-fallback`, the clauth dashboard in a floating pane, and a pane label
naming the account each Claude Code or codex pane spends.
Rex loads it as a Lua module (`require("clauth").setup{}` from init.lua).
Rex runs event handlers only in `rex do` scripts, so init.lua starts
start-watch.sh, which runs one tag-watch.lua per Rex server. The watcher
resolves a pane's foreground pid with resolve-profile.sh, the same
live-session join and adopted-codex readlink herdr-plugin/report-profile.sh
uses.
Claude-Session: https://claude.ai/code/session_01S5npf9mJwNArHszhk4v1eW
Rex has no plugin manager: a plugin is a Lua module beside Rex's own
init.lua. `clauth rex install` writes the rex-plugin/ files compiled into
the binary to `clauth/` beside init.lua (REX_CONFIG, then
XDG_CONFIG_HOME/rex, then ~/.config/rex, Rex's own lookup) and appends one
marked `require("clauth").setup{}` block, then runs `rex config reload`
when the CLI is on PATH. Rerunning it refreshes the files after an
upgrade and adds no second block.
It refuses a plugin directory clauth did not write (no `.clauth-managed`
marker) and a symlink onto a checkout, and leaves init.lua alone when it
already has its own require("clauth"). `clauth rex uninstall` takes the
block out, leaving the rest of the file byte for byte, and removes only a
directory clauth wrote. Both confirm first; `--yes` skips it.
herdr's `confirm` becomes pub(crate) so both commands share one prompt.
Completions gain `rex install|uninstall` and `--yes` in all three shells.
Claude-Session: https://claude.ai/code/session_01S5npf9mJwNArHszhk4v1eW
A wiki page in the shape of Herdr-Plugin.md (install, updates, uninstall, actions and keys, options, pane labels, what it runs as you), the plugin's own README, and a row in the README, wiki Home and sidebar, plus a Quickstart entry for `clauth rex install`. Each says Rex is in beta. Claude-Session: https://claude.ai/code/session_01S5npf9mJwNArHszhk4v1eW
Owner
|
oh awesome! will review soon, could i see how it looks tho? |
A pane running `clauth start <codex profile>` was labeled "claude · <profile>". Its foreground process is the clauth supervisor for either agent, so resolve-profile.sh reported only the account and how it is spent, and tag-watch.lua named every clauth launch "claude". resolve-profile.sh now prints a third field, the agent: the live-session row's harness for a clauth launch (rows from before that field are Claude Code, as clauth reads them), codex for an adopted codex login, and claude for a bare claude. tag-watch.lua names a pane that has no label of its own after it. The new rex:: tests run the real script against a faked /proc and registry: both harnesses, a row with no harness, a bare codex with and without an adopted login, and a bare claude. Claude-Session: https://claude.ai/code/session_01S5npf9N7fT9knNbKwdkNeh
uwuclxdy
requested changes
Nov 2, 2026
uwuclxdy
left a comment
Owner
There was a problem hiding this comment.
Thanks for the plugin and the screenshot! Rex goes in as experimental support, and two pieces move into clauth itself so neither plugin carries its own copy:
clauth which --pid <pid>resolves the account a process spends, the joinresolve-profile.shand herdr'sreport-profile.sheach do today: the registry row up the parent chain skippingclauth mcp,current_memberoverstart_profile, then the adopted codex login or the global one. Plain output is the profile name,--jsonaddssource(live_session,codex_adopted,global) andharness(claude,codex), and it printsunknownwhen nothing resolves, likeclauth which. From 0.19.0 both print nothing instead, so treat empty andunknownalike. I'll land it onmommyfirst.- a read-only Rex row in the Services tab: installed, stale against the running clauth, watcher alive. I'll add that too. It reads the
.clauth-managedmarker, so keep itswritten by clauth <version>line as it is.
Keys, the label format and the --auto --with-fallback default are fine as they are.
A temp-and-rename replaced a symlinked init.lua (a dotfiles checkout) with a plain file and reset its mode, so the checkout never got the block. Install and uninstall now write it in place, as `clauth herdr install` writes herdr's config.toml. Claude-Session: https://claude.ai/code/session_01S5npf7xz73gi937TG5ssdw
start-watch.sh exits while its pidfile names a live watcher, so after a reinstall the old tag-watch.lua kept running until Rex restarted, and after uninstall it kept running with no resolver. Install and uninstall now SIGTERM each recorded watcher whose pid still runs tag-watch.lua, and uninstall removes ~/.local/state/clauth-rex/. A linked or foreign plugin directory keeps its watcher and state, since its checkout runs them. Claude-Session: https://claude.ai/code/session_01S5npf7xz73gi937TG5ssdw
Say it in the wiki page, the README and Home rows, the Quickstart entry and rex-plugin/README.md: nothing heals or updates the install, the Services tab has no controls for it, and a new Rex build can break it. Also say that install and uninstall stop the pane-label watcher, that uninstall removes ~/.local/state/clauth-rex/, and that a symlinked init.lua is written in place. Claude-Session: https://claude.ai/code/session_01S5npf7xz73gi937TG5ssdw
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

This PR adds a Rex plugin beside
herdr-plugin/, plusclauth rex installandclauth rex uninstallto set it up.Rex is in beta. It is a terminal multiplexer for coding agents (sessions, tabs, panes; a CLI, a Lua config, a
rex doscripting runtime, and the OSC 7501 program-status protocol). Its Lua API can still change, so this plugin could break on a future Rex build. I checked everything below against Rex 0.1.0 builds 1541 and 1584 (October 2026) on macOS.What the plugin does
It does the same three jobs as the herdr plugin, built on Rex's own extension points:
clauth_claude(split) andclauth_claude_tabactions open a pane runningclauth start --auto --with-fallback, so a new session starts on the fallback-chain member with headroom and moves on as accounts run out. Aprofile=argument pins one. Bareclaudein a Rex pane runs on the global login, and that is what this fixes for my operator.clauth_dashboardopens the clauth TUI in a Rex floating layer. A second press closes it.claude · work,codex · codexfor codex started through clauth or on an adopted codex login, orclaude · main (global)for a bareclaude. Rex has no custom sidebar field like herdr's metadata tokens, so the label is the only place the account can go. The pane's original label comes back when the agent exits.How it is built (
rex-plugin/)init.luais a Lua module loaded withrequire("clauth").setup{}from Rex'sinit.lua. It defines the three actions and binds three default keys.rex doscripts, not ininit.lua. So on every config load,init.luastartsstart-watch.sh, which runs onerex do --all tag-watch.luaper Rex server. Each watcher is pinned to its parent server's--listensocket, because several Rex versions can run at once. Amkdirlock and a pid check against the watcher's own argv keep it to one watcher per server.tag-watch.lualistens forterminal.process_changed. For a foregroundclaude,clauthorcodex, it runsresolve-profile.sh. It also re-resolves tagged panes every 10 s, since a--with-fallbackswap fires no Rex event.resolve-profile.shrepeatsherdr-plugin/report-profile.sh's join: the pid chain against~/.clauth/live_sessions/,current_memberoverstart_profile, skippingclauth mcphops, the adopted-codex readlink, andclauth whichfor a bareclaude. It also uses the same/proc-or-psreaders, so it works on Linux and macOS. I copied the logic rather than sharing it, so the two scripts now need to change together. The README says so. It also prints the agent,claudeorcodex, since Rex doesn't report one the way herdr does: for aclauth startpane that comes from the row'sharness, because the pane's process is the clauth supervisor for either agent.clauth rex install/uninstall(src/rex.rs)Rex has no plugin manager, so install is small:
clauth/beside Rex'sinit.lua. The files come from the binary throughinclude_str!, so they always match the installed clauth. It findsinit.luathe way Rex does:REX_CONFIG, then$XDG_CONFIG_HOME/rex, then~/.config/rex.require("clauth").setup{}block toinit.lua.rex config reloadwhen the CLI is on PATH.Safety rules:
clauth/directory without its.clauth-managedmarker, and refuses a symlink there (the dev setup, linking a checkout).init.luaalone when it already has its ownrequire("clauth").--yesskips the prompt, mirroringclauth herdr. I made herdr'sconfirmpub(crate)rather than copying it.This is deliberately much smaller than
clauth herdr install. There is no auto-update or heal (the user reruns install after upgrading), no Services-tab row, and no daemon or MCP integration. I left those out until you decide whether Rex is worth supporting at that depth.User-visible changes (per CONTRIBUTING)
clauth rex, withinstallanduninstall,--yes, and help text. Completions are added for bash, zsh and fish.alt+cmd+candshift+alt+cmd+csplit a Claude pane right or down, andshift+cmd+ctoggles the dashboard. I picked them because they collided with nothing on my operator's setup (I could not find Rex's default keymap documented, so I can't promise they never will), andshift+…+cechoes the herdr plugin'sprefix+shift+c. Any of them can be turned off withkeys = { … = false }.--auto --with-fallback, which can be changed withselect = { … }. Without a profile,clauth startwould refuse to run, so the plugin needs some default.Docs
wiki/Rex-Plugin.md, shaped likeHerdr-Plugin.md.rex-plugin/README.md.All of them say Rex is in beta.
Commits
feat(rex): add a Rex plugin beside the herdr one: the scripts only.feat(rex): add clauth rex install and clauth rex uninstall:src/rex.rs,tests/inline/rex.rs, CLI wiring and completions.docs(rex): document the Rex pluginfix(rex): label a clauth-started codex pane codex, not claude: found while making the screenshots, where aclauth start <codex profile>pane readclaude · codex.docs(rex): say a clauth-started codex pane gets the codex labelagent
cargo fmt --all -- --checkis clean. My machine has a global rustfmt config, so I ran it with--config-pathpointed at an empty file. Without that, the clean tree fails too.cargo clippy --locked --all-targets --all-features -- -D warningsis clean. FYI, Homebrew's clippy 1.99 flags tworedundant_closureerrors on currentmommy, insrc/daemon/status_json.rs:383andtests/inline/daemon_status_json.rs:2573. That is unrelated to this PR, but CI's "latest stable" may hit it.CLAUTH_REQUIRE_SHELL_LINT=1 cargo test --locked --all-targets --all-features: 8755 passed, 21 failed. 6 of the failures were completion tests that failed only because fish wasn't installed. With fish installed, all 51completions::tests pass. The other 15 failures are TLS and socket tests (daemon::api::terminal,daemon::api::tests,push::tests, onedaemon::bridgetest), which fail at TLS client setup. The same tests fail on commit 1, which has none of my Rust changes, so I read them as specific to this machine.rex::tests pass. They cover path resolution, the block edit (append, idempotence, hand-written require, removal, unterminated block), install and uninstall against temp dirs (foreign dir, symlink, executable bits, reinstall, round trip), andresolve-profile.shrun against a faked/procand registry (both harnesses, a row with no harness, a bare codex with and without an adopted login, and a bare claude).target/debug/clauth rex install/uninstallwithREX_CONFIGpointed at a temp dir against a real Rex server. It refused with no TTY and no--yes. With--yesit wrote the files, appended the block once, and reloaded Rex. Uninstall restoredinit.luaexactly.clauth start) and bare-claudepanes, and the label coming back when Claude exits.deploy · prodsurvives.--with-fallbacksession reportsfollows_chain: true./procpaths andstart-watch.sh's/proc/<pid>/exelookup only ran undersh -nand shellcheck. Also untested: Rex builds other than 1541 and 1584, and installing throughclauth rex installon a machine already running a hand-copied plugin (by design it refuses that as a foreign directory).resolve-profile.sh.clauth rex installshould eventually get the herdr-style heal instead of "rerun after upgrading".https://claude.ai/code/session_01S5npf9mJwNArHszhk4v1eW