mcpField
T
tmux-skill

tmux-skill

github.com/agents365-aiエージェントワークフロー97183 回インストール2 週間前に更新
リポジトリ

tmux-skill について

tmux-skillは、コーディングエージェントがシェルからtmuxをプログラムで操作する方法を説明します。永続セッション、対話型プロセス、出力取得、完了検出を扱います。

主な機能

  1. 01サイズ指定のデタッチセッション作成
  2. 02ペインへのキー送信とコマンド実行
  3. 03画面出力とスクロールバックの取得
  4. 04機械可読形式でのペイン確認
  5. 05センチネルやペイン状態による完了検出

活用シーン

  1. 01長時間のビルドやサーバーの実行継続
  2. 02REPLや対話型ターミナルアプリの操作
  3. 03実行中プロセスの確認や人との共有

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/agents365-ai/365-skills --skill tmux-skill

インストール後、Claude Code で/tmux-skillを入力して読み込まれたか確認します。

同梱ファイル.skillspector-baseline.yaml

詳細

コーディングエージェント向け tmux

tmux はターミナルマルチプレクサーです。ターミナルを閉じても残るペイン内でプログラムを実行し、プログラムから状態を確認したり、操作したり、再接続したりできます。このスキルでは、非対話型(プログラムによる)tmux の使用方法、つまりコーディングエージェントがシェルから tmux を操作する方法を説明します。公式のtmux wikiに基づいています。

tmux を使う場面(使わない場面)

次のいずれかが必要な場合は tmux を使います。

  • プロセスをエージェントのターン/ターミナルが終了した後も実行し続ける必要がある場合(長時間かかるビルド、サーバー、監視処理など)
  • 対話操作が必要な場合:REPL、入力を求めるプログラム、TUI アプリ(vim、htop、fzf)
  • 実際のTTYが必要な場合(isatty がないと動作しないツールや、固定のウィンドウサイズが必要なツール)
  • 実行中の出力を確認したり、人間が attach して様子を見たりする場合

単純なリダイレクトで十分な場合は tmux を使わないでください。cmd > out.log 2>&1 や cmd & / nohup のほうが簡単で、TUI を読む必要もありません。

基本的な考え方

server (one per socket, auto-started, exits when last session dies)
└── sessions ($0, $1, ... unique names)
    └── windows (@0, @1, ... named, linked to 1+ sessions)
        └── panes (%0, %1, ... one terminal + one running program each)
  • スクリプトでは名前やインデックスよりも一意な ID($3 セッション、@2 ウィンドウ、%5 ペイン)を優先します。名前変更や並べ替えがあっても曖昧にならず、安定して使えます。
  • デフォルトのソケットはユーザーの tmux と共有されます。エージェント専用のセッションには、分離されたソケットを使います:tmux -L pi-agent ...。同じフラグをすべてのコマンドに適用できます。

基本的なループ(標準的なパターン)

# 1. Create a detached session with a fixed size (else it defaults to 80x24,
#    which mangles wide output you later capture)
tmux -L pi-agent new-session -d -s build -x 220 -y 50

# 2. Send a command. Append an echo sentinel to detect completion reliably.
#    Grep the EXPANDED sentinel (__DONE__:<digits>): the echoed command line still
#    contains the literal "$?", so a plain grep for __DONE__ matches the echo
#    before the command even runs.
tmux -L pi-agent send-keys -t build 'make 2>&1; echo "__DONE__:$?"' Enter

# 3. Poll for the sentinel in the pane output
until tmux -L pi-agent capture-pane -p -t build | grep -q '__DONE__:[0-9]'; do sleep 1; done

# 4. Read the result (including scrollback)
tmux -L pi-agent capture-pane -p -S -2000 -t build
#    -> last line tells you the exit code after "__DONE__:"

# 5. Clean up (or leave it running for the human to attach to)
tmux -L pi-agent kill-session -t build

センチネルを使ったポーリングが、完了を検出する最も確実な方法です。tmux wait-for (chan / wait-for -S chan)も使えますが、競合が発生します。待機を始める前にシグナルが送信されると、永遠に待機することになります。両端を制御できる場合にのみ使用してください。

コマンド早見表

