コンテンツにスキップ

マルチプレイヤー — アイデンティティ、メンバーシップ、プレゼンス

Control Center は単独のオペレーターでも機能しますが、その土台にあるモデルは最初からマルチアクターです。人間とエージェントは同じスペースでメッセージをやり取りし、同じチケットを編集し、同じ名簿に表示されます。これを安全かつ理解可能にする鍵は、3 つの判断に集約されます。誰がアクターと見なされるか、何がアクセスを制限するか、そしてどの状態を永続的に共有し、どの状態をライブでブロードキャストするだけにするかです。

プリンシパル — ユーザーとエージェントは対等なアクター

「プリンシパル — ユーザーとエージェントは対等なアクター」というセクション

「誰がこれをしたのか」を記録するものすべて — メッセージ、チケット、レビュー、プラン、実行ログ、監査エントリ — は、プリンシパルを通じて解決されます。これは UserPrincipal と AgentPrincipal の sealed なユニオンで、コンパクトなワイヤ形式(user:<id> / agent:<id>)を持ちます。帰属は、N 人の人間(または N 体のエージェント)を 1 つのセンチネルアカウントにまとめてしまうことはありません。そのため、エージェントが残したレビューと人間が残したレビューは、それが現れるあらゆる場所で区別できます。

プリンシパルはアイデンティティの単位であるため、封じ込めの単位でもあります。

  • レート制限はセッション単位ではなくプリンシパル単位です。 リモートのツール呼び出しに対するフラッドガードは、接続単位ではなくユーザー単位で予算を配分します。つまり、あるメンバーのすべてのデバイスが 1 つの共有スライディングウィンドウから消費します(1 分あたり 120 呼び出し、うち変更を伴ってよいのは最大 30 件)。そのため、3 台のデバイスを開いても誰かの許容量が 3 倍になることはなく、1 人の騒がしいメンバーが他のメンバーを飢えさせることもありません。
  • 元に戻せるのはプリンシパル単位です。 各クライアントのアクションジャーナルは、_その_プリンシパルが行った変更だけを記録します。自分のチケット編集は ⌘Z で元に戻せますが、チームメイトの編集は元に戻せません — あなたがそれを見るころには、永続レーンがすでに解決済みだからです(後述)。

アクセス境界はメンバーシップであり、ペアリングキーではない

「アクセス境界はメンバーシップであり、ペアリングキーではない」というセクション

2 つの別々の資格情報が、2 つの別々の問いに答えます。ペアリングキー(リモートコントロールとモバイルを参照)は、_デバイス_をサーバーに対して認証します。メンバーシップは、そのデバイスのユーザーが_ワークスペース_内で行動することを認可します。ユーザーがワークスペースのメンバーシップを持たないペアリング済みデバイスは、そのワークスペースを読み取ることも変更することもできません。

メンバーシップは (ワークスペース, ユーザー) ごとに 1 行で、そのワークスペース自身のデータベースファイルに保存されます。したがって「このワークスペースには誰がいるか?」は通常のスコープ付き読み取りであり、逆の問いである「自分はどのワークスペースに属しているか?」は必然的に複数のファイルにまたがり、数少ない公認のクロスワークスペースファンアウトの 1 つです。ワークスペースピッカーが、どのワークスペースもまだ選択されていない段階で実行するのはこれです。

各行は、5 段階のランク順のはしごから 1 つのロールを持ちます。

ロール できること
owner 完全な制御(ワークスペースの削除を含む)。ワークスペースごとにちょうど 1 つ
admin メンバー、招待、設定、破壊的操作の管理
member 日常的な読み書き: メッセージ、チケット、エージェント実行
viewer ワークスペース全体で読み取り専用。シークレット除外 glob が、コードを露出させるサーフェス上の一致するパスを隠す
guest 閲覧者と同じ読み取り専用の下限で、はしごの最下位

すべてのアクセス判断は「呼び出し元のロールが少なくとも X 以上か」に帰着します。下限は、操作が明示的に宣言していない限り、その操作の種類から導出されます。読み取りには guest、変更には member、破壊的操作には admin が必要です。以下で述べるリポジトリ単位の許可を超えるオブジェクト単位の ACL は、意図的に対象外です。

