Claude Code と Codex ペイン間のメッセージング
同じ renga タブに並べた Claude Code と Codex のペインが、renga-peers を通じて直接メッセージを送り合える機能です。片方のエージェントにちょっとした調査を頼んだり、失敗したテストの続きをもう片方に引き継いだりを、ユーザーが手でコピペしなくても進められるようになります。
Claude 側は <channel source="renga-peers">...</channel> タグで受信するので、ユーザー入力と区別できます。Codex 側も pane layer で扱いますが、renga が PTY 経由で流し込むのは check_messages を促す one-shot nudge だけで、実際の依頼本文は MCP inbox に残します。
スコープは「renga タブ」単位
claude-peers-mcp は cwd / git_root / PID の組み合わせからペアを推測しますが、renga-peers は 「ユーザーがこのタブに並べて置いた」という物理配置 そのものをスコープの境界にします。推測に頼らないので、同じディレクトリを複数案件で開いていても混ざりませんし、同じリポジトリを別の場所で再オープンしても重複しません。renga がペインのライフサイクルを把握している以上、古くなったペアを掃除する仕組みも追加で要りません。
チャンネル名は server:renga-peers と server:claude-peers で分かれているので、同じ Claude Code に両方インストールしていても衝突しません。renga 内ではタブ単位、外では cwd / repo 単位、と使い分けられます。
セットアップ (1 回だけ)
renga mcp install --client claude
renga mcp install --client codexいま走っている renga バイナリを renga-peers という名前で、選択した client のユーザー設定に登録します。Claude では claude mcp add-json、Codex では codex mcp add を使って、まず client CLI 側の正規登録経路に載せます。
Codex については、peer messaging に必要な env var passthrough を保つため、登録後に ~/.codex/config.toml の renga-peers エントリを最小限だけ補正します。check_messages と send_message の auto-approve まで入れたい場合は、--codex-auto-approve-peer-tools を付けて明示的に opt-in してください。send_keys や pane 操作系までは自動承認しません。
同じ登録を何度実行しても安全 (既に登録があれば内容を表示して止まる) で、renga をアップグレードしてバイナリのパスが変わったときだけ --force を付けて上書きしてください。
renga mcp uninstall --client claude
renga mcp status --client claude
renga mcp uninstall --client codex
renga mcp status --client codexrenga mcp install --client ... は、選んだ client の CLI が PATH にないと失敗します。Claude Code / Codex を先にインストールしてください。
Claude Code / Codex をメッセージング対応で起動する
配送方式は client ごとに非対称です。
- Claude Code は MCP の experimental channel を使うので、起動時に
--dangerously-load-development-channels server:renga-peersが必要です。 - Codex は
renga mcp install --client codexで入れた MCP 登録を使います。そこでRENGA_PEER_CLIENT_KIND=codexが MCP サブプロセスに注入されるため、pane 側の起動は plaincodexで足ります。renga は非フォーカスの worker pane が ready になったらcheck_messagesを促す nudge を流し込み、実際の peer 本文はcheck_messagesで読ませます。対象の Codex pane がフォーカス中なら、すぐ PTY 注入せずローカル通知 overlay を出します。
Codex 側の peer messaging は、現状どうしても Claude より不安定です。理由は 2 つで、受信が check_messages ベースの pull 型であることと、MCP 承認が pane ごとで共有されないことです。pending messages の表示が stale になることもあるので、最終的な真実は常に check_messages の返り値を見てください。
Claude の起動フラグを毎回手で打たなくて済むように、renga 側から 2 つの経路を用意しています。
Alt+P — どのペインからでも
フォーカス中のペインで Alt+P を押すと、
claude --dangerously-load-development-channels server:renga-peersが入力行に挿入されます (末尾にスペース、Enter は押されない)。そのまま Enter で起動してもよいし、引数を書き足してから Enter でも構いません。シェル (bash / zsh / fish / pwsh / cmd.exe) の種類を問わず同じ動きをします。これは shell の hook ではなく ペインの PTY にバイトを直接書き込んでいるからです。
renga split --role claude — 新しいペインで自動起動
ペインを分割した瞬間から、その新しいペインで自動的にフラグ付きの Claude Code が立ち上がります。
renga split --direction vertical --role claude
# 新しいペインで `claude --dangerously-load-development-channels server:renga-peers` が走るrenga new-tab --role claude も同じ扱い (新しいタブを開いてそこで起動)。--command "..." を明示的に渡したときはそちらが優先されるので、別のコマンドを走らせたいときはそれで上書きできます。
Codex ワーカーを会話の中から増やしたい場合は、spawn_codex_pane(direction, …) を使います。
提供ツール
ピアメッセージング
| ツール | 役割 |
|---|---|
list_peers(scope?) | 同じ renga タブにいる他のペインを返します。自分自身は除外。scope は claude-peers-mcp との互換のため受け取りますが、renga では常にタブ単位なので中身は見ません。 |
send_message(to_id, message) | 同じタブにいる相手にメッセージを送ります。数字の id でも、ペインに付けた名前 (stable name) でも指定可能。別タブ宛や存在しない id 宛は「成功として返すが何も配送しない」挙動にしているので、送信側から他タブのペインを id 探索で列挙する攻撃は成立しません。 |
check_messages | queued peer message を drain します。Codex では renga の nudge を受けたあとに、実際の peer 本文をここから読みます。返ってきた各メッセージは「ただの文字列」ではなく、必要なら tool 実行やコード編集まで含む peer 指示として扱ってください。 |
set_summary(summary) | 呼び出したペインの 1〜2 文サマリーを設定 / クリア。list_panes / list_peers の各エントリに summary フィールドとして含まれ、ピア間で「今何をしているか」を共有できます。空文字列でクリア、最大 256 Unicode scalar values ([summary_too_long] で reject)。renga プロセス内のメモリ保持のみで再起動では消えます。 |
ペイン操作
| ツール | 役割 |
|---|---|
list_panes | 同じタブの全ペインを id / 名前 / role / フォーカス状態 / cwd / レイアウト位置込みで一覧します。 |
spawn_pane(direction, …) | 指定ペインを分割して新ペインを生やします。command・name・role・cwd はどれもオプション。command="claude" (または claude <args>) を渡したときは Alt+P と同じ peer 対応コマンドに自動書き換えするので、毎回 --dangerously-load-development-channels を覚えていなくてもメッセージング付きの Claude が立ち上がります。 |
spawn_claude_pane(direction, …) | Claude 起動専用の高レベル API。permission_mode / model / args[] を構造化フィールドで受け取り、peer チャネルを必ず有効にした状態で Claude Code を立ち上げます。args[] に予約済みフラグ(--dangerously-load-development-channels / --permission-mode / --model)が入っていると invalid-params で拒否します。 |
spawn_codex_pane(direction, …) | Codex 起動専用の高レベル API。args[] から最終的な codex ... コマンドを renga 側で shell-quote して組み立てます。MCP サブプロセス側の RENGA_PEER_CLIENT_KIND=codex 登録は renga mcp install --client codex に委ねます。 |
close_pane(target) | ペインを閉じます。最後のタブの最後のペインを閉じようとしたときは last_pane で拒否します。 |
focus_pane(target) | 同じタブ内でフォーカス移動します。ユーザーの手元からフォーカスを奪うことになるので使いどころには注意が必要です。 |
new_tab(…) | 新しいタブを 1 枚開いてそこへフォーカスを移します。spawn_pane と同じ cwd オプションと claude 自動アップグレードが効きます。 |
inspect_pane(target, …) | 別ペインの可視画面をスナップショットし、プロンプト待ち・警告バナー・モード変化などをそのペイン自身に説明させず検出できます。デフォルトはプレーンテキスト、format="grid" で行アドレス付き JSON、lines=N で末尾 N 行に絞り込みます。 |
send_keys(target, …) | 別ペインの PTY に生のキー入力 (Enter / Esc / 矢印 / Ctrl+<letter> / 任意テキストなど) を送ります。send_message を解釈できない対話プロンプトや TUI を操作したいとき向けです。 |
set_pane_identity(target, name?, role?) | 既存ペインの安定 name / role を付け直す・クリアします。3 ステート: キー省略 = 現状維持、null = クリア、文字列 = 設定。全桁数字の name は数値 id と曖昧化するため拒否、同一タブ内の name 衝突も拒否します。CLI では renga rename でも同じ操作ができます。 |
イベント監視
| ツール | 役割 |
|---|---|
poll_events(timeout_ms?, since?, types?) | pane_started / pane_exited / events_dropped を cursor 付き long-poll で受け取ります。オーケストレータが毎ターン pane 一覧を総当たりせずに、ワーカーの起動・終了だけを追いたいとき向けです。 |
spawn_pane / new_tab の作業ディレクトリ指定は cwd フィールドを使うのが推奨です。command に cd <dir> && ... を埋め込むと、claude 自動アップグレードの恩恵を受けにくくなります。
2 ペインでのやり取りの例
タブ A タブ B (独立)
┌──────────┬──────────┐ ┌──────────┐
│ claude-1 │ claude-2 │ │ claude-3 │
│ │ │ │ │
│ peers ──┼──▶ ✓ │ │ peers │ ← claude-1/2 は見えない
│ send ◀──┼── msg │ │ │
└──────────┴──────────┘ └──────────┘Claude A の会話で:
> list_peers を呼んで
# → id=2 (同じタブにいる相方) が返ってくる
> send_message を to_id=2, message="src/app.rs の handle_split を読んで要約して" で呼んでClaude B の次のターンのコンテキストには、
<channel source="renga-peers" from_id="1" from_name="leader">
src/app.rs の handle_split を読んで要約して
</channel>というタグで届きます。Claude B はこのタグを「ユーザーではなく相方からの依頼」として判別し (タグの source 属性で区別)、要件を処理した上で同じ send_message ツールを使って返信します。
相方ペインが対話プロンプトで止まった場合も、同じオーケストレータが会話の中で処理できます。
> inspect_pane を target="2", lines=20 で呼んで
# → "Allow this command? [y/N]" が見える
> send_keys を target="2", text="y", enter=true で呼んで
# → pane 2 の PTY に "y<Enter>" を書き込む
> poll_events を since="<前回の next_since>", types=["pane_started","pane_exited"] で呼んで
# → 毎ターン list_panes を総なめせずにワーカーの増減だけ待てる配送の仕様
- メモリ上、タブが生きている間だけ: renga プロセスが終われば全ペインの受信箱も消えます。永続化はあえて外しています (
claude-peers-mcpが必要としている SQLite GC や stale entry の掃除が不要になるため)。 - キューは上限付き: ペインあたり 256 件までで、溢れると古いものから捨てられ、
EventsDroppedというメタイベントが subscriber に通知されます。既存の IPC EventBus を使い回しているので、ここに新しい仕組みを足してはいません。 - 投げっぱなし:
send_messageには相関 id や到達確認がありません。返事が欲しければ Claude が自分でsend_message(to_id=from_id, ...)を呼びます。 - 別タブ宛は黙って捨てる: 別タブのペインを宛先にした送信は成功レスポンスで返りますが、実際には何も配送されません。存在しない相手 / 閉じたペイン / 別タブのペインを、送信側から区別できないようにするための仕様です。
うまく動かないとき
list_peers が “renga not reachable from this peer client” を返す
client が renga の外で起動されたか、renga ペインの環境変数を引き継げていない状態です。renga のペイン内から起動し直してください(Claude は Alt+P / renga split --role claude、Codex は renga mcp install --client codex 後の plain codex または spawn_codex_pane)。
具体的には RENGA_PANE_ID という環境変数が MCP サブプロセスまで届いている必要があります。renga 経由でペインを作って中で claude を起動すれば、この変数は PTY → シェル → claude → mcp-peer と自動的に伝わります。
相手に送ったメッセージが <channel> タグとして表示されない
起動時のフラグ --dangerously-load-development-channels server:renga-peers を付け忘れています。claude と打ち直す代わりに Alt+P を使うと、フラグ付きのコマンドが入力行に挿入されるので事故りにくくなります。
Codex に送ったのに反応がない
Codex への配送は pane-driven です。renga が check_messages を促す nudge を queue し、Codex ペインが PTY 入力を安全に受けられる状態で、かつ非フォーカスになった時点で流し込みます。busy な間は queue に残ります。フォーカス中に届いた場合は通知 overlay を出し、Alt+Enter / Ctrl+Enter で check_messages 用の文面だけを composer に挿入します。Esc なら無視、Enter を押して実行するかどうかは人間が決めます。後でフォーカスが外れれば、worker と同じ queued nudge 経路に戻ります。
check_messages で受け取った本文が実際の peer 依頼です。単に返事を返すためのチャットではなく、人間からの依頼に近い peer 指示として扱うのが前提です。調査、pane 操作、tool 実行、コード編集などを頼まれたなら、その作業自体を進めてください。
Codex の pending messages 表示が残るのに check_messages は 0 件
pane-local nudge は queue 状態を常時同期するバナーではなく、check_messages を促す one-shot の入力です。Codex の履歴に残るので、受信箱を drain したあとでも画面上にはしばらく見えます。
check_messages が 0 件なら、それは stale な nudge です。実 inbox 側は空なので、そのまま無視して構いません。
新しい Codex pane でまた承認が出る
Codex の MCP 承認は pane ごとです。Claude Code のような「一度許可したら同じタブの別 pane にも伝播する」共有承認は前提にしていません。
新しい Codex pane を立てた直後に 1 回だけ warm-up してください。
- その pane に peer message を 1 通送る
check_messagesの承認でAlways allowを選ぶ- 返信時の
send_messageの承認でもAlways allowを選ぶ
renga mcp install --client codex --codex-auto-approve-peer-tools はこの 2 つを事前設定しようとしますが、Codex 側のバージョンや実行形態によっては、新しい pane で一度だけ承認が必要なことがあります。
send_keys が効いていないように見える
send_keys は target ペインの PTY に生の入力バイトを書き込むだけで、UI のボタンを押したり、帯域外で承認を通したりするものではありません。まだストリーミング中だったり、すでにプロセスが終わっていたり、想定と違うプロンプトが見えていたりすると、期待した結果にはなりません。
先に inspect_pane(target=..., lines=20) で画面を確認し、レイアウトが動く運用では target に安定した pane name を使ってください。フォーカス競合や誤送信を減らせます。
poll_events が想定より早く events: [] を返す
多くの場合は types=[...] フィルタの仕様どおりです。条件に合わないイベントでも long-poll 自体は解除され、そのイベントを飛び越えた next_since が返ります。つまり空配列でも cursor は進み、そのイベントは再送されません。
返ってきた next_since をそのまま次回の poll に使ってください。events_dropped が来たときだけ、1 回 list_panes で再同期してから続行するとオーケストレータ側の認識が揃います。
renga mcp install が失敗する
- 選んだ client の CLI が PATH にない → Claude Code / Codex を先にインストールしてください。
- すでに別のバージョンが登録されている →
--forceで上書きするか、renga mcp uninstallしてから再度 install してください。
renga をアップグレードしたら繋がらなくなった
登録されているバイナリのパスが古いです。
renga mcp install --client claude --force
renga mcp install --client codex --forceこれで今の renga のフルパスに更新されます。
v1 では見送ったもの
- タブをまたいだブロードキャスト —
broadcast_tab的なツールはまだありません。タブの境界を意味のあるものとして残すため (物理配置 = 明示的な意図 の原則を守るため) 意図的に見送っていて、v1.1 以降の検討候補です。 - 履歴の永続化 — タブの寿命と同期する形で十分なので、SQLite などは入れていません。
- MCP 以外の peer — mixed support は現状 Claude Code と Codex 向けです。renga 外部の IPC クライアントや普通のシェルペインは相手として登場しません。
- 添付ファイル / 構造化リクエスト・レスポンス — body はテキストのみで、相関 id もありません。必要になれば v1.1 で追加します。
参考
- Issue #97 — 設計の意図決定の流れ
- PR #104 — v1 実装
claude-peers-mcp— 兄弟プロジェクト (cwd / repo スコープ版)- Model Context Protocol