Quickstart¶
libtmux allows for developers and system administrators to control live tmux sessions using python code.
In this example, we will launch a tmux session and control the windows from inside a live tmux session.
Requirements¶
Installation¶
Next, ensure libtmux is installed:
$ pip install --user libtmux
Developmental releases¶
New versions of libtmux are published to PyPI as alpha, beta, or release
candidates. In their versions you will see notifications like a1, b1, and
rc1, respectively. 1.10.0b4 would mean the 4th beta release of 1.10.0
before general availability.
pip:
$ pip install --user --upgrade --pre libtmux
pipx:
$ pipx install \ --suffix=@next \ --pip-args '\--pre' \ --force \ 'libtmux'
Usage:
libtmux@next [command]-
$ uv tool install --prerelease=allow libtmux
uv:
$ uv add libtmux --prerelease allow
uvx:
$ uvx --from 'libtmux' --prerelease allow python
via trunk (can break easily):
Start a tmux session¶
Now, let’s open a tmux session.
$ tmux new-session -n bar -s foo
This tutorial will be using the session and window name in the example.
Window name -n: bar
Session name -s: foo
Control tmux via python¶
See also
$ python
For commandline completion, you can also use ptpython.
$ pip install --user ptpython
$ ptpython
First, we can grab a Server.
>>> import libtmux
>>> server = libtmux.Server()
>>> server
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.
Note
You can specify a socket_name, socket_path and config_file
in your server object. libtmux.Server(socket_name='mysocket') is
equivalent to $ tmux -L mysocket.
server is now a living object bound to the tmux server’s
Session, Window, and
Pane objects.
Raw, contextual commands¶
New session:
>>> server.cmd('new-session', '-d', '-P', '-F#{session_id}').stdout[0]
'$2'
>>> session.cmd('new-window', '-P').stdout[0]
'libtmux...:2.0'
From raw command output, to a rich Window object (in practice
and as shown later, you’d use
Session.new_window()):
>>> Window.from_window_id(window_id=session.cmd('new-window', '-P', '-F#{window_id}').stdout[0], server=session.server)
Window(@2 2:..., Session($1 libtmux_...))
Create a pane from a window:
>>> window.cmd('split-window', '-P', '-F#{pane_id}').stdout[0]
'%2'
Raw output directly to a Pane (in practice, you’d use
Window.split()):
>>> Pane.from_pane_id(pane_id=window.cmd('split-window', '-P', '-F#{pane_id}').stdout[0], server=window.server)
Pane(%... Window(@1 1:..., Session($1 libtmux_...)))
Find your Session¶
If you have multiple tmux sessions open, all methods in
Server are available.
We can list sessions with Server.sessions:
>>> server.sessions
[Session($1 ...), Session($0 ...)]
This returns a list of Session objects you can grab. We can
find our current session with:
>>> server.sessions[0]
Session($1 ...)
However, this isn’t guaranteed, libtmux works against current tmux information, the
session’s name could be changed, or another tmux session may be created,
so Server.sessions and
Server.windows exist as a lookup.
Get session by ID¶
tmux sessions use the $[0-9] convention as a way to identify sessions.
$1 is whatever ID Server.sessions returned
above.
>>> server.sessions.filter(session_id='$1')[0]
Session($1 ...)
You may call server.get_by_id() to use the
session object.
Get session by name / other properties¶
>>> server.sessions[0].rename_session('foo')
Session($1 foo)
>>> server.sessions.filter(session_name="foo")[0]
Session($1 foo)
>>> server.sessions.get(session_name="foo")
Session($1 foo)
With filter(), pass in
attributes and return a list of matches. In this case, a
Server holds a collection of child
Session objects. Session and
Window both utilize
filter() to sift
through windows and panes, respectively.
So you may now use:
>>> server.sessions[0].rename_session('foo')
Session($1 foo)
>>> session = server.sessions.get(session_name="foo")
>>> session
Session($1 foo)
to give us a session object to play with.
Playing with our tmux session¶
We now have access to session from above with all of the methods
available in Session.
Let’s make a Session.new_window(), in the
background:
>>> session.new_window(attach=False, window_name="ha in the bg")
Window(@2 ...:ha in the bg, Session($1 ...))
So a few things:
attach=Falsemeant to create a new window, but not to switch to it. It is the same as$ tmux new-window -d.window_namemay be specified.Returns the
Windowobject created.
Note
Use the API reference API Reference for more commands.
Let’s delete that window (Session.kill_window()).
Method 1: Use passthrough to tmux’s target system.
>>> session.kill_window(window.window_id)
The window in the bg disappeared. This was the equivalent of
$ tmux kill-window -t'ha in'
Internally, tmux uses target. Its specific behavior depends on what the
target is, view the tmux manpage for more information:
This section contains a list of the commands supported by tmux. Most commands
accept the optional -t argument with one of target-client, target-session,
target-window, or target-pane.
In this case, you can also go back in time and recreate the window again. The CLI should have history, so navigate up with the arrow key.
>>> session.new_window(attach=False, window_name="ha in the bg")
Window(@2 ...:ha in the bg, Session($1 ...))
Try to kill the window by the matching id @[0-9999].
>>> session.new_window(attach=False, window_name="ha in the bg")
Window(@2 ...:ha in the bg, Session($1 ...))
>>> session.kill_window('ha in the bg')
In addition, you could also call Window.kill() on
the Window object:
>>> window = session.new_window(attach=False, window_name="check this out")
>>> window
Window(@2 2:check this out, Session($1 ...))
And kill:
>>> window.kill()
Use Session.windows and
Session.windows.filter()
to list and sort through active Window objects.
Manipulating windows¶
Now that we know how to create windows, let’s use one. Let’s use
Session.active_window to grab our
current window.
>>> window = session.active_window
window now has access to all of the objects inside of
Window.
Let’s create a pane, Window.split():
>>> window.split(attach=False)
Pane(%2 Window(@1 ...:..., Session($1 ...)))
Powered up. Let’s have a break down:
session.active_windowgave us theWindowof the current attached window.attach=Falseassures the cursor didn’t switch to the newly created pane.Returned the created
Pane.
Also, since you are aware of this power, let’s commemorate the experience:
>>> window.rename_window('libtmuxower')
Window(@1 ...:..., Session($1 ...))
You should have noticed
Window.rename_window() renamed the
window.
Moving cursor across windows and panes¶
You have two ways you can move your cursor to new sessions, windows and panes.
For one, arguments such as attach=False can be omittted.
>>> pane = window.split()
This gives you the Pane along with moving the cursor to a new
window. You can also use the .select_* available on the object; in this case
the pane has Pane.select().
>>> pane = window.split(attach=False)
>>> pane.select()
Pane(%1 Window(@1 ...:..., Session($1 ...)))
Sending commands to tmux panes remotely¶
As long as you have the object, or are iterating through a list of them, you can
use Pane.send_keys().
>>> window = session.new_window(attach=False, window_name="test")
>>> pane = window.split(attach=False)
>>> pane.send_keys('echo hey', enter=False)
See the other window, notice that
Pane.send_keys() has “echo hey” written,
still in the prompt.
enter=False can be used to send keys without pressing return. In this case,
you may leave it to the user to press return himself, or complete a command
using Pane.enter():
>>> pane.enter()
Pane(%1 ...)
Avoid cluttering shell history¶
suppress_history=True can send commands to pane windows and sessions without
them being visible in the history.
>>> pane.send_keys('echo Howdy', enter=True, suppress_history=True)
In this case, Pane.send_keys() has
“ echo Howdy” written, automatically sent, the leading space character
prevents adding it to the user’s shell history. Omitting enter=false means the
default behavior (sending the command) is done, without needing to use
pane.enter() after.
Working with options¶
libtmux provides a unified API for managing tmux options across
Server, Session,
Window, and Pane objects.
Getting options¶
>>> server.show_option('buffer-limit')
50
>>> window.show_options()
{...}
Setting options¶
>>> window.set_option('automatic-rename', False)
Window(@... ...)
>>> window.show_option('automatic-rename')
False
>>> window.unset_option('automatic-rename')
Window(@... ...)
See also
See Options and hooks for more details on options and hooks.
Final notes¶
These objects use tmux’s internal IDs to make servers, sessions, windows, and panes accessible at the object level.
You don’t have to see the tmux session to be able to orchestrate it. After all, Workspace setup uses these same internals to build sessions in the background. :)
See also
If you want to dig deeper, check out API Reference, the code for and our test suite (see Development Tools.)