SpyBara
Go Premium

self-hosted-environments-configuration.md 2026-10-01 23:59 UTC to 2026-10-02 16:57 UTC

This page contains 74 additions and 31 deletions.

2026
Fri 2 18:00

Настройка сессий в самостоятельно размещаемых окружениях

Настройте сессии самостоятельно размещаемого окружения с помощью скриптов-оболочек для учётных данных для каждой сессии, хуков жизненного цикла и порождения средств выполнения по требованию.

Самостоятельно размещаемое окружение запускает облачные сеансы Claude Code на вашей собственной инфраструктуре, выполняемые процессом средства выполнения, который вы развертываете. Без конфигурации это средство выполнения клонирует репозиторий сеанса, порождает Claude Code и выполняет очистку. Эта страница предназначена для инженера платформы, управляющего средствами выполнения: она охватывает точки расширения для случаев, когда эти значения по умолчанию не подходят, от подготовки учетных данных для каждого сеанса до полной замены checkout. Оболочки и хуки запускаются как исполняемые файлы на хосте средства выполнения, который работает на Linux или macOS, и примеры на этой странице предполагают оболочку POSIX.

Несколько переменных окружения хука на этой странице по-прежнему используют pool, такие как CLAUDE_RUNNER_POOL_ID; флаги CLI и имена переменных окружения используют environment, такие как --environment-secret-file.

Скрипты-обёртки

Используйте скрипт-обёртку, когда каждой сессии требуется настройка, которую средство выполнения не может выполнить самостоятельно: подготовка краткосрочных учётных данных, ограниченных создателем сессии, экспорт секретов, специфичных для окружения, подготовка цепочек инструментов языка или применение ограничений ресурсов вокруг дочернего процесса. Средство выполнения запускает вашу обёртку вместо двоичного файла Claude Code один раз за сессию. Завершите обёртку, выполнив exec в $CLAUDE_RUNNER_CLAUDE_BIN, собственный двоичный файл средства выполнения, чтобы сигналы и коды выхода распространялись правильно.

Укажите в --exec-path или SELF_HOSTED_RUNNER_EXEC_PATH путь к обёртке при запуске средства выполнения:

claude self-hosted-runner --environment-secret-file /etc/claude/environment-secret --exec-path /etc/claude/session-wrapper.sh

Средство выполнения устанавливает следующие переменные в окружении обёртки:

Переменная Описание
CLAUDE_CODE_SESSION_ACCESS_TOKEN JWT сессии с префиксом sk-ant-cc-. Его утверждение act идентифицирует создателя сессии, вместе с электронной почтой создателя, если интерфейс, создавший сессию, её записал. Значение — это токен на момент порождения процесса; обновления поступают через stdin дочернего процесса, поэтому обёртка видит только начальное значение. См. Проверка идентичности сессии.
CCR_SESSION_ACCOUNT_EMAIL Электронная почта создателя сессии, предварительно извлечённая средством выполнения из утверждения act.email токена без проверки подписи. Подходит для маркировки, например для трейлеров коммитов. Когда электронная почта управляет выдачей учётных данных, вместо этого проверьте токен и прочитайте утверждение из него; см. Подготовка учётных данных, ограниченных создателем сессии. Не установлена, когда токен не содержит электронную почту создателя. Рассматривайте как персональные данные.
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 или новее.
CLAUDE_RUNNER_CLAUDE_BIN Абсолютный путь к собственному двоичному файлу Claude Code средства выполнения. Завершите вашу обёртку командой exec "$CLAUDE_RUNNER_CLAUDE_BIN" "$@", чтобы передать управление закреплённому двоичному файлу без жёсткого кодирования пути установки.
CLAUDE_CODE_REMOTE_SESSION_ID ID сессии в форме с тегом cse_.... Это та же сессия, которую хуки жизненного цикла видят как CLAUDE_RUNNER_SESSION_ID в форме session_...; переменные UUID совпадают в обоих случаях, а замена префикса cse_ на session_ даёт ID, показанный в URL сессии.
CLAUDE_CODE_REMOTE_SESSION_UUID Тот же ID сессии в канонической форме UUID для систем, которые используют UUID в качестве ключа.
CLAUDE_SESSION_INGRESS_TOKEN_FILE Абсолютный путь к файлу для каждой сессии, содержащему текущий JWT сессии, который поддерживается в актуальном состоянии при обновлении токенов. Подпроцессы оболочки читают его для своего заголовка Authorization при загрузке вложений, которые пользователь добавил в сессию. exec сохраняет переменную автоматически; обёртка, которая перестраивает окружение дочернего процесса, должна перенести переменную, иначе загрузки вложений молча прекратятся.
CLAUDE_CONFIG_DIR Каталог конфигурации Claude для каждой сессии, записываемый при запуске сессии из снимка конфигурации хоста средства выполнения, который средство выполнения захватывает при запуске; см. Разрешения и подтверждение инструментов. Записи здесь изолированы для этой сессии. Каталог остаётся в <base-dir>/_sessions/ после завершения сессии, если вы не запустите средство выполнения с --remove-session-state; см. Повторное использование предварительно подготовленного checkout.
ANTHROPIC_BASE_URL Базовый URL API, который будет использовать дочерний процесс, доставляемый плоскостью управления для каждой сессии; обычно https://api.anthropic.com. Не переопределяйте его: учётные данные вывода сессии — это выданный Anthropic токен OAuth, который другие поставщики не принимают, поэтому вывод в самостоятельно размещаемых окружениях нельзя перенаправить в другое место.
CLAUDE_CODE_OAUTH_TOKEN Краткосрочный токен доступа OAuth, который дочерний процесс использует для вывода модели, ограниченный только выводом модели и загрузкой файлов, со временем жизни около 30 минут. Средство выполнения перевыпускает его до истечения срока и доставляет ротацию через stdin дочернего процесса, поэтому обёртка, которая не сохраняет stdin подключённым, видит только начальное значение. Не полагайтесь на список разрешённых IP-адресов вашей организации для ограничения использования этого токена: рассматривайте его как Bearer-токен, который остаётся пригодным для использования примерно 30 минут в случае утечки, и не записывайте его в лог, не сохраняйте на диск и не пересылайте за пределы контейнера сессии.

Обёртка также наследует остальную часть управляемого окружения дочернего процесса, включая любые переменные окружения, предоставленные сервером. exec передаёт всё это автоматически; если ваша обёртка порождает дочерний процесс другим способом, пересылайте окружение полностью.

Сохраняйте stdin и дескриптор файла 3 подключёнными

stdin дочернего процесса — это канал управления средства выполнения. Ротации токенов и сигналы завершения сессии поступают через него. Средство выполнения также открывает канал на дескрипторе файла 3 и читает из него сигналы активности дочернего процесса для управления таймаутами простоя и запуска. Простой exec "$CLAUDE_RUNNER_CLAUDE_BIN" "$@" сохраняет оба автоматически.

