#Remote tmux
Remote tmux mirrors a tmux session running on a remote machine into coterm over SSH, using tmux control mode (tmux -CC). Instead of a plain SSH terminal, the remote session is reprojected into coterm's native UI — workspaces, tabs, splits, scrollback, and copy — and coterm drives the real tmux server behind it. It is a Beta Features flag and does not change local terminals.
#How tmux maps to coterm
coterm and tmux nest their layouts in opposite directions. In coterm, a pane holds a row of tabs (each tab is one terminal). In tmux, a window holds a split of panes. Remote tmux bridges the two by projecting tmux's structure onto coterm's:
| tmux | coterm |
|---|---|
session | A dedicated workspace in the sidebar. |
window | A tab in that workspace. |
pane | A pane in a native split inside that tab. |
The new capability is panes inside a tab: a coterm tab used to hold a single terminal, but a tmux window with several panes is now rendered as a real coterm split layout within one tab — each remote pane is a native coterm terminal pane with the usual chrome. The bridge is two-way: splitting or closing a pane in that tab runs tmux split-window, and reordering the tabs reorders the tmux windows with swap-window.
#Requirements
A reachable SSH host (coterm reads your ~/.ssh/config) with tmux 3.2 or newer installed. Control mode (tmux -CC) is a standard tmux feature, so no special build is needed; coterm checks the remote tmux version before attaching and fails clearly on older servers. coterm attaches over an SSH ControlMaster connection, and the remote tmux server keeps running when you detach.
#Enable it
Open Settings → Beta Features and turn on Remote tmux. The toggle is off by default, so nothing changes for local terminals until you opt in.
#Attaching
Run coterm ssh-tmux <destination> in a terminal — an ~/.ssh/config alias or user@host. coterm opens a new window that mirrors that host's tmux sessions: each session becomes a workspace, each window a tab, and multi-pane windows become in-tab splits.
Hosts that authenticate non-interactively (ssh-agent, or a key in ~/.ssh/config) attach with no prompt. If the host needs interactive authentication (a password, host-key confirmation, or MFA), coterm runs ssh inline in your terminal so you can authenticate, then opens the mirror window. Accepts --port and --identity.
coterm ssh-tmux dev@example.com
coterm ssh-tmux my-ssh-alias --port 2222 --identity ~/.ssh/id_ed25519The remote.tmux.* socket commands (below) give finer control — for example, remote.tmux.mirror mirrors a host's sessions into the current window's sidebar instead of opening a dedicated window.
#If you get "Permission denied"
The destination is handed to ssh as-is, so an alias must carry everything ssh needs to log in — most commonly User (without it, ssh tries your local username) and IdentityFile:
Host my-ssh-alias
HostName 203.0.113.10
User dev
IdentityFile ~/.ssh/id_ed25519Or pass the user explicitly: coterm ssh-tmux dev@my-ssh-alias. If plain ssh <destination> doesn't log you in, coterm ssh-tmux <destination> won't either.
#How it works
coterm spawns ssh … tmux -CC attach and parses the control-mode stream itself rather than relying on a built-in tmux viewer, so the protocol and %begin/%end command correlation are fully owned by coterm. Each remote pane renders into a dedicated terminal surface fed by tmux %output, and your input — keystrokes and mouse — is forwarded with tmux send-keys. The remote tmux server owns pane sizing and reflow; coterm keeps its surfaces in lock-step with it and never reflows locally.
#What it supports
- Sizing: the remote client is resized to the rendered grid (refresh-client -C), so TUIs aren't stuck at tmux's default 80×24.
- Splits: splitting or closing a pane in a mirrored window is propagated to tmux with split-window, so the coterm layout and the tmux layout stay in sync. Programmatic splits (coterm new-split or surface.split over the socket) report accepted with no surface id — the new pane arrives asynchronously once tmux confirms the layout change. Requests carrying options the routed split cannot honor (startup command, working directory, divider position, left/up placement) are rejected up front, before the remote session is mutated.
- Reordering: drag-reordering the mirrored tabs reorders the tmux windows with swap-window.
- Working directory: the remote pane's current folder is tracked and shown on the tab.
- Paste & drop: pasted text and dropped images/files go through tmux paste-buffer -p, so a remote app (e.g. a coding agent) receives a real bracketed paste — an image arrives as [Image #N], not a local path.
- Mouse: clicks, scroll, and drag reach the remote app when it has mouse mode on. Hold Shift while dragging for a native coterm text selection/copy (the same as any terminal running a mouse-mode app).
- Unicode-correct output: multi-byte characters are preserved even when tmux splits them across updates, so box-drawing and other wide content render cleanly.
#Socket commands
The feature is also driven by socket commands (gated on the Beta Features flag). host is an SSH destination or ~/.ssh/config alias; session is a tmux session name.
| Method | Params | Description |
|---|---|---|
remote.tmux.sessions | host, port?, identity_file? | List the tmux sessions on a host. |
remote.tmux.attach | host, session, create? | Attach a control client to a session (create attaches-or-creates). |
remote.tmux.mirror | host | Mirror every session on a host, each as its own workspace (windows become tabs). |
remote.tmux.window | host, port?, identity_file? | Open a dedicated window mirroring every session on a host (the coterm ssh-tmux entry point); returns the ssh command to run for interactive auth when the host needs it. |
remote.tmux.detach | host, session | Detach the control client; the remote session keeps running. |
remote.tmux.state | host, session | Report the control client's observed state (diagnostics). |
A dash-prefixed host or identity file is rejected at the trust boundary as a defense against SSH option injection.
{ "method": "remote.tmux.mirror", "params": { "host": "dev.example.com" } }#Limitations
- Transient SSH drops reconnect automatically: if the connection blips mid-session the mirror freezes and coterm retries with capped exponential backoff, re-seeding the panes when it resumes. The mirror only closes for good when the remote session itself ends, or when you close the mirror window or quit coterm — and it isn't restored on relaunch (re-attach with coterm ssh-tmux).
- Only single-line paste/drop (such as a file or image path) is delivered as a real bracketed paste via paste-buffer -p; multi-line text is sent as plain keystrokes, so a remote app won't treat it as one paste.
- Live working-directory updates use control-mode subscriptions, which is why coterm requires tmux 3.2 or newer before it opens the mirror.
- Primary-screen scrollback isn't re-wrapped on resize — coterm leaves reflow to tmux, so older lines can stay at the previous width until the app repaints. Full-screen TUIs, which redraw on resize, are unaffected.