| name | tmux |
| description | Run long-lived or background commands inside detached tmux sessions instead of the agent's own background shell, so that (1) a human can attach and watch the job live, and (2) the job's lifetime is decoupled from the parent shell / agent session and survives its death. Use when launching builds, servers, watchers, test runs, migrations, or any process that should keep running independently and be observable by the user. Triggers: "run in the background", "keep it running", "start a server", "I want to watch it", "バックグラウンドで動かして", "監視できるように", "tmuxで動かして". |
| user-invocable | true |
tmux as a Background Job Manager
Why tmux instead of a plain background shell
A command launched with the agent's own background shell (cmd &, run-in-background) has two problems:
- Not observable by the human. The user cannot easily inspect the live state
of a process buried inside the agent's shell.
- Tied to the parent's lifetime. If the agent session or parent shell dies,
the process dies with it.
tmux fixes both: the tmux server is a separate long-lived process, so a detached
session keeps running even after the parent shell / agent exits, and a human can
tmux attach at any time to watch and interact with it.
Prefer this skill over the agent's background shell whenever a job is long-running,
needs to outlive the current session, or the user wants to monitor it.
Conventions used below
- Session name:
job-<slug> (so tmux ls clearly shows agent-managed jobs).
- State dir:
${TMPDIR:-/tmp}/claude-tmux-jobs, holding <slug>.log and <slug>.exit.
- Always set a generous virtual size with
-x/-y; detached sessions default to
80x24 and capture-pane truncates wider output.
JOB=build
DIR="${TMPDIR:-/tmp}/claude-tmux-jobs"; mkdir -p "$DIR"
Start a job (default pattern)
Output stays visible in the pane (so a human can attach and watch), is mirrored to a
log file (so the agent can parse it even after the session ends), and the exit code is
written to a sentinel file on completion.
tmux new-session -d -s "job-$JOB" -x 220 -y 50 -c "$PWD" \
"bash -lc 'npm run build; echo \$? > \"$DIR/$JOB.exit\"'"
tmux pipe-pane -t "job-$JOB" -o "cat >> \"$DIR/$JOB.log\""
Useful new-session flags:
-c DIR — working directory.
-e KEY=VAL — inject an environment variable (repeatable).
-x W -y H — virtual terminal size for the detached session.
Check status
By default tmux destroys the session when its command exits, so session presence is
the running/done signal; the exit file gives the exit code once finished.
tmux has-session -t "job-$JOB" 2>/dev/null && echo RUNNING || echo DONE
cat "$DIR/$JOB.exit" 2>/dev/null
tmux ls -F '#{session_name}' | grep '^job-'
Read output
tail -n 50 "$DIR/$JOB.log"
tmux capture-pane -pt "job-$JOB" -S -
- The log file is authoritative after completion (the session and its pane are gone).
capture-pane -p prints the live pane; -S - starts from the beginning of history,
-S -200 grabs the last 200 lines.
Human monitoring
Tell the user they can watch or take over at any time:
tmux attach -t job-build
tmux attach -r -t job-build
Interact / stop
tmux send-keys -t "job-$JOB" 'some input' Enter
tmux send-keys -t "job-$JOB" C-c
tmux kill-session -t "job-$JOB"
Block until done (when the agent must wait)
Non-blocking polling (has-session / pane_dead) is preferred so the agent stays
responsive. When a hard wait is genuinely needed, use the wait-for channel:
tmux new-session -d -s "job-$JOB" -x 220 -y 50 \
"bash -lc 'CMD; tmux wait-for -S done-$JOB'"
tmux wait-for "done-$JOB"
Variant: keep the pane after exit (max observability)
Use remain-on-exit so the final output and exit status stay on screen for a human
to attach and inspect after the job finishes. The session no longer auto-disappears,
so detect completion via #{pane_dead} and clean up manually.
tmux new-session -d -s "job-$JOB" -x 220 -y 50 "bash -lc 'CMD'"
tmux set-option -t "job-$JOB" remain-on-exit on
tmux list-panes -t "job-$JOB" -F '#{pane_dead} #{pane_dead_status}'
tmux kill-session -t "job-$JOB"
Cleanup
tmux kill-session -t "job-$JOB"
for s in $(tmux ls -F '#{session_name}' | grep '^job-'); do tmux kill-session -t "$s"; done
rm -f "$DIR/$JOB.log" "$DIR/$JOB.exit"
Gotchas
- A detached session's default size is 80x24 — always pass
-x/-y, or wide output
is wrapped/truncated in capture-pane.
pipe-pane started just after new-session can miss the first lines of a very fast
command; for the complete history use capture-pane -S - while the session is alive,
or rely on the log for long-running jobs.
- Quote/escape carefully:
\$? and \$JOB must reach the inner bash -lc, not be
expanded by the outer shell.
capture-pane only works while the session exists; after a default (destroy-on-exit)
job finishes, read the log file instead.