TL;DR — cmux is two programs sharing one name: a macOS terminal app built on libghostty that behaves like a dashboard for coding agents, and a separate Rust TUI published on npm as cmux that is a genuine tmux-style multiplexer with a Ctrl+b prefix and attach/detach. tmux is the portable server both can lean on: the cmux app can mirror a remote tmux server into its sidebar, and it can use a local tmux server to keep sessions alive when the app quits. Choose tmux for ubiquity, portability, and text-protocol automation. Choose cmux when the terminal itself should surface agent state, notifications, and a browser.
| tmux 3.8 | cmux 0.65.2.2 | |
|---|---|---|
| First release | 2007 | 2025 (0.1.0 in January) |
| Implementation | C, libevent and ncurses | Swift and AppKit with libghostty; a separate TUI in Rust |
| License | ISC | GPL-3.0-or-later for the app; Business Source License 1.1 for server components; npm TUI package declares MIT; optional paid plans |
| Design centre | Any terminal workload, on any Unix | A macOS terminal for AI coding agents |
| Object model | Sessions → windows → panes | Windows → workspaces → panes (splits) → surfaces (tabs); the TUI uses sessions → workspaces → screens → panes → tabs |
| Configuration | ~/.tmux.conf, a command language | ~/.config/cmux/cmux.json plus Ghostty config; TUI uses cmux-tui.json |
| Default prefix | Ctrl+b | None in the app (⌘ chords); Ctrl+b in the TUI |
| Mouse | On by default (set -g mouse off) | Mouse-first GUI; the TUI accepts clicks and right-click menus |
| Agent state | Primitives only: OSC 133 events, pane commands, hooks | Hooks, lifecycle states, sidebar glyphs, and an input-state check before automation types |
| Automation | Shell commands, formats, hooks, text control mode | JSON CLI over a local control socket, cmux events stream, --json on most commands |
| Remote hosts | SSH, then attach to the server there | cmux ssh workspaces, ssh-tmux mirroring (beta), mosh-tmux, cloud VMs |
| Browser | None | Built-in browser pane with a Playwright-style automation REPL |
| Extensibility | TPM plugins, hooks, formats, shell scripts | cmux.json commands, skills, socket API, TUI plugins |
| Platforms | BSD, Linux, macOS, Solaris; Windows via WSL | App: macOS, iOS. TUI: macOS and Linux, Windows planned |
| Restore after reboot | Not native; add tmux-resurrect/continuum | Layout, cwd, best-effort scrollback, and supported agent resumes; processes do not survive |
The first thing to get right is that the cmux repository ships more than one front end, and they behave very differently.
cmux. It keeps a tree of machines, sessions, workspaces, screens, panes and tabs, and it speaks a documented JSON protocol over a Unix socket.Only the second is a multiplexer in the tmux sense. The GUI app has no detach key and no attach command: it is the terminal or it is not running. If you ask "can cmux replace tmux on my server?", the answer is the TUI, not the app — and the TUI is much younger than tmux.
tmux is a client/server system. A long-lived server owns the pseudo-terminals, session state, and layout; clients draw that state and can come and go. The server is native C, has no GUI dependency, and can be reached over a Unix socket, including through tmux -CC control mode.
The cmux app is a GUI process that owns the PTYs and renders them with libghostty. Automation talks to the running app over a local control socket with a trust mode you choose: cmuxOnly accepts only processes started inside a cmux terminal, password requires a secret, and allowAll is explicitly labelled unsafe. There is no separate local session daemon to attach to.
cmux-tui restores the server/client split. cmux server start --session agents runs a headless owner, cmux attach --session agents opens a client, and the server keeps running when the client detaches. The docs keep the durable owner separate from the client, and note that server stop also tears down the owner and its workspaces.
This is where the marketing descriptions diverge most from daily use, so it is worth separating three different promises.
| tmux 3.8 | cmux app 0.65.2.2 | cmux-tui | |
|---|---|---|---|
| SSH connection drops | Server keeps running | Auto-reconnects with backoff | Server keeps running |
| Client quits or detaches | Everything survives | Processes die with the app | Everything survives |
| Machine reboots | Nothing restores without a plugin | Layout, cwd, scrollback and agent sessions restore | Topology is saved; processes are not |
| Live processes across an app update | Restart the server and lose panes | Opt in to cmux local-tmux | Restart the owner and lose panes |
The app's session restore is real but bounded. It writes a versioned snapshot, rebuilds windows, workspaces, panes and working directories, reopens browser tabs, restores scrollback on a best-effort basis, and resumes supported agents through their native resume commands. It does not checkpoint arbitrary live process state: ordinary shells, vim, and tmux itself reopen as new terminals.
For live detach/reattach, the app delegates to tmux rather than reimplementing it:
# cmux: a tmux server owns the shell, cmux owns only the client surface
cmux local-tmux start work --cwd ~/src/project --command 'npm run dev'
cmux local-tmux list
cmux local-tmux detach work
cmux local-tmux attach workThe app's own docs are candid about the limits: the owner survives quitting, crashing, or updating cmux, and normally survives sleep, but not logout, restart, shutdown, or power loss. That is not a defect unique to cmux — it is the same boundary tmux has — but it means "cmux keeps my sessions alive" is only true when tmux is installed and this opt-in profile is used.
The TUI is closer to tmux out of the box. A plain cmux run starts or reuses a detached owner and attaches to it, so detaching (Ctrl+b d) never ends the session.
tmux's hierarchy is sessions, windows, and panes, and every navigation action goes through the prefix. cmux keeps the same ideas but renames two levels and moves most navigation to the mouse or to ⌘ chords.
| Concept | tmux 3.8 | cmux app | cmux-tui |
|---|---|---|---|
| Top container | Session | Window (app instance) | Session (one socket) |
| Project container | Window (named) | Workspace | Workspace |
| Layout container | Window layout | Pane | Screen |
| View container | Pane | Surface / tab | Tab |
| New view | Ctrl+b c | ⌘+T | Ctrl+b c or t |
| Split | Ctrl+b % / " | ⌘+D / ⌘+⇧+D | Ctrl+b % / " |
| Focus pane | Ctrl+b o or arrows | ⌥+⌘ arrows | Ctrl+b o or h/j/k/l |
| Jump between views | Ctrl+b w (choose-tree) | ⌃+1–9 (surfaces), ⌘+1–9 (workspaces) | Ctrl+b 0–9 |
| Detach | Ctrl+b d | No equivalent | Ctrl+b d |
One naming trap: a cmux pane is the split region, and surfaces (tabs) live inside it. new-split creates a pane; new-surface adds a tab to one.
The TUI deliberately matches tmux for the shared verbs: c, n, p, &, ,, z, o, {, }, and number keys all mean what they mean in tmux, and pressing the prefix twice sends a literal Ctrl+b. Two differences bite anyway: Ctrl+b x closes a tab while Ctrl+b X closes the pane, and Ctrl+b w selects the next workspace instead of opening a picker. The TUI also has no paste buffers, so Ctrl+b ] is unbound.
The app has no prefix at all. Its own actions are ⌘ chords, and terminal-level keybindings come from your Ghostty config, including leader sequences. That means muscle memory from tmux works only inside the terminal programs, not for window management.
tmux treats every pane as an opaque terminal. It exposes strong primitives — #{pane_current_command}, pane titles, capture-pane, hooks, and, in 3.8, OSC 133 events for command start and finish plus wait-for -E — but nothing in tmux knows that the thing in pane 2 is waiting for approval. You build that state machine yourself.
cmux ships the state machine and exposes it to scripts. Agent hooks capture native session IDs and report lifecycle. The sidebar summarizes each workspace with a single glyph whose states include running, needs input, waiting on a background command, working through subagents, idle, and error. Notifications arrive through standard OSC 9/99/777 sequences or cmux notify, and show as pane rings, a notification panel, and macOS banners.
The most tmux-unlike piece is the input-state check. Before typing, cmux send asks the app whether the surface is empty, holds a human's draft, has a dialog open, or is unknown (the reported state names), and refuses to type over a draft or an open permission prompt:
# tmux: the send always lands, whoever was typing
tmux send-keys -t agents:0.1 'fix the failing test' Enter
# cmux: refused when a person is mid-draft or a dialog is open
cmux send 'fix the failing test'
cmux send-key enterThe same information is available to your own programs through surface.input_state, which returns the input state together with the agent's lifecycle (unknown, running, idle, or needsInput) and a blocks_typing flag, alongside the workspace status lanes used by the sidebar: todo, working, needs-attention, review, and done.
Prior art check: if you only want blocked/working state from a terminal tool, herdr classifies panes directly. cmux's version is app-level and broader — notifications, browser, and resume — but macOS-bound.
tmux automation is a text protocol with two decades of scripts behind it. Commands return text, formats such as #{session_name} form a small query language, and control mode (tmux -C) frames replies with %begin, %end, and %error while streaming notifications.
cmux automation is JSON-first. The CLI is a thin client over a documented socket API, selectors accept typed IDs, and cmux rpc calls a raw method when no wrapper exists. cmux capabilities reports what the server supports, and cmux events streams newline-delimited JSON instead of %output blocks.
| Task | tmux 3.8 | cmux app 0.65.2.2 |
|---|---|---|
| Run a command in a pane | send-keys -t … 'cmd' Enter | cmux send 'cmd', cmux send-key enter |
| Read the screen | capture-pane -p -t … | cmux read-screen --surface … |
| Split a pane | split-window -h/-v | cmux new-split right |
| Machine-readable output | Formats and control-mode text | --json on most commands |
| Event stream | Control-mode notifications, hooks, monitors | cmux events as NDJSON |
| Schema discovery | Manual page | cmux capabilities, cmux rpc, cmux guide |
| Guarded input | None | Refuses to type over drafts and dialogs |
cmux-tui has its own noun-first CLI (cmux workspace create, cmux terminal … screen read, cmux session current events --jsonl) and returns opaque typed IDs rather than tmux's index-plus-name addressing. If your existing tooling parses tmux formats, porting is real work; if you are writing new orchestration, the JSON surface is easier to consume.
tmux's remote story is SSH plus attach. The server lives on the host, you connect, attach, and detach. It assumes nothing and works on machines where you cannot install anything else.
cmux has three remote modes, and one of them is explicitly a tmux client:
cmux ssh user@host opens a workspace whose terminals run on the remote machine; browser panes route through the remote network, and dragging an image uploads it with scp.cmux ssh-tmux user@host mirrors that host's tmux sessions into the sidebar: each tmux session becomes a workspace, each tmux window becomes a tab, and multi-pane windows become in-tab splits. It is a real control-mode client — a plain ssh … tmux -CC attach behind the scenes — so tmux remains authoritative for layout, and splits you make in cmux are translated back into split-window calls.cmux mosh-tmux attaches a named tmux session over Mosh for network roaming.Remote tmux is a beta feature, off by default, and requires tmux 3.2 or newer on the host. That requirement is the clean dividing line: cmux does not replace remote tmux, it consumes it. The TUI takes a different route, using SSH to start a matching cmux-tui owner on the remote host and reconnecting without nesting a second TUI.
tmux is ISC-licensed, available from the package manager of essentially every Unix-like system, part of the OpenBSD base system, and runs on FreeBSD, NetBSD, Linux, macOS, and Solaris, with WSL on Windows. It needs no account, no cloud, and no companion service.
cmux is GPL-3.0-or-later, with the server directories under the Business Source License 1.1, which requires a commercial license for production self-hosting. One inconsistency to watch: the root license says each directory keeps its own terms, and the npm-distributed TUI package declares MIT in its manifest, so check the component you actually redistribute. The app itself is free, and optional paid tiers cover cloud machines, team features, and early access. That matters if you plan to embed, redistribute, or self-host the server side — ISC gives you options GPL does not.
Platform support is narrower: the app targets macOS, with an iOS beta. The TUI runs on macOS and Linux, with Windows planned, and it is the part you can actually run on a server today. The app adds cloud VMs and a skills collection, but those are ecosystem breadth rather than multiplexer features.
Both are fast native programs. tmux renders text and SIXEL graphics; the app renders through libghostty and puts a real browser next to your terminal. That browser, not the rendering engine, is the feature tmux has no answer for.
| Task | tmux 3.8 | cmux app | cmux-tui |
|---|---|---|---|
| Start | tmux | Launch the app, ⌘+N | cmux |
| Named session | tmux new -s work | Workspaces, not sessions | cmux --session work |
| Detach | Ctrl+b d | No equivalent; use cmux local-tmux | Ctrl+b d |
| New window or tab | Ctrl+b c | ⌘+T | Ctrl+b t (tab), c (screen) |
| Split right / down | Ctrl+b % / " | ⌘+D / ⌘+⇧+D | Ctrl+b % / " |
| Close pane | Ctrl+b x | ⌘+W closes the tab | Ctrl+b X (pane), x (tab) |
| Zoom | Ctrl+b z | ⌘+⇧+↩ (toggle pane zoom) | Ctrl+b z |
| Send input | tmux send-keys -t … | cmux send … | cmux workspace current run -- … |
| Read output | tmux capture-pane -p | cmux read-screen | cmux terminal <id> screen read |
| Config | ~/.tmux.conf | ~/.config/cmux/cmux.json | ~/.config/cmux/cmux-tui.json |
ssh-tmux.npx cmux before committing.cmux local-tmux for live local persistence and cmux ssh-tmux for remote sessions make tmux the substrate rather than the competition. The migration table above is only relevant if you plan to remove tmux, which cmux does not require.