Bitdoze logo

Superlogical Rex: Ghostty's Creator Rethinks the Terminal Multiplexer

Rex is Mitchell Hashimoto's terminal multiplexer: raw PTY streaming to clients, persistent sessions, SSH-style remote logins, Lua config and a scriptable CLI.

Dragos

13 min read

Superlogical Rex terminal multiplexer

Rex is the terminal multiplexer Mitchell Hashimoto has been building at Superlogical since HashiCorp and Ghostty. It is a terminal emulator and a multiplexer in one native application: you open the app, you are in a terminal, and sessions, splits and persistence are already there. As of October 5 it is in public testing (mailing-list invites, macOS first), but the docs are already public and Hashimoto has published two long walkthroughs of how it works. There is enough real material to write a proper briefing, so here it is.

The Rex macOS app: session tabs across the top, split panes running a Codex code review, a git diff TUI, and a Snake game

What Rex is

You do not run Rex inside another terminal the way tmux runs inside Kitty or Ghostty; it is the terminal. Superlogical’s pitch is “a drop-in replacement for whichever terminal you use today,” with persistent sessions, remote connections, and program activity status on top.

The vocabulary is four nouns, and they show up everywhere in the CLI and config:

  • A session is a group of work, usually one project. The server keeps it alive whether or not anything is looking at it.
  • A window is a tab inside a session. It holds a layout of blocks.
  • A block is one application in a window. Today that means a terminal.
  • A client is a program connected to the server, like the macOS app.

The server owns everything. Clients attach, render, detach. Close the app mid-build, reopen it, and you are back in the same session where you left it.

Why the architecture is different (and why it matters)

This is the part worth understanding, because it is the reason Rex exists instead of being another tmux skin.

A traditional multiplexer sits between your terminal emulator and the PTY. Terminal → tmux → shell. Every byte gets parsed twice: once by the multiplexer’s internal terminal model, once by your emulator. And historically, the terminal cores inside tmux, screen and zellij are slow next to modern emulators. Hashimoto puts it bluntly in his architecture walkthrough: Ghostty, Kitty and Alacritty are sometimes 100x faster at terminal IO than the emulator inside a multiplexer, so bolting one in front of your fast terminal gives you, in his words, “that slow experience in a fast terminal.”

Who parses the PTY stream: traditional multiplexers sit between your terminal and the shell and parse bytes twice; Rex tees raw bytes to per-client libghostty instances

Rex flips who does the parsing:

  1. The server owns the PTY. When a client connects, the server pauses PTY processing for a moment and sends a custom binary frame carrying just enough state (dimensions, cursor, current screen) for the client to render. Then a ready frame: you can type, select and scroll while everything else loads.
  2. Raw bytes, not screen diffs. Instead of tracking a shared screen model and shipping diffs, the server tees raw PTY bytes to every client, like SSH. Each client runs libghostty and parses independently. If the server ever parses slowly, your client does not care.
  3. Scrollback streams in behind. Newest chunk first, with a loading state while history backfills. And because the client owns its viewport, two attached clients can scroll the same session independently, which fixes the famous tmux behavior where one person scrolling moves everyone’s screen.

Two consequences worth knowing:

  • No in-window multiplexing. Each split is its own PTY connection rendered as a native tab, split or window. That is what makes iOS and browser clients possible, and it is why a tmux-style pane tree is not the model. A legacy compatibility mode for dumb terminals (a libghostty layer in the middle, the same tradeoff tmux makes but with a faster core) is still being discussed.
  • Input stays centralized. Keystrokes serialize through the server, one writer and many readers, so the authoritative state never forks even if a client drifts out of sync. A drifted client just re-runs the handshake.

Since the client is the terminal emulator, feature support follows libghostty. The Kitty graphics protocol gap that tmux never closed is the kind of thing that lands much faster here, because Superlogical ships the terminal engine.

Remote hosts: quietly an SSH replacement

