tmux client library for Python
Control tmux, connect to and create servers, navigate sessions, windows, and panes, send keys, watch for changes via control mode, capture pane contents.
Quickstart
Install the package and run a complete program.
Guides
Task guides for Python.
Topics
Subject-by-subject, with Python in every code block.
Examples
Complete programs, sourced from the code each port tests.
API reference
Types and functions of the Python API.
Testing
Test code that uses tmux with an isolated server.
Install
uv add libtmuxAt a glance
Server → Session → Window → Pane. Each level of the tmux hierarchy has its own entry in the Python API, with the tmux object it wraps.
| Type | Wraps |
|---|---|
libtmux.Server | A tmux server |
libtmux.Session | A session, ID $n |
libtmux.Window | A window in a session, ID @n |
libtmux.Pane | A pane in a window, ID %n |
What it does
Start with Python
from __future__ import annotations
from pathlib import Pathimport tempfileimport time
import libtmux
directory = Path(tempfile.mkdtemp(prefix="libtmux-py-home-"))socket = directory / "tmux.sock"server = libtmux.Server(socket_path=socket, config_file="/dev/null")
session = server.new_session(session_name="demo")window = session.active_windowassert window is not Nonepane = window.split(shell="sh")
pane.send_keys("printf '\\nHello world\\n'", enter=True)
deadline = time.monotonic() + 5while "Hello world" not in pane.capture_pane(): if time.monotonic() >= deadline: raise TimeoutError("The pane did not print Hello world") time.sleep(0.02)
print("Hello world")from __future__ import annotations
from pathlib import Pathimport tempfileimport time
import libtmux
directory = Path(tempfile.mkdtemp(prefix="libtmux-py-home-"))socket = directory / "tmux.sock"server = libtmux.Server(socket_path=socket, config_file="/dev/null")
try: session = server.new_session(session_name="demo") window = session.active_window assert window is not None pane = window.split(shell="sh")
pane.send_keys("printf '\\nHello world\\n'", enter=True)
deadline = time.monotonic() + 5 while "Hello world" not in pane.capture_pane(): if time.monotonic() >= deadline: raise TimeoutError("The pane did not print Hello world") time.sleep(0.02)
print("Hello world")except Exception as error: raise RuntimeError("tmux quickstart failed") from errorfrom __future__ import annotations
from pathlib import Pathimport shutilimport tempfileimport time
import libtmux
directory = Path(tempfile.mkdtemp(prefix="libtmux-py-home-"))socket = directory / "tmux.sock"server = libtmux.Server(socket_path=socket, config_file="/dev/null")
try: session = server.new_session(session_name="demo") window = session.active_window assert window is not None pane = window.split(shell="sh")
pane.send_keys("printf '\\nHello world\\n'", enter=True)
deadline = time.monotonic() + 5 while "Hello world" not in pane.capture_pane(): if time.monotonic() >= deadline: raise TimeoutError("The pane did not print Hello world") time.sleep(0.02)
print("Hello world")finally: if socket.exists(): server.kill() shutil.rmtree(directory)from __future__ import annotations
from pathlib import Pathimport shutilimport tempfileimport time
import libtmux
directory = Path(tempfile.mkdtemp(prefix="libtmux-py-home-"))socket = directory / "tmux.sock"server = libtmux.Server(socket_path=socket, config_file="/dev/null")
try: session = server.new_session(session_name="demo") window = session.active_window assert window is not None pane = window.split(shell="sh")
pane.send_keys("printf '\\nHello world\\n'", enter=True)
deadline = time.monotonic() + 5 while "Hello world" not in pane.capture_pane(): if time.monotonic() >= deadline: raise TimeoutError("The pane did not print Hello world") time.sleep(0.02)
print("Hello world")except Exception as error: raise RuntimeError("tmux quickstart failed") from errorfinally: if socket.exists(): server.kill() shutil.rmtree(directory)Run this example
POSIX shell, Git, tmux 3.2a or newer, Python 3.14.6 and uv (tested 0.12.0).
Save the program above as quickstart.py in a new directory, along with the files below.
Cleanup is omitted; the private tmux server and its temporary files may remain. Select Cleanup to remove them when the program finishes. The program stops its private tmux server and removes any temporary files it created when it finishes. Error handling adds diagnostics; every version checks required results and deadlines.
Setup and run
git init -q sourcegit -C source fetch -q --depth=1 \ https://github.com/tmux-python/libtmux.git \ 9fdd083a8181a827889337b63cd4e6daea661a8cgit -C source checkout -q --detach FETCH_HEADuv venv .venvuv pip install --python .venv/bin/python ./sourceunset TMUX TMUX_PANEexport ENV=/dev/null BASH_ENV=/dev/null SHELL=/bin/sh.venv/bin/python quickstart.pyExpected output
Hello worldLibrary revision: 9fdd083a8181.
Typed API
- Typed objects instead of parsed format strings:
libtmux.neo.Obj - Addressing by tmux ID:
libtmux.Pane.id - Filtering and queries over tmux objects:
libtmux._internal.query_list.QueryList - Typed errors instead of exit codes and stderr:
libtmux.exc.LibTmuxException
What you get over the tmux CLI
- Connect to or start a tmux server:
libtmux.Server - Traversal from a server down to its panes:
libtmux.Server.panes - Send keys to a pane:
libtmux.Pane.send_keys - Watch for changes through tmux control mode:
libtmux._internal.control_mode.ControlMode - Capture pane contents:
libtmux.Pane.capture_pane
Know where you're running
Inside tmux, find the pane your program runs in from TMUX and TMUX_PANE: libtmux.Pane.from_env.
Testing
Run tests against an isolated tmux server: libtmux.pytest_plugin.server.