Tmux control mode protocol documentation
Tmux Control Mode Protocol Documentation
Overview
Control mode is a text-based protocol activated with -C (or -CC for no echo). The client sends tmux commands on stdin; the server responds with structured output blocks and asynchronous notifications.
Input (Client → Server)
Commands are standard tmux commands terminated by newline. An empty line detaches the client.
Output Blocks (Command Responses)
%begin TIME COMMAND_NUM FLAGS
[output lines]
%end TIME COMMAND_NUM FLAGS # success
or
%begin TIME COMMAND_NUM FLAGS
[output lines]
%error TIME COMMAND_NUM FLAGS # failure
- TIME - Unix timestamp
- COMMAND_NUM - Sequential command number
- FLAGS - Currently 0 or 1
Notifications (Asynchronous)
| Notification | Format |
|---|---|
| %output | %output pane-id value |
| %extended-output | %extended-output pane-id age ... : value |
| %pause | %pause pane-id |
| %continue | %continue pane-id |
| %layout-change | %layout-change window-id layout visible-layout flags |
| %window-add | %window-add window-id |
| %window-close | %window-close window-id |
| %window-renamed | %window-renamed window-id name |
| %window-pane-changed | %window-pane-changed window-id pane-id |
| %pane-mode-changed | %pane-mode-changed pane-id |
| %session-changed | %session-changed session-id name |
| %session-renamed | %session-renamed name |
| %session-window-changed | %session-window-changed session-id window-id |
| %sessions-changed | %sessions-changed |
| %client-detached | %client-detached client |
| %client-session-changed | %client-session-changed client session-id name |
| %unlinked-window-add/close/renamed | Same pattern as window notifications |
| %paste-buffer-changed | %paste-buffer-changed name |
| %paste-buffer-deleted | %paste-buffer-deleted name |
| %subscription-changed | %subscription-changed name session-id window-id window-index pane-id ... : value |
| %message | %message text |
| %config-error | %config-error error |
| %exit | %exit [reason] |
Identifiers
| Type | Format | Example |
|---|---|---|
| Session | $N |
$0, $1 |
| Window | @N |
@0, @1 |
| Pane | %N |
%0, %1 |
Character Escaping
Non-printable characters and backslashes are encoded as octal \XXX:
- Backslash →
\134 - Newline →
\012
Flow Control
- pause-after=N flag: Server sends
%pausewhen buffering exceeds N seconds, client must sendrefresh-client -A pane:+to resume - Extended output:
%extended-outputincludesagein milliseconds - Max buffer age without pause-after: 5 minutes (then client disconnects)
Subscriptions
Subscribe to format changes:
refresh-client -B name:what:format
- what:
%*(all panes),%N(specific pane),@*(all windows),@N(window), or empty (session)
Initialization (-CC mode)
Server sends DCS sequence: \033P1000p (7 bytes) on connect.
Tmux Data Model & Object Hierarchy
Entity Relationships
Server (singleton)
├── Sessions ($0, $1, ...)
│ └── Winlinks (index 0, 1, 2, ...)
│ └── → Window (shared reference)
├── Windows (@0, @1, ...) [global pool]
│ ├── Layout Tree (binary tree of cells)
│ └── Panes (%0, %1, ...) [leaf nodes]
├── Clients (terminal connections)
└── Session Groups (optional sync groups)
Core Entities
Session ($N)
A named, persistent context that survives client disconnection.
| Property | Description |
|---|---|
id |
Unique identifier ($0, $1) |
name |
User-friendly name ("dev", "work") |
windows |
RB-tree of winlinks indexed by number |
curw |
Currently active window |
attached |
Count of connected clients |
- Can exist with zero clients attached
- Multiple clients can attach to the same session
Window (@N)
A container of panes with a tiling layout. Windows are global (not session-specific).
| Property | Description |
|---|---|
id |
Global unique ID (@0, @1) |
name |
Display name in status bar |
panes |
List of panes |
active |
Currently focused pane |
layout_root |
Root of layout cell tree |
references |
Count of sessions linking this window |
- Same window can appear in multiple sessions (linked windows)
- Changes are visible to all sessions containing the window
Winlink (Session ↔ Window link)
The join table between sessions and windows, providing per-session metadata.
| Property | Description |
|---|---|
idx |
Window index within session (0, 1, 2...) |
session |
Back-pointer to session |
window |
Pointer to window |
flags |
Alert state (bell, activity, silence) |
- When you "move" or "renumber" a window, you're changing the winlink's
idx - When no winlinks reference a window, it's destroyed
Pane (%N)
A terminal subdivision within a window, containing a pty and shell process.
| Property | Description |
|---|---|
id |
Global unique ID (%0, %1) |
window |
Containing window |
screen |
Character grid/buffer |
pid |
Shell process ID |
sx, sy |
Size in cells |
xoff, yoff |
Position within window |
- Leaf nodes in the layout tree
- Each has independent scrollback buffer
Layout Cell (Pane Arrangement)
A binary tree describing spatial arrangement of panes.
| Type | Meaning |
|---|---|
LAYOUT_LEFTRIGHT |
Horizontal split (children side-by-side) |
LAYOUT_TOPBOTTOM |
Vertical split (children stacked) |
LAYOUT_WINDOWPANE |
Leaf node (contains one pane) |
Layout Example:
┌─────────┬─────────┐
│ │ pane1 │
│ pane0 ├─────────┤
│ │ pane2 │
└─────────┴─────────┘
Tree:
LAYOUT_LEFTRIGHT
├── LAYOUT_WINDOWPANE (pane0)
└── LAYOUT_TOPBOTTOM
├── LAYOUT_WINDOWPANE (pane1)
└── LAYOUT_WINDOWPANE (pane2)
Client
A connected terminal or control mode connection.
| Property | Description |
|---|---|
name |
Client identifier |
session |
Currently attached session (or NULL) |
flags |
CLIENT_CONTROL, CLIENT_ATTACHED, etc. |
control_state |
State for control mode clients |
- A client attaches to at most one session at a time
- Control mode clients receive structured protocol output instead of terminal rendering
Session Group (Optional)
Synchronizes windows across multiple sessions.
- All sessions in a group share the same windows
- Creating/closing a window affects all grouped sessions
- Useful for multiple terminals showing identical window sets
ID Namespaces
| Prefix | Entity | Scope | Example |
|---|---|---|---|
$ |
Session | Global, unique forever | $0, $5 |
@ |
Window | Global, unique forever | @0, @12 |
% |
Pane | Global, unique forever | %0, %7 |
IDs are never reused within a server lifetime—safe for tracking.
Key Implications for Control Mode
- Track by ID, not index: Window indices change;
@NIDs don't - Windows are shared:
%layout-change @5affects all sessions containing@5 - Pane output is global:
%output %3is the same pane regardless of which session you're viewing - Clients are independent: Multiple control clients can attach to different sessions simultaneously
Tmux Data Model — Source References
All structures are in the tmux/tmux repository.
Core Structures
| Entity | Struct | File | Lines |
|---|---|---|---|
| Session | struct session |
tmux.h | 1415–1450 |
| Session Group | struct session_group |
tmux.h | 1407–1413 |
| Window | struct window |
tmux.h | 1263–1316 |
| Winlink | struct winlink |
tmux.h | 1320–1337 |
| Pane | struct window_pane |
tmux.h | 1170–1259 |
| Layout Cell | struct layout_cell |
tmux.h | 1378–1393 |
| Client | struct client |
tmux.h | 1934–2116 |
Control Mode Structures
Notification Handlers
Control mode notifications are implemented in control-notify.c:
| Function | Lines | Notification |
|---|---|---|
control_notify_pane_mode_changed |
~30–40 | %pane-mode-changed |
control_notify_window_layout_changed |
~42–65 | %layout-change |
control_notify_window_pane_changed |
~67–80 | %window-pane-changed |
control_notify_window_unlinked |
~82–95 | %unlinked-window-add |
control_notify_window_linked |
~97–110 | %window-add |
control_notify_window_renamed |
~112–125 | %window-renamed |
control_notify_client_session_changed |
~127–145 | %client-session-changed |
control_notify_client_detached |
~147–160 | %client-detached |
control_notify_session_renamed |
~162–175 | %session-renamed |
control_notify_session_created |
~177–190 | %sessions-changed |
control_notify_session_closed |
~192–205 | %sessions-changed |
control_notify_session_window_changed |
~207–220 | %session-window-changed |
control_notify_paste_buffer_changed |
~222–235 | %paste-buffer-changed |
control_notify_paste_buffer_deleted |
~237–250 | %paste-buffer-deleted |
Other Key Files
No — panes cannot be shared across multiple windows.
Each pane has a single struct window *window back-pointer (tmux.h#L1174), not a list:
struct window_pane {
u_int id;
struct window *window; // ← Single window, not multiple
// ...
};
Comparison
| Entity | Can be shared? | Mechanism |
|---|---|---|
| Window | ✅ Yes, across sessions | winlink join table + references count |
| Pane | ❌ No | Single window pointer |
Panes Are Moved, Not Linked
Commands like join-pane and break-pane move the pane by reassigning its window pointer (cmd-join-pane.c#L150):
TAILQ_REMOVE(&src_w->panes, src_wp, entry); // Remove from source
src_wp->window = dst_w; // Reassign pointer
TAILQ_INSERT_AFTER(&dst_w->panes, ...); // Add to destination
The pane exists in exactly one window at any time.