
Research
2025 Report: Destructive Malware in Open Source Packages
Destructive malware is rising across open source registries, using delays and kill switches to wipe code, break builds, and disrupt CI/CD.
libtmux
Advanced tools
Drive tmux from Python: typed, object-oriented control over servers, sessions, windows, and panes.
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.
.cmd(...) on any objectMaintenance-only backports (no new fixes):
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.*"
First, start a tmux session to connect to:
$ tmux new-session -s foo -n bar
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.
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]
'$...'
>>> server.sessions
[Session($... ...), ...]
Filter by attribute:
>>> server.sessions.filter(history_limit='2000')
[Session($... ...), ...]
Direct lookup:
>>> server.sessions.get(session_id=session.session_id)
Session($... ...)
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()
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(%... ...)
>>> pane.clear()
Pane(%... ...)
>>> pane.send_keys("echo 'hello world'", enter=True)
>>> pane.cmd('capture-pane', '-p').stdout # doctest: +SKIP
["$ echo 'hello world'", 'hello world', '$']
Navigate from pane up to window to session:
>>> pane.window
Window(@... ...:..., Session($... ...))
>>> pane.window.session
Session($... ...)
| 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)
| 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 |
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
TestServer helper spins up multiple isolated tmux serversTopics: 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
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.
FAQs
Typed library that provides an ORM wrapper for tmux, a terminal multiplexer.
We found that libtmux demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Research
Destructive malware is rising across open source registries, using delays and kill switches to wipe code, break builds, and disrupt CI/CD.

Security News
Socket CTO Ahmad Nassri shares practical AI coding techniques, tools, and team workflows, plus what still feels noisy and why shipping remains human-led.

Research
/Security News
A five-month operation turned 27 npm packages into durable hosting for browser-run lures that mimic document-sharing portals and Microsoft sign-in, targeting 25 organizations across manufacturing, industrial automation, plastics, and healthcare for credential theft.