Если ваша обёртка переводит дочерний процесс в фоновый режим с помощью простого &, она разрывает stdin дочернего процесса: сессия выглядит работоспособной до истечения примерно 30-минутного времени жизни начального токена OAuth, после чего каждый вызов API завершается ошибкой 401 authentication_error. Если ваша обёртка должна переводить дочерний процесс в фоновый режим, например чтобы сохранить ловушку очистки, сохраните stdin на дескрипторе файла 4 или выше и явно подключите его заново:

exec 4<&0
"$CLAUDE_RUNNER_CLAUDE_BIN" "$@" <&4 4<&- &
CHILD=$!
trap 'teardown' EXIT
wait "$CHILD"

Не закрывайте и не переиспользуйте дескриптор файла 3 в обёртке. Перенаправлять stdout и stderr дочернего процесса можно.

Передавайте флаги системного промпта дальше

Системный промпт и дополнительный системный промпт, которые плоскость управления Anthropic отправляет для сессии, поступают в вашу обёртку в виде путей к файлам, а не встроенного текста. Средство выполнения записывает каждый промпт в файл в каталоге конфигурации сессии CLAUDE_CONFIG_DIR и передаёт его путь в аргументах, которые получает ваша обёртка, как --system-prompt-file <path> или --append-system-prompt-file <path>.

Средства выполнения на Claude Code v2.1.281 или новее передают промпты в виде файлов. До v2.1.281 средство выполнения передавало их как --system-prompt <text> и --append-system-prompt <text>.

В вашем скрипте-обёртке или хуке command обрабатывайте эти флаги следующим образом:

  • Передавайте их дальше: завершайте обёртку командой exec "$CLAUDE_RUNNER_CLAUDE_BIN" "$@", которая передаёт файловые флаги вместе со всеми остальными аргументами. Не удаляйте и не переписывайте их. Если сессия теряет файловый флаг промпта, она работает без инструкций, которые для неё отправила плоскость управления.
  • На средстве выполнения версии v2.1.281 или новее добавленный вами файловый флаг заменяет серверный, а не дополняет его: каждый файловый флаг промпта принимает одно значение, и Claude Code использует последнее вхождение, поэтому если вы добавите --append-system-prompt-file <path> после "$@", содержимое вашего файла заменит дополнительные инструкции сервера. Чтобы добавить инструкции поверх серверных, поместите их в CLAUDE.md образа средства выполнения, который средство выполнения добавляет в пользовательскую конфигурацию каждой сессии.

Подготовка учётных данных, ограниченных создателем сессии

Используйте подкоманду decode-token для чтения утверждений из JWT сессии. Она читает токен из аргумента, из CLAUDE_CODE_SESSION_ACCESS_TOKEN или из stdin, в этом порядке; о том, что она проверяет, см. Проверка токена внутри сессии. Пример ниже декодирует идентичность создателя, обменивает её на краткосрочные учётные данные AWS и выполняет exec в Claude Code:

#!/bin/bash
# Key on the stable Anthropic user ID and require a human creator.
CREATOR_SUB=$("$CLAUDE_RUNNER_CLAUDE_BIN" self-hosted-runner decode-token \
  | jq -re '.act.sub // "" | select(startswith("user:"))') \
  || { echo "decode-token: verification failed or no human creator" >&2; exit 1; }

creds=$(your-sts-helper assume-role --subject "$CREATOR_SUB") \
  || { echo "credential exchange failed" >&2; exit 1; }
eval "$creds"

exec "$CLAUDE_RUNNER_CLAUDE_BIN" "$@"

Используйте jq -re вместо jq -r, когда извлечённое утверждение определяет решение об авторизации, чтобы при отсутствии утверждения команда завершалась с ненулевым кодом выхода, а не передавала дальше буквальную строку null. Сессии, созданные служебной учётной записью организации, например сессии ботов и агентов, содержат субъект agent: вместо user:, поэтому этот пример отклоняет их; если ваше окружение обслуживает такие сессии, явно решите, должна ли обёртка для них переходить к учётным данным по умолчанию вместо завершения. Если вашему обмену учётными данными вместо этого нужна электронная почта, прочитайте .act.email и обработайте её отсутствие: токен содержит её только тогда, когда интерфейс, создавший сессию, её записал, а у сессии, запущенной через CLI, её может не быть. Полный справочник по утверждениям и описание проверки из служб вне средства выполнения см. в разделе Проверка идентичности сессии.

Lifecycle hooks

Lifecycle hooks заменяют этапы конвейера runner'а для каждой сессии вашими собственными скриптами. Укажите runner'у на директорию с hooks с помощью --hooks-dir <path> или SELF_HOSTED_RUNNER_HOOKS_DIR. Runner ищет исполняемые файлы с известными именами; любой hook, который отсутствует, переходит к встроенному поведению, поэтому вам нужно написать только те, которые вам нужны. Hooks запускаются с собственными привилегиями runner'а, и дочерние процессы сессии используют тот же UID, поэтому монтируйте директорию hooks в режиме только для чтения или встраивайте её в образ, чтобы код сессии не мог её изменять; см. раздел об усилении безопасности.

Эти hooks отличаются от Claude Code hooks, которые запускаются внутри сессии; lifecycle hooks запускаются на runner'е, вокруг сессии.

checkout

Запускается один раз на репозиторий вместо встроенного клонирования и получения данных runner'а. Используйте хук для клонирования из зеркала сквозного доступа, инициализации рабочего дерева из архива или применения аутентификации git для каждой сессии. Runner устанавливает эти переменные, а также может устанавливать другие переменные CLAUDE_RUNNER_, которых нет в таблице:

Variable Description
CLAUDE_RUNNER_REPO_URL URL репозитория для клонирования, после применения любых --git-host-rewrite и --git-ssh-rewrite
CLAUDE_RUNNER_REPO_REF Ревизия для проверки: ветка, тег или SHA коммита, как её запросила сессия. Пусто означает ветку по умолчанию репозитория.
CLAUDE_RUNNER_CHECKOUT_PATH Абсолютный путь, где должно остаться рабочее дерево
CLAUDE_RUNNER_SESSION_ID ID сессии в форме с тегом session_..., для логирования и корреляции
CLAUDE_RUNNER_SESSION_UUID Тот же ID сессии в канонической форме UUID
CLAUDE_RUNNER_API_BASE_URL Базовый URL API Anthropic для вызовов в области сессии
CLAUDE_RUNNER_CLIENT_PLATFORM Поверхность клиента, которая создала сессию, такая как web_claude_ai, desktop_app или ios. Не установлено, когда сессия не имеет записанной или распознанной поверхности.
CLAUDE_CODE_SESSION_ACCESS_TOKEN Токен доступа сессии для вызовов API в области сессии
GIT_CONFIG_COUNT, GIT_CONFIG_KEY_n, GIT_CONFIG_VALUE_n Настройки git, которые runner фиксирует для git, запускаемого вашим хуком. Они описаны в разделе Конфигурация git внутри хуков жизненного цикла. Требуется Claude Code v2.1.280 или новее.

