Skip to main content
Lingkungan yang di-host sendiri berada dalam beta publik pada paket Team dan Enterprise; Ketersediaan dan batasan mencakup jalur pengaktifan. Halaman ini mencakup menjalankan armada dalam produksi; lihat quickstart untuk runner dan sesi pertama Anda.
Sebuah lingkungan yang di-host sendiri menjalankan sesi cloud Claude Code pada runner yang Anda terapkan di dalam jaringan Anda, dan dalam produksi sesi-sesi tersebut menjalankan kode yang diarahkan model atas nama semua orang yang dapat mengirim sesi ke lingkungan. Halaman ini untuk operator yang membawa lingkungan yang berfungsi ke produksi. Ini berfungsi melalui penerapan secara berurutan: apa yang harus dikunci sebelum menghubungkan sistem nyata, egress yang dibutuhkan armada, bagaimana sesi mengautentikasi ke host git Anda, resep penerapan itu sendiri, dan apa yang harus diperiksa ketika sesi berperilaku tidak normal.

Perkuat deployment Anda

Runner self-hosted mengeksekusi kode arbitrer yang diarahkan oleh model di infrastruktur Anda atas nama setiap orang yang dapat mengirimkan sesi ke lingkungannya. Itu mencakup setiap anggota organisasi Anthropic Anda, dan siapa pun yang dapat memulai sesi channel Claude Tag dalam cakupan yang telah dirutekan oleh Owner ke lingkungan tersebut. Selesaikan setiap item sebelum Anda menghubungkan lingkungan ke sistem produksi:
  • Container ephemeral per sesi: jalankan setiap proses runner dalam container atau VM baru yang dihancurkan saat proses berakhir, dengan --capacity 1 dan --drain-grace-sec 0 default sehingga setiap container melayani tepat satu sesi. Pada kapasitas yang lebih tinggi, atau dengan drain grace positif, satu container melayani beberapa sesi dari pemilik terkunci yang sama; lihat Siklus hidup runner. Jangan gunakan ulang sistem file di antara restart runner, kecuali dalam penyiapan checkout yang sudah dipanaskan sebelumnya yang disengaja, dan jangan pernah lintas pemilik.
    • Saat runner menghentikan sesi, runner tidak mengirimkan sinyal ke proses yang masih berjalan setelah perintah shell-nya selesai, seperti layanan yang berjalan sebagai daemon. Menghancurkan container atau VM akan mengakhiri proses tersebut.
  • Tidak ada kredensial luas di dalam image: jangan sertakan kunci SSH berumur panjang, kredensial penyedia cloud, atau token akses pribadi yang memberikan lebih dari yang dibutuhkan sesi. Buat kredensial yang digunakan selama sesi, seperti token push atau API, per sesi dari skrip wrapper Anda. Clone awal terjadi sebelum wrapper berjalan, jadi tangani dengan hook siklus hidup checkout, atau dengan --use-anthropic-git-proxy jika semua repositori sesi berada di github.com. Untuk keduanya, lihat Konfigurasikan git.
  • Jauhkan kredensial GitHub milik host dari sesi: Claude dapat menggunakan kredensial GitHub apa pun yang dapat dibaca oleh sesi, dengan akses apa pun yang diberikan oleh kredensial tersebut. Jauhkan kredensial GitHub milik host runner sendiri yang memiliki cakupan luas dari apa pun yang dapat dibaca oleh sesi. Kredensial semacam itu dapat berupa token akses pribadi, token yang disimpan gh auth login untuk akun Anda, atau GH_TOKEN di lingkungan runner.
    • Dengan git yang dikelola Anthropic: dengan kredensial semacam itu, Claude menjangkau GitHub secara langsung alih-alih melalui git yang dikelola Anthropic.
    • Tanpa git yang dikelola Anthropic: kredensial clone dapat tetap berada di dalam image jika Anda membatasinya seketat yang dijelaskan di Sertakan konfigurasi git di image Anda.
  • Jauhkan secret lingkungan dari host yang menjalankan sesi: secret lingkungan dapat mendaftarkan runner dan mengambil sesi apa pun yang diantrekan pada lingkungan tersebut. Pada armada tetap, secret ini berada di setiap host runner, tempat kode sesi mana pun dapat membaca file secret. Utamakan runner on-demand, di mana secret tetap berada di host orkestrator, yang tidak pernah menjalankan kode pengguna, dan setiap runner menerima work order sekali pakai yang mendaftarkan tepat satu runner. Pada armada tetap, perlakukan file secret lingkungan sebagai dapat dibaca oleh setiap sesi dan rotasi secret setelah adanya dugaan kompromi sesi.
  • Tolak egress jaringan secara default: batasi lalu lintas keluar runner dan container sesi di batas jaringan Anda sendiri pada setiap lingkungan; Tolak egress secara default menjelaskan apa yang perlu diizinkan dan alasannya.
  • IAM host dengan hak akses minimal: identitas komputasi yang terpasang pada host runner, seperti instance profile atau akun layanan node, sebaiknya hanya memberikan apa yang dibutuhkan oleh runner itu sendiri. Sesi sebaiknya memperoleh kredensialnya sendiri melalui skrip wrapper Anda alih-alih mewarisi kredensial host.
  • Blokir endpoint metadata cloud dari sesi: menjauhkan sesi dari identitas host memerlukan pemblokiran akses mereka ke endpoint metadata cloud, dan kebijakan egress tingkat subnet tidak mencegat lalu lintas metadata link-local, jadi blokir di dalam container itu sendiri:
    • IMDSv2 dengan hop limit satu
    • GKE Workload Identity dengan metadata concealment
    • Penolakan eksplisit untuk 169.254.169.254 di namespace jaringan container sesi
    Pemblokiran ini juga berlaku untuk skrip wrapper dan hook siklus hidup Anda, karena keduanya berbagi container yang sama. Autentikasikan setiap pertukaran token dengan JWT sesi terhadap layanan token Anda sendiri melalui egress yang ada di allowlist, atau gunakan identitas web berbasis file seperti IAM Roles for Service Accounts (IRSA) di Amazon EKS.
  • Isolasi sistem file per runner: setiap proses runner mendapatkan direktori kerjanya sendiri yang tidak dapat dibaca atau ditulis oleh proses lain di host. Jadikan --hooks-dir, skrip wrapper, dan ~/.claude/ milik host read-only bagi sesi, baik dengan membangunnya ke dalam image maupun memasangnya sebagai read-only.
  • Dispatch tidak memiliki kontrol akses per lingkungan: setiap anggota organisasi Anthropic Anda dapat mengirimkan sesi ke lingkungan mana pun milik organisasi tersebut. Jika Owner merutekan channel Claude Tag ke lingkungan tersebut, siapa pun yang diizinkan oleh pengaturan akses Claude Tag dapat memulai sesi channel yang berjalan di sana. Secara default, itu adalah siapa pun di workspace Slack yang terhubung, dengan atau tanpa akun Claude. Perlakukan setiap host runner sebagai dapat dijangkau untuk eksekusi kode oleh setiap orang yang dapat mengirimkan sesi ke sana, dan tempatkan di host runner hanya data dan kredensial yang boleh dibaca oleh semua orang tersebut. --lock-to-account membatasi sesi akun mana yang dieksekusi oleh host tertentu, tetapi tidak mempersempit siapa yang dapat mengirimkan sesi ke lingkungan tersebut. Untuk menjadikan lingkungan self-hosted sebagai satu-satunya opsi pemilih, seorang Owner dapat menyembunyikan lingkungan yang di-host Anthropic untuk seluruh organisasi dari halaman Cloud environments.
  • Terapkan guard pengaturan repo: pilih mode guard dengan --confine-repo-settings. Mode default warn mencatat pelanggaran ke log dan tetap memunculkan sesi, enforce menolak sesi, dan off menonaktifkan pemindaian. Runner memindai pengaturan yang di-commit di setiap repositori untuk:
    • Pemberian akses yang mengarah ke luar workspace milik sesi itu sendiri: entri additionalDirectories, aturan Edit, Write, atau NotebookEdit di permissions.allow, atau entri sandbox.filesystem.allowWrite atau allowRead
    • Blok env yang tidak kosong
    • Override postur operator seperti sandbox.enabled: false
    Guard berjalan terlepas dari --trust-workspace, dan tidak mencakup hook repositori, .mcp.json, atau aturan Bash; lihat Izin dan persetujuan tool untuk mengetahui tempat pemberian akses tersebut seharusnya berada.
Jika organisasi Anda mengaktifkan allowlist IP, tambahkan alamat egress publik runner dan container sesi Anda ke allowlist sebelum Anda memulainya. Jika Anda menjalankan runner on-demand, tambahkan juga alamat host orkestrator. Jangan mengandalkan allowlist sebagai kontrol jaringan untuk lalu lintas runner atau sesi. Sebagai gantinya, terapkan penolakan egress secara default di batas jaringan Anda sendiri.

Persyaratan jaringan

Runner dan anak-anak sesi yang dihasilkannya membuat koneksi keluar ke host di bawah. Batasi egress kontainer sesi ke host ini dan layanan internal spesifik yang perlu dijangkau sesi; Default-deny egress mencakup cara dan alasannya. Host-host ini selalu diperlukan: Runner yang menggunakan --use-anthropic-git-proxy merutekan lalu lintas git github.com-nya melalui api.anthropic.com, sehingga tidak memerlukan jalur host git untuk github.com. Runner tersebut tetap memerlukan jalur itu jika Anda mengatur --push-outcome-on-release atau melakukan push dari hook post-session. Apakah host-host ini diperlukan tergantung pada konfigurasi Anda: Anda tidak perlu menambahkan host-host ini ke allowlist untuk lalu lintas runner atau sesi:
  • statsig.anthropic.com, *.sentry.io, claude.ai, dan platform.claude.com: host-host ini muncul dalam beberapa daftar periksa jaringan enterprise yang lebih lama, tetapi runner tidak menjangkaunya. Pengambilan flag fitur pergi ke api.anthropic.com, dan runner mengautentikasi dengan rahasia lingkungan daripada OAuth interaktif.
  • mcp-proxy.anthropic.com: sesi yang di-host sendiri tidak menggunakannya. Ketika pengiriman konektor diaktifkan untuk organisasi Anda, konektor claude.ai organisasi Anda menjangkau sesi melalui api.anthropic.com. Lihat MCP servers.
Alur sisi host berikut memang menjangkau claude.ai, jadi jalankan dari host yang egress-nya memungkinkannya daripada memperluas egress kontainer sesi:
  • Installer satu baris: mengambil install.sh dari claude.ai pada waktu instalasi.
  • claude auth login interaktif: masuk melalui claude.ai, claude.com, dan platform.claude.com. Guided setup, mode signed-in doctor, dan CI dispatch menggunakannya. Browser yang Anda gunakan untuk masuk juga memuat pemeriksaan browser halaman masuk claude.ai dari hcaptcha.com, *.hcaptcha.com, dan challenges.cloudflare.com. Jika organisasi Anda menggunakan single sign-on, browser tersebut juga dapat dialihkan melalui sso.claude.com.

Default-deny egress

Terapkan kontainer runner dan sesi dalam segmen jaringan atau namespace yang lalu lintas keluarnya dibatasi ke host dalam tabel persyaratan jaringan, host git Anda, dan layanan internal spesifik yang perlu dijangkau sesi. Produk tidak dapat memverifikasi atau menegakkan ini, jadi terapkan di batas jaringan Anda sendiri di setiap lingkungan. Kode sesi diarahkan model dan dapat mencoba koneksi ke host arbitrer; default-deny egress di lapisan jaringan membatasi di mana upaya tersebut dapat mendarat. Ini berlaku terlepas dari mode izin: set alat yang telah disetujui sebelumnya sudah mencakup Bash, jadi egress shell berjalan tanpa prompt bahkan tanpa mode auto. Untuk detail tentang telemetri mana yang dipancarkan setiap sesi dan cara mematikannya, lihat Telemetry.

Autentikasi ke proxy egress

Beberapa proxy egress korporat memerlukan header Proxy-Authorization pada setiap koneksi. Token dalam header itu sering berputar terlalu cepat untuk ditulis ke URL proxy yang Anda atur dalam HTTPS_PROXY. Atur HTTPS_PROXY atau HTTP_PROXY ke URL proxy Anda seperti biasa, kemudian atur --proxy-authorization-command atau --proxy-authorization-file untuk memberi tahu runner di mana membaca nilai header. Kedua flag memerlukan Claude Code v2.1.238 atau lebih baru.

Pilih dari mana nilai Proxy-Authorization berasal

Pilih flag yang cocok dengan cara Anda menghasilkan token Proxy-Authorization:
  • --proxy-authorization-command <command>: pilih ini untuk token yang Anda hasilkan sesuai permintaan. Runner menjalankan perintah shell dan menggunakan stdout yang dipangkas sebagai nilai header, misalnya Bearer <token>.
  • --proxy-authorization-file <path>: pilih ini untuk token yang proses lain putar di tempat. Runner membaca file dan menggunakan isinya yang dipangkas sebagai nilai header.

Konfigurasi yang menolak runner untuk dimulai dengan

Setiap flag juga memiliki bentuk variabel lingkungan, tercantum di sebelahnya dalam referensi flag CLI runner. Sebelum runner menghubungi proxy atau bidang kontrol Anda, itu memeriksa flag dan variabelnya, dan menolak untuk memulai dalam tiga kasus:
  • Kedua flag diatur: satu flag ditambah variabel lingkungan flag lainnya dihitung sebagai pengaturan keduanya.
  • Tidak ada URL proxy: baik HTTPS_PROXY maupun HTTP_PROXY tidak memegang URL http:// atau https://. Runner membaca kedua variabel dalam huruf besar atau kecil, dan tidak berkonsultasi dengan ALL_PROXY.
  • Flag apa pun diteruskan ke subperintah orchestrator: self-hosted-runner orchestrator tidak menerima flag atau variabel lingkungannya. Teruskan flag ke setiap runner yang dimulai orchestrator.

Apa yang diubah runner saat flag proxy-authorization diatur

