| name | tmux-pilot |
| description | Drive tmux from an AI agent — sessions, windows, panes, send commands, capture output, poll agents, browser-like workflow. Cross-platform (Linux/macOS/WSL). Use when the user wants to control terminal layout, launch parallel agents, run commands in background panes, orchestrate multi-pane workflows, or mentions tmux automation. |
tmux-pilot — Agent-Driven tmux Control
tmux-pilot gives AI agents full control over tmux topology: sessions, windows, panes, input routing, and output capture. It's the cross-platform equivalent of cmux for macOS.
Core Concepts
- Session — top-level tmux container (like a project workspace)
- Window — a tab within a session (like a workspace tab)
- Pane — a split region within a window (where commands run)
- Target — tmux addressing:
session:window.pane (e.g., main:0.1)
Detect tmux in a Shell
[ -n "$TMUX" ] || exit 0
ORIGIN_PANE=${TMUX_PANE:?}
CURRENT_SESSION=$(tmux display-message -p -t "$ORIGIN_PANE" '#S')
CURRENT_WINDOW=$(tmux display-message -p -t "$ORIGIN_PANE" '#I')
CURRENT_PANE=$(tmux display-message -p -t "$ORIGIN_PANE" '#P')
echo "Inside tmux: ${CURRENT_SESSION}:${CURRENT_WINDOW}.${CURRENT_PANE}"
Key env vars: $TMUX (socket path), $TMUX_PANE (pane ID like %5). Always derive CURRENT_SESSION and CURRENT_WINDOW from $TMUX_PANE, not from the user's active client, so panes are created in the same window as the running agent instance.
Fast Start — Topology
tmux list-sessions
tmux list-windows -t "$SESSION"
tmux list-panes -t "$SESSION:$WINDOW"
tmux display-message -p '#S:#I.#P'
tmux new-session -d -s work -c /path/to/repo
tmux new-window -t work -n build -c /path/to/repo
tmux split-window -h -t work:0 -c /path/to/repo
tmux split-window -v -t work:0 -c /path/to/repo
tmux select-layout -t work:0 even-horizontal
tmux resize-pane -t work:0.1 -R 20
tmux resize-pane -t work:0.1 -D 10
tmux select-pane -t work:0.1
tmux select-window -t work:1
Send Input to Panes
tmux send-keys -t work:0.1 "npm run build" Enter
tmux send-keys -t work:0.1 C-c
tmux send-keys -t work:0.1 C-l
tmux send-keys -t work:0.1 Escape
tmux send-keys -t work:0.1 Up Enter
tmux send-keys -t work:0.1 "partial command"
Capture Output (Read Pane Content)
This is the key differentiator — reading what's on screen or in scrollback.
tmux capture-pane -t work:0.1 -p
tmux capture-pane -t work:0.1 -p -S -100
tmux capture-pane -t work:0.1 -p -S -
tmux capture-pane -t work:0.1 -p -S -100 > /tmp/pane-output.txt
sleep 3 && tmux capture-pane -t work:0.1 -p | tail -20
Polling Pattern — Launch & Monitor
When launching a process in another pane and waiting for results:
tmux send-keys -t work:0.1 "npm test" Enter
sleep 3
OUTPUT=$(tmux capture-pane -t work:0.1 -p -S -50)
echo "$OUTPUT" | grep -qE "(PASS|FAIL|Error|✓|✗|done)" && echo "Complete"
Keep sleep intervals short (2–5s) for typical commands. Use longer (10–15s) only for builds, installs, or known-slow operations.
Launch Pi Agent in a Pane
[ -n "$TMUX" ] || exit 1
ORIGIN_PANE=${TMUX_PANE:?}
CURRENT_SESSION=$(tmux display-message -p -t "$ORIGIN_PANE" '#S')
CURRENT_WINDOW=$(tmux display-message -p -t "$ORIGIN_PANE" '#I')
NEW_PANE=$(tmux split-window -h -t "$CURRENT_SESSION:$CURRENT_WINDOW" -d -P -F '#P')
TARGET="$CURRENT_SESSION:$CURRENT_WINDOW.$NEW_PANE"
tmux send-keys -t "$TARGET" "pi --print 'Run the tests and fix failures'" Enter
for i in $(seq 1 30); do
sleep 5
OUTPUT=$(tmux capture-pane -t "$TARGET" -p -S -30)
if echo "$OUTPUT" | grep -qE '(❯|→|\$)\s*$'; then
echo "Agent finished"
break
fi
done
Multi-Pane Workspace Setup
tmux new-session -d -s dev -c ~/Projects/myapp
tmux rename-window -t dev:0 "code"
tmux split-window -h -t dev:0 -d -l 40%
tmux split-window -v -t dev:0.1 -d
tmux send-keys -t dev:0.0 "nvim ." Enter
tmux send-keys -t dev:0.1 "npm run dev" Enter
tmux send-keys -t dev:0.2 "npm test -- --watch" Enter
Window/Pane Management
tmux kill-pane -t work:0.1
tmux kill-window -t work:1
tmux kill-session -t old
tmux swap-pane -s work:0.0 -t work:0.1
tmux move-pane -s work:1.0 -t work:0
tmux join-pane -s work:1.0 -t work:0 -h
tmux resize-pane -t work:0.1 -Z
tmux break-pane -t work:0.1 -d
Notifications & Status
tmux display-message "Build complete ✓"
tmux display-message "Agent pane work: done. Close unused pane with: tmux kill-pane -t work:0.1"
tmux send-keys -t work:0.1 "echo 'Done. If this pane is no longer needed, close it with: tmux kill-pane -t work:0.1'" Enter
tmux rename-window -t work:0 "✓ tests"
tmux set-option -t work:0.1 monitor-activity on
tmux set-option -t work:0.1 monitor-silence 30
Session Persistence & Restore
tmux ls
tmux attach -t work
tmux detach-client
tmux rename-session -t old new
For persistent layouts across reboots, use tmux-resurrect or tmuxinator configs.
Environment & Options
tmux set-environment -t work MY_VAR "value"
tmux split-window -h -t work:0 "MY_VAR=value bash"
tmux set-option -g mouse on
tmux set-option -g history-limit 50000
tmux set-option -g remain-on-exit on
Critical Rules — Non-Disruptive Automation
- Create panes in the same window as the running agent. If this Pi instance is running in window
1, every agent-created pane must be inside window 1. Derive the target from $TMUX_PANE with tmux display-message -p -t "$TMUX_PANE" '#S' and '#I', then split "$CURRENT_SESSION:$CURRENT_WINDOW". Never use bare tmux split-window, {last} as the authority for window selection, or tmux new-window for sub-agents unless the user explicitly asks for a new window.
- Use
-d flag when creating panes/windows. This prevents stealing focus from the user's active pane.
- Anchor to session:window.pane targets. Never assume the active pane is your target — always use explicit targets.
- Capture before sending. If unsure of pane state,
capture-pane first to avoid sending input into the wrong context (e.g., a vim session).
- Don't kill panes you didn't create. Only manage panes the agent spawned.
- Clean up or announce cleanup. Track every pane/window you create. When it is no longer useful, either close it (
tmux kill-pane -t <target>) after capturing needed output, or clearly notify the user with the exact tmux kill-pane -t <target> command so idle panes do not stay open unnoticed. Ask before closing long-lived processes the user may want to keep.
- Short poll intervals. 2–5s for fast commands, 10–15s for builds. Don't
sleep 30 unless genuinely needed.
- Check if tmux exists first. Always guard with
[ -n "$TMUX" ] before automation.
Common Pitfalls
- Nested tmux. If pi is already in tmux,
tmux new-session inside it creates a nested session. Use tmux split-window -t "$CURRENT_SESSION:$CURRENT_WINDOW" for sub-agents; use tmux new-window only when the user explicitly asks for a separate window.
- Target syntax.
session:window.pane — window can be name or index, pane is always index.
- send-keys literal vs. key names.
Enter, Escape, Space, C-c are key names. Quoted text is literal. Don't quote key names: tmux send-keys -t t Enter not "Enter".
- capture-pane encoding. Pane content may have ANSI escape codes. Pipe through
sed 's/\x1b\[[0-9;]*m//g' to strip colors if parsing output.
- Pane indices shift. After killing a pane, remaining panes may be renumbered. Always re-query with
list-panes before targeting.
- Wrong window from active client.
tmux display-message -p '#I' can reflect the active client/window instead of the pane running the agent. Use tmux display-message -p -t "$TMUX_PANE" '#I' before creating panes.
- No socket API like cmux. tmux uses the CLI or
tmux -L socketname for alternate sockets. All control is via tmux subcommands.
Quick Reference: Target Formats
| Target | Meaning |
|---|
work | Session "work", current window+pane |
work:0 | Session "work", window 0, current pane |
work:0.1 | Session "work", window 0, pane 1 |
work:build | Session "work", window named "build" |
{last} | Last active pane/window |
{next} | Next pane/window |
%5 | Pane with unique ID %5 (from $TMUX_PANE) |