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 object

  • Works 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

Learn more about Filtering

>>> 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

Learn more about Traversal

Navigate from pane up to window to session:

>>> pane.window
Window(@... ...:..., Session($... ...))
>>> pane.window.session
Session($... ...)

Core concepts

libtmux object

tmux concept

Notes

Server

tmux server / socket

Entry point; owns sessions

Session

tmux session ($0, $1,…)

Owns windows

Window

tmux window (@1, @2,…)

Owns panes

Pane

tmux pane (%1, %2,…)

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

  • TestServer helper 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

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.