Dengan flag apa pun yang diatur, runner memulai pendengar miliknya sendiri dan mengirim lalu lintas proxy dari dirinya sendiri, lifecycle hooks-nya, dan sesi-sesinya melalui pendengar itu. Pendengar menambahkan header Proxy-Authorization dalam perjalanan ke proxy Anda.
  • Pendengar: pendengar adalah proxy forward di 127.0.0.1. Runner memulai pendengar sebelum mendaftar dengan bidang kontrol, dan keluar pada startup jika pendengar tidak dapat dimulai.
  • Variabel proxy: runner menulis ulang mana pun dari HTTPS_PROXY dan HTTP_PROXY yang Anda atur sehingga menunjuk ke pendengar. Nilai yang ditulis ulang itu menjangkau runner itu sendiri, lifecycle hooks-nya, dan setiap sesi yang dijalankannya.
  • Rotasi token: token yang diputar berlaku tanpa restart. Untuk setiap koneksi yang dibuka pendengar ke proxy Anda, runner menjalankan perintah Anda atau membaca file Anda lagi dan menambahkan hasilnya sebagai header.
  • Lingkungan sesi: sesi menjangkau proxy Anda hanya melalui pendengar. Dalam lingkungan setiap sesi, runner menghapus ALL_PROXY, menghapus ejaan apa pun dari HTTPS_PROXY atau HTTP_PROXY yang tidak Anda atur, dan menyematkan NO_PROXY ke nilai runner itu sendiri.
  • Log: runner tidak pernah mencatat nilai header.

Konfigurasi git

Runner mengelola checkout repositori tetapi tidak mengonfigurasi identitas git atau kredensial secara default. Anda mengontrol gambar dan lingkungan proses runner, jadi Anda mengontrol konfigurasi git. Pilih salah satu dari dua pendekatan:
  • Biarkan runner mengonfigurasi git: mulai runner dengan --configure-git untuk memilikinya menulis identitas yang sama dan konfigurasi penandatanganan komit yang digunakan sesi yang di-host Anthropic
  • Kirim konfigurasi git dalam gambar Anda: atur identitas dan kredensial push sendiri, misalnya untuk berkomitmen di bawah identitas bot Anda sendiri
Untuk repositori di github.com, Anda juga dapat memulai runner dengan --use-anthropic-git-proxy, atau menetapkan CLAUDE_RUNNER_USE_GIT_PROXY=1, untuk meminta Anthropic melayani git bagi sesi-sesi runner. Lantai versi Git di host runner: --configure-git penandatanganan komit SSH memerlukan Git 2.34 atau lebih baru, --use-anthropic-git-proxy memerlukan 2.32 atau lebih baru, dan melanjutkan sesi dari cabang yang didorong oleh --push-outcome-on-release memerlukan 2.29 atau lebih baru. Git 2.24 cukup jika Anda menghilangkan ketiganya dan mengelola identitas git sendiri.

Biarkan runner mengonfigurasi git

Mulai runner dengan --configure-git, atau atur SELF_HOSTED_RUNNER_CONFIGURE_GIT=1, untuk memilikinya menulis konfigurasi git global pada startup:
  • user.name = Claude dan user.email = noreply@anthropic.com, cocok dengan sesi yang di-host Anthropic
  • Penandatanganan komit dan tag format SSH, dirutekan melalui shim yang dikelola runner yang menandatangani setiap komit melalui layanan penandatanganan Anthropic menggunakan kredensial sesi itu sendiri. Tanda tangan dapat diverifikasi di GitHub terhadap kunci penandatanganan SSH yang dipublikasikan Anthropic.
  • push.negotiate = true, jadi git menanyakan host git Anda komit mana yang sudah dimilikinya sebelum mengemas push. Memerlukan Claude Code v2.1.257 atau lebih baru.
  • core.hooksPath menunjuk ke direktori hooks yang dikelola runner. Hook commit-msg dan prepare-commit-msg-nya menambahkan trailer Co-authored-by: untuk pembuat sesi ke setiap commit. Trailer tersebut dibangun dari email dalam CCR_SESSION_ACCOUNT_EMAIL dan dihilangkan ketika variabel itu tidak diatur. Jika gambar Anda sudah menetapkan core.hooksPath dan runner tidak menggunakan git yang dikelola Anthropic, runner mempertahankan pengaturan Anda, melewati instalasi hook ini, dan mencetak peringatan [runner:git].
Penandatanganan komit memerlukan git 2.34 atau lebih baru; runner memeriksa pada startup dan keluar dengan kesalahan jika git Anda lebih lama. Flag ini tidak mengonfigurasi kredensial push, yang masih Anda sediakan dalam gambar. Pada runner dengan v2.1.280 atau lebih baru, commit yang Anda buat dari lifecycle hook checkout atau post-session juga ditandatangani sebagai sesi, tanpa trailer Co-authored-by:. Konfigurasi git di dalam lifecycle hook menjelaskan pengaturan git yang ditetapkan runner di dalam hook tersebut. Dengan atau tanpa --configure-git, Claude Code menginstruksikan Claude untuk mengakhiri pesan commit-nya dengan trailer Claude-Session: <url> dan deskripsi pull request-nya dengan URL sesi. Untuk menghilangkan keduanya, atur attribution.sessionUrl ke false di ~/.claude/settings.json host runner, lalu mulai ulang runner.

Kirim konfigurasi git dalam gambar Anda

Identitas git diperlukan untuk komit apa pun. Aturnya di seluruh sistem dalam Dockerfile Anda sehingga konfigurasi berlaku terlepas dari pengguna mana yang menjalankan proses runner:
Tanpa identitas, git commit gagal dengan Please tell me who you are dan sesi tidak dapat membuat kemajuan. Anda dapat menggunakan identitas bot Anda sendiri; runner tidak mengganti nilai-nilai ini. Jangan menanamkan kredensial push jangka panjang atau berscope luas ke gambar runner bersama: kredensial dalam gambar tersedia untuk setiap sesi yang dijalankan gambar, siapa pun yang memulainya. Sebagai gantinya, buat token jangka pendek dengan scope seminimal mungkin per sesi dari script wrapper Anda, menggunakan identitas pembuat sesi yang didekode dari session JWT. Pasangkan dengan kontainer per-sesi ephemeral, yang memerlukan --capacity 1, sehingga tidak ada kredensial yang bertahan lebih lama dari sesi yang membuatnya; lihat bagian pengerasan. Jika Anda harus mengonfigurasi kredensial push di tingkat gambar, misalnya untuk kunci deploy read-only, cakupkan seerat mungkin yang diizinkan host git Anda:
  • Kunci deploy SSH terbatas pada satu repositori dengan rewrite url.<base>.insteadOf
  • credential.helper yang mengembalikan token berscope minimal
  • GIT_SSH_COMMAND menunjuk ke kunci berscope sempit
Mekanisme apa pun yang Anda konfigurasi harus bekerja tanpa prompt, karena klon built-in runner dan fetch menonaktifkan prompt yang git, SSH, dan Git Credential Manager akan menampilkan:
  • Runner menetapkan GIT_TERMINAL_PROMPT=0, jadi git tidak meminta nama pengguna atau kata sandi.
  • Runner menjalankan SSH dengan BatchMode=yes, ditambahkan ke GIT_SSH_COMMAND Anda jika Anda menetapkan satu, jadi SSH tidak meminta frasa sandi atau konfirmasi host.
  • Runner menetapkan GCM_INTERACTIVE=never, jadi Git Credential Manager tidak membuka dialog sign-in.
  • Runner menghapus core.askPass, jadi jika Anda menggunakan helper askpass, aturnya melalui variabel lingkungan GIT_ASKPASS sebagai gantinya.
Jika host git Anda menolak kredensial, atau Anda tidak mengonfigurasi satu, runner mencoba beberapa kali dan kemudian gagal persiapan repositori ketika repositori adalah yang didorong sesi untuk hasil. Untuk repositori yang hanya dibaca sesi, Troubleshooting mencakup kapan runner melewatinya. Runner tidak meneruskan pengaturan ini ke lingkungan sesi. Jaga agar program apa pun yang Anda beri nama dalam GIT_SSH_COMMAND atau GIT_ASKPASS tetap berada di tempat sesi tidak dapat menulisnya, seperti yang diminta daftar pengerasan untuk direktori hooks dan script wrapper. Hal yang sama berlaku untuk kunci atau file apa pun pada baris perintah program itu. Git runner itu sendiri menjalankan program itu ketika klon atau fetch. Jika direktori checkout dimiliki oleh uid berbeda dari proses runner, git menolak untuk beroperasi pada mereka; tambahkan safe.directory:

Gunakan proxy git Anthropic

Dengan proxy git Anthropic, yang juga disebut git yang dikelola Anthropic, gambar runner tidak memerlukan kunci SSH, credential helper, .netrc, atau kredensial git lain untuk sesi itu sendiri. Sebagai gantinya, runner meminta Anthropic untuk melayani git bagi sesi-sesinya. Untuk sesi pengguna yang dilayani Anthropic, clone runner serta fetch dan push milik sesi itu sendiri melewati Anthropic, yang menggunakan token OAuth GitHub yang disimpan untuk pembuat sesi. Bagaimana Anthropic melayani git untuk sebuah sesi membahas sesi bot dan agent. Proxy git nonaktif kecuali Anda mengaktifkannya. Runner yang menjangkau host git Anda dengan kredensialnya sendiri tidak memerlukannya, dan git-nya bekerja dengan host git apa pun. Sebagai gantinya, proxy git membatasi apa yang didukung runner dan mengubah apa yang dibutuhkannya:
  • Hanya github.com: Anthropic melayani sebuah sesi hanya ketika semua repositorinya berada di github.com, dan proxy git belum mendukung GitHub Enterprise Server. Pada runner dengan proxy git, sesi dengan repositori di host git lain gagal dimulai.
  • Kredensial hanya untuk repositori sesi: Anthropic menyediakan kredensial git untuk repositori yang merupakan bagian dari sesi, bukan untuk repositori lain di host git yang sama. Submodule privat, dependensi yang di-fetch oleh package manager Anda dengan git, atau marketplace plugin di repositori lain tidak mendapatkan kredensial dari Anthropic. Minta orang-orang yang membuat sesi untuk menambahkan setiap repositori yang dibutuhkan sesi saat mereka membuatnya. Setiap eksekusi tugas terjadwal cloud adalah sesi dengan repositori milik tugas tersebut, jadi minta pemilik setiap tugas untuk menambahkan setiap repositori yang dibutuhkan eksekusinya.
  • Hanya push branch: push yang menghapus branch gagal, begitu pula push ke jenis ref lain, seperti tag. Untuk branch mana yang dapat diperbarui oleh push, lihat GitHub proxy.
  • Akun GitHub yang terhubung: minta setiap orang yang membuat sesi pengguna dengan repositori untuk menghubungkan GitHub. Tanpa koneksi mereka sendiri, sesi tersebut tidak dimulai.
  • --capacity 1: proxy git memerlukan satu sesi per proses runner, jadi jalankan lebih banyak replika untuk paralelisme. Aktifkan proxy git Anthropic mencantumkan persyaratannya.
  • Konfigurasi git global yang digantikan: runner menghapus dan menggantikan konfigurasi git global milik pengguna yang menjalankannya. Jalankan runner sebagai pengguna khusus atau di dalam kontainer.
  • Kredensial host untuk push dari host: push --push-outcome-on-release milik runner dan push apa pun yang dilakukan hook post-session Anda tetap menggunakan kredensial git milik host runner sendiri dan jalur jaringannya ke github.com. Jauhkan kredensial tersebut dari konfigurasi git global, dan lihat Kirim konfigurasi git dalam gambar Anda untuk cara menyediakannya.
  • Keputusan per sesi: Anthropic memutuskan untuk setiap sesi di runner apakah akan melayani git-nya, dan sesi yang tidak dilayaninya gagal dimulai. Ketika sesi gagal dimulai pada runner dengan proxy git membahas penyebabnya.
Dengan --use-anthropic-git-proxy ditetapkan, runner menghapus dan menggantikan konfigurasi git global milik pengguna yang menjalankannya, tanpa menyimpan cadangan. Ini dilakukan saat startup dan sebelum setiap sesi. Login atau credential helper yang Anda simpan di sana akan hilang. Pengaturan yang ditulis --configure-git tetap bertahan. Jalankan runner sebagai pengguna khusus atau di dalam kontainer, jangan pernah sebagai pengguna Anda sendiri.
Simpan pengaturan git yang tidak rahasia, seperti identitas dan safe.directory, di konfigurasi git sistem.

Aktifkan proxy git Anthropic

Sebelum Anda memulai runner dengan --use-anthropic-git-proxy, pastikan host runner memenuhi setiap persyaratan berikut. Runner menolak untuk dimulai ketika persyaratan kapasitas atau git tidak terpenuhi:
  • Claude Code v2.1.267 atau lebih baru: versi sebelumnya menerima flag tetapi tidak melaporkan permintaan agar Anthropic melayani git atau mencetak baris Registering as opted in, sehingga Anthropic tidak melayani sesi-sesinya.
  • --capacity 1, nilai default: setiap proses runner menangani satu sesi pada satu waktu, jadi jalankan lebih banyak replika untuk paralelisme.
  • Git 2.32 atau lebih baru: git yang lebih lama mengabaikan konfigurasi git per sesi yang disiapkan runner untuk proxy git.
Resep Kubernetes dan Docker Compose di halaman ini menggunakan --capacity 4. Jika Anda menambahkan --use-anthropic-git-proxy atau CLAUDE_RUNNER_USE_GIT_PROXY=1 ke salah satunya tanpa mengubah kapasitas menjadi 1, runner keluar pada startup setiap kali orchestrator Anda memulainya kembali. Atur --capacity 1 dan jalankan lebih banyak replika untuk paralelisme. When the runner exits menunjukkan baris yang dicetak runner.
Untuk mengaktifkan proxy git, tambahkan --use-anthropic-git-proxy ke perintah runner, atau atur CLAUDE_RUNNER_USE_GIT_PROXY=1 di lingkungan runner. Perintah ini, yang dijalankan di shell pada host runner, memulai runner dari mulai cepat dengan proxy git aktif:
Saat startup, runner mencetak Registering as opted in to Anthropic-managed git (--use-anthropic-git-proxy). Anthropic kemudian memutuskan untuk setiap sesi pada runner tersebut apakah akan melayani git-nya. Untuk setiap sesi yang dilayaninya, runner mencatat baris [runner:session] yang berisi governed git ACTIVE. Jika sebuah sesi justru gagal dimulai, lihat Ketika sesi gagal dimulai pada runner dengan proxy git.

