tmux

Capture and inspect content from tmux sessions, windows, and panes — locally or over SSH. Useful for sharing terminal output with LLMs, debugging across multiple terminals, or monitoring long-running processes.

SSH

All capture and list functions accept SSH kwargs to target a remote machine: use host for an SSH alias, or ip + user + optional keyfile.

pane(host='hack')
windows(ip='1.2.3.4', user='ubuntu', keyfile='~/.ssh/id_rsa')

source

shell_ret


def shell_ret(
    cmd:str, capture_output:bool=True, text:bool=True, ret:bool=True, host:str=None, # Optional SSH Host
    ip:str=None, # Optional SSH IP
    user:str=None, # Optional SSH user
    keyfile:str=None, # Optional SSH keyfile
):

Run shell command locally or over ssh (use host for alias, or ip/user/keyfile)

print(shell_ret('du -sh'))
232K    .
print(shell_ret('du -sh', host='hack'))
ssh: Could not resolve hostname hack: nodename nor servname provided, or not known

source

set_default_history


def set_default_history(
    n:int
):

Set the default number of lines to capture from tmux history

pane


source

pane


def pane(
    n:int=None, # Number of scrollback lines to capture, in addition to visible area (None uses default_tmux_lines, which is 500 if not otherwise set)
    pane:int | str=None, # Pane number to capture from (accepts both integers for window IDs and "%{int}" for global pane IDs)
    session:str=None, # Session name to target
    window:int=None, # Window number to target
    capture_output:bool=True, text:bool=True, ret:bool=True, host:str=None, # Optional SSH Host
    ip:str=None, # Optional SSH IP
    user:str=None, # Optional SSH user
    keyfile:str=None, # Optional SSH keyfile
):

Grab the tmux history in plain text

# print(pane(1))
# print(pane(1, host='hack'))

list_panes


source

list_panes


def list_panes(
    session:str=None, # Session name to list panes from
    window:int=None, # Window number to list panes from
    capture_output:bool=True, text:bool=True, ret:bool=True, host:str=None, # Optional SSH Host
    ip:str=None, # Optional SSH IP
    user:str=None, # Optional SSH user
    keyfile:str=None, # Optional SSH keyfile
):

List panes for a session/window (or current if none specified)

print(list_panes(window=0))
0: [97x26] [history 1963/2000, 868118 bytes] %56
1: [90x26] [history 405/2000, 158948 bytes] %81
2: [97x25] [history 458/2000, 115648 bytes] %44 (active)
3: [90x25] [history 14/2000, 18831 bytes] %77
print(list_panes(window=0, host='hack'))
ssh: Could not resolve hostname hack: nodename nor servname provided, or not known

panes


source

panes


def panes(
    session:str=None, # Session name to target
    window:int=None, # Window number to target
    n:int=None, # Number of scrollback lines to capture
    capture_output:bool=True, text:bool=True, ret:bool=True, host:str=None, # Optional SSH Host
    ip:str=None, # Optional SSH IP
    user:str=None, # Optional SSH user
    keyfile:str=None, # Optional SSH keyfile
):

Grab history from all panes in a session/window

from pprint import pprint
# pprint(panes(window=0, n=10))
# pprint(panes(n=10, host='hack'))

list_windows


source

list_windows


def list_windows(
    session:str=None, # Session name to list windows from
    capture_output:bool=True, text:bool=True, ret:bool=True, host:str=None, # Optional SSH Host
    ip:str=None, # Optional SSH IP
    user:str=None, # Optional SSH user
    keyfile:str=None, # Optional SSH keyfile
):

List all windows in a session

print(list_windows())
0: bash* (4 panes) [188x52] [layout 37fe,188x52,0,0[188x26,0,0{97x26,0,0,56,90x26,98,0,81},188x25,0,27{97x25,0,27,44,90x25,98,27,77}]] @10 (active)
print(list_windows(host='hack'))
ssh: Could not resolve hostname hack: nodename nor servname provided, or not known

windows


source

windows


def windows(
    session:str=None, # Session name to target
    n:int=None, # Number of scrollback lines to capture
    capture_output:bool=True, text:bool=True, ret:bool=True, host:str=None, # Optional SSH Host
    ip:str=None, # Optional SSH IP
    user:str=None, # Optional SSH user
    keyfile:str=None, # Optional SSH keyfile
):

Grab history from all panes in all windows of a session as {'win_num:name': {pane_num: content}}

# pprint(windows())
# pprint(windows(host='hack'))

list_sessions


source

list_sessions


def list_sessions(
    capture_output:bool=True, text:bool=True, ret:bool=True, host:str=None, # Optional SSH Host
    ip:str=None, # Optional SSH IP
    user:str=None, # Optional SSH user
    keyfile:str=None, # Optional SSH keyfile
):

List all tmux sessions

print(list_sessions())
10: 1 windows (created Tue Apr 21 12:39:41 2026) (attached)
23: 1 windows (created Mon May 11 10:38:18 2026)
bgtmux-369d887b92: 1 windows (created Fri May  1 13:29:21 2026)
bgtmux-cd962474af: 1 windows (created Fri May  1 14:00:25 2026)
print(list_sessions(host='hack'))
ssh: Could not resolve hostname hack: nodename nor servname provided, or not known

sessions


source

sessions


def sessions(
    n:int=None, # Number of scrollback lines to capture
    capture_output:bool=True, text:bool=True, ret:bool=True, host:str=None, # Optional SSH Host
    ip:str=None, # Optional SSH IP
    user:str=None, # Optional SSH user
    keyfile:str=None, # Optional SSH keyfile
):

Grab history from all panes in all windows of all sessions as {session: {'win_num:name': {pane_num: content}}}

# pprint(sessions())
# pprint(sessions(host='hack'))

Searching nested results

windows() and sessions() return nested dicts. Use flatten_dict to search them as (path, content) tuples, where path identifies the session/window/pane source. The path string uses // separators showing the hierarchy, e.g. "mysession//0:bash//1" means session "mysession", window 0 named "bash", pane 1.

For example, find error lines across all tmux history:

errors = [(path, line)
          for path, content in flatten_dict(sessions(n=2000))
          for line in content.splitlines()
          if 'error' in line.lower()]

Or find panes containing a command you remember:

found = {path: content for path, content in flatten_dict(windows(n=2000)) if 'curl' in content}

source

flatten_dict


def flatten_dict(
    d, parent_key:str='', sep:str='//'
):

Flatten nested dict into list of (key_path, value) tuples

nested = {
    'session1': {
        '0:bash': {0: 'some content', 1: 'more content'},
        '1:vim': {0: 'editing file'}
    }
}
for path, content in flatten_dict(nested): print(f"{path}: {content}")
session1//0:bash//0: some content
session1//0:bash//1: more content
session1//1:vim//0: editing file