Скрипт должен оставить рабочее дерево в 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.

Runner не передаёт учётные данные git в hook. Вместо этого создайте учётные данные клонирования для каждой сессии из идентификации сессии: проверьте CLAUDE_CODE_SESSION_ACCESS_TOKEN с помощью стандартной библиотеки JWT для конечной точки JWKS под CLAUDE_RUNNER_API_BASE_URL, как описано в Verify the token from your service, затем попросите вашу службу учётных данных выдать краткосрочные учётные данные клонирования для идентификации в утверждении act токена. CLAUDE_RUNNER_CLAUDE_BIN не установлен в окружении checkout-hook, поэтому подкоманда decode-token недоступна здесь. Возврат к любой аутентификации git, которая уже есть на хосте, такой как SSH агент, помощник учётных данных или .netrc, также является вариантом.

Когда hook завершается с ненулевым кодом или завершается с кодом 0 без оставления пригодной для использования проверки, то, что делает runner, зависит от репозитория:

  • Репозиторий, в который сессия отправляет результаты: runner отмечает сеанс как неудачный, и при ненулевом выходе выводит пользователю конец stderr скрипта.
  • Репозиторий, из которого сессия только читает, такой как репозиторий, добавленный к запущенной сессии: runner логирует строку [runner:warn] с деталями отказа, отправляет шаг Skipped в сессию, удаляет всё, что hook оставил в пути проверки, и продолжает с оставшимися репозиториями. Когда runner не может немедленно удалить путь, он повторяет удаление в конце сессии. Если пропуск оставляет сессию вообще без репозитория, runner отмечает сеанс как неудачный в любом случае.

До v2.1.228 runner отмечал сеанс как неудачный при отказе hook для любого репозитория, поэтому репозиторий только для чтения, который hook не мог обслуживать, отмечал сеанс как неудачный снова при каждом новом runner'е, на котором сессия возобновлялась.

Runner удаляет путь проверки после завершения сессии.

post-session

Запускается один раз на сессию, после выхода дочернего процесса Claude Code и перед тем, как runner разбирает рабочее пространство. Этот hook — ваш единственный шанс сохранить незафиксированную работу: при --capacity выше одного runner удаляет рабочие деревья для каждой сессии сразу после возврата hook'а, а при --capacity 1 переиспользуемый канонический клон жёстко сбрасывается при запуске следующей сессии, поэтому незафиксированные отслеживаемые изменения не сохраняются ни в одном случае. Типичные применения — отправка ветки снимка незафиксированных изменений, архивирование логов или отправка события завершения сессии в ваши собственные системы.

Hook срабатывает при каждом завершении сессии, где был порождён дочерний процесс, независимо от причины; значения CLAUDE_RUNNER_EXIT_REASON ниже перечисляют случаи. Он не может срабатывать, когда runner завершается неожиданно, такой как вытеснение VM или потеря питания; если вам нужны гарантии против неожиданного завершения, делайте снимки периодически изнутри сессии с помощью Claude Code PostToolUse hook вместо этого. Runner устанавливает:

Variable Description
CLAUDE_RUNNER_SESSION_ID ID сессии в форме с тегом session_...
CLAUDE_RUNNER_SESSION_UUID Тот же ID сессии в канонической форме UUID
CLAUDE_RUNNER_EXIT_REASON Как завершилась сессия; см. значения ниже таблицы
CLAUDE_RUNNER_WORKSPACE_PATHS Разделённые двоеточиями абсолютные пути рабочих деревьев сессии. Пусто для сессий с нулевым репозиторием.
CLAUDE_RUNNER_DEBUG_LOG_PATH Путь к логу отладки сессии, всё ещё на диске во время выполнения hook'а
CLAUDE_RUNNER_API_BASE_URL Базовый URL API Anthropic для вызовов в области сессии
CLAUDE_RUNNER_CLIENT_PLATFORM Поверхность клиента, которая создала сессию, такая как web_claude_ai, desktop_app или ios. Не установлено, когда сессия не имеет записанной или распознанной поверхности. Требует Claude Code v2.1.229 или позже.
CLAUDE_CODE_SESSION_ACCESS_TOKEN Токен доступа сессии для вызовов API в области сессии
GIT_CONFIG_COUNT, GIT_CONFIG_KEY_n, GIT_CONFIG_VALUE_n Настройки git, которые runner фиксирует для git, запускаемого вашим хуком. Они описаны в разделе Конфигурация git внутри хуков жизненного цикла. Требуется Claude Code v2.1.280 или новее.

CLAUDE_RUNNER_EXIT_REASON принимает одно из четырёх значений:

  • completed: сессия завершилась чисто. Процесс Claude Code завершился нормально, или сессия была архивирована или удалена, пока она всё ещё работала.
  • failed: процесс Claude Code упал, или настройка не удалась после его запуска.
  • interrupted: runner остановил сессию. Он освободил сессию, чтобы освободить слот, сессия истекла при запуске, сервер переместил сессию с этого runner'а, runner был в режиме дренирования, или сессия превысила свой лимит --kill-session-after-min.
  • abandoned: зарезервировано для сессии, которую заявил другой runner. Hook в настоящее время не срабатывает в этом случае.

Счётчики жизненного цикла сессии считают освобождение, истечение времени при запуске и перемещение сервера как completed вместо interrupted, потому что runner чисто вернул слот. Ожидайте этого различия, если вы сравниваете квитанции hook'а со счётчиками.

Статус выхода hook'а никогда не влияет на результат сессии; отказ логируется и игнорируется. Runner ждёт до --post-session-hook-timeout-sec, 60 секунд по умолчанию, при каждом завершении сессии, включая завершение runner'а. Этот пример сохраняет незафиксированную работу в ветку спасения:

#!/usr/bin/env bash
set -u
IFS=':'
# -c overrides beat repo-local settings, blocking session-written fsmonitor,
# hook-path, and gpg-program config from executing code with the hook's
# privileges. -c commit.gpgsign=false also leaves these rescue commits
# unsigned under --configure-git.
# Repo-local credential.helper and pushurl still apply, and on a runner
# before v2.1.280 so does core.sshCommand; if the hook holds credentials
# the session didn't, see the note below the script.
g() { git -c core.fsmonitor=false -c core.hooksPath=/dev/null \
        -c commit.gpgsign=false "$@"; }