Bagaimana Anthropic melayani git untuk sebuah sesi

Untuk sesi yang dilayani Anthropic, clone runner serta fetch dan push milik sesi itu sendiri melewati Anthropic, diautentikasi dengan token jangka pendek milik sesi itu sendiri:
  • Sesi pengguna: Anthropic menggunakan token OAuth GitHub yang disimpan untuk pembuat sesi.
  • Sesi bot dan agent: Anthropic menggunakan token instalasi GitHub App organisasi Anda.
  • Penulisan ulang URL: --git-host-rewrite dan --git-ssh-rewrite tidak berpengaruh pada repositori yang dilayani proxy git.

Ketika sesi gagal dimulai pada runner dengan proxy git

Pada runner yang dimulai dengan --use-anthropic-git-proxy, sebuah sesi gagal dimulai ketika Anthropic tidak melayani git-nya. Cari di log runner kesalahan git yang menyebutkan alamat api.anthropic.com yang berisi /git_proxy/. Untuk setiap sesi, runner dengan Claude Code v2.1.267 atau lebih baru juga mencatat baris [runner:session] yang berisi governed git ACTIVE ketika Anthropic melayani git sesi tersebut, atau satu baris [runner:warn] yang berisi the server withheld Anthropic-managed git for this session ketika tidak. Temukan baris yang Anda lihat di antara kasus-kasus berikut:
  • Baik governed git ACTIVE maupun baris withheld tidak ada: runner yang lebih lama dari Claude Code v2.1.267 tidak mencatat kedua baris tersebut, dan Anthropic tidak melayani sesi-sesinya. Perbarui runner ke v2.1.267 atau lebih baru dengan mengikuti Pin the version.
  • Baris withheld: Anthropic tidak melayani sesi tersebut. Runner yang sebelumnya bekerja dengan proxy git dapat gagal dengan cara ini tanpa perubahan apa pun di pihak Anda.
    • Sebuah repositori tidak berada di github.com: sesi dengan satu repositori saja di host git lain, seperti GitHub Enterprise Server, tidak dilayani, termasuk repositori github.com-nya. Nonaktifkan proxy git Anthropic untuk runner di lingkungan tersebut.
    • Setiap repositori berada di github.com: laporkan kegagalan tersebut ke tim akun Anthropic Anda dengan ID sesi dari baris withheld. Anthropic mencatat alasannya di sisinya.
  • Baris yang berisi remote: access denied by the git proxy: sesi yang dilayani Anthropic masih dapat ditolak, misalnya ketika kebijakan organisasi menolak akses git untuk sesi tersebut, atau sesi tidak diotorisasi untuk repositori. Log runner kemudian menampilkan baris yang berisi remote: access denied by the git proxy, dan sisa baris tersebut menjelaskan alasannya.
  • GitHub authentication required: ini muncul ketika pembuat sesi tidak memiliki koneksi GitHub yang berfungsi di claude.ai. Clone sesi gagal, dan kesalahan git berbunyi GitHub authentication required. Please reconnect your GitHub account. Minta orang tersebut untuk menghubungkan atau menghubungkan ulang GitHub di pengaturan claude.ai mereka.
Setelah Anda memperbaiki penyebabnya, mulai lagi sesi-sesi yang gagal.

Nonaktifkan proxy git Anthropic

Jika sesi di suatu lingkungan menggunakan repositori di host git selain github.com, seperti GitHub Enterprise Server, nonaktifkan --use-anthropic-git-proxy untuk runner di lingkungan tersebut.
1

Hapus flag

Hapus --use-anthropic-git-proxy dari perintah runner. Jika Anda mengatur CLAUDE_RUNNER_USE_GIT_PROXY di lingkungan runner, seperti pod spec atau file Compose, hapus dari sana. Di shell, batalkan pengaturannya:
2

Berikan kredensial git ke runner

Sediakan kredensial yang bekerja tanpa prompt untuk setiap host git yang digunakan sesi-sesi runner, termasuk github.com. Kredensial apa pun yang ada di konfigurasi git global pengguna runner sudah hilang, karena runner menghapus konfigurasi tersebut selama --use-anthropic-git-proxy ditetapkan. Kirim kredensial dalam gambar Anda atau gunakan lifecycle hook checkout.
3

Buka jalur jaringan

Izinkan runner menjangkau setiap host git yang digunakan sesi-sesi runner pada port 443 atau 22. Lihat baris host git di Persyaratan jaringan.
4

Mulai ulang runner

Mulai ulang runner agar terdaftar tanpa proxy git. Kemudian mulai lagi setiap sesi yang gagal.

Akses GitHub API tanpa GitHub CLI

Jika gambar runner Anda tidak menyertakan GitHub CLI, Claude Code dapat menyediakan gh bawaan, sehingga Claude tetap dapat membuka pull request, berkomentar, dan membaca hasil CI. gh bawaan ditujukan untuk runner yang menggunakan git yang dikelola Anthropic. gh bawaan mendukung satu perintah, gh api, yang memanggil REST API GitHub. Memerlukan Claude Code v2.1.287 atau lebih baru di gambar runner. Perintah ini membuka pull request sebagai pengganti gh pr create. gh bawaan mengisi {owner} dan {repo} untuk repositori saat ini:
  • Kredensial: gh bawaan mengirimkan permintaan REST-nya melalui git yang dikelola Anthropic, yang menyediakan kredensial GitHub di sisi Anthropic, sehingga gambar tidak memerlukan token GitHub untuk itu
  • Sesi mana yang mendapatkannya: Anthropic memutuskan per sesi apakah git yang dikelola Anthropic melayani gh sesi tersebut. Jika ya, baris [runner:session] governed git ACTIVE yang dicatat runner untuk sesi tersebut menampilkan gh_path_shim=true. Jika tidak, sesi tidak memiliki gh
  • jq: instal jq di gambar jika Anda ingin --jq berfungsi
  • CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: jika lingkungan sesi menetapkannya, Claude Code tidak menyediakan gh bawaan, dan sesi tidak memiliki gh
Ketika gambar menyertakan GitHub CLI, sesi menggunakannya.

Percayai otoritas sertifikat pribadi dengan git yang dikelola Anthropic

Bagian ini berlaku jika Anda menetapkan GIT_SSL_CAINFO atau GIT_SSL_NO_VERIFY dalam lingkungan runner yang sesinya menggunakan git yang dikelola Anthropic. Penanganan yang dijelaskannya memerlukan runner untuk menjalankan Claude Code v2.1.283 atau lebih baru. Ketika git di runner harus mempercayai otoritas sertifikat pribadi (CA), seperti yang ditandatangani oleh proxy yang menginspeksi TLS, pendekatan biasa bekerja sebagai berikut:
  • Penyimpanan sertifikat sistem: instal CA Anda di penyimpanan sertifikat sistem host runner, dan git mempercayainya tanpa variabel apa pun.
  • GIT_SSL_CAINFO: aturnya ke file PEM dari CA Anda, misalnya GIT_SSL_CAINFO=/etc/ssl/corp-ca.pem.
  • GIT_SSL_NO_VERIFY: tidak membantu di balik proxy yang menandatangani ulang. Klon runner sendiri melalui git yang dikelola Anthropic memeriksa sertifikat bahkan ketika variabel diatur, jadi klon itu gagal sampai git mempercayai CA Anda melalui salah satu dari dua pendekatan lainnya.
Untuk koneksi git yang membawa token sesi ke git yang dikelola Anthropic, runner menerapkan dua variabel sebagai berikut. Hook command dimulai dengan lingkungan sesi, jadi itu mendapatkan apa yang git di dalam sesi dapatkan:
  • GIT_SSL_CAINFO: terhadap apa git memeriksa git yang dikelola Anthropic tergantung di mana git berjalan:
    • Klon dan fetch runner sendiri: berjalan tanpa variabel dan memeriksa git yang dikelola Anthropic terhadap file sertifikat per-sesi yang ditulis runner. Runner membangun file itu dari bundel CA sistem host runner dan sertifikat dalam file Anda.
    • Git di dalam sesi: mendapatkan konfigurasi http.sslCAInfo yang menamai file Anda sebagai pengganti variabel, ditambah entri http.<url>.sslCAInfo yang memeriksa git yang dikelola Anthropic terhadap file per-sesi.
    • Hook checkout dan post-session: mewarisi variabel tanpa perubahan.
  • GIT_SSL_NO_VERIFY: pemeriksaan sertifikat mana yang tetap mati tergantung di mana git berjalan:
    • Klon dan fetch runner sendiri: berjalan tanpa variabel dan periksa sertifikat yang mereka sajikan.
    • Git di dalam sesi: mendapatkan konfigurasi http.sslVerify=false sebagai pengganti variabel, jadi pemeriksaan tetap mati untuk host lain. Itu juga mendapatkan entri http.<url>.sslVerify=true yang menjaga pemeriksaan tetap aktif untuk git yang dikelola Anthropic.
    • Hook checkout dan post-session: ketika sesi memiliki repositori di git yang dikelola Anthropic, dapatkan konfigurasi http.sslVerify=false sebagai pengganti variabel. Mereka juga mendapatkan entri http.<url>.sslVerify=true yang menjaga pemeriksaan tetap aktif untuk git yang dikelola Anthropic.
File sertifikat per-sesi memerlukan bundel CA sistem di /etc/ssl/certs/ca-certificates.crt atau /etc/pki/tls/certs/ca-bundle.crt di host runner. Itu juga memerlukan file GIT_SSL_CAINFO yang dapat dibaca pengguna runner, yang menyimpan blok CERTIFICATE PEM, dan yang paling banyak 1 MiB. Ketika runner tidak dapat membangun file per-sesi, itu mencatat baris [runner:warn] yang berisi did not build the certificate file dan alasannya. Git kemudian menggunakan file Anda seperti apa adanya untuk git yang dikelola Anthropic. Perbaiki apa yang dinamai baris. Untuk setiap sesi yang menggunakan git yang dikelola Anthropic, runner juga mencatat baris [runner:warn] yang dimulai dengan governed git: GIT_SSL_CAINFO is set atau governed git: GIT_SSL_NO_VERIFY is set. Baris mengatakan apa yang dilakukan runner dengan variabel itu untuk git-nya sendiri, untuk git di dalam sesi, dan untuk hook lifecycle Anda. Itu berakhir dengan apakah Anda perlu mengubah apa pun.

Tambahkan repositori github.com ke sesi channel Claude Tag

Jika Claude tidak dapat menambahkan repositori github.com ke sesi channel Claude Tag, pastikan channel tersebut memiliki akses ke repositori itu, bahkan ketika runner Anda dapat meng-clone-nya. Akses tersebut berasal dari pengaturan di GitHub dan di organisasi Claude Anda, bukan dari kredensial git runner Anda.
1

Instal Claude GitHub App

Instal Claude GitHub App pada organisasi atau akun GitHub yang memiliki repositori tersebut, dan sertakan repositori itu dalam instalasi.
2

Tautkan organisasi atau akun GitHub

Di Organization settings > Git providers, tautkan organisasi atau akun tersebut ke organisasi Claude Anda. Owner organisasi Claude Anda yang juga memiliki organisasi GitHub dapat menautkannya. Lihat Link your GitHub organization.
3

Berikan akses repositori

Di pengaturan admin Claude Tag, berikan akses repositori ke channel atau ke cakupan yang lebih luas yang mencakup channel tersebut: workspace Slack-nya atau seluruh Slack. Seseorang dengan peran Owner atau izin Claude Tag Admin dapat memberikannya. Pengelola channel juga dapat menambahkannya ke channel mereka sendiri jika akun GitHub mereka adalah admin repositori tersebut. Lihat Grant repository access.
Kemudian mulai thread baru di channel dan sebutkan nama repositori dalam pesan pertama Anda. Jika Claude masih tidak dapat menambahkan repositori, lihat If Claude can’t reach a repository untuk mengetahui di mana memeriksa tautan GitHub dan pemberian akses repositori.

Tulis ulang URL git untuk jaringan pribadi

URL repositori tiba dari bidang kontrol sebagai HTTPS, dengan nama host dari host git Anda; untuk GitHub Enterprise, itu adalah nama host yang Anda konfigurasi untuk integrasi GitHub Enterprise di claude.ai. Dua flag yang dapat diulang menulis ulang URL tersebut sebelum klon:
  • --git-host-rewrite <from>=<to>: untuk split-horizon DNS, di mana Anthropic menjangkau host git Anda melalui nama host eksternal tetapi runner harus menggunakan yang internal
  • --git-ssh-rewrite <host>: untuk host git yang hanya menerima SSH, atau host runner yang hanya memiliki kunci SSH. Misalnya, untuk meng-clone repositori github.com melalui SSH, tambahkan --git-ssh-rewrite github.com ke perintah runner. Runner kemudian menulis ulang https://github.com/owner/repo menjadi git@github.com:owner/repo. SSH harus terhubung tanpa prompt.
Penulisan ulang host berjalan terlebih dahulu, jadi daftar nama host internal dalam --git-ssh-rewrite jika Anda memerlukan keduanya. Untuk kontrol penuh atas checkout, gunakan checkout lifecycle hook.

Bangun gambar runner

