libtmux¶
🐍 What is libtmux?¶
libtmux is a typed Python API over tmux, the terminal multiplexer. Stop shelling out and parsing tmux ls. Instead, interact with real Python objects: Server, Session, Window, and Pane. The same API powers tmuxp, so it stays battle-tested in real-world workflows.
✨ Features¶
Typed, object-oriented control of tmux state
Query and traverse live sessions, windows, and panes
Raw escape hatch via
.cmd(...)on any objectWorks with multiple tmux sockets and servers
Context managers for automatic cleanup
pytest plugin for isolated tmux fixtures
Proven in production via tmuxp and other tooling
Requirements & support¶
tmux: >= 3.2a
Python: >= 3.10 (CPython and PyPy)
Maintenance-only backports (no new fixes):
📦 Installation¶
Stable release:
pip install libtmux
With pipx:
pipx install libtmux
With uv / uvx:
uv add libtmux
uvx --from "libtmux" python
From the main branch (bleeding edge):
pip install 'git+https://github.com/tmux-python/libtmux.git'
Tip: libtmux is pre-1.0. Pin a range in projects to avoid surprises:
requirements.txt:
libtmux==0.50.*
pyproject.toml:
libtmux = "0.50.*"
🚀 Quickstart¶
Open a tmux session¶
First, start a tmux session to connect to:
$ tmux new-session -s foo -n bar
Pilot your tmux session via Python¶
Use ptpython, ipython, etc. for a nice REPL with autocompletions:
$ pip install --user ptpython
$ ptpython
Connect to a live tmux session:
>>> import libtmux
>>> svr = libtmux.Server()
>>> svr
Server(socket_path=/tmp/tmux-.../default)
Tip: You can also use tmuxp’s tmuxp shell to drop straight into your
current tmux server / session / window / pane.
Run any tmux command¶
Every object has a .cmd() escape hatch that honors socket name and path:
>>> server = Server(socket_name='libtmux_doctest')
>>> server.cmd('display-message', 'hello world')
<libtmux...>
Create a new session:
>>> server.cmd('new-session', '-d', '-P', '-F#{session_id}').stdout[0]
'$...'
List and filter sessions¶
>>> server.sessions
[Session($... ...), ...]
Filter by attribute:
>>> server.sessions.filter(history_limit='2000')
[Session($... ...), ...]
Direct lookup:
>>> server.sessions.get(session_id=session.session_id)
Session($... ...)
Control sessions and windows¶
Learn more about Workspace Setup
>>> session.rename_session('my-session')
Session($... my-session)
Create new window in the background (don’t switch to it):
>>> bg_window = session.new_window(attach=False, window_name="bg-work")
>>> bg_window
Window(@... ...:bg-work, Session($... ...))
>>> session.windows.filter(window_name__startswith="bg")
[Window(@... ...:bg-work, Session($... ...))]
>>> session.windows.get(window_name__startswith="bg")
Window(@... ...:bg-work, Session($... ...))
>>> bg_window.kill()
Split windows and send keys¶
Learn more about Pane Interaction
>>> pane = window.split(attach=False)
>>> pane
Pane(%... Window(@... ...:..., Session($... ...)))
Type inside the pane (send keystrokes):
>>> pane.send_keys('echo hello')
>>> pane.send_keys('echo hey', enter=False)
>>> pane.enter()
Pane(%... ...)
Capture pane output¶
>>> pane.clear()
Pane(%... ...)
>>> pane.send_keys("echo 'hello world'", enter=True)
>>> pane.cmd('capture-pane', '-p').stdout
["$ echo 'hello world'", 'hello world', '$']
Traverse the hierarchy¶
Navigate from pane up to window to session:
>>> pane.window
Window(@... ...:..., Session($... ...))
>>> pane.window.session
Session($... ...)
Core concepts¶
libtmux object |
tmux concept |
Notes |
|---|---|---|
tmux server / socket |
Entry point; owns sessions |
|
tmux session ( |
Owns windows |
|
tmux window ( |
Owns panes |
|
tmux pane ( |
Where commands run |
Also available: Options and Hooks abstractions for tmux configuration.
Collections are live and queryable:
server = libtmux.Server()
session = server.sessions.get(session_name="demo")
api_windows = session.windows.filter(window_name__startswith="api")
pane = session.active_window.active_pane
pane.send_keys("echo 'hello from libtmux'", enter=True)
tmux vs libtmux vs tmuxp¶
Tool |
Layer |
Typical use case |
|---|---|---|
tmux |
CLI / terminal multiplexer |
Everyday terminal usage, manual control |
libtmux |
Python API over tmux |
Programmatic control, automation, testing |
tmuxp |
App on top of libtmux |
Declarative tmux workspaces from YAML / TOML |
Testing & fixtures¶
Learn more about the pytest plugin
Writing a tool that interacts with tmux? Use our fixtures to keep your tests clean and isolated.
def test_my_tmux_tool(session):
# session is a real tmux session in an isolated server
window = session.new_window(window_name="test")
pane = window.active_pane
pane.send_keys("echo 'hello from test'", enter=True)
assert window.window_name == "test"
# Fixtures handle cleanup automatically
Fresh tmux server/session/window/pane fixtures per test
Temporary HOME and tmux config fixtures keep indices stable
TestServerhelper spins up multiple isolated tmux servers
When you might not need libtmux¶
Layouts are static and live entirely in tmux config files
You do not need to introspect or control running tmux from other tools
Python is unavailable where tmux is running
Project links¶
Topics: Traversal · Filtering · Pane Interaction · Workspace Setup · Automation Patterns · Context Managers · Options & Hooks
Reference: Docs · API · pytest plugin · Architecture · Changelog · Migration
Project: Issues · Coverage · Releases · License · Support
The Tao of tmux — deep-dive book on tmux fundamentals
Contributing & support¶
Contributions are welcome. Please open an issue or PR if you find a bug or want to improve the API or docs. If libtmux helps you ship, consider sponsoring development via support.