tmux ls                                   # list sessions (exit 1 + "no server running" = none; not an error)
tmux new-session -d -s NAME               # detached session; -x/-y set size; -c DIR sets start dir
tmux new-session -A -s NAME               # attach-or-create (human-facing convenience)
tmux send-keys -t TGT 'cmd' Enter         # type into a pane; Enter is a KEY NAME, not "\n"
tmux capture-pane -p -t TGT               # pane text to stdout (-S -3000 scrollback, -J join wrapped lines)
tmux list-panes -a -F FMT                 # enumerate panes with a format string
tmux display-message -p -t TGT '#{...}'   # expand a format for one target
tmux kill-session -t NAME                 # kill one session; kill-server kills everything
tmux split-window -h -t TGT 'cmd'         # new pane right; -v below; -d don't focus it; -b before
tmux select-pane -t %5                    # make a pane active
tmux set-option -t TGT remain-on-exit on  # keep pane (and its output) after the process exits
tmux respawn-pane -t %5                   # restart the program in a dead pane
tmux rename-window -t @2 name             # windows auto-rename by default; pin with rename or disable automatic-rename
tmux run-shell 'cmd'                      # run once in tmux's shell, no pane
tmux set-hook -t s hook 'cmds'            # run tmux commands on events (pane-died, after-send-keys, ...)
tmux wait-for CHAN / wait-for -S CHAN     # synchronization primitive (see race caveat above)

-t のターゲット:session:window.pane(例:build:0.1)、または単独の ID -t %5 / -t @2 / -t '$3'。シェルがセッション ID を展開しないよう、$ を引用符で囲みます。

send-keys のルール

tmux send-keys -t build 'echo "a b"' Enter      # args are typed into the pane; the pane's
                                                # shell does the parsing: your quoting must
                                                # survive tmux AND the target shell
tmux send-keys -t build C-c                     # send Ctrl-C to interrupt
tmux send-keys -t build Up Enter                # repeat last command (shell history)
tmux send-keys -t repl 'x = 1' Enter            # drive a REPL one statement at a time
tmux send-keys -t build -l '100%'               # -l: literal text, key names like "Enter" not interpreted
tmux send-keys -t build -H 41 42                # -H: hex-encoded keys (unicode-safe)
  • Enter、Tab、Space、BSpace、C-c、C-l、Up、Down、Escape、F1.. は キー名です。認識されない引数はリテラルテキストとして入力されます。
  • 改行を期待して "\n" を送信しないでください。これは \ と n の 2 文字を入力します。Enter を送信してください。
  • 複雑な引用符の扱いが必要な場合(ヒアドキュメントや入れ子の引用符など)は、引用符の階層に悩む代わりに、スクリプトファイルを書いて bash /tmp/script.sh と Enter を送信してください。
  • send-keys は実行要求を送ってすぐに戻ります。プログラムが動作するまで待つことはありません。
  • C-b プレフィックスをスクリプトで使わないでください。これはクライアントに接続した人間が使うものです。tmux コマンドを直接使ってください。

capture-pane のルール

  • デフォルトでは表示中の画面だけを取得します。 スクロールバックの最後の N 行には -S -3000、履歴全体には -S - を使います(履歴は history-limit で制限され、デフォルトは 2000 です)。
  • -S 0 - は画面の先頭から履歴の最後までを取得します:-S 0 -E -。
  • -J は折り返された行を論理行に結合します。解析時には通常これが適しています。
  • -e は ANSI エスケープシーケンス(色)を含めます。テキストをすっきりさせるには省略してください。
  • 行末に空白が含まれる場合があります。比較時には sed -e 's/[[:space:]]*$//' で削除してください。
  • -a は代替画面を取得します(画面全体を描画する TUI アプリ向け)。

フォーマット(検査用 API)

一覧表示コマンドの -F と display-message -p は、機械可読な情報を返します。

tmux -L pi-agent list-panes -a -F '#{session_name}:#{window_index}.#{pane_index} #{pane_id} cmd=#{pane_current_command} pid=#{pane_pid} dead=#{pane_dead} path=#{pane_current_path}'
tmux -L pi-agent display-message -p -t build '#{pane_pid} #{history_size} #{cursor_y}'

便利な変数:#{session_id}/#{session_name}/#{session_attached}、 #{window_id}/#{window_index}/#{window_name}/#{window_active}、 #{pane_id}/#{pane_index}/#{pane_active}/#{pane_dead}/#{pane_pid}/ #{pane_current_command}/#{pane_current_path}/#{pane_title}/#{pane_in_mode}、 #{history_size}、#{socket_name}、#{pid}(サーバー PID)。#{q:...} でエスケープします。 全一覧:man 1 tmux の FORMATS セクション。

完了を検出する4つの方法

  1. センチネルのエコー(デフォルト、競合なし):send ... 'cmd; echo __DONE__:$?' Enter を実行し、capture-pane | grep でポーリングします。
  2. remain-on-exit + #{pane_dead}:オプションを設定してコマンドを直接実行し、 display-message -p -t %5 '#{pane_dead}' が 1 を出力するまで待ちます。ペインは respawn-pane または kill-pane を実行するまで出力を保持します。
  3. プロセスの確認:#{pane_pid} はペインのシェルです。cmd をペインのコマンドとして直接起動した場合、 終了するとペインも終了します(方法2と併用してください)。
  4. wait-for:順序も制御できる場合に限ります(前述の競合に関する注意を参照)。

