libtmux Reference MCP Search

Server, session, window, pane

Edit this page on GitHub

Every libtmux port works through the same four nouns, because they aren’t a design choice a port made — they’re tmux’s own hierarchy, and a port’s object model is a typed proxy over it:

Server
├── Session
│ └── Window
│ └── Pane
└── Client (attached view)

A Server owns sessions. A Session owns windows. A Window owns panes. A Pane is where commands actually run — it’s the thing you type into and read output from. Whatever a port calls these (Python’s Server/Session/ Window/Pane, C++‘s value types of the same names, Go’s tmux.Session and tmux.Window), you are always navigating this same tree: a server’s sessions, a session’s windows, a window’s panes.

Stable identity, not name or indexLink to section

tmux assigns each session, window, and pane a unique ID the moment it’s created, and every port tracks objects by that ID rather than by name or position — names get renamed, indexes shift when a window in front of yours closes, but the ID is stable for the object’s lifetime:

ObjectID prefixExample
Session$$13
Window@@3243
Pane%%5433
Serveridentified by socket name or path instead

Ports that hand you a live-refreshing handle (Python’s Session.refresh()) use the ID to re-fetch the same object tmux still recognizes; ports that hand you an immutable snapshot (TypeScript’s Selection, Swift’s Snapshot, Go’s “records never refresh behind you” values) use the ID to compare two snapshots and confirm they’re talking about the same underlying object across reads.

Walking the whole tree, in each port:

for (const session of await server.sessions()) {
console.log(session.name);
for (const window of session.windows) {
console.log(" ", window.index, window.name);
for (const pane of window.panes) {
console.log(" ", pane.id, pane.currentCommand);
}
}
}

Client: a view, not a childLink to section

Client is the one thing in the diagram that isn’t a child of anything. Where a Session owns its Windows and a Window owns its Panes, a Client is an attached terminal that points at whichever session, window, and pane it’s currently viewing — one $ tmux attach from a person’s terminal. The same server can host several clients at once, each looking at something different, and a client’s view can change the instant that person runs switch-client or select-window. That’s why a client’s session/ window/pane fields are a snapshot of where it was pointed when you read it, not a live relationship you can walk the way you walk from a pane up to its window.

This distinction matters for one very concrete reason across every port: a control-mode connection (see Control mode vs one-shot) is a client. Opening one adds a row to list-clients, counts toward session_attached, and is visible to anything that keys off attachment — including policies like destroy-unattached, which will tear down a session the moment your program’s control client detaches from it.

What differs between portsLink to section

The hierarchy above is fixed. What ports disagree on, on purpose, is:

  • Whether a held object refreshes. Python’s objects re-read from tmux when you call .refresh(), but otherwise reflect the state at construction. TypeScript, Swift, and Go’s Rust-flavored “read once into an immutable snapshot, then query it like data” model goes further: the whole server is read in one pass, and every relationship you walk after that touches no further tmux state at all.
  • Sync vs async. Python and Java block on every call, matching tmux’s own subprocess model directly. Rust, Go, TypeScript, C#, and Swift make every tmux round trip an explicit async/await, because the underlying work — starting a process or reading a socket — is I/O.
  • How failure surfaces. Some ports raise (Python’s LibTmuxException hierarchy, C#‘s exceptions); C++ returns expected<T, CommandFailure> and never throws for a tmux-side failure; a few treat a nonzero-exit tmux command as data rather than an error, because (as C++‘s docs put it) has-session answering “no” is a reply, not a failure.

None of that changes the shape in the diagram above. It changes what it costs you to read from it, and how you find out when something went wrong.

Esc

Type to search.