for ws in $CLAUDE_RUNNER_WORKSPACE_PATHS; do
  cd "$ws" 2>/dev/null || continue
  [ -z "$(g status --porcelain 2>/dev/null)" ] && continue
  g add -A
  g commit -q -m "runner snapshot: $CLAUDE_RUNNER_SESSION_ID ($CLAUDE_RUNNER_EXIT_REASON)" || continue
  g push -q origin "HEAD:refs/heads/rescue/$CLAUDE_RUNNER_SESSION_ID" || true
done

Хук выполняет push с любыми учётными данными git, доступными в его собственном окружении на хосте runner'а. При подходе без учётных данных в образе, в том числе когда встроенное клонирование проходит через git-прокси Anthropic, их нет, поэтому перед push создайте краткосрочные учётные данные для отправки внутри хука: обменяйте токен сессии, который хук получает в CLAUDE_CODE_SESSION_ACCESS_TOKEN, в вашей собственной службе токенов, предварительно проверив его, как описано в разделе Проверка идентичности сессии. Когда у хука есть учётные данные, которых не было у сессии, замените origin на URL, предоставленный оператором, и передайте -c credential.helper= вместе с вашим собственным помощником. Раздел Конфигурация git внутри хуков жизненного цикла описывает, на что всё ещё может влиять конфигурация, записанная сессией.

Hook timing when the runner releases a session

Освобождённая сессия может возобновиться на другом runner'е. На runner'е версии 2.1.236 или позже то, что сессия делала при освобождении, решает, может ли она возобновиться до завершения этого hook'а:

  • Неактивна после хода или истекла при запуске: runner останавливает дочерний процесс и запускает этот hook до завершения. Только после этого он освобождает сессию. Сообщение пользователя, отправленное во время выполнения hook'а, не может возобновить сессию на другом runner'е до завершения hook'а.
  • Ожидание ответа пользователя на подсказку, такую как подсказка разрешения: runner сначала освобождает сессию, затем запускает этот hook. Сообщение пользователя, отправленное во время выполнения hook'а, может возобновить сессию на другом runner'е до завершения hook'а.

Это применяется всякий раз, когда runner освобождает сессию: при истечении времени неактивности, при --retire-at времени и, на runner'е версии 2.1.260 или позже, при лимите --kill-session-after-min сессии. Сессия, чей ход закончился и которая содержит только фоновые задачи, считается неактивной здесь. До v2.1.236 runner сначала освобождал сессию, а затем запускал этот hook в обоих случаях.

Во время дренирования SIGTERM runner держит аренду сессии до завершения hook'а; см. Shutdown timing.

Git configuration inside lifecycle hooks

Хуки checkout и post-session запускаются с токеном доступа сессии в своём окружении, а git, который они запускают, читает файлы конфигурации, в которые могут записывать сессии, например ~/.gitconfig и .git/config в checkout. Перед запуском любого из этих хуков runner устанавливает в окружении хука настройки git, включая перечисленные ниже, в виде пар GIT_CONFIG_COUNT/GIT_CONFIG_KEY_n/GIT_CONFIG_VALUE_n и переменных окружения git. Git ставит их выше любого файла конфигурации, и они применяются только к git, который запускают ваши хуки, но не к собственному git сессии. При запуске runner выводит строку [runner:git] lifecycle hooks:, в которой показаны действующие путь к хукам, разрешённые протоколы, программы gpg и режим подписи. Требуется Claude Code v2.1.280 или новее.

  • Хуки git: если вы не укажете значение, core.hooksPath равен /dev/null, поэтому git пропускает хуки в .git/hooks репозитория и любую директорию хуков, указанную в ~/.gitconfig. Чтобы указать своё значение, экспортируйте core.hooksPath как пару GIT_CONFIG_KEY_n/GIT_CONFIG_VALUE_n в окружении runner'а. Runner также читает core.hooksPath из системной конфигурации git и использует его, только если пользователь runner'а не может записывать в этот файл, в указанную в нём директорию или в файлы хуков в ней. Когда runner игнорирует значение, строка [runner:warn] при запуске называет это значение и причину.
  • Монитор файловой системы: core.fsmonitor пуст, поэтому git в вашем хуке не запускает программу-монитор, указанную в файле конфигурации.
  • Удалённые протоколы: GIT_ALLOW_PROTOCOL равна https:http:ssh. Clone, fetch или push с локальным путём, URL file:// или URL git:// завершается ошибкой fatal: transport 'file' not allowed или fatal: transport 'git' not allowed.
  • Команда SSH и запрос учётных данных: git в вашем хуке игнорирует core.sshCommand и core.askPass из файлов конфигурации. Чтобы использовать собственную команду SSH, установите GIT_SSH_COMMAND в окружении runner'а. Чтобы использовать программу запроса учётных данных, установите там GIT_ASKPASS. Сессии наследуют окружение runner'а, поэтому обе переменные также попадают в собственный git сессии. Не помещайте учётные данные ни в одну из них.
  • Программы gpg: gpg.program, gpg.openpgp.program, gpg.x509.program и gpg.ssh.program — это пути, которые устанавливает runner, а не значения из файла конфигурации.
  • Подпись коммитов: с --configure-git коммиты, которые вы делаете из хука, подписываются от имени сессии. Без этого флага commit.gpgsign и tag.gpgsign равны false.

Чтобы изменить одну из этих настроек, используйте окружение runner'а или опцию git -c внутри хука:

  • Пары конфигурации: пара GIT_CONFIG_KEY_n/GIT_CONFIG_VALUE_n, которую вы экспортируете в окружении runner'а, заменяет значение runner'а для того же ключа. Нумеруйте свои пары с 0 и установите GIT_CONFIG_COUNT равной их количеству. Если последняя пара, заявленная этим количеством, отсутствует, runner игнорирует все ваши пары и при запуске записывает в лог строку [runner:warn].
  • Переменные окружения git: runner оставляет GIT_ALLOW_PROTOCOL, GIT_SSH_COMMAND и GIT_ASKPASS такими, какими вы их установили в его окружении.
  • Опции git -c: опция git -c внутри хука переопределяет пару GIT_CONFIG_KEY_n — как runner'а, так и вашу. Она не изменяет GIT_ALLOW_PROTOCOL, GIT_SSH_COMMAND или GIT_ASKPASS, которые git читает раньше любой конфигурации.

Git в вашем хуке по-прежнему читает все настройки, которые не устанавливает runner, например помощники учётных данных, перезаписи url.*.insteadOf и драйверы фильтров, из всех файлов конфигурации, включая те, в которые могут записывать сессии. Помощник учётных данных или драйвер фильтра, указанный в одном из этих файлов, запускается как программа с привилегиями вашего хука, а конфигурация в этих файлах по-прежнему может изменить, куда уходит push из вашего хука, в том числе push на URL, который вы передаёте в командной строке.

