mcpField
S
skill-system-tmux

skill-system-tmux

github.com/arthur0824haoエージェントワークフロー44 回インストール
リポジトリ

skill-system-tmux について

シェルを使うエージェント向けに、コマンドを直接実行するかtmuxに回すかを判断し、セッション管理の規約を示すスキルです。長時間・対話型・タイムアウトの恐れがある処理を対象に、命名や後片付けも扱います。

主な機能

  1. 01所要時間と対話性に応じた実行方法の選択
  2. 02規約に沿ったtmuxセッションの命名
  3. 03永続セッションの開始・再利用・終了
  4. 04出力取得と処理完了の確認
  5. 05エージェントセッションと残存プロセスの整理

活用シーン

  1. 01長時間のビルドやインストールのバックグラウンド実行
  2. 02ツール呼び出し間での開発サーバーの維持
  3. 03接続切断後も継続するSSHタスクの実行
  4. 04分離したエージェントやテストスイートの並列実行

インストール

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

$npx skills add https://github.com/arthur0824hao/skills --skill skill-system-tmux

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

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

SKILL.behavior.yaml
SKILL.spec.yaml
scripts/
test_tmux_tool.py
tmux_tool.py

詳細

Skill System Tmux

タイムアウトのリスクがある場合、処理の継続が必要な場合、または対話型ターミナルへのアクセスが必要な場合は、シェルコマンドを tmux 経由で実行します。このスキルでは、判断のためのヒューリスティックとセッション管理の慣例を説明します。tmux のチュートリアルではありません。

判断マトリクス

このマトリクスを使って、直接 bash と tmux のどちらを使用するか判断します。

条件実行方法例
推定実行時間が 60 秒を超えるtmuxgit clone <large>、npm install、docker build、トレーニングスクリプト
コマンドが自動終了しないtmuxnpm run dev、python app.py、jupyter notebook
TUI または対話型入力が必要tmuxvim、htop、pudb、claude
分離した並列実行が必要tmux複数のエージェント、並行するテストスイート
SSH 経由のリモート実行tmux接続が切れても実行を継続する必要があるコマンド
単一処理で、対話型ではなく、高速(30 秒未満)直接 bashls、grep、git status、cat、mkdir
1 回限りの実行で、出力が予想できる直接 bashpython script.py(高速な場合)、git diff、npm test(短時間の場合)

デフォルトは直接 bash です。 上記の条件に該当する場合にのみ、tmux 経由で実行します。

実行時間の見積もりに関するヒューリスティック

タイムアウトを超える可能性が高いコマンド:

  • Git 操作:clone(大規模なリポジトリ)、push(大容量のデータ)、checkout(作業ツリーが 1GB 超)
  • パッケージのインストール:npm install、pip install(依存関係が多い場合)、cargo build
  • ビルドツール:docker build、make(大規模なプロジェクト)、webpack(本番ビルド)
  • データ処理:トレーニングスクリプト、前処理パイプライン、大容量ファイルの転送
  • CI/テストスイート:大規模なプロジェクトでの全テスト実行

セッションの命名規則

人が読みやすいように、プロジェクトのコンテキストを含めた名前を付けます。

Format: {project}-{purpose}

Agent-created sessions (MANDATORY prefix):
  oc-{purpose}        # e.g., oc-audit, oc-verify, oc-render
  oc-{project}-{task}  # e.g., oc-skills-build, oc-subproject-test

User/infra sessions (no prefix required):
  postgres-dev
  frontend-watch
  ml-training

ルール:

  • エージェントが作成するセッションには、必ず oc- プレフィックスを付けます — 一括識別とクリーンアップが可能になります
  • 小文字を使い、区切りにはハイフンを使用します(アンダースコアは使用しません)
  • 複数のプロジェクトを扱う環境では、プロジェクトのコンテキストを含めます
  • 既知の oc- セッション名がある場合は、それを再利用します(例:oc-exp-runner)
  • プレフィックスのないレガシーなエージェントセッションを引き継いだ場合は、再利用する前に oc-* に名前を変更します
  • 数字のみの名前(例:531)でセッションを作成しないでください

