自託管環境在您自己的基礎設施上執行 Claude Code 雲端工作階段,由您部署的執行器程序執行。在沒有設定的情況下,該執行器會複製工作階段的儲存庫、生成 Claude Code,然後進行清理。本頁面適用於操作執行器的平台工程師:它涵蓋了當預設值不適用時的擴展點,從每個工作階段的憑證佈建到完全替換簽出。包裝指令碼和 hook 在執行器主機上作為可執行檔案執行,該主機是 Linux 或 macOS,本頁面上的範例假設使用 POSIX shell。
本頁面上的一些 hook 環境變數仍然使用
pool,例如 CLAUDE_RUNNER_POOL_ID;CLI 旗標和環境變數名稱使用 environment,例如 --environment-secret-file。
包裝指令碼
當每個工作階段需要執行器無法自行完成的設定時,請使用包裝指令碼:佈建限定於工作階段建立者的短期憑證、匯出環境特定的祕密、準備語言工具鏈,或在子程序周圍套用資源限制。執行器每個工作階段啟動一次您的包裝指令碼,以取代 Claude Code 二進位檔案。透過exec 進入 $CLAUDE_RUNNER_CLAUDE_BIN(執行器自己的二進位檔案)來結束包裝指令碼,以便訊號和退出碼正確傳播。
在啟動執行器時,將 --exec-path 或 SELF_HOSTED_RUNNER_EXEC_PATH 指向包裝指令碼:
包裝指令碼也會繼承子程序的其餘受管環境,包括任何伺服器提供的環境變數。
exec 會自動傳播所有內容;如果您的包裝指令碼以另一種方式生成子程序,請轉發完整環境。
CLAUDE_CODE_REMOTE_SLACK_THREAD_URL 和 CLAUDE_CODE_REMOTE_SLACK_THREAD_TS 會傳到您的包裝指令碼或 command hook。它們也會傳到工作階段執行的內容,例如 shell 命令、git hook 和 Claude Code hook。checkout、post-session 和 spawn-runner hook 不會收到它們。
為可能未設定的變數提供預設值
CCR_SESSION_ACCOUNT_EMAIL、CLAUDE_RUNNER_CLIENT_PLATFORM、CLAUDE_CODE_REMOTE_SLACK_THREAD_URL 和 CLAUDE_CODE_REMOTE_SLACK_THREAD_TS 都可能未設定。如果您的指令碼使用 set -u,Bash 在展開未設定的變數時會以 unbound variable 停止,因此請以預設值展開它們,例如 ${CCR_SESSION_ACCOUNT_EMAIL:-}。
在 shell 展開 Slack 討論串連結的任何地方,請採取以下預防措施:
- 為其加上引號:連結可能包含 shell 會處理的字元,例如
?和&,因此請為變數加上引號,如"${CLAUDE_CODE_REMOTE_SLACK_THREAD_URL:-}"。 - 不要將其值放入
eval和sh -c字串中:不要將其值代入eval或sh -c執行的字串,即使在引號內也不行。請改為讓該字串參照變數。
保持 stdin 和檔案描述符 3 連接
子程序的 stdin 是執行器的控制通道。token 輪換和工作階段結束訊號會在其上到達。執行器也會在檔案描述符 3 上開啟一個管道,並從中讀取子程序的活動訊號以驅動閒置和啟動逾時。單純的exec "$CLAUDE_RUNNER_CLAUDE_BIN" "$@" 會自動保留兩者。
如果您的包裝指令碼使用單獨的 & 在背景中執行子程序,它會切斷子程序的 stdin。工作階段看起來健康,直到初始 OAuth token 大約 30 分鐘的生命週期過期,然後每個使用該 token 的 API 呼叫都會失敗,並出現 401 authentication_error。如果您的包裝指令碼必須在背景中執行子程序,例如為了讓拆卸 trap 保持作用,請將 stdin 儲存在檔案描述符 4 或更高的編號上,並明確重新連接它:
- 檔案描述符 3:將子程序的活動訊號傳送給執行器。不要在包裝指令碼中關閉或重複使用它。
- stderr:當包裝指令碼或子程序以非零狀態退出時,執行器會將 stderr 的最後幾行張貼到工作階段,並在自己的日誌中印出。工作階段的使用者會看到這些行,因此不要將祕密印到 stderr,並在部署包裝指令碼前移除
set -x。如果您重新導向 stderr,工作階段仍會執行,但執行器只會以退出碼回報失敗。
傳遞系統提示詞旗標
Anthropic 控制平面為工作階段傳送的系統提示詞和附加系統提示詞,會以檔案路徑而非內嵌文字的形式傳到您的包裝指令碼。執行器會將每個提示詞寫入工作階段設定目錄CLAUDE_CONFIG_DIR 中的檔案,並在您的包裝指令碼接收的引數中傳遞其路徑,形式為 --system-prompt-file <path> 或 --append-system-prompt-file <path>。
Claude Code v2.1.281 或更新版本上的執行器會以檔案形式傳遞提示詞。在 v2.1.281 之前,執行器以 --system-prompt <text> 和 --append-system-prompt <text> 傳遞它們。
在您的包裝指令碼或 command hook 中,請依下列方式處理這些旗標:
- 原樣傳遞它們:以
exec "$CLAUDE_RUNNER_CLAUDE_BIN" "$@"結束包裝指令碼,這會將檔案旗標連同其他所有引數一起轉發。不要捨棄或改寫它們。如果工作階段遺失了提示詞檔案旗標,它將在缺少控制平面為其傳送之指令的情況下執行。 - 在 v2.1.281 或更新版本的執行器上,您附加的檔案旗標會取代伺服器的旗標,而不會與其疊加:每個提示詞檔案旗標只接受單一值,且 Claude Code 會保留最後一次出現的值,因此如果您在
"$@"之後附加--append-system-prompt-file <path>,您檔案的內容會取代伺服器的附加指令。若要在伺服器的指令之上新增指令,請將它們放入執行器映像的CLAUDE.md中,執行器會將其植入每個工作階段的使用者層級設定。
佈建限定於工作階段建立者的憑證
使用decode-token 子命令從工作階段 JWT 讀取聲明。它依序從引數、CLAUDE_CODE_SESSION_ACCESS_TOKEN 或 stdin 讀取 token;請參閱驗證工作階段內的 token 以了解它檢查的內容。下面的範例解碼建立者身分,將其交換為短期 AWS 憑證,並透過 exec 進入 Claude Code:
jq -re 而不是 jq -r,以便缺少的聲明以非零狀態退出,而不是將字面字串 null 傳遞到下游。由組織服務身分(例如機器人和 agent 工作階段)建立的工作階段帶有 agent: 主體而不是 user:,因此此範例會拒絕它們;如果您的環境服務這些工作階段,請明確決定包裝指令碼是否為它們回退到預設憑證,而不是退出。當您的憑證交換改為需要電子郵件時,請讀取 .act.email 並處理其缺失的情況:token 只在建立的使用介面有記錄時才帶有它,而 CLI 分派的工作階段可能缺少它。有關完整的聲明參考以及從執行器外部服務進行的驗證,請參閱驗證工作階段身分。
生命週期掛鉤
生命週期掛鉤用您自己的指令碼替換執行器每個會話管道的階段。使用--hooks-dir <path> 或 SELF_HOSTED_RUNNER_HOOKS_DIR 將執行器指向掛鉤目錄。執行器尋找具有眾所周知名稱的可執行檔案;任何不存在的掛鉤都會回退到內建行為,因此您只需編寫所需的掛鉤。掛鉤以執行器自己的權限執行,會話子程序共享該 UID,因此請將掛鉤目錄掛載為唯讀,或將其烘焙到映像中,以便會話代碼無法修改它;請參閱強化部分。
這些掛鉤不同於Claude Code 掛鉤,後者在會話內執行;生命週期掛鉤在執行器上執行,圍繞會話。
checkout
每個儲存庫執行一次,取代執行器內建的複製與擷取。使用此 hook 從您透過 HTTPS 或 SSH 存取的直讀式鏡像複製、從封存檔植入工作樹,或套用每個工作階段的 git 身分驗證。執行器會設定下列變數,也可能設定表格未列出的其他CLAUDE_RUNNER_ 變數:
指令碼必須在
CLAUDE_RUNNER_CHECKOUT_PATH 留下一個簽出於所要求修訂版本的工作樹。分離的 HEAD 也可以,因為執行器會在其上建立工作階段的工作分支。
在您的 hook 返回後,執行器會驗證 CLAUDE_RUNNER_CHECKOUT_PATH 包含 .git。如果您的 hook 具體化的是非 git 來源(例如 Perforce 或解開的 tarball),請在執行器的環境中設定 CLAUDE_RUNNER_SKIP_GIT_VERIFY=1 以略過該檢查。基於 Git 的流程(例如建立工作分支與推送結果)需要 git 簽出,因此請使用 post-session hook 從非 git 樹匯出結果。
在 hook 中取得 git 憑證
執行器不會將 git 憑證傳遞給 hook。decode-token 子命令在此也無法使用,因為 CLAUDE_RUNNER_CLAUDE_BIN 未在 checkout hook 環境中設定。請改為從工作階段的身分產生每個工作階段的複製憑證,或退而使用主機本身的 git 身分驗證:
- 每個工作階段的複製憑證:依照從您的服務驗證 token所述,使用標準 JWT 函式庫,針對
CLAUDE_RUNNER_API_BASE_URL下的 JWKS 端點驗證CLAUDE_CODE_SESSION_ACCESS_TOKEN。接著讓您的憑證服務為 token 的act宣告中的身分核發短期複製憑證。請以act.sub作為該憑證的識別鍵,且不要要求act.email。 - 主機 git 身分驗證:使用主機已有的任何 git 身分驗證,例如 SSH agent、憑證輔助程式或
.netrc。
hook 失敗時
當 hook 以非零狀態結束,或以 0 結束卻未留下可用的簽出時,即視為 hook 失敗:- 會話推送結果的儲存庫:執行器失敗會話,在非零退出時將指令碼的 stderr 尾部呈現給使用者。
- 工作階段只會讀取的儲存庫,例如新增到執行中工作階段的儲存庫:執行器會記錄一行帶有失敗詳細資訊的
[runner:warn],向工作階段發佈Skipped步驟,移除 hook 在簽出路徑留下的任何內容,並繼續處理其餘儲存庫。如果略過後工作階段完全沒有任何儲存庫,執行器仍會使工作階段失敗。
post-session
在 Claude Code 子程序退出後、執行器拆卸工作區之前,每個會話執行一次。此掛鉤是您保存未提交工作的唯一機會:在--capacity 高於 1 時,執行器在掛鉤返回後立即刪除每個會話的工作樹,在 --capacity 1 時重複使用的規範複製在下一個會話開始時硬重設,因此未提交的追蹤變更在任何一條路徑上都不會存活。典型用途是推送未提交變更的快照分支、存檔日誌或向您自己的系統發出會話結束事件。
掛鉤在每個會話結束時觸發,其中生成了子程序,無論原因如何;下面的 CLAUDE_RUNNER_EXIT_REASON 值列舉了這些情況。當執行器突然終止時(例如 VM 搶佔或電源故障)無法觸發;如果您需要針對突然終止的保證,請改為使用 Claude Code PostToolUse 掛鉤從會話內定期快照。執行器設定:
CLAUDE_RUNNER_EXIT_REASON 採用四個值之一:
completed:工作階段正常結束。Claude Code 程序正常結束,或在工作階段被封存或刪除後自行結束。failed:Claude Code 程序崩潰,或在它啟動後設定失敗。interrupted:執行器停止了工作階段,屬於下列其中一種情況:- 執行器釋放工作階段以空出插槽。
- 工作階段在啟動時逾時。
- 伺服器將工作階段移出此執行器。
- 執行器的輪詢在程序結束前察覺到封存或刪除。
- 執行器正在排空。
- 工作階段超過其
--kill-session-after-min限制。
abandoned:保留給另一個執行器聲稱的會話。掛鉤目前在該情況下不觸發。
interrupted 結果在計數器中會被計為 completed。計數器會將釋放、啟動逾時、伺服器移動,以及由執行器輪詢先察覺到的封存或刪除計為 completed,因為執行器已乾淨地交回插槽。
掛鉤的結束狀態永遠不會影響會話結果;失敗被記錄並忽略。執行器在每個會話結束(包括執行器關閉)時等待最多 --post-session-hook-timeout-sec(預設 60 秒)。此範例將未提交的工作保存到救援分支:
GIT_ALLOW_PROTOCOL 這一行將 git 限制為 HTTPS、HTTP 與 SSH 遠端。如果執行器的環境已自行設定非空的 GIT_ALLOW_PROTOCOL 清單,指令碼會保留該清單。
hook 會使用執行器主機上其自身環境中可用的任何 git 憑證進行推送。在映像中不含憑證的做法下,包括內建複製經由 Anthropic git 代理伺服器進行時,都不會有任何憑證,因此請在推送前於 hook 內產生短期推送憑證:將 hook 在 CLAUDE_CODE_SESSION_ACCESS_TOKEN 中收到的工作階段 token 與您自己的 token 服務交換,並依照驗證工作階段身分所述進行驗證。
請將您的 hook 提供給 git 的任何憑證都視為工作階段能夠取得的憑證,並在產生時將其權限限制為僅足以完成此次推送。您 hook 中的 git 會讀取工作階段可寫入的設定檔,而其中任一檔案所指定的憑證輔助程式或篩選驅動程式,會以您 hook 的權限執行。無論您指定哪個遠端,這些檔案中的設定也可能改變推送的目的地。關於執行器在您 hook 中固定的 git 設定,以及交由這些檔案決定的設定,請參閱生命週期 hook 內的 Git 設定。
執行器釋放會話時的掛鉤計時
已釋放的會話可以在另一個執行器上恢復。在 v2.1.236 或更新版本的執行器上,會話在釋放時執行的操作決定了它是否可以在此掛鉤完成之前在另一個執行器上恢復:- 在轉換後閒置,或在啟動時逾時:執行器停止子程序並執行此掛鉤至完成。只有這樣它才會釋放會話。在掛鉤執行時發送的使用者訊息無法在掛鉤完成之前在另一個執行器上恢復會話。
- 等待使用者回答提示,例如權限提示:執行器首先釋放會話,然後執行此掛鉤。在掛鉤執行時發送的使用者訊息可以在掛鉤完成之前在另一個執行器上恢復會話。
--retire-at 時間,以及 在 v2.1.260 或更新版本的執行器上,在會話的 --kill-session-after-min 限制。轉換已結束且僅持有背景任務的會話在此計為閒置。在 v2.1.236 之前,執行器在兩種情況下都首先釋放會話,然後執行此掛鉤。
在 SIGTERM 排水期間,執行器持有會話租約直到掛鉤完成;請參閱關閉計時。
生命週期 hook 內的 Git 設定
checkout 與 post-session hook 執行時,其環境中帶有工作階段的存取 token,而它們執行的 git 會讀取工作階段可寫入的設定檔,例如 ~/.gitconfig 與簽出中的 .git/config。在任一 hook 執行前,執行器會在 hook 的環境中設定 git 設定(包括下列各項),形式為 GIT_CONFIG_COUNT/GIT_CONFIG_KEY_n/GIT_CONFIG_VALUE_n 配對以及 git 環境變數。Git 會將這些設定的優先順序排在所有設定檔之上,且它們只套用於您的 hook 所執行的 git,不套用於工作階段本身的 git。啟動時,執行器會印出一行 [runner:git] lifecycle hooks:,顯示目前生效的 hook 路徑、允許的協定、gpg 程式與簽署模式。需要 Claude Code v2.1.280 或更新版本。
- Git hook:除非您提供值,否則
core.hooksPath為/dev/null,因此 git 會略過儲存庫.git/hooks中的 hook,以及~/.gitconfig所指定的任何 hook 目錄。若要提供值,請在執行器的環境中將core.hooksPath匯出為GIT_CONFIG_KEY_n/GIT_CONFIG_VALUE_n配對。執行器也會從系統 git 設定讀取core.hooksPath,但僅在執行器的使用者無法寫入該檔案、其指定的目錄或其中的 hook 檔案時才使用。當執行器忽略某個值時,啟動時會有一行[runner:warn]指出該值與原因。 - 檔案系統監視器:
core.fsmonitor為空值,因此您 hook 中的 git 不會執行設定檔所指定的監視器程式。 - 遠端協定:
GIT_ALLOW_PROTOCOL為https:http:ssh。使用本機路徑、file://URL 或git://URL 的複製、擷取或推送,會以fatal: transport 'file' not allowed或fatal: transport 'git' not allowed失敗。 - SSH 命令與憑證提示:您 hook 中的 git 會忽略設定檔中的
core.sshCommand與core.askPass。若要使用您自己的 SSH 命令,請在執行器的環境中設定GIT_SSH_COMMAND。若要使用憑證提示程式,請在該處設定GIT_ASKPASS。工作階段會繼承執行器的環境,因此這兩個變數也會傳到工作階段本身的 git。請勿在其中任一變數中放入憑證。 - gpg 程式:
gpg.program、gpg.openpgp.program、gpg.x509.program與gpg.ssh.program是執行器設定的路徑,絕不會取自設定檔中的值。 - 提交簽署:使用
--configure-git時,您從 hook 建立的提交會以工作階段的身分簽署。未使用此旗標時,commit.gpgsign與tag.gpgsign為false。
git -c 選項:
- 設定配對:您在執行器環境中匯出的
GIT_CONFIG_KEY_n/GIT_CONFIG_VALUE_n配對,會取代執行器對相同鍵的值。請從0開始為配對編號,並將GIT_CONFIG_COUNT設為配對數量。當計數所宣告的最後一個配對不存在時,執行器會忽略您所有的配對,並在啟動時記錄一行[runner:warn]。 - Git 環境變數:執行器會保留您在其環境中設定的
GIT_ALLOW_PROTOCOL、GIT_SSH_COMMAND與GIT_ASKPASS。 git -c選項:hook 內的git -c選項會覆寫GIT_CONFIG_KEY_n配對,無論是執行器的還是您的。它不會變更GIT_ALLOW_PROTOCOL、GIT_SSH_COMMAND或GIT_ASKPASS,因為 git 會先於任何設定讀取這些變數。
url.*.insteadOf 重寫與篩選驅動程式。這些檔案之一所指定的憑證輔助程式或篩選驅動程式,會以您 hook 的權限作為程式執行,而這些檔案中的設定仍可改變您 hook 推送的目的地,包括推送到您在命令列上傳入的 URL。
在 v2.1.280 之前,執行器不會設定上述任何設定,且在 --configure-git 下,從 hook 建立的提交會失敗,除非 hook 傳入 -c commit.gpgsign=false。
command
在簽出後每個會話執行一次,代替內建的子程序生成。掛鉤接收與包裝指令碼相同的環境,應該以相同的方式exec 進入 "$CLAUDE_RUNNER_CLAUDE_BIN"。使用 command 掛鉤將所有自訂保留在一個掛鉤目錄中;當包裝指令碼在其他地方時使用 --exec-path。如果也設定了 --exec-path,旗標優先,command 掛鉤被忽略。
始終 exec 執行器自己的二進位檔案,而不是 PATH 解析的 claude;否則您會破壞版本固定。
隨需啟動的執行器
您可以不使用固定的執行器群組,而是每個工作階段啟動一個執行器。協調器是一個獨立的、無狀態的子命令,它會輪詢 Anthropic 以取得啟動請求,每個沒有可用執行器的已排隊工作階段一個請求,並為每個請求執行您的spawn-runner hook。您的 hook 會將工作負載提交到您的平台:Kubernetes Job、EC2 執行個體、Nomad dispatch。
隨需啟動的執行器改善了認證衛生。在固定群組上,環境祕密存在於每個執行器主機上,這與執行使用者工作階段的主機相同。使用協調器,環境祕密只保留在協調器主機上,該主機永遠不會執行使用者程式碼;每個啟動的執行器都會收到一個一次性工作單,它只註冊一個執行器,然後過期。
若要啟動協調器,請傳遞環境祕密和包含可執行 spawn-runner 指令碼的 hooks 目錄:
--expected-spawn-seconds 值;請參閱 hook 合約。
spawn-runner hook
協調器為每個啟動請求執行一次${hooks-dir}/spawn-runner。hook 必須非同步提交工作,不等待執行器啟動,並在 --hook-timeout 內返回,預設為 60 秒。hook 接收:
啟動的執行器使用工作單代替環境祕密進行註冊:
- 使用工作單啟動它:將
--environment-secret-file指向包含工作單 JWT 的檔案,或將SELF_HOSTED_RUNNER_ENVIRONMENT_SECRET設定為 JWT 值。 - 在 hook 退出前複製 JWT:協調器在 hook 退出後刪除工作單檔案,因此將 JWT 複製到您提交的工作負載中,例如啟動的 Job 上的 Kubernetes Secret,而不是透過檔案路徑。
- 在啟動的執行器上使用
--capacity 1:工作階段綁定的工作單恰好註冊一個綁定到該工作階段的執行器,因此更高的容量會新增永遠不會接收工作的插槽,執行器在啟動時會記錄警告。 - 預熱工作單註冊未綁定:待命執行器未綁定到工作階段,並像固定群組執行器一樣聲稱已排隊的工作。
-
在
CLAUDE_RUNNER_ORDER_ID上保持冪等性。 重新傳遞相同的請求最多必須啟動一個執行器。從 ID 衍生確定性資源名稱,並讓您的平台拒絕重複項。不要改為在CLAUDE_RUNNER_SESSION_ID上進行金鑰設定。每次重新請求工作階段都會使用相同的工作階段 ID 和新的訂單 ID,因此按工作階段 ID 命名或去重的工作負載會為該工作階段建立一次,之後永遠不會再建立。 -
不要重試工作負載。 一個訂單 ID 最多意味著建立一個工作負載。如果執行器永遠不註冊,Anthropic 會在
--expected-spawn-seconds後使用新的訂單 ID 重新請求。 -
使用退出碼合約。 以符合結果的狀態退出:
- 退出 0:已提交。
- 退出 1:可重試的失敗。工作階段會退避並被重新提供。
- 退出 2 或更高:不可重試的失敗。工作階段會被阻止再次啟動,直到使用者向其傳送新訊息,或 Owner 在環境的 Activity 標籤中對其選擇 Retry。
--expected-spawn-seconds租約到期後重新請求啟動。 -
將
--expected-spawn-seconds設定為至少您從啟動請求到執行器註冊的 p99 時間。 從協調器收到啟動請求時開始計算,並包含在您的平台上等待容量的時間以及啟動時間。此值是伺服器端租約,工作單會隨之過期,因此工作負載耗時更長的執行器將無法註冊。所有協調器副本必須使用相同的值。
/healthz 主體以取得佇列計數,然後在 Cloud environments 管理頁面 上開啟您環境的 Activity 標籤:在那裡展開失敗的工作階段以查看其啟動錯誤,並選擇 Retry 以重新請求它。
保持排隊且在 Activity 標籤中沒有啟動錯誤的工作階段可能意味著 hook 是在工作階段 ID 上進行金鑰設定的。若要確認,請檢查您的平台是否有該工作階段的第一個啟動請求的工作負載,以及沒有重新請求的工作負載。如果是這樣,請改為在 CLAUDE_RUNNER_ORDER_ID 上進行工作負載金鑰設定。
在 shell hook 中保持暫時性失敗可重試
在使用set -e 的 shell hook 中,原本重試即可排除的失敗可能會阻止工作階段。hook 會在失敗的命令處停止,並以該命令本身的狀態退出,而協調器會對該狀態套用退出碼合約。許多失敗會回傳 2 或更高的狀態,例如命令未安裝時的 127,以及 curl --fail 遇到 HTTP 錯誤時的 22,因此它們會在第一次失敗時就阻止工作階段。
已被 hook 阻止的工作階段會保持阻止狀態,直到使用者向其傳送新訊息,或 Owner 在環境的 Activity 標籤中對其選擇 Retry。
若要將此類失敗改為退出 1,請將以下幾行直接放在 hook 的 #! 行下方,位於任何可能失敗的內容之前:
-
單獨的
exit 2或更高:設定 trap 後,它會變成退出 1。對於任何重試都無法修正的錯誤,請改為以原因呼叫permanent,例如permanent "namespace claude-runners does not exist"。請在主 shell 中呼叫它,不要在$( )、( )或管線中呼叫。 -
exec:不要以exec開始 hook 的最後一個命令,因為exec會取代 shell,trap 將不會執行。 -
第二個
EXITtrap:第二個trap ... EXIT會取代第一個,因此請將兩者合併為單一 trap。將您的清理命令直接放在rc=$?;之後,並在每個命令結尾加上|| true;。如此一來,清理在失敗和成功時都會執行,且失敗的清理命令不會設定 hook 的退出狀態。以下合併後的 trap 展示了其形式,其中your-cleanup-command代表您自己的命令: -
允許失敗的命令:如果 hook 之前未使用
set -e,它現在會在第一個回傳非零的命令處停止,例如找不到任何結果的查詢,或被您的平台拒絕的重複提交。如果 hook 會根據結果採取動作,請將該命令作為if的條件。如果它忽略結果,請在該命令後加上|| true。
trap 行正下方新增一行,呼叫一個不存在的命令,例如 no-such-command。從您的 shell 執行 hook 檔案,確認 echo $? 輸出 1,然後移除該行。
將模型請求傳送至 Bedrock 或 Agent Platform
如果您的組織需要讓模型請求經過自己的 AWS 或 Google Cloud 帳戶,請為 runner 設定 Amazon Bedrock 或 Google Cloud 的 Agent Platform(前身為 Vertex AI)。之後該 runner 啟動的每個工作階段都會以您的雲端憑證,在您的雲端帳戶中呼叫模型。若未進行此設定,工作階段會將模型請求傳送至 Anthropic API。 Runner 仍會向 Anthropic 輪詢工作階段,且每個工作階段仍會將其事件串流傳送至api.anthropic.com。事件串流包含提示詞、回應和工具結果。可用性與限制中的方案要求和 Zero Data Retention 排除條款仍然適用。
工作階段是路由至環境,而非路由至 runner,且重新排入佇列或恢復的工作階段可能會在不同的 runner 上執行。請以相同方式設定環境中的每個 runner。開始之前,請閱讀這些供應商上有何不同。
1
準備雲端帳戶和輸出規則
設定模型存取權、範圍嚴格限定的政策或角色,以及網路存取:
2
為工作階段提供範圍嚴格限定的憑證
將步驟 1 中的政策或角色附加至一個無法執行其他任何操作的身分。關於 Claude Code 接受的方法,請參閱設定 AWS 憑證和設定 GCP 憑證。請根據以下 runner 行為檢查您選擇的方法:
- 中繼資料端點:如果您完全拒絕工作階段存取雲端中繼資料端點,由其提供的憑證(例如執行個體設定檔)也不會傳達至 Claude Code。以檔案為基礎的 Web 身分,例如 Amazon EKS 上的 IAM Roles for Service Accounts (IRSA) 或 Workload Identity Federation 憑證檔案,則不依賴該端點。
- 續期:工作階段的存續時間可能比憑證更長,因此請使用會自行續期的方法,例如以檔案為基礎的 Web 身分
- 包裝腳本:Runner 會在每個工作階段啟動一次您的包裝腳本,因此它匯出的憑證不會續期。Claude Code 會從其環境讀取 AWS 憑證,因此如果您的包裝腳本已為其他工作匯出 AWS 憑證,Claude Code 可能會使用這些憑證來簽署模型請求。
3
在 runner 的環境中設定單一供應商的變數
在您設定 runner 其他環境變數的地方(例如容器規格或服務單元)設定恰好一個供應商的變數,然後重新啟動 runner。範例以 shell 匯出的形式呈現。若使用隨需 runner,請在您的
spawn-runner hook 所啟動的工作負載上設定這些變數。請使用 --confine-repo-settings enforce 啟動這些 runner。它會拒絕在已提交設定遭其標記的儲存庫上執行工作階段,因此請先以預設的 warn 模式執行,並清除它在日誌中記錄的項目。- Amazon Bedrock
- Google Cloud's Agent Platform
將區域替換為您自己的區域:關於 Claude Code 如何解析區域,請參閱設定 Claude Code。關於 Claude Code 針對您的區域使用哪個推論設定檔前綴,請參閱跨區域推論設定檔前綴。
4
檢查變數是否已傳達至工作階段
您在主機上自己的 shell 是不同的程序,因此請從工作階段內部檢查。在該環境中啟動一個工作階段,並請 Claude 執行此命令:若有一行將
CLAUDE_CODE_USE_BEDROCK 或 CLAUDE_CODE_USE_VERTEX 設為 1,表示該變數已傳達至工作階段。如果兩者都出現,Claude Code 會使用 Amazon Bedrock。沒有輸出則表示兩者皆未傳達。此命令顯示的是設定,而非流量。若要確認請求本身,請在您雲端帳戶自己的指標或請求日誌中查看。如果第一則訊息反而失敗,請參閱 Amazon Bedrock 或 Agent Platform 的疑難排解。與 Anthropic API 上的工作階段有何不同
將模型請求傳送至 Amazon Bedrock 或 Google Cloud 的 Agent Platform 的工作階段,與 Anthropic API 上的工作階段有以下差異:- 來自 claude.ai 的政策:伺服器管理設定不會傳達至這些工作階段。Owner 在 Claude Code 管理設定中設定的組織政策也不會傳達,因此 Claude Code 不會在工作階段內強制執行這些政策。請將您所依賴的規則放入 runner 映像檔的受管設定檔案中。
- 帳戶 skill:這些工作階段不會下載使用者的 claude.ai 帳戶所啟用的 skill。請參閱每個工作階段的設定如何組成。
- 檔案:使用者在 claude.ai 或行動裝置或桌面應用程式中附加至工作階段的檔案不會傳達至工作階段,且 Claude 無法使用
SendUserFile工具回傳檔案。請改將輸入檔案放在儲存庫中或 runner 上。 - 模型選擇:Anthropic 的控制平面會傳送每個工作階段的模型,當工作階段在沒有指定模型的情況下啟動時,Claude Code 會使用該供應商的預設模型。您無法透過 runner 環境中的
ANTHROPIC_MODEL或ANTHROPIC_DEFAULT_MODEL選擇模型,但可以固定別名所解析的目標:ANTHROPIC_MODEL和ANTHROPIC_DEFAULT_MODEL:即使供應商頁面的範例會設定ANTHROPIC_MODEL,runner 仍會從其傳遞給工作階段的環境中移除這兩個變數。- 各模型系列的固定變數:Amazon Bedrock 和 Agent Platform 的「固定模型版本」中的變數確實會傳達至工作階段。這些變數決定的是
opus等別名解析為哪個模型,而非完整模型 ID 解析為哪個模型。
- 您的帳戶未提供的模型:工作階段可能會在某則訊息上失敗,並出現指出該模型名稱的錯誤。請啟用您的開發人員可以選擇的模型、「固定模型版本」中所述的背景模型,以及自動模式所使用的分類器模型。在 Amazon Bedrock 上,請在您的政策中允許其中每一個模型。
- 網路搜尋和快速模式:網路搜尋在 Amazon Bedrock 上無法使用,而快速模式在兩個供應商上都無法使用。關於其他因供應商而異的功能,請參閱因供應商而異的 CLI 功能。
MCP 伺服器
若要讓 MCP 伺服器在每個工作階段中都可用,請在映像建置時使用與桌面安裝相同的claude mcp add 命令加入它們。如果您的 runner 是裸程序而非容器,請以 runner 的使用者身分在主機上執行相同的命令,然後重新啟動 runner:它只會在啟動時讀取一次主機設定。--scope user 旗標是必要的;預設的 local 範圍會寫入以各目錄為鍵的位置,而 runner 不會將其植入工作階段。例如,在您的 Dockerfile 中:
.claude.json 中的 mcpServers 鍵(該檔案位於 ~/.claude/ 旁邊,而非其內部),且 runner 只會將該鍵植入每個工作階段的隔離設定中;帳戶狀態和專案歷史記錄會被捨棄。若要確認伺服器已傳達到工作階段,請在該環境上啟動一個工作階段,並請 Claude 列出其 MCP 工具;對於任何 type 無法辨識的已擷取項目,runner 也會在啟動時記錄警告並捨棄該項目,讓您能看出該伺服器為何未出現在工作階段中。當設定了 SELF_HOSTED_RUNNER_HOST_CONFIG_DIR 時,runner 會改為從該目錄讀取 .claude.json,因此將該變數指向空目錄也會停用 MCP 植入。
Claude Code 也會從其他來源載入 MCP 伺服器:
- 位於標準系統路徑的企業範圍受管 MCP 檔案:Linux runner 主機上為
/etc/claude-code/managed-mcp.json,macOS 主機上為/Library/Application Support/ClaudeCode/managed-mcp.json。適用於僅允許載入管理員所列伺服器的鎖定機群。優先順序規則請參閱使用 managed-mcp.json 進行獨占控制。當此檔案存在於 runner 主機上時,Claude Code 會略過 Anthropic 控制平面傳遞給工作階段的 MCP 伺服器(包括 claude.ai 連接器),並在工作階段子程序的 stderr 上以警告列出它們,runner 會以debug日誌層級記錄這些警告。在 v2.1.229 之前,這些工作階段會在啟動時以You cannot dynamically configure MCP servers when an enterprise MCP config is present結束。 - runner 主機上受管設定中的
managedMcpServers鍵:提供 HTTP 和 SSE 伺服器而不取得獨占控制,因此來自其他來源的伺服器仍會載入。需要 Claude Code v2.1.259 或更新版本。 <repo>/.mcp.json:專案範圍。將此檔案提交到儲存庫;其伺服器在雲端工作階段中會自動核准。在包含多個儲存庫的工作階段中,最多只會載入一個儲存庫的檔案。
api.anthropic.com 路由。以程式化方式建立的工作階段(例如 CLI 派送)不會接收連接器傳遞;請改為透過本節列出的任何其他來源為它們提供 MCP 伺服器。子程序的 OAuth token 不具備直接擷取連接器的範圍,因此子程序本身不會嘗試該擷取;傳遞是由伺服器驅動的。
settings.json 不包含 MCP 伺服器定義,且設定 schema 中沒有頂層的 mcpServers 欄位。在受管設定中,請改用 managedMcpServers 鍵來提供伺服器。
工作階段會繼承 runner 的環境,因此請在該處設定 ENABLE_TOOL_SEARCH,以控制 runner 產生的每個工作階段的 MCP 工具搜尋;各個值的說明請參閱 MCP 頁面。
在第一個回合前等待 MCP 伺服器
自架的工作階段會在兩個不同的時間點,短暫等待仍在連線中的 MCP 伺服器。錯過等待的伺服器,其工具在第一個回合開始時將不可用,之後無需您採取任何動作即會變為可用。這兩次等待如下:- 工作階段啟動:在首次取得工具清單之前,工作階段預設最多會等待 5 秒,等待項目中設定了
alwaysLoad: true的 HTTP 或 SSE 伺服器;若您在 runner 的環境中設定了MCP_CONNECTION_NONBLOCKING=0,則會等待所有伺服器。否則,HTTP 和 SSE 伺服器會在背景中連線。工作階段在此等待期間,初始化速度會較慢。MCP_CONNECT_TIMEOUT_MS可變更 5 秒的預設值。 - 第一個回合:在訊息抵達後,第一個回合最多會等待 2 秒,等待仍在連線中的 stdio 伺服器。工作階段在此等待期間,第一個回覆會較慢。若要變更此等待的時間長度,請在 runner 的環境中設定
CLAUDE_CODE_MCP_STARTUP_WAIT_MS。它不會變更此等待涵蓋哪些伺服器。需要 Claude Code v2.1.274 或更新版本。
claude mcp add 沒有 alwaysLoad 旗標。若要設定此鍵,請改用 claude mcp add-json 加入伺服器,它會在伺服器的 JSON 中接受此鍵並將其寫入 .claude.json。在您的 Dockerfile 中:
關閉內建工作階段工具
Anthropic 的控制平面會將其自有的 MCP 伺服器(名為 Claude Code Remote)附加到雲端工作階段。Claude 使用該伺服器的工具來排程 routine、啟動並引導其他雲端工作階段、附加更多儲存庫,以及追蹤 pull request 活動。 若要關閉整個伺服器,請在您的設定中新增伺服器層級的拒絕規則。控制平面會依工作階段的建立方式,以三個名稱之一註冊該伺服器。Claude Code 會完全比對規則中的名稱(包括大小寫),因此請如下所示為每個名稱各寫一條規則:mcp__Claude_Code_Remote__add_repo。若要完全阻止伺服器連線,而不只是移除其工具,請改為將這三個名稱(不含 mcp__ 前綴)作為 serverName 項目加入 deniedMcpServers 下。
將規則放在伺服器受管設定中,即可在不變更 runner 的情況下套用到工作階段,或放在 runner 上的 ~/.claude/settings.json 中。在將模型請求傳送至 Bedrock 或 Agent Platform 的 runner 上,請使用該檔案,因為伺服器受管設定不會套用到這些工作階段。權限與工具核准說明了 runner 上的設定如何套用到工作階段。
若要確認規則已生效,請在該環境上啟動一個工作階段,並請 Claude 列出其 MCP 工具。Claude Code 會從 Claude 的上下文中移除被拒絕的工具,因此被拒絕的工具不會出現在其回答中。
提示會話推送其工作
Anthropic 託管的會話執行Stop 掛鉤,Claude Code 掛鉤在 Claude 完成回應時執行,提示 Claude 提交並推送其工作。執行器不安裝一個。沒有它,以未提交變更結束的會話只在執行器的磁碟上留下該工作,claude.ai/code 中的建立 PR 按鈕保持非活動狀態,直到分支存在於遠端。
下面的參考實現有兩個部分。將設定塊合併到執行器主機上的 ~/.claude/settings.json 中,執行器將其植入每個會話,並將指令碼保存為執行器主機上的 ~/.claude/hooks/stop-hook-nudge.sh 並使其可執行:
$CLAUDE_PROJECT_DIR 所指的目錄。
權限和工具核准
自託管工作階段沒有連接的終端機,因此未回應的權限提示會使回合停滯,直到使用者在 UI 中回應。Anthropic 的控制平面會隨工作 payload 傳送每個工作階段的工具清單和權限規則;預設設定會預先核准例行的工具呼叫(包括Bash),而雲端工作階段無論模式為何都會預先核准檔案編輯。未被任何規則預先核准的呼叫會透過工作階段 UI 提示。
若要無論控制平面傳送什麼都將提示降到最低,請從您的包裝指令碼或
command hook 固定自動模式。自動模式讓工作階段無需例行權限提示即可執行:一個獨立的分類器模型會在操作執行前進行審查,並阻擋其拒絕的操作,而明確的詢問規則仍會強制提示;權限模式頁面說明了分類器檢查的內容。執行器在呼叫包裝指令碼前會附加伺服器計算的旗標,而對於單值旗標(例如 --permission-mode),解析器會採用最後一次出現的值,因此您在 "$@" 之後附加的旗標會覆寫伺服器傳送的值:
--allowed-tools 及您的規則,例如 --allowed-tools "Bash(bazel *) Bash(yarn *) mcp__internal__*"。清單旗標(例如 --allowed-tools 和 --disallowed-tools)會在多次出現時累加,而非覆寫,因此您的規則會套用在控制平面傳送的任何規則之上。若要縮小範圍,請附加 --disallowed-tools,即使其他規則允許某工具,它也會拒絕該工具。
如何組合每個工作階段的設定
執行器為每個工作階段提供其專屬的設定目錄,並以執行器在啟動時擷取一次的主機~/.claude/ 快照植入:您執行器映像中的 settings.json、CLAUDE.md、hook、agent、命令和 skill 會作為使用者層級基準套用至每個工作階段。如果您在執行中的主機上變更設定,變更僅在您重新啟動執行器後生效。
設定 SELF_HOSTED_RUNNER_HOST_CONFIG_DIR 以從不同路徑植入,或將其指向空目錄以停用植入。
工作階段也會讀取以下設定檔:
- 專案設定:儲存庫提交的
.claude/settings.json會疊加於使用者層級基準之上。在包含多個儲存庫的工作階段中,最多只有一個儲存庫的檔案會生效。 - 受管設定:工作階段會從執行器映像中的標準系統路徑讀取
managed-settings.json。關於其設定鍵是否與伺服器受管設定一併套用,請參閱 Claude Code 如何組合受管來源。
- 放置位置:執行器會將每個提供的 hook 指令碼寫入工作階段設定目錄中保留的
hooks/.ccr-launcher/子目錄,並在一個獨立的設定檔中註冊這些指令碼,再透過--settings將該檔案傳遞給工作階段,而植入的settings.json和您位於hooks/<name>的指令碼則保持不變。執行器會為每個工作階段重新建立該保留子目錄,且不會將主機上~/.claude/hooks/.ccr-launcher/的內容植入工作階段。 - 撰寫者:控制平面以其自身部署中的固定常數填入這些指令碼,絕不來自個別工作階段或第三方輸入。
- 仍受何者管控:透過
--settings傳遞的 hook 會進入一般的合併 hook 設定,而非受管層級,因此您的受管設定仍然適用。disableAllHooks會停用它們,且它們不屬於allowManagedHooksOnly保持載入的類別。
.claude/skills/,或將其加入您的執行器映像。
在 Claude Tag 工作階段以外,自託管環境中的工作階段預設會關閉自動記憶。若有應跨工作階段延續的指令,請使用執行器映像或儲存庫中的 CLAUDE.md。
執行器對主機 ~/.claude/ 的快照不包含 projects/ 目錄。自動記憶的預設儲存位置就位於該目錄下。如果您將記憶檔案放在那裡,執行器不會將其植入工作階段,這些檔案也不會開啟自動記憶。
包含多個儲存庫之工作階段中的儲存庫設定
在包含多個儲存庫的工作階段中,Claude Code 會從工作階段啟動時所在的目錄讀取專案設定,因此最多只有一個儲存庫的.claude/settings.json 會作為專案設定生效。在其他儲存庫檔案中定義的 hook 不會執行,其中的拒絕規則不會套用,其 env 也不會被設定。
--capacity 1(預設值)搭配內建簽出:工作階段會在其儲存庫清單中的第一個儲存庫啟動。該儲存庫的.claude/settings.json會作為專案設定生效,其.mcp.json也會載入,其他儲存庫的則不會。--capacity大於一,或使用checkouthook:工作階段會在包含各簽出內容的個別工作階段目錄中啟動。沒有任何儲存庫的.claude/settings.json會作為專案設定生效,沒有任何儲存庫的.mcp.json會載入,且 hook 命令中的$CLAUDE_PROJECT_DIR為該目錄,而非某個簽出內容。
CLAUDE.md 和 skill 都會載入。執行器會將每個儲存庫作為額外目錄傳遞給 Claude Code,因此 Claude Code 也會從每個儲存庫的 .claude/settings.json 讀取 enabledPlugins 和 extraKnownMarketplaces 設定鍵。
若要在每個工作階段中執行 hook 或套用權限規則,請將其放在執行器主機上的 ~/.claude/settings.json 中。無論工作階段在何處啟動,執行器都會將主機檔案植入每個工作階段。在 Read 或 Edit 規則中,請將路徑寫成 // 絕對路徑或 ~/ 相對於家目錄的模式,因為其他模式會以設定來源或目前目錄為基準。
儲存庫提交的權限規則
請勿在儲存庫提交的permissions.allow 中放入單獨的 "Edit"、"Write" 或 "NotebookEdit" 項目。單獨的檔案工具規則會不論路徑地比對該工具,授予主機上任何位置的寫入權,而不僅限於工作區,因此執行器的寫入範圍限制防護會對該工作階段發出警示;若使用 --confine-repo-settings enforce,它會拒絕啟動該工作階段,而非記錄後繼續。請參閱強化部分。
儲存庫完全不需要檔案工具規則:雲端工作階段無論模式為何都會預先核准檔案編輯。如果您確實提交了規則,請將其範圍限定於工作區,例如 "Edit(/**)";單一前導斜線是相對於專案根目錄,也就是工作階段的工作區。單獨的檔案工具規則可以放在操作員的主機層級 settings.json 中,因為該檔案並非由儲存庫提交。
defaultMode 為 auto 的設定僅在映像層級或使用者層級設定檔中才會生效,因此簽出的儲存庫無法自行授予自動模式。有關雲端工作階段接受的模式及完整規則語法,請參閱權限模式。