Anthropic tidak menerbitkan gambar runner yang telah dibangun sebelumnya. Bangun milik Anda sendiri di sekitar biner claude, berlapis dengan toolchain apa pun yang dibutuhkan repositori Anda: runtime bahasa, compiler, package manager, dan sidecar MCP. Resep di bawah menggunakan --capacity 4, jadi satu kontainer melayani hingga empat sesi bersamaan dari pemilik terkunci yang sama. Itu tidak memberikan isolasi kontainer per-sesi dalam bagian pengerasan: sebelum menghubungkan lingkungan ke sistem produksi, jalankan resep pada --capacity 1 dengan satu kontainer per sesi, atau gunakan runner on-demand, yang juga menjaga rahasia lingkungan dari host yang menjalankan sesi. Jika Anda menambahkan proxy git Anthropic ke salah satu resep ini, juga ubah --capacity menjadi 1. Dockerfile ini adalah titik awal minimal. Dockerfile ini menginstal python3 karena hook yang disediakan control plane Anthropic untuk sesi Claude Tag, termasuk hook yang membuat Claude memposting balasannya di Slack, menjalankan python3. Pertahankan python3 pada PATH di gambar apa pun yang melayani sesi Claude Tag:
Tukar linux-x64 untuk linux-arm64 jika node Anda adalah ARM, atau untuk linux-x64-musl atau linux-arm64-musl pada gambar berbasis musl seperti Alpine; lihat Alpine Linux setup untuk paket tambahan yang dibutuhkan gambar musl. URL adalah lokasi rilis Claude Code standar, jadi Anda dapat memverifikasi biner yang diunduh terhadap manifes yang ditandatangani rilis seperti yang dijelaskan dalam Binary integrity and code signing. Runner memerlukan Claude Code versi 2.1.224 atau lebih baru, atau 2.1.229 atau lebih baru untuk melayani sesi Claude Tag. Bangun gambar, kemudian dorong ke registri Anda dan referensikan dalam resep di bawah:
Substitusi perintah mencari nomor rilis stable saat ini dan meneruskannya sebagai argumen build, jadi menjalankan perintah yang sama setelah rilis stabil baru membangun ulang lapisan unduhan dengan biner yang lebih baru. Untuk menyematkan rilis tertentu untuk build yang dapat direproduksi, teruskan nomor versi langsung sebagai CLAUDE_CODE_VERSION. Ganti stable dengan latest dalam URL pencarian ketika Anda memerlukan rilis yang lebih baru dari saluran stabil, seperti yang diperlukan model yang baru diluncurkan.

Ukuran CPU dan memori untuk sesi

Ukuran kontainer atau host runner untuk sesi yang dijalankannya daripada untuk proses runner. Runner itu sendiri menanyakan pekerjaan, menyiapkan checkout setiap sesi, menjalankan lifecycle hooks Anda, dan memulai serta mengawasi proses sesi. Beban datang dari sesi: masing-masing adalah proses Claude Code ditambah apa pun yang dimulainya, seperti build, test suite, instalasi paket, dan MCP server. Untuk satu sesi, mulai dengan nilai-nilai berikut, dinyatakan sebagai permintaan dan batas Kubernetes atau setara platform Anda, dan perlakukan sebagai titik awal daripada persyaratan:
  • Memori: permintaan dan batas 4 GiB masing-masing, yang memenuhi minimum 4 GB dalam persyaratan sistem Claude Code. Jaga keduanya tetap sama sehingga penjadwal memperhitungkan memori penuh kontainer. Ketika kontainer mencapai batas memorinya, kernel membunuh proses di dalamnya, yang dapat mengakhiri sesi di tengah-tugas.
  • CPU: permintaan 2 CPU dan batas 4 CPU, jadi sesi dapat meledak di atas permintaan selama build. Kernel membatasi kontainer pada batas CPU-nya daripada membunuh proses di dalamnya, jadi sesi pada batas berjalan lebih lambat tetapi terus berjalan.
Dalam spec kontainer Kubernetes, atur nilai awal tersebut dengan blok resources berikut:
Build dan test biasanya merupakan bagian terbesar dan paling variabel dari beban sesi, jadi jalankan build representatif repositori Anda, ukur puncak CPU dan memorinya, dan naikkan nilai awal apa pun yang tidak meninggalkan ruang untuk proses Claude Code di atas puncak itu. Runner menggunakan --capacity untuk membatasi berapa banyak sesi yang dijalankannya sekaligus. Itu tidak membagi CPU atau memori di antara mereka, jadi sesi pada runner berbagi CPU dan memori kontainer. Agar penggunaan memori satu sesi tidak mengakhiri sesi lainnya, jalankan satu sesi per runner dengan batas memorinya sendiri.
  • Satu sesi per runner: berikan setiap kontainer nilai satu sesi. Gunakan ukuran ini pada --capacity 1, yang bagian pengerasan rekomendasikan, dan untuk runner on-demand, di mana Anda menetapkan nilai pada workload yang spawn-runner hook Anda kirimkan, seperti template pod Job Kubernetes.
  • Beberapa sesi per runner: pada --capacity di atas satu, kalikan nilai satu sesi dengan kapasitas, karena hingga banyak sesi dapat berjalan dalam kontainer sekaligus. Resep Kubernetes dan Docker Compose menjalankan --capacity 4 tanpa batas CPU atau memori, jadi tambahkan batas yang diukur untuk kapasitas yang Anda jalankan.
  • Beberapa kontainer runner pada satu host: ukur host untuk jumlah kapasitas semua runner, karena setiap runner hanya menghitung sesinya sendiri terhadap --capacity:
    • Memori: kalikan memori satu sesi dengan jumlah tersebut, lalu tambahkan apa yang digunakan oleh proses host itu sendiri
    • CPU: kalikan permintaan CPU satu sesi dengan jumlah tersebut. Agar setiap sesi dapat meledak sekaligus, kalikan batas CPU-nya sebagai gantinya.
    Berikan setiap runner kontainernya sendiri. Gunakan path --base-dir yang sama di masing-masing, pada penyimpanan yang tidak di-mount oleh kontainer runner lain, sehingga setiap runner memiliki direktori kerjanya sendiri.

Berikan setiap sesi batas memorinya sendiri

Untuk mencegah satu sesi mengakhiri sesi lainnya ketika memori habis, jalankan setiap runner pada --capacity 1 di bawah batas memorinya sendiri, yang diatur ke memori satu sesi:
  • Di dalam kontainer: jalankan satu runner per kontainer, dan atur batas memori kontainer, seperti limits.memory di Kubernetes, --memory di Docker, atau mem_limit dalam file Compose. Jaga agar jumlah batas semua kontainer tetap di bawah memori host, karena ketika host itu sendiri kehabisan memori, kernel dapat membunuh proses di mana saja pada host.
  • Di bawah systemd tanpa kontainer: atur MemoryMax pada unit runner, dan jalankan satu runner per host, karena runner yang menggunakan --base-dir yang sama pada satu sistem file berbagi repositori yang di-clone di sana. Misalnya, pada --capacity 1 tanpa hook checkout, sesi mereka pada satu repositori dapat bekerja di checkout yang sama sekaligus. Untuk menjalankan beberapa runner pada satu host, berikan masing-masing sebuah kontainer.
Ketika kontainer atau unit mencapai batas memorinya, kernel hanya membunuh proses di dalamnya. Jika Anda mengatur --capacity di atas satu, sesi-sesi tersebut berbagi satu batas. Ketika mereka mencapainya, kernel tidak memilih berdasarkan sesi proses mana yang akan dibunuh, sehingga penggunaan memori satu sesi dapat mengakhiri sesi lainnya. Di Kubernetes, Anda tidak dapat memisahkan sesi dengan nilai mana pun dari pengaturan singleProcessOOMKill milik kubelet. Anda juga tidak dapat membatasi total memori sesi dengan ulimit memori dalam script wrapper Anda. Kernel menerapkan nilai seperti ulimit -v ke setiap proses secara terpisah.

Sisakan ruang di bawah batas proses dan thread

Untuk menentukan ukuran batas proses dan thread, ukur apa yang dibutuhkan satu sesi dan kalikan dengan jumlah sesi yang berbagi batas tersebut. Ketika sesi-sesi tersebut mencapai batas, kernel menolak proses dan thread baru, sehingga perintah, build, dan test di salah satu sesi dapat gagal. Panggilan yang ditolak mengembalikan EAGAIN, yang pesan standarnya adalah Resource temporarily unavailable. Misalkan satu sesi mencapai puncak 300 proses dan thread, dan empat sesi berbagi batas tersebut. Bersama-sama mereka membutuhkan 1.200, dan dengan batas 2.400, Anda menyisakan ruang untuk build yang membutuhkan dua kali lipat.

Tempat mengatur setiap batas

Setiap batas dalam tabel ini menghitung thread maupun proses, dan pids.max adalah file yang menyimpan batas cgroup: Ketika Anda tidak mengatur TasksMax, systemd menerapkan DefaultTasksMax, yang secara default bernilai 15% dari nilai terendah di antara kernel.pid_max, kernel.threads-max, dan pids.max milik cgroup root.

Ukur puncak satu sesi

Untuk mendapatkan angka bagi runner Anda sendiri, ukur satu sesi pada host-nya, yang di Kubernetes adalah node:
1

Mulai satu runner sendirian

Mulai satu runner pada --capacity 1 tanpa hal lain di kontainer atau unit systemd-nya, sendirian pada host-nya dan di environment-nya:
  • Host-nya: gunakan host yang tidak menjalankan runner lain. Anda kemudian dapat mengenali prosesnya pada langkah berikutnya.
  • Environment-nya: jadikan runner tersebut satu-satunya runner di sana, misalnya di environment yang Anda buat untuk pengujian. Sesi dirutekan ke environment dan bukan ke runner.
Jangan mulai sesi dulu, karena Anda memerlukan direktori dari langkah berikutnya sebelum build dimulai.
2

Temukan direktori cgroup runner

Pada host, bukan di dalam kontainer, temukan ID proses runner, misalnya dengan ps. Baca /proc/<pid>/cgroup untuk ID tersebut:
  • Sebuah baris berisi :pids:: host menggunakan cgroup v1, dan direktorinya adalah /sys/fs/cgroup/pids diikuti teks setelah :pids:
  • Satu-satunya baris dimulai dengan 0::: host menggunakan cgroup v2, dan direktorinya adalah /sys/fs/cgroup diikuti teks setelah 0::
3

Jalankan build representatif dan catat puncaknya

Jalankan satu sesi melalui build representatif, dan ambil puncaknya dari direktori cgroup runner:
  • Direktori memiliki pids.peak: baca file tersebut setelah build selesai
  • Direktori tidak memiliki pids.peak: baca pids.current sekali setiap detik selama build berjalan, dan simpan nilai tertinggi. Puncak di antara dua pembacaan tidak akan terlihat, jadi perlakukan nilai tersebut sebagai perkiraan rendah.
4

Kalikan dengan sesi yang berbagi batas

  • Pod, kontainer, atau unit satu runner: kalikan puncak dengan --capacity runner
  • Batas yang dibagi oleh beberapa runner: kalikan puncak dengan jumlah kapasitas mereka
Kemudian tambahkan puncak dari hal lain yang berbagi batas tersebut, seperti kontainer lain di Pod.
5

Atur batas di atas hasilnya

Dengan batas yang lebih tinggi, Anda menyisakan ruang untuk build yang lebih berat, dan dengan batas yang lebih rendah, Anda menghentikan fork bomb lebih cepat.

Periksa batas pids.max

  • Periksa apakah pids.max telah tercapai: cari di log kernel host, misalnya dengan dmesg, baris yang berisi cgroup: fork rejected by pids controller in dan path sebuah cgroup. Kernel hanya mencatatnya pertama kali ia menolak proses atau thread dalam cgroup tersebut, jadi cari di seluruh log.
  • Lihat batas yang berlaku: baca pids.max di direktori cgroup runner dan di setiap direktori di atasnya. Nilai terendah adalah batas yang berlaku, dan max berarti tidak ada batas pada tingkat tersebut.

Kubernetes

Runner melayani GET /healthz di port 8080 secara default, dapat dikonfigurasi dengan --health-port, jadi probe Kubernetes bekerja tanpa setup tambahan. Endpoint mengembalikan 200 kapan pun proses hidup, jadi probe di bawah mendeteksi proses mati, bukan yang terjebak; untuk menangkap runner yang berhenti polling, beri peringatan pada seri last_poll_age_seconds dari /metrics. Deployment di bawah memasang rahasia lingkungan dari Secret Kubernetes, menunjuk probe liveness dan readiness ke /healthz, dan menetapkan periode grace terminasi 90 detik. Lihat Shutdown timing untuk alasan periode grace penting. Manifest tidak menetapkan resources CPU atau memori pada kontainer runner. Tambahkan blok yang diukur untuk kapasitas yang Anda jalankan, seperti Size CPU and memory for sessions jelaskan.
Deployment di atas hidup dalam namespace claude-runners. Buat namespace terlebih dahulu:
Buat Secret pendukung dari file lokal yang memegang nilai yang Anda salin dalam langkah Copy environment key UI admin, jadi rahasia tidak pernah muncul dalam riwayat shell Anda. Jalankan (umask 077 && cat > ./environment-secret), tempel rahasia, tekan Enter, kemudian Ctrl-D. Kemudian buat Secret dan hapus file:

Docker Compose

Layanan Compose di bawah memulai ulang runner kapan pun keluar, yang mencakup crash dan exit normal setelah draining. Kebijakan restart Docker memulai ulang kontainer yang sama dengan lapisan yang dapat ditulisnya utuh, jadi runner kembali pada filesystem yang digunakan kembali daripada yang segar yang postur pengerasan rekomendasikan; gunakan resep ini untuk evaluasi, dan untuk produksi baik buat ulang kontainer per run atau gunakan orchestrator yang melakukannya. Docker menunggu lebih lama sebelum setiap restart kontainer yang terus keluar, hingga batas maksimal, jadi runner yang tidak dapat dimulai tidak terus memulai ulang dalam loop ketat di bawah resep ini. Ketika runner keluar menjelaskan apa yang harus diperiksa ketika itu terjadi.

Waktu shutdown

Setelah SIGTERM, runner memerlukan waktu untuk menghentikan sesinya dengan bersih sebelum orchestrator Anda membunuhnya. Runner mencatat berapa lama waktu tersebut saat startup, dalam baris yang berisi This runner needs up to 80s pada pengaturan default. Atur stop timeout orchestrator Anda ke setidaknya jumlah detik tersebut: terminationGracePeriodSeconds pada Kubernetes, stop_grace_period pada Docker Compose, atau yang setara di platform Anda. Default Kubernetes adalah 30 detik, jadi tanpa pengaturan ini Kubernetes dapat menghentikan pod sebelum runner selesai. Pada SIGTERM, runner berhenti menerima sesi baru. Runner kemudian memulai shutdown yang terkendali, yang disebut drain, kecuali Anda menetapkan --defer-shutdown-max-min untuk menundanya. Drain memiliki tiga langkah:
  1. Runner menunggu hingga --drain-wait-sec detik, 0 secara default, agar giliran yang masih berjalan selesai.
  2. Runner menghentikan pohon proses setiap sesi, termasuk perintah apa pun yang masih dijalankan Claude, tetapi tidak termasuk proses yang masih berjalan setelah perintah shell-nya keluar.
  3. Runner menjalankan hook lifecycle post-session.
