libtmux Reference MCP Search

Socket and servers

Edit this page on GitHub

Every Server handle in every port ultimately resolves to a Unix domain socket — tmux itself has no other notion of “which server.” Running more than one tmux server at once (a suite of tests, each wanting its own private instance; a program that manages several unrelated sessions on purpose) is ordinary, not exotic, and every port gives you the same three ways tmux itself supports for picking one: the default socket, a named one (-L), or an explicit path (-S).

Naming a serverLink to section

PortDefaultNamed socket (-L)Explicit path (-S)
PythonServer()Server(socket_name="work")Server(socket_path="/tmp/tmux-1000/work")
TypeScriptnew Server()new Server({ socketName: "work" })new Server({ socketPath: "..." })
Gotmux.NewServer(tmux.ServerOptions{})tmux.ServerOptions{SocketName: "work"}tmux.ServerOptions{SocketPath: "..."}
RustServer::new()Server::builder().socket_name("work").build()?Server::builder().socket_path("...").build()?
JavaServerEndpoint.defaultSocket()ServerEndpoint.namedSocket("work")ServerEndpoint.socketPath(path)
.NETnew ServerConnectionOptions()new ServerConnectionOptions(socketName: "work")new ServerConnectionOptions(socketPath: "...")
C++Server::at_default()Server::at_socket_name("work")Server::at_socket_path("...")
Swiftno bare default — see belowServer(socketName: "work")Server(socketPath: "...")
ServerConfig config = ServerConfig.builder()
.endpoint(ServerEndpoint.namedSocket("work"))
.build();
Server named = Server.open(config);

Naming a socket and naming a path are mutually exclusive everywhere this was checked — TypeScript throws a TypeError if you pass both, and Go’s own doc comment says SocketPath simply takes precedence when both are set rather than raising. TMUX_TMPDIR is the one environment variable that matters here across every port: tmux itself (not libtmux) resolves the default and named-socket directory through it, so it shapes which server a bare, no-argument Server lands on even though no port reads it directly.

Swift is the one port with no bare default at all. Server has exactly two public initializers — init(socketPath:) and init(socketName:) — and neither has a way to omit the argument, so there is no verified Server()-shaped call that lands on whatever TMUX_TMPDIR/default resolves to the way the other seven ports’ zero-argument constructors do. Reaching the default socket in Swift means naming it yourself, e.g. Server(socketName: "default").

Python and .NET add one more convenience worth calling out because the parallel is exact: Python’s Server(socket_name_factory=...) and .NET’s ServerConnectionOptions(socketNameFactory: ...) both take a callable that generates a fresh, unique socket name — the shape a test suite wants when every test needs its own throwaway server and nobody wants to hand-write a random name generator.

Is the server actually there?Link to section

A Server handle is inert until you ask tmux something — constructing one never starts a process or fails on a socket that doesn’t exist yet. Every port gives you an explicit, cheap check rather than making you infer liveness from whatever error a real command happens to throw:

PortCheck
Pythonserver.is_alive()bool
TypeScriptawait server.isAlive()Promise<boolean>; await server.raiseIfDead() throws with tmux’s own reason instead
Goserver.IsAlive(ctx)(bool, error) — the error is reserved for a question that couldn’t be answered at all, not for “not alive”
Rustserver.is_alive().awaitbool; server.check_alive().await is the fallible twin, for when the reason matters
Javaserver.isAlive()boolean
.NETawait server.IsAliveAsync()Task<bool>
C++server.is_alive(timeout)bool
Swifttry await server.isRunning()Bool
if (server.isAlive()) {
server.sessions();
}

TypeScript and Rust both separate “tell me” from “tell me why not,” and for the same reason: every read already raises on an unreachable server, so isAlive() / is_alive() isn’t what turns an empty result into a dead-server diagnosis — it exists for a caller that wants the check on its own, with nothing to hang a read on yet. raiseIfDead() / check_alive() is the assertion form of the same question, for when you do want the failure to carry tmux’s own reason.

Killing a server, and telling two apartLink to section

Killing the whole server — not a session inside it — is kill-server, reached the same way in every port: server.kill_server() (Python), await server.kill() (TypeScript), server.Kill(ctx) (Go), server.kill().await? (Rust), server.killServer() (Java and Swift), await server.KillAsync() (.NET), server.kill() (C++). Context managers covers the one place this is easy to get backwards: Java’s Server.close() — the method try-with-resources calls — is not this; it releases the local connection and leaves the server running.

Two Server handles can name the same socket without being the same object, so “is this the same server” starts as a question about the selector (which socket), not the handle: Python’s Server.__eq__ compares socket_name and socket_path directly, and Go’s server.Equal(other) does the same job more carefully — it “evaluates relative paths and environment-dependent named and default sockets against each handle’s frozen binding” rather than comparing the two fields as literal strings.

Neither answers a sharper question that both ports separately guard against: a socket path names a place, not a process, and kill-server followed by a restart on the same path produces a server that resolves to the same place while being, underneath, a different tmux daemon with none of the state the first one had. TypeScript’s TmuxServerRestarted and Go’s ErrDaemonReplaced both exist specifically to catch a handle acting on a daemon that already isn’t the one that made it — verified, real guards against exactly this, not a theoretical concern.

Esc

Type to search.