コンテンツにスキップ

エージェントのディスパッチライフサイクル

ディスパッチとは、1 つのエージェントが、1 つの会話で、1 つのアダプター上で行う 1 回の実行です。それに関するすべては cc_server 上で起こります。クライアントはメッセージを送り、その後、返ってくるイベントのストリームを眺めるだけです。どのクライアントにもディスパッチの経路はありません。

エージェントが起こされる理由は 6 つあり、実行はそれをウェイクコンテキストとして運ぶため、エージェントは自分が_なぜ_起きているのかを把握できます:

ウェイク理由 トリガー
userMessage 誰かがスペースでメッセージを送った、またはエージェントにメンションした
assignment チケットがエージェントに割り当てられた
pipelineStep パイプラインステップがそれをディスパッチした
childCompleted 子チケットが完了した
followUp スケジュールされたフォローアップのハートビート
recovery 復旧パスが失敗後に再ディスパッチした

ウェイクコンテキストは、理由に付随する ID — チケット、スペース、メッセージ、パイプライン実行 — を運び、それらはエージェントの環境とプロンプトに注入されます。

プロンプトはレイヤーごとに、それぞれラベル付きのセクションとして構築されます:

  • アイデンティティ — エージェント自身の ID、名前、ワークスペース ID と、それらの正確な UUID をワークスペーススコープのツールに渡すよう明示的に指示する文です。ワークスペースはエージェントに内在するため、常に存在します。
  • ツールカタログとリソースプロトコル、続いてワークスペースレイアウト。
  • システムプロンプトの上書き(エージェントに設定がある場合)、続いてペルソナ(ロールでパラメーター化されます)とチームブリーフ。
  • スキル — エージェントに付与された名前です。
  • 現在のモードの実行コントラクトと手順。
  • ウェイクコンテキストとメンションコンテキスト: 誰がエージェントを呼び出したか、そしてその周囲のメンバー構成。
  • モードブロック — そのモードの機能プロファイル_と実体化されたツールリスト_から生成されるため、プロンプトが実行に実際には存在しないツールを名指しすることは決してありません。
  • メモリコンテキスト — タスクのために取得されたファクト。
  • 会話コンテキスト — 最近のスペース履歴で、エージェントに設定されたコンテキストサイズにかかわらず、逐語のウィンドウは 50,000 文字に上限が設けられます。古い履歴は切り捨てられません。エージェントは get_messages でオンデマンドに取得し、意味的に関連する古いメッセージも依然として浮かび上がります。

コマンドは 2 か所に分かれています。/todo と /compact はコンポーザーで横取りされ、意図的にメッセージとして永続化されることも、エージェントに送られることもありません — /compact を永続化すると、コンパクションの区切りが 1 ターン分後ろにずれ、トランスクリプトが汚れるからです。/plan は両方で扱われます。コンポーザーがスペースのモードを切り替え、それによってツール面、ガードプリセット、プロンプトが、このターンとそれ以降のすべてのターンで一致します。/goal、/loop、/skill:<name> は実行の内部で、しかも内蔵ハーネス上でのみ扱われます — /goal と /loop はコスト予算を伴う自律作業を開始し、skill: を前置した名前はスキルとして検索され、その SKILL.md の本文がそのターンの指示になります。名前空間が 2 つの語彙を切り離しています。スキルに対して素の名前を解決する方式では、plan や compact という名前のスキルが組み込みコマンドに恒久的に隠されてしまっていました。組み込み以外の素の名前は、名前空間が存在する前に書かれたメッセージのために、今でも解決されます。認識されない名前は、そのままプレーンテキストとして素通りします。

何かが動き出す前に、会話は独自の作業ルートを手に入れ、その下にリポジトリごとの分離されたコピーオンライトのワークツリーが置かれます。既定ではそれが、ワークスペースにリンクされたすべてのリポジトリです。PR スペース — または明示的な選択で作成されたスペース — は、許可リストに載っているものだけをプロビジョニングし、PR レビューの会話は、その 1 つのリポジトリをプルリクエストの head ref に固定し、他はデフォルトブランチのままにします。ソースのチェックアウトが変更されることはなく、スペースが削除されると会話ディレクトリ全体が回収されます。