The second demo is the one that made me sit up. Rex is not just local persistence. From the command palette you add a remote host (Hashimoto demos against a VPS on his tailnet), and what opens looks like SSH but is not SSH:

  • It does a real system login. The session shows up in who, your login shell loads, per-user limits are honored. Hashimoto says he does not run SSH on that machine at all; Rex is how he gets in, including as root. A server-side mapping controls which identities can act as which users, and existing SSH keys are respected.
  • rex whoami reports the identity chain. In the demo it shows he connected as mitchellh via his Tailscale identity across a couple of hops. Remote auth rides on network identity you already have.
  • It feels local. He describes borrowing architectural ideas from Mosh for responsiveness, without claiming full Mosh parity. Killing a remote session via rex session kill propagates before you can reopen the app.
  • Everything local works remote. The Cmd+Shift+G go-to-directory jump works on remote hosts too. “Everything that works local should work remote” is a stated design rule.

Local sessions need no remote anything. Remote hosts are for when you want the same persistence on a VPS.

The rex CLI is the control surface

Every terminal Rex opens gets rex on its PATH automatically, plus three environment variables that tell the CLI where it is:

Variable Holds
REX_SESSION ID of the session the terminal belongs to
REX_BLOCK ID of the terminal’s own block
REX_SERVER Address of the server running the terminal

So rex split inside a pane splits that pane. To act somewhere else, target with -s (session), -w (window), -b (block), -C (client) or -S (server). Targets resolve in a fixed order: full ID, then label, then position, then a 4+ character ID suffix. An ambiguous target changes nothing: it lists the matches and exits with status 3.

bash
rex ls                              # list sessions
rex session inspect                 # details of the session you're in
rex send -s build -w 2 'make test'  # type into window 2 of the "build" session
rex capture -b logs                 # print the screen of the block labeled "logs"
rex -S studio ls                    # sessions on the host labeled "studio"

Most commands take --json (stable output with full IDs, made for scripts) and return meaningful exit codes: 0 ok, 1 failed, 2 bad command line, 3 target missing or ambiguous, 4 server unreachable, 130 interrupted. rex wait and rex run --wait adopt the wrapped program’s exit status, so scripts compose cleanly. This is the same “everything is automatable” philosophy as cmux, taken further.

Configuration is Lua, and custom actions are real

Config lives in one file: ~/.config/rex/init.lua on macOS and Linux, %AppData%\rex\init.lua on Windows, REX_CONFIG overrides both. Rex needs no config at all, and require lets you split a big one into files.

lua
rex.bind("cmd+d", "pane.split", { direction = "right" })
rex.bind("ctrl+b>c", "window.new")  -- tmux-style prefix chords work

Two details the docs make clear that are easy to miss: the server reads the file, so rex config reload must run on the server machine and is refused over a remote connection. And there is no file watching; reload is manual. rex config check validates a file without applying it, a bad rex.* call is skipped with an error while the rest of the file still loads, and a hard Lua syntax error keeps the last good config.

Custom actions are named Lua functions defined with rex.action. Once defined they behave like built-ins: bindable to keys, searchable in the command palette, runnable from the CLI with rex do:

lua
rex.action{
  name  = "scratch",
  title = "Open Scratch Window",
  run   = function(ctx, args)
    rex.session.new_window{
      layout = rex.layout.block{
        flavor = "com.superlogical.terminal.shell",
      },
    }
  end,
}
rex.bind("shift+cmd+n", "scratch")

Actions take typed args (or a full JSON Schema as a Lua table), receive a ctx (session_id, block_id, client_id, origin), call other actions through rex.invoke, and queue client-side actions with rex.client.queue. Two gates to know: the app only accepts actions from the CLI when Remote Control is on in settings, and rex do ~/.config/rex/init.lua --action scratch runs an action from a file against the live session without touching the running config. That last one is the fast iteration loop.

