Rmux is a Rust terminal multiplexer with a typed async SDK that treats pane output the way Playwright treats the DOM: structured, queryable, and awaitable. For teams running Claude Code, Codex, or aider over persistent SSH sessions, it targets something tmux 3.6a has never provided, a first-class automation surface above the byte-stream level. The repo first appeared May 15, 2026; as of v0.7.0 (June 25, 2026) it has shipped seven minor releases and official SDKs in three languages [Updated June 2026].
The Automation Gap tmux Never Filled
tmux’s automation story is send-keys and capture-pane. You write text into a session, read back raw bytes, and sleep until you think the command has finished. Agents running on top of this pattern spend a lot of time grep-and-retrying against unstructured output. It works until a prompt changes format, a command takes longer than expected, or a pane scrolls past the capture buffer. Teams have been patching these cases with brittle shell wrappers for two years.
Rmux, created May 15 by GitHub user shideneyu under the Helvesec org, frames this as the problem worth solving. v0.3.0 shipped May 23, eight days after the repo appeared, two days after its Show HN debut, dual-licensed MIT/Apache-2.0, with 90 tmux-compatible CLI commands implemented. The cadence has not slowed: v0.4.x added browser-based session sharing, v0.5.0 stabilized the window-creation APIs, and v0.6.0 (June 17) shipped the first official non-Rust SDK [Updated June 2026].
The SDK: Playwright Primitives for Terminal Sessions
The rmux-sdk crate is where the interesting engineering lives. The public API surface has three primitives that don’t exist in tmux:
connect_or_start() is an idempotent session bootstrap. The EnsureSessionPolicy::CreateOrReuse enum variant handles the case where your automation script runs twice, which is the normal case for any coding agent operating in a retry loop.
pane.wait_for_text() is an async locator-style wait. Instead of sleep 5 && tmux capture-pane, you await a condition on pane output. The direct analogue is Playwright’s page.waitForSelector().
PaneSnapshot objects expose the pane’s cell grid with cols, rows, and per-cell data. A downstream consumer can parse specific screen regions without writing a terminal emulator.
The “Playwright for terminals” framing comes from the project itself, not from independent characterization. Worth noting given the project is ten days old. The primitives are real, though, and the analogy is accurate at the API level.
tmux Compatibility: 90 Commands and Config Migration
According to the GitHub repository, rmux implements 90 tmux-compatible CLI commands. .tmux.conf keybinding and core option carryover is supported, which matters for teams with existing config. The intent is drop-in CLI replacement.
The compatibility story has a clear gap: no Lua scripting parity. tmux’s plugin ecosystem, tpm, tmuxinator, and the long tail of shell wrappers that assume tmux in $PATH, doesn’t port automatically. Teams with deep tmux config customization should treat migration as non-trivial.
Architecture: Single Daemon, Three Surfaces
The workspace is 13 crates split into public surfaces and support crates: CLI, SDK (rmux-sdk), Ratatui widget (ratatui-rmux), types, and the IPC protocol crate (rmux-proto). The support layer covers PTY handling, the core multiplexer, the daemon server, and the client.
The ratatui-rmux companion crate embeds live pane snapshots as Ratatui widgets, which opens a use case tmux doesn’t address: building TUI dashboards that embed live terminal output as a first-class widget rather than scraping it from a separate pane.
IPC uses Unix sockets on Linux/macOS. On Windows, per-user Named Pipes.
Windows via ConPTY: The Cross-Platform Bet
tmux 3.6a has no Windows-native support. Running tmux on Windows means WSL, which adds a virtualization layer, a separate filesystem tree, and network namespace complications that matter when attaching an agent to a Windows development environment.
Rmux’s Windows implementation uses ConPTY, the Windows Console Pseudoterminal API, with no WSL dependency. IPC uses Named Pipes rather than Unix sockets, but the SDK API is identical across platforms. For teams running agent workflows on Windows CI, this is a practical distinction. Zellij also lacks native Windows support; screen predates the question.
Practical Patterns
The idempotent connect_or_start() + EnsureSessionPolicy::CreateOrReuse pair means session bootstrap can be called on every agent loop iteration without spawning duplicate sessions. Combined with pane.wait_for_text(), the run-wait-read pattern becomes deterministic rather than timer-based, which is the difference between an agent that handles the common case and one that also survives the rare timing failure when a build takes thirty seconds longer than the sleep allowed for.
For TUI dashboard embedding, ratatui-rmux renders live agent session panes alongside status panels without shell gymnastics. For CI pipelines that need to drive interactive TUI tools (test runners, database CLIs), typed pane snapshots with wait_for_text() are a cleaner abstraction than expect scripts and substantially more debuggable when they break.
What the Locator Model Buys You Over capture-pane
capture-pane hands you a rectangle of text and a return code. Whitespace, cursor position, and color attributes are flattened into a string or discarded depending on which flags you pass. An agent reading that output is doing the terminal emulator’s job inside its own prompt: reconstructing where the cursor sits, whether a full-screen TUI just redrew a region, whether the shell prompt has actually returned. PaneSnapshot keeps the cell grid intact instead. Each cell carries its glyph and its coordinates, so a wait_for_text() call can scope its match to a row range or a column band rather than grepping the whole scrollback. The concrete payoff is that a wait can resolve on a status line at the bottom of a htop or lazygit view without false-matching the same string scrolling past in the log above it.
The deeper difference is event versus poll. send-keys plus capture-pane is a polling loop by construction: write, sleep, read, decide whether to read again. Every layer that wraps that pattern inherits the loop. rmux’s async wait is designed to settle when the condition is met rather than when a timer fires, which removes the two failure modes that dominate sleep-and-grep automation: reading too early and capturing a half-drawn screen, or sleeping too long and burning wall-clock time on every step of a multi-hundred-step agent run. Whether the daemon delivers that cleanly under concurrent sessions is exactly the part six weeks of releases has not yet proven.
Rmux Versus Wrapping tmux in an MCP Server
The obvious alternative for an LLM agent is not to replace tmux at all but to expose it through a protocol the model already speaks. A small ecosystem of tmux-MCP servers now does exactly this: they register tools like create-session, send-keys, and capture-pane, and the model calls them as functions. This is the lowest-friction path because it leaves the battle-tested tmux daemon untouched and adds only a thin protocol shim. It is also where the byte-stream problem reappears one layer up. An MCP capture-pane tool returns the same flattened text, so the model still has to reason about whether a command finished, and it pays a full tool-call round trip for every poll. The structure rmux adds below the agent is structure an MCP wrapper cannot add above tmux without reimplementing a terminal emulator inside the server.
That tension connects to a recurring question in agent tooling: whether the right interface is the raw artifact or a typed projection of it. The same choice shows up in GUI automation, where the debate is between feeding a model screenshots and giving it a structured CLI to act against. rmux is the terminal-side answer that says give the agent typed state, not pixels or raw bytes. It also fits where coding harnesses are heading, with background agent sessions becoming first-class managed objects rather than detached processes a human babysits. A multiplexer whose sessions are addressable and awaitable from the agent’s own language is a natural substrate for that, assuming the daemon earns the trust the API design is asking for.
One caveat worth stating plainly: none of this helps if your agents already run inside a sandbox that hands them a fresh shell per task. The automation surface rmux sells is most valuable for long-lived, stateful sessions over SSH, the case where capture-pane scraping actually hurts and where benchmarks like Terminal-Bench increasingly test whether an agent can finish multi-step work without losing the thread. For ephemeral, stateless command execution, the typed SDK is overhead you do not need, and tmux or a bare PTY is the simpler choice.
Where It Breaks: Maturity Assessment
The maturity risks are specific, and a month of releases has sharpened rather than erased them [Updated June 2026]. The project is now roughly six weeks old, not ten days, and the original README line that “bugs are expected” has been dropped as the docs filled out. The honest signal moved to the package metadata: librmux is still classified Development Status :: 3 - Alpha on PyPI, and the TypeScript SDK explicitly tracks “RMUX 0.6.x” while the daemon has already moved to 0.7.0. The daemon’s memory footprint at idle remains undocumented, which matters for teams running persistent agent sessions on constrained hardware. The release cadence (v0.3.0 May 23 through v0.7.0 June 25, with web-sharing and SDK surfaces added along the way) is fast enough that “rapid iteration” and “instability” are still hard to distinguish from the outside, and every new public surface is a new API that has not yet earned a stable contract.
The dev.to review from May 21 is the most substantive independent write-up available, and it’s enthusiast-written, not adversarial. The comparison table it contains, rmux vs tmux vs Zellij vs WezTerm mux vs screen, is the reviewer’s analysis, not vendor documentation. Treat it as directionally useful, not authoritative.
Competitive Landscape
| Multiplexer | Typed SDK | Windows Native | Async Pane Waits | Status |
|---|---|---|---|---|
| rmux v0.7.0 | Yes (Rust, Python, TS) | Yes (ConPTY) | Yes | Active, pre-1.0, ~6 weeks old |
| tmux 3.6a | No | No | No | Active, stable |
| Zellij | No | No | No | Active |
| WezTerm (mux) | Lua scripting | Yes | No | Active |
| screen | No | No | No | Maintenance |
Sources: rmux GitHub and rmux.io; tmux, Zellij, WezTerm, and screen columns from the dev.to reviewer’s analysis, not vendor documentation. The rmux Typed SDK row now spans three languages [Updated June 2026].
WezTerm’s mux mode is the closest prior art: Lua scripting, native Windows support, active development. The architectural difference is that WezTerm is a terminal emulator with multiplexing as a feature; rmux is a multiplexer designed from the start as an automation substrate. The earlier open question (whether rmux-sdk would mature into something Python and Node agents can call) has been answered: it has, in the form of librmux and @rmux/sdk, so the comparison is no longer Rust-binding versus Lua-scripting but typed-SDK-from-your-agent’s-language versus an embedded scripting runtime [Updated June 2026].
The Opportunity Cost of Staying on tmux
The session persistence problem tmux solved over a decade ago is not what breaks long-running agent sessions today. The bottleneck is the interaction layer between the agent and the terminal: detecting when a command finishes, parsing structured output, handling retries without race conditions. Teams have been solving this with brittle expect scripts and sleep-and-grep loops because there was no better abstraction.
Rmux’s SDK is a bet that the abstraction belongs in the multiplexer, not in the agent’s outer loop. One leg of that bet has already paid off [Updated June 2026]: the Python and Node SDKs followed within a month, so the cost of staying on tmux for automation-heavy workflows now rises for the most common agent stacks, not because tmux breaks, but because the alternative has a type system in the language you already write the agent in.
Whether a six-week-old, pre-1.0 project with an undocumented daemon footprint is the right foundation for production agent sessions today is a separate question. The architectural bet is sound, and the SDK-coverage bet has landed. The stability bet is the one still open.
Frequently Asked Questions
How does pane.wait_for_text() differ technically from expect or pexpect?
expect, written by Don Libes in 1990, matches regex patterns against a flat byte stream from a single PTY. It has no concept of panes, window layouts, or session multiplexing. rmux’s wait_for_text operates on typed PaneSnapshot objects that expose per-cell grid data with column and row coordinates, so you can wait for a condition in a specific screen region while ignoring output elsewhere. expect scripts also have no idempotent session bootstrap; every run assumes the terminal state is unknown.
What breaks when migrating from tmux if the team relies on tpm or tmuxinator?
tpm (Tmux Plugin Manager) hooks into tmux’s internal sourcing protocol to load plugins at session start, and tmuxinator generates full tmux command sequences from YAML project definitions. The 90 compatible CLI commands in rmux cover interactive usage, but neither tpm’s plugin loading infrastructure nor tmuxinator’s code generation target anything other than the tmux binary. Teams depending on either would need to rewrite session bootstrapping against rmux-sdk directly or run both multiplexers during a transition period.
What happens to running sessions if the rmux daemon process crashes?
rmux uses a single-daemon architecture with IPC (Unix sockets on Unix, Named Pipes on Windows), so a daemon crash would lose all session state and attached PTYs. tmux has the same architectural risk but has accumulated over fifteen years of crash hardening and signal handling across thousands of production deployments. rmux is roughly six weeks old, its idle memory footprint is still undocumented, and its Python SDK carries an alpha classifier on PyPI [Updated June 2026]. v0.3.1 added daemon-upgrade safety so an in-place binary update no longer forces every session to die, which is the right kind of hardening to see early, but the daemon stability question remains the blocker for production use, not the SDK API design.
Can Python-based agents use rmux-sdk today without writing Rust?
Yes, as of June 2026 [Updated June 2026]. The Python SDK librmux shipped with v0.6.0 on June 17 and installs from PyPI (pip install librmux); a TypeScript/Node SDK, @rmux/sdk, is on npm. Both are first-party packages from the Helvesec org rather than community FFI wrappers, and both speak the same rmux-proto wire protocol the Rust crate uses, so you no longer need PyO3 bindings or a hand-rolled socket client to drive a session from Python or Node. The one caveat is version skew: the published SDKs track the 0.6.x protocol, and the daemon has already moved to 0.7.0, so pin the daemon and the SDK to compatible releases until the project reaches 1.0 and the wire contract stabilizes.