Agent skill
tmux
Remote control tmux sessions for interactive CLIs (python, gdb, etc.) by sending keystrokes and scraping pane output.
Install this agent skill to your Project
npx add-skill https://github.com/dmmulroy/.dotfiles/tree/main/home/.pi/agent/skills/tmux
SKILL.md
tmux Skill
Source: https://github.com/mitsuhiko/agent-stuff/blob/main/skills/tmux/SKILL.md
Use tmux as a programmable terminal multiplexer for interactive work. Works on Linux and macOS with stock tmux; avoid custom config by using a private socket.
Quickstart (isolated socket)
SOCKET_DIR=${TMPDIR:-/tmp}/claude-tmux-sockets # well-known dir for all agent sockets
mkdir -p "$SOCKET_DIR"
SOCKET="$SOCKET_DIR/claude.sock" # keep agent sessions separate from your personal tmux
SESSION=claude-python # slug-like names; avoid spaces
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 # watch output
tmux -S "$SOCKET" kill-session -t "$SESSION" # clean up
After starting a session ALWAYS tell the user how to monitor the session by giving them a command to copy paste:
To monitor this session yourself:
tmux -S "$SOCKET" attach -t claude-lldb
Or to capture the output once:
tmux -S "$SOCKET" capture-pane -p -J -t claude-lldb:0.0 -S -200
This must ALWAYS be printed right after a session was started and once again at the end of the tool loop. But the earlier you send it, the happier the user will be.
Socket convention
- Agents MUST place tmux sockets under
CLAUDE_TMUX_SOCKET_DIR(defaults to${TMPDIR:-/tmp}/claude-tmux-sockets) and usetmux -S "$SOCKET"so we can enumerate/clean them. Create the dir first:mkdir -p "$CLAUDE_TMUX_SOCKET_DIR". - Default socket path to use unless you must isolate further:
SOCKET="$CLAUDE_TMUX_SOCKET_DIR/claude.sock". - The
CLAUDE_TMUX_SOCKET_DIRname is preserved for upstream compatibility; using it from Pi is fine.
Targeting panes and naming
- Target format:
{session}:{window}.{pane}, defaults to:0.0if omitted. Keep names short (e.g.,claude-py,claude-gdb). - Use
-S "$SOCKET"consistently to stay on the private socket path. If you need user config, drop-f /dev/null; otherwise-f /dev/nullgives a clean config. - Inspect:
tmux -S "$SOCKET" list-sessions,tmux -S "$SOCKET" list-panes -a.
Finding sessions
- List sessions on your active socket with metadata:
./scripts/find-sessions.sh -S "$SOCKET"; add-q partial-nameto filter. - Scan all sockets under the shared directory:
./scripts/find-sessions.sh --all(usesCLAUDE_TMUX_SOCKET_DIRor${TMPDIR:-/tmp}/claude-tmux-sockets).
Sending input safely
- Prefer literal sends to avoid shell splitting:
tmux -S "$SOCKET" send-keys -t target -l -- "$cmd". - When composing inline commands, use single quotes or ANSI C quoting to avoid expansion:
tmux ... send-keys -t target -- $'python3 -m http.server 8000'. - To send control keys:
tmux ... send-keys -t target C-c,C-d,C-z,Escape, etc.
Watching output
- Capture recent history (joined lines to avoid wrapping artifacts):
tmux -S "$SOCKET" capture-pane -p -J -t target -S -200. - For continuous monitoring, poll with the helper script (below) instead of
tmux wait-for(which does not watch pane output). - You can also temporarily attach to observe:
tmux -S "$SOCKET" attach -t "$SESSION"; detach withCtrl+b d. - When giving instructions to a user, explicitly print a copy/paste monitor command alongside the action; don't assume they remembered the command.
Spawning Processes
Some special rules for processes:
- when asked to debug, use lldb by default
- when starting a python interactive shell, always set the
PYTHON_BASIC_REPL=1environment variable. This is very important as the non-basic console interferes with your send-keys.
Synchronizing / waiting for prompts
- Use timed polling to avoid races with interactive tools. Example: wait for a Python prompt before sending code:
bash
./scripts/wait-for-text.sh -S "$SOCKET" -t "$SESSION":0.0 -p '^>>>' -T 15 -l 4000 - For long-running commands, poll for completion text (
"Type quit to exit","Program exited", etc.) before proceeding.
Interactive tool recipes
- Python REPL:
tmux ... send-keys -- 'python3 -q' Enter; wait for^>>>; send code with-l; interrupt withC-c. Always withPYTHON_BASIC_REPL. - gdb:
tmux ... send-keys -- 'gdb --quiet ./a.out' Enter; disable pagingtmux ... send-keys -- 'set pagination off' Enter; break withC-c; issuebt,info locals, etc.; exit viaquitthen confirmy. - Other TTY apps (ipdb, psql, mysql, node, bash): same pattern—start the program, poll for its prompt, then send literal text and Enter.
Cleanup
- Kill a session when done:
tmux -S "$SOCKET" kill-session -t "$SESSION". - Kill all sessions on a socket:
tmux -S "$SOCKET" list-sessions -F '#{session_name}' | xargs -r -n1 tmux -S "$SOCKET" kill-session -t. - Remove everything on the private socket:
tmux -S "$SOCKET" kill-server.
Helper: wait-for-text.sh
./scripts/wait-for-text.sh polls a pane for a regex (or fixed string) with a timeout. Works on Linux/macOS with bash + tmux + grep.
./scripts/wait-for-text.sh [-L socket-name|-S socket-path] -t session:0.0 -p 'pattern' [-F] [-T 20] [-i 0.5] [-l 2000]
-L/--sockettmux socket name passed totmux -L-S/--socket-pathtmux socket path passed totmux -S-t/--targetpane target (required)-p/--patternregex to match (required); add-Ffor fixed string-Ttimeout seconds (integer, default 15)-ipoll interval seconds (default 0.5)-lhistory lines to search from the pane (integer, default 1000)- Exits 0 on first match, 1 on timeout. On failure prints the last captured text to stderr to aid debugging.
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
pr-walkthrough
Generate an interactive visual walkthrough of any pull/merge request as a local HTML webapp. Produces a multi-slide presentation with SVG diagrams, annotated code, and architecture visuals. Pass a PR/MR URL and optional audience context (e.g. "assume I don't know Rust"). Use when the user says "walkthrough this PR", "explain this MR", "visual walkthrough", "PR presentation", or provides a PR/MR URL and asks for a walkthrough.
tdd
Test-driven development with red-green-refactor loop. Use when user wants to build features or fix bugs using TDD, mentions "red-green-refactor", wants integration tests, or asks for test-first development.
write-a-prd
Create a PRD through user interview, codebase exploration, and module design. Use when user wants to write a PRD, create a product requirements document, or plan a new feature.
grill-me
Interview the user relentlessly about a plan or design until reaching shared understanding, resolving each branch of the decision tree. Use when user wants to stress-test a plan, get grilled on their design, or mentions "grill me".
prd-to-todos
Break a PRD into independently-grabbable file-backed todos using tracer-bullet vertical slices. Use when the user wants to convert a PRD into implementation tasks, create vertical-slice todos, or break down a PRD into work items.
vcs-detect
Detect whether the current project uses jj (Jujutsu) or git for version control. Run this BEFORE any VCS command to use the correct tool.
Didn't find tool you were looking for?