
Tmux
- 77 installs
- 15 repo stars
- Updated August 1, 2026
- connorads/dotfiles
Drives interactive CLIs (Python, gdb, psql) via tmux by sending keystrokes and capturing pane output, including remote execution over SSH.
About
Controls interactive terminal applications like Python REPLs, gdb, and psql through tmux by sending keystrokes and scraping pane output. A developer uses it when a CLI requires TTY interaction or remote observation of output.
- Sends keystrokes and captures pane output to drive interactive CLIs
- Includes polling for prompts and remote execution over SSH with zsh wrapping
Tmux by the numbers
- 77 all-time installs (skills.sh)
- Ranked #269 of 550 CLI & Terminal skills by installs in the Skillselion catalog
- Data as of Aug 2, 2026 (Skillselion catalog sync)
npx skills add https://github.com/connorads/dotfiles --skill tmuxAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 77 |
|---|---|
| repo stars | ★ 15 |
| Last updated | August 1, 2026 |
| Repository | connorads/dotfiles ↗ |
What it does
Drives interactive CLIs (Python, gdb, psql) via tmux by sending keystrokes and capturing pane output, including remote execution over SSH.
Files
tmux Skill
Use tmux to control interactive terminal applications by sending keystrokes and capturing output.
When to Use
- Running interactive REPLs (python, node, psql)
- Debugging with gdb/lldb
- Any CLI that requires TTY interaction
- Remote execution where you need to observe output
Core Pattern
# Create session
tmux new-session -d -s "$SESSION" -x 120 -y 40
# Send commands
tmux send-keys -t "$SESSION" "python3" Enter
# Capture output
tmux capture-pane -t "$SESSION" -p
# Wait for prompt (poll)
for i in {1..30}; do
output=$(tmux capture-pane -t "$SESSION" -p)
if echo "$output" | grep -q ">>>"; then break; fi
sleep 0.5
done
# Cleanup
tmux kill-session -t "$SESSION"Remote Execution (Codespaces/SSH)
For mise-installed tools, wrap in zsh:
# Non-interactive (won't hang)
ssh host 'zsh -c "source ~/.zshrc; tmux new-session -d -s mysession; tmux send-keys -t mysession python Enter"'
# Interactive (for tmux attach) - needs TTY
ssh host -t 'zsh -ilc "tmux attach -t mysession"'Critical: Use zsh -c "source ~/.zshrc; ..." not zsh -lc to avoid hangs.
User Notification
After starting a session, ALWAYS print:
To monitor: tmux attach -t $SESSION
To capture: tmux capture-pane -t $SESSION -pTips
- Use
-x 120 -y 40for consistent pane size - Poll with
capture-pane -prather thanwait-for - Send literal text with
-lflag to avoid shell expansion - Control keys:
C-c(interrupt),C-d(EOF),Escape - For Python REPL: set
PYTHON_BASIC_REPL=1to avoid fancy console interference
Helper Scripts
wait-for-text.sh
Poll tmux pane for a text pattern with timeout:
scripts/wait-for-text.sh -t session:0.0 -p '^>>>' -T 15find-sessions.sh
List tmux sessions, optionally filtered:
scripts/find-sessions.sh -q claude # filter by name
scripts/find-sessions.sh --all # all sessions#!/usr/bin/env bash
# List tmux sessions, optionally filtered by name
# Usage: find-sessions.sh [-q QUERY] [-S SOCKET] [--all]
set -euo pipefail
usage() {
cat <<EOF
Usage: $(basename "$0") [-q QUERY] [-S SOCKET] [--all]
List tmux sessions with optional filtering.
Options:
-q QUERY filter sessions by name (grep pattern)
-S SOCKET use specific tmux socket path
--all show all info (windows, panes, commands)
-h show this help
Examples:
$(basename "$0") # list all sessions
$(basename "$0") -q claude # sessions matching 'claude'
$(basename "$0") --all # detailed view
$(basename "$0") -S /tmp/my.sock # specific socket
EOF
exit 1
}
query=""
socket=""
show_all=false
while [[ $# -gt 0 ]]; do
case $1 in
-q) query="$2"; shift 2 ;;
-S) socket="$2"; shift 2 ;;
--all) show_all=true; shift ;;
-h|--help) usage ;;
*) echo "Unknown option: $1" >&2; usage ;;
esac
done
tmux_cmd=(tmux)
[[ -n "$socket" ]] && tmux_cmd+=(-S "$socket")
# Check if tmux server is running
if ! "${tmux_cmd[@]}" list-sessions &>/dev/null; then
echo "No tmux sessions (server not running)" >&2
exit 0
fi
if $show_all; then
# Detailed view with windows and panes
format="#{session_name}|#{session_windows}|#{session_created}|#{?session_attached,attached,detached}"
"${tmux_cmd[@]}" list-sessions -F "$format" | while IFS='|' read -r name windows created attached; do
[[ -n "$query" ]] && ! echo "$name" | grep -qE "$query" && continue
created_fmt=$(date -d "@$created" '+%Y-%m-%d %H:%M' 2>/dev/null || date -r "$created" '+%Y-%m-%d %H:%M' 2>/dev/null || echo "$created")
echo "Session: $name ($windows windows, $attached, created $created_fmt)"
# List windows and their commands
"${tmux_cmd[@]}" list-windows -t "$name" -F " Window #{window_index}: #{window_name} (#{pane_current_command})" 2>/dev/null || true
done
else
# Simple list
"${tmux_cmd[@]}" list-sessions -F "#{session_name}" | while read -r name; do
[[ -n "$query" ]] && ! echo "$name" | grep -qE "$query" && continue
echo "$name"
done
fi
#!/usr/bin/env bash
# Poll tmux pane for a text pattern with timeout
# Usage: wait-for-text.sh -t session:0.0 -p '^>>>' -T 15
set -euo pipefail
usage() {
cat <<EOF
Usage: $(basename "$0") -t TARGET -p PATTERN [-T TIMEOUT] [-i INTERVAL]
Poll a tmux pane until a pattern appears in the output.
Options:
-t TARGET tmux target (session, session:window, or session:window.pane)
-p PATTERN grep pattern to wait for
-T TIMEOUT timeout in seconds (default: 30)
-i INTERVAL poll interval in seconds (default: 0.5)
-h show this help
Examples:
$(basename "$0") -t mysession -p '^>>>' # wait for Python prompt
$(basename "$0") -t dev:0.0 -p 'gdb>' -T 60 # wait for gdb prompt
$(basename "$0") -t repl -p 'error' -i 0.2 # quick polling for error
EOF
exit 1
}
target=""
pattern=""
timeout=30
interval=0.5
while getopts "t:p:T:i:h" opt; do
case $opt in
t) target="$OPTARG" ;;
p) pattern="$OPTARG" ;;
T) timeout="$OPTARG" ;;
i) interval="$OPTARG" ;;
h) usage ;;
*) usage ;;
esac
done
[[ -z "$target" ]] && { echo "Error: -t TARGET required" >&2; usage; }
[[ -z "$pattern" ]] && { echo "Error: -p PATTERN required" >&2; usage; }
# Check session exists
if ! tmux has-session -t "${target%%:*}" 2>/dev/null; then
echo "Error: session '${target%%:*}' does not exist" >&2
exit 1
fi
elapsed=0
while (( $(echo "$elapsed < $timeout" | bc -l) )); do
output=$(tmux capture-pane -t "$target" -p 2>/dev/null || true)
if echo "$output" | grep -qE "$pattern"; then
echo "Pattern '$pattern' found after ${elapsed}s"
exit 0
fi
sleep "$interval"
elapsed=$(echo "$elapsed + $interval" | bc -l)
done
echo "Timeout (${timeout}s) waiting for pattern '$pattern'" >&2
echo "Last output:" >&2
tmux capture-pane -t "$target" -p | tail -20 >&2
exit 1