31| Переменная | Описание |31| Переменная | Описание |
32| :- | :- |32| :- | :- |
33| `CLAUDE_CODE_SESSION_ACCESS_TOKEN` | JWT сессии с префиксом `sk-ant-cc-`. Его утверждение `act` идентифицирует создателя сессии, вместе с электронной почтой создателя, если интерфейс, создавший сессию, её записал. Значение — это токен на момент порождения процесса; обновления поступают через stdin дочернего процесса, поэтому обёртка видит только начальное значение. См. [Проверка идентичности сессии](/docs/ru/self-hosted-environments-identity). |33| `CLAUDE_CODE_SESSION_ACCESS_TOKEN` | JWT сессии с префиксом `sk-ant-cc-`. Его утверждение `act` идентифицирует создателя сессии, вместе с электронной почтой создателя, если интерфейс, создавший сессию, её записал. Значение — это токен на момент порождения процесса; обновления поступают через stdin дочернего процесса, поэтому обёртка видит только начальное значение. См. [Проверка идентичности сессии](/docs/ru/self-hosted-environments-identity). |
34| `CCR_SESSION_ACCOUNT_EMAIL` | Электронная почта создателя сессии, предварительно извлечённая средством выполнения из утверждения `act.email` токена без проверки подписи. Подходит для маркировки, например для трейлеров коммитов. Когда электронная почта управляет выдачей учётных данных, вместо этого проверьте токен и прочитайте утверждение из него; см. [Подготовка учётных данных, ограниченных создателем сессии](#provision-credentials-scoped-to-the-session-creator). Не установлена, когда токен не содержит электронную почту создателя. Рассматривайте как персональные данные. |34| `CCR_SESSION_ACCOUNT_EMAIL` | Электронная почта создателя сессии, предварительно извлечённая средством выполнения из утверждения `act.email` токена без проверки подписи. Подходит для маркировки, например для трейлеров коммитов. Когда электронная почта управляет выдачей учётных данных, вместо этого проверьте токен и прочитайте утверждение из него. См. [Подготовка учётных данных, ограниченных создателем сессии](#provision-credentials-scoped-to-the-session-creator). Не установлена, когда токен не содержит электронную почту создателя, например в сессиях, которые создаёт служебная учётная запись вашей организации. Рассматривайте как персональные данные. |
35| `CLAUDE_RUNNER_CLIENT_PLATFORM` | Клиентский интерфейс, который создал сессию, например `web_claude_ai`, `desktop_app`, `ios`, `claude_code_cli` или `scheduled_trigger`. Anthropic записывает значение один раз при создании сессии, поэтому обёртка и каждый хук жизненного цикла видят одно и то же значение. Используйте его только для аналитики внедрения и маркировки, а не как сигнал авторизации. Не установлена, когда у сессии нет записанного или распознанного интерфейса, поэтому ссылайтесь на неё как `${CLAUDE_RUNNER_CLIENT_PLATFORM:-}` при `set -u`. Требует Claude Code v2.1.229 или новее. |35| `CLAUDE_RUNNER_CLIENT_PLATFORM` | Клиентский интерфейс, который создал сессию, например `web_claude_ai`, `desktop_app`, `ios`, `claude_code_cli` или `scheduled_trigger`. Anthropic записывает значение один раз при создании сессии, поэтому обёртка и каждый хук жизненного цикла видят одно и то же значение. Используйте его только для аналитики внедрения и маркировки, а не как сигнал авторизации. Не установлена, когда у сессии нет записанного или распознанного интерфейса. Требует Claude Code v2.1.229 или новее. |
36| `CLAUDE_RUNNER_CLAUDE_BIN` | Абсолютный путь к собственному двоичному файлу Claude Code средства выполнения. Завершите вашу обёртку командой `exec "$CLAUDE_RUNNER_CLAUDE_BIN" "$@"`, чтобы передать управление закреплённому двоичному файлу без жёсткого кодирования пути установки. |36| `CLAUDE_RUNNER_CLAUDE_BIN` | Абсолютный путь к собственному двоичному файлу Claude Code средства выполнения. Завершите вашу обёртку командой `exec "$CLAUDE_RUNNER_CLAUDE_BIN" "$@"`, чтобы передать управление закреплённому двоичному файлу без жёсткого кодирования пути установки. |
37| `CLAUDE_CODE_REMOTE_SESSION_ID` | ID сессии в форме с тегом `cse_...`. Это та же сессия, которую [хуки жизненного цикла](#lifecycle-hooks) видят как `CLAUDE_RUNNER_SESSION_ID` в форме `session_...`; переменные UUID совпадают в обоих случаях, а замена префикса `cse_` на `session_` даёт ID, показанный в URL сессии. |37| `CLAUDE_CODE_REMOTE_SESSION_ID` | ID сессии в форме с тегом `cse_...`. Это та же сессия, которую [хуки жизненного цикла](#lifecycle-hooks) видят как `CLAUDE_RUNNER_SESSION_ID` в форме `session_...`; переменные UUID совпадают в обоих случаях, а замена префикса `cse_` на `session_` даёт ID, показанный в URL сессии. |
38| `CLAUDE_CODE_REMOTE_SESSION_UUID` | Тот же ID сессии в канонической форме UUID для систем, которые используют UUID в качестве ключа. |38| `CLAUDE_CODE_REMOTE_SESSION_UUID` | Тот же ID сессии в канонической форме UUID для систем, которые используют UUID в качестве ключа. |
39| `CLAUDE_CODE_REMOTE_SLACK_THREAD_URL` | Для сессии [Claude Tag](https://claude.com/docs/claude-tag/overview), которая относится к одной ветке Slack, — ссылка на эту ветку. Не установлена для других сессий и может быть не установлена и для сессии ветки. |
40| `CLAUDE_CODE_REMOTE_SLACK_THREAD_TS` | Для сессии Claude Tag, которая относится к одной ветке Slack, — временная метка Slack этой ветки, например `1700000000.000100`. Может быть не установлена, а также может быть установлена, когда `CLAUDE_CODE_REMOTE_SLACK_THREAD_URL` не установлена, поэтому проверяйте каждую переменную отдельно. |
39| `CLAUDE_SESSION_INGRESS_TOKEN_FILE` | Абсолютный путь к файлу для каждой сессии, содержащему текущий JWT сессии, который поддерживается в актуальном состоянии при обновлении токенов. Подпроцессы оболочки читают его для своего заголовка `Authorization` при загрузке вложений, которые пользователь добавил в сессию. `exec` сохраняет переменную автоматически; обёртка, которая перестраивает окружение дочернего процесса, должна перенести переменную, иначе загрузки вложений молча прекратятся. |41| `CLAUDE_SESSION_INGRESS_TOKEN_FILE` | Абсолютный путь к файлу для каждой сессии, содержащему текущий JWT сессии, который поддерживается в актуальном состоянии при обновлении токенов. Подпроцессы оболочки читают его для своего заголовка `Authorization` при загрузке вложений, которые пользователь добавил в сессию. `exec` сохраняет переменную автоматически; обёртка, которая перестраивает окружение дочернего процесса, должна перенести переменную, иначе загрузки вложений молча прекратятся. |
40| `CLAUDE_CONFIG_DIR` | Каталог конфигурации Claude для каждой сессии, записываемый при запуске сессии из снимка конфигурации хоста средства выполнения, который средство выполнения захватывает при запуске; см. [Разрешения и подтверждение инструментов](#permissions-and-tool-approval). Записи здесь изолированы для этой сессии. Каталог остаётся в `<base-dir>/_sessions/` после завершения сессии, если вы не запустите средство выполнения с [`--remove-session-state`](/docs/ru/self-hosted-environments-reference#runner-cli-flags); см. [Повторное использование предварительно подготовленного checkout](/docs/ru/self-hosted-environments-deploy#reuse-a-pre-warmed-checkout). |42| `CLAUDE_CONFIG_DIR` | Каталог конфигурации Claude для каждой сессии, записываемый при запуске сессии из снимка конфигурации хоста средства выполнения, который средство выполнения захватывает при запуске; см. [Разрешения и подтверждение инструментов](#permissions-and-tool-approval). Записи здесь изолированы для этой сессии. Каталог остаётся в `<base-dir>/_sessions/` после завершения сессии, если вы не запустите средство выполнения с [`--remove-session-state`](/docs/ru/self-hosted-environments-reference#runner-cli-flags); см. [Повторное использование предварительно подготовленного checkout](/docs/ru/self-hosted-environments-deploy#reuse-a-pre-warmed-checkout). |
41| `ANTHROPIC_BASE_URL` | Базовый URL API, который будет использовать дочерний процесс, доставляемый плоскостью управления для каждой сессии; обычно `https://api.anthropic.com`. Не переопределяйте его: учётные данные вывода сессии — это выданный Anthropic токен OAuth, который другие поставщики не принимают. |43| `ANTHROPIC_BASE_URL` | Базовый URL API, который будет использовать дочерний процесс, доставляемый плоскостью управления для каждой сессии; обычно `https://api.anthropic.com`. Не переопределяйте его: учётные данные вывода сессии — это выданный Anthropic токен OAuth, который другие поставщики не принимают. |
43 45
44Обёртка также наследует остальную часть управляемого окружения дочернего процесса, включая любые переменные окружения, предоставленные сервером. `exec` передаёт всё это автоматически; если ваша обёртка порождает дочерний процесс другим способом, пересылайте окружение полностью.46Обёртка также наследует остальную часть управляемого окружения дочернего процесса, включая любые переменные окружения, предоставленные сервером. `exec` передаёт всё это автоматически; если ваша обёртка порождает дочерний процесс другим способом, пересылайте окружение полностью.
45 47
48`CLAUDE_CODE_REMOTE_SLACK_THREAD_URL` и `CLAUDE_CODE_REMOTE_SLACK_THREAD_TS` доступны вашей обёртке или [хуку `command`](#command). Они также доступны тому, что запускает сессия, например shell-командам, хукам git и хукам Claude Code. Хуки `checkout`, `post-session` и `spawn-runner` их не получают.
49
50<h3 id="give-a-default-to-variables-that-can-be-unset">
51 Задавайте значение по умолчанию для переменных, которые могут быть не установлены
52</h3>
53
54Каждая из переменных `CCR_SESSION_ACCOUNT_EMAIL`, `CLAUDE_RUNNER_CLIENT_PLATFORM`, `CLAUDE_CODE_REMOTE_SLACK_THREAD_URL` и `CLAUDE_CODE_REMOTE_SLACK_THREAD_TS` может быть не установлена. Если ваш скрипт использует `set -u`, Bash останавливается с ошибкой `unbound variable` при раскрытии неустановленной переменной, поэтому раскрывайте их со значением по умолчанию, например `${CCR_SESSION_ACCOUNT_EMAIL:-}`.
55
56Везде, где оболочка раскрывает ссылку на ветку Slack, соблюдайте следующие меры предосторожности:
57
58* **Заключайте её в кавычки**: ссылка может содержать символы, на которые реагирует оболочка, например `?` и `&`, поэтому заключайте переменную в кавычки, как в `"${CLAUDE_CODE_REMOTE_SLACK_THREAD_URL:-}"`.
59* **Не подставляйте её значение в строки `eval` и `sh -c`**: не подставляйте её значение в строку, которую выполняет `eval` или `sh -c`, даже внутри кавычек. Вместо этого пусть такая строка ссылается на саму переменную.
60
46<h3 id="keep-stdin-and-file-descriptor-3-attached">61<h3 id="keep-stdin-and-file-descriptor-3-attached">
47 Сохраняйте stdin и дескриптор файла 3 подключёнными62 Сохраняйте stdin и дескриптор файла 3 подключёнными
48</h3>63</h3>
49 64
50stdin дочернего процесса — это канал управления средства выполнения. Ротации токенов и сигналы завершения сессии поступают через него. Средство выполнения также открывает канал на дескрипторе файла 3 и читает из него сигналы активности дочернего процесса для управления таймаутами простоя и запуска. Простой `exec "$CLAUDE_RUNNER_CLAUDE_BIN" "$@"` сохраняет оба автоматически.65stdin дочернего процесса — это канал управления средства выполнения. Ротации токенов и сигналы завершения сессии поступают через него. Средство выполнения также открывает канал на дескрипторе файла 3 и читает из него сигналы активности дочернего процесса для управления таймаутами простоя и запуска. Простой `exec "$CLAUDE_RUNNER_CLAUDE_BIN" "$@"` сохраняет оба автоматически.
51 66
52Если ваша обёртка переводит дочерний процесс в фоновый режим с помощью простого `&`, она разрывает stdin дочернего процесса: сессия выглядит работоспособной до истечения примерно 30-минутного времени жизни начального токена OAuth, после чего каждый вызов API завершается ошибкой `401 authentication_error`. Если ваша обёртка должна переводить дочерний процесс в фоновый режим, например чтобы сохранить ловушку очистки, сохраните stdin на дескрипторе файла 4 или выше и явно подключите его заново:67Если ваша обёртка переводит дочерний процесс в фоновый режим с помощью простого `&`, она разрывает stdin дочернего процесса. Сессия выглядит работоспособной до истечения примерно 30-минутного времени жизни начального токена OAuth, после чего каждый вызов API, использующий этот токен, завершается ошибкой `401 authentication_error`. Если ваша обёртка должна переводить дочерний процесс в фоновый режим, например чтобы сохранить ловушку очистки, сохраните stdin на дескрипторе файла 4 или выше и явно подключите его заново:
53 68
54```bash theme={null}69```bash theme={null}
55exec 4<&070exec 4<&0
59wait "$CHILD"74wait "$CHILD"
60```75```
61 76
62Не закрывайте и не переиспользуйте дескриптор файла 3 в обёртке. Перенаправлять stdout и stderr дочернего процесса можно.77Перенаправлять stdout дочернего процесса можно. Дескриптор файла 3 и stderr должны оставаться подключёнными к средству выполнения:
78
79* **Дескриптор файла 3**: передаёт сигналы активности дочернего процесса средству выполнения. Не закрывайте и не переиспользуйте его в обёртке.
80* **stderr**: когда обёртка или дочерний процесс завершается с ненулевым кодом выхода, средство выполнения публикует последние строки stderr в сессию и выводит их в свой собственный лог. Пользователь сессии видит эти строки, поэтому не выводите секреты в stderr и удалите `set -x` перед развёртыванием обёртки. Если вы перенаправите stderr, сессии по-прежнему будут работать, но средство выполнения будет сообщать о сбое только с кодом выхода.
63 81
64<h3 id="pass-the-system-prompt-flags-through">82<h3 id="pass-the-system-prompt-flags-through">
65 Передавайте флаги системного промпта дальше83 Передавайте флаги системного промпта дальше
108 checkout126 checkout
109</h3>127</h3>
110 128
111Запускается один раз на репозиторий вместо встроенного клонирования и получения данных runner'а. Используйте хук для клонирования из зеркала сквозного доступа, инициализации рабочего дерева из архива или применения аутентификации git для каждой сессии. Runner устанавливает эти переменные, а также может устанавливать другие переменные `CLAUDE_RUNNER_`, которых нет в таблице:129Запускается один раз на репозиторий вместо встроенного клонирования и получения данных runner'а. Используйте хук для клонирования из зеркала сквозного доступа, к которому вы обращаетесь по HTTPS или SSH, инициализации рабочего дерева из архива или применения аутентификации git для каждой сессии. Runner устанавливает эти переменные, а также может устанавливать другие переменные `CLAUDE_RUNNER_`, которых нет в таблице:
112 130
113| Variable | Description |131| Variable | Description |
114| :- | :- |132| :- | :- |
115| `CLAUDE_RUNNER_REPO_URL` | URL репозитория для клонирования, после применения любых `--git-host-rewrite` и `--git-ssh-rewrite` |133| `CLAUDE_RUNNER_REPO_URL` | URL репозитория для клонирования, после применения любых `--git-host-rewrite` и `--git-ssh-rewrite` |
116| `CLAUDE_RUNNER_REPO_REF` | Ревизия для проверки: ветка, тег или SHA коммита, как её запросила сессия. Пусто означает ветку по умолчанию репозитория. |134| `CLAUDE_RUNNER_REPO_REF` | Ревизия для checkout в том виде, в каком её запросила сессия: ветка, тег, SHA коммита или полное имя ссылки, например `refs/pull/<number>/head`. Пустое значение означает ветку по умолчанию репозитория. |
117| `CLAUDE_RUNNER_CHECKOUT_PATH` | Абсолютный путь, где должно остаться рабочее дерево |135| `CLAUDE_RUNNER_CHECKOUT_PATH` | Абсолютный путь, где должно остаться рабочее дерево |
118| `CLAUDE_RUNNER_SESSION_ID` | ID сессии в форме с тегом `session_...`, для логирования и корреляции |136| `CLAUDE_RUNNER_SESSION_ID` | ID сессии в форме с тегом `session_...`, для логирования и корреляции |
119| `CLAUDE_RUNNER_SESSION_UUID` | Тот же ID сессии в канонической форме UUID |137| `CLAUDE_RUNNER_SESSION_UUID` | Тот же ID сессии в канонической форме UUID |
120| `CLAUDE_RUNNER_API_BASE_URL` | Базовый URL API Anthropic для вызовов в области сессии |138| `CLAUDE_RUNNER_API_BASE_URL` | Базовый URL API Anthropic для вызовов в области сессии |
121| `CLAUDE_RUNNER_CLIENT_PLATFORM` | Поверхность клиента, которая создала сессию, такая как `web_claude_ai`, `desktop_app` или `ios`. Не установлено, когда сессия не имеет записанной или распознанной поверхности. |139| `CLAUDE_RUNNER_CLIENT_PLATFORM` | Интерфейс клиента, который создал сессию, например `web_claude_ai`, `desktop_app` или `ios`. Не установлена, если у сессии нет записанного или распознанного интерфейса, поэтому при `set -u` ссылайтесь на неё как `${CLAUDE_RUNNER_CLIENT_PLATFORM:-}`. Требуется Claude Code v2.1.229 или новее. |
122| `CLAUDE_CODE_SESSION_ACCESS_TOKEN` | Токен доступа сессии для вызовов API в области сессии |140| `CLAUDE_CODE_SESSION_ACCESS_TOKEN` | Токен доступа сессии для вызовов API в области сессии |
123| `GIT_CONFIG_COUNT`, `GIT_CONFIG_KEY_n`, `GIT_CONFIG_VALUE_n` | Настройки git, которые runner фиксирует для git, запускаемого вашим хуком. Они описаны в разделе [Конфигурация git внутри хуков жизненного цикла](#git-configuration-inside-lifecycle-hooks). Требуется Claude Code v2.1.280 или новее. |141| `GIT_CONFIG_COUNT`, `GIT_CONFIG_KEY_n`, `GIT_CONFIG_VALUE_n` | Настройки git, которые runner фиксирует для git, запускаемого вашим хуком. Они описаны в разделе [Конфигурация git внутри хуков жизненного цикла](#git-configuration-inside-lifecycle-hooks). Требуется Claude Code v2.1.280 или новее. |
124 142
125Скрипт должен оставить рабочее дерево в `CLAUDE_RUNNER_CHECKOUT_PATH`, проверенное на запрошенной ревизии. Отсоединённая HEAD в порядке; runner создаёт рабочую ветку сессии сверху. Runner проверяет, что путь содержит `.git` после этого; если ваш hook материализует источник, не основанный на git, такой как Perforce или распакованный tarball, установите `CLAUDE_RUNNER_SKIP_GIT_VERIFY=1` в окружении runner'а, чтобы пропустить эту проверку. Потоки на основе Git, такие как создание рабочей ветки и отправка результатов, требуют проверки git, поэтому экспортируйте результаты из деревьев, не основанных на git, с помощью [`post-session` hook](#post-session).143Скрипт должен оставить в `CLAUDE_RUNNER_CHECKOUT_PATH` рабочее дерево, переключённое на запрошенную ревизию. Отсоединённый HEAD подходит, потому что runner создаёт рабочую ветку сессии поверх него.
126 144
127Runner не передаёт учётные данные git в hook. Вместо этого создайте учётные данные клонирования для каждой сессии из идентификации сессии: проверьте `CLAUDE_CODE_SESSION_ACCESS_TOKEN` с помощью стандартной библиотеки JWT для конечной точки JWKS под `CLAUDE_RUNNER_API_BASE_URL`, как описано в [Verify the token from your service](/docs/ru/self-hosted-environments-identity#verify-the-token-from-your-service), затем попросите вашу службу учётных данных выдать краткосрочные учётные данные клонирования для идентификации в утверждении `act` токена. `CLAUDE_RUNNER_CLAUDE_BIN` не установлен в окружении checkout-hook, поэтому подкоманда `decode-token` недоступна здесь. Возврат к любой аутентификации git, которая уже есть на хосте, такой как SSH агент, помощник учётных данных или `.netrc`, также является вариантом.145После возврата вашего хука runner проверяет, что `CLAUDE_RUNNER_CHECKOUT_PATH` содержит `.git`. Если ваш хук материализует источник, не основанный на git, такой как Perforce или распакованный tarball, установите `CLAUDE_RUNNER_SKIP_GIT_VERIFY=1` в окружении runner'а, чтобы пропустить эту проверку. Потоки на основе Git, такие как создание рабочей ветки и отправка результатов, требуют checkout git, поэтому экспортируйте результаты из деревьев, не основанных на git, с помощью [хука `post-session`](#post-session).
128 146
129Когда hook завершается с ненулевым кодом или завершается с кодом 0 без оставления пригодной для использования проверки, то, что делает runner, зависит от репозитория:147<h4 id="get-git-credentials-in-the-hook">
148 Получение учётных данных git в хуке
149</h4>
130 150
131* **Репозиторий, в который сессия отправляет результаты**: runner отмечает сеанс как неудачный, и при ненулевом выходе выводит пользователю конец stderr скрипта.151Runner не передаёт учётные данные git в хук. Подкоманда `decode-token` здесь тоже недоступна, потому что `CLAUDE_RUNNER_CLAUDE_BIN` не установлена в окружении хука checkout. Вместо этого создайте учётные данные клонирования для каждой сессии на основе идентичности сессии или вернитесь к собственной аутентификации git хоста:
132* **Репозиторий, из которого сессия только читает**, такой как репозиторий, добавленный к запущенной сессии: runner логирует строку `[runner:warn]` с деталями отказа, отправляет шаг `Skipped` в сессию, удаляет всё, что hook оставил в пути проверки, и продолжает с оставшимися репозиториями. Когда runner не может немедленно удалить путь, он повторяет удаление в конце сессии. Если пропуск оставляет сессию вообще без репозитория, runner отмечает сеанс как неудачный в любом случае.
133 152
134До v2.1.228 runner отмечал сеанс как неудачный при отказе hook для любого репозитория, поэтому репозиторий только для чтения, который hook не мог обслуживать, отмечал сеанс как неудачный снова при каждом новом runner'е, на котором сессия возобновлялась.153* **Учётные данные клонирования для каждой сессии**: проверьте `CLAUDE_CODE_SESSION_ACCESS_TOKEN` с помощью стандартной библиотеки JWT по эндпоинту JWKS под `CLAUDE_RUNNER_API_BASE_URL`, как описано в разделе [Verify the token from your service](/docs/ru/self-hosted-environments-identity#verify-the-token-from-your-service). Затем попросите вашу службу учётных данных выдать краткосрочные учётные данные клонирования для идентичности из утверждения `act` токена. Привязывайте эти учётные данные к `act.sub` и не требуйте `act.email`.
154* **Аутентификация git хоста**: используйте любую аутентификацию git, которая уже есть на хосте, например SSH-агент, помощник учётных данных или `.netrc`.
135 155
136Runner удаляет путь проверки после завершения сессии.156<h4 id="when-the-hook-fails">
157 Когда хук завершается ошибкой
158</h4>
159
160Хук считается завершившимся ошибкой, если он завершается с ненулевым кодом или завершается с кодом 0, не оставив пригодного для использования checkout:
161
162* **Репозиторий, в который сессия отправляет результаты**: runner отмечает сеанс как неудачный, и при ненулевом выходе выводит пользователю конец stderr скрипта.
163* **Репозиторий, из которого сессия только читает**, например репозиторий, добавленный к запущенной сессии: runner записывает в лог строку `[runner:warn]` с подробностями ошибки, отправляет в сессию шаг `Skipped`, удаляет всё, что хук оставил по пути checkout, и продолжает работу с оставшимися репозиториями. Если после пропуска у сессии не остаётся ни одного репозитория, runner всё равно отмечает сессию как неудачную.
164
165Если хук завершается успешно, runner удаляет путь checkout после завершения сессии.
137 166
138<h3 id="post-session">167<h3 id="post-session">
139 post-session168 post-session
151| `CLAUDE_RUNNER_WORKSPACE_PATHS` | Разделённые двоеточиями абсолютные пути рабочих деревьев сессии. Пусто для сессий с нулевым репозиторием. |180| `CLAUDE_RUNNER_WORKSPACE_PATHS` | Разделённые двоеточиями абсолютные пути рабочих деревьев сессии. Пусто для сессий с нулевым репозиторием. |
152| `CLAUDE_RUNNER_DEBUG_LOG_PATH` | Путь к логу отладки сессии, всё ещё на диске во время выполнения hook'а |181| `CLAUDE_RUNNER_DEBUG_LOG_PATH` | Путь к логу отладки сессии, всё ещё на диске во время выполнения hook'а |
153| `CLAUDE_RUNNER_API_BASE_URL` | Базовый URL API Anthropic для вызовов в области сессии |182| `CLAUDE_RUNNER_API_BASE_URL` | Базовый URL API Anthropic для вызовов в области сессии |
154| `CLAUDE_RUNNER_CLIENT_PLATFORM` | Поверхность клиента, которая создала сессию, такая как `web_claude_ai`, `desktop_app` или `ios`. Не установлено, когда сессия не имеет записанной или распознанной поверхности. Требует Claude Code v2.1.229 или позже. |183| `CLAUDE_RUNNER_CLIENT_PLATFORM` | Интерфейс клиента, который создал сессию, например `web_claude_ai`, `desktop_app` или `ios`. Не установлена, если у сессии нет записанного или распознанного интерфейса, поэтому при `set -u` ссылайтесь на неё как `${CLAUDE_RUNNER_CLIENT_PLATFORM:-}`. Требуется Claude Code v2.1.229 или новее. |
155| `CLAUDE_CODE_SESSION_ACCESS_TOKEN` | Токен доступа сессии для вызовов API в области сессии |184| `CLAUDE_CODE_SESSION_ACCESS_TOKEN` | Токен доступа сессии для вызовов API в области сессии |
156| `GIT_CONFIG_COUNT`, `GIT_CONFIG_KEY_n`, `GIT_CONFIG_VALUE_n` | Настройки git, которые runner фиксирует для git, запускаемого вашим хуком. Они описаны в разделе [Конфигурация git внутри хуков жизненного цикла](#git-configuration-inside-lifecycle-hooks). Требуется Claude Code v2.1.280 или новее. |185| `GIT_CONFIG_COUNT`, `GIT_CONFIG_KEY_n`, `GIT_CONFIG_VALUE_n` | Настройки git, которые runner фиксирует для git, запускаемого вашим хуком. Они описаны в разделе [Конфигурация git внутри хуков жизненного цикла](#git-configuration-inside-lifecycle-hooks). Требуется Claude Code v2.1.280 или новее. |
157 186
158`CLAUDE_RUNNER_EXIT_REASON` принимает одно из четырёх значений:187`CLAUDE_RUNNER_EXIT_REASON` принимает одно из четырёх значений:
159 188
160* `completed`: сессия завершилась чисто. Процесс Claude Code завершился нормально, или сессия была архивирована или удалена, пока она всё ещё работала.189* `completed`: сессия завершилась чисто. Процесс Claude Code завершился нормально или завершился сам после того, как сессия была архивирована или удалена.
161* `failed`: процесс Claude Code упал, или настройка не удалась после его запуска.190* `failed`: процесс Claude Code упал, или настройка не удалась после его запуска.
162* `interrupted`: runner остановил сессию. Он освободил сессию, чтобы освободить слот, сессия истекла при запуске, сервер переместил сессию с этого runner'а, runner был в режиме дренирования, или сессия превысила свой лимит [`--kill-session-after-min`](/docs/ru/self-hosted-environments-reference#runner-cli-flags).191* `interrupted`: runner остановил сессию в одном из следующих случаев:
192 * Runner освободил сессию, чтобы освободить слот.
193 * Истекло время ожидания сессии при запуске.
194 * Сервер переместил сессию с этого runner'а.
195 * Опрос runner'а обнаружил архивирование или удаление до завершения процесса.
196 * Runner был в режиме дренирования.
197 * Сессия превысила свой лимит [`--kill-session-after-min`](/docs/ru/self-hosted-environments-reference#runner-cli-flags).
163* `abandoned`: зарезервировано для сессии, которую заявил другой runner. Hook в настоящее время не срабатывает в этом случае.198* `abandoned`: зарезервировано для сессии, которую заявил другой runner. Hook в настоящее время не срабатывает в этом случае.
164 199
165[Счётчики жизненного цикла сессии](/docs/ru/self-hosted-environments-reference#session-lifecycle-counter-semantics) считают освобождение, истечение времени при запуске и перемещение сервера как `completed` вместо `interrupted`, потому что runner чисто вернул слот. Ожидайте этого различия, если вы сравниваете квитанции hook'а со счётчиками.200Если вы сравниваете квитанции хука со [счётчиками жизненного цикла сессии](/docs/ru/self-hosted-environments-reference#session-lifecycle-counter-semantics), ожидайте, что некоторые квитанции `interrupted` будут учтены там как `completed`. Счётчики считают освобождение, истечение времени при запуске, перемещение сервером, а также архивирование или удаление, которые первым обнаружил опрос runner'а, как `completed`, потому что runner чисто вернул слот.
166 201
167Статус выхода hook'а никогда не влияет на результат сессии; отказ логируется и игнорируется. Runner ждёт до `--post-session-hook-timeout-sec`, 60 секунд по умолчанию, при каждом завершении сессии, включая завершение runner'а. Этот пример сохраняет незафиксированную работу в ветку спасения:202Статус выхода hook'а никогда не влияет на результат сессии; отказ логируется и игнорируется. Runner ждёт до `--post-session-hook-timeout-sec`, 60 секунд по умолчанию, при каждом завершении сессии, включая завершение runner'а. Этот пример сохраняет незафиксированную работу в ветку спасения:
168 203
169```bash theme={null}204```bash theme={null}
170#!/usr/bin/env bash205#!/usr/bin/env bash
171set -u206set -u
207export GIT_ALLOW_PROTOCOL=${GIT_ALLOW_PROTOCOL:-https:http:ssh}
172IFS=':'208IFS=':'
173# -c overrides beat repo-local settings, blocking session-written fsmonitor,209# -c overrides beat repo-local settings, blocking session-written fsmonitor,
174# hook-path, and gpg-program config from executing code with the hook's210# hook-path, and gpg-program config from executing code with the hook's
188done224done
189```225```
190 226
227Строка `GIT_ALLOW_PROTOCOL` в скрипте ограничивает git удалёнными репозиториями по HTTPS, HTTP и SSH. Если окружение runner'а уже задаёт собственный непустой список `GIT_ALLOW_PROTOCOL`, скрипт сохраняет этот список.
228
191Хук выполняет push с любыми учётными данными git, доступными в его собственном окружении на хосте runner'а. При [подходе без учётных данных в образе](/docs/ru/self-hosted-environments-deploy#configure-git), в том числе когда встроенное клонирование проходит через git-прокси Anthropic, их нет, поэтому перед push создайте краткосрочные учётные данные для отправки внутри хука: обменяйте токен сессии, который хук получает в `CLAUDE_CODE_SESSION_ACCESS_TOKEN`, в вашей собственной службе токенов, предварительно проверив его, как описано в разделе [Проверка идентичности сессии](/docs/ru/self-hosted-environments-identity). Когда у хука есть учётные данные, которых не было у сессии, замените `origin` на URL, предоставленный оператором, и передайте `-c credential.helper=` вместе с вашим собственным помощником. Раздел [Конфигурация git внутри хуков жизненного цикла](#git-configuration-inside-lifecycle-hooks) описывает, на что всё ещё может влиять конфигурация, записанная сессией.229Хук выполняет push с любыми учётными данными git, доступными в его собственном окружении на хосте runner'а. При [подходе без учётных данных в образе](/docs/ru/self-hosted-environments-deploy#configure-git), в том числе когда встроенное клонирование проходит через git-прокси Anthropic, их нет, поэтому перед push создайте краткосрочные учётные данные для отправки внутри хука: обменяйте токен сессии, который хук получает в `CLAUDE_CODE_SESSION_ACCESS_TOKEN`, в вашей собственной службе токенов, предварительно проверив его, как описано в разделе [Проверка идентичности сессии](/docs/ru/self-hosted-environments-identity). Когда у хука есть учётные данные, которых не было у сессии, замените `origin` на URL, предоставленный оператором, и передайте `-c credential.helper=` вместе с вашим собственным помощником. Раздел [Конфигурация git внутри хуков жизненного цикла](#git-configuration-inside-lifecycle-hooks) описывает, на что всё ещё может влиять конфигурация, записанная сессией.
192 230
193<h4 id="hook-timing-when-the-runner-releases-a-session">231<h4 id="hook-timing-when-the-runner-releases-a-session">
264| `CLAUDE_RUNNER_ORDER_ID` | Непрозрачный ключ идемпотентности, уникальный для каждого запроса на порождение и безопасный для имен ресурсов Kubernetes. Используйте только ID заказа как ключ дедупликации вашего провизионера. |302| `CLAUDE_RUNNER_ORDER_ID` | Непрозрачный ключ идемпотентности, уникальный для каждого запроса на порождение и безопасный для имен ресурсов Kubernetes. Используйте только ID заказа как ключ дедупликации вашего провизионера. |
265| `CLAUDE_RUNNER_SESSION_ID` | Сеанс, для которого предназначен этот запрос. Он повторяется при каждом повторном запросе для сеанса, поэтому используйте его для логирования и маршрутизации, а не как ключ дедупликации. Пусто для запросов предварительного прогрева, которые загружают резервное средство выполнения перед любым конкретным сеансом, когда установлен [`--min-idle`](/docs/ru/self-hosted-environments-reference#orchestrator-cli-flags), поэтому не предполагайте, что переменная установлена. |303| `CLAUDE_RUNNER_SESSION_ID` | Сеанс, для которого предназначен этот запрос. Он повторяется при каждом повторном запросе для сеанса, поэтому используйте его для логирования и маршрутизации, а не как ключ дедупликации. Пусто для запросов предварительного прогрева, которые загружают резервное средство выполнения перед любым конкретным сеансом, когда установлен [`--min-idle`](/docs/ru/self-hosted-environments-reference#orchestrator-cli-flags), поэтому не предполагайте, что переменная установлена. |
266| `CLAUDE_RUNNER_SESSION_UUID` | Тот же ID сеанса в канонической форме UUID. Пусто для запросов предварительного прогрева. |304| `CLAUDE_RUNNER_SESSION_UUID` | Тот же ID сеанса в канонической форме UUID. Пусто для запросов предварительного прогрева. |
267| `CLAUDE_RUNNER_ATTEMPT` | Сколько запросов на порождение было у этого сеанса. `0` для запросов предварительного прогрева. |305| `CLAUDE_RUNNER_ATTEMPT` | Счётчик для каждой сессии, предназначенный для логирования. Это не число повторных попыток и не число запросов. `0` для запросов предварительного прогрева, хотя запрос для сессии тоже может содержать `0`. |
268| `CLAUDE_RUNNER_ORDER_SERVER_TIME` | Время сервера из заголовка HTTP `Date` ответа опроса. Когда хук проверяет `exp` JWT наряда на работу, сравнивайте с этим значением вместо локальных часов, чтобы допустить перекос. Пусто, когда шлюз опустил заголовок. |306| `CLAUDE_RUNNER_ORDER_SERVER_TIME` | Время сервера из заголовка HTTP `Date` ответа опроса. Когда хук проверяет `exp` JWT наряда на работу, сравнивайте с этим значением вместо локальных часов, чтобы допустить перекос. Пусто, когда шлюз опустил заголовок. |
269| `CLAUDE_RUNNER_POOL_ID` | ID окружения, к которому должно присоединиться новое средство выполнения, в форме `ccpool_...` |307| `CLAUDE_RUNNER_POOL_ID` | ID окружения, к которому должно присоединиться новое средство выполнения, в форме `ccpool_...` |
270| `CLAUDE_RUNNER_ACCOUNT_ID` | Помеченный ID учетной записи, которая поставила сеанс в очередь, для маршрутизации по учетной записи, квоты или возврата средств. Пусто, когда недоступно, и всегда пусто для сеансов канала Claude Tag, которые не ставит в очередь ни одна учетная запись. |308| `CLAUDE_RUNNER_ACCOUNT_ID` | Помеченный ID учетной записи, которая поставила сеанс в очередь, для маршрутизации по учетной записи, квоты или возврата средств. Пусто, когда недоступно, и всегда пусто для сеансов канала Claude Tag, которые не ставит в очередь ни одна учетная запись. |
271| `CLAUDE_RUNNER_ACCOUNT_EMAIL` | Электронная почта учетной записи, которая поставила сеанс в очередь. Пусто, когда недоступно. Рассматривайте электронную почту как личную информацию и не логируйте ее. |309| `CLAUDE_RUNNER_ACCOUNT_EMAIL` | Электронная почта учетной записи, которая поставила сеанс в очередь. Пусто, когда недоступно. Рассматривайте электронную почту как личную информацию и не логируйте ее. |
272| `CLAUDE_RUNNER_PRIMARY_REPO_URL` | URL первого источника git сеанса для маршрутизации на средство выполнения с этим репозиторием предварительно прогретым. Пусто, когда сеанс не имеет источников git. |310| `CLAUDE_RUNNER_PRIMARY_REPO_URL` | URL первого источника git сеанса для маршрутизации на средство выполнения с этим репозиторием предварительно прогретым. Пусто, когда сеанс не имеет источников git. |
273| `CLAUDE_RUNNER_PRIMARY_REPO_REVISION` | Ревизия первого источника git сеанса: ветка, SHA или тег. Пусто, когда не указано. |311| `CLAUDE_RUNNER_PRIMARY_REPO_REVISION` | Ревизия первого git-источника сессии: ветка, SHA, тег или полное имя ссылки. Пусто, когда не указано. |
274| `CLAUDE_RUNNER_REPO_SOURCES` | JSON массив `{url, revision}` для всех источников git сеанса для хуков, которые маршрутизируют на вторичный репозиторий. Пусто, когда нет источников. |312| `CLAUDE_RUNNER_REPO_SOURCES` | JSON массив `{url, revision}` для всех источников git сеанса для хуков, которые маршрутизируют на вторичный репозиторий. Пусто, когда нет источников. |
275| `CLAUDE_RUNNER_CORRELATION_ID` | ID корреляции, предоставленный при создании сеанса, повторно отправленный, чтобы хук мог сопоставить этот наряд на работу с запросом, который создал сеанс. Пусто, когда сеанс не имеет ни одного. |313| `CLAUDE_RUNNER_CORRELATION_ID` | ID корреляции, предоставленный при создании сеанса, повторно отправленный, чтобы хук мог сопоставить этот наряд на работу с запросом, который создал сеанс. Пусто, когда сеанс не имеет ни одного. |
276| `CLAUDE_RUNNER_CLIENT_PLATFORM` | Поверхность клиента, которая создала сеанс, такая как `web_claude_ai`, `desktop_app`, `ios` или `scheduled_trigger`, для аналитики внедрения. Не установлена, когда сеанс не имеет записанной или распознанной поверхности, и для запросов предварительного прогрева; проверьте ее с помощью `[ -n "${CLAUDE_RUNNER_CLIENT_PLATFORM:-}" ]`, что остается безопасным под `set -u`. |314| `CLAUDE_RUNNER_CLIENT_PLATFORM` | Поверхность клиента, которая создала сеанс, такая как `web_claude_ai`, `desktop_app`, `ios` или `scheduled_trigger`, для аналитики внедрения. Не установлена, когда сеанс не имеет записанной или распознанной поверхности, и для запросов предварительного прогрева; проверьте ее с помощью `[ -n "${CLAUDE_RUNNER_CLIENT_PLATFORM:-}" ]`, что остается безопасным под `set -u`. |
282* **Используйте `--capacity 1` на порожденных средствах выполнения**: наряд на работу, привязанный к сеансу, регистрирует ровно одно средство выполнения, привязанное к этому сеансу, поэтому более высокая емкость добавляет слоты, которые никогда не получают работу, и средство выполнения логирует предупреждение при запуске.320* **Используйте `--capacity 1` на порожденных средствах выполнения**: наряд на работу, привязанный к сеансу, регистрирует ровно одно средство выполнения, привязанное к этому сеансу, поэтому более высокая емкость добавляет слоты, которые никогда не получают работу, и средство выполнения логирует предупреждение при запуске.
283* **Нарядные работы предварительного прогрева регистрируют без привязки**: резервное средство выполнения не привязано к сеансу и заявляет поставленную в очередь работу, как средство выполнения фиксированного флота.321* **Нарядные работы предварительного прогрева регистрируют без привязки**: резервное средство выполнения не привязано к сеансу и заявляет поставленную в очередь работу, как средство выполнения фиксированного флота.
284 322
285Контракт имеет четыре правила, независимые от провизионера:323Контракт состоит из четырёх правил, независимо от того, на какой платформе ваш хук выделяет ресурсы:
286 324
2871. **Будьте идемпотентны на `CLAUDE_RUNNER_ORDER_ID`.** Переделивка одного и того же запроса должна порождать не более одного средства выполнения. Выведите детерминированное имя ресурса из ID заказа и позвольте вашей платформе отклонить дубликат. Не ключируйте на `CLAUDE_RUNNER_SESSION_ID` вместо этого. Каждый повторный запрос для сеанса несет тот же ID сеанса с новым ID заказа, поэтому рабочая нагрузка, названная или дедуплицированная по ID сеанса, создается один раз и никогда снова для этого сеанса.3251. **Будьте идемпотентны на `CLAUDE_RUNNER_ORDER_ID`.** Переделивка одного и того же запроса должна порождать не более одного средства выполнения. Выведите детерминированное имя ресурса из ID заказа и позвольте вашей платформе отклонить дубликат. Не ключируйте на `CLAUDE_RUNNER_SESSION_ID` вместо этого. Каждый повторный запрос для сеанса несет тот же ID сеанса с новым ID заказа, поэтому рабочая нагрузка, названная или дедуплицированная по ID сеанса, создается один раз и никогда снова для этого сеанса.
2882. **Не повторяйте рабочую нагрузку.** Один ID заказа означает не более одной созданной рабочей нагрузки. Если средство выполнения никогда не регистрируется, Anthropic повторно запрашивает с новым ID заказа после `--expected-spawn-seconds`.3262. **Не повторяйте рабочую нагрузку.** Один ID заказа означает не более одной созданной рабочей нагрузки. Если средство выполнения никогда не регистрируется, Anthropic повторно запрашивает с новым ID заказа после `--expected-spawn-seconds`.
2893. **Используйте контракт кода выхода.** Выход 0 означает отправлено. Выход 1 означает повторяемый отказ; сеанс отступает и переоффертируется. Выход 2 или выше означает неповторяемый; сеанс блокируется от порождения снова до тех пор, пока [владелец](/docs/ru/cloud-environments#organization-shared-environments) не выберет **Retry** на нем на вкладке **Activity** окружения. При ненулевом выходе хвост stderr хука появляется там как причина отказа, поэтому напишите действенную ошибку в stderr и никогда не секреты. Для запроса предварительного прогрева нет сеанса для отказа: оркестратор логирует ненулевой выход локально только, и сервер повторно запрашивает порождение после аренды.3273. **Соблюдайте контракт кода выхода.** Завершайтесь со статусом, соответствующим результату:
2904. **Установите `--expected-spawn-seconds` на по крайней мере ваше время загрузки p99.** Это аренда на стороне сервера. Все реплики оркестратора должны использовать одно и то же значение.328
329 * **Выход 0**: отправлено.
330 * **Выход 1**: сбой, допускающий повторную попытку. Сессия выжидает и предлагается снова.
331 * **Выход 2 или выше**: сбой, не допускающий повторной попытки. Сессия блокируется от повторного порождения до тех пор, пока пользователь не отправит ей новое сообщение или [Owner](/docs/ru/cloud-environments#organization-shared-environments) не выберет для неё **Retry** на вкладке **Activity** окружения.
332
333 При ненулевом выходе конец stderr хука отображается на вкладке **Activity** как причина сбоя, поэтому пишите в stderr понятную ошибку, указывающую, что делать, и никогда не пишите туда секреты. В shell-хуке [сохраняйте временные сбои повторяемыми](#keep-transient-failures-retryable-in-a-shell-hook).
334
335 У запроса предварительного прогрева нет сессии, которая могла бы завершиться сбоем: оркестратор записывает ненулевой выход только в локальный лог, а сервер повторно запрашивает порождение после истечения аренды `--expected-spawn-seconds`.
3364. **Установите `--expected-spawn-seconds` не меньше вашего времени p99 от запроса на порождение до регистрации средства выполнения.** Отсчитывайте от момента, когда оркестратор получает запрос на порождение, и учитывайте как ожидание ресурсов на вашей платформе, так и время загрузки. Это значение является арендой на стороне сервера, и наряд на работу истекает вместе с ней, поэтому средство выполнения, рабочая нагрузка которого запускается дольше, не сможет зарегистрироваться. Все реплики оркестратора должны использовать одно и то же значение.
291 337
292Все, что хук пишет в stdout или stderr, появляется в логе оркестратора с автоматически удаленными учетными данными. Если сеансы остаются в очереди, проверьте тело `/healthz` оркестратора на предмет количества в очереди, затем откройте вкладку **Activity** вашего окружения на [странице администратора **Cloud environments**](https://claude.ai/admin-settings/cloud-environments): разверните неудачный сеанс там для его ошибки порождения и выберите **Retry** для повторного запроса.338Все, что хук пишет в stdout или stderr, появляется в логе оркестратора с автоматически удаленными учетными данными. Если сеансы остаются в очереди, проверьте тело `/healthz` оркестратора на предмет количества в очереди, затем откройте вкладку **Activity** вашего окружения на [странице администратора **Cloud environments**](https://claude.ai/admin-settings/cloud-environments): разверните неудачный сеанс там для его ошибки порождения и выберите **Retry** для повторного запроса.
293 339
294Сеанс, который остается в очереди без ошибки порождения на вкладке **Activity**, может означать, что хук ключируется по ID сеанса. Чтобы подтвердить, проверьте, есть ли на вашей платформе рабочая нагрузка для первого запроса порождения этого сеанса и нет ни одной для повторных запросов. Если это так, ключируйте рабочую нагрузку на `CLAUDE_RUNNER_ORDER_ID` вместо этого.340Сеанс, который остается в очереди без ошибки порождения на вкладке **Activity**, может означать, что хук ключируется по ID сеанса. Чтобы подтвердить, проверьте, есть ли на вашей платформе рабочая нагрузка для первого запроса порождения этого сеанса и нет ни одной для повторных запросов. Если это так, ключируйте рабочую нагрузку на `CLAUDE_RUNNER_ORDER_ID` вместо этого.
295 341
342<h4 id="keep-transient-failures-retryable-in-a-shell-hook">
343 Сохраняйте временные сбои повторяемыми в shell-хуке
344</h4>
345
346В shell-хуке, использующем `set -e`, сбой, который могла бы устранить повторная попытка, может заблокировать сессию. Хук останавливается на сбойной команде и завершается с собственным статусом этой команды, а оркестратор применяет контракт кода выхода к этому статусу. Многие сбои возвращают статус 2 или выше, например `127`, когда команда не установлена, и `22` от `curl --fail` при ошибке HTTP, поэтому они блокируют сессию при первом же сбое.
347
348Сессия, которую хук уже заблокировал, остаётся заблокированной, пока пользователь не отправит ей новое сообщение или [Owner](/docs/ru/cloud-environments#organization-shared-environments) не выберет для неё **Retry** на вкладке **Activity** окружения.
349
350Чтобы вместо этого превращать такой сбой в выход 1, поместите эти строки сразу под строкой `#!` хука, перед всем, что может завершиться сбоем:
351
352```bash theme={null}
353set -e
354PERMANENT=; permanent() { printf '%s\n' "$*" >&2; PERMANENT=1; exit 2; }
355trap 'rc=$?; [ "$rc" -eq 0 ] || [ -n "${PERMANENT:-}" ] || exit 1' EXIT
356```
357
358Эти строки меняют поведение остальной части хука, поэтому после их добавления проверьте хук на каждый из следующих шаблонов:
359
360* **Просто `exit 2` или выше**: при установленной ловушке он превращается в выход 1. Для ошибки, которую не исправит никакая повторная попытка, вместо этого вызовите `permanent` с указанием причины, например `permanent "namespace claude-runners does not exist"`. Вызывайте её в основной оболочке, а не внутри `$( )`, `( )` или конвейера.
361* **`exec`**: не начинайте последнюю команду хука с `exec`, потому что `exec` заменяет оболочку, и ловушка не выполняется.
362* **Вторая ловушка `EXIT`**: второй `trap ... EXIT` заменяет первый, поэтому объедините их в одну ловушку. Поместите команды очистки сразу после `rc=$?;` и завершите каждую `|| true;`. Тогда очистка выполняется как при сбое, так и при успехе, а сбойная команда очистки не влияет на статус выхода хука. Эта объединённая ловушка показывает структуру, где `your-cleanup-command` заменяет вашу собственную команду:
363
364 ```bash theme={null}
365 trap 'rc=$?; your-cleanup-command || true; [ "$rc" -eq 0 ] || [ -n "${PERMANENT:-}" ] || exit 1' EXIT
366 ```
367* **Команды, которым разрешено завершаться сбоем**: если хук раньше не использовал `set -e`, теперь он останавливается на первой команде, вернувшей ненулевой статус, например на поиске, который ничего не нашёл, или на повторной отправке, которую отклоняет ваша платформа. Если хук использует результат, сделайте эту команду условием `if`. Если он игнорирует результат, добавьте после команды `|| true`.
368
369Чтобы убедиться, что ловушка работает, добавьте сразу под строкой `trap` строку, вызывающую несуществующую команду, например `no-such-command`. Запустите файл хука из своей оболочки и убедитесь, что `echo $?` выводит `1`, затем удалите эту строку.
370
296<h2 id="send-model-requests-to-bedrock-or-agent-platform">371<h2 id="send-model-requests-to-bedrock-or-agent-platform">
297 Отправка запросов к модели в Bedrock или Agent Platform372 Отправка запросов к модели в Bedrock или Agent Platform
298</h2>373</h2>
381Сессия, отправляющая запросы к модели в Amazon Bedrock или Google Cloud's Agent Platform, отличается от сессии в Anthropic API следующим:456Сессия, отправляющая запросы к модели в Amazon Bedrock или Google Cloud's Agent Platform, отличается от сессии в Anthropic API следующим:
382 457
383* **Политики из claude.ai**: [настройки, управляемые сервером](/docs/ru/server-managed-settings), не доходят до этих сессий. Не доходят и политики организации, которые Owner задаёт в настройках администратора Claude Code, поэтому Claude Code не применяет их внутри сессии. Поместите правила, на которые вы полагаетесь, в [файл управляемых настроек](/docs/ru/managed-settings#delivery-mechanisms) образа runner.458* **Политики из claude.ai**: [настройки, управляемые сервером](/docs/ru/server-managed-settings), не доходят до этих сессий. Не доходят и политики организации, которые Owner задаёт в настройках администратора Claude Code, поэтому Claude Code не применяет их внутри сессии. Поместите правила, на которые вы полагаетесь, в [файл управляемых настроек](/docs/ru/managed-settings#delivery-mechanisms) образа runner.
459* **Скиллы аккаунта**: эти сессии не загружают скиллы, включённые для аккаунта claude.ai пользователя. См. [Как собирается конфигурация каждой сессии](#how-each-session’s-config-is-assembled).
384* **Файлы**: файлы, которые пользователи прикрепляют к сессии в claude.ai, мобильном или десктопном приложении, до неё не доходят, и Claude не может отправлять файлы обратно с помощью [инструмента `SendUserFile`](/docs/ru/tools-reference). Вместо этого размещайте входные файлы в репозитории или на runner.460* **Файлы**: файлы, которые пользователи прикрепляют к сессии в claude.ai, мобильном или десктопном приложении, до неё не доходят, и Claude не может отправлять файлы обратно с помощью [инструмента `SendUserFile`](/docs/ru/tools-reference). Вместо этого размещайте входные файлы в репозитории или на runner.
385* **Выбор модели**: управляющий уровень Anthropic передаёт модель для каждой сессии, а если сессия запускается без неё, Claude Code использует модель по умолчанию для провайдера. Runner удаляет `ANTHROPIC_MODEL` и `ANTHROPIC_DEFAULT_MODEL` из окружения, которое он передаёт сессиям. В примерах на страницах провайдеров задаётся `ANTHROPIC_MODEL`, но в окружении runner ни одна из этих переменных ни на что не влияет. Переменные для отдельных семейств из раздела «Закрепление версий моделей» для [Amazon Bedrock](/docs/ru/amazon-bedrock#4-pin-model-versions) и [Agent Platform](/docs/ru/google-vertex-ai#5-pin-model-versions) до сессий доходят. Они определяют, во что разрешается псевдоним, например `opus`, но не полный идентификатор модели.461* **Выбор модели**: управляющий уровень Anthropic передаёт модель для каждой сессии, а если сессия запускается без неё, Claude Code использует модель по умолчанию для провайдера. Вы не можете выбрать модель с помощью `ANTHROPIC_MODEL` или `ANTHROPIC_DEFAULT_MODEL` в окружении runner, но можете закрепить, во что разрешается псевдоним:
462 * **`ANTHROPIC_MODEL` и `ANTHROPIC_DEFAULT_MODEL`**: runner удаляет их из окружения, которое он передаёт сессиям, хотя в примерах на страницах провайдеров задаётся `ANTHROPIC_MODEL`.
463 * **Переменные закрепления для отдельных семейств**: переменные из раздела «Закрепление версий моделей» для [Amazon Bedrock](/docs/ru/amazon-bedrock#4-pin-model-versions) и [Agent Platform](/docs/ru/google-vertex-ai#5-pin-model-versions) до сессий доходят. Они определяют, во что разрешается псевдоним, например `opus`, но не полный идентификатор модели.
386* **Модели, которые ваш аккаунт не обслуживает**: сессия может завершиться ошибкой на сообщении с указанием модели. Включите модели, которые могут выбирать ваши разработчики, фоновую модель, описанную в разделе «Закрепление версий моделей», и модель классификатора, которую использует [авторежим](/docs/ru/permission-modes#enable-auto-mode-on-bedrock-agent-platform-or-foundry). В Amazon Bedrock разрешите каждую из них в своей политике.464* **Модели, которые ваш аккаунт не обслуживает**: сессия может завершиться ошибкой на сообщении с указанием модели. Включите модели, которые могут выбирать ваши разработчики, фоновую модель, описанную в разделе «Закрепление версий моделей», и модель классификатора, которую использует [авторежим](/docs/ru/permission-modes#enable-auto-mode-on-bedrock-agent-platform-or-foundry). В Amazon Bedrock разрешите каждую из них в своей политике.
387* **Веб-поиск и быстрый режим**: [веб-поиск](/docs/ru/tools-reference#websearch-tool-behavior) недоступен в Amazon Bedrock, а [быстрый режим](/docs/ru/fast-mode) недоступен ни у одного из этих провайдеров. О других возможностях, различающихся в зависимости от провайдера, см. [Возможности CLI, зависящие от провайдера](/docs/ru/feature-availability#cli-capabilities-that-vary-by-provider).465* **Веб-поиск и быстрый режим**: [веб-поиск](/docs/ru/tools-reference#websearch-tool-behavior) недоступен в Amazon Bedrock, а [быстрый режим](/docs/ru/fast-mode) недоступен ни у одного из этих провайдеров. О других возможностях, различающихся в зависимости от провайдера, см. [Возможности CLI, зависящие от провайдера](/docs/ru/feature-availability#cli-capabilities-that-vary-by-provider).
388 466
411 489
412Сессии наследуют окружение раннера, поэтому задайте там [`ENABLE_TOOL_SEARCH`](/docs/ru/mcp#scale-with-mcp-tool-search), чтобы управлять поиском инструментов MCP для каждой сессии, которую запускает раннер; допустимые значения описаны на странице MCP.490Сессии наследуют окружение раннера, поэтому задайте там [`ENABLE_TOOL_SEARCH`](/docs/ru/mcp#scale-with-mcp-tool-search), чтобы управлять поиском инструментов MCP для каждой сессии, которую запускает раннер; допустимые значения описаны на странице MCP.
413 491
492<a id="connection-timing" />
493
494<h3 id="wait-for-mcp-servers-before-the-first-turn">
495 Ожидание MCP-серверов перед первым ходом
496</h3>
497
498Сессия на собственном хостинге ненадолго ожидает MCP-серверы, которые ещё подключаются, в двух разных точках. Если сервер не успевает к моменту окончания ожидания, его инструменты отсутствуют в начале первого хода и становятся доступны позже без каких-либо действий с вашей стороны. Вот эти две точки ожидания:
499
500* **Запуск сессии**: до того как список инструментов будет получен в первый раз, сессия по умолчанию ждёт до 5 секунд сервер HTTP или SSE, в записи которого задано [`alwaysLoad: true`](/docs/ru/mcp#exempt-a-server-from-deferral), или все серверы, если в окружении раннера задано [`MCP_CONNECTION_NONBLOCKING=0`](/docs/ru/env-vars). В остальных случаях серверы HTTP и SSE подключаются в фоновом режиме. Пока сессия ждёт на этом этапе, она инициализируется медленнее. [`MCP_CONNECT_TIMEOUT_MS`](/docs/ru/env-vars) изменяет значение по умолчанию в 5 секунд.
501* **Первый ход**: после поступления сообщения первый ход ждёт до 2 секунд stdio-серверы, которые ещё подключаются. Пока сессия ждёт на этом этапе, первый ответ приходит медленнее. Чтобы изменить длительность этого ожидания, задайте [`CLAUDE_CODE_MCP_STARTUP_WAIT_MS`](/docs/ru/env-vars) в окружении раннера. Эта переменная не меняет, какие серверы охватывает ожидание. Требуется Claude Code v2.1.274 или новее.
502
503У `claude mcp add` нет флага `alwaysLoad`. Чтобы задать этот ключ, добавьте сервер командой `claude mcp add-json`, которая принимает его в JSON сервера и записывает в `.claude.json`. В вашем Dockerfile:
504
505```dockerfile theme={null}
506RUN claude mcp add-json core '{"type":"http","url":"https://mcp.example.com/mcp","alwaysLoad":true}' --scope user
507```
508
509Если инструменты сервера не появляются и в последующих ходах, проверьте, попал ли сервер в сессию вообще, как описано в разделе [MCP-серверы](#mcp-servers).
510
414<h3 id="turn-off-built-in-session-tools">511<h3 id="turn-off-built-in-session-tools">
415 Отключение встроенных инструментов сессии512 Отключение встроенных инструментов сессии
416</h3>513</h3>
571 668
572Установите `SELF_HOSTED_RUNNER_HOST_CONFIG_DIR` для заполнения из другого пути или укажите его на пустой каталог для отключения заполнения.669Установите `SELF_HOSTED_RUNNER_HOST_CONFIG_DIR` для заполнения из другого пути или укажите его на пустой каталог для отключения заполнения.
573 670
574Закоммиченный в репозиторий `.claude/settings.json` накладывается сверху как настройки проекта. В сессии с несколькими репозиториями [действует файл не более чем одного репозитория](#repository-settings-in-sessions-with-several-repositories). Сессии также читают [`managed-settings.json`](/docs/ru/settings#where-settings-live) из стандартного системного пути в вашем образе средства выполнения. Применяются ли его ключи наряду с [управляемыми сервером настройками](/docs/ru/server-managed-settings), определяется тем, [как Claude Code объединяет управляемые источники](/docs/ru/managed-settings#how-claude-code-combines-managed-sources): по умолчанию, когда ваша организация доставляет какие-либо управляемые сервером ключи, сессии игнорируют файл из образа средства выполнения, за исключением [ключей, которые Claude Code читает из каждого источника администратора](/docs/ru/managed-settings#keys-read-from-every-admin-source), таких как блок `env`, блокировки песочницы, пути к исполняемым файлам песочницы и `forceRemoteSettingsRefresh`. См. [приоритет настроек](/docs/ru/settings#settings-precedence).671Сессии также читают следующие файлы настроек:
672
673* **Настройки проекта**: закоммиченный в репозиторий `.claude/settings.json` накладывается поверх базовой конфигурации уровня пользователя. В сессии с несколькими репозиториями [действует файл не более чем одного репозитория](#repository-settings-in-sessions-with-several-repositories).
674* **Управляемые настройки**: сессии читают [`managed-settings.json`](/docs/ru/settings#where-settings-live) из стандартного системного пути в вашем образе средства выполнения. О том, применяются ли его ключи наряду с [управляемыми сервером настройками](/docs/ru/server-managed-settings), см. раздел [как Claude Code объединяет управляемые источники](/docs/ru/managed-settings#how-claude-code-combines-managed-sources).
675
676О порядке применения этих источников см. [приоритет настроек](/docs/ru/settings#settings-precedence).
575 677
576Когда плоскость управления Anthropic предоставляет сеансу [хуки Claude Code](/docs/ru/hooks), средство выполнения устанавливает их рядом, а не над вашей собственной конфигурацией. Требует Claude Code v2.1.229 или позже.678Когда плоскость управления Anthropic предоставляет сеансу [хуки Claude Code](/docs/ru/hooks), средство выполнения устанавливает их рядом, а не над вашей собственной конфигурацией. Требует Claude Code v2.1.229 или позже.
577 679
579* **Кто их создает**: плоскость управления заполняет скрипты из фиксированных констант в своем собственном развертывании, никогда не из входных данных для каждого сеанса или третьей стороны.681* **Кто их создает**: плоскость управления заполняет скрипты из фиксированных констант в своем собственном развертывании, никогда не из входных данных для каждого сеанса или третьей стороны.
580* **Что по-прежнему их управляет**: хуки, доставленные через `--settings`, входят в обычную объединенную конфигурацию хука, а не в управляемый уровень, поэтому ваши управляемые настройки по-прежнему применяются. `disableAllHooks` отключает их, и они не входят в категории, которые [`allowManagedHooksOnly`](/docs/ru/settings-reference#allowmanagedhooksonly) сохраняет загруженными.682* **Что по-прежнему их управляет**: хуки, доставленные через `--settings`, входят в обычную объединенную конфигурацию хука, а не в управляемый уровень, поэтому ваши управляемые настройки по-прежнему применяются. `disableAllHooks` отключает их, и они не входят в категории, которые [`allowManagedHooksOnly`](/docs/ru/settings-reference#allowmanagedhooksonly) сохраняет загруженными.
581 683
684Когда пользователь сам запускает свою сессию, Claude Code также загружает [скиллы, включённые для его учётной записи claude.ai](/docs/ru/skills#skills-in-cowork-and-cloud-sessions), в каталог конфигурации этой сессии. Запуск [routine](/docs/ru/routines) не получает скиллы своего владельца, а сессия, которая [отправляет запросы к модели в Bedrock или Agent Platform](#send-model-requests-to-bedrock-or-agent-platform), не загружает никаких скиллов. Если такой сессии нужен скилл, сделайте его коммит в `.claude/skills/` репозитория или добавьте его в образ средства выполнения.
685
582Вне сессий [Claude Tag](https://claude.com/docs/claude-tag/overview) сессия в самостоятельно размещаемом окружении по умолчанию работает с отключённой [автоматической памятью](/docs/ru/memory#auto-memory). Для инструкций, которые должны сохраняться между сессиями, используйте `CLAUDE.md` в вашем образе средства выполнения или в репозитории.686Вне сессий [Claude Tag](https://claude.com/docs/claude-tag/overview) сессия в самостоятельно размещаемом окружении по умолчанию работает с отключённой [автоматической памятью](/docs/ru/memory#auto-memory). Для инструкций, которые должны сохраняться между сессиями, используйте `CLAUDE.md` в вашем образе средства выполнения или в репозитории.
583 687
584Снимок `~/.claude/` хоста, который делает средство выполнения, не включает каталог `projects/`. Место хранения автоматической памяти по умолчанию находится внутри этого каталога. Если вы поместите туда файлы памяти, средство выполнения не перенесёт их в сессии, и они не включат автоматическую память.688Снимок `~/.claude/` хоста, который делает средство выполнения, не включает каталог `projects/`. Место хранения автоматической памяти по умолчанию находится внутри этого каталога. Если вы поместите туда файлы памяти, средство выполнения не перенесёт их в сессии, и они не включат автоматическую память.