313 313
314Para cada sessão que usa git gerenciada pela Anthropic, o runner também registra uma linha `[runner:warn]` que começa com `governed git: GIT_SSL_CAINFO is set` ou `governed git: GIT_SSL_NO_VERIFY is set`. A linha diz o que o runner fez com essa variável para seu próprio git, para git dentro da sessão, e para seus hooks de ciclo de vida. Ela termina com se você precisa alterar algo.314Para cada sessão que usa git gerenciada pela Anthropic, o runner também registra uma linha `[runner:warn]` que começa com `governed git: GIT_SSL_CAINFO is set` ou `governed git: GIT_SSL_NO_VERIFY is set`. A linha diz o que o runner fez com essa variável para seu próprio git, para git dentro da sessão, e para seus hooks de ciclo de vida. Ela termina com se você precisa alterar algo.
315 315
316### Adicione repositórios do github.com a sessões de canal do Claude Tag
317
318Se o Claude não conseguir adicionar um repositório do github.com a uma sessão de canal do Claude Tag, certifique-se de que o canal tem acesso a ele, mesmo quando seu runner consegue cloná-lo. Esse acesso vem de configurações no GitHub e em sua organização do Claude, não das credenciais git do seu runner.
319
320**1. Instale o Claude GitHub App**
321
322Instale o [Claude GitHub App](https://github.com/apps/claude) na organização ou conta do GitHub que é proprietária do repositório e inclua esse repositório na instalação.
323
324**2. Vincule a organização ou conta do GitHub**
325
326Em [**Organization settings > Git providers**](https://claude.ai/admin-settings/source-control), vincule essa organização ou conta à sua organização do Claude. Um Owner da sua organização do Claude que também seja proprietário da organização do GitHub pode vinculá-la. Consulte [Link your GitHub organization](https://claude.com/docs/claude-tag/admins/configure-github#link-your-github-organization).
327
328**3. Conceda o repositório**
329
330Nas [configurações de administrador do Claude Tag](https://claude.ai/admin-settings/claude-tag), conceda o repositório ao canal ou a um escopo mais amplo que inclua o canal: seu workspace do Slack ou todo o Slack. Alguém com a função Owner ou a permissão Claude Tag Admin pode concedê-lo. Um gerente de canal também pode adicioná-lo ao próprio canal se a conta do GitHub dele for administrador do repositório. Consulte [Grant repository access](https://claude.com/docs/claude-tag/admins/configure-github#grant-repository-access).
331
332Em seguida, inicie uma nova thread no canal e [nomeie o repositório](https://claude.com/docs/claude-tag/admins/configure-github#how-granted-repositories-reach-a-session) em sua primeira mensagem.
333
334Se o Claude ainda não conseguir adicionar o repositório, consulte [If Claude can't reach a repository](https://claude.com/docs/claude-tag/admins/configure-github#if-claude-can%E2%80%99t-reach-a-repository) para saber onde verificar o vínculo com o GitHub e a concessão do repositório.
335
316### Reescrever URLs git para redes privadas336### Reescrever URLs git para redes privadas
317 337
318URLs de repositório chegam do plano de controle como HTTPS, com o nome do host do seu host git; para GitHub Enterprise, esse é o nome do host que você configurou para a [integração GitHub Enterprise](https://code.claude.com/docs/pt/github-enterprise-server.md) em claude.ai. Duas flags repetíveis reescrevem essas URLs antes do clone:338URLs de repositório chegam do plano de controle como HTTPS, com o nome do host do seu host git; para GitHub Enterprise, esse é o nome do host que você configurou para a [integração GitHub Enterprise](https://code.claude.com/docs/pt/github-enterprise-server.md) em claude.ai. Duas flags repetíveis reescrevem essas URLs antes do clone:
376 396
377Builds e testes são geralmente a maior e mais variável parte da carga de uma sessão, então execute um build representativo de seu repositório, meça seu pico de CPU e memória, e aumente qualquer valor inicial que deixe sem espaço para o processo Claude Code no topo desse pico.397Builds e testes são geralmente a maior e mais variável parte da carga de uma sessão, então execute um build representativo de seu repositório, meça seu pico de CPU e memória, e aumente qualquer valor inicial que deixe sem espaço para o processo Claude Code no topo desse pico.
378 398
379O runner usa `--capacity` para limitar quantas sessões ele executa de uma vez. Ele não divide CPU ou memória entre elas, então as sessões em um runner compartilham a CPU e memória do contêiner. Para limitar a participação de uma sessão, aplique limites a partir de seu [script wrapper](https://code.claude.com/docs/pt/self-hosted-environments-configuration.md#wrapper-scripts). O que dar a um contêiner, portanto, depende de quantas sessões ele serve de uma vez:399O runner usa `--capacity` para limitar quantas sessões ele executa de uma vez. Ele não divide CPU ou memória entre elas, então as sessões em um runner compartilham a CPU e memória do contêiner. Para evitar que o uso de memória de uma sessão encerre as outras, execute uma sessão por runner com [seu próprio limite de memória](#give-each-session-its-own-memory-limit).
380 400
381* **Uma sessão por runner**: dê a cada contêiner os valores de uma sessão. Use este dimensionamento em `--capacity 1`, que a [seção de endurecimento](#harden-your-deployment) recomenda, e para [runners sob demanda](https://code.claude.com/docs/pt/self-hosted-environments-configuration.md#on-demand-runners), onde você define os valores na carga de trabalho que seu [hook `spawn-runner`](https://code.claude.com/docs/pt/self-hosted-environments-configuration#the-spawn-runner-hook) submete, como um modelo de pod de um Kubernetes Job.401* **Uma sessão por runner**: dê a cada contêiner os valores de uma sessão. Use este dimensionamento em `--capacity 1`, que a [seção de endurecimento](#harden-your-deployment) recomenda, e para [runners sob demanda](https://code.claude.com/docs/pt/self-hosted-environments-configuration.md#on-demand-runners), onde você define os valores na carga de trabalho que seu [hook `spawn-runner`](https://code.claude.com/docs/pt/self-hosted-environments-configuration#the-spawn-runner-hook) submete, como um modelo de pod de um Kubernetes Job.
382* **Várias sessões por runner**: em um `--capacity` acima de um, multiplique os valores de uma sessão pela capacidade, porque até muitas sessões podem ser executadas no contêiner ao mesmo tempo. As receitas [Kubernetes](#kubernetes) e [Docker Compose](#docker-compose) executam `--capacity 4` sem limites de CPU ou memória, então adicione limites dimensionados para a capacidade que você executa.402* **Várias sessões por runner**: em um `--capacity` acima de um, multiplique os valores de uma sessão pela capacidade, porque até muitas sessões podem ser executadas no contêiner ao mesmo tempo. As receitas [Kubernetes](#kubernetes) e [Docker Compose](#docker-compose) executam `--capacity 4` sem limites de CPU ou memória, então adicione limites dimensionados para a capacidade que você executa.
403* **Vários contêineres de runner em um host**: dimensione o host para a soma das capacidades dos runners, porque cada runner conta apenas suas próprias sessões em relação ao `--capacity`:
404
405 * **Memória**: multiplique a memória de uma sessão pela soma e, em seguida, adicione o que os próprios processos do host usam
406 * **CPU**: multiplique a requisição de CPU de uma sessão pela soma. Para permitir que todas as sessões explodam ao mesmo tempo, multiplique o limite de CPU em vez disso.
407
408 Dê a cada runner seu próprio contêiner. Use o [mesmo caminho `--base-dir`](#keep-the-base-directory-and-capacity-identical-across-runners) em cada um, em um armazenamento que nenhum outro contêiner de runner monte, para que cada runner tenha [seu próprio diretório de trabalho](#harden-your-deployment).
409
410### Dar a cada sessão seu próprio limite de memória
411
412Para impedir que uma sessão encerre as outras quando a memória se esgota, execute cada runner em `--capacity 1` sob seu próprio limite de memória, definido como a memória de uma sessão:
413
414* **Em um contêiner**: execute um runner por contêiner e defina o limite de memória do contêiner, como `limits.memory` no Kubernetes, `--memory` no Docker ou `mem_limit` em um arquivo Compose. Mantenha a soma dos limites dos contêineres abaixo da memória do host, porque quando o próprio host fica sem memória, o kernel pode matar processos em qualquer lugar do host.
415* **Sob systemd sem contêiner**: defina `MemoryMax` na unit do runner e execute um runner por host, porque runners que [usam o mesmo `--base-dir`](#keep-the-base-directory-and-capacity-identical-across-runners) em um sistema de arquivos compartilham os repositórios clonados ali. Por exemplo, em `--capacity 1` sem hook `checkout`, as sessões deles em um repositório podem trabalhar no mesmo checkout ao mesmo tempo. Para executar vários runners em um host, dê a cada um deles um contêiner.
416
417Quando um contêiner ou unit atinge seu limite de memória, o kernel mata processos apenas dentro dele. Se você definir `--capacity` acima de um, as sessões compartilham um único limite. Quando elas o atingem, o kernel não escolhe por sessão quais processos matar, então o uso de memória de uma sessão pode encerrar as outras.
418
419No Kubernetes, você não pode separar as sessões com nenhum dos valores da configuração `singleProcessOOMKill` do kubelet. Você também não pode limitar a memória total de uma sessão com um `ulimit` de memória em seu [script wrapper](https://code.claude.com/docs/pt/self-hosted-environments-configuration.md#wrapper-scripts). O kernel aplica um valor como `ulimit -v` a cada processo separadamente.
420
421### Deixar espaço sob os limites de processos e threads
422
423Para dimensionar um limite de processos e threads, meça o que uma sessão precisa e multiplique pelo número de sessões que compartilham o limite. Quando essas sessões atingem o limite, o kernel recusa novos processos e threads, então comandos, builds e testes em qualquer uma delas podem falhar. A chamada recusada retorna `EAGAIN`, cuja mensagem padrão é `Resource temporarily unavailable`.
424
425Suponha que uma sessão atinja um pico de 300 processos e threads, e que quatro sessões compartilhem o limite. Juntas, elas precisam de 1.200 e, com um limite de 2.400, você deixa espaço para builds que precisem do dobro.
426
427#### Onde definir cada limite
428
429Cada limite nesta tabela conta threads assim como processos, e `pids.max` é o arquivo que contém o limite de um cgroup:
430
431| Limite | Onde você o define | O que o compartilha |
432| :- | :- | :- |
433| `pids.max` no Kubernetes | `podPidsLimit` na configuração do kubelet dos nós que executam runners. Você não pode defini-lo em uma especificação de Pod. | Os contêineres de um Pod |
434| `pids.max` no Docker | `--pids-limit`, ou `pids_limit` em um arquivo Compose | Um contêiner |
435| `pids.max` sob systemd | `TasksMax` na unit do runner | Uma unit |
436| `ulimit -u` | O shell ou serviço que inicia o runner | Tudo no host que é executado com o ID de usuário do runner. Não é aplicado para root. |
437
438Quando você não define `TasksMax`, o systemd aplica `DefaultTasksMax`, cujo padrão é 15% do menor valor entre `kernel.pid_max`, `kernel.threads-max` e o `pids.max` do cgroup raiz.
439
440#### Medir o pico de uma sessão
441
442Para obter os números para seus próprios runners, meça uma sessão em seu host, que no Kubernetes é o nó:
443
444**1. Inicie um runner isoladamente**
445
446Inicie um runner em `--capacity 1` sem mais nada em seu contêiner ou unit do systemd, sozinho em seu host e em seu ambiente:
447
448* **Seu host**: use um que não execute nenhum outro runner. Assim você poderá identificar o processo dele na próxima etapa.
449* **Seu ambiente**: faça dele o único runner ali, por exemplo em um ambiente que você [cria para o teste](https://code.claude.com/docs/pt/self-hosted-environments-quickstart.md#set-up-manually). As sessões são roteadas para um ambiente, e não para um runner.
450
451Não inicie uma sessão ainda, porque você precisa do diretório da próxima etapa antes que o build comece.
452
453**2. Encontre o diretório cgroup do runner**
454
455No host, não dentro do contêiner, encontre o ID do processo do runner, por exemplo com `ps`. Leia `/proc/<pid>/cgroup` para esse ID:
456
457* **Uma linha contém `:pids:`**: o host usa cgroup v1, e o diretório é `/sys/fs/cgroup/pids` seguido do texto após `:pids:`
458* **A única linha começa com `0::`**: o host usa cgroup v2, e o diretório é `/sys/fs/cgroup` seguido do texto após `0::`
459
460**3. Execute um build representativo e registre o pico**
461
462Execute uma sessão durante um build representativo e obtenha o pico a partir do diretório cgroup do runner:
463
464* **O diretório tem `pids.peak`**: leia o arquivo após o término do build
465* **O diretório não tem `pids.peak`**: leia `pids.current` uma vez por segundo enquanto o build é executado e guarde o valor mais alto. Um pico entre duas leituras passa despercebido, então trate esse valor como uma estimativa baixa.
466
467**4. Multiplique pelas sessões que compartilham o limite**
468
469* **O Pod, contêiner ou unit de um runner**: multiplique o pico pelo `--capacity` do runner
470* **Um limite que vários runners compartilham**: multiplique o pico pela soma de suas capacidades
471
472Em seguida, adicione o pico de qualquer outra coisa que compartilhe o limite, como outro contêiner no Pod.
473
474**5. Defina o limite acima do resultado**
475
476Com um limite mais alto, você deixa espaço para builds mais pesados e, com um mais baixo, você interrompe uma fork bomb mais cedo.
477
478#### Verificar um limite `pids.max`
479
480* **Verifique se `pids.max` foi atingido**: pesquise no log do kernel do host, por exemplo com `dmesg`, uma linha que contenha `cgroup: fork rejected by pids controller in` e o caminho de um cgroup. O kernel a registra em log apenas na primeira vez que recusa um processo ou thread nesse cgroup, então pesquise o log inteiro.
481* **Veja o limite em vigor**: leia `pids.max` no diretório cgroup do runner e em cada diretório acima dele. O menor valor é o limite em vigor, e `max` significa nenhum limite nesse nível.
383 482
384## Kubernetes483## Kubernetes
385 484
577 676
578O que o caminho de reutilização faz e não garante:677O que o caminho de reutilização faz e não garante:
579 678
580* **Qualquer forma de clone funciona**: um clone completo, raso, ou de um único branch no caminho é usado como está. O runner nunca passa `--depth` ao buscar em um clone existente, então um pré-aquecimento completo mantém seu histórico completo e um raso permanece raso. `CLAUDE_RUNNER_FETCH_DEPTH` (`full`, `0`, ou um número; padrão 50) controla apenas o clone frio que o runner faz quando nenhum clone existe ainda.679* **Profundidade do clone**: crie o clone sem `--depth`, com ou sem `--single-branch`. O runner nunca passa `--depth` ao buscar em um clone com um remote `origin`, mesmo que você defina [`CLAUDE_RUNNER_FETCH_DEPTH`](https://code.claude.com/docs/pt/self-hosted-environments-reference#environment-variable-only-settings). Com um clone completo, cada sessão baixa apenas os commits que faltam ao clone. Com um clone raso, uma sessão em um branch que divergiu antes do commit mais antigo do clone baixa todo o histórico desse branch.
581* **Mudanças rastreadas redefinem, arquivos não rastreados persistem**: em `--capacity 1`, cada sessão começa a partir de uma redefinição dura que limpa as modificações rastreadas da sessão anterior, mas o runner nunca executa `git clean`, então arquivos não rastreados das sessões anteriores do owner bloqueado permanecem na árvore.680* **Mudanças rastreadas redefinem, arquivos não rastreados persistem**: em `--capacity 1`, cada sessão começa a partir de uma redefinição dura que limpa as modificações rastreadas da sessão anterior, mas o runner nunca executa `git clean`, então arquivos não rastreados das sessões anteriores do owner bloqueado permanecem na árvore.
582* **Diretórios por sessão também persistem**: ao lado do checkout, o runner cria entradas por sessão sob `<base-dir>/_sessions/` para cada sessão que executa. O diretório de configuração Claude da sessão contém uma cópia local da transcrição da conversa. Ao lado dele ficam os arquivos carregados da sessão, quando a sessão tem algum. O diretório da sessão também fica lá: ele contém quaisquer worktrees por sessão e checkouts do hook `checkout` enquanto a sessão é executada, e mantém tudo mais que Claude escreveu nele.681* **Diretórios por sessão também persistem**: ao lado do checkout, o runner cria entradas por sessão sob `<base-dir>/_sessions/` para cada sessão que executa. O diretório de configuração Claude da sessão contém uma cópia local da transcrição da conversa. Ao lado dele ficam os arquivos carregados da sessão, quando a sessão tem algum. O diretório da sessão também fica lá: ele contém quaisquer worktrees por sessão e checkouts do hook `checkout` enquanto a sessão é executada, e mantém tudo mais que Claude escreveu nele.
583 682
587* **Com o proxy git, um pré-aquecimento `reftable` perde suas refs**: quando o runner sanitiza o `.git/` antes de cada sessão, ele mantém `.git/refs/` e remove o diretório `.git/reftable/`. Um clone pré-aquecido no formato de ref `reftable` do git perde suas refs dessa forma, então pré-aqueça o clone no formato de ref `files` do git.686* **Com o proxy git, um pré-aquecimento `reftable` perde suas refs**: quando o runner sanitiza o `.git/` antes de cada sessão, ele mantém `.git/refs/` e remove o diretório `.git/reftable/`. Um clone pré-aquecido no formato de ref `reftable` do git perde suas refs dessa forma, então pré-aqueça o clone no formato de ref `files` do git.
588* **Clones longos não precisam de workaround**: o runner limita cada operação git com um watchdog de 120 segundos sem progresso e um limite duro de 30 minutos, não um tempo limite fixo, então um clone frio lento que continua relatando progresso é concluído.687* **Clones longos não precisam de workaround**: o runner limita cada operação git com um watchdog de 120 segundos sem progresso e um limite duro de 30 minutos, não um tempo limite fixo, então um clone frio lento que continua relatando progresso é concluído.
589 688
689### Confirmar que o runner usa seu clone
690
691Para confirmar que o runner usa seu clone, inicie-o com [`--log-level debug`](https://code.claude.com/docs/pt/self-hosted-environments-reference#runner-cli-flags) e inicie uma sessão no repositório. O runner registra em log `Prefetched repo found at` e o caminho do clone. Se, em vez disso, ele registrar `No prefetched repo, fresh init at`, não encontrou nenhum clone utilizável no caminho indicado nessa linha. Verifique se seu clone está nesse caminho, pertence ao usuário do runner e tem um remote chamado `origin`.
692
693Se o runner encontrar seu clone e as sessões ainda iniciarem lentamente, verifique se o clone é raso.
694
590## Pin the version695## Pin the version
591 696
592O processo filho de cada sessão executa o próprio binário do runner por padrão, e o runner desativa auto-update dentro das sessões que gera. Com esse padrão, cada sessão executa a versão que você instalou no host ou incluiu no build da imagem. Uma atualização no nível do host entra em vigor na próxima vez que o runner inicia.697O processo filho de cada sessão executa o próprio binário do runner por padrão, e o runner desativa auto-update dentro das sessões que gera. Com esse padrão, cada sessão executa a versão que você instalou no host ou incluiu no build da imagem. Uma atualização no nível do host entra em vigor na próxima vez que o runner inicia.
609* **Frota fixa**: execute um conjunto estático de réplicas de runner e dimensione nas [métricas Prometheus](https://code.claude.com/docs/pt/self-hosted-environments-reference.md#prometheus-metrics) que cada runner serve714* **Frota fixa**: execute um conjunto estático de réplicas de runner e dimensione nas [métricas Prometheus](https://code.claude.com/docs/pt/self-hosted-environments-reference.md#prometheus-metrics) que cada runner serve
610* **Runners sob demanda**: execute o subcomando `claude self-hosted-runner orchestrator`, que faz polling na Anthropic para sessões que estão enfileiradas sem runner disponível e invoca seu hook `spawn-runner` para iniciar um por sessão. Consulte [Runners sob demanda](https://code.claude.com/docs/pt/self-hosted-environments-configuration.md#on-demand-runners).715* **Runners sob demanda**: execute o subcomando `claude self-hosted-runner orchestrator`, que faz polling na Anthropic para sessões que estão enfileiradas sem runner disponível e invoca seu hook `spawn-runner` para iniciar um por sessão. Consulte [Runners sob demanda](https://code.claude.com/docs/pt/self-hosted-environments-configuration.md#on-demand-runners).
611 716
717### Liberar sessões ociosas em uma frota fixa
718
719Se as sessões permanecerem enfileiradas em uma frota fixa enquanto todos os runners estão online, sessões ociosas podem ser a causa. Por padrão, uma sessão mantém seu slot depois que seu turno termina, e seu runner permanece bloqueado para o [owner](https://code.claude.com/docs/pt/self-hosted-environments#key-concepts) dessa sessão. Se a [tarefa agendada na nuvem](https://code.claude.com/docs/pt/routines.md) da sua equipe inicia uma nova sessão a cada execução, suas sessões ociosas podem ocupar todos os slots.
720
721Para verificar, leia `claude_code_self_hosted_runner_session_idle_seconds` nas [métricas Prometheus](https://code.claude.com/docs/pt/self-hosted-environments-reference.md#prometheus-metrics) de cada runner. Cada sessão que um runner mantém tem sua própria série: `0` enquanto a sessão está ocupada; caso contrário, os segundos desde que ela ficou ociosa. Escolha o tempo ocioso que você permitiria: mais longo do que as pausas que as pessoas fazem no meio de uma tarefa, e curto o suficiente para que cada execução seja liberada antes que a próxima execução da tarefa agendada comece. Compare as séries com ele.
722
723* **Séries acima desse tempo, como `1800` para 30 minutos**: sessões ociosas mantêm esses slots, então defina `--release-idle-session-min`
724* **Todas as séries abaixo dele**: nenhuma sessão ficou ociosa por tanto tempo. Adicione runners ou defina [`--kill-session-after-min`](https://code.claude.com/docs/pt/self-hosted-environments-reference#runner-cli-flags) para [sessões que nunca ficam ociosas](#some-sessions-don’t-count-as-idle).
725* **Um runner sem séries**: nenhuma sessão o mantém. Consulte **As sessões permanecem enfileiradas** em [Solução de problemas](#troubleshooting).
726* **Um runner cujas métricas não respondem**: seu processo pode ter sido encerrado. Consulte **Um ambiente que parece saudável** em [Quando o runner é encerrado](#when-the-runner-exits).
727
728Para liberar sessões ociosas, inicie todos os runners com [`--release-idle-session-min`](https://code.claude.com/docs/pt/self-hosted-environments-reference#runner-cli-flags) e esse tempo em minutos, como `--release-idle-session-min 30`. O runner então libera qualquer sessão que permaneça ociosa por esse tempo, seja ela iniciada por uma tarefa agendada ou por uma pessoa.
729
730* **Trabalho não enviado**: uma sessão liberada é retomada na sua próxima mensagem, sem o trabalho que ela não havia enviado com push. Para manter seus commits, consulte [Sessões retomadas perdem trabalho não enviado](#additional-limitations).
731* **Encerramento do runner**: um runner que libera sua última sessão inicia um [encerramento normal](#when-the-runner-exits). Faça com que seu supervisor o reinicie em um sistema de arquivos novo, conforme descrito em [Proteja sua implantação](#harden-your-deployment).
732* **Sessões que nunca ficam ociosas**: defina também [`--kill-session-after-min`](https://code.claude.com/docs/pt/self-hosted-environments-reference#runner-cli-flags), porque [algumas sessões não contam como ociosas](#some-sessions-don’t-count-as-idle)
733
612## Problemas conhecidos e limitações734## Problemas conhecidos e limitações
613 735
614As seguintes são as limitações nesta versão, com workarounds onde um existe.736As seguintes são as limitações nesta versão, com workarounds onde um existe.
642### Limitações adicionais764### Limitações adicionais
643 765
644* **Sessões retomadas perdem trabalho não enviado**: um runner novo clona o repositório novamente a partir de seu branch inicial, então o trabalho que a sessão não tinha enviado se foi.766* **Sessões retomadas perdem trabalho não enviado**: um runner novo clona o repositório novamente a partir de seu branch inicial, então o trabalho que a sessão não tinha enviado se foi.
645 * **Para manter trabalho com commit**: defina [`--push-outcome-on-release`](https://code.claude.com/docs/pt/self-hosted-environments-reference#runner-cli-flags) em todos os runners do ambiente, porque um runner sem a flag retoma a sessão a partir de seu branch inicial. Um runner com a flag faz um push de melhor esforço dos branches de resultado da sessão antes de liberá-la, e a sessão retomada começa a partir desses commits. O push usa as próprias credenciais git do host do runner, inclusive em um runner que usa [git gerenciado pela Anthropic](#use-the-anthropic-git-proxy). Alterações sem commit ainda são perdidas.767 * **Para manter trabalho com commit**: defina [`--push-outcome-on-release`](https://code.claude.com/docs/pt/self-hosted-environments-reference#runner-cli-flags) em todos os runners do ambiente, porque um runner sem a flag retoma a sessão a partir de seu branch inicial. Um runner com a flag faz um push de melhor esforço dos branches de resultado da sessão antes de liberá-la, e a sessão retomada começa a partir desses commits. O push usa as próprias credenciais git do host do runner, inclusive em um runner que usa [git gerenciado pela Anthropic](#use-the-anthropic-git-proxy).
646 * **Com um hook `checkout`**: repositórios obtidos por meio de um [hook de ciclo de vida `checkout`](https://code.claude.com/docs/pt/self-hosted-environments-configuration#checkout) não recebem push. Em vez disso, faça um snapshot deles a partir do [hook `post-session`](https://code.claude.com/docs/pt/self-hosted-environments-configuration#post-session).768 * **Com um hook `checkout`**: repositórios obtidos por meio de um [hook de ciclo de vida `checkout`](https://code.claude.com/docs/pt/self-hosted-environments-configuration#checkout) não recebem push. Em vez disso, faça um snapshot deles a partir do [hook `post-session`](https://code.claude.com/docs/pt/self-hosted-environments-configuration#post-session).
647 * **Antes de habilitar a flag**: restrinja quem pode fazer push para refs `claude/*` no remoto de origem. Na retomada, o runner busca o branch previamente enviado sem verificar quem o enviou.769 * **Antes de habilitar a flag**: restrinja quem pode fazer push para refs `claude/*` no remoto de origem. Na retomada, o runner busca o branch previamente enviado sem verificar quem o enviou.
770 * **Alterações sem commit ainda são perdidas**: para solicitar que Claude faça commit e push quando terminar de responder, consulte [Solicitar que as sessões enviem seu trabalho](https://code.claude.com/docs/pt/self-hosted-environments-configuration.md#prompt-sessions-to-push-their-work)
648* **Um repositório adicionado no meio da sessão pode falhar ao ser clonado**: Claude o clona com `git clone` via HTTPS. Em um runner sem [`--use-anthropic-git-proxy`](#use-the-anthropic-git-proxy), o clone falha com um erro de autenticação do git se nada no host puder ler o repositório. Sempre que possível, selecione cada repositório que a sessão precisa quando você a cria.771* **Um repositório adicionado no meio da sessão pode falhar ao ser clonado**: Claude o clona com `git clone` via HTTPS. Em um runner sem [`--use-anthropic-git-proxy`](#use-the-anthropic-git-proxy), o clone falha com um erro de autenticação do git se nada no host puder ler o repositório. Sempre que possível, selecione cada repositório que a sessão precisa quando você a cria.
649* **Alguns conectores não aparecem em sessões auto-hospedadas**: um conector que você ainda não conectou nas Configurações do claude.ai não está listado em uma sessão auto-hospedada, e a sessão não o solicitará para conectar. Conecte-o nas Configurações primeiro, depois inicie uma sessão fresca. Adicionar um conector a uma sessão já em execução também não torna suas ferramentas disponíveis para Claude; inicie uma sessão fresca para pegar um conector recém-adicionado.772* **Alguns conectores não aparecem em sessões auto-hospedadas**: um conector que você ainda não conectou nas Configurações do claude.ai não está listado em uma sessão auto-hospedada, e a sessão não o solicitará para conectar. Conecte-o nas Configurações primeiro, depois inicie uma sessão fresca. Adicionar um conector a uma sessão já em execução também não torna suas ferramentas disponíveis para Claude; inicie uma sessão fresca para pegar um conector recém-adicionado.
650* **Quando alguém arquiva ou exclui uma sessão, ou libera seu runner a partir do menu da sessão**: não conte com o push de [`--push-outcome-on-release`](https://code.claude.com/docs/pt/self-hosted-environments-reference#runner-cli-flags). Para salvar commits nesses casos, faça push de `HEAD` para um branch de resgate a partir de um [hook `post-session`](https://code.claude.com/docs/pt/self-hosted-environments-configuration#post-session). Se você partir do exemplo ali, faça-o fazer push mesmo quando não houver nada sem commit, porque ele faz push apenas após um commit de snapshot.773* **Quando alguém arquiva ou exclui uma sessão, ou libera seu runner a partir do menu da sessão**: não conte com o push de [`--push-outcome-on-release`](https://code.claude.com/docs/pt/self-hosted-environments-reference#runner-cli-flags). Para salvar commits nesses casos, faça push de `HEAD` para um branch de resgate a partir de um [hook `post-session`](https://code.claude.com/docs/pt/self-hosted-environments-configuration#post-session). Se você partir do exemplo ali, faça-o fazer push mesmo quando não houver nada sem commit, porque ele faz push apenas após um commit de snapshot.
684* **As sessões falham imediatamente após a coleta**: abra a sessão em claude.ai/code para ver o erro. Se o erro mostrar que o git não conseguiu se autenticar, verifique as [credenciais git](#configure-git) do runner. Em um runner iniciado com `--use-anthropic-git-proxy`, consulte [Quando as sessões não iniciam em um runner com o proxy git](#when-anthropic-doesnt-serve-a-session).807* **As sessões falham imediatamente após a coleta**: abra a sessão em claude.ai/code para ver o erro. Se o erro mostrar que o git não conseguiu se autenticar, verifique as [credenciais git](#configure-git) do runner. Em um runner iniciado com `--use-anthropic-git-proxy`, consulte [Quando as sessões não iniciam em um runner com o proxy git](#when-anthropic-doesnt-serve-a-session).
685 808
686 Um diretório base não gravável interrompe o runner na inicialização em vez de fazer as sessões falharem. Consulte a entrada **O runner sai na inicialização com `cannot create or write to base directory`** nesta lista.809 Um diretório base não gravável interrompe o runner na inicialização em vez de fazer as sessões falharem. Consulte a entrada **O runner sai na inicialização com `cannot create or write to base directory`** nesta lista.
810* **Uma sessão é coletada, mas o Claude nunca responde à primeira mensagem**: se seus runners alcançam `api.anthropic.com` através de um proxy, configure-o para repassar a resposta `/worker/events/stream` da sessão à medida que ela chega. Aumentar os timeouts do runner não ajuda. Para confirmar a causa no log do runner, consulte [Uma sessão é coletada, mas o Claude nunca responde à primeira mensagem](#when-a-sessions-first-message-is-never-answered).
687* **As sessões não iniciam em um runner que definiu `--use-anthropic-git-proxy`**: procure no log do runner por `access denied by the git proxy`, ou por um erro do git que mencione um endereço de `api.anthropic.com` contendo `/git_proxy/`. Para saber se a Anthropic atendeu a sessão e corrigir a causa, consulte [Quando as sessões não iniciam em um runner com o proxy git](#when-anthropic-doesnt-serve-a-session).811* **As sessões não iniciam em um runner que definiu `--use-anthropic-git-proxy`**: procure no log do runner por `access denied by the git proxy`, ou por um erro do git que mencione um endereço de `api.anthropic.com` contendo `/git_proxy/`. Para saber se a Anthropic atendeu a sessão e corrigir a causa, consulte [Quando as sessões não iniciam em um runner com o proxy git](#when-anthropic-doesnt-serve-a-session).
688* **Sessions can't reach the network through an authenticating egress proxy**: quando a fonte que você definiu com [`--proxy-authorization-command` ou `--proxy-authorization-file`](#authenticate-to-an-egress-proxy) falha, expira após 30 segundos ou produz um valor vazio, o runner responde essa conexão com `502 Bad Gateway` e registra o motivo. O runner redige o stderr do comando nesse log e nunca registra o valor do cabeçalho. Com `--proxy-authorization-command`, execute o comando você mesmo no host para confirmar que ele imprime o valor do cabeçalho inteiro em stdout. Se o runner sair na inicialização com `could not start the proxy-authorization listener`, ele não conseguiu abrir seu listener de loopback.812* **Sessions can't reach the network through an authenticating egress proxy**: quando a fonte que você definiu com [`--proxy-authorization-command` ou `--proxy-authorization-file`](#authenticate-to-an-egress-proxy) falha, expira após 30 segundos ou produz um valor vazio, o runner responde essa conexão com `502 Bad Gateway` e registra o motivo. O runner redige o stderr do comando nesse log e nunca registra o valor do cabeçalho. Com `--proxy-authorization-command`, execute o comando você mesmo no host para confirmar que ele imprime o valor do cabeçalho inteiro em stdout. Se o runner sair na inicialização com `could not start the proxy-authorization listener`, ele não conseguiu abrir seu listener de loopback.
689* **O runner registra linhas `Poll failed` contendo `rejecting the malformed poll response`**: o runner recebeu uma resposta de work-poll cujo corpo não é o JSON esperado da fila. Uma causa é um proxy interceptador ou um portal cativo respondendo com sua própria página. Se o runner se conecta através de um proxy, configure o proxy para passar as respostas de `api.anthropic.com` inalteradas.813* **O runner registra linhas `Poll failed` contendo `rejecting the malformed poll response`**: o runner recebeu uma resposta de work-poll cujo corpo não é o JSON esperado da fila. Uma causa é um proxy interceptador ou um portal cativo respondendo com sua própria página. Se o runner se conecta através de um proxy, configure o proxy para passar as respostas de `api.anthropic.com` inalteradas.
708* **Uma sessão não inicia com `This runner couldn't read`**: o runner solicitou um repositório ao host git com suas [credenciais git](#configure-git) e recebeu uma resposta de não encontrado. O repositório não existe, ou essas credenciais não conseguem alcançar o repositório.832* **Uma sessão não inicia com `This runner couldn't read`**: o runner solicitou um repositório ao host git com suas [credenciais git](#configure-git) e recebeu uma resposta de não encontrado. O repositório não existe, ou essas credenciais não conseguem alcançar o repositório.
709 * **Se você administra o runner**: conceda às credenciais git dele acesso de leitura ao repositório e, em seguida, inicie uma nova sessão.833 * **Se você administra o runner**: conceda às credenciais git dele acesso de leitura ao repositório e, em seguida, inicie uma nova sessão.
710 * **Se você iniciou a sessão**: se o repositório não existir, inicie uma nova sessão com o repositório correto. Se o runner não conseguir alcançar o repositório, peça ao administrador do runner que conceda acesso e, em seguida, inicie uma nova sessão.834 * **Se você iniciou a sessão**: se o repositório não existir, inicie uma nova sessão com o repositório correto. Se o runner não conseguir alcançar o repositório, peça ao administrador do runner que conceda acesso e, em seguida, inicie uma nova sessão.
711* **Sessions take minutes to start**: o clone inicial geralmente domina. Observe a métrica `claude_code_self_hosted_runner_session_init_duration_seconds` [metric](https://code.claude.com/docs/pt/self-hosted-environments-reference.md#prometheus-metrics) para confirmar e corte o clone com um [pre-warmed checkout](#reuse-a-pre-warmed-checkout) ou um `CLAUDE_RUNNER_FETCH_DEPTH` menor.835* **As sessões levam minutos para iniciar ou retomar**: uma causa é um clone novo. Em uma frota que inicia cada runner em um disco vazio, sem [hook `checkout`](https://code.claude.com/docs/pt/self-hosted-environments-configuration#checkout), o runner clona os repositórios da sessão do zero antes de iniciar o Claude Code. Uma sessão que é retomada em um disco vazio aguarda o mesmo clone novamente.
836
837 Para evitar o clone novo, forneça um [checkout pré-aquecido](#reuse-a-pre-warmed-checkout). Se você já fornece um, [confirme que o runner o usa](#confirm-that-the-runner-uses-your-clone). Onde o próprio runner faz o clone e sai após uma sessão, reduza [`CLAUDE_RUNNER_FETCH_DEPTH`](https://code.claude.com/docs/pt/self-hosted-environments-reference#environment-variable-only-settings) do seu padrão de 50 commits para buscar menos histórico.
838
839 Se você usa um hook, ele é executado no lugar do clone do runner, então verifique o que seu hook faz. Observe a [métrica](https://code.claude.com/docs/pt/self-hosted-environments-reference.md#prometheus-metrics) `claude_code_self_hosted_runner_session_init_duration_seconds` para ver quanto tempo os inícios levam.
712* **Os turnos falham com um 401**: quando um turno termina com um 401 ou 403 da API da Anthropic, o runner busca um [`CLAUDE_CODE_OAUTH_TOKEN`](https://code.claude.com/docs/pt/self-hosted-environments-configuration#wrapper-scripts) novo da Anthropic e o passa para a sessão. O turno com falha não é tentado novamente. Esse token é de curta duração, e o runner o rotaciona pelo stdin da sessão.840* **Os turnos falham com um 401**: quando um turno termina com um 401 ou 403 da API da Anthropic, o runner busca um [`CLAUDE_CODE_OAUTH_TOKEN`](https://code.claude.com/docs/pt/self-hosted-environments-configuration#wrapper-scripts) novo da Anthropic e o passa para a sessão. O turno com falha não é tentado novamente. Esse token é de curta duração, e o runner o rotaciona pelo stdin da sessão.
713 841
714 Quando uma busca falha, o runner registra uma linha `inference_token refresh failed` que diz quando tentará novamente, e continua tentando novamente enquanto a sessão estiver em execução.842 Quando uma busca falha, o runner registra uma linha `inference_token refresh failed` que diz quando tentará novamente, e continua tentando novamente enquanto a sessão estiver em execução.
788 916
789Para diagnóstico orientado no host do runner, execute o [subcomando doctor](#troubleshooting).917Para diagnóstico orientado no host do runner, execute o [subcomando doctor](#troubleshooting).
790 918
919### Uma sessão é coletada, mas o Claude nunca responde à primeira mensagem
920
921Se um runner coleta uma sessão, mas o Claude nunca responde à primeira mensagem, e seus runners alcançam `api.anthropic.com` através de um proxy, o proxy pode ser a causa. A Anthropic envia a uma sessão suas mensagens por uma única resposta de streaming que permanece aberta. Se seu proxy a armazena em buffer, ou a encerra antes de repassar qualquer coisa, a primeira mensagem nunca chega. Outras requisições da sessão ainda são bem-sucedidas.
922
923Para corrigir, altere como o proxy trata esta requisição:
924
925```text theme={null}
926GET https://api.anthropic.com/v1/code/sessions/<session-id>/worker/events/stream
927```
928
929* **Não armazene a resposta em buffer**: repasse-a à medida que ela chega. Seu tipo de conteúdo é `text/event-stream`.
930* **Deixe a resposta permanecer aberta**: ela pode ficar aberta por até uma hora. Se o proxy tiver um timeout de inatividade, mantenha-o bem acima de 15 segundos, porque a Anthropic envia um keep-alive pelo menos com essa frequência por padrão.
931
932Em seguida, inicie uma nova sessão e verifique se o Claude responde. Aumentar os timeouts do runner não ajuda: você apenas espera mais antes que o runner interrompa a sessão.
933
934#### Confirme a causa no log do runner
935
936Estas etapas são para runners no Claude Code v2.1.287 ou posterior, no `--log-level info` padrão. Runners mais antigos registram essas linhas mais tarde, ou não as registram.
937
9381. Aguarde [`--startup-timeout-min`](https://code.claude.com/docs/pt/self-hosted-environments-reference#runner-cli-flags) passar, 15 minutos por padrão. O runner então interrompe a sessão e registra uma linha que contém `no child output for` e termina com `— releasing`.
9392. Pesquise no log do runner por `SDKStartup: SSE`. Essas linhas vêm depois de uma linha `finished: interrupted`, algumas linhas após a da etapa 1. A maioria não tem timestamp, então um coletor de logs pode exibi-las em outro lugar.
9403. Encontre a linha nesta tabela:
941
942| A linha de log contém | O que fazer |
943| :- | :- |
944| `SSE connect failed (no response in 30s)` ou `SSE liveness timeout` | Verifique se o proxy encaminha a requisição, repassa os cabeçalhos e os dados da resposta à medida que chegam e não derruba a conexão |
945| `SSE connect failed (HTTP` e um código de status | Verifique o próprio log do proxy. Se o próprio proxy respondeu à requisição, deixe a requisição passar por ele. |
946| `SSE connect failed (` e qualquer outro texto | O texto entre parênteses é o erro. Procure a mesma conexão no próprio log do proxy. |
947| `SSE stream ended by server`, repetidamente | Verifique o limite de tempo do proxy para respostas de longa duração. Uma única linha desse tipo é normal. |
948| `SSE reconnected after` | Procure uma das outras linhas depois dela. Esta não significa que algo chegou à sessão. |
949
950Se o log não tiver nenhuma dessas linhas, ou o log do proxy não mostrar nada de errado, [relate um problema](#report-an-issue).
951
952#### Impeça que a sessão tente novamente
953
954A sessão mantém a mensagem pendente, e um runner que pode atender o proprietário da sessão coleta a sessão novamente. Até que você altere o proxy, a sessão aguarda da mesma forma a cada vez. Para impedir isso, arquive a sessão em claude.ai/code.
955
791## O que vem a seguir956## O que vem a seguir
792 957
793* [Customize sessions](https://code.claude.com/docs/pt/self-hosted-environments-configuration.md): wrapper scripts, lifecycle hooks, on-demand runners, MCP servers, and permissions958* [Customize sessions](https://code.claude.com/docs/pt/self-hosted-environments-configuration.md): wrapper scripts, lifecycle hooks, on-demand runners, MCP servers, and permissions