До v2.1.280 runner не устанавливал ни одну из этих настроек, а при --configure-git коммит из хука завершался ошибкой, если хук не передавал -c commit.gpgsign=false.

command

Запускается один раз на сессию после checkout, вместо встроенного порождения дочернего процесса. Hook получает то же окружение, что и wrapper script, и должен exec в "$CLAUDE_RUNNER_CLAUDE_BIN" таким же образом. Используйте command hook, чтобы держать всю настройку в одной директории hooks; используйте --exec-path, когда wrapper находится в другом месте. Если --exec-path также установлен, флаг имеет приоритет и command hook игнорируется.

Всегда exec собственный бинарный файл runner'а вместо разрешённого PATH claude; иначе вы нарушите закрепление версии.

Средства выполнения по требованию

Вместо запуска фиксированного флота вы можете загрузить одно средство выполнения за сеанс. Оркестратор — это отдельная, без состояния подкоманда, которая опрашивает Anthropic на предмет запросов на порождение, по одному за сеанс, который находится в очереди без доступного средства выполнения, и запускает ваш хук spawn-runner для каждого. Ваш хук отправляет рабочую нагрузку на вашу платформу: Kubernetes Job, экземпляр EC2, Nomad dispatch.

Средства выполнения по требованию улучшают гигиену учетных данных. На фиксированном флоте секрет окружения находится на каждом хосте средства выполнения, который является тем же хостом, на котором запускается код пользователя. С оркестратором секрет окружения остается только на хосте оркестратора, который никогда не запускает код пользователя; каждое порожденное средство выполнения получает одноразовый наряд на работу, который регистрирует ровно одно средство выполнения и затем истекает.

Чтобы запустить оркестратор, передайте секрет окружения и каталог хуков, содержащий исполняемый скрипт spawn-runner:

claude self-hosted-runner orchestrator \
  --environment-secret-file /etc/claude/environment-secret \
  --hooks-dir /etc/claude/hooks

Оркестратор не сохраняет состояние между опросами, поэтому вы можете запустить две или более реплик против одного и того же окружения для доступности. Каждый запрос на порождение заявляется на стороне сервера ровно одной репликой. Все реплики должны использовать одно и то же значение --expected-spawn-seconds; см. контракт хука.

Хук spawn-runner

Оркестратор запускает ${hooks-dir}/spawn-runner один раз за запрос на порождение. Хук должен отправить работу асинхронно, без ожидания загрузки средства выполнения, и вернуться в течение --hook-timeout, 60 секунд по умолчанию. Хук получает:

Переменная Описание
CLAUDE_RUNNER_WORK_ORDER_FILE Путь к временному файлу, содержащему подписанный JWT наряда на работу, с которым регистрируется новое средство выполнения. Удалено после выхода хука. Не логируйте содержимое файла.
CLAUDE_RUNNER_ORDER_ID Непрозрачный ключ идемпотентности, уникальный для каждого запроса на порождение и безопасный для имен ресурсов Kubernetes. Используйте только ID заказа как ключ дедупликации вашего провизионера.
CLAUDE_RUNNER_SESSION_ID Сеанс, для которого предназначен этот запрос. Он повторяется при каждом повторном запросе для сеанса, поэтому используйте его для логирования и маршрутизации, а не как ключ дедупликации. Пусто для запросов предварительного прогрева, которые загружают резервное средство выполнения перед любым конкретным сеансом, когда установлен --min-idle, поэтому не предполагайте, что переменная установлена.
CLAUDE_RUNNER_SESSION_UUID Тот же ID сеанса в канонической форме UUID. Пусто для запросов предварительного прогрева.
CLAUDE_RUNNER_ATTEMPT Сколько запросов на порождение было у этого сеанса. 0 для запросов предварительного прогрева.
CLAUDE_RUNNER_ORDER_SERVER_TIME Время сервера из заголовка HTTP Date ответа опроса. Когда хук проверяет exp JWT наряда на работу, сравнивайте с этим значением вместо локальных часов, чтобы допустить перекос. Пусто, когда шлюз опустил заголовок.
CLAUDE_RUNNER_POOL_ID ID окружения, к которому должно присоединиться новое средство выполнения, в форме ccpool_...
CLAUDE_RUNNER_ACCOUNT_ID Помеченный ID учетной записи, которая поставила сеанс в очередь, для маршрутизации по учетной записи, квоты или возврата средств. Пусто, когда недоступно, и всегда пусто для сеансов канала Claude Tag, которые не ставит в очередь ни одна учетная запись.
CLAUDE_RUNNER_ACCOUNT_EMAIL Электронная почта учетной записи, которая поставила сеанс в очередь. Пусто, когда недоступно. Рассматривайте электронную почту как личную информацию и не логируйте ее.
CLAUDE_RUNNER_PRIMARY_REPO_URL URL первого источника git сеанса для маршрутизации на средство выполнения с этим репозиторием предварительно прогретым. Пусто, когда сеанс не имеет источников git.
CLAUDE_RUNNER_PRIMARY_REPO_REVISION Ревизия первого источника git сеанса: ветка, SHA или тег. Пусто, когда не указано.
CLAUDE_RUNNER_REPO_SOURCES JSON массив {url, revision} для всех источников git сеанса для хуков, которые маршрутизируют на вторичный репозиторий. Пусто, когда нет источников.
CLAUDE_RUNNER_CORRELATION_ID ID корреляции, предоставленный при создании сеанса, повторно отправленный, чтобы хук мог сопоставить этот наряд на работу с запросом, который создал сеанс. Пусто, когда сеанс не имеет ни одного.
CLAUDE_RUNNER_CLIENT_PLATFORM Поверхность клиента, которая создала сеанс, такая как web_claude_ai, desktop_app, ios или scheduled_trigger, для аналитики внедрения. Не установлена, когда сеанс не имеет записанной или распознанной поверхности, и для запросов предварительного прогрева; проверьте ее с помощью [ -n "${CLAUDE_RUNNER_CLIENT_PLATFORM:-}" ], что остается безопасным под set -u.

Порожденное средство выполнения регистрируется с нарядом на работу вместо секрета окружения:

  • Запустите его с нарядом на работу: укажите --environment-secret-file на файл, содержащий JWT наряда на работу, или установите SELF_HOSTED_RUNNER_ENVIRONMENT_SECRET на значение JWT.
  • Скопируйте JWT перед выходом хука: оркестратор удаляет файл наряда на работу после выхода хука, поэтому скопируйте JWT в рабочую нагрузку, которую вы отправляете, такую как Kubernetes Secret на порожденном Job, вместо передачи пути файла.
  • Используйте --capacity 1 на порожденных средствах выполнения: наряд на работу, привязанный к сеансу, регистрирует ровно одно средство выполнения, привязанное к этому сеансу, поэтому более высокая емкость добавляет слоты, которые никогда не получают работу, и средство выполнения логирует предупреждение при запуске.
  • Нарядные работы предварительного прогрева регистрируют без привязки: резервное средство выполнения не привязано к сеансу и заявляет поставленную в очередь работу, как средство выполнения фиксированного флота.

