libtmux
English
Reference MCP Search

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.

Quickstart

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 libtmux
import libtmux
server = libtmux.Server()
session = server.new_session(session_name="demo")
session.active_pane.send_keys("echo hello from libtmux")
$ bun add @libtmux/libtmux
import { 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 libtmux
use 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-go
session, 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 LibTmux
using 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)
}

Eight ports, one API shape

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.

Go

github.com/libtmux/libtmux-go/tmux

go get github.com/libtmux/libtmux-go

API reference

Java

io.github.libtmux:libtmux

implementation("io.github.libtmux:libtmux:VERSION")

API reference

Swift

libtmux-swift

.package(url: "https://github.com/libtmux/libtmux-swift", from: "0.1.0")

API reference

Read the docs

Esc

Type to search.