Runner terus melakukan polling ke Anthropic sepanjang drain. Hal itu membuat sesinya tetap ditugaskan kepadanya, sehingga runner lain tidak mengambil salah satu sesi tersebut sementara hook post-session Anda masih menyimpan pekerjaan yang belum dikomit. Waktu yang dicatat adalah jumlah dari nilai-nilai berikut: Pada pengaturan default, totalnya adalah 0 + 5 + 60 + 15 = 80 detik. --capacity yang lebih tinggi tidak menambahnya, karena runner melakukan drain terhadap semua sesinya secara bersamaan. Sediakan waktu lebih jika Anda mengatur salah satu dari flag berikut:
  • Dengan --retire-at: sisakan cukup waktu antara waktu retire dan waktu host berhenti agar giliran tipikal dapat selesai, ditambah waktu tunggu untuk tugas latar belakang yang dijelaskan Runner lifecycle, ditambah waktu yang dicatat. Hitung waktu retire di setiap peluncuran, misalnya date +%s ditambah masa hidup yang dimaksudkan untuk runner.
  • Dengan --defer-shutdown-max-min: stop timeout juga harus mencakup menit yang Anda konfigurasi dan waktu tunggu tambahan sebelum drain dimulai, 75 detik pada pengaturan default. Defer the drain past the first signal menjelaskan keduanya. Runner juga mencatat waktu yang lebih panjang ini saat startup.

Biarkan giliran yang sedang berjalan selesai sebelum restart

Untuk membiarkan giliran yang sedang berjalan selesai sebelum restart bergulir, atur --drain-wait-sec, dan naikkan stop timeout Anda ke setidaknya waktu tunggu tersebut ditambah 80 detik. Dengan waktu tunggu default 0, restart memotong giliran apa pun yang masih berjalan, dan sesi dilanjutkan di runner lain tanpa pekerjaan yang belum di-push.
  • --drain-wait-sec: kira-kira selama giliran dan tugas latar belakang yang ingin Anda biarkan selesai. Ini adalah nilai maksimum: waktu tunggu berakhir lebih awal jika semuanya selesai lebih dulu.
  • Stop timeout Anda: terminationGracePeriodSeconds di Kubernetes, stop_grace_period di Docker Compose. Misalnya, dengan --drain-wait-sec 120, ganti 90 dalam resep Kubernetes atau Docker Compose dengan 200.
  • Jika Anda mengubah pengaturan shutdown lainnya: 80 detik tersebut berlaku untuk pengaturan default. Jalankan satu runner dengan flag Anda, dan gunakan setidaknya angka dalam baris startup-nya This runner needs up to, yang sudah mencakup waktu tunggu. Dengan --defer-shutdown-max-min diatur, gunakan angka yang lebih besar di baris startup berikutnya, setelah Size the stop timeout to at least. Shutdown timing mencantumkan apa saja yang menambah angka-angka ini.
Jika stop timeout habis selama waktu tunggu, host Anda membunuh runner saat pekerjaan masih berjalan. Sesinya tidak mendapatkan hook post-session. Runner juga tidak melakukan deregistrasi, sehingga control plane dapat memerlukan beberapa menit, dan terkadang lebih lama, untuk mengantrekan kembali sesi tersebut.

Kirim pesan status sebelum restart

Sebelum restart yang akan mengganggu sesi, minta seorang Owner mengirim pesan status pada environment dari halaman admin Cloud environments. Di claude.ai/code, anggota melihat pesan tersebut di sesi mereka dalam environment itu. Minta Owner menetapkan waktu kedaluwarsa saat mengirim pesan, atau hapus pesan tersebut setelah runner kembali aktif.

Defer the drain past the first signal

Atur --defer-shutdown-max-min <n> jika Anda ingin runner yang sedang Anda restart terus melayani sesi yang dipegang selama hingga n menit, alih-alih mendrainnya pada sinyal pertama. Pada SIGTERM atau SIGINT pertama, runner berhenti menerima pekerjaan baru dan terus melayani sesi yang dipegang. Ini terus polling sehingga control plane tidak mengantrekan kembali sesi tersebut. Memerlukan Claude Code v2.1.238 atau lebih baru.

Apa yang terjadi pada sesi yang dipegang runner setelah sinyal pertama

Dalam dua tahap pertama yang mengikuti sinyal, runner melepaskan sesi, dan sesi yang dirilis dilanjutkan di runner segar ketika pengguna mereka mengirim pesan berikutnya. Menghitung dari sinyal pertama, runner bergerak melalui tiga tahap:
  • Untuk n menit pertama: runner melayani sesinya secara normal dan terus memberlakukan --startup-timeout-min dan --kill-session-after-min. Jika Anda juga menetapkan --release-idle-session-min, runner melepaskan sesi apa pun yang penggunanya telah idle selama itu; tanpanya, sesi idle tetap di runner.
  • Ketika n menit habis: runner melepaskan setiap sesi yang masih dipegang, idle atau tidak. Runner menunggu turn sesi mid-turn berakhir, dan hingga 60 detik lagi untuk background tasks turn, sebelum melepaskan sesi itu.
  • Ketika post-release grace habis: runner mendrainkan sesi apa pun yang masih dipegang, dan control plane mengantrekan kembali setiap sesi yang didrain ke runner lain segera. Post-release grace dimulai ketika n menit habis dan 75 detik pada default. Jika Anda menetapkan --drain-wait-sec di atas 60 detik, post-release grace adalah --drain-wait-sec ditambah 15 detik sebagai gantinya.
Di tahap mana pun, runner keluar 0 segera setelah tidak memegang sesi. Sinyal kedua memotong tahap pendek: runner mendrainkan segera, seperti yang dilakukan pada sinyal pertama tanpa --defer-shutdown-max-min. Setelah drain sedang berlangsung, sinyal berikutnya force-exits runner. Itu berlaku apakah sinyal kedua atau post-release grace yang habis memulai drain.

Ukuran stop timeout

Berikan stop timeout host Anda setidaknya jumlah dari tiga bagian: n menit yang Anda konfigurasi, post-release grace, dan drain yang dijelaskan Shutdown timing. Dengan pengaturan default, post-release grace adalah 75 detik dan drain memerlukan hingga 80 detik, jadi sediakan n menit ditambah 155 detik. Runner mencetak jumlah ini saat startup kapan pun --defer-shutdown-max-min diatur. Jika stop timeout habis sebelum runner selesai, sesi yang masih dipegangnya tidak mendapatkan hook post-session. Runner tidak melakukan deregistrasi, sehingga control plane dapat memerlukan beberapa menit, dan terkadang lebih lama, untuk mengantrekan kembali sesi tersebut. Jika Anda tidak dapat memberikan stop timeout jumlah itu, biarkan --defer-shutdown-max-min tidak diatur sehingga runner mendrainkan pada sinyal pertama sebagai gantinya.

Apa yang mencapai hook post-session yang sedang berjalan

Hook post-session dan setiap anak sesi Claude masing-masing berjalan dalam kelompok proses POSIX mereka sendiri, terpisah dari runner, jadi mekanisme stop mencapainya secara berbeda:
  • SIGTERM sementara runner sudah draining: force-exits runner segera, melewati apa pun yang tersisa dari drain. Tanpa --defer-shutdown-max-min, itu adalah SIGTERM kedua yang diterima runner. Tidak ada yang mengirim sinyal ke hook post-session yang sedang berjalan, jadi di host bare di mana proses init mengadopsi orphans, hook itu selesai sendiri, tetapi tanpa pengawasan: anggaran timeout-nya tidak lagi berlaku, dan penulisan ke pipa log tertutup dapat membunuhnya dengan SIGPIPE, jadi hook yang perlu bertahan dari forced exit di sana harus mengarahkan ulang output-nya sendiri ke file. Dalam resep container di halaman ini runner adalah PID 1 container dan keluarnya mengakhiri container, dan di bawah KillMode=control-group default systemd, kill cgroup-wide mencapai hook juga, seperti yang dijelaskan entri Cgroup-wide kills; di keduanya, perlakukan forced exit sebagai fatal untuk hook dan andalkan periode grace sebagai gantinya.
  • Sinyal process-group-wide, seperti kill -- -<pid> dalam skrip wrapper, shell job control, atau watchdog group-wide: mencapai runner dan subprocess mid-checkout-hook, yang tetap group-attached dengan sengaja, tetapi bukan hook post-session mid-run atau anak sesi.
  • Cgroup-wide kills, seperti KillMode=control-group default systemd atau SIGKILL yang dikirimkan Kubernetes ke seluruh container ketika terminationGracePeriodSeconds kedaluwarsa: mencapai segalanya, termasuk hook. Isolasi process-group tidak melindungi terhadap ini, itulah mengapa periode grace harus mencakup seluruh drain.
  • Timeout hook sendiri: ketika hook melebihi --post-session-hook-timeout-sec, runner mengirim SIGTERM ke seluruh kelompok proses hook, kemudian SIGKILL dua detik kemudian, jadi worker yang hook fork, seperti tar, rsync, atau git, berakhir dengan shell wrapper alih-alih bertahan sebagai orphan. Pengawasan runner berakhir setelah stdio hook ditutup: worker yang mengarahkan ulang output-nya sendiri ke file dan bertahan melampaui tahap SIGTERM melampaui jangkauan runner.
Ketika drain dimulai, dan lagi pada forced exit, runner mencatat berapa banyak hook post-session yang masih berjalan, jadi Anda dapat membedakan drain yang tenang dari yang mid-snapshot.

Jaga direktori dasar dan kapasitas identik di seluruh runner

Jika runner mati mid-sesi, server antri ulang sesi dan runner lain dalam lingkungan mengambilnya. Runner itu menurunkan jalur checkout dari --base-dir dan --capacity miliknya sendiri: --capacity 1 checkout langsung di bawah --base-dir, dan --capacity di atas 1 menggunakan worktree per-sesi. Ketika runner dalam lingkungan yang sama menggunakan nilai berbeda untuk flag apa pun, direktori kerja sesi yang dilanjutkan berubah, dan jalur absolut yang agen catat sebelumnya, dalam edit, panggilan alat, atau catatan miliknya sendiri, menunjuk ke lokasi yang tidak lagi ada. Gunakan --base-dir dan --capacity yang sama pada setiap runner dalam lingkungan, dan jangan gunakan nilai per-host seperti ID instans atau nama host. Berikan kedua flag secara eksplisit, seperti yang dilakukan resep Kubernetes dan Docker Compose, sehingga tidak ada nilai yang bergantung pada default. Direktori dasar default ke /workspace, dengan pengecualian baris referensi --base-dir catat. Runner memerlukan akses tulis ke sana. Pada startup, sebelum mendaftar, runner membuat direktori dan mengkonfirmasi dapat menulis ke sana, dan keluar dengan cannot create or write to base directory ketika tidak bisa. Runner yang dimulai sebagai root membuat /workspace default itu sendiri. Untuk runner non-root, buat direktori dan berikan kepemilikan pengguna runner sebelum memulai runner, atau arahkan --base-dir ke direktori yang pengguna itu sudah miliki.

Gunakan kembali checkout yang telah dipanaskan sebelumnya

Untuk repositori besar, klon dapat mendominasi startup sesi. Untuk melewati klon dingin, sediakan sendiri klon di jalur tempat runner menyimpan klonnya sendiri. Tanpa checkout hook, runner menyimpan satu klon kanonik per repositori di <base-dir>/<repo-owner>/<repo> dan menggunakannya kembali di seluruh sesi:
  • Pada --capacity 1: runner mengambil ref yang diminta, melepaskan HEAD, dan melakukan reset keras ke sana, yang hampir instan ketika hanya sedikit yang berubah.
  • Pada --capacity di atas satu: runner mengambil ke dalam klon tersebut, lalu melakukan checkout worktree terpisah darinya untuk setiap sesi. Klon yang telah dipanaskan sebelumnya menghemat unduhan tetapi tidak menghemat checkout.
Sediakan klon di dalam image atau pada volume persisten:
  • Klon dalam gambar: bangun klon ke gambar runner Anda di jalur itu. Setiap kontainer segar kemudian dimulai dengan klon hangat tanpa menggunakan kembali disk.
  • Klon pada volume persisten: pada runner yang Anda pre-lock ke akun satu pengguna dengan --lock-to-account, arahkan --base-dir ke volume persisten, jadi disk hanya pernah melayani akun itu. Runner yang pre-locked tidak pernah mengambil sesi saluran Claude Tag, jadi opsi ini tidak berlaku untuk runner yang melayani mereka.
Apa jalur penggunaan kembali lakukan dan tidak jamin:
  • Kedalaman klon: lakukan build klon tanpa --depth, dengan atau tanpa --single-branch. Runner tidak pernah meneruskan --depth saat mengambil ke dalam klon yang memiliki remote origin, bahkan jika Anda menetapkan CLAUDE_RUNNER_FETCH_DEPTH. Dengan klon penuh, setiap sesi hanya mengunduh commit yang belum dimiliki klon. Dengan klon shallow, sesi pada branch yang bercabang sebelum commit tertua klon akan mengunduh seluruh riwayat branch tersebut.
  • Perubahan terlacak di-reset, file tidak terlacak bertahan: pada --capacity 1, setiap sesi dimulai dari reset keras yang menghapus modifikasi terlacak dari sesi sebelumnya, tetapi runner tidak pernah menjalankan git clean, sehingga file tidak terlacak dari sesi-sesi sebelumnya milik pemilik terkunci tetap ada di pohon.
  • Direktori per-sesi juga bertahan: di samping checkout, runner membuat entri per-sesi di bawah <base-dir>/_sessions/ untuk setiap sesi yang dijalankannya. Direktori konfigurasi Claude sesi menyimpan salinan lokal transkrip percakapan. Di sebelahnya duduk file yang diunggah sesi, ketika sesi memiliki apa pun. Direktori sesi duduk di sana juga: itu menyimpan worktree per-sesi apa pun dan checkout hook checkout sementara sesi berjalan, dan itu menyimpan apa pun yang Claude tulis di dalamnya. Secara default runner meninggalkan ini di tempat ketika sesi berakhir, jadi pada disk yang melampaui proses runner mereka menumpuk. Setiap sesi berjalan sebagai pengguna runner sendiri, jadi sesi kemudian apa pun yang disk layani dapat membacanya. Jika Anda menyimpan --base-dir persisten, ukuran volume untuk pertumbuhan itu. Hal yang sama berlaku untuk setup apa pun yang memulai ulang runner pada filesystem yang sama, termasuk resep Docker Compose.
  • Dengan --remove-session-state, direktori per-sesi tidak bertahan: mulai runner dengan --remove-session-state untuk memilikinya menghapus direktori per-sesi setiap sesi saat sesi berakhir. Penghapusan adalah best-effort: direktori tetap ketika runner dibunuh sebelum cleanup-nya berjalan. Klon kanonik dan file yang ditulis sesi di tempat lain di host, seperti direktori sementara, tetap terlepas.
  • Dengan proxy git, reset menjadi checkout: dengan --use-anthropic-git-proxy, runner membersihkan .git/ klon sebelum setiap sesi. Runner tetap menyimpan object store dan shallow state, serta menghapus index. Tanpa index, setiap sesi dimulai dengan checkout working-tree penuh alih-alih reset yang hampir instan. Runner tetap mengambil ke dalam klon yang ada alih-alih mengklon ulang repositori. Pre-warm submodule tidak didukung di bawah proxy.
  • Dengan proxy git, pre-warm reftable kehilangan ref-nya: saat runner membersihkan .git/ sebelum setiap sesi, runner menyimpan .git/refs/ dan menghapus direktori .git/reftable/. Klon yang dipanaskan sebelumnya dalam format ref reftable milik git kehilangan ref-nya dengan cara itu, jadi lakukan pre-warm klon dalam format ref files milik git sebagai gantinya.
  • Klon panjang tidak memerlukan workaround: runner membatasi setiap operasi git dengan watchdog no-progress 120 detik dan hard cap 30 menit, bukan timeout flat, jadi klon dingin lambat yang terus melaporkan kemajuan selesai.