招待は、メンバーシップを付与する手段で、設定 → ワークスペース → メンバーから行います。管理者は使い捨てコード(リンクまたは QR として)を発行します。これは既定で 7 日後に失効します。サーバーが保存するのはそのコードの SHA-256 ハッシュだけで、コード自体は 1 回だけ表示されます。コードを引き換えると、ユーザーが JIT でプロビジョニングされ、招待のロールでメンバーシップが記録され(決して owner にはなりません — 所有権は明示的に譲渡されるもので、招待で付与されることはありません)、デバイスのペアリングへと引き継がれます。ペアリング後に発行されるデバイス資格情報自体も 30 日に期限が区切られているため、ペアリングは恒久的なキーではありません。

**リポジトリ単位の許可(grant)**はメンバーシップの下に位置します。サーバーが完全なチェックアウトを保持しているため、ワークスペースのメンバーシップだけでコードホストより強い権限を得ることは決してあってはなりません。コードを露出させるすべてのサーフェス — ファイル、差分、PR レビュー、コード検索 — は、_そのリポジトリ_に対するメンバーの許可をチェックします。許可は (ワークスペース, ユーザー, リポジトリ) 単位で、none → read → review → write とランク付けされます。ここで write は、リポジトリに書き込むエージェント実行を駆動することを意味します。行が存在しない場合は none を意味し、オーナーと管理者はリンクされたすべてのリポジトリに対して暗黙に write を保持し、行を一切持ちません。

Control Center は、共有状態を相反する耐久性ルールを持つ 2 つのレーンに分割します。2 種類の状態が、正反対の仕方で破綻するからです。

プレゼンス — 誰がオンラインか、どこにいるか、何を入力しているか、エージェントが今何をしているか — は、古くなった瞬間に価値を失います。もし永続化されていたら、再接続のたびに「データベースには Sam がこのチケットを編集中とある」という状態を現実と突き合わせて調整しなければならなくなります。そこでプレゼンスは決してデータベースに書き込まれません。それはサーバー上のインメモリのプレゼンスハブに存在します。クライアントは presence.update で発行し、ピアは presence.watch で購読し、エントリはハートビートを 3 回逃すと自動的に失効します(ハートビートは 10 秒ごと、ハブのスイープは 5 秒ごと)。調整すべきものは何もなく、ただ失効させるだけです。

2 つの性質が、このレーンの信頼性を保ちます。

  • アイデンティティはセッションから来るもので、クライアントの引数から来ることはありません。 サーバーは、接続の認証済みデバイスをユーザー ID にマッピングします。クライアントは自分のプレゼンスしか更新できないため、誰も他の参加者のステータスやローカスをなりすませません。明示的な offline 更新(切断、または非表示トグル)は、そのエントリを即座に削除します。
  • 名簿はサーバーハブ方式です。 ピア同士がプレゼンスを直接やり取りすることはないため、トポロジーに関係なくすべての参加者が同じ名簿を見ます。エージェントにはクライアントがないため、サーバーがライブの実行状態からエントリを_合成_します — 思考中、実行中、承認ゲートでブロック中、完了 — そしてエージェントの状態とローカスは 1 つの代表的な実行が決めるので、並行する実行によって名簿がばたつくことはありません。

ファンアウトはコンシューマーごとに階層化されています。デスクトップと Web は完全な階層(名簿の送出は最大 100 ms に 1 回)に乗り、スマートフォンは要約階層(500 ms に 1 回)に乗ります。これにより、カーソル頻度の更新が PWA を溶かすことはありません。

参加者のローカス — 現在どこにいるか、どの成果物に至るまで — は sealed なユニオンです: Space、File(リポジトリ + パス + 任意の行)、Pr、Ticket、PlanNode。すべてのローカスにジャンプ先があるわけではありません。ファイルビューアーのルートが存在しないため、File ローカスは移動先ではなくラベルとして描画されます。このレーンはソフトクレーム(「Sam がこのチケットを編集中」「あるエージェントがこのワークツリーを保持している」)も運びます。これは競合の_可視性_であり、ロックではありません。未知のローカス種別は null にパースされるため、古いクライアントは理解できないものを単に描画しません。

生き残らなければならないレコード — チケット、共有スペースの Notes ドキュメント、メッセージ — は逆の道をたどります。権威的で、順序付けられ、永続化されます。並行する編集は、クライアントの時計によってではなく、サーバーの受信順での最終書き込み優先によって解決されます。この解決は意図的に細粒度です。チケットの編集は_列単位_であるため、同じチケットの異なるフィールドを編集している 2 人はどちらも反映され、互いを上書きしません(ワークフローの遷移は従来どおり楽観的ロックを保ちます)。スペースの Notes ドキュメントは 1 列なので、ドキュメント全体が LWW であり、プレゼンスレーン上のソフトクレームが、並行編集をロックするのではなく可視化します。これは意図的に CRDT ではありません — 証明責任は CRDT 側にあり、受信順 LWW と可視化されたクレームで実際のコラボレーションパターンはカバーできるからです。