rift が同梱されているすべての場所では、同梱のネイティブに支えられたコピーオンライトが唯一の実装です。reflink できないファイルシステム — またはリポジトリとは別のボリュームにあるデータディレクトリ — は、フォールバックせずにプロビジョニングを失敗させます。git worktree は、コピーオンライトのバックエンドをビルドできない Windows でのバックエンドであり、他のホストで暗黙に格下げされるものではありません。rift を同梱するプラットフォームで rift が見つからないのは壊れたインストールです — 黙ってフォールバックするよりも、サーバーは起動を拒否します。黙ったフォールバックは、その壊れをより遅い経路の背後に永久に隠してしまうからです。

アイデンティティは、どのプロセスが起動されるよりも前に、実行ごとに 2 つ解決されます。

Git の著者情報。 エージェントが作成するコミットは、_エージェントとして_作成されます — GIT_AUTHOR_* と GIT_COMMITTER_* の両方で <Name> (agent) <agentId@agents.control-center.local> となり、人間になりすますことはありません。ローカル部はエージェントの UUID であり、その名前スラグではありません。依頼した人間は Co-Authored-By: トレーラーでクレジットされ、それは環境で運ばれ、システムプロンプトでも指示されます。呼び出し側が明示的に設定したアイデンティティは、常にその両方に優先します。

forge のアイデンティティ。 実行の GitHub 資格情報は、常にブローカーのものだけです — リポジトリスコープの App インストールトークン、またはその環境 PAT フォールバック — 依頼したメンバー自身が保存したトークンになることはありません。actingUserId は PAT フォールバックを制限するため、サーバー所有者ではないメンバーがサーバーの到達範囲を継承することはありません。ただし、エージェントの環境に個人トークンを重ねることはしません。

モデルプロバイダーの資格情報は決まった順序で解決され、その順序が重要です:

  1. アダプター単位の環境オーバーライド
  2. 呼び出し側の環境
  3. サーバーの資格情報ストア(OAuth トークンが失効間近であれば更新します)
  4. プロセス環境

アダプター単位のオーバーライドが最初に来るため、アプリで接続したプロバイダーアカウントを黙って打ち負かします。ある実行が誤ったアカウントに課金されている場合は、まずそのオーバーライドを確認してください。プロバイダーの資格情報はホスト全体にわたり、インストール上のすべてのワークスペースで共有されます。

実行の GitHub トークンは資格情報ブローカーから提供されます。これはワークツリーのリポジトリにスコープされた読み取り専用のトークンです。プッシュはエージェント実行ゲートウェイを通り、ゲートウェイは転送前にリモートへプッシュのルールに問い合わせます。チケット管理のキーは注入されません。サンドボックスとセキュリティを参照してください。

実行は、ワークツリーを作業ディレクトリとして起動され、Claude Code の場合は、エージェントが Control Center のツール面に到達できるよう生成された MCP 設定も渡されます。ACP とハーネスの bash にはサニタイズされた環境が渡されます。NoSandboxAdapter 経由の Claude Code はホストの環境を継承します。

実行は型付きのイベント列を返し、ストリームプロセッサーがそれをメッセージ差分として永続化し、トランスクリプトセグメントに畳み込み、メッセージングイベントに変換します:

イベント 内容
thinking 推論の出力。インラインで描画されます
text 可視の出力
toolCall ツール呼び出し。その ID と構造化された引数を含みます
toolResult 対応する結果。エラーになった場合や部分ストリームである場合にフラグが立ちます
usage 計測ウィンドウのトークン数とコスト
error エラー。アダプターが報告した場合はその構造化コードを含みます
sandboxViolation OS がシステムコールを拒否しました。サンドボックスが実際にプロセスをラップしている場合にのみ発行されます — 上のノートを参照してください
debug ランタイム診断(起動マーカー、ガードの判定、コントラクトの催促)
done 実行が終了しました

