libtmux¶
Typed Python API for tmux. Control servers, sessions, windows, and panes as Python objects.
Install and make your first API call in 5 minutes.
Architecture, traversal, filtering, and automation patterns.
Every public class, function, and exception.
Isolated tmux fixtures and test helpers.
Development setup, code style, release process.
Install¶
$ pip install libtmux
$ uv add libtmux
Tip: libtmux is pre-1.0. Pin to a range: libtmux>=0.55,<0.56
See Quickstart for all methods and first steps.
At a glance¶
>>> demo_window = session.new_window(window_name="my-project")
>>> demo_pane = demo_window.active_pane
>>> demo_pane.send_keys("echo hello")
>>> demo_window.kill()
Server → Session → Window → Pane
Every level of the tmux hierarchy is a typed Python object with traversal, filtering, and command execution.
Know where you’re running¶
Sometimes you hold no handle at all, because your code is running inside a
pane. You don’t have to search the server for yourself — tmux writes TMUX and
TMUX_PANE into every pane it spawns, and each level of the hierarchy reads
them back:
>>> socket_path = server.cmd(
... "display-message", "-p", "-t", session.session_id, "#{socket_path}"
... ).stdout[0]
>>> monkeypatch.setenv("TMUX", f"{socket_path},1,{session.session_id}")
>>> monkeypatch.setenv("TMUX_PANE", pane.pane_id)
>>> Pane.from_env().pane_id == pane.pane_id
True
>>> Session.from_env().session_name == session.session_name
True
Inside a pane tmux has already set those two variables, so Pane.from_env() takes no arguments; these docs are not running in a
pane, so the example sets them first. Outside tmux there is no pane to return and
NotInsideTmux is raised instead. See Locating yourself.
Testing¶
libtmux ships a pytest plugin with isolated tmux fixtures:
>>> test_window = session.new_window(window_name="test")
>>> test_pane = test_window.active_pane
>>> test_pane.send_keys("echo hello")
>>> test_window.window_name
'test'
>>> test_window.kill()