「最後の書き込み」とはサーバーの受信順を意味し、クライアントの時計を意味することは決してありません — 時計がずれたラップトップが、負けたはずの編集に勝つことはできません。永続レーンの背後には同期フィードがあります。SQLite トリガーが、すべての変更を_書き込みトランザクションの内部で_ワークスペース単位の変更ログに追記し、変更そのものと同じトランザクションで単調増加するワークスペース単位のシーケンス番号を割り当てます。サーバーサービスがそのログをシーケンス順に、バージョン付きのデルタフレームへと追いかけます。クライアントは完全なスナップショットからデルタへと進化します。シーケンスに欠落があれば、フレームを誤って適用するのではなく、そのストアをスナップショットモードに戻します。

プレゼンスレーンは単なる名簿ではありません — コラボレーションの動詞を駆動します。

  • フォローモード。 参加者をクリックすると、クライアントはその参加者のローカスに追随し、相手がナビゲートするのに合わせてナビゲートします。フォローは「あなたが行動するまで」続きます。あなたが自分の意思でナビゲートした瞬間、フォローは外れます。他の参加者が自分がいるスペースをスポットライト(発表)しているときは、閉じられるバナーで知らせます。
  • ステア。 実行中のエージェントへのメッセージは軌道修正としてキューに入り、エージェントは次のターンを再開する前にそれを読み直します。そのため、実行を止めることなく飛行中にそっと方向を修正できます。
  • 引き継ぎ。 会話の制御を引き継ぐと、すべてのアクティブな実行が次にきれいなターン境界で一時停止します(安全な境界を持たない Claude Code の実行は停止されます)。その際、ターンごとの git スナップショットが取られるため、引き継ぎは元に戻せます。永続的なマーカーがスペースへの新しいディスパッチをブロックし、サーバーの再起動をまたいで存続します — サーバーが人間の未完成の編集へ自動的に再開することは決してありません。ワークツリーごとにライブの編集者は 1 人というのはソフトクレームです。2 度目の引き継ぎは可視化され、黙ってマージされるのではなく拒否されます。
  • 返却。 制御を返すと、ワークツリーの構造化された差分サマリーがスペースに投稿され、一時停止中の実行に対する軌道修正としてキューに入り、それらが再開され、マーカーがクリアされます。

ステアと引き継ぎは事後的な介入です。自律度ダイヤルは常設の設定です。スペースごと、エージェントごとに、スペースヘッダーから設定し、エージェントがゲートされたアクションに到達したときに何が起こるかを決めます。

レベル ワイヤ値 ゲートされたツール呼び出しへの影響
提案のみ proposeOnly 無条件に拒否され、エージェントはその理由を伝えるよう指示されます — アクションを説明することはできても、実行はできません
承認後に実行 actWithApproval フェイルクローズドの承認ゲート。接続中のオペレーターに 1 件の確認が提示され、承認者がいなければ拒否となります
自由に実行 actFreely 事前承認済み。ただしハードな deny ガードレールルールが適用される場合を除きます — deny ルールが常に優先されます
(未設定) null 承認後に実行と同じ。サーバーのデフォルトです

2 つのことが、どちらの方向でもダイヤルの外にあります。モード自身の出力動詞は固定されており、ダイヤルが何を言おうと決して拒否されません — かつて orchestrate モードは、プリセットがその動詞の宣言する効果クラスを拒否したため、唯一の成果物を構造的に出力できませんでした。そして、アクションガードレールからのハードな deny は actFreely で上書きできません。

これらはすべて追加的なものです。単独のオペレーターのワークフローは変わりません。人間が 1 人でエージェントがいなければ、プレゼンスハブにはブロードキャストするものが何もないため、レーンは初期スナップショットを送出した後、トラフィックゼロで待機します。LWW と同期の仕組みは、これまでどおり同じ単一ライターの経路です。そしてペアリングキーは、これまでどおりのデバイス資格情報のままです。メンバーシップはすでにアクセス境界です — 人間が 1 人なら、オーナーの行が 1 つあるだけで、名簿の UI はありません。