Python
libtmux
pip install libtmux Drive a real tmux from your language of choice.
Server, session, window, pane — the same object hierarchy tmux itself defines, typed and ported to eight languages. Script a workspace, harness a TUI in tests, or give an assistant hands on a terminal, without hand-rolling a subprocess wrapper first.
Pick your language below — the install line and the example both follow it. Each snippet is that port's own opening example; see Attach and send keys for one task written out in all eight.
$ pip install libtmuximport libtmux
server = libtmux.Server()session = server.new_session(session_name="demo")session.active_pane.send_keys("echo hello from libtmux")$ bun add @libtmux/libtmuximport { Server } from "libtmux";
const server = new Server();
const session = await server.newSession({ name: "quickstart" });const editor = await session.newWindow({ name: "editor" });await editor.split();
const snapshot = await server.snapshot();const found = snapshot.windows.where({ name: "editor" }).one();
const paneCount = found.panes.length;$ cargo add libtmuxuse libtmux::test::TestServer;
#[tokio::main]async fn main() -> Result<(), Box<dyn std::error::Error>> { // Runs for real. `TestServer` is an isolated tmux on its own socket under // `/tmp/libtmux-rs-test/`, torn down at the end. Your own code says // `let server = libtmux::Server::new()?;` instead; nothing else changes. let guard = TestServer::new().await?; let server = guard.server();
let session = server.new_session("work").await?; let window = session.new_window("editor").await?; let pane = window.active_pane().await?.expect("a window has a pane");
pane.send_line("echo hello").await?;
for line in pane.capture().await? { println!("{}", line.to_string_lossy()); }
guard.shutdown().await?; Ok(())}$ go get github.com/libtmux/libtmux-gosession, err := server.NewSession(ctx, tmux.NewSessionRequest{ Name: "libtmux-go-quickstart", WindowName: "start",})if err != nil { return fmt.Errorf("create session: %w", err)}
windowName := "work"window, err := session.NewWindow(ctx, tmux.NewWindowRequest{Name: &windowName})if err != nil { return fmt.Errorf("create window: %w", err)}pane, err := window.SplitPane(ctx, tmux.SplitPaneRequest{ Direction: tmux.PaneDirectionRight,})if err != nil { return fmt.Errorf("split window: %w", err)}command := "printf 'libtmux ready\\n'"if err := pane.SendKeys(ctx, tmux.SendKeysRequest{Command: &command, Literal: true}); err != nil { return fmt.Errorf("send command: %w", err)}$ implementation("io.github.libtmux:libtmux:VERSION")ServerConfig config = ServerConfig.builder() .endpoint(ServerEndpoint.socketPath(socket)) .build();
try (Server server = Server.open(config)) { Session session = server.newSession("demo"); Window window = session.newWindow("build"); Pane pane = window.split();
pane.sendLine("echo hello from libtmux");}$ dotnet add package LibTmuxusing LibTmux;
Server server = await Server.ConnectAsync();Session session = await server.CreateSessionAsync(new NewSessionRequest(name: "build"));Window window = await session.CreateWindowAsync(new NewWindowRequest(name: "tests"));Pane pane = (await window.GetPanesAsync())[0];
await pane.SendTextAsync("dotnet test");$ vcpkg install libtmux-cxx// No tmux failure is thrown. Every call answers with a value that is either// the result or the reason there isn't one.const auto sessions = server.sessions();if (!sessions.has_value()) { std::fprintf(stderr, "%s\n", sessions.error().diagnostic.c_str()); return 1;}
for (const libtmux::Session& session : *sessions) { std::printf("%s has %lld window(s)\n", std::string{session.name()}.c_str(), session.window_count());}$ .package(url: "https://github.com/libtmux/libtmux-swift", from: "0.1.0")import LibTmux
let server = try Server(socketName: "default")for session in try await server.sessions() { print(session.name, session.windowCount)}Rust, Go, and Java deep-link to the canonical host their own ecosystem already uses (docs.rs, pkg.go.dev, javadoc.io); the rest are self-hosted here, in the same design.
libtmux
pip install libtmux @libtmux/libtmux
bun add @libtmux/libtmux libtmux
cargo add libtmux github.com/libtmux/libtmux-go/tmux
go get github.com/libtmux/libtmux-go io.github.libtmux:libtmux
implementation("io.github.libtmux:libtmux:VERSION") LibTmux
dotnet add package LibTmux libtmux-cxx
vcpkg install libtmux-cxx libtmux-swift
.package(url: "https://github.com/libtmux/libtmux-swift", from: "0.1.0") Deep dives into one subject at a time — architecture, traversal, options and hooks — compared across all eight ports.
The mental model every port shares before you read any one port’s own reference: the object hierarchy, transports, and filtering.
Task-oriented walkthroughs — install tmux, pick a port, and run the round trip every real program starts from.
Every public symbol in all eight ports, extracted from source and cross-linked — 13,753 of them, in one place and one style.
The same concrete task, worked through in each of the eight ports side by side, so you can compare syntax directly.