Rmux is a 10-day-old 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 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 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 95% of cases and one that handles the other 5%.
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.
Where It Breaks: Maturity Assessment
The maturity risks are specific. The project is 10 days old. The README states explicitly that “bugs are expected”. The daemon’s memory footprint at idle is undocumented, which matters for teams running persistent agent sessions on constrained hardware. The release cadence, v0.2.0 May 18, v0.3.0 May 23, is fast enough that “rapid iteration” and “instability” are hard to distinguish from the outside.
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.3.0 | Yes (Rust) | Yes (ConPTY) | Yes | Active, 10 days 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; tmux, Zellij, WezTerm, and screen columns from the dev.to reviewer’s analysis, not vendor documentation.
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. Whether that distinction matters depends on whether rmux-sdk matures into something Python and Node agents can call.
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. If the project matures and Python/Node SDKs follow, the cost of staying on tmux for automation-heavy workflows rises, not because tmux breaks, but because the alternative now has a type system.
Whether a 10-day-old project with stated bugs and an undocumented daemon footprint is the right foundation for production agent sessions today is a separate question. The architectural bet is sound. The timing of the bet is early.
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 has existed for ten days, its idle memory footprint is undocumented, and the README explicitly warns that bugs are expected. The daemon stability question is the blocker for production use, not the SDK API design.
Can Python-based agents use rmux-sdk today without writing Rust?
No. The rmux-proto crate publishes the IPC data transfer objects publicly, which documents the wire protocol for third-party implementations, but no Python or Node client library has been published as of v0.3.0. A team wanting Python access today would need to either write FFI bindings against the Rust crate using PyO3 or implement a native client that speaks the rmux-proto protocol over Unix sockets or Named Pipes. Both are non-trivial engineering efforts, and until one ships, the SDK story is Rust-only in practice.