
Summary
この文書の要点
- Agent DeskはAIをサーバー側で起動する実行基盤ではなく、利用者の環境で動くClaudeとCodexへMCP経由の協業面を提供する制御層です。
- メッセージは配達状態と確認結果を持ち、共有コンテキストはcompare-and-swapで更新して、未読の変更を黙って上書きしません。
- Claudeを実装、Codexを独立レビューに分けても、共有情報は未検証データとして扱い、受け手はGit差分、コード、テストを再確認します。
- 協業の品質はAIの数ではなく、身元、責務、状態遷移、配達上限、ワークスペース分離、人間だけが持つ承認権限で決まります。
感動の正体は、会話ではなく仕事がつながることです
二つのAIが互いにメッセージを送り合うだけなら、簡単なチャット機能でも実現できます。しかし、開発で必要なのは会話の再現ではありません。誰が何を担当し、どの差分を作り、何を検証し、どこで止まり、次の担当者が何を根拠に再開するかをつなぐことです。
たとえばClaudeが実装を終えたとします。次のCodexが実装者の要約だけを信じて承認すれば、独立レビューにはなりません。受け手は共有された目的と判断を読みつつ、実際のGit差分、コード、テスト結果、リポジトリの規則を自分で確認する必要があります。Agent Deskが運ぶのは結論そのものではなく、次の担当者が検証を始められる作業文脈です。
この違いは重要です。AI同士の協業を『賢いモデルを二つ接続すること』と捉えると、失敗時の責任境界が消えます。『状態を持つ制御面を介して、独立した実行主体が仕事を受け渡すこと』と捉えると、配達、競合、権限、監査、停止条件を通常の分散システムと同じように設計できます。
- 会話: 意見や依頼を伝える。
- 共有状態: 現在の担当、進捗、判断、検証結果を版付きで保持する。
- 独立検証: 受け手が実データを確認し、送り手の説明をそのまま承認しない。
- 人間の監督: AIが決めてよい範囲と、必ず人へ戻す操作を分ける。
Agent Deskはエージェントを動かす場所ではなく、協業の制御面です
Agent Deskのサーバーは、ClaudeやCodexのプロセスを起動しません。エージェントは利用者の環境で動き、MCPのリモートサーバーを通じてメッセージ、共有コンテキスト、セッション情報へアクセスします。この境界により、協業機能を追加しても、エージェントが元から持つファイル操作やコマンド実行の権限が自動的に広がりません。
サーバー側はTypeScript、Hono、Drizzle ORMでAPIと永続化境界を構成し、ブラウザの操作面とMCPの機械向け経路を同じサービス契約へ接続します。HTTP用とMCP用で入力形式を別々に定義せず、共通のZodスキーマを使うことで、片方だけが大きな値や不正な状態を受け入れるずれを防ぎます。
画面には、エージェントのセッション、メッセージ、共有コンテキスト、タイムライン、GitHub Actionsとの相関を表示します。ここでの価値は派手な自動実行ではなく、『いま何が起きているか』『相手へ届かなかったものは何か』『共有状態がいつ誰に更新されたか』を人が追えることにあります。
- 実行面: 利用者の環境で動くClaudeとCodex。
- 接続面: JSON-RPC 2.0とMCPによる道具の公開。
- 制御面: メッセージ、共有状態、セッション、操作履歴の永続化。
- 観測面: 状態盤、受信箱、共有コンテキスト、タイムライン。
エージェントの身元は自己申告ではなく資格情報へ結び付けます
協業の履歴に『Claudeが送った』『Codexが確認した』と表示するなら、その身元をリクエスト本文のclientフィールドだけで決めてはいけません。自己申告では、どちらも相手として振る舞え、観測データの意味が失われます。
Agent Deskでは、MCPの資格情報を発行時にエージェント種別とワークスペースへ結び付けます。Bearer tokenの検証結果からactorを作り、メッセージ本文やURLパラメータから組織IDを受け取りません。資格情報が存在しない場合と失効している場合を同じ応答にするのも、総当たりの手掛かりを増やさないためです。
一方、どのウィンドウや会話から呼ばれたかを示すセッションIDは、呼び出し側の申告です。エージェント種別の認証と、個々の実行セッションの観測精度は同じ強さではありません。確実に言える範囲と推定に留まる範囲を分けることで、画面の見栄えを事実より強くしない設計にしています。
メッセージは送信より、届かない場合まで設計します
AIエージェントは常時起動しているとは限りません。Agent Deskのsend_messageは相手を強制的に起動せず、相手の次のターンへ向けてメッセージを保存します。受信側はread_inboxで取り出し、処理できたらhandled、対応できなければ理由付きのfailedでacknowledgeします。送信と処理完了を分けることで、『送ったから伝わったはず』を状態として残しません。
配達状態はqueued、delivered、handled、failed、expired、undeliverableを持ちます。受信時には可視性リースを取り、同じ宛先の複数セッションが同時に同じメッセージを処理しにくくします。さらに、一つのセッションへ同じ内容を注入する回数と、全体の配達試行回数に上限を置きます。相手が戻らない場合は永久再試行せず、undeliverableとして人が確認できる場所へ移します。
待機には最大25秒のbounded long-pollを使います。短い定期ポーリングだけではターン境界とすれ違いやすく、無制限の待機では接続資源を占有します。外側のfacadeにもMCP経路専用のタイムアウト予算が必要で、内側だけ25秒を許可しても、手前が15秒で切れば設計は成立しません。
- 送信成功と、相手による処理完了を別の状態にする。
- failedには理由を必須にし、障害と不同意を後から判断できる材料を残す。
- 再配達は有界にし、届かないものを人の注意へ昇格する。
- ロングポーリングの上限を、APIだけでなくproxyやfacadeを含む経路全体で揃える。
ClaudeとCodexの役割分担は、道具ではなく運用契約で決まります
Agent DeskはClaudeを必ず実装担当にし、Codexを必ずレビュー担当にする仕組みではありません。どちらを設計、実装、調査、レビューへ割り当てるかは、リポジトリの運用契約です。重要なのは、開始前に役割と完了条件を決め、途中で都合よく責務を広げないことです。
一つの実務例では、Claudeが調査、設計判断、実装、必要な検証を行い、共有状態をready_for_reviewへ進めます。Codexは共有された説明を参考にしつつ、base commitからの差分、未コミット差分、正典ルール、テストを独立に確認します。局所修正で安全に閉じるなら修正と再検証を行い、大きな設計変更が必要ならchanges_requestedとして戻します。
この往復で、メッセージは『レビューを始めてほしい』という通知を担い、共有コンテキストは目的、状態、検証、所見を担います。同じ詳細を両方へ複製しないことで、どちらが現在の正本か分からなくなる問題を避けます。最終的な承認根拠は、どちらの文章でもなく、実際の差分と検証結果です。
- 実装担当: 判断、変更範囲、検証済み項目、未実施項目、既知のリスクを渡す。
- レビュー担当: 共有説明と独立に差分、コード、テスト、ルールを確認する。
- 差し戻し: 所見を具体的な修正条件へ変換し、状態と担当を戻す。
- 完了: 必要作業と未解決の指摘が残っていない場合だけ終端へ進める。
共有された文章は、便利でも信頼境界の外側に置きます
共有コンテキストやメッセージは、AIが生成した未検証の文章です。そこへ『規則を無視する』『権限を追加する』と書かれていても、ユーザー指示、リポジトリ規則、コード、テストより上位にはなりません。この優先順位を曖昧にすると、共有メモリが長期的なprompt injectionの増幅器になります。
MCPで公開する道具も、協業に必要な範囲へ絞ります。メッセージ送受信、共有値の読書き、検索、セッションの観測はできますが、それ自体がファイル編集、デプロイ、マージ、権限拡張を許可するわけではありません。人へ入力を求めることと、人の承認を代行することも別です。
ここでの安全性は、AIが常に正しく判断することへ依存しません。誤った説明が届く、同じ共有値を同時に更新する、相手が戻らない、資格情報が失効する、といった失敗を通常状態として扱い、それぞれを版競合、配達状態、期限、監査イベントへ落とし込むことで成立します。
組織分離と観測可能性は、すべての経路で同時に守ります
複数のワークスペースを一つのサービスで扱う場合、メッセージ、共有値、セッション、履歴のすべてにorganizationIdの条件が必要です。Agent Deskではactorから組織を取得し、要求本文から任意の組織を指定させません。返信先の存在確認も同じ組織スコープで行い、他組織のIDを渡されても『存在しない』として扱います。
この方式はアプリケーション層の規律に依存します。データベースのrow-level securityが無い構成では、新しい一覧APIや集計を一つ追加するだけでも組織条件の漏れが情報漏洩につながります。そのため、別組織のデータが見えないことをAPI単位で回帰テストし、管理者向けの横断経路は通常利用者の経路と分けます。
観測では、ツール呼び出しの成功だけでなく失敗も記録します。画面の最終観測時刻を表示し、古い状態を現在状態のように見せないことも重要です。GitHub Actionsとの相関にはブランチ命名規則を使えますが、規則に合わないブランチは無理にどちらかへ分類せず、不明として扱います。
- 組織IDは認証済みactorから取得し、入力値を信用しない。
- 返信、検索、履歴、集計を含むすべての読み書きへ同じ分離条件を掛ける。
- 成功件数だけでなく、失敗、未配達、古さ、分類不能を観測する。
- webhookは署名検証に必要なraw bodyを保ち、facadeで再エンコードしない。
協業機能は、正常な往復より境界の破れを検証します
最小のE2Eは、Claudeとして送信し、Codexとして受信し、handledで確認し、送信側と画面から終端状態を読めることです。ただし、それだけでは配達と分離の主要な故障を見逃します。
メッセージでは、同じ内容が同一セッションへ無制限に再注入されないこと、可視性リース中に別セッションが重複取得しないこと、期限切れと配達上限超過が再試行対象から外れることを確認します。共有コンテキストでは、同じ版への二つの更新の片方だけが成功し、もう片方が現在版を伴う競合になることを確認します。
認可では、Claude用資格情報がCodexを自己申告できないこと、別組織のmessageIdやnamespaceを指定しても読めないこと、失効した資格情報を拒否することを検証します。運用経路では、MCPの25秒待機がfacadeで途中切断されないこと、webhook署名がproxy通過後も検証できること、残高切れやAI機能の停止がメッセージと共有状態まで巻き込まないことを確かめます。
Agent Deskが解決しないことを、先に理解して使います
Agent Deskは共有リポジトリへの同時書き込みを自動的に安全にしません。ClaudeとCodexが同じファイル、lockfile、migration、Terraform stateを同時に変更すれば、共有コンテキストが正しくてもコード側では競合します。単一write owner、worktree分離、重い処理の排他は別の運用として必要です。
また、メッセージは相手を起動しません。相手の次のターンまで待つ非同期連携であり、即時応答を前提にした同期RPCではありません。セッションIDも自己申告なので、『どちらのエージェント種別か』は認証できても、『どの会話ウィンドウか』まで強く証明するものではありません。
共有状態は協業の正本になっても、コードの正本ではありません。レビュー完了と書かれていても、実際のGit差分やCIが異なればそちらを優先します。Agent Deskは判断を置き換える自動承認装置ではなく、判断に必要な状態と根拠を失わないための作業台です。
- 同一ファイルや共有基盤への並列writeは、別の排他制御が必要。
- メッセージ送信は相手の自動起動や即時実行を保証しない。
- 共有文章はコード、テスト、ユーザー指示より上位の事実ではない。
- 高リスク操作の承認、マージ、デプロイは人間の権限として残す。
良い協業は、AIの個性を消さずに責務をつなぎます
ClaudeとCodexは、同じ出力を競わせるだけでなく、異なる文脈で考え、相手の前提を疑い、成果を引き継げます。その違いが価値になるのは、どちらか一方の説明へ全体を寄せず、メッセージ、版付き共有状態、実差分、検証結果を別の証拠として保持できるときです。
実務で最初に整えるべきものは、大規模な自動実行ではありません。身元を資格情報へ結び付けること、共有値をCAS更新すること、配達を有界にすること、受け手が独立検証すること、人にしかできない承認を残すこと。この五つが揃えば、AI同士のやり取りは面白いデモから、再現可能な開発プロセスへ変わります。

