fastmux

Drive and inspect tmux from Python: live session, window, and pane handles with CLI-style reprs

fastmux controls and inspects tmux from Python. It exposes live Session, Window, and Pane objects for applications and agents that need to drive terminal programs or share a terminal with a user.

tmux() displays sessions, windows, and panes as a tree. tmux(target) returns a handle using standard target syntax, such as mysess:1.2, %5, or @3. A pane displays its current screen and exposes its transcript as an indexable, sliceable sequence of lines. Search works across panes, windows, or sessions with rg-style results.

Use send and send_keys to interact with a pane. fastmux.bg provides named background sessions that can be created or reused across tool calls and attached to by a user.

Install

pip install fastmux

You will also need tmux itself installed and on your PATH.

Getting started

import sys
from fastmux import *

Start a throwaway session running anything you like. It’s created detached, so your terminal is untouched:

s = new_session([sys.executable,'-u','-c','import time\n'
                                          'for i in range(30): print(f"line {i}")\n'
                                          'time.sleep(600)'],
                width=60, height=8)
p = s.pane
p.poll(wait_ms=2000)  # wait for output to arrive
p
line 23
line 24
line 25
line 26
line 27
line 28
line 29

A Pane’s repr is its live screen. The whole transcript (scrollback included) works like a list of lines:

len(p), p[0], p[-1], p[5:7].lines
(30, 'line 0', 'line 29', ('line 5', 'line 6'))

Split to the right, below, left, or above with rsplit, bsplit, lsplit, and asplit (no tmux -h/-v confusion). These operations preserve the current focus:

p.bsplit(size=3, cmd="top")
s.windows
1: nbs* (2 panes) @0
  1.1: [60x4] %0 python (active)
  1.2: [60x3] %1 tmux

Pane methods support direct interaction and waiting:

  • p.send('ls\n') pastes text and polls for a response.
  • p.send_keys('C-c') sends tmux key names.
  • p.click('[menu]') clicks a coordinate or matching on-screen text.
  • p.wheel() scrolls.
  • p.wait() returns an exit status.

Use until='READY' to wait for a screen regex match, or settle_ms=300 to wait until the screen stops changing. See the full API documentation.

Search any scope (one pane, a window, a session, or every terminal you have) and get rg-style hits whose target can be pasted straight back into tmux():

hits = s.search('line 2')
hits
0:1.1:2: line 2
0:1.1:20: line 20
0:1.1:21: line 21
0:1.1:22: line 22
0:1.1:23: line 23
0:1.1:24: line 24
0:1.1:25: line 25
0:1.1:26: line 26
0:1.1:27: line 27
0:1.1:28: line 28
0:1.1:29: line 29
tmux(hits[0].target)[-3:]
line 27
line 28
line 29
── 0:1.1 %0 · lines 27-30 of 30

And tmux() alone shows everything as a tree of sessions, windows, and panes:

tmux()
0: 1 windows
  1: nbs* (2 panes) @0
    1.1: [60x4] %0 python (active)
    1.2: [60x3] %1 top
s.kill()

Background sessions

Named background sessions can be created in one tool call and controlled in later calls without retaining a Python handle. A user can attach to the same session.

fastmux.bg accepts a sid identifying a session name, a %pane_id, a handle, or None for the current pane. start_session creates a session or reuses an existing one:

from fastmux.bg import *
sid = 'fastmux-demo-bg'
start_session(sid, width=60, height=8)
send(sid, 'echo $((6*7)) apples\n', wait_ms=2000)

A user can watch or type in the session with tmux attach -t fastmux-demo-bg. Polling tracks output already seen by the caller. New output that arrived between polls satisfies the next poll(sid) immediately.

managed_sessions() lists sessions created by start_session. close(sid) kills the specified session:

managed_sessions()
close(sid)