libtmux
English
Reference MCP Search

Attaching to tmux

Edit this page on GitHub

“Attach” means two different things in this ecosystem, and mixing them up is the most common way to be surprised. This guide is about the first: your program obtaining a live handle to a running (or freshly created) tmux server and session. It is not a terminal takeover — your process keeps its own stdin and stdout, and tmux keeps running whether or not anything is looking at it. Every port’s object API works this way, and it’s what the rest of this guide, and the flagship example, means by “attach.”

The other kind is real: Python’s Session.attach() runs tmux attach-session and hands your process’s own terminal to tmux — this is how tmuxp finishes, after it has built a workspace with the first kind of attach. If you want that, look for it by name in your port’s reference; it isn’t covered further here.

Which socket a bare constructor reachesLink to section

Every port lets you name a socket explicitly, but a call with no arguments still has to land somewhere, and that “somewhere” is worth knowing before you’re debugging why two processes can’t see the same session. Reading the socket back from inside a pane — TMUX / TMUX_PANE, the variables tmux writes into every pane it spawns — is a separate call in every port that offers it, kept apart from the bare constructor on purpose: a plain Server() never guesses that you’re inside tmux.

# Server() with no arguments talks to tmux's own default socket.
# Server(socket_name=...) or Server(socket_path=...) pick a different one.
server = libtmux.Server()
# from_env() is also on Session, Window, and Pane, for code running inside a
# pane that wants to ask "where am I" instead of being told.
server = libtmux.Server.from_env()

Sources: Python’s Server.from_env() is doctested in src/libtmux/server.py (pyproject.toml testpaths). .NET’s resolution order and FromEnvironment are from src/LibTmux/README.md (“Where a bare connect lands”), one of the nine documents ReadmeExampleTests compiles and runs. Go’s is tmux/server_options.go’s doc comments. Rust’s fallback is crates/libtmux/examples/find.rs, run via cargo run --example find. C++‘s four constructors are the README’s own description of Server, at the top of “What is libtmux?”. Swift’s is README.md’s top-level quickstart, matched against Examples/Sources/QuickStart/main.swift by Scripts/check_examples.py. Java’s is README.md, run by docs-tests.

Finding a session instead of always creating oneLink to section

A script that runs more than once usually wants “attach if a session by this name already exists, create it otherwise,” not a fresh session every time.

# default only stands in for *absence*: an ambiguous match still raises
# MultipleObjectsReturned even with a default supplied — handing back an
# arbitrary match from several is how a script ends up driving the wrong
# pane. See Filtering and queries.
session = server.sessions.get(session_name="demo", default=None)
if session is None:
session = server.new_session(session_name="demo")

Sources: Go’s is examples/filter-query/main.go, the docs:query-in-tmux region the README quotes. Java’s exact ternary is examples/.../BuildAWorkspace.java, one of the four programs the examples module’s own test compiles and runs — Selections.exactlyOne(...) is the alternative shape when “found more than one” should be a distinct error rather than “found none,” see Filtering and querying, in practice. Swift’s hasSession is Examples/Sources/ExampleCode/Querying.swift, matched against the README by Scripts/check_examples.py and exercised by Examples/Tests/ExampleTests/ModeTests.swift.

.NET’s Server.HasSessionAsync(name) exists in source (src/LibTmux/Server.Lifecycle.cs), and CreateSessionAsync takes a ReplaceExisting option that kills and recreates rather than throwing TmuxSessionExistsException — but neither appears in a checked README snippet as of this page, so the existence of the method is verified and the exact call shape is not, until it’s quoted somewhere ReadmeExampleTests compiles. Rust and C++ both have a query layer capable of the same check (see Filtering and querying, in practice), but neither exposes a single has_session-shaped call, and no README quotes the “session exists by name” pattern directly — so it isn’t guessed at here.

Where to go nextLink to section

Esc

Type to search.