Контракт имеет четыре правила, независимые от провизионера:

  1. Будьте идемпотентны на CLAUDE_RUNNER_ORDER_ID. Переделивка одного и того же запроса должна порождать не более одного средства выполнения. Выведите детерминированное имя ресурса из ID заказа и позвольте вашей платформе отклонить дубликат. Не ключируйте на CLAUDE_RUNNER_SESSION_ID вместо этого. Каждый повторный запрос для сеанса несет тот же ID сеанса с новым ID заказа, поэтому рабочая нагрузка, названная или дедуплицированная по ID сеанса, создается один раз и никогда снова для этого сеанса.
  2. Не повторяйте рабочую нагрузку. Один ID заказа означает не более одной созданной рабочей нагрузки. Если средство выполнения никогда не регистрируется, Anthropic повторно запрашивает с новым ID заказа после --expected-spawn-seconds.
  3. Используйте контракт кода выхода. Выход 0 означает отправлено. Выход 1 означает повторяемый отказ; сеанс отступает и переоффертируется. Выход 2 или выше означает неповторяемый; сеанс блокируется от порождения снова до тех пор, пока владелец не выберет Retry на нем на вкладке Activity окружения. При ненулевом выходе хвост stderr хука появляется там как причина отказа, поэтому напишите действенную ошибку в stderr и никогда не секреты. Для запроса предварительного прогрева нет сеанса для отказа: оркестратор логирует ненулевой выход локально только, и сервер повторно запрашивает порождение после аренды.
  4. Установите --expected-spawn-seconds на по крайней мере ваше время загрузки p99. Это аренда на стороне сервера. Все реплики оркестратора должны использовать одно и то же значение.

Все, что хук пишет в stdout или stderr, появляется в логе оркестратора с автоматически удаленными учетными данными. Если сеансы остаются в очереди, проверьте тело /healthz оркестратора на предмет количества в очереди, затем откройте вкладку Activity вашего окружения на странице администратора Cloud environments: разверните неудачный сеанс там для его ошибки порождения и выберите Retry для повторного запроса.

Сеанс, который остается в очереди без ошибки порождения на вкладке Activity, может означать, что хук ключируется по ID сеанса. Чтобы подтвердить, проверьте, есть ли на вашей платформе рабочая нагрузка для первого запроса порождения этого сеанса и нет ни одной для повторных запросов. Если это так, ключируйте рабочую нагрузку на CLAUDE_RUNNER_ORDER_ID вместо этого.

MCP серверы

Чтобы сделать MCP серверы доступными в каждом сеансе, добавьте их во время сборки образа с помощью той же команды claude mcp add, используемой при установке на рабочем столе. Если ваше средство выполнения — это простой процесс, а не контейнер, запустите ту же команду от пользователя средства выполнения на хосте, затем перезагрузите средство выполнения: оно читает конфигурацию хоста один раз при запуске. Флаг --scope user требуется; область по умолчанию пишет под ключом для каждого каталога, который средство выполнения не заполняет в сеансы. Например, в вашем Dockerfile:

RUN claude mcp add --scope user sidecar -- /usr/local/bin/mcp-sidecar
RUN claude mcp add --scope user --transport http internal http://mcp-gateway.svc.cluster.local:8080

Средство выполнения снимает конфигурацию хоста один раз при запуске. Снимок захватывает ключ mcpServers из .claude.json хоста, который находится рядом, а не внутри ~/.claude/, и средство выполнения заполняет только этот ключ в изолированную конфигурацию каждого сеанса; состояние учетной записи и история проекта отбрасываются. Чтобы подтвердить, что серверы достигли сеансов, запустите сеанс в окружении и попросите Claude перечислить его инструменты MCP; средство выполнения также логирует предупреждение при запуске для любой захваченной записи, чей type оно не распознает, и отбрасывает запись, поэтому вы можете увидеть, почему этот сервер отсутствует в сеансах. Когда установлен SELF_HOSTED_RUNNER_HOST_CONFIG_DIR, средство выполнения читает .claude.json из этого каталога вместо этого, поэтому указание переменной на пустой каталог также отключает заполнение MCP.

Claude Code также загружает MCP серверы из других источников:

  • Файл MCP управляемый на уровне предприятия по его стандартному системному пути: /etc/claude-code/managed-mcp.json на хостах средства выполнения Linux, /Library/Application Support/ClaudeCode/managed-mcp.json на хостах macOS. Используйте его для заблокированных флотов, где только серверы, указанные администратором, могут загружаться. См. exclusive control with managed-mcp.json для правил приоритета. Когда этот файл находится на хосте средства выполнения, Claude Code пропускает MCP серверы, которые плоскость управления Anthropic доставляет в сеанс, включая разъемы claude.ai, и называет их в предупреждении на stderr дочернего процесса сеанса, которое средство выполнения записывает на уровне логирования debug. До v2.1.229 эти сеансы выходили при запуске с You cannot dynamically configure MCP servers when an enterprise MCP config is present.
  • Ключ managedMcpServers в управляемых настройках на хосте средства выполнения: предоставляет HTTP и SSE серверы без принятия исключительного управления, поэтому серверы из других источников по-прежнему загружаются. Требует Claude Code v2.1.259 или позже.
  • <repo>/.mcp.json: область проекта. Зафиксируйте файл в репозитории; его серверы автоматически одобрены в облачных сеансах.

Когда доставка разъемов включена для вашей организации, плоскость управления Anthropic доставляет разъемы, которые вы настроили на claude.ai, в интерактивно созданные сеансы через конфигурацию MCP, предоставленную сервером, маршрутизируемую через api.anthropic.com. Сеансы, созданные программно, такие как CLI dispatches, не получают доставку разъемов; дайте им MCP серверы через любой из других источников, которые этот раздел перечисляет вместо этого. Токен OAuth дочернего процесса не содержит область для прямой выборки разъемов, поэтому дочерний процесс не пытается эту выборку сам; доставка управляется сервером.

settings.json не содержит определения MCP сервера, и в схеме настроек нет поля mcpServers верхнего уровня. В управляемых настройках предоставляйте серверы с помощью ключа managedMcpServers вместо этого.

Сеансы наследуют окружение средства выполнения, поэтому установите ENABLE_TOOL_SEARCH там для управления поиском инструментов MCP для каждого сеанса, который порождает средство выполнения; страница MCP охватывает значения.