レシピ

人間も監視する長時間ジョブ
tmux -L pi-agent new-session -d -s train -x 220 -y 50
tmux -L pi-agent send-keys -t train './train.sh' Enter
echo "watch with: tmux -L pi-agent attach -t train"   # hand this to the user
複数ペインのモニター
tmux -L pi-agent new-session -d -s mon -x 220 -y 50 -c "$PWD"
tmux -L pi-agent send-keys -t mon 'tail -f app.log' Enter
tmux -L pi-agent split-window -v -t mon
tmux -L pi-agent send-keys -t mon.1 'watch -n5 df -h' Enter
# capture one specific pane: -t mon.0 / -t mon.1, or the pane ID
REPL/対話型プログラム
tmux -L pi-agent new-session -d -s repl -x 220 -y 50 'python3 -i'
sleep 1                                          # let it start before typing
tmux -L pi-agent send-keys -t repl 'print(6*7)' Enter
sleep 0.5
tmux -L pi-agent capture-pane -p -t repl         # parse "42" between prompts
tmux -L pi-agent send-keys -t repl C-d           # exit
実行して出力を取得する、自己完結型ヘルパー
tmuxrun() {  # tmuxrun SESSION 'COMMAND' -> prints output, exit code in $?
  local s=$1; local t=$2
  tmux -L pi-agent new-session -d -s "$s" -x 220 -y 50 || return 1
  tmux -L pi-agent send-keys -t "$s" "$t; echo \"__DONE__:\$?\"" Enter
  until tmux -L pi-agent capture-pane -p -t "$s" | grep -q '__DONE__:[0-9]'; do sleep 1; done
  tmux -L pi-agent capture-pane -p -S -2000 -t "$s" | sed -e 's/[[:space:]]*$//'
  tmux -L pi-agent kill-session -t "$s"
}

落とし穴のチェックリスト

  • 新しいセッションをデタッチし、サイズも指定しましたか(-d -x ... -y ...)?サイズを指定しないデタッチ済みペインは80x24です。
  • \n という文字列ではなく、キーの名前(Enter)を送信しましたか?
  • 引用符の扱いは、tmuxと対象のシェルの両方で維持されますか?そうでない場合は、一時スクリプトファイルを使ってください。
  • スクロールバックが必要な場合、-S を指定してキャプチャしましたか?デフォルトでは表示中の画面のみが対象です。
  • 固定の sleep ではなく、センチネル/pane_dead で完了を検出しましたか?
  • センチネルのgrepでは、展開後の形式(__DONE__:[0-9])に一致させましたか?センチネル名だけのgrepでは、コマンドの実行前にシェルがエコーしたコマンドラインにも一致します。
  • ウィンドウ名(自動で変更されます)ではなく、ターゲットの指定にID(%0、@1、$2)を使いましたか?
  • デフォルトのソケットを使う場合、最初に tmux ls を確認しましたか?ユーザーが稼働中のセッションを持っている可能性があり、それらを妨げてはいけません(デフォルトのソケットで kill-session/kill-server を実行すると、ユーザーのセッションが終了します)。
  • tmux ls の終了コード1と「no server running」は、異常ではなく空の状態を意味します。
  • 残ったセッションをクリーンアップし(kill-session/kill-server)、ソケットファイルも削除しましたか?
  • プログラムが終了し、ペインが予期せず消えましたか?実行前に remain-on-exit on を設定してください。

コントロールモード(上級者向け、必要となることはまれです)

tmux -C attach(または、生のアプリケーション向けの -CC)はテキストプロトコルを使用します。コマンドを受け取り、それぞれに %begin ... %end(成功)または %begin ... %error(失敗)のガード行で応答します。稼働中のペイン出力は %output %paneID text 通知として届きます。ペイン出力をストリーミングする長時間稼働のスーパーバイザーを構築する場合に便利です。1回限りの操作には、上記のシェルコマンドのほうが簡単です。大量のストリーミング向けに、フロー制御(refresh-client -f pause-after=...、%pause、%extended-output)とフォーマットのサブスクリプション(refresh-client -B)も利用できます。詳しくは コントロールモードのWikiページを参照してください。

参考資料

  • Wiki:https://github.com/tmux/tmux/wiki(Getting-Started、Formats、Control-Mode、 Events、Clipboard、FAQ、Recipes)
  • マニュアルページ:man 1 tmux(すべてのコマンド、フラグ、フォーマット変数)

コメント