Skip to main content
The tmux skill enables remote-controlling tmux sessions by sending keystrokes and scraping pane output. Use tmux when you need an interactive TTY.
Use tmux only for interactive TTY tasks. Prefer exec background mode for long-running, non-interactive tasks.

Platform Support

Supported on macOS and Linux. On Windows, use WSL and install tmux inside WSL.

Quickstart (Isolated Socket)

SOCKET_DIR="${NANOBOT_TMUX_SOCKET_DIR:-${TMPDIR:-/tmp}/nanobot-tmux-sockets}"
mkdir -p "$SOCKET_DIR"
SOCKET="$SOCKET_DIR/nanobot.sock"
SESSION=nanobot-python

tmux -S "$SOCKET" new -d -s "$SESSION" -n shell
tmux -S "$SOCKET" send-keys -t "$SESSION":0.0 -- 'PYTHON_BASIC_REPL=1 python3 -q' Enter
tmux -S "$SOCKET" capture-pane -p -J -t "$SESSION":0.0 -S -200
After starting a session, always print monitor commands:
To monitor:
  tmux -S "$SOCKET" attach -t "$SESSION"
  tmux -S "$SOCKET" capture-pane -p -J -t "$SESSION":0.0 -S -200

Socket Convention

  • Use NANOBOT_TMUX_SOCKET_DIR environment variable
  • Default socket path: "$NANOBOT_TMUX_SOCKET_DIR/nanobot.sock"

Targeting Panes and Naming

  • Target format: session:window.pane (defaults to :0.0)
  • Keep names short; avoid spaces
  • Inspect: tmux -S "$SOCKET" list-sessions, tmux -S "$SOCKET" list-panes -a

Finding Sessions

List sessions on your socket:
{baseDir}/scripts/find-sessions.sh -S "$SOCKET"
Scan all sockets:
{baseDir}/scripts/find-sessions.sh --all

Sending Input Safely

Prefer literal sends:
tmux -S "$SOCKET" send-keys -t target -l -- "$cmd"
Send control keys:
tmux -S "$SOCKET" send-keys -t target C-c

Watching Output

Capture recent history:
tmux -S "$SOCKET" capture-pane -p -J -t target -S -200
Wait for prompts:
{baseDir}/scripts/wait-for-text.sh -t session:0.0 -p 'pattern'
Attaching is OK; detach with Ctrl+b d.

Spawning Processes

For Python REPLs, set PYTHON_BASIC_REPL=1 (non-basic REPL breaks send-keys flows).

Orchestrating Coding Agents

tmux excels at running multiple coding agents in parallel:
SOCKET="${TMPDIR:-/tmp}/codex-army.sock"

# Create multiple sessions
for i in 1 2 3 4 5; do
  tmux -S "$SOCKET" new-session -d -s "agent-$i"
done

# Launch agents in different workdirs
tmux -S "$SOCKET" send-keys -t agent-1 "cd /tmp/project1 && codex --yolo 'Fix bug X'" Enter
tmux -S "$SOCKET" send-keys -t agent-2 "cd /tmp/project2 && codex --yolo 'Fix bug Y'" Enter

# Poll for completion (check if prompt returned)
for sess in agent-1 agent-2; do
  if tmux -S "$SOCKET" capture-pane -p -t "$sess" -S -3 | grep -q "โฏ"; then
    echo "$sess: DONE"
  else
    echo "$sess: Running..."
  fi
done

# Get full output from completed session
tmux -S "$SOCKET" capture-pane -p -t agent-1 -S -500

Tips for Parallel Agents

  • Use separate git worktrees for parallel fixes (no branch conflicts)
  • pnpm install first before running codex in fresh clones
  • Check for shell prompt (โฏ or $) to detect completion
  • Codex needs --yolo or --full-auto for non-interactive fixes

Cleanup

Kill a session:
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

{baseDir}/scripts/wait-for-text.sh polls a pane for a regex (or fixed string) with a timeout.
{baseDir}/scripts/wait-for-text.sh -t session:0.0 -p 'pattern' [-F] [-T 20] [-i 0.5] [-l 2000]

Options

  • -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 (integer, default 1000)

Build docs developers (and LLMs) love