セルフホストされた環境は Team および Enterprise プランでパブリックベータ版です。Owner が Cloud environments 管理ページ で Allow self-hosted environments をオンにすることで有効になります。このページは動作するランナーを前提としています。セットアップについては クイックスタート を、フリートレシピについては 本番環境へのデプロイ を参照してください。
pool を使用しています(例:CLAUDE_RUNNER_POOL_ID)。CLI フラグと環境変数名は environment を使用しています(例:--environment-secret-file)。
ラッパースクリプト
各セッションがランナー自体では実行できないセットアップが必要な場合、ラッパースクリプトを使用します。セッション作成者にスコープされた短期認証情報のプロビジョニング、環境固有のシークレットのエクスポート、言語ツールチェーンの準備、または子プロセスの周囲のリソース制限の適用などです。ランナーはセッションごとに 1 回、Claude Code バイナリの代わりにラッパーを起動します。ラッパーを終了するには、$CLAUDE_RUNNER_CLAUDE_BIN(ランナー自体のバイナリ)に exec することで、シグナルと終了コードが正しく伝播します。
ランナーを起動するときに --exec-path または SELF_HOSTED_RUNNER_EXEC_PATH をラッパーに指定します。
ラッパーはこどもの管理環境の残りの部分も継承します。これには、サーバーが提供する環境変数が含まれます。
exec はすべてを自動的に伝播します。ラッパーが別の方法でこどもをスポーンする場合、完全な環境を転送します。
stdin とファイルディスクリプタ 3 を接続したままにする
こどもの stdin はランナーのコントロールチャネルです。トークン更新とセッション終了シグナルがそこに到着します。ランナーはファイルディスクリプタ 3 でパイプも開き、こどものアクティビティシグナルを読み取ってアイドルおよびスタートアップタイムアウトを駆動します。プレーンなexec "$CLAUDE_RUNNER_CLAUDE_BIN" "$@" は両方を自動的に保持します。
ラッパーが裸の & でこどもをバックグラウンドにする場合、こどもの stdin が切断されます。セッションは初期 OAuth トークンの約 30 分の有効期限が切れるまで健全に見えますが、その後すべての API 呼び出しが 401 authentication_error で失敗します。ラッパーがこどもをバックグラウンドにする必要がある場合(例えば、ティアダウントラップを生かしておくため)、stdin をファイルディスクリプタ 4 以上に保存し、明示的に再接続します。
セッション作成者にスコープされた認証情報をプロビジョニングする
decode-token サブコマンドを使用してセッション JWT からクレームを読み取ります。引数、CLAUDE_CODE_SESSION_ACCESS_TOKEN、または stdin からトークンを読み取ります(この順序で)。セッション内のトークンを検証する を参照して、何をチェックするかを確認してください。以下の例は作成者 ID をデコードし、短期 AWS 認証情報と交換し、Claude Code に exec します。
jq -r ではなく jq -re を使用して、不在のクレームが下流に文字列 null を渡す代わりにゼロ以外で終了するようにします。組織のサービス ID(ボットおよびエージェントセッションなど)によって作成されたセッションは、user: サブジェクトではなく agent: サブジェクトを持つため、この例はそれらを拒否します。環境がそれらのセッションを提供する場合、ラッパーが終了する代わりにデフォルト認証情報にフォールバックするかどうかを明示的に決定します。認証情報交換が SSO サブジェクトまたはメールが必要な場合、.act.attested_by.sub または .act.email を読み取り、それらの不在を処理します。トークンは作成サーフェスが記録した場合にのみそれらを持ち、CLI ディスパッチセッション は両方を欠く可能性があります。完全なクレーム参照とランナーの外のサービスからの検証については、セッション ID を検証する を参照してください。
ライフサイクルフック
ライフサイクルフックはランナーのセッションごとのパイプラインのステージを独自のスクリプトに置き換えます。--hooks-dir <path> または SELF_HOSTED_RUNNER_HOOKS_DIR でランナーをフックのディレクトリに指定します。ランナーは既知の名前の実行可能ファイルを探します。存在しないフックはビルトイン動作にフォールスルーするため、必要なものだけを書きます。フックはランナー自体の権限で実行され、セッションこどもはその UID を共有するため、フックディレクトリを読み取り専用でマウントするか、イメージにベイクするため、セッションコードはそれを変更できません。強化セクション を参照してください。
これらのフックは Claude Code フック(セッション内で実行)とは異なります。ライフサイクルフックはランナーで、セッションの周囲で実行されます。
checkout
リポジトリごとに 1 回実行され、ランナーのビルトインクローンとフェッチの代わりに実行されます。フックを使用して読み取りスルーミラーからクローンし、アーカイブからワーキングツリーをシード、またはセッションごとの git 認証を適用します。ランナーは以下を設定します。
スクリプトは
CLAUDE_RUNNER_CHECKOUT_PATH にワーキングツリーを残し、要求されたリビジョンでチェックアウトする必要があります。デタッチされた HEAD は問題ありません。ランナーはその上にセッションのワーキングブランチを作成します。ランナーはその後、パスに .git が含まれていることを検証します。フックが Perforce や解凍されたタールボールなどの非 git ソースを具体化する場合、ランナーの環境で CLAUDE_RUNNER_SKIP_GIT_VERIFY=1 を設定してそのチェックをスキップします。ワーキングブランチ作成と結果のプッシュなどの git ベースのフローには git チェックアウトが必要なため、post-session フック で非 git ツリーから結果をエクスポートします。
ランナーはフックに git 認証情報を渡しません。代わりに、セッションの ID からセッションごとのクローン認証情報を発行します。セッション ID を検証する で説明されているように、標準 JWT ライブラリを使用して CLAUDE_CODE_SESSION_ACCESS_TOKEN を CLAUDE_RUNNER_API_BASE_URL の下の JWKS エンドポイントに対して検証し、トークンの act クレーム内の ID に対して認証情報サービスが短期クローン認証情報を発行するようにします。CLAUDE_RUNNER_CLAUDE_BIN はチェックアウトフック環境で設定されないため、decode-token サブコマンドはここでは利用できません。ホストが既に持っている git 認証(SSH エージェント、認証情報ヘルパー、.netrc など)にフォールバックするのも選択肢です。
フックがゼロ以外で終了するか、0 で終了して使用可能なチェックアウトを残さない場合、ランナーが実行する内容はリポジトリによって異なります。
- セッションが結果をプッシュするリポジトリ:ランナーはセッションを失敗させ、ゼロ以外の終了時にスクリプトの stderr の末尾をユーザーに表示します。
- セッションが読み取るだけのリポジトリ(実行中のセッションに追加されたリポジトリなど):ランナーは失敗の詳細を含む
[runner:warn]行をログに記録し、Skippedステップをセッションにポストし、フックがチェックアウトパスに残したものを削除し、残りのリポジトリで続行します。ランナーがパスをすぐに削除できない場合、セッション終了時に削除を再試行します。スキップがセッションをリポジトリなしで残す場合、ランナーはとにかくセッションを失敗させます。
post-session
セッションごとに 1 回実行され、Claude Code こどもが終了した後、ランナーがワークスペースをティアダウンする前に実行されます。このフックはコミットされていない作業を保存する唯一のチャンスです。--capacity が 1 より上の場合、ランナーはフックが返った直後にセッションごとのワークツリーを削除し、--capacity 1 の場合、再利用された 正規クローン は次のセッションが開始されるときにハードリセットされるため、コミットされていない追跡変更はどちらのパスでも生き残りません。典型的な用途は、コミットされていない変更のスナップショットブランチをプッシュ、ログをアーカイブ、またはセッション終了イベントを独自のシステムに発行することです。
フックはこどもプロセスがスポーンされたセッション終了のすべてで発火します。原因は何でもかまいません。以下の CLAUDE_RUNNER_EXIT_REASON 値はケースを列挙します。ランナーが突然終了する場合(VM プリエンプションまたは停電など)は発火できません。突然の終了に対する保証が必要な場合、代わりに Claude Code PostToolUse フックを使用してセッション内から定期的にスナップショットします。ランナーは以下を設定します。
CLAUDE_RUNNER_EXIT_REASON は 4 つの値のいずれかを取ります。
completed:クリーンな終了。こどもがまだ接続されている間にセッションがアーカイブまたは削除されたことを含みます。failed:こどもクラッシュまたはスポーン後のセットアップ失敗。interrupted:アイドルリリース、スタートアップタイムアウト、サーバーデアサイン、ドレイン、またはウォッチドッグキル。abandoned:別のランナーが要求したセッション用に予約されています。フックは現在その場合に発火しません。
completed として分類します。セッションの観点からはクリーンなハンドオフですが、このフックはそれらを interrupted として報告します。
フックの終了ステータスはセッション結果に影響しません。失敗はログに記録され、無視されます。ランナーはすべてのセッション終了(ランナーシャットダウンを含む)で --post-session-hook-timeout-sec(デフォルト 60 秒)まで待機します。この例はコミットされていない作業をレスキューブランチに保存します。
CLAUDE_CODE_SESSION_ACCESS_TOKEN のセッショントークンを独自のトークンサービスと交換し、セッション ID を検証する で説明されているように検証します。フックがセッションが持たなかった認証情報を保持する場合、プッシュ先もピン留めします。origin をオペレーター提供の URL に置き換え、-c credential.helper= と独自のヘルパーを渡して、セッションが書き込んだリポジトリローカル設定が認証情報付きプッシュをリダイレクトできないようにします。
ランナーがセッションをリリースするときのフックタイミング
リリースされたセッションは別のランナーで再開できます。v2.1.236 以降のランナーでは、セッションがリリース時に何をしていたかによって、このフックが終了する前に別のランナーで再開できるかどうかが決まります。- ターン後のアイドル、またはスタートアップでタイムアウト:ランナーはこどもを停止し、このフックを完了まで実行します。その後でのみセッションをリリースします。フックが実行されている間に送信されたユーザーメッセージは、フックが終了する前に別のランナーでセッションを再開できません。
- ユーザーがプロンプトに答えるのを待機中(権限プロンプトなど):ランナーは最初にセッションをリリースし、その後このフックを実行します。フックが実行されている間に送信されたユーザーメッセージは、フックが終了する前に別のランナーでセッションを再開できます。
--retire-at 時間でのリリースは同じ 2 つのパスに従います。SIGTERM ドレイン中、ランナーはフックが終了するまでセッションリースを保持します。シャットダウンタイミング を参照してください。v2.1.236 より前は、ランナーは両方のパスで最初にセッションをリリースし、その後このフックを実行しました。
command
セッションごとに 1 回実行され、チェックアウト後、ビルトインこどもスポーンの代わりに実行されます。フックは ラッパースクリプト と同じ環境を受け取り、同じ方法で"$CLAUDE_RUNNER_CLAUDE_BIN" に exec する必要があります。command フックを使用してすべてのカスタマイズを 1 つのフックディレクトリに保つ。ラッパーが他の場所にある場合は --exec-path を使用します。--exec-path も設定されている場合、フラグが優先され、command フックは無視されます。
PATH 解決された claude ではなく、常にランナー自体のバイナリに exec してください。そうしないと、バージョンピン留め を無効にします。
オンデマンドランナー
固定フリートを実行する代わりに、セッションごとに 1 つのランナーをブートできます。オーケストレーターは別の、ステートレスなサブコマンドで、Anthropic にスポーン要求をポーリングします。利用可能なランナーがないキューに入っているセッションごとに 1 つの要求をポーリングし、各要求に対してspawn-runner フックを実行します。フックは、ワークロードをプラットフォームに送信します。Kubernetes Job、EC2 インスタンス、Nomad dispatch などです。
オンデマンドランナーは認証情報の衛生状態を改善します。固定フリートでは、環境シークレットはすべてのランナーホストに存在し、これはユーザーセッションを実行するのと同じホストです。オーケストレーターを使用すると、環境シークレットはオーケストレーターホストにのみ存在し、ユーザーコードは実行されません。各スポーンされたランナーは、正確に 1 つのランナーを登録してから期限切れになる単一用途の作業指示を受け取ります。
オーケストレーターを開始するには、環境シークレットと実行可能な spawn-runner スクリプトを含むフックディレクトリを渡します。
--expected-spawn-seconds 値を使用する必要があります。フックコントラクトを参照してください。
spawn-runner フック
オーケストレーターは、スポーン要求ごとに 1 回${hooks-dir}/spawn-runner を実行します。フックは非同期でワークを送信する必要があり、ランナーのブートを待たずに、--hook-timeout(デフォルトは 60 秒)以内に戻る必要があります。フックは以下を受け取ります。
スポーンされたランナーは、環境シークレットの代わりにワークオーダーで登録します。
- ワークオーダーで開始します。
--environment-secret-fileをワークオーダー JWT を含むファイルに指定するか、SELF_HOSTED_RUNNER_ENVIRONMENT_SECRETを JWT 値に設定します。 - フック終了前に JWT をコピーします。オーケストレーターはフック終了後にワークオーダーファイルを削除するため、JWT を送信するワークロード(スポーンされたジョブの Kubernetes Secret など)にコピーし、ファイルパスを渡さないでください。
- スポーンされたランナーで
--capacity 1を使用します。セッションバウンドワークオーダーは正確に 1 つのランナーをそのセッションにバウンドするため、より高い容量を使用するとスロットが追加されますが、これらのスロットは作業を受け取らず、ランナーはスタートアップで警告をログに記録します。 - 事前ウォーミングワークオーダーはアンバウンドで登録します。スタンバイランナーはセッションにバウンドされず、固定フリートランナーのようにキューに入った作業を要求します。
CLAUDE_RUNNER_ORDER_IDでべき等です。 同じ要求の再配信は、最大 1 つのランナーをスポーンする必要があります。ID から決定論的なリソース名を導出し、プラットフォームに重複を拒否させてください。- ワークロードを再試行しないでください。 1 つのオーダー ID は、最大 1 つの作成されたワークロードを意味します。ランナーが登録されない場合、Anthropic は
--expected-spawn-seconds後に新しいオーダー ID で再要求します。 - 終了コードコントラクトを使用します。 終了 0 は送信されたことを意味します。終了 1 は再試行可能な失敗を意味します。セッションはバックオフして再度提供されます。終了 2 以上は再試行不可を意味します。セッションは、Owner が環境の Activity タブでそれに対して Retry を選択するまで、再度スポーンされることがブロックされます。ゼロ以外の終了時に、フックの stderr の末尾がそこに失敗理由として表示されるため、実行可能なエラーを stderr に書き込み、シークレットは決して書き込まないでください。事前ウォーミング要求の場合、失敗するセッションはありません。オーケストレーターはゼロ以外の終了をローカルでのみログに記録し、サーバーはリース後にスポーンを再要求します。
--expected-spawn-secondsを少なくとも p99 ブート時間に設定します。 これはサーバー側のリースです。すべてのオーケストレーターレプリカは同じ値を使用する必要があります。
/healthz ボディをチェックしてキュー数を確認し、Cloud environments 管理ページで環境の Activity タブを開きます。失敗したセッションをそこで展開してスポーンエラーを確認し、Retry を選択して再要求してください。
MCP サーバー
MCP サーバーをすべてのセッションで利用可能にするには、デスクトップインストールで使用する同じclaude mcp add コマンドを使用して、イメージビルド時に追加します。ランナーがコンテナではなくベアプロセスの場合は、ホスト上でランナーのユーザーとして同じコマンドを実行してから、ランナーを再起動します。ランナーは起動時に一度だけホスト設定を読み込みます。--scope user フラグが必須です。デフォルトのローカルスコープはディレクトリごとのキーの下に書き込まれ、ランナーはセッションにシードしません。例えば、Dockerfile では以下のようになります。
.claude.json から mcpServers キーをキャプチャします。.claude.json は ~/.claude/ の内部ではなく隣に存在し、ランナーはそのキーのみを各セッションの分離された設定にシードします。アカウント状態とプロジェクト履歴は削除されます。サーバーがセッションに到達したことを確認するには、環境でセッションを開始し、Claude に MCP ツールをリストするよう依頼します。ランナーはまた、キャプチャされたエントリのうち、その type を認識しないものについて起動時に警告をログに記録し、エントリを削除するため、そのサーバーがセッションから欠落している理由を確認できます。SELF_HOSTED_RUNNER_HOST_CONFIG_DIR が設定されている場合、ランナーはその代わりにそのディレクトリから .claude.json を読み込むため、変数を空のディレクトリに指すことで MCP シーディングも無効にできます。
Claude Code は他のソースからも MCP サーバーを読み込みます。
- エンタープライズスコープの管理 MCP ファイル(標準システムパス)。Linux ランナーホストでは
/etc/claude-code/managed-mcp.json、macOS ホストでは/Library/Application Support/ClaudeCode/managed-mcp.json。管理者がリストしたサーバーのみが読み込まれるロックダウンされたフリートに使用します。優先順位ルールについては、managed-mcp.json による排他的制御を参照してください。このファイルがランナーホスト上にある場合、Claude Code は Anthropic のコントロールプレーンがセッションに配信する MCP サーバー(claude.ai コネクタを含む)をスキップし、セッション子の stderr に警告として名前を付けます。ランナーはこれをdebugログレベルで記録します。v2.1.229 より前では、これらのセッションは起動時にYou cannot dynamically configure MCP servers when an enterprise MCP config is presentで終了していました。 - ランナーホスト上の管理設定の
managedMcpServersキー。排他的制御を取得しないで HTTP および SSE サーバーを提供するため、他のソースからのサーバーは引き続き読み込まれます。Claude Code v2.1.259 以降が必要です。 <repo>/.mcp.json。プロジェクトスコープ。ファイルをリポジトリにコミットします。そのサーバーはクラウドセッションで自動承認されます。
api.anthropic.com を経由してルーティングされます。CLI ディスパッチなどプログラムで作成されたセッションはコネクタ配信を受け取りません。代わりに、このセクションにリストされている他のソースのいずれかを通じて MCP サーバーを提供します。子の OAuth トークンはコネクタを直接取得するためのスコープを持たないため、子はその取得を試みません。配信はサーバー駆動です。
settings.json は MCP サーバー定義を持たず、設定スキーマに最上位の mcpServers フィールドはありません。管理設定では、代わりに managedMcpServers キーでサーバーを提供します。
セッションはランナーの環境を継承するため、ENABLE_TOOL_SEARCHをそこに設定して、ランナーが生成するすべてのセッションの MCP ツール検索を制御します。MCP ページは値をカバーしています。
セッションに作業をプッシュするよう促す
Anthropic ホストセッションはStop フック(Claude Code フック。Claude が応答を終了するときに実行)を実行し、Claude にその作業をコミットしてプッシュするよう促します。ランナーはそれをインストールしません。それなしで、コミットされていない変更で終了するセッションはその作業をランナーのディスク上のみに残し、claude.ai/code の Create PR ボタンはブランチがリモートに存在するまで非アクティブなままです。
以下の参照実装には 2 つの部分があります。設定ブロックを ~/.claude/settings.json にランナーホストにマージし、スクリプトを ~/.claude/hooks/stop-hook-nudge.sh にランナーホストに保存して実行可能にします。
権限とツール承認
セルフホストセッションには接続されたターミナルがないため、未回答の権限プロンプトはユーザーが UI で応答するまでターンを停止します。Anthropic のコントロールプレーンは各セッションのツールリストと権限ルールをワークペイロードで送信します。デフォルト設定はBash を含むルーチンツール呼び出しを事前承認し、クラウドセッションは モードに関係なくファイル編集を事前承認 します。何も事前承認しない呼び出しはセッション UI を通じてプロンプトします。
デフォルト拒否ネットワーク出力 を実行するセッションコンテナと 強化セクション の残りを備えた環境でのみ、オートモードをピン留めします。ルーチンツール呼び出し(
Bash ネットワークリクエストを含む)は、デフォルト事前承認ツールセットとオートモードの両方で人間のループなしで実行されるため、ネットワーク境界がそれらの呼び出しが到達できる場所を制限するものです。command フック から オートモード をピン留めします。オートモードはセッションがルーチン権限プロンプトなしで実行されるようにします。別の分類器モデルは実行前にアクションをレビューし、拒否するものをブロックし、明示的な ask ルールはまだプロンプトを強制します。権限モードページは分類器がチェックするものをカバーしています。ランナーはラッパーを呼び出す前にサーバー計算フラグを追加し、--permission-mode などの単一値フラグの場合、パーサーは最後の出現を尊重するため、"$@" の後に追加するフラグはサーバー送信値をオーバーライドします。
--allowed-tools をルールで追加します。例えば --allowed-tools "Bash(bazel *) Bash(yarn *) mcp__internal__*"。--allowed-tools と --disallowed-tools などのリストフラグは出現全体で蓄積され、オーバーライドされないため、ルールはコントロールプレーンが送信するルールの上に適用されます。絞り込むには、--disallowed-tools を追加します。これは別のルールがそれらを許可しても、ツールを拒否します。
各セッションの設定がどのように組み立てられるか
ランナーは各セッションに独自の設定ディレクトリを提供します。ランナーが起動時に 1 回キャプチャするホストの~/.claude/ のメモリ内スナップショットからシードされます。settings.json、CLAUDE.md、フック、エージェント、コマンド、スキルがランナーイメージにあります。これらはすべてのセッションにユーザーレベルのベースラインとして適用されます。スナップショットは起動時に取得されるため、実行中のホストの設定変更はランナー再起動後にのみ有効になります。SELF_HOSTED_RUNNER_HOST_CONFIG_DIR を設定して別のパスからシードするか、空のディレクトリに指定してシーディングを無効にします。
リポジトリコミット .claude/settings.json はプロジェクト設定として上に層状化されます。セッションはランナーイメージの標準システムパスから managed-settings.json も読み取ります。そのキーが サーバー管理設定 と一緒に適用されるかどうかは、Claude Code が管理ソースを組み合わせる方法 に従います。デフォルトでは、組織が任意のサーバー管理キーを配信する場合、セッションは Claude Code がすべての管理ソースから読み取るキー(env ブロック、サンドボックスロック、サンドボックスバイナリパス、forceRemoteSettingsRefresh など)を除いて、ランナーイメージのファイルを無視します。設定優先順位 を参照してください。
Anthropic のコントロールプレーンがセッションに Claude Code フック を提供する場合、ランナーはそれらを独自の設定の上ではなく隣に設定します。Claude Code v2.1.229 以降が必要です。
- どこに着地するか:ランナーは提供された各フックスクリプトをセッションの設定ディレクトリの予約済み
hooks/.ccr-launcher/サブディレクトリに書き込み、スクリプトを--settingsで渡す別の設定ファイルに登録し、シードされたsettings.jsonとhooks/<name>の独自のスクリプトを変更しないままにします。ランナーは各セッションの予約済みサブディレクトリを再作成し、~/.claude/hooks/.ccr-launcher/のホストコンテンツをセッションにシードしません。 - 誰がそれらを作成するか:コントロールプレーンはセッションごとまたはサードパーティ入力からではなく、独自のデプロイメント内の固定定数からスクリプトを入力します。
- 何がそれらを管理するか:
--settingsを通じて配信されるフックは通常のマージされたフック設定に入り、管理層ではないため、管理設定はまだ適用されます。disableAllHooksはそれらを無効にし、allowManagedHooksOnlyが保つカテゴリーには含まれません。
リポジトリコミット権限ルール
リポジトリコミットpermissions.allow にベアな "Edit"、"Write"、または "NotebookEdit" エントリを入れないでください。ベアなファイルツールルールはパスに関係なくツールにマッチし、ワークスペースのみではなくホスト全体への書き込みを許可するため、ランナーの書き込みスコープ閉じ込めガードはセッションにフラグを立てます。--confine-repo-settings enforce を使用すると、ログして続行する代わりにセッションのスポーンを拒否します。強化セクション を参照してください。
リポジトリはファイルツールルールをまったく必要としません。クラウドセッションは モードに関係なくファイル編集を事前承認 します。ルールをコミットする場合、ワークスペースにスコープします。例えば "Edit(**)"。単一の先頭スラッシュはプロジェクトルート(セッションのワークスペース)に相対的です。ベアなファイルツールルールはオペレーターのホストレベル settings.json では問題ありません。そのファイルはリポジトリコミットされないため。
defaultMode の auto はイメージ全体またはユーザーレベルの設定ファイルからのみ尊重されるため、チェックアウトされたリポジトリはそれ自体にオートモードを許可できません。クラウドセッションが受け入れるモードと完全なルール構文については、権限モード を参照してください。
次のステップ
- リファレンス:すべての CLI フラグ、環境変数、メトリック
- セッション ID を検証する:ランナーの外のサービスからセッショントークンを検証