Skip to main content

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'))
480K    .
print(shell_ret('du -sh', host='hack'))
48G .

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: [89x27] [history 396/2000, 2409771 bytes] %0
1: [89x26] [history 19/2000, 23461 bytes] %21
2: [87x27] [history 1751/2000, 6228987 bytes] %17
3: [87x26] [history 556/2000, 208537 bytes] %22 (active)
print(list_panes(window=0, host='hack'))
0: [84x21] [history 263/2000, 386400 bytes] %0
1: [84x21] [history 0/2000, 1648 bytes] %3
2: [84x21] [history 1995/2000, 3844365 bytes] %1
3: [84x21] [history 0/2000, 3724 bytes] %2 (active)

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) [177x54] [layout 2f91,177x54,0,0{89x54,0,0[89x27,0,0,0,89x26,0,28,21],87x54,90,0[87x27,90,0,17,87x26,90,28,22]}] @0 (active)
1: bash- (2 panes) [177x54] [layout 5fd7,177x54,0,0{88x54,0,0,4,88x54,89,0,5}] @1
print(list_windows(host='hack'))
0: bash* (4 panes) [169x43] [layout 30b2,169x43,0,0{84x43,0,0[84x21,0,0,0,84x21,0,22,3],84x43,85,0[84x21,85,0,1,84x21,85,22,2]}] @0 (active)

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())
0: 2 windows (created Fri Oct 16 12:03:34 2026) (attached)
print(list_sessions(host='hack'))
0: 1 windows (created Thu Sep 17 00:43:58 2026)

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