119 119
120## Настройка git120## Настройка git
121 121
122Раннер управляет извлечением репозиториев, но по умолчанию не настраивает идентификацию или учётные данные git. Вы контролируете образ раннера и окружение его процесса, поэтому конфигурация git тоже в ваших руках. Выберите один из двух подходов:122Раннер управляет извлечением репозиториев, но по умолчанию не настраивает идентичность git и учётные данные. Вы контролируете образ раннера и окружение его процесса, а значит, и конфигурацию git. Выберите один из двух подходов:
123 123
124* **Позвольте раннеру настроить git**: запустите раннер с `--configure-git`, чтобы он записал ту же конфигурацию идентификации и подписи коммитов, что используют сессии, размещённые Anthropic124* **Позволить раннеру настроить git**: запустите раннер с `--configure-git`, чтобы он записал ту же конфигурацию идентичности и подписи коммитов, что используется в сессиях, размещённых Anthropic
125* **Поставляйте конфигурацию git в своём образе**: задайте идентификацию и учётные данные для push самостоятельно, например чтобы делать коммиты от имени собственного бота125* **Поставлять конфигурацию git в образе**: задайте идентичность и учётные данные для push самостоятельно, например чтобы делать коммиты от имени собственного бота
126 126
127Для репозиториев на github.com также можно запустить раннер с [`--use-anthropic-git-proxy`](#use-the-anthropic-git-proxy) или задать `CLAUDE_RUNNER_USE_GIT_PROXY=1`, чтобы попросить Anthropic обслуживать git для сессий раннера.127Для репозиториев на github.com также можно запустить раннер с [`--use-anthropic-git-proxy`](#use-the-anthropic-git-proxy) или задать `CLAUDE_RUNNER_USE_GIT_PROXY=1`, чтобы попросить Anthropic обслуживать git для сессий раннера.
128 128
129Минимальные версии Git на хосте раннера: для подписи коммитов через SSH с [`--configure-git`](#let-the-runner-configure-git) требуется Git 2.34 или новее, для [`--use-anthropic-git-proxy`](#use-the-anthropic-git-proxy) — 2.32 или новее, а для возобновления сессий из веток, отправленных с помощью [`--push-outcome-on-release`](https://code.claude.com/docs/ru/self-hosted-environments-reference#runner-cli-flags), — 2.29 или новее. Git 2.24 достаточно, если вы не используете ни одну из этих трёх возможностей и управляете идентификацией git самостоятельно.129Минимальные версии Git на хосте раннера: подпись коммитов по SSH с [`--configure-git`](#let-the-runner-configure-git) требует Git 2.34 или новее, [`--use-anthropic-git-proxy`](#use-the-anthropic-git-proxy) требует 2.32 или новее, а возобновление сессий из веток, отправленных с помощью [`--push-outcome-on-release`](https://code.claude.com/docs/ru/self-hosted-environments-reference#runner-cli-flags), требует 2.29 или новее. Git 2.24 достаточно, если вы не используете ни одну из этих трёх возможностей и управляете идентичностью git самостоятельно.
130 130
131### Позвольте раннеру настроить git131### Позволить раннеру настроить git
132 132
133Запустите раннер с `--configure-git` или задайте `SELF_HOSTED_RUNNER_CONFIGURE_GIT=1`, чтобы при запуске он записал глобальную конфигурацию git:133Запустите раннер с `--configure-git` или задайте `SELF_HOSTED_RUNNER_CONFIGURE_GIT=1`, чтобы при запуске он записал глобальную конфигурацию git:
134 134
135* `user.name = Claude` и `user.email = noreply@anthropic.com`, как в сессиях, размещённых Anthropic135* `user.name = Claude` и `user.email = noreply@anthropic.com`, как в сессиях, размещённых Anthropic
136* Подпись коммитов и тегов в формате SSH, проходящая через управляемую раннером прослойку, которая подписывает каждый коммит через сервис подписи Anthropic с использованием собственных учётных данных сессии. Подписи можно проверить на GitHub по опубликованному ключу подписи SSH от Anthropic.136* Подпись коммитов и тегов в формате SSH через управляемую раннером прослойку, которая подписывает каждый коммит через сервис подписи Anthropic с использованием собственных учётных данных сессии. Подписи проверяются на GitHub по опубликованному ключу подписи SSH от Anthropic.
137* `push.negotiate = true`, чтобы перед упаковкой push git спрашивал у вашего git-хостинга, какие коммиты у него уже есть. Требуется Claude Code v2.1.257 или новее.137* `push.negotiate = true`, чтобы перед упаковкой push git спрашивал у вашего git-хоста, какие коммиты у него уже есть. Требуется Claude Code v2.1.257 или новее.
138* `core.hooksPath`, указывающий на управляемый раннером каталог хуков. Его хуки `commit-msg` и `prepare-commit-msg` добавляют к каждому коммиту трейлер `Co-authored-by:` для создателя сессии. Трейлер формируется из адреса электронной почты в [`CCR_SESSION_ACCOUNT_EMAIL`](https://code.claude.com/docs/ru/self-hosted-environments-configuration#wrapper-scripts) и не добавляется, если эта переменная не задана. Если ваш образ уже задаёт `core.hooksPath` и раннер не использует [git под управлением Anthropic](#use-the-anthropic-git-proxy), раннер оставляет вашу настройку как есть, не устанавливает эти хуки и выводит предупреждение `[runner:git]`.138* `core.hooksPath`, указывающий на управляемый раннером каталог хуков. Его хуки `commit-msg` и `prepare-commit-msg` добавляют к каждому коммиту трейлер `Co-authored-by:` для создателя сессии. Трейлер формируется из адреса электронной почты в [`CCR_SESSION_ACCOUNT_EMAIL`](https://code.claude.com/docs/ru/self-hosted-environments-configuration#wrapper-scripts) и опускается, если эта переменная не задана. Если ваш образ уже задаёт `core.hooksPath` и раннер не использует [управляемый Anthropic git](#use-the-anthropic-git-proxy), раннер сохраняет вашу настройку, пропускает установку этих хуков и выводит предупреждение `[runner:git]`.
139 139
140Для подписи коммитов требуется git 2.34 или новее; раннер проверяет это при запуске и завершается с ошибкой, если ваш git старше. Этот флаг не настраивает учётные данные для push — их по-прежнему нужно предоставить в образе.140Подпись коммитов требует git 2.34 или новее; раннер проверяет это при запуске и завершается с ошибкой, если ваш git старее. Этот флаг не настраивает учётные данные для push — их по-прежнему нужно предоставить в образе.
141 141
142На раннере версии v2.1.280 или новее коммиты, которые вы делаете из хука жизненного цикла `checkout` или `post-session`, также подписываются от имени сессии, но без трейлера `Co-authored-by:`. В разделе [Конфигурация git внутри хуков жизненного цикла](https://code.claude.com/docs/ru/self-hosted-environments-configuration.md#git-configuration-inside-lifecycle-hooks) описаны настройки git, которые раннер фиксирует внутри этих хуков.142На раннере версии v2.1.280 или новее коммиты, которые вы делаете из хука жизненного цикла `checkout` или `post-session`, также подписываются от имени сессии, но без трейлера `Co-authored-by:`. В разделе [Конфигурация git внутри хуков жизненного цикла](https://code.claude.com/docs/ru/self-hosted-environments-configuration.md#git-configuration-inside-lifecycle-hooks) описаны настройки git, которые раннер фиксирует внутри этих хуков.
143 143
144С `--configure-git` или без него Claude Code указывает Claude завершать сообщения коммитов трейлером `Claude-Session: <url>`, а описания pull request — URL сессии. Чтобы отключить и то и другое, задайте для [`attribution.sessionUrl`](https://code.claude.com/docs/ru/settings-reference#attribution-sessionurl) значение `false` в файле [`~/.claude/settings.json`](https://code.claude.com/docs/ru/self-hosted-environments-configuration#how-each-session’s-config-is-assembled) на хосте раннера, а затем перезапустите раннер.144С `--configure-git` или без него Claude Code указывает Claude завершать сообщения коммитов трейлером `Claude-Session: <url>`, а описания pull request — URL сессии. Чтобы исключить и то и другое, задайте [`attribution.sessionUrl`](https://code.claude.com/docs/ru/settings-reference#attribution-sessionurl) значение `false` в файле [`~/.claude/settings.json`](https://code.claude.com/docs/ru/self-hosted-environments-configuration#how-each-session’s-config-is-assembled) на хосте раннера, а затем перезапустите раннер.
145 145
146### Поставляйте конфигурацию git в своём образе146### Поставлять конфигурацию git в образе
147 147
148Идентификация git требуется для любого коммита. Задайте её на уровне системы в своём Dockerfile, чтобы конфигурация применялась независимо от того, от имени какого пользователя запущен процесс раннера:148Идентичность git необходима для любого коммита. Задайте её на уровне системы в Dockerfile, чтобы конфигурация применялась независимо от того, от имени какого пользователя работает процесс раннера:
149 149
150```dockerfile theme={null}150```dockerfile theme={null}
151RUN git config --system user.name "Claude" && \151RUN git config --system user.name "Claude" && \
152 git config --system user.email "noreply@anthropic.com"152 git config --system user.email "noreply@anthropic.com"
153```153```
154 154
155Без идентификации `git commit` завершается ошибкой `Please tell me who you are`, и сессии не могут продвигаться. Вместо этого можно использовать идентификацию собственного бота; раннер не переопределяет эти значения.155Без идентичности `git commit` завершается ошибкой `Please tell me who you are`, и сессии не могут продвинуться. Вместо этого можно использовать идентичность собственного бота; раннер не переопределяет эти значения.
156 156
157Не встраивайте долгоживущие или широко ограниченные учётные данные для push в общий образ раннера: учётные данные в образе доступны каждой сессии, которую запускает этот образ, кто бы её ни начал. Вместо этого выпускайте краткосрочный токен с минимальной областью действия для каждой сессии в своём [скрипте-обёртке](https://code.claude.com/docs/ru/self-hosted-environments-configuration.md#wrapper-scripts), используя идентификацию создателя сессии, декодированную из JWT сессии. Сочетайте это с эфемерным контейнером на каждую сессию, для чего требуется `--capacity 1`, чтобы никакие учётные данные не переживали сессию, которая их выпустила; см. [раздел об усилении защиты](#harden-your-deployment).157Не встраивайте долгоживущие учётные данные для push или учётные данные с широкими правами в общий образ раннера: учётные данные в образе доступны каждой сессии, которую запускает этот образ, кто бы её ни создал. Вместо этого выпускайте для каждой сессии краткоживущий токен с минимально необходимыми правами из своего [скрипта-обёртки](https://code.claude.com/docs/ru/self-hosted-environments-configuration.md#wrapper-scripts), используя идентичность создателя сессии, декодированную из JWT сессии. Сочетайте это с эфемерным контейнером для каждой сессии, что требует `--capacity 1`, чтобы никакие учётные данные не пережили сессию, для которой они были выпущены; см. [раздел об усилении защиты](#harden-your-deployment).
158 158
159Если вам необходимо настроить учётные данные для push на уровне образа, например для ключа развёртывания только для чтения, ограничьте их настолько жёстко, насколько позволяет ваш git-хостинг:159Если необходимо настроить учётные данные для push на уровне образа, например для ключа развёртывания только для чтения, ограничьте их настолько жёстко, насколько позволяет ваш git-хост:
160 160
161* Ключ развёртывания SSH, ограниченный одним репозиторием, с перезаписью `url.<base>.insteadOf`161* Ключ развёртывания SSH, ограниченный одним репозиторием, с перезаписью `url.<base>.insteadOf`
162* `credential.helper`, возвращающий токен с минимальной областью действия162* `credential.helper`, возвращающий токен с минимальной областью действия
163* `GIT_SSH_COMMAND`, указывающий на ключ с узкой областью действия163* `GIT_SSH_COMMAND`, указывающий на ключ с узкой областью действия
164 164
165Какой бы механизм вы ни настроили, он должен работать без запроса ввода, потому что встроенные операции clone и fetch раннера отключают запросы, которые иначе показали бы git, SSH и Git Credential Manager:165Какой бы механизм вы ни настроили, он должен работать без интерактивного запроса, поскольку встроенные клонирование и fetch раннера отключают запросы, которые иначе показали бы git, SSH и Git Credential Manager:
166 166
167* Раннер задаёт `GIT_TERMINAL_PROMPT=0`, поэтому git не запрашивает имя пользователя или пароль.167* Раннер задаёт `GIT_TERMINAL_PROMPT=0`, поэтому git не запрашивает имя пользователя или пароль.
168* Раннер запускает SSH с `BatchMode=yes`, добавленным к вашему `GIT_SSH_COMMAND`, если вы его задали, поэтому SSH не запрашивает парольную фразу или подтверждение хоста.168* Раннер запускает SSH с `BatchMode=yes`, добавленным к вашему `GIT_SSH_COMMAND`, если вы его задали, поэтому SSH не запрашивает парольную фразу или подтверждение хоста.
169* Раннер задаёт `GCM_INTERACTIVE=never`, поэтому Git Credential Manager не открывает диалог входа.169* Раннер задаёт `GCM_INTERACTIVE=never`, поэтому Git Credential Manager не открывает диалог входа.
170* Раннер очищает `core.askPass`, поэтому если вы используете вспомогательную программу askpass, задайте её через переменную окружения `GIT_ASKPASS`.170* Раннер очищает `core.askPass`, поэтому, если вы используете askpass-помощник, задайте его через переменную окружения `GIT_ASKPASS`.
171 171
172Если ваш git-хостинг отклоняет учётные данные или вы их не настроили, раннер делает несколько повторных попыток, а затем завершает подготовку репозитория с ошибкой, если это репозиторий, в который сессия отправляет результаты. Для репозитория, который сессия только читает, в разделе [Устранение неполадок](#troubleshooting) описано, когда раннер вместо этого его пропускает. Раннер не передаёт эти настройки в окружение сессии.172Если ваш git-хост отклоняет учётные данные или вы их не настроили, раннер делает несколько повторных попыток, а затем прерывает подготовку репозитория, если это репозиторий, в который сессия отправляет результаты. О том, когда раннер вместо этого пропускает репозиторий, который сессия только читает, рассказано в разделе [Устранение неполадок](#troubleshooting). Раннер не передаёт эти настройки в окружение сессии.
173 173
174Храните любую программу, указанную в `GIT_SSH_COMMAND` или `GIT_ASKPASS`, там, куда сессии не могут записывать, — так же, как [контрольный список усиления защиты](#harden-your-deployment) требует для каталога хуков и скрипта-обёртки. То же относится к любому ключу или файлу в командной строке этой программы. Собственный git раннера запускает эту программу при выполнении clone или fetch.174Храните любую программу, указанную в `GIT_SSH_COMMAND` или `GIT_ASKPASS`, там, куда сессии не могут писать, — так же, как [контрольный список усиления защиты](#harden-your-deployment) требует для каталога хуков и скрипта-обёртки. То же относится к любому ключу или файлу в командной строке этой программы. Собственный git раннера запускает эту программу при клонировании или fetch.
175 175
176Если каталоги извлечения принадлежат другому uid, чем процесс раннера, git отказывается с ними работать; добавьте `safe.directory`:176Если каталоги извлечения принадлежат другому uid, чем процесс раннера, git отказывается с ними работать; добавьте `safe.directory`:
177 177
179RUN git config --system --add safe.directory '*'179RUN git config --system --add safe.directory '*'
180```180```
181 181
182### Используйте git-прокси Anthropic182### Использование git-прокси Anthropic
183 183
184С git-прокси Anthropic, который также называется git под управлением Anthropic, образу раннера не нужны ключи SSH, вспомогательная программа учётных данных, `.netrc` или другие учётные данные git для самой сессии. Вместо этого раннер просит Anthropic обслуживать git для его сессий. Для пользовательской сессии, которую обслуживает Anthropic, clone раннера и собственные fetch и push сессии проходят через Anthropic, который использует OAuth-токен GitHub, сохранённый для создателя сессии. Сессии ботов и агентов описаны в разделе [Как Anthropic обслуживает git для сессии](#how-anthropic-serves-git-for-a-session).184С git-прокси Anthropic, также называемым управляемым Anthropic git, образу раннера не нужны ключи SSH, помощник учётных данных, `.netrc` или другие учётные данные git для самой сессии. Вместо этого раннер просит Anthropic обслуживать git для своих сессий. Для пользовательской сессии, которую обслуживает Anthropic, клонирование раннера и собственные fetch и push сессии проходят через Anthropic, которая использует OAuth-токен GitHub, сохранённый для создателя сессии. Сессии ботов и агентов описаны в разделе [Как Anthropic обслуживает git для сессии](#how-anthropic-serves-git-for-a-session).
185 185
186Git-прокси отключён, пока вы [не включите его](#turn-the-anthropic-git-proxy-on). Раннеру, который обращается к вашему git-хостингу с собственными учётными данными, он не нужен, и git такого раннера работает с любым git-хостингом.186Git-прокси отключён, пока вы [не включите его](#turn-the-anthropic-git-proxy-on). Раннеру, который обращается к вашему git-хосту со своими учётными данными, он не нужен, и его git работает с любым git-хостом.
187 187
188Взамен git-прокси ограничивает то, что поддерживает раннер, и меняет то, что ему нужно:188Взамен git-прокси ограничивает то, что поддерживает раннер, и меняет то, что ему нужно:
189 189
190* **Только github.com**: Anthropic обслуживает сессию, только если все её репозитории находятся на github.com, а git-прокси пока не поддерживает GitHub Enterprise Server. На раннере с git-прокси сессия с репозиторием на другом git-хостинге [не запускается](#when-anthropic-doesnt-serve-a-session).190* **Только github.com**: Anthropic обслуживает сессию, только если все её репозитории находятся на github.com, а git-прокси пока не поддерживает GitHub Enterprise Server. На раннере с git-прокси сессия с репозиторием на другом git-хосте [не запускается](#when-anthropic-doesnt-serve-a-session).
191* **Учётные данные только для репозиториев сессии**: Anthropic предоставляет учётные данные git для репозиториев, входящих в сессию, но не для других репозиториев на том же git-хостинге. Приватный субмодуль, зависимость, которую ваш менеджер пакетов получает через git, или маркетплейс плагинов в другом репозитории не получают учётных данных от Anthropic. Попросите тех, кто создаёт сессии, [добавлять каждый репозиторий](https://code.claude.com/docs/ru/web-quickstart.md#start-a-task), который нужен сессии, при её создании.191* **Учётные данные только для репозиториев сессии**: Anthropic предоставляет учётные данные git для репозиториев, входящих в сессию, но не для других репозиториев на том же git-хосте. Приватный подмодуль, зависимость, которую ваш менеджер пакетов получает через git, или маркетплейс плагинов в другом репозитории не получают учётных данных от Anthropic. Попросите тех, кто создаёт сессии, [добавлять каждый репозиторий](https://code.claude.com/docs/ru/web-quickstart.md#start-a-task), который нужен сессии, при её создании.
192 192
193 Каждый запуск [облачной запланированной задачи](https://code.claude.com/docs/ru/routines.md) — это сессия с репозиториями задачи, поэтому попросите владельца каждой задачи [добавить каждый репозиторий, который нужен её запускам](https://code.claude.com/docs/ru/routines.md#edit-and-control-routines).193 Каждый запуск [облачной запланированной задачи](https://code.claude.com/docs/ru/routines.md) — это сессия с репозиториями задачи, поэтому попросите владельца каждой задачи [добавить все репозитории, которые нужны её запускам](https://code.claude.com/docs/ru/routines.md#edit-and-control-routines).
194* **Только push веток**: push, который удаляет ветку, завершается ошибкой, как и push в ref любого другого типа, например в тег. О том, какие ветки может обновлять push, см. [GitHub-прокси](https://code.claude.com/docs/ru/cloud-environments.md#github-proxy).194* **Только push веток**: push, удаляющий ветку, завершается ошибкой, как и push в ref любого другого типа, например в тег. О том, какие ветки может обновлять push, см. [GitHub-прокси](https://code.claude.com/docs/ru/cloud-environments.md#github-proxy).
195* **Подключённые аккаунты GitHub**: попросите каждого, кто создаёт пользовательские сессии с репозиторием, [подключить GitHub](https://code.claude.com/docs/ru/web-quickstart.md#connect-github). Без собственного подключения такие сессии [не запускаются](#creator-has-no-github-connection).195* **Подключённые аккаунты GitHub**: попросите каждого, кто создаёт пользовательские сессии с репозиторием, [подключить GitHub](https://code.claude.com/docs/ru/web-quickstart.md#connect-github). Без собственного подключения такие сессии [не запускаются](#creator-has-no-github-connection).
196* **`--capacity 1`**: git-прокси требует одну сессию на процесс раннера, поэтому для параллелизма запускайте больше реплик. Требования перечислены в разделе [Включение git-прокси Anthropic](#turn-the-anthropic-git-proxy-on).196* **`--capacity 1`**: git-прокси требует одну сессию на процесс раннера, поэтому для параллелизма запускайте больше реплик. Требования перечислены в разделе [Включение git-прокси Anthropic](#turn-the-anthropic-git-proxy-on).
197* **Заменённая глобальная конфигурация git**: раннер [удаляет и заменяет глобальную конфигурацию git](#git-proxy-replaces-global-git-config) пользователя, от имени которого он запущен. Запускайте его от имени отдельного пользователя или в контейнере.197* **Заменённая глобальная конфигурация git**: раннер [удаляет и заменяет глобальную конфигурацию git](#git-proxy-replaces-global-git-config) пользователя, от имени которого работает. Запускайте его от имени выделенного пользователя или в контейнере.
198* **Учётные данные хоста для push с хоста**: push с помощью [`--push-outcome-on-release`](https://code.claude.com/docs/ru/self-hosted-environments-reference#runner-cli-flags) раннера и любой push, который делает ваш [хук `post-session`](https://code.claude.com/docs/ru/self-hosted-environments-configuration#post-session), по-прежнему используют собственные учётные данные git хоста раннера и его [сетевой путь к `github.com`](#github-com-egress-with-the-anthropic-git-proxy). Не храните эти учётные данные в [глобальной конфигурации git](#git-proxy-replaces-global-git-config); способы их предоставления описаны в разделе [Поставляйте конфигурацию git в своём образе](#ship-git-config-in-your-image).198* **Учётные данные хоста для push с хоста**: push раннера через [`--push-outcome-on-release`](https://code.claude.com/docs/ru/self-hosted-environments-reference#runner-cli-flags) и любой push, который делает ваш [хук `post-session`](https://code.claude.com/docs/ru/self-hosted-environments-configuration#post-session), по-прежнему используют собственные учётные данные git хоста раннера и его [сетевой путь к `github.com`](#github-com-egress-with-the-anthropic-git-proxy). Не храните эти учётные данные в [глобальной конфигурации git](#git-proxy-replaces-global-git-config); способы их предоставления см. в разделе [Поставлять конфигурацию git в образе](#ship-git-config-in-your-image).
199* **Решение для каждой сессии**: Anthropic решает для каждой сессии на раннере, обслуживать ли её git, и сессия, которую он не обслуживает, не запускается. Причины описаны в разделе [Когда сессии не запускаются на раннере с git-прокси](#when-anthropic-doesnt-serve-a-session).199* **Решение для каждой сессии**: Anthropic решает для каждой сессии на раннере, обслуживать ли её git, и сессия, которую она не обслуживает, не запускается. Причины описаны в разделе [Когда сессии не запускаются на раннере с git-прокси](#when-anthropic-doesnt-serve-a-session).
200 200
201> [!WARNING]201> [!WARNING]
202>202>
203> Когда задан `--use-anthropic-git-proxy`, раннер удаляет и заменяет глобальную конфигурацию git пользователя, от имени которого он запущен, и не сохраняет резервную копию. Он делает это при запуске и перед каждой сессией. Данные входа или вспомогательная программа учётных данных, которые вы там хранили, теряются. Настройки, которые записывает [`--configure-git`](#let-the-runner-configure-git), сохраняются. Запускайте раннер от имени отдельного пользователя или в контейнере, но никогда от своего имени.203> При заданном `--use-anthropic-git-proxy` раннер удаляет и заменяет глобальную конфигурацию git пользователя, от имени которого работает, не сохраняя резервной копии. Он делает это при запуске и перед каждой сессией. Помощник входа или учётных данных, который вы там хранили, будет потерян. Настройки, которые записывает [`--configure-git`](#let-the-runner-configure-git), сохраняются. Запускайте раннер от имени выделенного пользователя или в контейнере, но никогда от своего собственного пользователя.
204 204
205Храните несекретные настройки git, такие как идентификация и `safe.directory`, в системной конфигурации git.205Храните несекретные настройки git, такие как идентичность и `safe.directory`, в системной конфигурации git.
206 206
207#### Включение git-прокси Anthropic207#### Включение git-прокси Anthropic
208 208
209Прежде чем запускать раннер с `--use-anthropic-git-proxy`, убедитесь, что хост раннера отвечает каждому из этих требований. Раннер отказывается запускаться, если требование к capacity или к git не выполнено:209Прежде чем запускать раннер с `--use-anthropic-git-proxy`, убедитесь, что хост раннера соответствует каждому из этих требований. Раннер отказывается запускаться, если требование к capacity или git не выполнено:
210 210
211* **Claude Code v2.1.267 или новее**: более ранние версии принимают флаг, но не сообщают Anthropic о запросе на обслуживание git и не выводят строку `Registering as opted in`, поэтому Anthropic не обслуживает их сессии.211* **Claude Code v2.1.267 или новее**: более ранние версии принимают флаг, но не сообщают запрос на обслуживание git Anthropic и не выводят строку `Registering as opted in`, поэтому Anthropic не обслуживает их сессии.
212* **`--capacity 1`, значение по умолчанию**: каждый процесс раннера обрабатывает одну сессию за раз, поэтому для параллелизма запускайте больше реплик.212* **`--capacity 1`, значение по умолчанию**: каждый процесс раннера обрабатывает одну сессию за раз, поэтому для параллелизма запускайте больше реплик.
213* **Git 2.32 или новее**: более старые версии git игнорируют конфигурацию git для отдельной сессии, которую раннер настраивает для git-прокси.213* **Git 2.32 или новее**: более старый git игнорирует посессионную конфигурацию git, которую раннер настраивает для git-прокси.
214 214
215> [!WARNING]215> [!WARNING]
216>216>
217> Рецепты для [Kubernetes](#kubernetes) и [Docker Compose](#docker-compose) на этой странице используют `--capacity 4`. Если вы добавите `--use-anthropic-git-proxy` или `CLAUDE_RUNNER_USE_GIT_PROXY=1` в один из них, не изменив capacity на `1`, раннер будет завершаться при запуске каждый раз, когда оркестратор его перезапускает. Задайте `--capacity 1` и запускайте больше реплик для параллелизма. В разделе [Когда раннер завершается](#when-the-runner-exits) показана строка, которую выводит раннер.217> Рецепты [Kubernetes](#kubernetes) и [Docker Compose](#docker-compose) на этой странице используют `--capacity 4`. Если вы добавите `--use-anthropic-git-proxy` или `CLAUDE_RUNNER_USE_GIT_PROXY=1` в один из них, не изменив capacity на `1`, раннер будет завершаться при запуске каждый раз, когда оркестратор его перезапускает. Задайте `--capacity 1` и для параллелизма запускайте больше реплик. Строка, которую выводит раннер, показана в разделе [Когда раннер завершается](#when-the-runner-exits).
218 218
219Чтобы включить git-прокси, добавьте `--use-anthropic-git-proxy` в команду раннера или задайте `CLAUDE_RUNNER_USE_GIT_PROXY=1` в окружении раннера. Эта команда, выполненная в оболочке на хосте раннера, запускает раннер из [быстрого старта](https://code.claude.com/docs/ru/self-hosted-environments-quickstart.md#set-up-manually) с включённым git-прокси:219Чтобы включить git-прокси, добавьте `--use-anthropic-git-proxy` в команду раннера или задайте `CLAUDE_RUNNER_USE_GIT_PROXY=1` в окружении раннера. Эта команда, выполненная в оболочке на хосте раннера, запускает раннер из [быстрого старта](https://code.claude.com/docs/ru/self-hosted-environments-quickstart.md#set-up-manually) с включённым git-прокси:
220 220
226 226
227#### Как Anthropic обслуживает git для сессии227#### Как Anthropic обслуживает git для сессии
228 228
229Для сессии, которую обслуживает Anthropic, clone раннера и собственные fetch и push сессии проходят через Anthropic с аутентификацией собственным краткосрочным токеном сессии:229Для сессии, которую обслуживает Anthropic, клонирование раннера и собственные fetch и push сессии проходят через Anthropic с аутентификацией собственным краткоживущим токеном сессии:
230 230
231* **Пользовательские сессии**: Anthropic использует OAuth-токен GitHub, сохранённый для создателя сессии.231* **Пользовательские сессии**: Anthropic использует OAuth-токен GitHub, сохранённый для создателя сессии.
232* **Сессии ботов и агентов**: Anthropic использует токен установки GitHub App вашей организации.232* **Сессии ботов и агентов**: Anthropic использует токен установки GitHub App вашей организации.
236 236
237На раннере, запущенном с `--use-anthropic-git-proxy`, сессия не запускается, если Anthropic не обслуживает её git. Найдите в логе раннера ошибку git, в которой указан адрес `api.anthropic.com`, содержащий `/git_proxy/`.237На раннере, запущенном с `--use-anthropic-git-proxy`, сессия не запускается, если Anthropic не обслуживает её git. Найдите в логе раннера ошибку git, в которой указан адрес `api.anthropic.com`, содержащий `/git_proxy/`.
238 238
239Для каждой сессии раннер на Claude Code v2.1.267 или новее также записывает в лог либо строку `[runner:session]`, содержащую `governed git ACTIVE`, если Anthropic обслуживает git сессии, либо одну строку `[runner:warn]`, содержащую `the server withheld Anthropic-managed git for this session`, если нет. Найдите строку, которую вы видите, среди следующих случаев:239Для каждой сессии раннер на Claude Code v2.1.267 или новее также записывает в лог либо строку `[runner:session]`, содержащую `governed git ACTIVE`, если Anthropic обслуживает git сессии, либо одну строку `[runner:warn]`, содержащую `the server withheld Anthropic-managed git for this session`, если нет. Найдите среди этих случаев строку, которую вы видите:
240 240
241* **Нет ни `governed git ACTIVE`, ни строки `withheld`**: раннер старше Claude Code v2.1.267 не записывает ни одну из этих строк, и Anthropic не обслуживает его сессии. Обновите раннер до v2.1.267 или новее, следуя разделу [Закрепление версии](#pin-the-version).241* **Нет ни `governed git ACTIVE`, ни строки `withheld`**: раннер старее Claude Code v2.1.267 не записывает ни одну из этих строк, и Anthropic не обслуживает его сессии. Обновите раннер до v2.1.267 или новее, следуя разделу [Закрепление версии](#pin-the-version).
242* **Строка `withheld`**: Anthropic не обслужил сессию. Раннер, который раньше работал с git-прокси, может начать так завершаться без каких-либо изменений с вашей стороны.242* **Строка `withheld`**: Anthropic не стала обслуживать сессию. Раннер, который раньше работал с git-прокси, может так отказать без каких-либо изменений с вашей стороны.
243 * **Репозиторий находится не на github.com**: сессия, у которой хотя бы один репозиторий находится на другом git-хостинге, например GitHub Enterprise Server, не обслуживается, включая её репозитории на github.com. [Отключите git-прокси Anthropic](#turn-the-anthropic-git-proxy-off) для раннеров этой среды.243 * **Репозиторий не на github.com**: сессия хотя бы с одним репозиторием на другом git-хосте, например GitHub Enterprise Server, не обслуживается, включая её репозитории на github.com. [Отключите git-прокси Anthropic](#turn-the-anthropic-git-proxy-off) для раннеров этого окружения.
244 * **Все репозитории находятся на github.com**: сообщите о сбое [вашей команде по работе с аккаунтом в Anthropic](#report-an-issue), указав ID сессии из строки `withheld`. Anthropic записывает причину на своей стороне.244 * **Все репозитории на github.com**: сообщите о сбое [вашей команде по работе с аккаунтом Anthropic](#report-an-issue), указав ID сессии из строки `withheld`. Anthropic фиксирует причину на своей стороне.
245* **Строка, содержащая `remote: access denied by the git proxy`**: сессии, которую обслуживает Anthropic, всё равно может быть отказано, например когда политика организации запрещает доступ к git для сессии или у сессии нет авторизации для репозитория. Тогда в логе раннера есть строка, содержащая `remote: access denied by the git proxy`, и остальная часть этой строки объясняет причину.245* **Строка, содержащая `remote: access denied by the git proxy`**: сессии, которую обслуживает Anthropic, всё равно может быть отказано, например когда политика организации запрещает доступ к git для сессии или сессия не авторизована для репозитория. Тогда в логе раннера появляется строка, содержащая `remote: access denied by the git proxy`, а остальная часть этой строки объясняет причину.
246* **`GitHub authentication required`**: появляется, когда у создателя сессии нет работающего подключения GitHub на claude.ai. Clone сессии завершается ошибкой, и ошибка git гласит `GitHub authentication required. Please reconnect your GitHub account.` Попросите этого человека подключить или переподключить GitHub в настройках claude.ai.246* **`GitHub authentication required`**: появляется, когда у создателя сессии нет рабочего подключения GitHub на claude.ai. Клонирование сессии завершается ошибкой, и ошибка git содержит `GitHub authentication required. Please reconnect your GitHub account.` Попросите этого человека подключить или переподключить GitHub в настройках claude.ai.
247 247
248После устранения причины снова запустите сессии, которые не запустились.248После устранения причины снова запустите сессии, которые не запустились.
249 249
250#### Отключение git-прокси Anthropic250#### Отключение git-прокси Anthropic
251 251
252Если сессии в среде используют репозиторий на git-хостинге, отличном от github.com, например GitHub Enterprise Server, отключите `--use-anthropic-git-proxy` для раннеров этой среды.252Если сессии в окружении используют репозиторий на git-хосте, отличном от github.com, например GitHub Enterprise Server, отключите `--use-anthropic-git-proxy` для раннеров этого окружения.
253 253
254**1. Удалите флаг**254**1. Удалите флаг**
255 255
256Удалите `--use-anthropic-git-proxy` из команды раннера. Если вы задали `CLAUDE_RUNNER_USE_GIT_PROXY` в окружении раннера, например в спецификации пода или в файле Compose, удалите её оттуда. В оболочке сбросьте её:256Удалите `--use-anthropic-git-proxy` из команды раннера. Если вы задали `CLAUDE_RUNNER_USE_GIT_PROXY` в окружении раннера, например в спецификации pod или файле Compose, удалите её оттуда. В оболочке сбросьте её:
257 257
258```bash theme={null}258```bash theme={null}
259unset CLAUDE_RUNNER_USE_GIT_PROXY259unset CLAUDE_RUNNER_USE_GIT_PROXY
261 261
262**2. Предоставьте раннеру учётные данные git**262**2. Предоставьте раннеру учётные данные git**
263 263
264Предоставьте учётные данные, работающие без запроса ввода, для каждого git-хостинга, который используют сессии раннеров, включая github.com. Любые учётные данные, которые были в глобальной конфигурации git пользователя раннера, утеряны, потому что раннер удалил эту конфигурацию, пока был задан `--use-anthropic-git-proxy`. [Поставляйте учётные данные в своём образе](#ship-git-config-in-your-image) или используйте [хук жизненного цикла `checkout`](https://code.claude.com/docs/ru/self-hosted-environments-configuration#checkout).264Предоставьте учётные данные, работающие без интерактивного запроса, для каждого git-хоста, который используют сессии раннеров, включая github.com. Любые учётные данные, которые были в глобальной конфигурации git пользователя раннера, утрачены, поскольку раннер удалил эту конфигурацию, пока был задан `--use-anthropic-git-proxy`. [Поставляйте учётные данные в образе](#ship-git-config-in-your-image) или используйте [хук жизненного цикла `checkout`](https://code.claude.com/docs/ru/self-hosted-environments-configuration#checkout).
265 265
266**3. Откройте сетевой путь**266**3. Откройте сетевой путь**
267 267
268Разрешите раннеру обращаться к каждому git-хостингу, который используют сессии раннеров, по порту 443 или 22. См. строку о git-хостинге в разделе [Сетевые требования](#network-requirements).268Разрешите раннеру доступ к каждому git-хосту, который используют сессии раннеров, по порту 443 или 22. См. строку о git-хосте в разделе [Сетевые требования](#network-requirements).
269 269
270**4. Перезапустите раннеры**270**4. Перезапустите раннеры**
271 271
273 273
274#### Доступ к API GitHub без GitHub CLI274#### Доступ к API GitHub без GitHub CLI
275 275
276Если в вашем образе раннера нет GitHub CLI, Claude Code может предоставить встроенный `gh`, чтобы Claude всё равно мог открывать pull request, оставлять комментарии и читать результаты CI. Встроенный `gh` предназначен для раннеров, использующих git под управлением Anthropic. Он поддерживает одну команду, `gh api`, которая вызывает REST API GitHub. Требуется Claude Code v2.1.287 или новее в образе раннера.276Если ваш образ раннера не включает GitHub CLI, Claude Code может предоставить встроенный `gh`, чтобы Claude всё равно мог открывать pull request, оставлять комментарии и читать результаты CI. Встроенный `gh` предназначен для раннеров, использующих управляемый Anthropic git. Он поддерживает одну команду, `gh api`, которая вызывает REST API GitHub. Требуется Claude Code v2.1.287 или новее в образе раннера.
277 277
278Эта команда открывает pull request вместо `gh pr create`. Встроенный `gh` подставляет `{owner}` и `{repo}` для текущего репозитория:278Эта команда открывает pull request вместо `gh pr create`. Встроенный `gh` подставляет `{owner}` и `{repo}` для текущего репозитория:
279 279
281gh api repos/{owner}/{repo}/pulls -f title='Fix' -f head='my-branch' -f base='main'281gh api repos/{owner}/{repo}/pulls -f title='Fix' -f head='my-branch' -f base='main'
282```282```
283 283
284* **Учётные данные**: встроенный `gh` отправляет свои REST-запросы через git под управлением Anthropic, который предоставляет учётные данные GitHub на стороне Anthropic, поэтому образу не нужен токен GitHub для этого284* **Учётные данные**: встроенный `gh` отправляет свои REST-запросы через управляемый Anthropic git, который предоставляет учётные данные GitHub на стороне Anthropic, поэтому образу не нужен токен GitHub для этого
285* **Какие сессии его получают**: Anthropic решает для каждой сессии, обслуживает ли git под управлением Anthropic `gh` этой сессии. Если да, строка `[runner:session] governed git ACTIVE`, которую раннер записывает в лог для сессии, показывает `gh_path_shim=true`. Если нет, у сессии нет `gh`285* **Какие сессии его получают**: Anthropic решает для каждой сессии, обслуживает ли управляемый Anthropic git `gh` этой сессии. Если да, строка `[runner:session] governed git ACTIVE`, которую раннер записывает в лог для сессии, показывает `gh_path_shim=true`. Если нет, у сессии нет `gh`
286* **`jq`**: установите `jq` в образ, если хотите, чтобы работал `--jq`286* **`jq`**: установите `jq` в образ, если хотите, чтобы работал `--jq`
287* **[`CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC`](https://code.claude.com/docs/ru/env-vars)**: если окружение сессии задаёт эту переменную, Claude Code не предоставляет встроенный `gh`, и у сессии нет `gh`287* **[`CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC`](https://code.claude.com/docs/ru/env-vars)**: если окружение сессии задаёт эту переменную, Claude Code не предоставляет встроенный `gh`, и у сессии нет `gh`
288 288
289Если образ включает GitHub CLI, сессии используют его.289Если образ включает GitHub CLI, сессии используют его.
290 290
291#### Доверие частному центру сертификации при использовании git под управлением Anthropic291#### Доверие частному центру сертификации при использовании управляемого Anthropic git
292 292
293Этот раздел применим, если вы задаёте `GIT_SSL_CAINFO` или `GIT_SSL_NO_VERIFY` в окружении раннера, сессии которого используют git под управлением Anthropic. Описанная обработка требует, чтобы раннер работал на Claude Code v2.1.283 или новее.293Этот раздел применим, если вы задаёте `GIT_SSL_CAINFO` или `GIT_SSL_NO_VERIFY` в окружении раннера, сессии которого используют управляемый Anthropic git. Описанная обработка требует, чтобы раннер работал на Claude Code v2.1.283 или новее.
294 294
295Когда git на раннере должен доверять частному центру сертификации (CA), например тому, которым подписывает сертификаты прокси с TLS-инспекцией, обычные подходы работают следующим образом:295Когда git на раннере должен доверять частному центру сертификации (CA), например тому, которым подписывает прокси с инспекцией TLS, обычные подходы работают следующим образом:
296 296
297* **Системное хранилище сертификатов**: установите свой CA в системное хранилище сертификатов хоста раннера, и git будет доверять ему без обеих переменных.297* **Системное хранилище сертификатов**: установите свой CA в системное хранилище сертификатов хоста раннера, и git будет доверять ему без каких-либо из этих переменных.
298* **`GIT_SSL_CAINFO`**: задайте в ней PEM-файл ваших CA, например `GIT_SSL_CAINFO=/etc/ssl/corp-ca.pem`.298* **`GIT_SSL_CAINFO`**: задайте путь к PEM-файлу с вашими CA, например `GIT_SSL_CAINFO=/etc/ssl/corp-ca.pem`.
299* **`GIT_SSL_NO_VERIFY`**: не помогает за прокси, переподписывающим сертификаты. Собственный clone раннера через git под управлением Anthropic проверяет сертификаты, даже когда переменная задана, поэтому этот clone завершается ошибкой, пока git не начнёт доверять вашему CA одним из двух других способов.299* **`GIT_SSL_NO_VERIFY`**: не помогает за повторно подписывающим прокси. Собственное клонирование раннера через управляемый Anthropic git проверяет сертификаты, даже если эта переменная задана, поэтому такое клонирование завершается ошибкой, пока git не начнёт доверять вашему CA одним из двух других способов.
300 300
301Для git-соединений, которые передают токен сессии в git под управлением Anthropic, раннер применяет эти две переменные следующим образом. [Хук `command`](https://code.claude.com/docs/ru/self-hosted-environments-configuration#command) запускается с окружением сессии, поэтому получает то же, что и git внутри сессии:301Для git-соединений, передающих токен сессии в управляемый Anthropic git, раннер применяет эти две переменные следующим образом. [Хук `command`](https://code.claude.com/docs/ru/self-hosted-environments-configuration#command) запускается с окружением сессии, поэтому получает то же, что и git внутри сессии:
302 302
303* **`GIT_SSL_CAINFO`**: по чему git проверяет git под управлением Anthropic, зависит от того, где запущен git:303* **`GIT_SSL_CAINFO`**: то, с чем git сверяет управляемый Anthropic git, зависит от того, где запускается git:
304 * **Собственные clone и fetch раннера**: выполняются без переменной и проверяют git под управлением Anthropic по файлу сертификатов для отдельной сессии, который записывает раннер. Раннер собирает этот файл из системного пакета CA хоста раннера и сертификатов из вашего файла.304 * **Собственные клонирование и fetch раннера**: выполняются без переменной и сверяют управляемый Anthropic git с посессионным файлом сертификатов, который записывает раннер. Раннер собирает этот файл из системного пакета CA хоста раннера и сертификатов из вашего файла.
305 * **Git внутри сессии**: получает конфигурацию `http.sslCAInfo` с указанием вашего файла вместо переменной, а также записи `http.<url>.sslCAInfo`, которые проверяют git под управлением Anthropic по файлу для отдельной сессии.305 * **Git внутри сессии**: получает конфигурацию `http.sslCAInfo` с указанием вашего файла вместо переменной, а также записи `http.<url>.sslCAInfo`, которые сверяют управляемый Anthropic git с посессионным файлом.
306 * **Хуки `checkout` и `post-session`**: наследуют переменную без изменений.306 * **Хуки `checkout` и `post-session`**: наследуют переменную без изменений.
307* **`GIT_SSL_NO_VERIFY`**: какие проверки сертификатов остаются отключёнными, зависит от того, где запущен git:307* **`GIT_SSL_NO_VERIFY`**: какие проверки сертификатов остаются отключёнными, зависит от того, где запускается git:
308 * **Собственные clone и fetch раннера**: выполняются без переменной и проверяют предъявленный им сертификат.308 * **Собственные клонирование и fetch раннера**: выполняются без переменной и проверяют предъявленный им сертификат.
309 * **Git внутри сессии**: получает конфигурацию `http.sslVerify=false` вместо переменной, поэтому проверки остаются отключёнными для других хостов. Он также получает записи `http.<url>.sslVerify=true`, которые сохраняют проверки включёнными для git под управлением Anthropic.309 * **Git внутри сессии**: получает конфигурацию `http.sslVerify=false` вместо переменной, поэтому проверки остаются отключёнными для других хостов. Он также получает записи `http.<url>.sslVerify=true`, которые сохраняют проверки включёнными для управляемого Anthropic git.
310 * **Хуки `checkout` и `post-session`**: когда у сессии есть репозиторий в git под управлением Anthropic, получают конфигурацию `http.sslVerify=false` вместо переменной. Они также получают записи `http.<url>.sslVerify=true`, которые сохраняют проверки включёнными для git под управлением Anthropic.310 * **Хуки `checkout` и `post-session`**: если у сессии есть репозиторий на управляемом Anthropic git, получают конфигурацию `http.sslVerify=false` вместо переменной. Они также получают записи `http.<url>.sslVerify=true`, которые сохраняют проверки включёнными для управляемого Anthropic git.
311 311
312Для файла сертификатов отдельной сессии нужен системный пакет CA по пути `/etc/ssl/certs/ca-certificates.crt` или `/etc/pki/tls/certs/ca-bundle.crt` на хосте раннера. Также нужен файл `GIT_SSL_CAINFO`, который может прочитать пользователь раннера, который содержит PEM-блоки `CERTIFICATE` и размер которого не превышает 1 МиБ. Если раннер не может собрать файл для отдельной сессии, он записывает в лог строку `[runner:warn]`, содержащую `did not build the certificate file` и причину. Тогда git использует ваш файл как есть для git под управлением Anthropic. Исправьте то, что указано в строке.312Для посессионного файла сертификатов нужен системный пакет CA по пути `/etc/ssl/certs/ca-certificates.crt` или `/etc/pki/tls/certs/ca-bundle.crt` на хосте раннера. Также нужен файл `GIT_SSL_CAINFO`, который может прочитать пользователь раннера, который содержит PEM-блоки `CERTIFICATE` и размер которого не превышает 1 МиБ. Если раннер не может собрать посессионный файл, он записывает в лог строку `[runner:warn]`, содержащую `did not build the certificate file` и причину. Тогда git использует ваш файл как есть для управляемого Anthropic git. Исправьте то, что указано в строке.
313 313
314Для каждой сессии, использующей git под управлением Anthropic, раннер также записывает в лог строку `[runner:warn]`, которая начинается с `governed git: GIT_SSL_CAINFO is set` или `governed git: GIT_SSL_NO_VERIFY is set`. Строка сообщает, что раннер сделал с этой переменной для собственного git, для git внутри сессии и для ваших хуков жизненного цикла. В конце она указывает, нужно ли вам что-либо менять.314Для каждой сессии, использующей управляемый Anthropic git, раннер также записывает в лог строку `[runner:warn]`, начинающуюся с `governed git: GIT_SSL_CAINFO is set` или `governed git: GIT_SSL_NO_VERIFY is set`. В строке сказано, что раннер сделал с этой переменной для собственного git, для git внутри сессии и для ваших хуков жизненного цикла. Она завершается указанием, нужно ли вам что-либо менять.
315
316### Добавление репозиториев github.com в сессии каналов Claude Tag
317
318Если Claude не может добавить репозиторий github.com в сессию канала Claude Tag, убедитесь, что у канала есть к нему доступ, даже если ваш раннер может его клонировать. Этот доступ определяется настройками на GitHub и в вашей организации Claude, а не учётными данными git вашего раннера.
319
320**1. Установите Claude GitHub App**
321
322Установите [Claude GitHub App](https://github.com/apps/claude) в организацию или аккаунт GitHub, которому принадлежит репозиторий, и включите этот репозиторий в установку.
323
324**2. Свяжите организацию или аккаунт GitHub**
325
326В разделе [**Organization settings > Git providers**](https://claude.ai/admin-settings/source-control) свяжите эту организацию или аккаунт со своей организацией Claude. Связать её может Owner вашей организации Claude, который также является владельцем организации GitHub. См. [Связывание организации GitHub](https://claude.com/docs/claude-tag/admins/configure-github#link-your-github-organization).
327
328**3. Предоставьте доступ к репозиторию**
329
330В [настройках администратора Claude Tag](https://claude.ai/admin-settings/claude-tag) предоставьте репозиторий каналу или более широкой области действия, включающей канал: его рабочему пространству Slack или всему Slack. Предоставить его может пользователь с ролью Owner или разрешением Claude Tag Admin. Менеджер канала также может добавить его в свой канал, если его аккаунт GitHub является администратором репозитория. См. [Предоставление доступа к репозиторию](https://claude.com/docs/claude-tag/admins/configure-github#grant-repository-access).
331
332Затем начните новую ветку обсуждения в канале и [назовите репозиторий](https://claude.com/docs/claude-tag/admins/configure-github#how-granted-repositories-reach-a-session) в первом сообщении.
333
334Если Claude по-прежнему не может добавить репозиторий, см. [Если Claude не может получить доступ к репозиторию](https://claude.com/docs/claude-tag/admins/configure-github#if-claude-can%E2%80%99t-reach-a-repository), где описано, как проверить связь с GitHub и предоставление доступа к репозиторию.
315 335
316### Перезапись URL git для частных сетей336### Перезапись URL git для частных сетей
317 337
318URL репозиториев поступают из плоскости управления в формате HTTPS с именем хоста вашего git-хостинга; для GitHub Enterprise это имя хоста, которое вы настроили для [интеграции GitHub Enterprise](https://code.claude.com/docs/ru/github-enterprise-server.md) на claude.ai. Два повторяемых флага перезаписывают эти URL перед clone:338URL репозиториев поступают из control plane в формате HTTPS с именем хоста вашего git-хоста; для GitHub Enterprise это имя хоста, которое вы настроили для [интеграции GitHub Enterprise](https://code.claude.com/docs/ru/github-enterprise-server.md) на claude.ai. Два повторяемых флага перезаписывают эти URL перед клонированием:
319 339
320* `--git-host-rewrite <from>=<to>`: для split-horizon DNS, когда Anthropic обращается к вашему git-хостингу по внешнему имени хоста, а раннеры должны использовать внутреннее340* `--git-host-rewrite <from>=<to>`: для split-horizon DNS, когда Anthropic обращается к вашему git-хосту по внешнему имени хоста, а раннеры должны использовать внутреннее
321* `--git-ssh-rewrite <host>`: для git-хостингов, принимающих только SSH, или для хоста раннера, у которого есть только ключ SSH. Например, чтобы клонировать репозитории github.com через SSH, добавьте `--git-ssh-rewrite github.com` в команду раннера. Тогда раннер перезаписывает `https://github.com/owner/repo` в `git@github.com:owner/repo`. SSH должен [подключаться без запроса ввода](#git-must-work-without-a-prompt).341* `--git-ssh-rewrite <host>`: для git-хостов, которые принимают только SSH, или для хоста раннера, у которого есть только ключ SSH. Например, чтобы клонировать репозитории github.com по SSH, добавьте `--git-ssh-rewrite github.com` в команду раннера. Тогда раннер перезаписывает `https://github.com/owner/repo` в `git@github.com:owner/repo`. SSH должен [подключаться без интерактивного запроса](#git-must-work-without-a-prompt).
322 342
323Перезапись хоста выполняется первой, поэтому если вам нужны обе, укажите в `--git-ssh-rewrite` внутреннее имя хоста. Для полного контроля над извлечением используйте [хук жизненного цикла `checkout`](https://code.claude.com/docs/ru/self-hosted-environments-configuration#checkout).343Перезапись хоста выполняется первой, поэтому, если вам нужны обе, указывайте в `--git-ssh-rewrite` внутреннее имя хоста. Для полного контроля над извлечением используйте [хук жизненного цикла `checkout`](https://code.claude.com/docs/ru/self-hosted-environments-configuration#checkout).
324 344
325## Постройте образ runner345## Постройте образ runner
326 346
376 396
377Сборки и тесты обычно являются самой большой и наиболее переменной частью нагрузки сеанса, поэтому запустите репрезентативную сборку вашего репозитория, измерьте его пиковый CPU и память и поднимите любое начальное значение, которое не оставляет места для процесса Claude Code на вершине этого пика.397Сборки и тесты обычно являются самой большой и наиболее переменной частью нагрузки сеанса, поэтому запустите репрезентативную сборку вашего репозитория, измерьте его пиковый CPU и память и поднимите любое начальное значение, которое не оставляет места для процесса Claude Code на вершине этого пика.
378 398
379Runner использует `--capacity` для ограничения количества сеансов, которые он запускает одновременно. Он не делит CPU или память между ними, поэтому сеансы на runner делят CPU и память контейнера. Чтобы ограничить долю одного сеанса, применяйте лимиты из вашего [скрипта-обертки](https://code.claude.com/docs/ru/self-hosted-environments-configuration.md#wrapper-scripts). То, что дать одному контейнеру, поэтому зависит от того, сколько сеансов он обслуживает одновременно:399Runner использует `--capacity`, чтобы ограничить число одновременно запускаемых сессий. Он не распределяет CPU или память между ними, поэтому сессии на одном runner делят CPU и память контейнера. Чтобы потребление памяти одной сессией не приводило к завершению остальных, запускайте одну сессию на runner с [собственным лимитом памяти](#give-each-session-its-own-memory-limit).
380 400
381* **Один сеанс на runner**: дайте каждому контейнеру значения одного сеанса. Используйте эту размер на `--capacity 1`, которую [раздел усиления безопасности](#harden-your-deployment) рекомендует, и для [on-demand runners](https://code.claude.com/docs/ru/self-hosted-environments-configuration.md#on-demand-runners), где вы устанавливаете значения на рабочую нагрузку, которую ваш [`spawn-runner` hook](https://code.claude.com/docs/ru/self-hosted-environments-configuration#the-spawn-runner-hook) отправляет, такую как шаблон pod Kubernetes Job.401* **Один сеанс на runner**: дайте каждому контейнеру значения одного сеанса. Используйте эту размер на `--capacity 1`, которую [раздел усиления безопасности](#harden-your-deployment) рекомендует, и для [on-demand runners](https://code.claude.com/docs/ru/self-hosted-environments-configuration.md#on-demand-runners), где вы устанавливаете значения на рабочую нагрузку, которую ваш [`spawn-runner` hook](https://code.claude.com/docs/ru/self-hosted-environments-configuration#the-spawn-runner-hook) отправляет, такую как шаблон pod Kubernetes Job.
382* **Несколько сеансов на runner**: на `--capacity` выше одного, умножьте значения одного сеанса на емкость, потому что до такого количества сеансов может работать в контейнере одновременно. Рецепты [Kubernetes](#kubernetes) и [Docker Compose](#docker-compose) запускают `--capacity 4` без лимитов CPU или памяти, поэтому добавьте лимиты, размер которых соответствует емкости, которую вы запускаете.402* **Несколько сеансов на runner**: на `--capacity` выше одного, умножьте значения одного сеанса на емкость, потому что до такого количества сеансов может работать в контейнере одновременно. Рецепты [Kubernetes](#kubernetes) и [Docker Compose](#docker-compose) запускают `--capacity 4` без лимитов CPU или памяти, поэтому добавьте лимиты, размер которых соответствует емкости, которую вы запускаете.
403* **Несколько контейнеров runner на одном хосте**: рассчитывайте размер хоста на сумму capacity всех runner, потому что каждый runner учитывает в `--capacity` только собственные сессии:
404
405 * **Память**: умножьте память одной сессии на эту сумму, затем добавьте то, что потребляют собственные процессы хоста
406 * **CPU**: умножьте request CPU одной сессии на эту сумму. Чтобы все сессии могли одновременно превышать request, умножайте вместо этого её limit CPU.
407
408 Выделите каждому runner собственный контейнер. Используйте в каждом [один и тот же путь `--base-dir`](#keep-the-base-directory-and-capacity-identical-across-runners) на хранилище, которое не монтирует контейнер никакого другого runner, чтобы у каждого runner был [собственный рабочий каталог](#harden-your-deployment).
409
410### Задайте каждой сессии собственный лимит памяти
411
412Чтобы при нехватке памяти одна сессия не приводила к завершению остальных, запускайте каждый runner с `--capacity 1` под собственным лимитом памяти, равным памяти одной сессии:
413
414* **В контейнере**: запускайте один runner на контейнер и задайте лимит памяти контейнера, например `limits.memory` в Kubernetes, `--memory` в Docker или `mem_limit` в файле Compose. Следите, чтобы сумма лимитов контейнеров была меньше памяти хоста, потому что когда память заканчивается на самом хосте, ядро может завершать процессы в любом месте хоста.
415* **Под systemd без контейнера**: задайте `MemoryMax` для unit-а runner и запускайте один runner на хост, потому что runner, [использующие один и тот же `--base-dir`](#keep-the-base-directory-and-capacity-identical-across-runners) в одной файловой системе, совместно используют клонированные туда репозитории. Например, при `--capacity 1` и без хука `checkout` их сессии в одном репозитории могут одновременно работать в одном и том же checkout. Чтобы запустить несколько runner на одном хосте, выделите каждому контейнер.
416
417Когда контейнер или unit достигает лимита памяти, ядро завершает процессы только внутри него. Если задать `--capacity` больше единицы, сессии делят один лимит. Когда они его достигают, ядро выбирает, какие процессы завершить, без учёта сессий, поэтому потребление памяти одной сессией может завершить остальные.
418
419В Kubernetes разделить сессии не удастся ни при одном значении настройки kubelet `singleProcessOOMKill`. Ограничить общую память сессии с помощью `ulimit` для памяти в вашем [скрипте-обёртке](https://code.claude.com/docs/ru/self-hosted-environments-configuration.md#wrapper-scripts) тоже не получится. Ядро применяет значение вроде `ulimit -v` к каждому процессу отдельно.
420
421### Оставьте запас под лимитами процессов и потоков
422
423Чтобы подобрать лимит процессов и потоков, измерьте, сколько нужно одной сессии, и умножьте это на число сессий, которые делят лимит. Когда эти сессии достигают лимита, ядро отказывает в создании новых процессов и потоков, поэтому команды, сборки и тесты в любой из них могут завершаться ошибкой. Отклонённый вызов возвращает `EAGAIN`, стандартное сообщение которого — `Resource temporarily unavailable`.
424
425Допустим, одна сессия достигает пика в 300 процессов и потоков, и четыре сессии делят лимит. Вместе им нужно 1 200, а при лимите 2 400 вы оставляете запас для сборок, которым нужно вдвое больше.
426
427#### Где задать каждый лимит
428
429Каждый лимит в этой таблице учитывает потоки наравне с процессами, а `pids.max` — это файл, в котором хранится лимит cgroup:
430
431| Лимит | Где его задать | Кто его делит |
432| :- | :- | :- |
433| `pids.max` в Kubernetes | `podPidsLimit` в конфигурации kubelet узлов, на которых работают runner. Задать его в спецификации Pod нельзя. | Контейнеры одного Pod |
434| `pids.max` в Docker | `--pids-limit` или `pids_limit` в файле Compose | Один контейнер |
435| `pids.max` под systemd | `TasksMax` для unit-а runner | Один unit |
436| `ulimit -u` | Оболочка или служба, запускающая runner | Всё на хосте, что работает под ID пользователя runner. Не применяется для root. |
437
438Если вы не задали `TasksMax`, systemd применяет `DefaultTasksMax`, который по умолчанию равен 15% от наименьшего из значений `kernel.pid_max`, `kernel.threads-max` и `pids.max` корневой cgroup.
439
440#### Измерьте пик одной сессии
441
442Чтобы получить значения для ваших runner, измерьте одну сессию на её хосте, которым в Kubernetes является узел:
443
444**1. Запустите один runner отдельно**
445
446Запустите один runner с `--capacity 1`, ничего больше не размещая в его контейнере или unit-е systemd, так чтобы он был один на своём хосте и в своём окружении:
447
448* **Его хост**: используйте хост, на котором не работает ни один другой runner. Тогда на следующем шаге вы сможете найти его процесс.
449* **Его окружение**: сделайте его единственным runner в окружении, например в окружении, которое вы [создадите для теста](https://code.claude.com/docs/ru/self-hosted-environments-quickstart.md#set-up-manually). Сессии направляются в окружение, а не на конкретный runner.
450
451Пока не запускайте сессию, потому что каталог из следующего шага нужен вам до начала сборки.
452
453**2. Найдите каталог cgroup runner**
454
455На хосте, а не внутри контейнера, найдите ID процесса runner, например с помощью `ps`. Прочитайте `/proc/<pid>/cgroup` для этого ID:
456
457* **Есть строка, содержащая `:pids:`**: хост использует cgroup v1, а каталог — это `/sys/fs/cgroup/pids`, за которым следует текст после `:pids:`
458* **Единственная строка начинается с `0::`**: хост использует cgroup v2, а каталог — это `/sys/fs/cgroup`, за которым следует текст после `0::`
459
460**3. Выполните репрезентативную сборку и запишите пик**
461
462Проведите одну сессию через репрезентативную сборку и возьмите пиковое значение из каталога cgroup runner:
463
464* **В каталоге есть `pids.peak`**: прочитайте этот файл после завершения сборки
465* **В каталоге нет `pids.peak`**: читайте `pids.current` раз в секунду во время сборки и сохраняйте наибольшее значение. Пик между двумя чтениями останется незамеченным, поэтому считайте это значение заниженной оценкой.
466
467**4. Умножьте на число сессий, делящих лимит**
468
469* **Pod, контейнер или unit одного runner**: умножьте пик на `--capacity` этого runner
470* **Лимит, который делят несколько runner**: умножьте пик на сумму их capacity
471
472Затем добавьте пик всего остального, что делит лимит, например другого контейнера в Pod.
473
474**5. Задайте лимит выше полученного результата**
475
476Более высокий лимит оставляет запас для более тяжёлых сборок, а более низкий быстрее останавливает fork-бомбу.
477
478#### Проверьте лимит `pids.max`
479
480* **Проверьте, был ли достигнут `pids.max`**: найдите в логе ядра хоста, например с помощью `dmesg`, строку, содержащую `cgroup: fork rejected by pids controller in` и путь cgroup. Ядро записывает её в лог только в первый раз, когда отказывает в создании процесса или потока в этой cgroup, поэтому ищите по всему логу.
481* **Узнайте действующий лимит**: прочитайте `pids.max` в каталоге cgroup runner и в каждом каталоге выше него. Наименьшее значение и есть действующий лимит, а `max` означает отсутствие лимита на этом уровне.
383 482
384## Kubernetes483## Kubernetes
385 484
577 676
578Что путь переиспользования делает и не гарантирует:677Что путь переиспользования делает и не гарантирует:
579 678
580* **Любая форма клона работает**: полный, неглубокий или однозвездный клон на пути используется как есть. Runner никогда не передает `--depth` при получении в существующий клон, поэтому полный pre-warm держит свою полную историю и неглубокий остается неглубоким. `CLAUDE_RUNNER_FETCH_DEPTH` (`full`, `0` или число; по умолчанию 50) контролирует только холодный клон, который runner делает, когда клон еще не существует.679* **Глубина клона**: создавайте клон без `--depth`, с `--single-branch` или без него. Runner никогда не передает `--depth` при выполнении fetch в клон с удаленным репозиторием `origin`, даже если вы задали [`CLAUDE_RUNNER_FETCH_DEPTH`](https://code.claude.com/docs/ru/self-hosted-environments-reference#environment-variable-only-settings). С полным клоном каждая сессия загружает только те коммиты, которых нет в клоне. С неглубоким клоном сессия в ветке, ответвившейся до самого старого коммита клона, загружает всю историю этой ветки.
581* **Отслеживаемые изменения сбрасываются, неотслеживаемые файлы сохраняются**: при `--capacity 1` каждая сессия начинается с жесткого сброса, который стирает отслеживаемые изменения предыдущей сессии, но runner никогда не запускает `git clean`, поэтому неотслеживаемые файлы из более ранних сессий заблокированного владельца остаются в дереве.680* **Отслеживаемые изменения сбрасываются, неотслеживаемые файлы сохраняются**: при `--capacity 1` каждая сессия начинается с жесткого сброса, который стирает отслеживаемые изменения предыдущей сессии, но runner никогда не запускает `git clean`, поэтому неотслеживаемые файлы из более ранних сессий заблокированного владельца остаются в дереве.
582* **Каталоги для каждого сеанса также сохраняются**: рядом с checkout runner создает записи для каждого сеанса под `<base-dir>/_sessions/` для каждого сеанса, который он запускает. Локальный каталог конфигурации Claude сеанса содержит локальную копию транскрипта беседы. Рядом с ним находятся загруженные файлы сеанса, когда сеанс их имеет. Каталог сеанса находится там же: он содержит любые worktrees для каждого сеанса и `checkout` hook checkouts во время работы сеанса, и он сохраняет все остальное, что Claude написал в нем.681* **Каталоги для каждого сеанса также сохраняются**: рядом с checkout runner создает записи для каждого сеанса под `<base-dir>/_sessions/` для каждого сеанса, который он запускает. Локальный каталог конфигурации Claude сеанса содержит локальную копию транскрипта беседы. Рядом с ним находятся загруженные файлы сеанса, когда сеанс их имеет. Каталог сеанса находится там же: он содержит любые worktrees для каждого сеанса и `checkout` hook checkouts во время работы сеанса, и он сохраняет все остальное, что Claude написал в нем.
583 682
587* **С git proxy pre-warm в формате `reftable` теряет свои refs**: очищая `.git/` перед каждой сессией, runner сохраняет `.git/refs/` и удаляет каталог `.git/reftable/`. Клон, подготовленный в формате refs `reftable` в git, при этом теряет свои refs, поэтому выполняйте pre-warm клона в формате refs `files`.686* **С git proxy pre-warm в формате `reftable` теряет свои refs**: очищая `.git/` перед каждой сессией, runner сохраняет `.git/refs/` и удаляет каталог `.git/reftable/`. Клон, подготовленный в формате refs `reftable` в git, при этом теряет свои refs, поэтому выполняйте pre-warm клона в формате refs `files`.
588* **Длинные клоны не нуждаются в обходном пути**: runner ограничивает каждую операцию git с помощью 120-секундного наблюдателя без прогресса и 30-минутного жесткого лимита, а не плоского тайм-аута, поэтому медленный холодный клон, который продолжает сообщать о прогрессе, завершается.687* **Длинные клоны не нуждаются в обходном пути**: runner ограничивает каждую операцию git с помощью 120-секундного наблюдателя без прогресса и 30-минутного жесткого лимита, а не плоского тайм-аута, поэтому медленный холодный клон, который продолжает сообщать о прогрессе, завершается.
589 688
689### Убедитесь, что runner использует ваш клон
690
691Чтобы убедиться, что runner использует ваш клон, запустите его с [`--log-level debug`](https://code.claude.com/docs/ru/self-hosted-environments-reference#runner-cli-flags) и начните сессию в репозитории. Runner записывает в лог `Prefetched repo found at` и путь к клону. Если вместо этого он записывает `No prefetched repo, fresh init at`, значит, по пути, указанному в этой строке, он не нашел пригодного клона. Проверьте, что ваш клон находится по этому пути, принадлежит пользователю runner и имеет удаленный репозиторий с именем `origin`.
692
693Если runner находит ваш клон, но сессии по-прежнему запускаются медленно, проверьте, не является ли клон неглубоким.
694
590## Закрепите версию695## Закрепите версию
591 696
592Дочерний процесс каждой сессии по умолчанию запускает собственный бинарный файл runner, и runner отключает auto-update внутри сессий, которые он порождает. При таком поведении по умолчанию каждая сессия запускает версию, которую вы установили на хосте или встроили в образ. Обновление на уровне хоста вступает в силу в следующий раз, когда runner запускается.697Дочерний процесс каждой сессии по умолчанию запускает собственный бинарный файл runner, и runner отключает auto-update внутри сессий, которые он порождает. При таком поведении по умолчанию каждая сессия запускает версию, которую вы установили на хосте или встроили в образ. Обновление на уровне хоста вступает в силу в следующий раз, когда runner запускается.
609* **Фиксированный флот**: запустите статический набор реплик runner и масштабируйте на [Prometheus metrics](https://code.claude.com/docs/ru/self-hosted-environments-reference.md#prometheus-metrics), которые обслуживает каждый runner714* **Фиксированный флот**: запустите статический набор реплик runner и масштабируйте на [Prometheus metrics](https://code.claude.com/docs/ru/self-hosted-environments-reference.md#prometheus-metrics), которые обслуживает каждый runner
610* **On-demand runners**: запустите подкоманду `claude self-hosted-runner orchestrator`, которая опрашивает Anthropic для сеансов, которые поставлены в очередь без доступного runner и вызывает ваш hook `spawn-runner` для загрузки одного на сеанс. См. [On-demand runners](https://code.claude.com/docs/ru/self-hosted-environments-configuration.md#on-demand-runners).715* **On-demand runners**: запустите подкоманду `claude self-hosted-runner orchestrator`, которая опрашивает Anthropic для сеансов, которые поставлены в очередь без доступного runner и вызывает ваш hook `spawn-runner` для загрузки одного на сеанс. См. [On-demand runners](https://code.claude.com/docs/ru/self-hosted-environments-configuration.md#on-demand-runners).
611 716
717### Освобождение простаивающих сессий во фиксированном флоте
718
719Если сессии остаются в очереди во фиксированном флоте, хотя все runners в сети, причиной могут быть простаивающие сессии. По умолчанию сессия сохраняет свой слот после завершения своего хода, а её runner остаётся заблокированным за [владельцем](https://code.claude.com/docs/ru/self-hosted-environments#key-concepts) этой сессии. Если [облачная запланированная задача](https://code.claude.com/docs/ru/routines.md) вашей команды запускает новую сессию при каждом выполнении, её простаивающие сессии могут занять все слоты.
720
721Чтобы проверить это, посмотрите `claude_code_self_hosted_runner_session_idle_seconds` в [Prometheus metrics](https://code.claude.com/docs/ru/self-hosted-environments-reference.md#prometheus-metrics) каждого runner. У каждой сессии, которую удерживает runner, есть собственный ряд: `0`, пока сессия занята, в противном случае — количество секунд с момента перехода в простой. Выберите допустимое время простоя: дольше пауз, которые люди делают посреди задачи, и достаточно короткое, чтобы каждое выполнение освобождалось до начала следующего выполнения запланированной задачи. Сравните ряды с этим временем.
722
723* **Ряды выше этого времени, например `1800` для 30 минут**: простаивающие сессии удерживают эти слоты, поэтому задайте `--release-idle-session-min`
724* **Все ряды ниже него**: ни одна сессия не простаивала так долго. Добавьте runners или задайте [`--kill-session-after-min`](https://code.claude.com/docs/ru/self-hosted-environments-reference#runner-cli-flags) для [сессий, которые никогда не переходят в простой](#some-sessions-don’t-count-as-idle).
725* **Runner без рядов**: его не удерживает ни одна сессия. См. **Sessions stay queued** в разделе [Устранение неполадок](#troubleshooting).
726* **Runner, метрики которого не отвечают**: его процесс мог завершиться. См. **An environment that looks healthy** в разделе [Когда runner завершает работу](#when-the-runner-exits).
727
728Чтобы освобождать простаивающие сессии, запускайте каждый runner с [`--release-idle-session-min`](https://code.claude.com/docs/ru/self-hosted-environments-reference#runner-cli-flags) и этим временем в минутах, например `--release-idle-session-min 30`. Тогда runner освобождает любую сессию, которая простаивает так долго, независимо от того, запустила её запланированная задача или человек.
729
730* **Неотправленная работа**: освобождённая сессия возобновляется при следующем сообщении, но без работы, которую она не отправила (push). Чтобы сохранить её коммиты, см. [Resumed sessions lose unpushed work](#additional-limitations).
731* **Завершение runner**: runner, освободивший свою последнюю сессию, начинает [обычное завершение](#when-the-runner-exits). Настройте ваш супервизор так, чтобы он перезапускал его на чистой файловой системе, как описано в разделе [Усиление защиты развёртывания](#harden-your-deployment).
732* **Сессии, которые никогда не переходят в простой**: также задайте [`--kill-session-after-min`](https://code.claude.com/docs/ru/self-hosted-environments-reference#runner-cli-flags), потому что [некоторые сессии не считаются простаивающими](#some-sessions-don’t-count-as-idle)
733
612## Известные проблемы и ограничения734## Известные проблемы и ограничения
613 735
614Ниже приведены ограничения в этом выпуске с обходными путями, где они существуют.736Ниже приведены ограничения в этом выпуске с обходными путями, где они существуют.
642### Дополнительные ограничения764### Дополнительные ограничения
643 765
644* **Возобновлённые сессии теряют неотправленную работу**: новый runner заново клонирует репозиторий с его начальной ветки, поэтому работа, которую сессия не отправила, теряется.766* **Возобновлённые сессии теряют неотправленную работу**: новый runner заново клонирует репозиторий с его начальной ветки, поэтому работа, которую сессия не отправила, теряется.
645 * **Чтобы сохранить закоммиченную работу**: задайте [`--push-outcome-on-release`](https://code.claude.com/docs/ru/self-hosted-environments-reference#runner-cli-flags) на каждом runner в окружении, поскольку runner без этого флага возобновляет сессию с её начальной ветки. Runner с этим флагом перед освобождением по возможности отправляет (push) ветки результатов сессии, и возобновлённая сессия начинается с этих коммитов. Для push используются собственные учётные данные git хоста runner, в том числе на runner, который использует [управляемый Anthropic git](#use-the-anthropic-git-proxy). Незакоммиченные изменения всё равно теряются.767 * **Чтобы сохранить закоммиченную работу**: задайте [`--push-outcome-on-release`](https://code.claude.com/docs/ru/self-hosted-environments-reference#runner-cli-flags) на каждом runner в окружении, поскольку runner без этого флага возобновляет сессию с её начальной ветки. Runner с этим флагом перед освобождением по возможности отправляет (push) ветки результатов сессии, и возобновлённая сессия начинается с этих коммитов. Для push используются собственные учётные данные git хоста runner, в том числе на runner, который использует [управляемый Anthropic git](#use-the-anthropic-git-proxy).
646 * **С хуком `checkout`**: репозитории, извлечённые с помощью [хука жизненного цикла `checkout`](https://code.claude.com/docs/ru/self-hosted-environments-configuration#checkout), не отправляются. Вместо этого сохраняйте их снимки из [хука `post-session`](https://code.claude.com/docs/ru/self-hosted-environments-configuration#post-session).768 * **С хуком `checkout`**: репозитории, извлечённые с помощью [хука жизненного цикла `checkout`](https://code.claude.com/docs/ru/self-hosted-environments-configuration#checkout), не отправляются. Вместо этого сохраняйте их снимки из [хука `post-session`](https://code.claude.com/docs/ru/self-hosted-environments-configuration#post-session).
647 * **Перед включением флага**: ограничьте круг тех, кто может выполнять push в refs `claude/*` на исходном удалённом репозитории. При возобновлении runner получает ранее отправленную ветку, не проверяя, кто её отправил.769 * **Перед включением флага**: ограничьте круг тех, кто может выполнять push в refs `claude/*` на исходном удалённом репозитории. При возобновлении runner получает ранее отправленную ветку, не проверяя, кто её отправил.
770 * **Незакоммиченные изменения всё равно теряются**: чтобы побудить Claude делать коммит и push по завершении ответа, см. [Побуждение сессий отправлять свою работу](https://code.claude.com/docs/ru/self-hosted-environments-configuration.md#prompt-sessions-to-push-their-work)
648* **Репозиторий, добавленный в середине сессии, может не клонироваться**: Claude клонирует его с помощью `git clone` по HTTPS. На runner без [`--use-anthropic-git-proxy`](#use-the-anthropic-git-proxy) клонирование завершается ошибкой аутентификации git, если ничто на хосте не может прочитать репозиторий. По возможности выбирайте все необходимые сессии репозитории при её создании.771* **Репозиторий, добавленный в середине сессии, может не клонироваться**: Claude клонирует его с помощью `git clone` по HTTPS. На runner без [`--use-anthropic-git-proxy`](#use-the-anthropic-git-proxy) клонирование завершается ошибкой аутентификации git, если ничто на хосте не может прочитать репозиторий. По возможности выбирайте все необходимые сессии репозитории при её создании.
649* **Некоторые коннекторы не появляются в самостоятельно размещаемых сеансах**: коннектор, который вы еще не подключили в параметрах claude.ai, не указан в самостоятельно размещаемом сеансе, и сеанс не будет вас приглашать подключить его. Подключите его в параметрах сначала, затем запустите свежий сеанс. Добавление коннектора в уже работающий сеанс тоже не делает его инструменты доступными для Claude; запустите свежий сеанс, чтобы подхватить недавно добавленный коннектор.772* **Некоторые коннекторы не появляются в самостоятельно размещаемых сеансах**: коннектор, который вы еще не подключили в параметрах claude.ai, не указан в самостоятельно размещаемом сеансе, и сеанс не будет вас приглашать подключить его. Подключите его в параметрах сначала, затем запустите свежий сеанс. Добавление коннектора в уже работающий сеанс тоже не делает его инструменты доступными для Claude; запустите свежий сеанс, чтобы подхватить недавно добавленный коннектор.
650* **Когда кто-то архивирует или удаляет сессию либо освобождает её runner из меню сессии**: не рассчитывайте на push через [`--push-outcome-on-release`](https://code.claude.com/docs/ru/self-hosted-environments-reference#runner-cli-flags). Чтобы сохранить коммиты в этих случаях, отправляйте `HEAD` в резервную ветку из [хука `post-session`](https://code.claude.com/docs/ru/self-hosted-environments-configuration#post-session). Если вы берёте за основу приведённый там пример, сделайте так, чтобы он выполнял push, даже когда незакоммиченных изменений нет, поскольку он выполняет push только после коммита-снимка.773* **Когда кто-то архивирует или удаляет сессию либо освобождает её runner из меню сессии**: не рассчитывайте на push через [`--push-outcome-on-release`](https://code.claude.com/docs/ru/self-hosted-environments-reference#runner-cli-flags). Чтобы сохранить коммиты в этих случаях, отправляйте `HEAD` в резервную ветку из [хука `post-session`](https://code.claude.com/docs/ru/self-hosted-environments-configuration#post-session). Если вы берёте за основу приведённый там пример, сделайте так, чтобы он выполнял push, даже когда незакоммиченных изменений нет, поскольку он выполняет push только после коммита-снимка.
684* **Сессии завершаются сбоем сразу после принятия**: откройте сессию в claude.ai/code, чтобы увидеть ошибку. Если ошибка показывает, что git не смог пройти аутентификацию, проверьте [учётные данные git](#configure-git) runner'а. Для runner'а, запущенного с `--use-anthropic-git-proxy`, см. [Если сессии не запускаются на runner'е с git-прокси](#when-anthropic-doesnt-serve-a-session).807* **Сессии завершаются сбоем сразу после принятия**: откройте сессию в claude.ai/code, чтобы увидеть ошибку. Если ошибка показывает, что git не смог пройти аутентификацию, проверьте [учётные данные git](#configure-git) runner'а. Для runner'а, запущенного с `--use-anthropic-git-proxy`, см. [Если сессии не запускаются на runner'е с git-прокси](#when-anthropic-doesnt-serve-a-session).
685 808
686 Базовый каталог, недоступный для записи, останавливает runner при запуске, а не приводит к сбою сессий. См. пункт **Runner завершается при запуске с `cannot create or write to base directory`** в этом списке.809 Базовый каталог, недоступный для записи, останавливает runner при запуске, а не приводит к сбою сессий. См. пункт **Runner завершается при запуске с `cannot create or write to base directory`** в этом списке.
810* **Сессия принята, но Claude так и не отвечает на её первое сообщение**: если ваши runner'ы подключаются к `api.anthropic.com` через прокси, настройте его так, чтобы ответ `/worker/events/stream` сессии передавался по мере поступления. Увеличение таймаутов runner'а не поможет. Чтобы подтвердить причину по логу runner'а, см. [Сессия принята, но Claude так и не отвечает на её первое сообщение](#when-a-sessions-first-message-is-never-answered).
687* **Сессии не запускаются на runner'е, для которого задан `--use-anthropic-git-proxy`**: ищите в логе runner'а `access denied by the git proxy` или ошибку git, в которой указан адрес `api.anthropic.com`, содержащий `/git_proxy/`. Чтобы определить, обслуживала ли Anthropic сессию, и устранить причину, см. [Если сессии не запускаются на runner'е с git-прокси](#when-anthropic-doesnt-serve-a-session).811* **Сессии не запускаются на runner'е, для которого задан `--use-anthropic-git-proxy`**: ищите в логе runner'а `access denied by the git proxy` или ошибку git, в которой указан адрес `api.anthropic.com`, содержащий `/git_proxy/`. Чтобы определить, обслуживала ли Anthropic сессию, и устранить причину, см. [Если сессии не запускаются на runner'е с git-прокси](#when-anthropic-doesnt-serve-a-session).
688* **Сессии не могут выйти в сеть через исходящий прокси с аутентификацией**: когда источник, заданный с помощью [`--proxy-authorization-command` или `--proxy-authorization-file`](#authenticate-to-an-egress-proxy), завершается сбоем, превышает таймаут в 30 секунд или возвращает пустое значение, runner отвечает на это соединение `502 Bad Gateway` и записывает причину в лог. Runner скрывает stderr команды в этом логе и никогда не записывает в лог значение заголовка. При использовании `--proxy-authorization-command` выполните команду на хосте самостоятельно, чтобы убедиться, что она выводит полное значение заголовка в stdout. Если вместо этого runner завершается при запуске с `could not start the proxy-authorization listener`, он не смог открыть свой loopback-слушатель.812* **Сессии не могут выйти в сеть через исходящий прокси с аутентификацией**: когда источник, заданный с помощью [`--proxy-authorization-command` или `--proxy-authorization-file`](#authenticate-to-an-egress-proxy), завершается сбоем, превышает таймаут в 30 секунд или возвращает пустое значение, runner отвечает на это соединение `502 Bad Gateway` и записывает причину в лог. Runner скрывает stderr команды в этом логе и никогда не записывает в лог значение заголовка. При использовании `--proxy-authorization-command` выполните команду на хосте самостоятельно, чтобы убедиться, что она выводит полное значение заголовка в stdout. Если вместо этого runner завершается при запуске с `could not start the proxy-authorization listener`, он не смог открыть свой loopback-слушатель.
689* **Runner записывает в лог строки `Poll failed`, содержащие `rejecting the malformed poll response`**: runner получил ответ на опрос очереди работ, тело которого не является ожидаемым JSON очереди. Одна из причин — перехватывающий прокси или captive portal, отвечающий собственной страницей. Если runner подключается через прокси, настройте прокси так, чтобы ответы от `api.anthropic.com` передавались без изменений.813* **Runner записывает в лог строки `Poll failed`, содержащие `rejecting the malformed poll response`**: runner получил ответ на опрос очереди работ, тело которого не является ожидаемым JSON очереди. Одна из причин — перехватывающий прокси или captive portal, отвечающий собственной страницей. Если runner подключается через прокси, настройте прокси так, чтобы ответы от `api.anthropic.com` передавались без изменений.
708* **Сессия не запускается с `This runner couldn't read`**: runner запросил у git-хоста репозиторий со своими [учётными данными git](#configure-git) и получил ответ «не найдено». Репозиторий не существует, или эти учётные данные не дают доступа к репозиторию.832* **Сессия не запускается с `This runner couldn't read`**: runner запросил у git-хоста репозиторий со своими [учётными данными git](#configure-git) и получил ответ «не найдено». Репозиторий не существует, или эти учётные данные не дают доступа к репозиторию.
709 * **Если вы администрируете runner**: предоставьте его учётным данным git доступ на чтение к репозиторию, затем запустите новую сессию.833 * **Если вы администрируете runner**: предоставьте его учётным данным git доступ на чтение к репозиторию, затем запустите новую сессию.
710 * **Если вы запустили сессию**: если репозиторий не существует, запустите новую сессию с правильным репозиторием. Если у runner'а нет доступа к репозиторию, попросите администратора runner'а предоставить доступ, затем запустите новую сессию.834 * **Если вы запустили сессию**: если репозиторий не существует, запустите новую сессию с правильным репозиторием. Если у runner'а нет доступа к репозиторию, попросите администратора runner'а предоставить доступ, затем запустите новую сессию.
711* **Сессии запускаются несколько минут**: обычно основное время занимает первоначальное клонирование. Чтобы убедиться в этом, следите за [метрикой](https://code.claude.com/docs/ru/self-hosted-environments-reference.md#prometheus-metrics) `claude_code_self_hosted_runner_session_init_duration_seconds`, и сократите клонирование с помощью [предварительно подготовленного checkout](#reuse-a-pre-warmed-checkout) или меньшего значения `CLAUDE_RUNNER_FETCH_DEPTH`.835* **Сессии запускаются или возобновляются несколько минут**: одна из причин — клонирование с нуля. В парке, где каждый runner запускается на пустом диске без [хука `checkout`](https://code.claude.com/docs/ru/self-hosted-environments-configuration#checkout), runner заново клонирует репозитории сессии, прежде чем запустить Claude Code. Сессия, которая возобновляется на пустом диске, снова ждёт того же клонирования.
836
837 Чтобы избежать клонирования с нуля, предоставьте [предварительно подготовленный checkout](#reuse-a-pre-warmed-checkout). Если вы уже его предоставляете, [убедитесь, что runner его использует](#confirm-that-the-runner-uses-your-clone). Если runner сам создаёт клон и завершается после одной сессии, уменьшите [`CLAUDE_RUNNER_FETCH_DEPTH`](https://code.claude.com/docs/ru/self-hosted-environments-reference#environment-variable-only-settings) со значения по умолчанию в 50 коммитов, чтобы получать меньше истории.
838
839 Если вы используете хук, он выполняется вместо клонирования runner'ом, поэтому вместо этого проверьте, что делает ваш хук. Следите за [метрикой](https://code.claude.com/docs/ru/self-hosted-environments-reference.md#prometheus-metrics) `claude_code_self_hosted_runner_session_init_duration_seconds`, чтобы видеть, сколько времени занимают запуски.
712* **Ходы завершаются с ошибкой 401**: когда ход заканчивается ответом 401 или 403 от Anthropic API, runner получает новый [`CLAUDE_CODE_OAUTH_TOKEN`](https://code.claude.com/docs/ru/self-hosted-environments-configuration#wrapper-scripts) от Anthropic и передаёт его сессии. Неудавшийся ход не повторяется. Этот токен краткосрочный, и runner ротирует его через stdin сессии.840* **Ходы завершаются с ошибкой 401**: когда ход заканчивается ответом 401 или 403 от Anthropic API, runner получает новый [`CLAUDE_CODE_OAUTH_TOKEN`](https://code.claude.com/docs/ru/self-hosted-environments-configuration#wrapper-scripts) от Anthropic и передаёт его сессии. Неудавшийся ход не повторяется. Этот токен краткосрочный, и runner ротирует его через stdin сессии.
713 841
714 Когда получение токена не удаётся, runner записывает в лог строку `inference_token refresh failed` с указанием, когда будет повторная попытка, и продолжает повторять попытки, пока работает сессия.842 Когда получение токена не удаётся, runner записывает в лог строку `inference_token refresh failed` с указанием, когда будет повторная попытка, и продолжает повторять попытки, пока работает сессия.
788 916
789Для пошаговой диагностики на хосте runner'а запустите [подкоманду doctor](#troubleshooting).917Для пошаговой диагностики на хосте runner'а запустите [подкоманду doctor](#troubleshooting).
790 918
919### Сессия принята, но Claude так и не отвечает на её первое сообщение
920
921Если runner принимает сессию, но Claude так и не отвечает на первое сообщение, а ваши runner'ы подключаются к `api.anthropic.com` через прокси, причиной может быть прокси. Anthropic отправляет сессии её сообщения через один потоковый ответ, который остаётся открытым. Если ваш прокси буферизует его или закрывает, прежде чем что-либо передать, первое сообщение так и не доходит. Другие запросы сессии при этом выполняются успешно.
922
923Чтобы это исправить, измените то, как прокси обрабатывает этот запрос:
924
925```text theme={null}
926GET https://api.anthropic.com/v1/code/sessions/<session-id>/worker/events/stream
927```
928
929* **Не буферизуйте ответ**: передавайте его по мере поступления. Его тип содержимого — `text/event-stream`.
930* **Позвольте ответу оставаться открытым**: он может оставаться открытым до часа. Если у прокси есть таймаут бездействия, сделайте его значительно больше 15 секунд, поскольку по умолчанию Anthropic отправляет keep-alive как минимум с такой частотой.
931
932Затем запустите новую сессию и проверьте, что Claude отвечает. Увеличение таймаутов runner'а не поможет: вы лишь дольше ждёте, прежде чем runner остановит сессию.
933
934#### Подтвердите причину по логу runner'а
935
936Эти шаги предназначены для runner'ов на Claude Code v2.1.287 или новее с уровнем логирования по умолчанию `--log-level info`. Более старые runner'ы записывают эти строки позже или не записывают вовсе.
937
9381. Дождитесь истечения [`--startup-timeout-min`](https://code.claude.com/docs/ru/self-hosted-environments-reference#runner-cli-flags), по умолчанию 15 минут. Затем runner останавливает сессию и записывает в лог строку, которая содержит `no child output for` и заканчивается на `— releasing`.
9392. Найдите в логе runner'а `SDKStartup: SSE`. Эти строки следуют за строкой `finished: interrupted`, через несколько строк после строки из шага 1. У большинства из них нет временной метки, поэтому сборщик логов может показывать их в другом месте.
9403. Найдите строку в этой таблице:
941
942| Строка лога содержит | Что делать |
943| :- | :- |
944| `SSE connect failed (no response in 30s)` или `SSE liveness timeout` | Проверьте, что прокси пересылает запрос, передаёт заголовки и данные ответа по мере поступления и не разрывает соединение |
945| `SSE connect failed (HTTP` и код состояния | Проверьте собственный лог прокси. Если прокси сам ответил на запрос, пропустите запрос через него. |
946| `SSE connect failed (` и любой другой текст | Текст в скобках — это ошибка. Найдите то же соединение в собственном логе прокси. |
947| `SSE stream ended by server`, снова и снова | Проверьте ограничение прокси по времени для долгоживущих ответов. Одна такая строка — это нормально. |
948| `SSE reconnected after` | Ищите после неё одну из других строк. Эта строка не означает, что что-либо дошло до сессии. |
949
950Если в логе нет ни одной из этих строк или в логе прокси нет признаков проблемы, [сообщите о проблеме](#report-an-issue).
951
952#### Остановите повторные попытки сессии
953
954Сессия сохраняет сообщение как ожидающее, и runner, который может обслуживать владельца сессии, снова принимает сессию. Пока вы не измените прокси, сессия каждый раз ждёт так же. Чтобы это прекратить, архивируйте сессию в claude.ai/code.
955
791## Что дальше956## Что дальше
792 957
793* [Customize sessions](https://code.claude.com/docs/ru/self-hosted-environments-configuration.md): скрипты-обертки, lifecycle hooks, on-demand runners, MCP servers и разрешения958* [Customize sessions](https://code.claude.com/docs/ru/self-hosted-environments-configuration.md): скрипты-обертки, lifecycle hooks, on-demand runners, MCP servers и разрешения