主なパターン

パターン 1:起動したまま実行(バックグラウンドタスク)

リアルタイムの出力を必要としない、長時間実行のコマンドに使用します。

# Kill any existing session with same name, then start fresh
tmux kill-session -t {session} 2>/dev/null || true
tmux new-session -d -s {session} bash -c '{command}'

interactive_bash ツールを使用する場合:

tmux_command: new-session -d -s {session}
tmux_command: send-keys -t {session} "{command}" Enter
パターン 2:永続サーバー

開発サーバーなど、実行し続ける必要があるプロセスに使用します。

tmux_command: new-session -d -s {session}
tmux_command: send-keys -t {session} "{command}" Enter

後で実行中かどうかを確認します:

tmux_command: has-session -t {session}
パターン 3:出力の取得

tmux セッションに出力された内容を読み取ります。

tmux_command: capture-pane -p -t {session}

より長い履歴(直近 1000 行)を取得するには:

tmux_command: capture-pane -p -t {session} -S -1000
パターン 4:準備完了の検出

コマンドを送信した後、完了を検出するためにポーリングします:

  1. ペインの出力を取得します
  2. 出力の末尾にシェルプロンプトがあるか確認します(正規表現:/(\\$|>|#)\s*$/m)
  3. プロンプトが表示された場合、コマンドは完了しています
  4. 予想される時間が経過してもプロンプトが表示されない場合は、まだ実行中か、応答が停止していると判断します
パターン 5:正常なシャットダウン

作業が終わったら、必ずセッションをクリーンアップします。

tmux_command: kill-session -t {session}

新規作成前に終了するパターンにより、ゾンビセッションを防止できます:

tmux_command: kill-session -t {session}
# (ignore error if doesn't exist)
tmux_command: new-session -d -s {session}
パターン 6:リソースの一括解放

エージェントが作成したすべてのセッションを解放し、古いリソースを検出します。次の場合に実行します:

  • マシンの動作が遅い、またはメモリ使用量が多い場合
  • エージェントによる長時間の作業セッションの前後
  • ユーザーからクリーンアップを依頼された場合

ステップ 1:エージェントのセッションを特定する

tmux list-sessions -F '#{session_name} #{session_activity}' | grep '^oc-'

ステップ 2:エージェントのセッションをすべて終了する

tmux list-sessions -F '#{session_name}' | grep '^oc-' | xargs -I{} tmux kill-session -t {}

ステップ 3:古い非エージェントセッションを検出する

次の条件に該当するセッションは、古くなっている可能性があります:

  • 最後のアクティビティから 6 時間以上経過しており、フォアグラウンドプロセスが実行されていない
  • セッションにアイドル状態のシェルプロンプトしかない(capture-pane に $ または ╰─ だけが表示される)
# List sessions with last activity timestamp
tmux list-sessions -F '#{session_name} #{session_activity}'
# Compare #{session_activity} (epoch) against current time
# Capture pane of suspects to verify idle state

ステップ 4:孤立したプロセスを解放する

# Find opencode processes whose parent tmux pane was killed
ps aux | grep opencode | grep -v grep
# Check if port is held by a zombie
lsof -i :{port} 2>/dev/null
# Force kill if needed (SIGTERM first, SIGKILL if unresponsive after 5s)
kill {pid} && sleep 5 && kill -0 {pid} 2>/dev/null && kill -9 {pid}

重要:既知の非エージェントのインフラセッションは、ユーザーから明示的な確認を得ずに終了しないでください。関連プロジェクトのレガシーな名前は、エージェント管理対象のセッションとして扱う前に oc-* に統一する必要があります。

エージェントツールとの統合

interactive_bash ツール

主なインターフェースです。tmux のサブコマンドを、tmux プレフィックスを付けずに直接渡します。

# Create session
tmux_command: new-session -d -s oc-my-session

# Send command
tmux_command: send-keys -t oc-my-session "npm run dev" Enter

# Read output
tmux_command: capture-pane -p -t oc-my-session

# Kill session
tmux_command: kill-session -t oc-my-session
タイムアウト付きの bash ツール

タイムアウト境界付近のコマンドでは、tmux を使うより timeout パラメーターを増やしてください。

bash(command="npm install", timeout=300000)  # 5 min timeout

次の場合にのみ tmux を使ってください。

  • タイムアウトを確実に見積もれない場合
  • 現在のツール呼び出し後もプロセスを継続させる必要がある場合
  • 対話型/TUI アクセスが必要な場合

既知のエラーと回避策

interactive_bash で capture-pane がブロックされる

エラー:'capture-pane' is blocked in interactive_bash

これは tmux で最もよくあるエラーです。interactive_bash ツールは、一部の tmux サブコマンド(capture-pane、pipe-pane、save-buffer など)をブロックします。これらの操作には、必ず Bash ツールを使ってください。

# WRONG — will be blocked:
# interactive_bash: tmux_command: capture-pane -p -t oc-dev-server

# CORRECT — use Bash tool:
tmux capture-pane -p -t oc-dev-server

# Capture with history (last 1000 lines):
tmux capture-pane -p -t oc-dev-server -S -1000

# Capture and grep for specific output:
tmux capture-pane -p -t oc-dev-server | grep -i "error\|ready\|listening"

ルール:tmux の読み取り専用操作(capture-pane、list-sessions、display-message、show-options)には、Bash ツールを優先してください。interactive_bash は変更操作(send-keys、new-session、kill-session)に限定してください。

kill/再作成後に session not found が発生する

エラー:can't find session: oc-xxx

kill してから新規作成するパターンで競合が発生した場合によく起こります。簡単なガードを追加してください。

tmux kill-session -t oc-build 2>/dev/null || true
tmux new-session -d -s oc-build bash -c 'make all'
new-session で duplicate session が発生する

エラー:duplicate session: oc-xxx

セッションはすでに存在します。再利用するか、kill してから新規作成してください。

# Reuse (send new command to existing session):
tmux send-keys -t oc-build "make clean && make all" Enter

# Or kill and recreate:
tmux kill-session -t oc-build 2>/dev/null || true
tmux new-session -d -s oc-build bash -c 'make all'
no server running/tmux が起動していない

エラー:no server running on /tmp/tmux-*/default

tmux サーバーが起動していません。new-session コマンドを実行すると、自動的に起動します。

tmux new-session -d -s oc-init echo "tmux ready"
ツール選択の早見表
tmux サブコマンドinteractive_bash を使う?Bash ツールを使う?
new-sessionはいはい
send-keysはい(推奨)はい
kill-sessionはいはい
capture-paneいいえ — ブロックされますはい(必須)
list-sessions避けてくださいはい(推奨)
has-sessionはいはい
pipe-paneいいえ — ブロックされますはい(必須)
display-message避けてくださいはい(推奨)

アンチパターン

しないこと代わりにすること
すべてのコマンドを tmux 経由で実行する高速でアトミックなコマンドには、直接 bash を使います
使用後にセッションを終了し忘れる必ず kill-session で後片付けします
s1 のような汎用的なセッション名を使うoc-project-purpose のような説明的な名前を使います
oc- 接頭辞なしでエージェントのセッションを作成する必ず oc-audit、oc-verify、oc-build のように接頭辞を付けます
capture-pane を短い間隔で繰り返し確認する確認の間隔を 1~2 秒にします
古いセッションを終了せずに新しいセッションを開始する同じセッション名では、必ず終了してから新規作成します
行を消去せずにコマンドを送信する行に入力が残っている可能性がある場合は、コマンドの前に C-u を送信します
タスク完了後もセッションを実行したままにするセッション終了時に一括回収(パターン 6)を実行します
capture-pane に interactive_bash を使うcapture-pane には必ず Bash ツールを使います
ブロックされたコマンドを interactive_bash で再試行するすぐに Bash ツールに切り替えます

既存プロジェクトの規約

このスキルシステムの関連プロジェクトには、古い tmux の命名パターンが残っている場合がありますが、このリポジトリのエージェント所有セッションは oc-* に統一する必要があります。

  • セッション名 oc-exp-runner:実験実行用のエージェント所有セッションに推奨される名前です
  • ウォッチャーセッション:tmux send-keys を使ってエージェントを起動するバックグラウンドモニターです
  • machines.json 設定:tmux_session フィールドでマシンごとのセッション名を定義します
  • kill してから新規作成:すべての実験スクリプトで使われる標準的な後片付けパターンです

既存の tmux 規約があるプロジェクトで作業する場合は、実際のユーザー/インフラのセッションを維持しつつ、引き継いだエージェントセッションは作業を続ける前に oc-* 形式に変更してください。

{
  "schema_version": "2.0",
  "id": "skill-system-tmux",
  "version": "1.0.0",
  "capabilities": ["tmux-session-start", "tmux-capture", "tmux-wait", "tmux-session-list", "tmux-session-kill"],
  "effects": ["proc.exec"],
  "operations": {
    "start-session": {
      "description": "Start a long-running command in a managed tmux session.",
      "input": {
        "name": { "type": "string", "required": true, "description": "Logical session name" },
        "command": { "type": "string", "required": true, "description": "Command to execute inside tmux" }
      },
      "output": {
        "description": "Started session metadata",
        "fields": { "status": "string", "session_name": "string" }
      },
      "entrypoints": {
        "unix": ["python3", "{skill_dir}/scripts/tmux_tool.py", "start-session", "{name}", "{command}"]
      }
    },
    "capture-pane": {
      "description": "Capture output from a managed tmux session.",
      "input": {
        "session_name": { "type": "string", "required": true, "description": "Target session name" },
        "lines": { "type": "integer", "required": false, "description": "Number of lines to capture" }
      },
      "output": {
        "description": "Captured output",
        "fields": { "status": "string", "output": "string" }
      },
      "entrypoints": {
        "unix": ["python3", "{skill_dir}/scripts/tmux_tool.py", "capture-pane", "{session_name}"]
      }
    },
    "wait-completion": {
      "description": "Poll a managed tmux session until completion.",
      "input": {
        "session_name": { "type": "string", "required": true, "description": "Target session name" },
        "timeout_seconds": { "type": "integer", "required": false, "description": "Maximum wait time" }
      },
      "output": {
        "description": "Completion result and final output",
        "fields": { "status": "string", "completed": "boolean", "output": "string" }
      },
      "entrypoints": {
        "unix": ["python3", "{skill_dir}/scripts/tmux_tool.py", "wait-completion", "{session_name}"]
      }
    },
    "list-sessions": {
      "description": "List managed tmux sessions.",
      "input": {},
      "output": {
        "description": "Managed session rows",
        "fields": { "status": "string", "sessions": "array" }
      },
      "entrypoints": {
        "unix": ["python3", "{skill_dir}/scripts/tmux_tool.py", "list-sessions"]
      }
    },
    "kill-session": {
      "description": "Kill a managed tmux session.",
      "input": {
        "session_name": { "type": "string", "required": true, "description": "Target session name" }
      },
      "output": {
        "description": "Kill result",
        "fields": { "status": "string", "session_name": "string" }
      },
      "entrypoints": {
        "unix": ["python3", "{skill_dir}/scripts/tmux_tool.py", "kill-session", "{session_name}"]
      }
    }
  },
  "stdout_contract": {
    "last_line_json": false,
    "note": "Agent-executed; uses interactive_bash tool for tmux operations."
  }
}

コメント