Pastikan bahwa runner menggunakan klon Anda

Untuk memastikan bahwa runner menggunakan klon Anda, mulai runner dengan --log-level debug dan mulai sesi pada repositori tersebut. Runner menulis Prefetched repo found at beserta jalur klon ke log. Jika runner justru menulis No prefetched repo, fresh init at ke log, runner tidak menemukan klon yang dapat digunakan di jalur pada baris tersebut. Periksa bahwa klon Anda berada di jalur tersebut, dimiliki oleh pengguna runner, dan memiliki remote bernama origin. Jika runner menemukan klon Anda tetapi sesi masih dimulai dengan lambat, periksa apakah klon tersebut shallow.

Sematkan versi

Secara default, proses anak setiap sesi menjalankan biner runner itu sendiri, dan runner mematikan auto-update di dalam sesi yang dihasilkannya. Dengan default tersebut, setiap sesi menjalankan versi yang Anda instal di host atau yang di-build ke dalam gambar. Update tingkat host berlaku waktu berikutnya runner dimulai. Pilih versi yang dijalankan sesi Anda dan kapan versi tersebut berubah:
  • Sebelum Anda menyematkan versi: periksa versi Claude Code yang diperlukan model untuk setiap model yang digunakan sesi Anda. Jika suatu model memerlukan versi yang lebih baru daripada yang dijalankan sesi Anda, server menolak permintaan untuk model tersebut dengan Claude Code does not support this model.
  • Untuk menyimpan armada pada satu versi: bangun gambar dengan versi yang disematkan, atau pada host telanjang instal versi spesifik dan nonaktifkan auto-update
  • Untuk upgrade armada tetap: baca entri changelog antara versi Anda dan versi yang akan Anda instal, kemudian instal versi yang lebih baru atau build ulang gambar dan mulai ulang runner
  • Untuk upgrade runner sesuai permintaan: baca entri changelog antara versi Anda dan versi yang akan Anda instal, kemudian ubah gambar yang dimulai oleh hook spawn-runner Anda. Setiap runner baru mendapatkan versi baru. Runner yang sudah berjalan, termasuk runner siaga yang dimulai oleh --min-idle, mempertahankan versinya hingga keluar. Jangan mulai ulang runner tersebut, karena perintah kerjanya hanya sekali pakai.
  • Jika sesi memulai biner yang berbeda: jika Anda menggunakan --exec-path atau hook command untuk memulai biner Claude Code selain biner runner itu sendiri, sesi menjalankan versi biner tersebut. Perbarui biner tersebut saat Anda memperbarui runner.
  • Plugin: marketplace plugin tidak auto-update juga; atur FORCE_AUTOUPDATE_PLUGINS=1 dalam lingkungan runner untuk membiarkan plugin auto-update sementara biner tetap disematkan

Skala armada

Orchestrator Anda memutuskan kapan menambah atau menghapus runner. Karena kunci one-owner-per-runner, jumlah replika minimum adalah jumlah pengguna dan agen Claude Tag yang Anda harapkan aktif bersamaan; --capacity mengontrol paralelisme dalam sesi satu pemilik, bukan di seluruh pemilik. Dua pendekatan penskalaan tersedia:
  • Armada tetap: jalankan set replika runner statis dan skala pada metrik Prometheus yang dilayani setiap runner
  • Runner on-demand: jalankan subperintah claude self-hosted-runner orchestrator, yang menanyakan Anthropic untuk sesi yang antri tanpa runner tersedia dan memanggil hook spawn-runner Anda untuk boot satu per sesi. Lihat On-demand runners.

Lepaskan sesi idle pada armada tetap

Jika sesi tetap mengantri pada armada tetap sementara setiap runner online, sesi idle mungkin penyebabnya. Secara default, sebuah sesi mempertahankan slotnya setelah gilirannya selesai, dan runner-nya tetap terkunci pada pemilik sesi tersebut. Jika tugas terjadwal cloud tim Anda memulai sesi baru pada setiap eksekusi, sesi idle-nya dapat memenuhi setiap slot. Untuk memeriksanya, baca claude_code_self_hosted_runner_session_idle_seconds di metrik Prometheus setiap runner. Setiap sesi yang dipegang runner memiliki seri tersendiri: 0 selama sesi sibuk, jika tidak, jumlah detik sejak sesi tersebut menjadi idle. Pilih waktu idle yang Anda izinkan: lebih lama dari jeda yang diambil orang di tengah tugas, dan cukup singkat sehingga setiap eksekusi dilepaskan sebelum eksekusi berikutnya dari tugas terjadwal dimulai. Bandingkan seri tersebut dengan waktu itu.
  • Seri di atas waktu tersebut, seperti 1800 untuk 30 menit: sesi idle memegang slot tersebut, jadi atur --release-idle-session-min
  • Setiap seri di bawahnya: tidak ada sesi yang idle selama itu. Tambahkan runner, atau atur --kill-session-after-min untuk sesi yang tidak pernah menjadi idle.
  • Runner tanpa seri: tidak ada sesi yang memegangnya. Lihat Sessions stay queued di bawah Pemecahan masalah.
  • Runner yang metriknya tidak merespons: prosesnya mungkin telah keluar. Lihat An environment that looks healthy di bawah When the runner exits.
Untuk melepaskan sesi idle, mulai setiap runner dengan --release-idle-session-min dan waktu tersebut dalam menit, seperti --release-idle-session-min 30. Runner kemudian melepaskan setiap sesi yang tetap idle selama itu, baik yang dimulai oleh tugas terjadwal maupun oleh seseorang.

Masalah dan batasan yang diketahui

Berikut adalah batasan dalam rilis ini, dengan workaround di mana ada.

Lalu lintas konektor meninggalkan jaringan Anda

Anthropic memanggil alat konektor dari infrastruktur miliknya sendiri daripada dari runner Anda. Alat konektor adalah konektor claude.ai, seperti GitHub, Slack, dan Linear. Ketika Claude menggunakan konektor dalam sesi yang di-host sendiri, lalu lintas itu melewati api.anthropic.com daripada berasal dari dalam batas jaringan Anda. Untuk menjaga konektor keluar dari sesi yang di-host sendiri, saring dengan pengaturan kebijakan allowedMcpServers dan deniedMcpServers. Claude Code menerapkan pengaturan ini ke konektor yang dikirimkan Anthropic serta ke server yang Anda seed dari host runner dan server yang ditambahkan pengguna, jadi jika Anda terapkan allowlist untuk server lain, Claude Code memblokir konektor yang dikirimkan juga. Untuk menjaga konektor tersedia bersama allowlist berbasis URL, tambahkan entri yang cocok dengan jalur proxy Anthropic untuk konektor yang dikirimkan:
  • https://api.anthropic.com/v2/ccr-sessions/*
  • https://api.anthropic.com/v1/code/sessions/*
  • https://api.anthropic.com/v1/code/mcp/*
Jika lalu lintas alat harus tetap di dalam jaringan, jalankan alat setara sebagai server MCP lokal pada gambar runner. Lihat MCP servers.

Beberapa sesi tidak dihitung sebagai menganggur

Sesi yang memegang tugas latar belakang yang tidak pernah selesai tidak dihitung sebagai menganggur, jadi --release-idle-session-min tidak akan melepaskan slot sesi itu. Sesi yang menunggu persetujuan yang diminta dari dalam panggilan alat yang berjalan juga tidak dihitung sebagai menganggur. Selalu atur --kill-session-after-min bersama sebagai backstop keras sehingga tidak ada sesi yang dapat memegang slot tanpa batas. --kill-session-after-min adalah backstop untuk sesi yang melarikan diri. Pada runner pada v2.1.260 atau lebih baru, sesi yang mencapai batas tidak dihentikan begitu saja. Runner memberikan jendela grace, 15 menit secara default, yang dapat Anda ubah dengan SELF_HOSTED_RUNNER_MAX_LIFETIME_GRACE_MS:
  • Jika sesi menunggu penggunanya, runner melepaskannya. Jika putarannya telah berakhir dan hanya memegang tugas latar belakang, runner menunggu hingga 60 detik untuk tugas-tugas itu selesai dan kemudian melepaskannya. Sesi dilanjutkan ketika penggunanya mengirim pesan berikutnya.
  • Jika putaran masih berjalan, runner menunggu putaran selesai, atau untuk sesi berikutnya menunggu penggunanya, dan kemudian melepaskannya.
  • Jika sesi masih di runner ketika jendela grace berakhir, runner menghentikannya, dan pekerjaan putaran yang berjalan hilang. Putaran menunggu persetujuan yang diminta dari dalam panggilan alat yang berjalan adalah satu cara sesi melampaui jendela.
Sesi yang dilepaskan dilanjutkan dari klon segar, jadi pekerjaan yang tidak didorong hilang bagaimanapun; lihat Resumed sessions lose unpushed work. Sebelum v2.1.260, runner menghentikan setiap sesi pada batas, setelah menunggu paling banyak jendela grace untuk putaran yang berjalan selesai. Atur flag di atas sesi terpanjang yang diharapkan, seperti --kill-session-after-min 480 untuk 8 jam. Untuk membebaskan slot dari percakapan yang menjadi menganggur, gunakan --release-idle-session-min.