意図的に、どこにもターン上限は設けていません。ハードなイテレーション回数は、正当な長期作業(マイグレーション、ファンアウトのクリーンアップ)を打ち切り、下記のガードがより早く捕まえるものを何も捕まえません。実行が終わるのは次の場合です:

  • モデルが自ら停止したとき。
  • 人間が停止したとき、または会話を引き継いだとき(内蔵ハーネスは次のきれいなターン境界で一時停止します — 安全な境界を持たない Claude Code の実行は、代わりに停止されます)。
  • 無音ウォッチドッグが発火したとき。しきい値のあいだ出力がなければ、セッションは silentRun 失敗で終了されます。既定値は 15 分で、読み取り中心のモード(レビューとプラン)では 10 分に下がります。エージェントは 1 分から 240 分のあいだでこれを上書きできます。ウォッチドッグは子プロセスが PID を報告した時点で武装されるため、Claude Code CLI を対象にします — 何も起動しない内蔵ハーネスは対象外です。
  • コスト上限が作動したとき — ただし自律コマンドに限られます。

ドゥームループガードは終了装置ではありません。同一のツール呼び出しが 3 回続くと、ループはエージェントを_軌道修正_してアプローチを変えさせます。

まとめると、内蔵ハーネス上の通常の対話的なターンには、ターン上限も、コスト上限も、無音ウォッチドッグもありません。モデルが停止するか、あなたが停止したときに終わります。これは意図的なトレードオフです — 代替案はどれも正当な長期作業を殺してしまうからです — ただし、それは無人で走る対話的な実行が、モデル自身の判断以外に何にも制限されないということを意味します。

実行の途中で、実行中のエージェントに送られたメッセージは軌道修正としてキューに入れられ、次のターン境界で排出されるため、実行を殺さずにそっと方向づけできます。軌道修正、一時停止、サブエージェント、完了コントラクトは内蔵ハーネスの機能です。Claude Code にはそのいずれもありません。

すべてのディスパッチは AgentRunLog を書き込みます。開始時刻と終了時刻、サマリー、トークン数と推定コスト(サブエージェントから積み上げられたコストを含む)、アダプターとモデル、プロセス ID とログパス、その実行が属する会話とチケットやパイプライン実行、そして真実の大半を担う 2 つの分類フィールドです。

  • ステータスは粗い粒度です: pending、running、completed、error。
  • ライブネスはより細かい読み取りです: alive、productive、completed、blocked、empty、looping、failed、stalled、dead。
  • エラー分類は失敗を役立つ形でまとめます: transientUpstream、sandboxInfrastructure、budgetExceeded、processLost、silentRun、unknown。

実行を閉じると AgentRunCompleted が発行され、多くのものがこれに連なります。パイプラインのコスト集計、実行を待っていたパイプラインステップの再開、元になったチケットの完了、オーケストレーションの終端状態へのマッピング、ゴールスーパーバイザーの継続か停止かの判断、チェッカーのロール、実行後の予算評価です。プレゼンスの名簿は別途、イベントではなく最近の実行ログを監視することで更新されます。「エージェント完了」の通知はこの一覧に含まれません。このイベントはプロセスのストリームが終わった時点、つまり返信が書き込まれる前に発火するため、通知はそのターンの MessageReceived であり、メッセージが永続化された後に発行されます。

予算の強制は_リアクション_であり、ゲートではありません。実行が完了すると、評価器がエージェントの月初からの支出を実効的な上限(リンクされた予算ポリシーがあればそれ、なければエージェント自身の月額。ゼロは無制限を意味します)と比較します。ソフトしきい値を超えると警告インシデントが記録され、予算を使い切るとハードインシデントが記録され、組織図上でエージェントのライフサイクルステータスが paused に切り替わります。それでもディスパッチはそのエージェントからの作業を受け付けます。BudgetThresholdCrossed パイプライントリガーは、同じイベントからフォローアップ作業を開始できます。

すべての実行ログはリトライの系譜を運ぶことができます — 親実行 ID、試行カウンター、継続サマリーです。会話の実行ツリーは、試行番号がゼロでないときにそれを表示します。チャットからの「再試行」は、新しい実行ログを伴う新しいディスパッチです。