Отключение встроенных инструментов сеанса

Плоскость управления Anthropic присоединяет свой собственный MCP сервер, названный Claude Code Remote, к облачным сеансам. Claude использует инструменты сервера для планирования routines, запуска и управления другими облачными сеансами, присоединения дополнительных репозиториев и отслеживания активности запросов на слияние.

Чтобы отключить весь сервер, добавьте server-level deny rule в ваши настройки. Плоскость управления регистрирует сервер под одним из трех имен в зависимости от того, как был создан сеанс. Claude Code точно совпадает с именем в правиле, включая регистр, поэтому напишите правило один раз для каждого имени, как показано:

{
  "permissions": {
    "deny": [
      "mcp__Claude_Code_Remote",
      "mcp__claude-code-remote",
      "mcp__bf7c680d-5fdc-5ef4-b4a0-abadb619bf0a"
    ]
  }
}

Правило, которое называет весь сервер, охватывает инструменты, которые сервер получает позже. Чтобы отключить один инструмент и сохранить остальные, добавьте два дополнительных подчеркивания и имя инструмента к каждому правилу, как в mcp__Claude_Code_Remote__add_repo. Чтобы заблокировать подключение сервера вообще, а не удалять его инструменты, добавьте три имена без префикса mcp__ как записи serverName под deniedMcpServers вместо этого.

Поместите правила в server-managed settings для достижения каждого сеанса без изменения средства выполнения, или в ~/.claude/settings.json на средстве выполнения. Permissions and tool approval объясняет, как настройки на средстве выполнения достигают сеансов.

Чтобы подтвердить, что правила вступили в силу, запустите сеанс в окружении и попросите Claude перечислить его инструменты MCP. Claude Code удаляет запрещенный инструмент из контекста Claude, поэтому запрещенные инструменты отсутствуют в его ответе.

Подсказка сеансов для отправки их работы

Размещенные Anthropic сеансы запускают хук Stop, хук Claude Code, который запускается, когда Claude заканчивает отвечать, который подсказывает Claude зафиксировать и отправить его работу. Средство выполнения не устанавливает один. Без него сеанс, который заканчивается с незафиксированными изменениями, оставляет эту работу только на диске средства выполнения, и кнопка Create PR в claude.ai/code остается неактивной до тех пор, пока ветка не существует на удаленном.

Эталонная реализация ниже имеет две части. Объедините блок настроек в ~/.claude/settings.json на хосте средства выполнения, который средство выполнения заполняет в каждый сеанс, и сохраните скрипт как ~/.claude/hooks/stop-hook-nudge.sh на хосте средства выполнения и сделайте его исполняемым:

{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "timeout": 10,
            "command": "\"$CLAUDE_CONFIG_DIR/hooks/stop-hook-nudge.sh\""
          }
        ]
      }
    ]
  }
}
#!/bin/sh
# Stop-hook reference implementation for self-hosted runners.
#
# Nudges Claude once per turn if the project directory has uncommitted
# changes OR unpushed commits, so work isn't lost when an idle session
# is released and so the "Create PR" button on claude.ai/code lights up.
#
# Runner-level (no repo changes): drop this file at ~/.claude/hooks/ on
# the runner host and merge the accompanying Stop-hook settings block
# into ~/.claude/settings.json — the runner seeds both into every session.
# Repo-level alternative: commit to <repo>/.claude/hooks/ and change the
# settings.json command path to $CLAUDE_PROJECT_DIR/.claude/hooks/.
#
# stdin: hook JSON payload (see https://code.claude.com/docs/en/hooks)
# stdout: {"decision":"block","reason":"..."} to nudge, or nothing to allow stop.

# Re-entry guard: the harness sets stop_hook_active=true when re-invoking
# the Stop hook after a block. Bail so we only nudge once per turn. The
# harness emits compact JSON (no space after the colon), which this
# pattern relies on; use jq if you need a whitespace-tolerant check.
in=$(cat)
case "$in" in *'"stop_hook_active":true'*) exit 0 ;; esac

d="$CLAUDE_PROJECT_DIR"

# Not a git repo → nothing to nudge.
git -C "$d" rev-parse --git-dir >/dev/null 2>&1 || exit 0

# No remote → "push to the remote" is unsatisfiable; bail.
[ -z "$(git -C "$d" remote 2>/dev/null)" ] && exit 0

# Uncommitted changes (staged, unstaged, or untracked). Exclude .claude/
# entirely — operator-seeded settings and CLI-written runtime state
# (scheduler lock, worktrees, routine state) live there and neither is
# "uncommitted work" the model needs to push.
s=$(git -C "$d" status --porcelain -- . ':(exclude).claude/' 2>/dev/null)
if [ -n "$s" ]; then
  printf '{"decision":"block","reason":"There are uncommitted changes in the repository. Please commit and push these changes to the remote branch."}'
  exit 0
fi

# Unpushed commits. Count commits on HEAD not reachable from any
# remote-tracking ref or FETCH_HEAD. This works uniformly for:
#   - init+fetch checkouts (runner default: only FETCH_HEAD exists)
#   - clone-based checkouts (origin/* exist)
#   - the runner default: the child starts on the session's outcome
#     branch, which the runner creates after checkout
#   - detached HEAD, when a custom setup skips that branch creation
# With no reference point at all (never fetched), stay silent rather
# than false-positive on a read-only turn.
base=""
git -C "$d" rev-parse --verify -q FETCH_HEAD >/dev/null && base="FETCH_HEAD"
if [ -z "$base" ] && [ -z "$(git -C "$d" for-each-ref --count=1 refs/remotes/origin 2>/dev/null)" ]; then
  exit 0
fi
# shellcheck disable=SC2086  # $base is either "" or "FETCH_HEAD", intentional word-split
unpushed=$(git -C "$d" rev-list HEAD --not $base --remotes=origin --count 2>/dev/null) || unpushed=0
if [ "$unpushed" -gt 0 ]; then
  branch=$(git -C "$d" symbolic-ref --short -q HEAD)
  if [ -n "$branch" ]; then
    # $branch is attacker-influenced — git-check-ref-format(1) allows `"`
    # in ref names. `\` is forbidden (rule 10) but escaped anyway as cheap
    # defense-in-depth.
    # Escape JSON metacharacters before interpolating into the hand-built
    # payload so a branch like x","continue":false can't inject keys into
    # the hook-output JSON the harness parses. $unpushed is safe — the
    # -gt guard above rejects anything that isn't a plain integer.
    branch_esc=$(printf '%s' "$branch" | sed 's/\\/\\\\/g; s/"/\\"/g')
    printf '{"decision":"block","reason":"There are %s unpushed commit(s) on branch '\''%s'\''. Please push these changes to the remote repository."}' "$unpushed" "$branch_esc"
  else
    printf '{"decision":"block","reason":"There are %s unpushed commit(s) on a detached HEAD. Please create a branch and push it to the remote repository."}' "$unpushed"
  fi
  exit 0