Batasan tambahan

  • Sesi yang dilanjutkan kehilangan pekerjaan yang belum di-push: runner segar mengklon repositori lagi dari branch awalnya, jadi pekerjaan yang belum di-push oleh sesi hilang.
    • Untuk mempertahankan pekerjaan yang sudah di-commit: atur --push-outcome-on-release pada setiap runner di lingkungan tersebut, karena runner tanpa flag ini melanjutkan sesi dari branch awalnya. Runner dengan flag ini melakukan push best-effort atas branch hasil sesi sebelum melepaskannya, dan sesi yang dilanjutkan dimulai dari commit tersebut. Push tersebut menggunakan kredensial git milik host runner sendiri, termasuk pada runner yang menggunakan git yang dikelola Anthropic.
    • Dengan hook checkout: repositori yang di-checkout melalui hook siklus hidup checkout tidak di-push. Buat snapshot repositori tersebut dari hook post-session sebagai gantinya.
    • Sebelum mengaktifkan flag ini: batasi siapa yang dapat melakukan push ke ref claude/* pada remote sumber. Saat dilanjutkan, runner mengambil branch yang sebelumnya di-push tanpa memverifikasi siapa yang melakukan push-nya.
    • Perubahan yang belum di-commit tetap hilang: untuk meminta Claude melakukan commit dan push ketika selesai merespons, lihat Prompt sessions to push their work
  • Perintah yang terputus karena runner yang hilang dapat berjalan lagi: ketika sesi dilanjutkan di runner lain, Claude melihat panggilan tool yang terinterupsi dengan hasil yang menyatakan bahwa hasil akhirnya tidak diketahui.
  • Repositori yang ditambahkan di tengah sesi dapat gagal diklon: Claude mengklonnya dengan git clone melalui HTTPS. Pada runner tanpa --use-anthropic-git-proxy, klon gagal dengan kesalahan autentikasi git jika tidak ada apa pun di host yang dapat membaca repositori tersebut. Jika memungkinkan, pilih setiap repositori yang dibutuhkan sesi ketika Anda membuatnya.
  • Beberapa konektor tidak muncul dalam sesi yang di-host sendiri: konektor yang belum Anda hubungkan dalam pengaturan claude.ai tidak terdaftar dalam sesi yang di-host sendiri, dan sesi tidak akan meminta Anda untuk menghubungkannya. Hubungkan dalam Pengaturan terlebih dahulu, kemudian mulai sesi segar. Menambahkan konektor ke sesi yang sudah berjalan juga tidak membuat alat-alatnya tersedia untuk Claude; mulai sesi segar untuk mengambil konektor yang baru ditambahkan.
  • Ketika seseorang mengarsipkan atau menghapus sesi, atau melepaskan runner-nya dari menu sesi: jangan mengandalkan push --push-outcome-on-release. Untuk menyimpan commit dalam kasus tersebut, push HEAD ke branch penyelamat dari hook post-session. Jika Anda memulai dari contoh di sana, ubah agar contoh tersebut melakukan push bahkan ketika tidak ada perubahan yang belum di-commit, karena contoh tersebut hanya melakukan push setelah commit snapshot.

Laporkan masalah

Untuk masalah dengan lingkungan yang di-host sendiri, hubungi tim akun Anthropic Anda.

Pemecahan masalah

Untuk diagnosis terpandu, jalankan subperintah doctor pada host runner. Subperintah doctor memulai sesi Claude Code interaktif dengan log dan status runner terlampir. Masuk terlebih dahulu dengan claude auth login pada host tersebut agar sesi dapat melakukan kueri terhadap lingkungan Anda, runner-nya, dan sesi yang sedang dalam antrean. Tanpa proses masuk tersebut, misalnya ketika host melakukan autentikasi dengan kunci API, sesi hanya dapat mengakses endpoint kesehatan lokal, metrik, dan log runner, dan sesi hanya membaca log tersebut jika Anda memulai runner dengan --log-file.
Masalah umum:
  • Runner tidak muncul di lingkungan: pastikan host dapat menjangkau api.anthropic.com melalui HTTPS, secret lingkungan masih yang terkini, dan jam host berselisih tidak lebih dari lima menit dari waktu sebenarnya; selisih yang lebih besar menyebabkan autentikasi gagal. Runner mencatat [runner:fatal] beserta alasan penolakan ke log saat autentikasi gagal.
  • Runner keluar saat startup dengan cannot create or write to base directory: runner tidak dapat membuat atau menulis ke --base-dir, yang secara default adalah /workspace. Perbaiki kepemilikan direktori tersebut atau arahkan --base-dir ke path yang dapat ditulisi, seperti yang dijelaskan di Jaga agar direktori dasar dan kapasitas identik di seluruh runner. Jika runner justru mencatat [runner:fatal] yang menyatakan bahwa pemeriksaan direktori dasar mengalami timeout, direktori tersebut berada pada mount NFS atau CSI yang macet. Periksa kesehatan mount, bukan permission. Runner mencetak kedua kegagalan startup ini ke stderr sebelum membuka --log-file, jadi cari keduanya di terminal atau log container platform Anda, bukan di file log. Sebelum v2.1.225, runner tidak memeriksa direktori dasar saat startup, dan kesalahan konfigurasi ini justru menggagalkan sesi setelah sesi diambil.
  • Runner keluar saat startup dengan RegisterRunner failed: dan kesalahan sertifikat TLS: kesalahannya dapat berupa self signed certificate in certificate chain, misalnya. Runner tidak memercayai otoritas sertifikat (CA) di balik sertifikat yang diterimanya, seperti yang terjadi di balik proxy yang melakukan inspeksi TLS. Atur NODE_EXTRA_CA_CERTS di lingkungan runner ke file PEM yang berisi root CA proxy tersebut. Anda tidak perlu mengaturnya lagi untuk sesi, karena sesi mewarisinya. Git tidak membacanya: untuk clone melalui proxy tersebut, atur juga GIT_SSL_CAINFO.
  • Skrip start Anda mencetak kesalahan penulisan yang berisi Resource temporarily unavailable lalu keluar: skrip Anda berbagi stdout atau stderr dengan proses claude self-hosted-runner atau orkestrator yang dimulainya, dan proses tersebut telah mengalihkan pipe atau socket bersama itu ke mode non-blocking. Ketika pipe penuh, penulisan dari skrip Anda gagal dengan kesalahan sistem operasi ini alih-alih menunggu, dan di bawah set -e skrip tersebut keluar. Untuk menghentikan kesalahan ini, kirim output runner atau orkestrator ke file yang dapat dibuat oleh pengguna skrip Anda. Tambahkan >> "$HOME/claude-runner.log" 2>&1 ke perintah yang memulainya, sebelum & yang menjalankannya di latar belakang:
    Output skrip Anda sendiri tetap menuju ke tempat sebelumnya, sedangkan apa yang ditulis runner ke stdout dan stderr, termasuk kesalahan startup-nya, menuju ke file tersebut. Gunakan pengalihan shell ini, bukan --log-file saja, yang mencerminkan log ke sebuah file sementara runner tetap menulis ke stdout dan stderr. Jika Anda sudah meneruskan --log-file, pertahankan juga, karena pengalihan tersebut tidak mengubah apa yang diterima file itu.
  • Orkestrator mencatat poll failed: dengan kesalahan sertifikat TLS dan terus mencoba ulang: orkestrator tidak memercayai CA di balik sertifikat yang diterimanya, seperti yang terjadi di balik proxy yang melakukan inspeksi TLS. Atur NODE_EXTRA_CA_CERTS di lingkungan orkestrator ke file PEM yang berisi root CA proxy tersebut. Atur juga untuk runner yang dimulai oleh hook spawn-runner Anda. Misalnya, sebuah baris dapat diakhiri dengan poll failed: self signed certificate in certificate chain — retrying in 1s, dengan kata-kata dari pustaka TLS di antara titik dua dan tanda pisah. Untuk memastikan perbaikannya berhasil, periksa bahwa connected bernilai true di body /healthz orkestrator.
  • Sesi tetap dalam antrean: setiap runner yang online mungkin terkunci ke pemilik yang berbeda. Periksa metrik claude_code_self_hosted_runner_locked_account setiap runner atau field locked_account pada baris log [runner:health]-nya untuk melihat siapa yang memegangnya. Keduanya hanya menampilkan email pemilik setelah runner diberi token sesi yang membawa klaim act.email, yang tidak pernah dimiliki oleh sesi agent Claude Tag. Tanpa klaim tersebut, runner tidak memancarkan deret locked_account dan mencatat locked_account=yes, yang memberi tahu Anda bahwa runner terkunci tetapi tidak ke pemilik mana. Tambahkan replika, atau tunggu runner yang ada selesai melakukan drain dan dimulai ulang. Jika lingkungan menggunakan runner on-demand, periksa orkestrator sebagai gantinya; lihat Runner on-demand.
  • Sesi gagal segera setelah diambil: buka sesi di claude.ai/code untuk melihat kesalahannya. Jika kesalahan menunjukkan bahwa git tidak dapat melakukan autentikasi, periksa kredensial git runner. Pada runner yang dimulai dengan --use-anthropic-git-proxy, lihat Ketika sesi gagal dimulai pada runner dengan git proxy. Direktori dasar yang tidak dapat ditulisi menghentikan runner saat startup alih-alih menggagalkan sesi. Lihat entri Runner keluar saat startup dengan cannot create or write to base directory dalam daftar ini.
  • Sesi diambil, tetapi Claude tidak pernah menjawab pesan pertamanya: jika runner Anda menjangkau api.anthropic.com melalui proxy, konfigurasikan proxy tersebut agar meneruskan respons /worker/events/stream sesi saat respons tersebut tiba. Menaikkan timeout runner tidak membantu. Untuk memastikan penyebabnya di log runner, lihat Sesi diambil, tetapi Claude tidak pernah menjawab pesan pertamanya.
  • Sesi gagal dimulai pada runner yang mengatur --use-anthropic-git-proxy: cari access denied by the git proxy di log runner, atau kesalahan git yang menyebutkan alamat api.anthropic.com yang berisi /git_proxy/. Untuk mengetahui apakah Anthropic melayani sesi tersebut dan memperbaiki penyebabnya, lihat Ketika sesi gagal dimulai pada runner dengan git proxy.
  • Sesi tidak dapat menjangkau jaringan melalui proxy egress yang melakukan autentikasi: ketika sumber yang Anda atur dengan --proxy-authorization-command atau --proxy-authorization-file gagal, mengalami timeout setelah 30 detik, atau menghasilkan nilai kosong, runner menjawab koneksi tersebut dengan 502 Bad Gateway dan mencatat alasannya ke log. Runner menyamarkan stderr perintah tersebut di log itu dan tidak pernah mencatat nilai header ke log. Dengan --proxy-authorization-command, jalankan sendiri perintah tersebut di host untuk memastikan perintah itu mencetak seluruh nilai header ke stdout. Jika runner justru keluar saat startup dengan could not start the proxy-authorization listener, runner tidak dapat membuka listener loopback-nya.
  • Runner mencatat baris Poll failed yang berisi rejecting the malformed poll response: runner menerima respons work-poll yang body-nya bukan JSON yang diharapkan oleh antrean. Salah satu penyebabnya adalah proxy yang mencegat atau captive portal yang menjawab dengan halamannya sendiri. Jika runner terhubung melalui proxy, konfigurasikan proxy agar meneruskan respons dari api.anthropic.com tanpa diubah. Runner menolak respons yang rusak tersebut, menghitungnya di bawah jenis transport dari metrik claude_code_self_hosted_runner_poll_errors_total, dan mencoba ulang sesuai jadwal poll-gagal yang dijelaskan di Siklus hidup sesi. Runner tetap melayani sesi aktifnya. Sebelum v2.1.246, runner membaca respons semacam itu sebagai antrean kerja kosong, yang dapat mengakhiri sesi aktifnya atau membuatnya keluar.
  • Sesi gagal dengan no longer exists on the remote atau couldn't find remote ref: runner membaca couldn't find remote ref dari git sebagai branch yang telah dihapus. Branch tersebut mungkin masih ada. Cari branch tersebut di host git Anda, dengan nama yang persis sama seperti di pesan, lalu periksa setiap penyebab yang sesuai:
    • Branch sudah tidak ada: pulihkan branch tersebut, seperti yang diminta oleh pesan.
    • Branch ada dan Anda tidak mengelola runner: kirimkan pesan lengkapnya kepada administrator runner dan beri tahu mereka bahwa branch tersebut ada.
    • Branch ada dan runner memiliki hook checkout: perintah git di hook Anda dapat mencetak couldn't find remote ref ke stderr sebelum hook keluar dengan kode bukan nol. Temukan perintah tersebut, lalu perbaiki ref yang dimintanya atau remote tempat perintah itu melakukan fetch. Runner meneruskan revisi yang diminta sesi ke hook Anda sebagai CLAUDE_RUNNER_REPO_REF.
    • Branch ada dan runner tidak memiliki hook checkout: runner melakukan fetch branch tersebut sendiri. Jika --git-host-rewrite berlaku untuk repositori tersebut, pastikan host tujuan penulisan ulangnya memiliki branch dengan nama yang sama, dan push branch tersebut ke sana jika belum ada.
    • Branch ada dan runner lebih lama dari v2.1.301: tingkatkan runner seperti yang dijelaskan di Sematkan versi, sehingga kegagalan yang berbeda menampilkan kesalahannya sendiri. Sebelum v2.1.301, kegagalan lain yang memiliki couldn't find remote ref dalam output kesalahannya juga dilaporkan sebagai branch yang dihapus.
    Setelah runner ditingkatkan atau penyebabnya diperbaiki, coba ulang sesi tersebut atau mulai sesi baru. Jika tidak ada pemeriksaan ini yang menemukan penyebabnya, laporkan masalah. Untuk sumber tempat sesi mendorong hasil, branch yang dihapus menggagalkan sesi. Untuk sumber git yang hanya dibaca oleh sesi, runner melewati sumber tersebut dan melanjutkan dengan sumber lainnya. Runner menggagalkan sesi ketika melewati sumber akan membuat sesi tidak memiliki repositori sama sekali. Sebelum v2.1.228, sesi semacam itu dimulai di direktori kosong.
  • Claude Tag terkadang tidak memposting balasannya di Slack: pengingat balasan adalah hook yang disediakan oleh control plane. Pastikan runner adalah Claude Code v2.1.229 atau yang lebih baru dengan claude --version, karena runner yang lebih lama mengabaikan hook yang disediakan; pastikan python3 --version berhasil di dalam image runner, karena hook tersebut menjalankan python3; dan pastikan tidak ada file pengaturan yang mematikan hook, baik disableAllHooks di managed-settings.json, ~/.claude/settings.json milik pengguna runner, atau .claude/settings.json atau .claude/settings.local.json milik repositori, maupun allowManagedHooksOnly atau strictPluginOnlyCustomization yang mencakup hook di pengaturan terkelola.
  • Sesi dimulai tanpa salah satu repositorinya: pada runner tanpa hook checkout, host git dapat menolak pemeriksaan akses runner untuk repositori yang hanya dibaca oleh sesi. Runner kemudian melewati repositori tersebut, mencatat baris [runner:warn] could not access context source yang menyebutkan penolakan tersebut, dan memulai sesi dengan repositori lainnya. Runner hanya melewati penolakan yang jelas: host menjawab bahwa repositori tidak ditemukan, git tidak menemukan kredensial untuk host tersebut, atau autentikasi gagal. Kegagalan jaringan, timeout, atau HTTP 403 tetap menggagalkan dimulainya sesi, begitu pula penolakan untuk repositori tempat sesi mendorong hasil. Runner tetap menggagalkan sesi yang akan tidak memiliki repositori sama sekali jika dilewati. Dengan --use-anthropic-git-proxy, runner hanya melewati repositori yang ditolak oleh git proxy itu sendiri. Pemeriksaan akses dijalankan lagi setiap kali sesi dimulai pada runner, sehingga begitu identitas git runner memiliki akses baca, proses mulai berikutnya akan meng-clone repositori tersebut. Sebelum v2.1.274, setiap penolakan ini menggagalkan dimulainya sesi.
  • Sesi gagal dimulai dengan This runner couldn't read: runner meminta repositori dari host git dengan kredensial git-nya dan mendapat jawaban tidak ditemukan. Repositori tersebut tidak ada, atau kredensial tersebut tidak dapat menjangkau repositori itu.
    • Jika Anda mengelola runner: berikan akses baca ke repositori tersebut kepada kredensial git runner, lalu mulai sesi baru.
    • Jika Anda yang memulai sesi: jika repositori tidak ada, mulai sesi baru dengan repositori yang benar. Jika runner tidak dapat menjangkau repositori tersebut, minta administrator runner untuk memberikan akses, lalu mulai sesi baru.
  • Sesi membutuhkan waktu beberapa menit untuk dimulai atau dilanjutkan: salah satu penyebabnya adalah clone baru. Pada fleet yang memulai setiap runner pada disk kosong, tanpa hook checkout, runner meng-clone ulang repositori sesi dari awal sebelum memulai Claude Code. Sesi yang dilanjutkan pada disk kosong menunggu clone yang sama lagi. Untuk melewati clone baru, sediakan checkout yang sudah dipanaskan sebelumnya. Jika Anda sudah menyediakannya, pastikan runner menggunakannya. Ketika runner membuat clone sendiri dan keluar setelah satu sesi, turunkan CLAUDE_RUNNER_FETCH_DEPTH dari default-nya sebanyak 50 commit untuk mengambil lebih sedikit riwayat. Jika Anda menggunakan hook, hook tersebut berjalan sebagai pengganti clone runner, jadi periksa apa yang dilakukan hook Anda. Pantau metrik claude_code_self_hosted_runner_session_init_duration_seconds untuk melihat berapa lama proses mulai berlangsung.
  • Giliran gagal dengan 401: ketika sebuah giliran berakhir dengan 401 atau 403 dari Anthropic API, runner mengambil CLAUDE_CODE_OAUTH_TOKEN baru dari Anthropic dan meneruskannya ke sesi. Giliran yang gagal tidak dicoba ulang. Token ini berumur pendek, dan runner merotasinya melalui stdin sesi. Ketika pengambilan gagal, runner mencatat baris inference_token refresh failed yang menyebutkan kapan runner akan mencoba ulang, dan runner terus mencoba ulang selama sesi berjalan. Jika setiap panggilan mulai gagal sekitar 30 menit setelah sesi dimulai, kemungkinan besar sebuah skrip wrapper telah memutus stdin sesi, sehingga rotasi token tidak dapat menjangkaunya; lihat Biarkan stdin dan file descriptor 3 tetap terhubung. Sebelum v2.1.274, runner berhenti mencoba ulang pengambilan yang gagal setelah beberapa percobaan dan menunggu pengambilan terjadwal berikutnya. Giliran yang gagal tidak memicu pengambilan, sehingga setiap giliran gagal dengan 401 hingga pengambilan terjadwal berikutnya.
  • Giliran gagal di claude.ai/code dengan This model needs a newer version of Claude Code: versi Claude Code yang digunakan runner Anda untuk memulai sesi lebih lama daripada yang dibutuhkan model sesi tersebut, sehingga API menolak permintaan tersebut. Tingkatkan runner ke versi yang diminta oleh pesan tersebut, atau yang lebih baru, seperti yang dijelaskan di Sematkan versi. Sampai saat itu, pengguna dapat memilih model lain di dalam sesi.
  • Pod dihentikan di tengah drain: naikkan terminationGracePeriodSeconds setidaknya ke nilai yang dicatat runner saat startup. Lihat Waktu shutdown.
Setelah logging diinisialisasi, runner menulis log siklus hidupnya, termasuk baris [runner:fatal], ke stdout, dan output debug ke stderr, semuanya sebagai baris teks biasa, bukan JSON. Kegagalan direktori dasar yang dijelaskan dalam entri pemecahan masalah di atas dicetak ke stderr sebelum titik tersebut. Tangkap kedua stream dengan --log-file, yang juga memungkinkan self-hosted-runner doctor mengikutinya (tail), atau dengan pengumpulan log platform Anda. Proses anak setiap sesi menulis log debug terpisah. Saat terjadi kegagalan, runner menampilkan bagian akhir log tersebut bersama sesi di claude.ai/code. Kecuali Anda memulai runner dengan --remove-session-state, runner juga menyimpan log sesi yang gagal di disk dan mencetak path-nya di log runner.

Ketika runner keluar

Jangan memulai ulang runner on-demand, karena work order-nya hanya sekali pakai. Runner yang keluar tepat setelah dimulai memerlukan penanganan yang berbeda dari runner yang keluar karena alasan lain.
  • Keluar normal: runner telah menyelesaikan sesinya dan melakukan drain, mencapai waktu pensiunnya, atau diperintahkan untuk berhenti. Mulai ulang runner agar lingkungan memiliki kapasitas lagi. Siklus hidup runner menjelaskan jenis keluar ini.
  • Gagal dimulai: runner tidak dapat dimulai dengan konfigurasi atau host yang diberikan kepadanya, sehingga runner keluar beberapa detik setelah dimulai, dan runner keluar dengan cara yang sama setiap kali Anda memulainya ulang. Memulainya ulang lebih cepat tidak membantu. Seseorang perlu membaca outputnya dan memperbaiki penyebabnya.
  • Kehilangan kontak: runner yang tidak dapat menjangkau Anthropic lebih lama dari lease-nya, misalnya saat host-nya dalam mode tidur, dapat dihapus dari lingkungan. Ketika runner yang telah dihapus terhubung kembali, runner tersebut keluar. Log-nya dapat menampilkan baris [runner:fatal] yang berisi runner record gone server-side atau, setelah gangguan yang lebih lama, poll auth failed. Runner tidak mendaftar ulang dengan sendirinya, jadi mulai ulang runner tersebut.
Konfigurasikan supervisor Anda agar memulai ulang runner setiap kali runner keluar, menunggu lebih lama di antara proses mulai ulang ketika runner terus keluar tepat setelah dimulai, dan memberi tahu seseorang ketika hal itu terus terjadi. Untuk produksi, minta supervisor Anda memulai ulang runner pada disk yang baru, di container atau VM baru, seperti yang direkomendasikan oleh Perkuat deployment Anda.

Mengenali kegagalan dimulai

Ketika runner tidak dapat dimulai, runner mencetak baris yang menyebutkan alasannya, lalu keluar. Untuk sebagian besar penyebab, baris tersebut berisi [runner:fatal]. Untuk beberapa penyebab, baris tersebut justru diawali dengan error:, termasuk ketika runner tidak dapat mengurai flag-nya, tidak dapat membaca secret lingkungan, atau tidak dapat membuat atau menulis ke direktori dasar. Baris berikutnya kemudian merujuk ke --help. Sebagian besar baris log diawali dengan timestamp dan [self-hosted-runner], yang dihilangkan dalam contoh di bawah. Misalnya, runner yang dimulai dengan Anthropic git proxy dan kapasitas di atas satu akan mencetak baris seperti ini:
Cari baris tersebut di standard output dan standard error runner, di log container platform Anda, atau di file yang Anda atur dengan --log-file. Runner mencetak baris error: sebelum membuka file log, jadi cari baris tersebut di terminal atau log container Anda, seperti yang dicatat di Pemecahan masalah. Hal-hal berikut juga membantu ketika Anda membaca kegagalan dimulai:
  • Tidak ada baris sama sekali: runner yang dihentikan oleh host tidak mencetak keduanya. Jika output berakhir tanpa baris [runner:fatal] dan tanpa baris error:, periksa apakah host atau orkestrator Anda menghentikan proses tersebut, misalnya karena melebihi batas memori.
  • Exit code: runner tidak mencadangkan exit code khusus untuk kesalahan yang berulang pada setiap proses mulai. Runner keluar dengan kode yang sama untuk kesalahan konfigurasi, seperti kombinasi flag yang tidak didukung, dan untuk kegagalan yang dapat hilang dengan sendirinya, seperti API yang tetap tidak dapat dijangkau selama retry yang dilakukan runner sendiri. Dasarkan keputusan untuk menunggu lebih lama pada seberapa cepat runner keluar, dan baca output runner untuk mengetahui alasannya.
  • Lingkungan yang tampak sehat: beberapa langkah startup berjalan setelah runner mendaftar ke lingkungan Anda, seperti --configure-git dan penyiapan kredensial Anthropic git proxy. Jika salah satu langkah tersebut gagal, lingkungan dapat terus mencantumkan runner tersebut selama beberapa menit setelah prosesnya keluar, dan halaman Cloud environments dapat menampilkan Healthy meskipun tidak ada runner yang mengambil pekerjaan. Jika sesi tetap dalam antrean di lingkungan yang tampak sehat, periksa apakah supervisor Anda sedang memulai ulang runner.

Memulai ulang dengan waktu tunggu yang bertambah

Cara Anda mendapatkan waktu tunggu yang bertambah bergantung pada supervisor Anda.
  • Kubernetes: Deployment di halaman ini tidak memerlukan perubahan. Setelah container keluar, kubelet secara default menunggu sebelum memulai ulang container, dan waktu tunggu bertambah pada setiap proses mulai ulang hingga batas atas. Waktu tunggu kembali dari awal setelah container berjalan selama beberapa waktu tanpa keluar. Kubelet menerapkan waktu tunggu yang sama setelah keluar normal ketika container hanya berjalan sebentar. Oleh karena itu, runner yang sering melakukan drain juga dapat menampilkan status CrashLoopBackOff, jadi baca outputnya sebelum Anda menyimpulkan bahwa runner tidak dapat dimulai. Perintah di bawah membaca output dari proses terakhir pada satu pod dari Deployment tersebut:
    Ketika proses terakhir merupakan kegagalan dimulai, baris [runner:fatal] atau error: berada di antara baris-baris terakhir output. Untuk membaca proses terakhir pod lain, sebutkan pod tersebut sebagai pengganti deploy/claude-runner.
  • Docker dan Docker Compose: resep Compose di halaman ini tidak memerlukan perubahan. Dengan restart: always, Docker menunggu lebih lama sebelum setiap proses mulai ulang container yang terus keluar, hingga batas atas. Ganti <container> dengan nama container pada perintah di bawah, yang membaca berapa kali Docker telah memulai ulang container tersebut:
    Perintah tersebut mencetak sebuah angka. Angka yang terus bertambah berarti Docker terus memulai ulang runner.
  • Unit systemd: secara default systemd menunggu RestartSec yang sama sebelum setiap proses mulai ulang dan tidak memperpanjangnya, sehingga unit dengan Restart=always memulai ulang runner yang tidak dapat dimulai pada interval yang sama setiap kali. Ketika proses mulai terjadi cukup cepat hingga mencapai rate limit mulai unit tersebut, yaitu lima kali mulai dalam 10 detik secara default, systemd berhenti memulai ulang unit tersebut. Unit tetap berhenti hingga seseorang memulainya lagi, yang diizinkan systemd setelah interval rate limit berlalu atau setelah systemctl reset-failed. Karena RestartSec berlaku untuk setiap proses mulai ulang, nilai yang lebih besar juga menunda proses mulai ulang setelah keluar normal. Pilih nilai yang menyeimbangkan keduanya, dan buat peringatan berdasarkan jumlah mulai ulang unit tersebut.
  • Loop shell atau supervisor Anda sendiri: terapkan sendiri aturan yang sama. Mulailah dengan waktu tunggu lima detik. Setelah setiap proses yang berakhir dalam satu menit, gandakan waktu tunggu untuk proses mulai ulang berikutnya, hingga lima menit. Setelah proses yang berlangsung satu menit atau lebih, kembali ke lima detik.

Memeriksa mengapa runner terus keluar

Ketika runner telah keluar tepat setelah dimulai beberapa kali berturut-turut, berhentilah dan periksa hal-hal berikut sebelum memulainya ulang lagi.
  • Baris [runner:fatal] atau error: terakhir: baris ini menyebutkan mengapa runner berhenti. Pemecahan masalah mencantumkan penyebab umumnya.
  • Kombinasi flag: Anthropic git proxy memerlukan --capacity 1. Resep di halaman ini menggunakan kapasitas yang lebih tinggi, jadi turunkan kapasitas tersebut ketika Anda menambahkan proxy ke salah satunya.
  • Apa yang dapat dijangkau oleh lingkungan layanan: jika runner dapat dimulai secara manual tetapi gagal di bawah supervisor Anda, bandingkan pengguna, direktori home, PATH, dan batas memori. --configure-git dan Anthropic git proxy memerlukan git di PATH dan ~/.gitconfig yang dapat ditulisi.
  • Secret lingkungan: jika Anda telah mencabut secret tersebut atau salah mengetiknya, runner mencetak baris yang berisi RegisterRunner auth failed.
  • Tab Activity lingkungan: buka lingkungan dan pilih Activity. Jika runner baru terus muncul di sana dan tidak ada yang mengambil pekerjaan, supervisor Anda sedang memulai ulang runner.
Untuk diagnosis terpandu pada host runner, jalankan subperintah doctor.

Sesi diambil, tetapi Claude tidak pernah menjawab pesan pertamanya

Jika runner mengambil sesi tetapi Claude tidak pernah menjawab pesan pertama, dan runner Anda menjangkau api.anthropic.com melalui proxy, proxy tersebut mungkin penyebabnya. Anthropic mengirimkan pesan-pesan ke sesi melalui satu respons streaming yang tetap terbuka. Jika proxy Anda melakukan buffering terhadapnya, atau mengakhirinya sebelum meneruskan apa pun, pesan pertama tidak pernah tiba. Permintaan lain dari sesi tetap berhasil. Untuk memperbaikinya, ubah cara proxy menangani permintaan ini:
  • Jangan lakukan buffering terhadap respons: teruskan respons saat tiba. Content type-nya adalah text/event-stream.
  • Biarkan respons tetap terbuka: respons dapat tetap terbuka hingga satu jam. Jika proxy memiliki idle timeout, atur jauh di atas 15 detik, karena Anthropic secara default mengirimkan keep-alive setidaknya sesering itu.
Kemudian mulai sesi baru dan periksa apakah Claude menjawab. Menaikkan timeout runner tidak membantu: Anda hanya menunggu lebih lama sebelum runner menghentikan sesi.

Memastikan penyebabnya di log runner

Langkah-langkah ini ditujukan untuk runner pada Claude Code v2.1.287 atau yang lebih baru, dengan --log-level info default. Runner yang lebih lama mencatat baris-baris ini lebih lambat, atau tidak sama sekali.
  1. Tunggu hingga --startup-timeout-min berlalu, 15 menit secara default. Runner kemudian menghentikan sesi dan mencatat baris yang berisi no child output for dan diakhiri dengan — releasing.
  2. Cari SDKStartup: SSE di log runner. Baris-baris ini mengikuti baris finished: interrupted, beberapa baris setelah baris pada langkah 1. Sebagian besar tidak memiliki timestamp, sehingga pengumpul log dapat menampilkannya di tempat lain.
  3. Temukan baris tersebut dalam tabel ini:
Jika log tidak memiliki satu pun dari baris-baris ini, atau log proxy tidak menunjukkan masalah apa pun, laporkan masalah.

Menghentikan sesi agar tidak mencoba lagi

Sesi tetap menahan pesan tersebut dalam status tertunda, dan runner yang dapat melayani pemilik sesi akan mengambil sesi tersebut lagi. Hingga Anda mengubah proxy, sesi menunggu dengan cara yang sama setiap kali. Untuk menghentikannya, arsipkan sesi tersebut di claude.ai/code.

Apa selanjutnya

  • Sesuaikan sesi: script wrapper, lifecycle hook, runner on-demand, server MCP, dan izin
  • Uji end to end: verifikasi gambar runner baru dari CI sebelum mempromosikannya
  • Referensi: setiap flag CLI, variabel lingkungan, dan metrik