tmux
Original:🇺🇸 English
Translated
2 scriptsChecked / no sensitive code detected
Control tmux sessions, windows, and panes via the tmux CLI. Covers session management, window/pane operations, sending keys, reading output, and pane decoration.
2installs
Sourcehalfwhey/skills
Added on
NPX Install
npx skill4agent add halfwhey/skills tmuxTags
Translated version includes tags in frontmatterSKILL.md Content
View Translation Comparison →tmux
Use the CLI to interact with running tmux sessions.
tmuxGolden Rule: Always Resolve pane_id First
Before interacting with any pane, resolve its unique . Use this as the canonical handle for all subsequent operations — it is stable, unambiguous, and survives window/session renames.
pane_idbash
# From a user-supplied number (e.g. "pane 1" in the current window)
PANE_ID=$(tmux display-message -t :.1 -p '#{pane_id}') # → %42
# From a full target
PANE_ID=$(tmux display-message -t 0:2.1 -p '#{pane_id}')
# pane_id is valid as a -t target for all pane-level commands
tmux send-keys -t %42 "echo hello" Enter
tmux capture-pane -t %42 -p
tmux select-pane -t %42 -T "my title"
tmux kill-pane -t %42A pane's changes when it is destroyed and recreated — even at the same index. This means using automatically treats recreated panes as new sessions.
pane_idpane_idResolving Panes by Description
The user may refer to panes informally — "the other pane", "the pane running vim", "the shell on the right". Resolve these yourself before falling back to asking:
bash
# List all panes in the current window (excluding yourself)
tmux list-panes -F '#{pane_id} #{pane_current_command}' | grep -v "^$TMUX_PANE "
# "The other pane" / "the only other pane" — works when there are exactly 2 panes
PANE_ID=$(tmux list-panes -F '#{pane_id}' | grep -v "^$TMUX_PANE$")
# "The pane running vim"
PANE_ID=$(tmux list-panes -F '#{pane_id} #{pane_current_command}' | grep vim | awk '{print $1}')Use (your own pane ID, set automatically by tmux) to exclude yourself from the list.
$TMUX_PANEIf the description is ambiguous or matches multiple panes, ask the user:
- Run — numbered overlays appear for 5 seconds
tmux display-panes -d 5000 - Ask the user which number
- Resolve with :
:.NbashPANE_ID=$(tmux display-message -t :.1 -p '#{pane_id}')
Reading Pane Output
Use the script — do not use raw for reading command output.
${CLAUDE_SKILL_DIR}/scripts/read-tmuxcapture-panebash
${CLAUDE_SKILL_DIR}/scripts/read-tmux %42 # delta mode (default) — for shell output
${CLAUDE_SKILL_DIR}/scripts/read-tmux --tui %42 # TUI mode — diff of changed screen regions
${CLAUDE_SKILL_DIR}/scripts/read-tmux --full %42 # TUI mode — always full screen (no diff)Delta mode (default)
- First call: captures full scrollback, saves position marker, prints ≤4KB
- Subsequent calls: captures only new lines since last read
- No changes: prints
(no new output)
TUI mode (--tui
)
--tuiUse for any full-screen application (vim, htop, lazygit, top, etc.).
- First call: captures full visible screen, saves snapshot
- Subsequent calls: diffs against previous capture
- If ≤50% of lines changed → shows unified diff (only changed regions)
- If >50% of lines changed → shows full screen (heavy redraw fallback)
- No changes: prints
(no changes on screen)
Output capping
All output is capped at first 2000 + last 2000 bytes; middle is truncated if exceeded.
State directory
State is stored in :
/tmp/tmux-skill/<pane_id>/position ← line counter for delta mode
tui_prev ← last TUI capture for diffingPane Decoration
Both and auto-decorate panes on first interaction — a yellow "● Operated by Claude" bar appears at the top of the pane. No manual decoration needed.
${CLAUDE_SKILL_DIR}/scripts/read-tmux${CLAUDE_SKILL_DIR}/scripts/send-tmuxTo release decoration when done with a pane:
bash
tmux set-option -p -t %42 -u pane-border-status 2>/dev/null || true
tmux set-option -p -t %42 -u pane-border-format 2>/dev/null || trueSending Commands
Use — it auto-decorates the pane and passes all arguments to .
send-tmuxtmux send-keysbash
# Run a command
${CLAUDE_SKILL_DIR}/scripts/send-tmux %42 "npm test" Enter
# Interrupt
${CLAUDE_SKILL_DIR}/scripts/send-tmux %42 C-c
# Send EOF / exit shell
${CLAUDE_SKILL_DIR}/scripts/send-tmux %42 C-d
# Quit a pager
${CLAUDE_SKILL_DIR}/scripts/send-tmux %42 qSessions
bash
# List
tmux list-sessions
tmux list-sessions -F '#{session_name} (#{session_windows} windows)'
# Create (detached)
tmux new-session -d -s <name> [-c <start-dir>]
# Rename
tmux rename-session -t <old> <new>
# Kill
tmux kill-session -t <name>
# Check existence
tmux has-session -t <name> 2>/dev/null && echo existsWindows
bash
# List
tmux list-windows -t <session>
tmux list-windows -t <session> -F '#{window_index}: #{window_name}'
# Create
tmux new-window -t <session> -n <name> [-c <dir>]
# Rename
tmux rename-window -t <session>:<index> <new-name>
# Move to another session or index
tmux move-window -s <session>:<index> -t <dst-session>:<new-index>
# Swap two windows
tmux swap-window -s <session>:<a> -t <session>:<b>
# Kill
tmux kill-window -t <session>:<index>Panes
bash
# List (resolve pane_id for any pane you'll interact with)
tmux list-panes -t <session>:<window> -F '#{pane_index} #{pane_id} #{pane_current_command}'
tmux list-panes -a -F '#{session_name}:#{window_index}.#{pane_index} #{pane_id} #{pane_current_command}'
# Create — split relative to Claude's own pane so it opens in the right window.
# $TMUX_PANE is Claude's pane_id, set automatically by tmux.
# -P -F prints the new pane's id directly.
PANE_ID=$(tmux split-window -h -t "$TMUX_PANE" -P -F '#{pane_id}') # side by side
PANE_ID=$(tmux split-window -v -t "$TMUX_PANE" -P -F '#{pane_id}') # top/bottom
# Rename (sets title shown in pane border)
tmux select-pane -t %42 -T <title>
# Move pane to another window
tmux move-pane -s %42 -t <dst-session>:<dst-window>
# Break pane out into its own window
tmux break-pane -t %42 -n <new-window-name>
# Join a window into another as a pane
tmux join-pane -s <src-window> -t <dst-window>
# Swap two panes
tmux swap-pane -s %42 -t %99
# Kill
tmux kill-pane -t %42Querying State
bash
# Pane properties
tmux display-message -t %42 -p '#{pane_id}'
tmux display-message -t %42 -p '#{pane_current_command}'
tmux display-message -t %42 -p '#{pane_current_path}'
tmux display-message -t %42 -p '#{pane_pid}'
# Useful format variables
# #{pane_id} unique pane identifier (%42)
# #{pane_index} position within window (can be reused after kill)
# #{pane_current_command} process running in pane
# #{pane_current_path} working directory
# #{pane_pid} PID of pane shell
# #{session_name} session name
# #{window_index} window number
# #{window_name} window namePractical Patterns
Poll until a command finishes
bash
${CLAUDE_SKILL_DIR}/scripts/send-tmux %42 "make build && echo __DONE__" Enter
while ! ${CLAUDE_SKILL_DIR}/scripts/read-tmux %42 | grep -q "__DONE__"; do sleep 0.5; doneOpen a new pane for a project task
bash
WINDOW=$(tmux new-window -t myproject -n build -P -F '#{window_index}')
PANE_ID=$(tmux display-message -t "myproject:${WINDOW}.0" -p '#{pane_id}')
tmux select-pane -t "$PANE_ID" -T "● claude"
tmux send-keys -t "$PANE_ID" "make build" EnterInterrupt and re-run
bash
tmux send-keys -t %42 C-c
sleep 0.2
tmux send-keys -t %42 "make build" Enter