fi

exit 0

Хук подсказывает Claude зафиксировать и отправить перед завершением сеанса и остается молчаливым, когда каталог не является репозиторием git или не имеет удаленного.

Разрешения и одобрение инструментов

Самостоятельно размещаемый сеанс не имеет прикрепленного терминала, поэтому неотвеченная подсказка разрешения блокирует ход до тех пор, пока пользователь не ответит в UI. Плоскость управления Anthropic отправляет список инструментов каждого сеанса и правила разрешений с полезной нагрузкой работы; конфигурация по умолчанию предварительно одобряет обычные вызовы инструментов, включая Bash, и облачные сеансы предварительно одобряют редактирование файлов независимо от режима. Вызов, который ничто не предварительно одобряет, подсказывает через UI сеанса.

Чтобы минимизировать подсказки независимо от того, что отправляет плоскость управления, закрепите автоматический режим из вашего скрипта-оболочки или хука command. Автоматический режим позволяет сеансам запускаться без обычных подсказок разрешения: отдельная модель классификатора проверяет действия перед их запуском и блокирует те, которые она отклоняет, и явные правила запроса по-прежнему вынуждают подсказку; страница режимов разрешений охватывает то, что классификатор проверяет. Средство выполнения добавляет вычисленные сервером флаги перед вызовом оболочки, и для флагов с одним значением, таких как --permission-mode, парсер соблюдает последнее вхождение, поэтому флаг, который вы добавляете после "$@", переопределяет значение, отправленное сервером:

#!/bin/bash
exec "$CLAUDE_RUNNER_CLAUDE_BIN" "$@" --permission-mode auto

Чтобы предварительно одобрить конкретные инструменты вместо этого, добавьте --allowed-tools с вашими правилами, например --allowed-tools "Bash(bazel *) Bash(yarn *) mcp__internal__*". Флаги списков, такие как --allowed-tools и --disallowed-tools, накапливаются при вхождениях вместо переопределения, поэтому ваши правила применяются поверх любых правил, которые отправляет плоскость управления. Чтобы сузить, добавьте --disallowed-tools, который отрицает инструменты, даже если другое правило их разрешает.

Как собирается конфигурация каждого сеанса

Средство выполнения дает каждому сеансу свой собственный каталог конфигурации, заполненный из снимка в памяти ~/.claude/ хоста, который средство выполнения захватывает один раз при запуске: settings.json, CLAUDE.md, хуки, агенты, команды и навыки в вашем образе средства выполнения применяются к каждому сеансу как базовая линия уровня пользователя. Если вы измените конфигурацию на работающем хосте, изменение вступает в силу только после перезагрузки средства выполнения.

Установите SELF_HOSTED_RUNNER_HOST_CONFIG_DIR для заполнения из другого пути или укажите его на пустой каталог для отключения заполнения.

Зафиксированный в репозитории .claude/settings.json накладывается сверху как настройки проекта. Сеансы также читают managed-settings.json из стандартного системного пути в вашем образе средства выполнения. Применяются ли его ключи наряду с управляемыми сервером настройками следует как Claude Code объединяет управляемые источники: по умолчанию, когда ваша организация доставляет любые управляемые сервером ключи, сеансы игнорируют файл образа средства выполнения, кроме ключей, которые Claude Code читает из каждого источника администратора, такие как блок env, блокировки песочницы, пути двоичных файлов песочницы и forceRemoteSettingsRefresh. См. приоритет настроек.

Когда плоскость управления Anthropic предоставляет сеансу хуки Claude Code, средство выполнения устанавливает их рядом, а не над вашей собственной конфигурацией. Требует Claude Code v2.1.229 или позже.

  • Где они приземляются: средство выполнения пишет каждый предоставленный скрипт хука в зарезервированный подкаталог hooks/.ccr-launcher/ каталога конфигурации сеанса и регистрирует скрипты в отдельном файле настроек, который он передает сеансу с помощью --settings, оставляя заполненный settings.json и ваши собственные скрипты в hooks/<name> нетронутыми. Средство выполнения пересоздает зарезервированный подкаталог для каждого сеанса и не заполняет содержимое хоста в ~/.claude/hooks/.ccr-launcher/ в сеансы.
  • Кто их создает: плоскость управления заполняет скрипты из фиксированных констант в своем собственном развертывании, никогда не из входных данных для каждого сеанса или третьей стороны.
  • Что по-прежнему их управляет: хуки, доставленные через --settings, входят в обычную объединенную конфигурацию хука, а не в управляемый уровень, поэтому ваши управляемые настройки по-прежнему применяются. disableAllHooks отключает их, и они не входят в категории, которые allowManagedHooksOnly сохраняет загруженными.

Вне сессий Claude Tag сессия в самостоятельно размещаемом окружении по умолчанию работает с отключённой автоматической памятью. Для инструкций, которые должны сохраняться между сессиями, используйте CLAUDE.md в вашем образе средства выполнения или в репозитории.

Снимок ~/.claude/ хоста, который делает средство выполнения, не включает каталог projects/. Место хранения автоматической памяти по умолчанию находится внутри этого каталога. Если вы поместите туда файлы памяти, средство выполнения не перенесёт их в сессии, и они не включат автоматическую память.

Правила разрешений, зафиксированные в репозитории

Не помещайте запись "Edit", "Write" или "NotebookEdit" без квалификации в зафиксированный в репозитории permissions.allow. Правило инструмента файла без квалификации соответствует инструменту независимо от пути, предоставляя записи в любом месте на хосте вместо только рабочей области, поэтому охрана ограничения области записи средства выполнения отмечает сеанс; с --confine-repo-settings enforce она отказывает в порождении сеанса вместо логирования и продолжения. См. раздел hardening.

Репозиторий не нуждается в правиле инструмента файла вообще: облачные сеансы предварительно одобряют редактирование файлов независимо от режима. Если вы все же зафиксируете правило, ограничьте его рабочей областью, такой как "Edit(/**)"; одна ведущая косая черта относительна к корню проекта, который является рабочей областью сеанса. Правила инструмента файла без квалификации в порядке в settings.json оператора на уровне хоста, так как этот файл не зафиксирован в репозитории.

defaultMode из auto соблюдается только из файла настроек на уровне образа или пользователя, поэтому проверенный репозиторий не может предоставить себе автоматический режим. Для того, какие режимы облачные сеансы принимают и полный синтаксис правила, см. режимы разрешений.

Что дальше

  • Reference: каждый флаг CLI, переменная окружения и метрика
  • Verify session identity: проверьте токен сеанса из служб вне средства выполнения