AgentSkillsCN

tmux

对于任何交互式或长时间运行的命令,都应使用 tmux。在 tmux 中启动命令,定期查看输出,与提示符互动——相比在 Bash 中阻塞等待,tmux 能带来更快速的反馈。

SKILL.md
--- frontmatter
name: tmux
description: "Use tmux for any interactive or long-running command. Start it in tmux, check output periodically, interact with prompts — faster feedback than blocking on bash."
license: Vibecoded

tmux Skill

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.

When to Reach for tmux

Default to tmux for any command that isn't a quick one-shot. If you know the command will:

  • Produce streaming output you need to read and react to
  • Ask for input, confirmations, or selections
  • Take more than a few seconds and you want to check progress
  • Run interactively (installers, wizards, watch-mode tools, test runners)

...then start it in tmux instead of blocking on bash. The workflow is:

  1. Start the command in a tmux session
  2. Check output with capture-pane periodically
  3. Interact — send input, respond to prompts, ctrl-c if needed
  4. Clean up the session when done

This is faster because you see partial output immediately, react to errors early, and never get stuck waiting for a blocking command to finish. You stay in control.

Don't use tmux for: quick one-shot commands (git status, ls, cat, grep), simple non-interactive CLIs, or file operations.

Quickstart (isolated socket)

bash
SOCKET_DIR=${TMPDIR:-/tmp}/pi-tmux-sockets  # well-known dir for all agent sockets
mkdir -p "$SOCKET_DIR"
SOCKET="$SOCKET_DIR/pi.sock"                # keep agent sessions separate from your personal tmux
SESSION=pi-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 ready-to-copy-paste command with the fully resolved absolute socket path — never use $SOCKET, $TMPDIR, or any variable. The user's shell may not have these set.

Example (adapt session name):

code
To monitor this session yourself:
  tmux -S /var/folders/xx/.../pi-tmux-sockets/pi.sock attach -t pi-lldb

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 PI_TMUX_SOCKET_DIR (defaults to ${TMPDIR:-/tmp}/pi-tmux-sockets) and use tmux -S "$SOCKET" so we can enumerate/clean them. Create the dir first: mkdir -p "$PI_TMUX_SOCKET_DIR".
  • Default socket path to use unless you must isolate further: SOCKET="$PI_TMUX_SOCKET_DIR/pi.sock".

Targeting panes and naming

  • Target format: {session}:{window}.{pane}, defaults to :0.0 if omitted. Keep names short (e.g., pi-py, pi-gdb).
  • Use -S "$SOCKET" consistently to stay on the private socket path. If you need user config, drop -f /dev/null; otherwise -f /dev/null gives 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-name to filter.
  • Scan all sockets under the shared directory: ./scripts/find-sessions.sh --all (uses PI_TMUX_SOCKET_DIR or ${TMPDIR:-/tmp}/pi-tmux-sockets).

Sending input safely

  • Prefer literal sends to avoid shell splitting: tmux -L "$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 -L "$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 -L "$SOCKET" attach -t "$SESSION"; detach with Ctrl+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=1 environment 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 -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 with C-c. Always with PYTHON_BASIC_REPL.
  • gdb: tmux ... send-keys -- 'gdb --quiet ./a.out' Enter; disable paging tmux ... send-keys -- 'set pagination off' Enter; break with C-c; issue bt, info locals, etc.; exit via quit then confirm y.
  • 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.

bash
./scripts/wait-for-text.sh -t session:0.0 -p 'pattern' [-F] [-T 20] [-i 0.5] [-l 2000]
  • -t/--target pane target (required)
  • -p/--pattern regex to match (required); add -F for fixed string
  • -T timeout seconds (integer, default 15)
  • -i poll interval seconds (default 0.5)
  • -l history 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.