313 313
314Per ogni sessione che usa git gestito da Anthropic, il runner registra anche una riga `[runner:warn]` che inizia con `governed git: GIT_SSL_CAINFO is set` o `governed git: GIT_SSL_NO_VERIFY is set`. La riga dice quello che il runner ha fatto con quella variabile per il suo git, per git dentro la sessione, e per i tuoi lifecycle hook. Termina con se hai bisogno di cambiare qualcosa.314Per ogni sessione che usa git gestito da Anthropic, il runner registra anche una riga `[runner:warn]` che inizia con `governed git: GIT_SSL_CAINFO is set` o `governed git: GIT_SSL_NO_VERIFY is set`. La riga dice quello che il runner ha fatto con quella variabile per il suo git, per git dentro la sessione, e per i tuoi lifecycle hook. Termina con se hai bisogno di cambiare qualcosa.
315 315
316### Aggiungi repository github.com alle sessioni dei canali Claude Tag
317
318Se Claude non riesce ad aggiungere un repository github.com a una sessione di un canale Claude Tag, assicurati che il canale vi abbia accesso, anche quando il tuo runner riesce a clonarlo. Quell'accesso deriva dalle impostazioni su GitHub e nella tua organizzazione Claude, non dalle credenziali git del tuo runner.
319
320**1. Installa la Claude GitHub App**
321
322Installa la [Claude GitHub App](https://github.com/apps/claude) sull'organizzazione o sull'account GitHub proprietario del repository e includi quel repository nell'installazione.
323
324**2. Collega l'organizzazione o l'account GitHub**
325
326In [**Organization settings > Git providers**](https://claude.ai/admin-settings/source-control), collega quell'organizzazione o quell'account alla tua organizzazione Claude. Può collegarla un Owner della tua organizzazione Claude che sia anche proprietario dell'organizzazione GitHub. Vedi [Collegare la tua organizzazione GitHub](https://claude.com/docs/claude-tag/admins/configure-github#link-your-github-organization).
327
328**3. Concedi il repository**
329
330Nelle [impostazioni di amministrazione di Claude Tag](https://claude.ai/admin-settings/claude-tag), concedi il repository al canale o a un ambito più ampio che includa il canale: il suo workspace Slack o tutto Slack. Può concederlo chi ha il ruolo Owner o il permesso Claude Tag Admin. Anche un gestore del canale può aggiungerlo al proprio canale se il suo account GitHub è amministratore del repository. Vedi [Concedere l'accesso ai repository](https://claude.com/docs/claude-tag/admins/configure-github#grant-repository-access).
331
332Quindi avvia un nuovo thread nel canale e [nomina il repository](https://claude.com/docs/claude-tag/admins/configure-github#how-granted-repositories-reach-a-session) nel tuo primo messaggio.
333
334Se Claude non riesce ancora ad aggiungere il repository, vedi [Se Claude non riesce a raggiungere un repository](https://claude.com/docs/claude-tag/admins/configure-github#if-claude-can%E2%80%99t-reach-a-repository) per sapere dove controllare il collegamento GitHub e la concessione del repository.
335
316### Riscrivi gli URL git per le reti private336### Riscrivi gli URL git per le reti private
317 337
318Gli URL dei repository arrivano dal piano di controllo come HTTPS, con il nome host del tuo host git; per GitHub Enterprise, questo è il nome host che hai configurato per l'[integrazione GitHub Enterprise](https://code.claude.com/docs/it/github-enterprise-server.md) su claude.ai. Due flag ripetibili riscrivono quegli URL prima del clone:338Gli URL dei repository arrivano dal piano di controllo come HTTPS, con il nome host del tuo host git; per GitHub Enterprise, questo è il nome host che hai configurato per l'[integrazione GitHub Enterprise](https://code.claude.com/docs/it/github-enterprise-server.md) su claude.ai. Due flag ripetibili riscrivono quegli URL prima del clone:
376 396
377Le build e i test sono solitamente la parte più grande e più variabile del carico di una sessione, quindi esegui una build rappresentativa del tuo repository, misura il suo picco di CPU e memoria, e aumenta qualsiasi valore iniziale che non lascia spazio per il processo Claude Code in cima a quel picco.397Le build e i test sono solitamente la parte più grande e più variabile del carico di una sessione, quindi esegui una build rappresentativa del tuo repository, misura il suo picco di CPU e memoria, e aumenta qualsiasi valore iniziale che non lascia spazio per il processo Claude Code in cima a quel picco.
378 398
379Il runner usa `--capacity` per limitare quante sessioni esegue contemporaneamente. Non divide CPU o memoria tra di loro, quindi le sessioni su un runner condividono la CPU e la memoria del container. Per limitare la quota di una sessione, applica limiti dal tuo [script wrapper](https://code.claude.com/docs/it/self-hosted-environments-configuration.md#wrapper-scripts). Cosa dare a un container quindi dipende da quante sessioni serve contemporaneamente:399Il runner usa `--capacity` per limitare quante sessioni esegue contemporaneamente. Non divide CPU o memoria tra di loro, quindi le sessioni su un runner condividono la CPU e la memoria del container. Per evitare che l'uso di memoria di una sessione termini le altre, esegui una sessione per runner con [il proprio limite di memoria](#give-each-session-its-own-memory-limit).
380 400
381* **Una sessione per runner**: dai a ogni container i valori di una sessione. Usa questo dimensionamento a `--capacity 1`, che la [sezione hardening](#harden-your-deployment) consiglia, e per [runner on-demand](https://code.claude.com/docs/it/self-hosted-environments-configuration.md#on-demand-runners), dove imposti i valori sul carico di lavoro che il tuo hook [`spawn-runner`](https://code.claude.com/docs/it/self-hosted-environments-configuration#the-spawn-runner-hook) invia, come il modello di pod di un Kubernetes Job.401* **Una sessione per runner**: dai a ogni container i valori di una sessione. Usa questo dimensionamento a `--capacity 1`, che la [sezione hardening](#harden-your-deployment) consiglia, e per [runner on-demand](https://code.claude.com/docs/it/self-hosted-environments-configuration.md#on-demand-runners), dove imposti i valori sul carico di lavoro che il tuo hook [`spawn-runner`](https://code.claude.com/docs/it/self-hosted-environments-configuration#the-spawn-runner-hook) invia, come il modello di pod di un Kubernetes Job.
382* **Diverse sessioni per runner**: a un `--capacity` sopra uno, moltiplica i valori di una sessione per la capacità, perché fino a quel numero di sessioni possono essere eseguite nel container contemporaneamente. Le ricette [Kubernetes](#kubernetes) e [Docker Compose](#docker-compose) eseguono `--capacity 4` senza limiti di CPU o memoria, quindi aggiungi limiti dimensionati per la capacità che esegui.402* **Diverse sessioni per runner**: a un `--capacity` sopra uno, moltiplica i valori di una sessione per la capacità, perché fino a quel numero di sessioni possono essere eseguite nel container contemporaneamente. Le ricette [Kubernetes](#kubernetes) e [Docker Compose](#docker-compose) eseguono `--capacity 4` senza limiti di CPU o memoria, quindi aggiungi limiti dimensionati per la capacità che esegui.
403* **Diversi container runner su un host**: dimensiona l'host per la somma delle capacità dei runner, perché ogni runner conta solo le proprie sessioni rispetto a `--capacity`:
404
405 * **Memoria**: moltiplica la memoria di una sessione per la somma, quindi aggiungi ciò che usano i processi propri dell'host
406 * **CPU**: moltiplica la richiesta di CPU di una sessione per la somma. Per permettere a ogni sessione di superare temporaneamente la richiesta contemporaneamente, moltiplica invece il suo limite di CPU.
407
408 Dai a ogni runner il proprio container. Usa lo [stesso percorso `--base-dir`](#keep-the-base-directory-and-capacity-identical-across-runners) in ciascuno, su uno storage che nessun altro container runner monta, in modo che ogni runner abbia [la propria directory di lavoro](#harden-your-deployment).
409
410### Dai a ogni sessione il proprio limite di memoria
411
412Per evitare che una sessione termini le altre quando la memoria si esaurisce, esegui ogni runner a `--capacity 1` sotto il proprio limite di memoria, impostato sulla memoria di una sessione:
413
414* **In un container**: esegui un runner per container e imposta il limite di memoria del container, come `limits.memory` su Kubernetes, `--memory` su Docker, o `mem_limit` in un file Compose. Mantieni la somma dei limiti dei container al di sotto della memoria dell'host, perché quando è l'host stesso a esaurirla, il kernel può uccidere processi ovunque sull'host.
415* **Sotto systemd senza un container**: imposta `MemoryMax` sull'unità del runner ed esegui un runner per host, perché i runner che [usano lo stesso `--base-dir`](#keep-the-base-directory-and-capacity-identical-across-runners) su un filesystem condividono i repository clonati lì. Ad esempio, a `--capacity 1` senza hook `checkout`, le loro sessioni su un repository possono lavorare nello stesso checkout contemporaneamente. Per eseguire diversi runner su un host, dai a ciascuno un container.
416
417Quando un container o un'unità raggiunge il proprio limite di memoria, il kernel uccide i processi solo al suo interno. Se imposti `--capacity` sopra uno, le sessioni condividono un unico limite. Quando lo raggiungono, il kernel non sceglie per sessione quali processi uccidere, quindi l'uso di memoria di una sessione può terminare le altre.
418
419Su Kubernetes, non puoi separare le sessioni con nessuno dei due valori dell'impostazione `singleProcessOOMKill` del kubelet. Non puoi nemmeno limitare la memoria totale di una sessione con un `ulimit` di memoria nel tuo [script wrapper](https://code.claude.com/docs/it/self-hosted-environments-configuration.md#wrapper-scripts). Il kernel applica un valore come `ulimit -v` a ogni processo separatamente.
420
421### Lascia spazio sotto i limiti di processi e thread
422
423Per dimensionare un limite di processi e thread, misura ciò di cui ha bisogno una sessione e moltiplicalo per il numero di sessioni che condividono il limite. Quando quelle sessioni raggiungono il limite, il kernel rifiuta nuovi processi e thread, quindi comandi, build e test in ognuna di esse possono fallire. La chiamata rifiutata restituisce `EAGAIN`, il cui messaggio standard è `Resource temporarily unavailable`.
424
425Supponi che una sessione raggiunga un picco di 300 processi e thread, e che quattro sessioni condividano il limite. Insieme ne richiedono 1.200, e con un limite di 2.400 lasci spazio per build che ne richiedono il doppio.
426
427#### Dove impostare ciascun limite
428
429Ogni limite in questa tabella conta i thread oltre ai processi, e `pids.max` è il file che contiene il limite di un cgroup:
430
431| Limite | Dove lo imposti | Cosa lo condivide |
432| :- | :- | :- |
433| `pids.max` su Kubernetes | `podPidsLimit` nella configurazione del kubelet dei nodi che eseguono i runner. Non puoi impostarlo in una specifica di Pod. | I container di un Pod |
434| `pids.max` su Docker | `--pids-limit`, o `pids_limit` in un file Compose | Un container |
435| `pids.max` sotto systemd | `TasksMax` sull'unità del runner | Un'unità |
436| `ulimit -u` | La shell o il servizio che avvia il runner | Tutto ciò che sull'host viene eseguito con l'ID utente del runner. Non applicato per root. |
437
438Quando non imposti `TasksMax`, systemd applica `DefaultTasksMax`, che per impostazione predefinita è il 15% del valore più basso tra `kernel.pid_max`, `kernel.threads-max` e il `pids.max` del cgroup root.
439
440#### Misura il picco di una sessione
441
442Per ottenere i numeri per i tuoi runner, misura una sessione sul suo host, che su Kubernetes è il nodo:
443
444**1. Avvia un runner da solo**
445
446Avvia un runner a `--capacity 1` senza nient'altro nel suo container o nella sua unità systemd, da solo sul suo host e nel suo ambiente:
447
448* **Il suo host**: usane uno che non esegue nessun altro runner. Potrai così individuare il suo processo nel passaggio successivo.
449* **Il suo ambiente**: rendilo l'unico runner lì, ad esempio in un ambiente che [crei per il test](https://code.claude.com/docs/it/self-hosted-environments-quickstart.md#set-up-manually). Le sessioni vengono instradate a un ambiente e non a un runner.
450
451Non avviare ancora una sessione, perché ti serve la directory del passaggio successivo prima che la build inizi.
452
453**2. Trova la directory cgroup del runner**
454
455Sull'host, non all'interno del container, trova l'ID del processo del runner, ad esempio con `ps`. Leggi `/proc/<pid>/cgroup` per quell'ID:
456
457* **Una riga contiene `:pids:`**: l'host usa cgroup v1, e la directory è `/sys/fs/cgroup/pids` seguita dal testo dopo `:pids:`
458* **L'unica riga inizia con `0::`**: l'host usa cgroup v2, e la directory è `/sys/fs/cgroup` seguita dal testo dopo `0::`
459
460**3. Esegui una build rappresentativa e registra il picco**
461
462Esegui una sessione attraverso una build rappresentativa e rileva il picco dalla directory cgroup del runner:
463
464* **La directory ha `pids.peak`**: leggi il file al termine della build
465* **La directory non ha `pids.peak`**: leggi `pids.current` una volta al secondo mentre la build è in esecuzione e conserva il valore più alto. Un picco tra due letture passa inosservato, quindi considera quel valore come una stima per difetto.
466
467**4. Moltiplica per le sessioni che condividono il limite**
468
469* **Il Pod, il container o l'unità di un runner**: moltiplica il picco per il `--capacity` del runner
470* **Un limite condiviso da diversi runner**: moltiplica il picco per la somma delle loro capacità
471
472Poi aggiungi il picco di qualsiasi altra cosa che condivide il limite, come un altro container nel Pod.
473
474**5. Imposta il limite al di sopra del risultato**
475
476Con un limite più alto lasci spazio per build più pesanti, e con uno più basso fermi prima una fork bomb.
477
478#### Controlla un limite `pids.max`
479
480* **Verifica se `pids.max` è stato raggiunto**: cerca nel log del kernel dell'host, ad esempio con `dmesg`, una riga che contiene `cgroup: fork rejected by pids controller in` e il percorso di un cgroup. Il kernel lo registra solo la prima volta che rifiuta un processo o un thread in quel cgroup, quindi cerca nell'intero log.
481* **Visualizza il limite in vigore**: leggi `pids.max` nella directory cgroup del runner e in ogni directory al di sopra di essa. Il valore più basso è il limite in vigore, e `max` significa nessun limite a quel livello.
383 482
384## Kubernetes483## Kubernetes
385 484
577 676
578Cosa il percorso di riutilizzo fa e non garantisce:677Cosa il percorso di riutilizzo fa e non garantisce:
579 678
580* **Qualsiasi forma di clone funziona**: un clone completo, shallow, o single-branch al percorso viene usato così com'è. Il runner non passa mai `--depth` quando recupera in un clone esistente, quindi un pre-warm completo mantiene la sua cronologia completa e uno shallow rimane shallow. `CLAUDE_RUNNER_FETCH_DEPTH` (`full`, `0`, o un numero; predefinito 50) controlla solo il clone freddo che il runner fa quando nessun clone esiste ancora.679* **Profondità del clone**: crea il clone senza `--depth`, con o senza `--single-branch`. Il runner non passa mai `--depth` quando esegue il fetch in un clone con un remote `origin`, anche se imposti [`CLAUDE_RUNNER_FETCH_DEPTH`](https://code.claude.com/docs/it/self-hosted-environments-reference#environment-variable-only-settings). Con un clone completo, ogni sessione scarica solo i commit che mancano al clone. Con un clone shallow, una sessione su un branch che si è separato prima del commit più vecchio del clone scarica l'intera cronologia di quel branch.
581* **Le modifiche tracciate si resettano, i file non tracciati persistono**: a `--capacity 1`, ogni sessione inizia da un reset duro che cancella le modifiche tracciate della sessione precedente, ma il runner non esegue mai `git clean`, quindi i file non tracciati dalle sessioni precedenti dell'owner bloccato rimangono nell'albero.680* **Le modifiche tracciate si resettano, i file non tracciati persistono**: a `--capacity 1`, ogni sessione inizia da un reset duro che cancella le modifiche tracciate della sessione precedente, ma il runner non esegue mai `git clean`, quindi i file non tracciati dalle sessioni precedenti dell'owner bloccato rimangono nell'albero.
582* **Directory per sessione persistono anche**: accanto al checkout, il runner crea voci per sessione sotto `<base-dir>/_sessions/` per ogni sessione che esegue. La directory di configurazione Claude della sessione contiene una copia locale della trascrizione della conversazione. Accanto ad essa si trovano i file caricati della sessione, quando la sessione ne ha. La directory della sessione si trova lì anche: contiene qualsiasi worktree per sessione e checkout di hook `checkout` mentre la sessione è in esecuzione, e mantiene qualsiasi altra cosa Claude abbia scritto in essa.681* **Directory per sessione persistono anche**: accanto al checkout, il runner crea voci per sessione sotto `<base-dir>/_sessions/` per ogni sessione che esegue. La directory di configurazione Claude della sessione contiene una copia locale della trascrizione della conversazione. Accanto ad essa si trovano i file caricati della sessione, quando la sessione ne ha. La directory della sessione si trova lì anche: contiene qualsiasi worktree per sessione e checkout di hook `checkout` mentre la sessione è in esecuzione, e mantiene qualsiasi altra cosa Claude abbia scritto in essa.
583 682
587* **Con il proxy git, un pre-warm `reftable` perde i suoi ref**: quando il runner sanitizza `.git/` prima di ogni sessione, mantiene `.git/refs/` e rimuove la directory `.git/reftable/`. Un clone pre-riscaldato nel formato dei ref `reftable` di git perde così i suoi ref, quindi pre-riscalda invece il clone nel formato dei ref `files` di git.686* **Con il proxy git, un pre-warm `reftable` perde i suoi ref**: quando il runner sanitizza `.git/` prima di ogni sessione, mantiene `.git/refs/` e rimuove la directory `.git/reftable/`. Un clone pre-riscaldato nel formato dei ref `reftable` di git perde così i suoi ref, quindi pre-riscalda invece il clone nel formato dei ref `files` di git.
588* **I clone lunghi non hanno bisogno di workaround**: il runner limita ogni operazione git con un watchdog senza progresso di 120 secondi e un hard cap di 30 minuti, non un timeout piatto, quindi un clone freddo lento che continua a segnalare progresso si completa.687* **I clone lunghi non hanno bisogno di workaround**: il runner limita ogni operazione git con un watchdog senza progresso di 120 secondi e un hard cap di 30 minuti, non un timeout piatto, quindi un clone freddo lento che continua a segnalare progresso si completa.
589 688
689### Conferma che il runner usa il tuo clone
690
691Per confermare che il runner usa il tuo clone, avvialo con [`--log-level debug`](https://code.claude.com/docs/it/self-hosted-environments-reference#runner-cli-flags) e avvia una sessione sul repository. Il runner registra `Prefetched repo found at` e il percorso del clone. Se invece registra `No prefetched repo, fresh init at`, non ha trovato alcun clone utilizzabile al percorso indicato in quella riga. Verifica che il tuo clone si trovi in quel percorso, sia di proprietà dell'utente del runner e abbia un remote chiamato `origin`.
692
693Se il runner trova il tuo clone e le sessioni si avviano comunque lentamente, verifica se il clone è shallow.
694
590## Fissa la versione695## Fissa la versione
591 696
592Per impostazione predefinita, il processo figlio di ogni sessione esegue il binario del runner stesso, e il runner disattiva l'auto-aggiornamento all'interno delle sessioni che genera. Con questa impostazione predefinita, ogni sessione esegue la versione che hai installato sull'host o incluso nell'immagine. Un aggiornamento a livello di host ha effetto la prossima volta che il runner si avvia.697Per impostazione predefinita, il processo figlio di ogni sessione esegue il binario del runner stesso, e il runner disattiva l'auto-aggiornamento all'interno delle sessioni che genera. Con questa impostazione predefinita, ogni sessione esegue la versione che hai installato sull'host o incluso nell'immagine. Un aggiornamento a livello di host ha effetto la prossima volta che il runner si avvia.
609* **Flotta fissa**: esegui un set statico di repliche runner e scala sulle [metriche Prometheus](https://code.claude.com/docs/it/self-hosted-environments-reference.md#prometheus-metrics) che ogni runner serve714* **Flotta fissa**: esegui un set statico di repliche runner e scala sulle [metriche Prometheus](https://code.claude.com/docs/it/self-hosted-environments-reference.md#prometheus-metrics) che ogni runner serve
610* **Runner on-demand**: esegui il sottocomando `claude self-hosted-runner orchestrator`, che esegue il polling di Anthropic per le sessioni in coda senza runner disponibile e invoca il tuo hook `spawn-runner` per avviarne uno per sessione. Vedi [Runner on-demand](https://code.claude.com/docs/it/self-hosted-environments-configuration.md#on-demand-runners).715* **Runner on-demand**: esegui il sottocomando `claude self-hosted-runner orchestrator`, che esegue il polling di Anthropic per le sessioni in coda senza runner disponibile e invoca il tuo hook `spawn-runner` per avviarne uno per sessione. Vedi [Runner on-demand](https://code.claude.com/docs/it/self-hosted-environments-configuration.md#on-demand-runners).
611 716
717### Rilascia le sessioni inattive su una flotta fissa
718
719Se le sessioni restano in coda su una flotta fissa mentre tutti i runner sono online, la causa potrebbe essere costituita dalle sessioni inattive. Per impostazione predefinita, una sessione mantiene il suo slot dopo la fine del suo turno, e il suo runner resta bloccato sull'[owner](https://code.claude.com/docs/it/self-hosted-environments#key-concepts) di quella sessione. Se l'[attività pianificata cloud](https://code.claude.com/docs/it/routines.md) del tuo team avvia una nuova sessione a ogni esecuzione, le sue sessioni inattive possono occupare tutti gli slot.
720
721Per verificarlo, leggi `claude_code_self_hosted_runner_session_idle_seconds` nelle [metriche Prometheus](https://code.claude.com/docs/it/self-hosted-environments-reference.md#prometheus-metrics) di ogni runner. Ogni sessione detenuta da un runner ha la propria serie: `0` mentre la sessione è occupata, altrimenti i secondi trascorsi da quando è diventata inattiva. Scegli il tempo di inattività che vuoi consentire: più lungo delle pause che le persone fanno a metà di un'attività, e abbastanza breve da rilasciare ogni esecuzione prima che inizi quella successiva dell'attività pianificata. Confronta le serie con questo valore.
722
723* **Serie sopra quel tempo, ad esempio `1800` per 30 minuti**: le sessioni inattive occupano quegli slot, quindi imposta `--release-idle-session-min`
724* **Tutte le serie sotto quel tempo**: nessuna sessione è rimasta inattiva così a lungo. Aggiungi runner, oppure imposta [`--kill-session-after-min`](https://code.claude.com/docs/it/self-hosted-environments-reference#runner-cli-flags) per le [sessioni che non diventano mai inattive](#some-sessions-don’t-count-as-idle).
725* **Un runner senza serie**: nessuna sessione lo occupa. Consulta **Sessions stay queued** in [Risoluzione dei problemi](#troubleshooting).
726* **Un runner le cui metriche non rispondono**: il suo processo potrebbe essere terminato. Consulta **An environment that looks healthy** in [Quando il runner termina](#when-the-runner-exits).
727
728Per rilasciare le sessioni inattive, avvia ogni runner con [`--release-idle-session-min`](https://code.claude.com/docs/it/self-hosted-environments-reference#runner-cli-flags) e quel tempo in minuti, ad esempio `--release-idle-session-min 30`. Il runner rilascia quindi qualsiasi sessione che resta inattiva così a lungo, sia che l'abbia avviata un'attività pianificata sia una persona.
729
730* **Lavoro non inviato**: una sessione rilasciata riprende al messaggio successivo, senza il lavoro di cui non aveva fatto il push. Per conservarne i commit, consulta [Le sessioni riprese perdono il lavoro non inviato](#additional-limitations).
731* **Uscita del runner**: un runner che rilascia la sua ultima sessione avvia una [normale uscita](#when-the-runner-exits). Fai in modo che il tuo supervisor lo riavvii su un filesystem pulito, come descritto in [Rafforza il tuo deploy](#harden-your-deployment).
732* **Sessioni che non diventano mai inattive**: imposta anche [`--kill-session-after-min`](https://code.claude.com/docs/it/self-hosted-environments-reference#runner-cli-flags), perché [alcune sessioni non vengono considerate inattive](#some-sessions-don’t-count-as-idle)
733
612## Problemi noti e limitazioni734## Problemi noti e limitazioni
613 735
614Le seguenti sono le limitazioni in questa versione, con workaround dove uno esiste.736Le seguenti sono le limitazioni in questa versione, con workaround dove uno esiste.
642### Limitazioni aggiuntive764### Limitazioni aggiuntive
643 765
644* **Le sessioni riprese perdono il lavoro non spinto**: un nuovo runner clona di nuovo il repository dal suo branch iniziale, quindi il lavoro che la sessione non aveva spinto è perso.766* **Le sessioni riprese perdono il lavoro non spinto**: un nuovo runner clona di nuovo il repository dal suo branch iniziale, quindi il lavoro che la sessione non aveva spinto è perso.
645 * **Per conservare il lavoro di cui è stato fatto il commit**: imposta [`--push-outcome-on-release`](https://code.claude.com/docs/it/self-hosted-environments-reference#runner-cli-flags) su ogni runner nell'ambiente, perché un runner senza il flag riprende la sessione dal suo branch iniziale. Un runner con il flag esegue un push best-effort dei branch di risultato della sessione prima del rilascio, e la sessione ripresa parte da quei commit. Il push usa le credenziali git proprie dell'host del runner, anche su un runner che usa [git gestito da Anthropic](#use-the-anthropic-git-proxy). Le modifiche senza commit vengono comunque perse.767 * **Per conservare il lavoro di cui è stato fatto il commit**: imposta [`--push-outcome-on-release`](https://code.claude.com/docs/it/self-hosted-environments-reference#runner-cli-flags) su ogni runner nell'ambiente, perché un runner senza il flag riprende la sessione dal suo branch iniziale. Un runner con il flag esegue un push best-effort dei branch di risultato della sessione prima del rilascio, e la sessione ripresa parte da quei commit. Il push usa le credenziali git proprie dell'host del runner, anche su un runner che usa [git gestito da Anthropic](#use-the-anthropic-git-proxy).
646 * **Con un hook `checkout`**: i repository estratti tramite un [hook del ciclo di vita `checkout`](https://code.claude.com/docs/it/self-hosted-environments-configuration#checkout) non vengono sottoposti a push. Crea invece uno snapshot di questi repository dall'[hook `post-session`](https://code.claude.com/docs/it/self-hosted-environments-configuration#post-session).768 * **Con un hook `checkout`**: i repository estratti tramite un [hook del ciclo di vita `checkout`](https://code.claude.com/docs/it/self-hosted-environments-configuration#checkout) non vengono sottoposti a push. Crea invece uno snapshot di questi repository dall'[hook `post-session`](https://code.claude.com/docs/it/self-hosted-environments-configuration#post-session).
647 * **Prima di abilitare il flag**: limita chi può eseguire il push sui ref `claude/*` sul remote di origine. Alla ripresa, il runner recupera il branch precedentemente spinto senza verificare chi ne ha eseguito il push.769 * **Prima di abilitare il flag**: limita chi può eseguire il push sui ref `claude/*` sul remote di origine. Alla ripresa, il runner recupera il branch precedentemente spinto senza verificare chi ne ha eseguito il push.
770 * **Le modifiche senza commit vengono comunque perse**: per chiedere a Claude di fare il commit e il push quando finisce di rispondere, vedi [Chiedere alle sessioni di eseguire il push del proprio lavoro](https://code.claude.com/docs/it/self-hosted-environments-configuration.md#prompt-sessions-to-push-their-work)
648* **Un repository aggiunto a metà sessione può non riuscire a essere clonato**: Claude lo clona con `git clone` tramite HTTPS. Su un runner senza [`--use-anthropic-git-proxy`](#use-the-anthropic-git-proxy), il clone fallisce con un errore di autenticazione git se nulla sull'host può leggere il repository. Quando possibile, seleziona ogni repository di cui la sessione ha bisogno quando la crei.771* **Un repository aggiunto a metà sessione può non riuscire a essere clonato**: Claude lo clona con `git clone` tramite HTTPS. Su un runner senza [`--use-anthropic-git-proxy`](#use-the-anthropic-git-proxy), il clone fallisce con un errore di autenticazione git se nulla sull'host può leggere il repository. Quando possibile, seleziona ogni repository di cui la sessione ha bisogno quando la crei.
649* **Alcuni connettori non appaiono nelle sessioni self-hosted**: un connettore che non hai ancora connesso nelle Impostazioni di claude.ai non è elencato in una sessione self-hosted, e la sessione non ti chiederà di connettarlo. Connettilo prima nelle Impostazioni, quindi avvia una sessione fresca. L'aggiunta di un connettore a una sessione già in esecuzione non rende i suoi strumenti disponibili a Claude; avvia una sessione fresca per raccogliere un connettore appena aggiunto.772* **Alcuni connettori non appaiono nelle sessioni self-hosted**: un connettore che non hai ancora connesso nelle Impostazioni di claude.ai non è elencato in una sessione self-hosted, e la sessione non ti chiederà di connettarlo. Connettilo prima nelle Impostazioni, quindi avvia una sessione fresca. L'aggiunta di un connettore a una sessione già in esecuzione non rende i suoi strumenti disponibili a Claude; avvia una sessione fresca per raccogliere un connettore appena aggiunto.
650* **Quando qualcuno archivia o elimina una sessione, o rilascia il suo runner dal menu della sessione**: non fare affidamento sul push di [`--push-outcome-on-release`](https://code.claude.com/docs/it/self-hosted-environments-reference#runner-cli-flags). Per salvare i commit in questi casi, esegui il push di `HEAD` su un branch di recupero da un [hook `post-session`](https://code.claude.com/docs/it/self-hosted-environments-configuration#post-session). Se parti dall'esempio presente lì, fai in modo che esegua il push anche quando non ci sono modifiche senza commit, perché esegue il push solo dopo un commit di snapshot.773* **Quando qualcuno archivia o elimina una sessione, o rilascia il suo runner dal menu della sessione**: non fare affidamento sul push di [`--push-outcome-on-release`](https://code.claude.com/docs/it/self-hosted-environments-reference#runner-cli-flags). Per salvare i commit in questi casi, esegui il push di `HEAD` su un branch di recupero da un [hook `post-session`](https://code.claude.com/docs/it/self-hosted-environments-configuration#post-session). Se parti dall'esempio presente lì, fai in modo che esegua il push anche quando non ci sono modifiche senza commit, perché esegue il push solo dopo un commit di snapshot.
684* **Le sessioni falliscono subito dopo la presa in carico**: apri la sessione in claude.ai/code per vedere l'errore. Se l'errore mostra che git non è riuscito ad autenticarsi, controlla le [credenziali git](#configure-git) del runner. Su un runner avviato con `--use-anthropic-git-proxy`, consulta [Quando le sessioni non si avviano su un runner con il git proxy](#when-anthropic-doesnt-serve-a-session).807* **Le sessioni falliscono subito dopo la presa in carico**: apri la sessione in claude.ai/code per vedere l'errore. Se l'errore mostra che git non è riuscito ad autenticarsi, controlla le [credenziali git](#configure-git) del runner. Su un runner avviato con `--use-anthropic-git-proxy`, consulta [Quando le sessioni non si avviano su un runner con il git proxy](#when-anthropic-doesnt-serve-a-session).
685 808
686 Una directory di base non scrivibile arresta il runner all'avvio invece di far fallire le sessioni. Consulta la voce **Il runner esce all'avvio con `cannot create or write to base directory`** in questo elenco.809 Una directory di base non scrivibile arresta il runner all'avvio invece di far fallire le sessioni. Consulta la voce **Il runner esce all'avvio con `cannot create or write to base directory`** in questo elenco.
810* **Una sessione viene presa in carico, ma Claude non risponde mai al suo primo messaggio**: se i tuoi runner raggiungono `api.anthropic.com` attraverso un proxy, configuralo in modo che lasci passare la risposta `/worker/events/stream` della sessione man mano che arriva. Aumentare i timeout del runner non serve. Per confermare la causa nel log del runner, consulta [Una sessione viene presa in carico, ma Claude non risponde mai al primo messaggio](#when-a-sessions-first-message-is-never-answered).
687* **Le sessioni non si avviano su un runner che ha impostato `--use-anthropic-git-proxy`**: cerca nel log del runner `access denied by the git proxy`, oppure un errore git che nomina un indirizzo `api.anthropic.com` contenente `/git_proxy/`. Per capire se Anthropic ha servito la sessione e correggere la causa, consulta [Quando le sessioni non si avviano su un runner con il git proxy](#when-anthropic-doesnt-serve-a-session).811* **Le sessioni non si avviano su un runner che ha impostato `--use-anthropic-git-proxy`**: cerca nel log del runner `access denied by the git proxy`, oppure un errore git che nomina un indirizzo `api.anthropic.com` contenente `/git_proxy/`. Per capire se Anthropic ha servito la sessione e correggere la causa, consulta [Quando le sessioni non si avviano su un runner con il git proxy](#when-anthropic-doesnt-serve-a-session).
688* **Le sessioni non riescono a raggiungere la rete attraverso un proxy di uscita autenticante**: quando l'origine impostata con [`--proxy-authorization-command` o `--proxy-authorization-file`](#authenticate-to-an-egress-proxy) fallisce, scade dopo 30 secondi o produce un valore vuoto, il runner risponde a quella connessione con `502 Bad Gateway` e registra il motivo. Il runner redige lo stderr del comando in quel log e non registra mai il valore dell'intestazione. Con `--proxy-authorization-command`, eseguire il comando stesso sull'host per confermare che stampa l'intero valore dell'intestazione su stdout. Se il runner esce invece all'avvio con `could not start the proxy-authorization listener`, non ha potuto aprire il suo listener di loopback.812* **Le sessioni non riescono a raggiungere la rete attraverso un proxy di uscita autenticante**: quando l'origine impostata con [`--proxy-authorization-command` o `--proxy-authorization-file`](#authenticate-to-an-egress-proxy) fallisce, scade dopo 30 secondi o produce un valore vuoto, il runner risponde a quella connessione con `502 Bad Gateway` e registra il motivo. Il runner redige lo stderr del comando in quel log e non registra mai il valore dell'intestazione. Con `--proxy-authorization-command`, eseguire il comando stesso sull'host per confermare che stampa l'intero valore dell'intestazione su stdout. Se il runner esce invece all'avvio con `could not start the proxy-authorization listener`, non ha potuto aprire il suo listener di loopback.
689* **Il runner registra righe `Poll failed` contenenti `rejecting the malformed poll response`**: il runner ha ricevuto una risposta di work-poll il cui corpo non è il JSON previsto dalla coda. Una possibile causa è un proxy di intercettazione o un captive portal che risponde con una propria pagina. Se il runner si connette attraverso un proxy, configura il proxy in modo che lasci passare inalterate le risposte da `api.anthropic.com`.813* **Il runner registra righe `Poll failed` contenenti `rejecting the malformed poll response`**: il runner ha ricevuto una risposta di work-poll il cui corpo non è il JSON previsto dalla coda. Una possibile causa è un proxy di intercettazione o un captive portal che risponde con una propria pagina. Se il runner si connette attraverso un proxy, configura il proxy in modo che lasci passare inalterate le risposte da `api.anthropic.com`.
708* **Una sessione non si avvia e mostra `This runner couldn't read`**: il runner ha chiesto un repository all'host git con le sue [credenziali git](#configure-git) e ha ricevuto una risposta di repository non trovato. Il repository non esiste, oppure quelle credenziali non possono raggiungerlo.832* **Una sessione non si avvia e mostra `This runner couldn't read`**: il runner ha chiesto un repository all'host git con le sue [credenziali git](#configure-git) e ha ricevuto una risposta di repository non trovato. Il repository non esiste, oppure quelle credenziali non possono raggiungerlo.
709 * **Se amministri il runner**: concedi alle sue credenziali git l'accesso in lettura al repository, poi avvia una nuova sessione.833 * **Se amministri il runner**: concedi alle sue credenziali git l'accesso in lettura al repository, poi avvia una nuova sessione.
710 * **Se hai avviato tu la sessione**: se il repository non esiste, avvia una nuova sessione con il repository corretto. Se il runner non riesce a raggiungere il repository, chiedi all'amministratore del runner di concedere l'accesso, poi avvia una nuova sessione.834 * **Se hai avviato tu la sessione**: se il repository non esiste, avvia una nuova sessione con il repository corretto. Se il runner non riesce a raggiungere il repository, chiedi all'amministratore del runner di concedere l'accesso, poi avvia una nuova sessione.
711* **Le sessioni impiegano minuti per avviarsi**: il clone iniziale di solito domina. Osservare la [metrica](https://code.claude.com/docs/it/self-hosted-environments-reference.md#prometheus-metrics) `claude_code_self_hosted_runner_session_init_duration_seconds` per confermare e ridurre il clone con un [pre-warmed checkout](#reuse-a-pre-warmed-checkout) o un `CLAUDE_RUNNER_FETCH_DEPTH` più piccolo.835* **Le sessioni impiegano minuti per avviarsi o riprendere**: una possibile causa è un clone da zero. In una flotta che avvia ogni runner su un disco vuoto, senza [hook `checkout`](https://code.claude.com/docs/it/self-hosted-environments-configuration#checkout), il runner clona da zero i repository della sessione prima di avviare Claude Code. Una sessione che riprende su un disco vuoto attende di nuovo lo stesso clone.
836
837 Per evitare il clone da zero, fornisci un [checkout pre-riscaldato](#reuse-a-pre-warmed-checkout). Se ne fornisci già uno, [verifica che il runner lo usi](#confirm-that-the-runner-uses-your-clone). Dove è il runner stesso a creare il clone ed esce dopo una sola sessione, abbassa [`CLAUDE_RUNNER_FETCH_DEPTH`](https://code.claude.com/docs/it/self-hosted-environments-reference#environment-variable-only-settings) dal valore predefinito di 50 commit per recuperare meno cronologia.
838
839 Se usi un hook, questo viene eseguito al posto del clone del runner, quindi esamina invece ciò che fa il tuo hook. Osserva la [metrica](https://code.claude.com/docs/it/self-hosted-environments-reference.md#prometheus-metrics) `claude_code_self_hosted_runner_session_init_duration_seconds` per vedere quanto durano gli avvii.
712* **I turni falliscono con un 401**: quando un turno termina con un 401 o un 403 dall'API di Anthropic, il runner recupera da Anthropic un nuovo [`CLAUDE_CODE_OAUTH_TOKEN`](https://code.claude.com/docs/it/self-hosted-environments-configuration#wrapper-scripts) e lo passa alla sessione. Il turno fallito non viene ritentato. Questo token ha una durata breve e il runner lo ruota tramite lo stdin della sessione.840* **I turni falliscono con un 401**: quando un turno termina con un 401 o un 403 dall'API di Anthropic, il runner recupera da Anthropic un nuovo [`CLAUDE_CODE_OAUTH_TOKEN`](https://code.claude.com/docs/it/self-hosted-environments-configuration#wrapper-scripts) e lo passa alla sessione. Il turno fallito non viene ritentato. Questo token ha una durata breve e il runner lo ruota tramite lo stdin della sessione.
713 841
714 Quando un recupero fallisce, il runner registra una riga `inference_token refresh failed` che dice quando riproverà, e continua a riprovare finché la sessione è in esecuzione.842 Quando un recupero fallisce, il runner registra una riga `inference_token refresh failed` che dice quando riproverà, e continua a riprovare finché la sessione è in esecuzione.
788 916
789Per una diagnosi guidata sull'host del runner, eseguire il [subcommand doctor](#troubleshooting).917Per una diagnosi guidata sull'host del runner, eseguire il [subcommand doctor](#troubleshooting).
790 918
919### Una sessione viene presa in carico, ma Claude non risponde mai al primo messaggio
920
921Se un runner prende in carico una sessione ma Claude non risponde mai al primo messaggio, e i tuoi runner raggiungono `api.anthropic.com` attraverso un proxy, la causa potrebbe essere il proxy. Anthropic invia a una sessione i suoi messaggi tramite un'unica risposta in streaming che rimane aperta. Se il tuo proxy la mette in buffer, o la chiude prima di inoltrare qualcosa, il primo messaggio non arriva mai. Le altre richieste della sessione continuano a riuscire.
922
923Per risolvere, modifica il modo in cui il proxy gestisce questa richiesta:
924
925```text theme={null}
926GET https://api.anthropic.com/v1/code/sessions/<session-id>/worker/events/stream
927```
928
929* **Non mettere in buffer la risposta**: lasciala passare man mano che arriva. Il suo content type è `text/event-stream`.
930* **Lascia che la risposta resti aperta**: può restare aperta fino a un'ora. Se il proxy ha un timeout di inattività, mantienilo ben al di sopra di 15 secondi, perché per impostazione predefinita Anthropic invia un keep-alive almeno con quella frequenza.
931
932Poi avvia una nuova sessione e verifica che Claude risponda. Aumentare i timeout del runner non serve: attendi solo più a lungo prima che il runner arresti la sessione.
933
934#### Confermare la causa nel log del runner
935
936Questi passaggi valgono per i runner con Claude Code v2.1.287 o successivo, con il valore predefinito `--log-level info`. I runner meno recenti registrano queste righe più tardi, oppure non le registrano affatto.
937
9381. Attendi che trascorra [`--startup-timeout-min`](https://code.claude.com/docs/it/self-hosted-environments-reference#runner-cli-flags), 15 minuti per impostazione predefinita. Il runner arresta quindi la sessione e registra una riga che contiene `no child output for` e termina con `— releasing`.
9392. Cerca `SDKStartup: SSE` nel log del runner. Queste righe seguono una riga `finished: interrupted`, alcune righe dopo quella del passaggio 1. La maggior parte non ha un timestamp, quindi un raccoglitore di log potrebbe mostrarle altrove.
9403. Trova la riga in questa tabella:
941
942| La riga di log contiene | Cosa fare |
943| :- | :- |
944| `SSE connect failed (no response in 30s)` o `SSE liveness timeout` | Verifica che il proxy inoltri la richiesta, lasci passare le intestazioni e i dati della risposta man mano che arrivano e non interrompa la connessione |
945| `SSE connect failed (HTTP` e un codice di stato | Controlla il log del proxy stesso. Se il proxy ha risposto direttamente alla richiesta, lascia passare la richiesta attraverso di esso. |
946| `SSE connect failed (` e qualsiasi altro testo | Il testo tra parentesi è l'errore. Cerca la stessa connessione nel log del proxy stesso. |
947| `SSE stream ended by server`, ripetutamente | Controlla il limite di tempo del proxy per le risposte di lunga durata. Una singola riga di questo tipo è normale. |
948| `SSE reconnected after` | Cerca una delle altre righe dopo di essa. Questa riga non significa che qualcosa abbia raggiunto la sessione. |
949
950Se il log non contiene nessuna di queste righe, o il log del proxy non mostra nulla di anomalo, [segnala un problema](#report-an-issue).
951
952#### Impedire alla sessione di riprovare
953
954La sessione mantiene il messaggio in sospeso, e un runner che può servire il proprietario della sessione la prende di nuovo in carico. Finché non modifichi il proxy, la sessione resta in attesa nello stesso modo ogni volta. Per evitarlo, archivia la sessione in claude.ai/code.
955
791## Cosa c'è dopo956## Cosa c'è dopo
792 957
793* [Personalizza le sessioni](https://code.claude.com/docs/it/self-hosted-environments-configuration.md): script wrapper, lifecycle hook, runner on-demand, server MCP, e permessi958* [Personalizza le sessioni](https://code.claude.com/docs/it/self-hosted-environments-configuration.md): script wrapper, lifecycle hook, runner on-demand, server MCP, e permessi