Where you can run it, and what it costs

  • macOS app first. It self-hosts a Rex server locally and connects to other Rex servers, so Mac-to-Mac remoting already works.
  • Other platforms are built, not shipped. Rex servers run on Linux and Windows internally, and iOS, Linux and Windows clients exist at “varying stages of readiness.”
  • Free, no account, self-hostable. Superlogical: “Rex is and will always be free,” clients and servers “are not going to be directly monetized,” no data sharing. The commercialization plan is promised before the stable release.
  • Access via the mailing list. Invites go out in waves; about 50 people ran the private test for months, and the team wants to clear the whole list in under a month.

To get a seat, join the mailing list on the announcement page. The docs are public and worth reading even without access; the CLI and Lua reference tell you most of what the product is.

Rex vs tmux vs Herdr

Rex tmux / zellij Herdr
What it is Terminal app + multiplexer Multiplexer inside your terminal Agent control plane
How it renders Native tabs/splits, per-client libghostty Internal screen model diffed to your terminal TUI over a session server
Remote story Built-in remoting, real system login, Mosh-style responsiveness SSH in, then attach SSH attach, web/mobile clients
Config Lua (init.lua) tmux.conf / KDL ~/.config/herdr
Scripting rex CLI, Lua actions, --json CLI + shell scripts Socket API + CLI
Status New, macOS only Everywhere, decades mature Open source, active

Honest framing: these are different tools solving different problems. tmux is the incumbent with decades of muscle memory behind it. Rex bets that the multiplexer should be the terminal. Herdr is not a terminal at all, it is a control plane for AI coding agents (agent-state sidebar, socket API, marketplace plugins). If agents are your actual problem, start with my Herdr review and the guides to the best Herdr clients and best Herdr plugins. If terminal ergonomics are the problem, Rex is the most interesting thing in this space since zellij.

Rough edges to know about

  • macOS only for now. No workaround, no sideload; the Linux and Windows pieces exist but aren’t in testers’ hands yet.
  • The tmux workflow does not port 1:1. No in-window pane tree; splits are separate connections in native containers. Prefix chords like ctrl+b>c work in rex.bind, your .tmux.conf does not.
  • Config reload is manual. No file watching yet; rex config reload on the server machine only.
  • The SSH replacement is real but early. Demos show full logins and SSH-key respect, but the server-side identity mapping is not yet documented in depth.
  • Feature surface follows libghostty. Fast adoption of terminal features, but the server still gates what a session can do.

FAQ

Is Rex free?

Yes. Superlogical says “Rex is and will always be free,” no account required, servers fully self-hostable, and they don’t see or share your data. Whatever the eventual commercialization is, they have committed it will not be the client or server itself.

Can I run Rex on Linux or Windows today?

Not yet. The shipping client is the macOS app. Rex servers already run on Linux and Windows internally, and iOS, Linux and Windows clients exist at varying readiness, but none are available to testers yet.

Does Rex replace tmux?

It replaces the job tmux does (persistence, sessions, splits, remote attach) with a different model: raw PTY bytes to per-client terminal emulators instead of one shared screen model. What you lose is in-window pane nesting and decades of ecosystem plugins. What you gain is per-client scrollback, native UI, first-class remoting, and a scriptable Lua and CLI surface. Our tmux basics guide shows what the incumbent workflow looks like.

Does Rex work with my Ghostty config or theme?

Not documented yet. Rex is built on libghostty and demos show Ghostty-style theme handling, so expect familiarity rather than a config import path today.

The short version

Rex is Mitchell Hashimoto arguing that a terminal multiplexer should not emulate a terminal in the middle of your terminal. The client parses, the server streams, sessions persist, remotes log in for real, and the whole thing is scriptable in Lua. It is macOS-only for now, but the docs are public and the architecture is genuinely different rather than a reskin. Join the mailing list if you want in.

Also worth a look: my Ghostty setup guide (the same engine sits under Rex’s hood) and the cmux guide, another libghostty-based terminal with an automation CLI that is already out for macOS.