Remote control tmux sessions for interactive CLIs (python, gdb, node, etc.) by sending keystrokes and scraping pane output. Includes session presets, save/restore, and JSON capture.
Use tmux as a programmable terminal multiplexer for interactive work.
SOCKET_DIR=${TMPDIR:-/tmp}/claude-tmux-sockets
mkdir -p "$SOCKET_DIR"
SOCKET="$SOCKET_DIR/claude.sock"
SESSION=claude-python
# Create and control
tmux -S "$SOCKET" new -d -s "$SESSION" -n shell
tmux -S "$SOCKET" send-keys -t "$SESSION":0.0 -- 'python3 -q' Enter
tmux -S "$SOCKET" capture-pane -p -J -t "$SESSION":0.0 -S -200
tmux -S "$SOCKET" kill-session -t "$SESSION"
./scripts/python-session.sh [session-name]
Creates a Python session with PYTHON_BASIC_REPL=1 set.
./scripts/gdb-session.sh ./binary [session-name]
Creates GDB session with pagination disabled.
./scripts/node-session.sh [session-name]
Creates a Node.js REPL session.
# Save session state
./scripts/save-session.sh claude-python > session.json
# Restore session (recreates panes with correct CWD)
./scripts/restore-session.sh session.json
./scripts/find-sessions.sh -S "$SOCKET"
./scripts/find-sessions.sh --all # All sockets
./scripts/wait-for-text.sh -t session:0.0 -p '^>>>' -T 15
tmux -S "$SOCKET" capture-pane -p -J -t "$SESSION":0.0 -S -200
./scripts/capture-json.sh claude-python:0.0
./scripts/capture-json.sh claude-node:0.0 --last # Last JSON only
$CLAUDE_TMUX_SOCKET_DIR/claude.sock (or ${TMPDIR:-/tmp}/claude-tmux-sockets/claude.sock)-S "$SOCKET" to stay isolated from personal tmux{session}:{window}.{pane} (defaults to :0.0)tmux -S "$SOCKET" send-keys -t "$SESSION":0.0 -l -- "print('hello world')"
tmux -S "$SOCKET" send-keys -t "$SESSION":0.0 C-c # Interrupt
tmux -S "$SOCKET" send-keys -t "$SESSION":0.0 C-d # EOF
tmux -S "$SOCKET" send-keys -t "$SESSION":0.0 C-z # Suspend
tmux -S "$SOCKET" send-keys -t "$SESSION":0.0 -- $'python3 -m http.server 8000'
# Start
tmux -S "$SOCKET" send-keys -t "$SESSION":0.0 -- 'python3 -q' Enter
# Wait for >>>
./scripts/wait-for-text.sh -t "$SESSION":0.0 -p '^>>>'
# Send code
tmux -S "$SOCKET" send-keys -t "$SESSION":0.0 -l -- "import os"
tmux -S "$SOCKET" send-keys -t "$SESSION":0.0 Enter
# Interrupt
tmux -S "$SOCKET" send-keys -t "$SESSION":0.0 C-c
# Start with binary
tmux -S "$SOCKET" send-keys -t "$SESSION":0.0 -- 'gdb --quiet ./a.out' Enter
# Disable paging
tmux -S "$SOCKET" send-keys -t "$SESSION":0.0 -- 'set pagination off' Enter
# Debug commands
tmux -S "$SOCKET" send-keys -t "$SESSION":0.0 -l -- 'break main'
tmux -S "$SOCKET" send-keys -t "$SESSION":0.0 Enter
tmux -S "$SOCKET" send-keys -t "$SESSION":0.0 -l -- 'run'
# When breakpoint hits
tmux -S "$SOCKET" send-keys -t "$SESSION":0.0 -l -- 'bt full' # Backtrace
tmux -S "$SOCKET" send-keys -t "$SESSION":0.0 -l -- 'info locals'
# Exit
tmux -S "$SOCKET" send-keys -t "$SESSION":0.0 -l -- 'quit'
tmux -S "$SOCKET" send-keys -t "$SESSION":0.0 -l -- 'y'
Same pattern applies: start program, poll for prompt, send text.
ipdb, pdb - Python debuggerspsql, mysql - Database clientsnode - Node.js REPL# Kill specific session
tmux -S "$SOCKET" kill-session -t "$SESSION"
# Kill all sessions on socket
tmux -S "$SOCKET" list-sessions -F '#{session_name}' | xargs -r -n1 tmux -S "$SOCKET" kill-session -t
# Kill server (all sessions)
tmux -S "$SOCKET" kill-server
-J to join wrapped lineswait-for-text.sh instead of tmux wait-for