import sys
from fastmux import *fastmux
fastmux is a pythonic binding to tmux. tmux() shows every session, window, and pane as a tree, and tmux(target) returns a live Session, Window, or Pane handle, using standard tmux target syntax such as mysess:1.2, %5, or @3. A Pane’s repr is its current screen, its transcript can be indexed and sliced like a list of lines, any scope can be searched rg-style, and panes are driven with send, send_keys, and friends. fastmux.bg adds named, managed background sessions on top: create-or-reuse a session by name and drive it by sid, so an agent and a user can share the same terminal.
Install
pip install fastmuxYou will also need tmux itself installed and on your PATH.
Getting started
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
pline 23
line 24
line 25
line 26
line 27
line 28
line 29A 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 panes with the directional verbs rsplit, bsplit, lsplit, and asplit (no tmux -h/-v confusion), again without stealing focus:
p.bsplit(size=3, cmd="top")
s.windows1: nbs* (2 panes) @0
1.1: [60x4] %0 python (active)
1.2: [60x3] %1 tmux
Panes can also be driven directly: p.send('ls\n') pastes text and polls for the response, p.send_keys('C-c') sends tmux key names, and p.wait() returns an exit status. See the full docs for the complete API.
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')
hits0: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 30And 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
A handle like p only helps while you can hold it. A background session outlives that: it is created in one tool call, driven from another, and shared with a user who attaches by name. fastmux.bg addresses sessions by sid — a session name, a %pane_id, a handle, or None for the current pane — and start_session creates-or-reuses, so the same line works in every call:
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)The user can watch or type alongside with tmux attach -t fastmux-demo-bg, and polling is seen-state based: output that arrived while nobody was watching satisfies the next poll(sid) immediately, rather than making it wait for yet another change. managed_sessions() lists every session start_session created, and close(sid) kills one:
managed_sessions()close(sid)