ai-agents-cmux-migration
14台のAIエージェントが散らばったGhosttyターミナルをcmuxで一元管理。セッション履歴を1件も失わずに16ワークスペースへ移行した実録。
AIエージェント14台が散らばったターミナルを、cmuxで一元管理するまで
はじめに
私は普段、複数のAIエージェント(piを14台、Clineを1台)を同時に動かしながら開発をしています。エージェントごとに役割を持たせて並行稼働させるスタイルです。
ある日気づきました。Ghosttyのウィンドウが7つ、タブが14枚、それぞれにエージェントが1匹ずつ棲みついているという状態に。
- エージェントAで調査をしている最中に、エージェントBの結果を確認するにはタブを探す
- いま何が動いているのか、俯瞰できない
- ターミナルが「カオスの入れ物」と化している
「これ、全部1つのアプリでグリッド表示できたらいいのに」——その願いを叶えてくれたのが cmux でした。この記事では、Ghosttyで乱立していた14台のAIエージェント+シェル・Clineを、cmuxのワークスペースとして一括移行した実録をお届けします。
1. まず現状を完全に棚卸しする
移行の第一歩は「何が動いているのか」の把握です。殺す前に調べる。これが鉄則でした。
プロセスのツリーを洗い出す
# GhosttyのPIDを特定
pgrep -fl Ghostty
# TTYを持つ全セッションを一覧
ps -eo pid,ppid,tty,stat,command | awk '$3 ~ /^ttys/ {print}'
結果、Ghostty (PID 672) の配下に 14個のTTYセッション が確認できました。
| TTY | 中身 |
|---|---|
| ttys000 | pi(作画ヘッドオフィス) |
| ttys001 | pi(mattermost) |
| ttys004 | Cline(CLINE mente) |
| ttys005〜014 | pi(PrimeAgent / 電話自動 / 索敵 / ケスラー など) |
| ttys017 | pi(この作業セッション) |
さらに Terminal.app にも pi×1、素のシェル×1。合計16の対話セッションが別々の場所に散らばっていました。
AIエージェントのセッションIDを特定する
ここが本題の核です。piはセッション履歴をJSONLファイルとして保存しています。
ls -lt ~/.pi/agent/sessions/--Users-user--/
ファイル名は 2026-08-08T21-06-08-175Z_019fe332-8aaf-7d69-89a5-510b2bda70d3.jsonl
という形式で、後半のUUID(019fe332-...)がセッションIDです。
さらに各セッションの「名前」(pi --name で付けた名前やGhosttyのタブ名)は、JSONL内の session_info イベントに記録されています。これをPythonで一括抽出すると、タブ名 ↔ セッションID ↔ TTY の完全な対応表ができあがります。
import json, glob
for f in glob.glob('*.jsonl'):
with open(f) as fp:
for line in fp:
d = json.loads(line)
if d.get('type') == 'session_info' and d.get('name'):
print(f.split('_')[1][:8], d['name'])
この調査が価値を持つのは、「どのエージェントがどんな作業をしていたか」を履歴ごと移行できるからです。会話をゼロからやり直さずに済みます。
2. cmux導入 — まずはアップグレード
実はcmuxは既にHomebrewで入っていましたが、初回起動でソケット通信が Broken pipe になる不具合に遭遇。調査すると 0.64.17 には既知の問題があり、0.64.22 で修正済みとのこと。
brew upgrade --cask cmux
# 0.64.17 → 0.64.22
アップグレード後、cmux ping が PONG を返すようになりました。まず最新版にする。これでかなりのトラブルを回避できます。
エージェント連携フックを仕込む
cmux hooks setup を実行すると、対応エージェントの設定ファイルにcmux連携が注入されます。
cmux hooks setup --yes
# pi / codex / opencode / omp / cursor / hermes-agent / kimi の7種に適用
piに対しては ~/.pi/agent/extensions/cmux-session.ts がインストールされ、piが起動したセッションのIDが自動的にcmuxへ通知されるようになります。cmuxのサイドバーに pi.<セッションID> のタグが付くので、どのエージェントが何の会話をしているかが一目瞭然になります。
3. 一括移行 — コマンド一つで16ワークスペース
移行の本丸です。cmuxのワークスペース作成はCLIから完結します。
cmux new-workspace --name "mattermost" --cwd /Users/user \
--command "pi --session 019fa002-6ead-78de-8b1f-e0f8476c7ad1" --focus false
これを全セッション分ループで実行。16ワークスペースが一瞬で完成しました。
=== RESULT: OK=16 NG=0 ===
workspace:2 mattermost
workspace:3 キルヒアイス4
workspace:4 AGI-SHOP
...(計17、初期の~を含む)
検証(最重要)
移行で怖いのは元のセッションとの二重オープン競合です。Ghostty側のpiが生きているまま、cmux側でも同じセッションファイルを開くことになります。
この点、piのセッションファイルは「resume時は読み込みのみ、ユーザーが発言した時に初めて追記」という仕様でした。実際にファイルのmtimeを確認し、cmux側の起動後も更新されていないことを確認して安全性を担保しました。
# 移行後の全セッションファイルmtime確認 → 全て移行前のまま
# = Ghostty側との競合なし
さらに、cmux側の各ワークスペースに tag:pi.<正しいセッションID> が付いていること、ターミナルタイトルが π - <セッション名> になっていることで、正しいセッションが正しく復元されたことを確認しました。
4. 最後の引っ越し — 自分自身も
移行作業をしているこのセッション自身(019fe332)もcmuxに引っ越しました。
cmux new-workspace --name "cmux-migration" \
--command "pi --session 019fe332-8aaf-7d69-89a5-510b2bda70d3"
cmux側での起動を確認した後、Ghostty (PID 672) を終了。14タブのうち一切データを失うことなく、全セッションがcmuxのワークスペースとして再誕生しました。
5. 移行後の運用Tips
セッションIDを調べる(ID不要の裏技も)
# 稼働中のエージェントIDをcmuxが表示
cmux top --all --flat | grep tag:pi
# セッションファイル一覧(過去含む)
ls -t ~/.pi/agent/sessions/--Users-user--/
# そもそもID不要で再開できる
pi --resume # 対話式ピッカー
pi --continue # 直近を継続
セッション系コマンドは先頭8桁の部分IDで曖昧一致します。 フルID(36桁)を覚える必要はありません。
フォークで枝分かれさせる
1つの会話をコピーして別の視点で続けたいときはフォークが便利です。
pi --fork 019fe332 # この会話を複製して新規セッションとして開始
cmuxのグリッド表示
⌘D/⌘⇧D… 右/下に分割⌃⌘T… 分割したペインをグリッドに整列⌃⌘C… キャンバスモード(自由配置)に切替⌃⌘O… 全体表示(オーバービュー)⌘P… ワークスペーススイッチャー(全セッションから即選択)
まとめ
Ghosttyに散らばっていた16の対話セッションを、cmuxの17ワークスペースとして一元化しました。
- 調査 → セッションID特定 → cmux構築 → 一括移行 → 検証 → 旧環境撤去
- 1つの会話履歴も失わずに移行完了
- AIエージェントをターミナル上で「管理する」体制が手に入った
特に学んだのは、**「移行とは殺すことではなく、引き継ぐこと」**だということです。
- プロセスは殺さず、棚卸しから始める
- セッションIDのような「引き継ぎのハンドル」を見つける
- 新しい環境で復元できたことを確認してから、旧環境を畳む
同じように「ターミナルが乱立してきてつらい」と思っている方の参考になれば幸いです。リストラして殺すよりも、仕組みで引き継いで整理する方が、はるかに安全で美しい。そう確信しました。