Перейти к содержимому

API среды выполнения сеанса (официальные CLI)

Плоскость управления запускает CLI поставщика. Она не заменяет Claude Code, Codex или Grok Build. Сеансы и терминалы — один модуль этого продукта, а не продукт.

Эта страница описывает Community operate-маршруты под /v1/m/sessions/runs. Они уже есть в бета-документе OpenAPI. Выпуск 26.10 добавляет контракт драйвера, транспорт, который нужен каждой форме запуска, и сценарии J01–J08 как тесты.

Редакция Что делает Чего не делает
Community (эта страница) Собственный локальный потомок: запуск, stdin/stdout/stderr, attach с курсором, возобновление точного разговора, повторное подключение живого потока, остановка с наблюдаемым кодом выхода. Строки сессий и доказательства остаются в модуле II. Движок Identity & Scale с несколькими панелями, слушатель mTLS, ввод в панели cockpit, чанк интерфейса xterm
Оверлей Identity & Scale Коммерческий движок session-cockpit (слушатель, панели, журнал записей). Маршруты находятся под /v1/m/session-cockpit/, когда модуль присутствует. Не заменяет /v1/m/sessions/runs

Сборка Community отвечает на пространство имён оверлея отсутствием (404). Она не монтирует заглушку 501.

Путь hook Claude Code остаётся olivares claude-hook (PreToolUse PEP). Это наблюдение и принуждение, а не замена CLI.

Существующее принуждение на маршрутах модуля:

Право Маршруты
sessions:run:read GET /runs, GET /runs/{ref}, GET /runs/{ref}/events, GET /runs/{ref}/attach, GET /runs/{ref}/handoff, GET /runs/{ref}/activity, GET /runs/{ref}/activity/agents/{agent}, GET /runs/{ref}/messages, POST /runs/{ref}/pin, DELETE /runs/{ref}/pin
sessions:run:write POST /runs, POST /runs/{ref}/input, POST /runs/{ref}/interrupt, POST /runs/{ref}/stop, POST /runs/{ref}/resume, POST /runs/{ref}/move, POST /runs/{ref}/handoff, PUT /runs/{ref}/name, POST /runs/{ref}/archive, DELETE /runs/{ref}/archive
sessions:run:admin POST /runs/{ref}/cleanup, DELETE /runs/{ref}

Viewer может читать список и закреплять сессии для себя. Создание, ввод и остановка требуют write. Authorizer маршрута — точка принуждения; отсутствующее право даёт 403.

База: /v1/m/sessions. Аутентифицируйтесь. Отправьте X-Olivares-Tenant.

Метод Путь Результат
GET /runs Страница управляемых запусков. Необязательные state, live_ref, claude_session_id (legacy)
GET /runs/{ref} Один запуск. state выводится. exit_code наблюдается. Нет выдуманного поля успеха. archived_at (RFC 3339, UTC) присутствует, пока сессия в архиве
GET /runs/{ref}/events Строки доказательств жизненного цикла
GET /runs/{ref}/attach?from={seq} SSE: кадры output, lag, если кольцо вытеснило ниже курсора, end или notice, что сессия не жива. Сессия Grok, OpenCode или Gemini CLI, возобновлённая после запуска, которому переданы секреты хранилища (vault), учётные данные репозитория, управляемые учётные данные или токен реестра пакетов, не передаёт разговор, который её инструмент воспроизводит при возобновлении, и сообщает об этом одним кадром olivares_notice (history_withheld)
POST /runs/{ref}/input stdin. Stream-json использует line/message. Codex/Grok — text. 202 {accepted:true}
POST /runs/{ref}/stop SIGTERM, затем SIGKILL группы процессов. Наблюдаемый код выхода в строке
POST /runs/{ref}/resume Новое поколение процесса. Точный сохранённый разговор. Тихого отката к новому разговору нет
POST /runs/{ref}/interrupt Отменяет активный ход. Процесс остаётся
POST, DELETE /runs/{ref}/pin Закрепляет сессию за вызывающим или открепляет её. Закрепление принадлежит вызывающему и следует за ним в другой браузер или на другую машину; оно никогда не меняет список другого человека. Оба вызова идемпотентны и отвечают 200 {run_ref, pinned, pinned_at}. За одним человеком закреплено не более 20 сессий: при закреплении 21-й самая старая открепляется. Освобождение или удаление сессии снимает все закрепления на ней. GET /runs и GET /runs/{ref} несут собственные pinned и pinned_at вызывающего, а GET /runs также возвращает закреплённые сессии вызывающего, которые выходят за пределы его страницы (не более 20 строк сверх limit; pagination=cursor ничего не добавляет, поскольку один раз охватывает все сессии). Закрепление принадлежит учётным данным, которыми оно сделано: консоль человека и сессии olivares login делят свои закрепления, а токен API хранит собственные. Освобождённая сессия отвечает 409
POST, DELETE /runs/{ref}/snooze Откладывает сессию для вызывающего до момента или снимает отложение. POST принимает {until}, время RFC 3339 в будущем (иначе 400); второй POST переносит его. Отложение принадлежит вызывающему, как и закрепление: консоль убирает сессию из списка этого человека до until, списки других людей не меняются. Оба запроса отвечают 200 {run_ref, snoozed_until?, done}. GET /runs и GET /runs/{ref} несут snoozed_until вызывающего только пока действует отложение. Освобождение или удаление сессии снимает все отложения на ней. Освобождённая сессия отвечает 409
POST, DELETE /runs/{ref}/done Отмечает сессию как готовую для вызывающего или снимает отметку. Консоль помещает готовую сессию в «Ранее» в списке этого человека. Оба вызова идемпотентны и отвечают 200 {run_ref, snoozed_until?, done}. GET /runs и GET /runs/{ref} несут done вызывающего. Освобождение или удаление сессии снимает все отметки на ней. Освобождённая сессия отвечает 409
PUT /runs/{ref}/name Тело {name}. Переименовывает сессию. Имя обрезается по краям; пустое имя стирает его, и клиенты возвращаются к собственному именованию. Больше 200 символов, управляющий или невидимый символ (форматирования, разделитель строк или абзацев: пробелы нулевой ширины, переопределения направления) или отсутствующее name дают 400. 200 run. Имя принадлежит сессии, поэтому его видит каждый читатель. Записывается в журнал аудита как sessions.run.renamed со ссылкой на запуск, а не с именем; имя, которое уже принадлежит сессии, ничего не меняет и ничего не записывает
POST, DELETE /runs/{ref}/archive Архивирует сессию или возвращает её из архива. Без тела. 200 run, с archived_at, пока сессия в архиве. Архивация не останавливает и не удаляет сессию. Отметка принадлежит сессии, а не вызывающему: сессия архивирована для всех. GET /runs ею не сужается; каждый клиент сам исключает архивированные сессии из своего списка. Оба вызова идемпотентны: архивация уже архивированной сессии сохраняет её archived_at и ничего не записывает. Записывается в журнал аудита как sessions.run.archived и sessions.run.unarchived
POST /runs/{ref}/move Тело {provider_profile_ref}. Привязывает остановленную или завершившуюся сбоем сессию Claude Code к другому профилю того же инструмента и переносит её разговор. Ничего не запускает. 200 run
GET /runs/{ref}/handoff Сводка, с которой начиналась бы передача: summary, source_driver, turns, transcript_bytes. Только чтение, записывается в журнал аудита. Работающая сессия читается как есть; сессия, которая ещё не запустилась, отвечает 409
POST /runs/{ref}/handoff Тело {provider_profile_ref, summary?, name?}. Запускает новую сессию в этом профиле, связанную с данной. 201 run плюс summary_state (и first_turn, когда он не delivered); 202, пока запуск ожидает одобрения
GET /runs/{ref}/activity Что делает инструмент сессии Claude Code или Codex, читается из его собственной нативной записи при каждом запросе: agents, tasks (команды и фоновая работа), files (путь, added, removed, created), todos, skills, mcp_servers, model, context_tokens, обнуляемое context_window, когда его сообщает инструмент, и context_percent (процент для Claude Code, null, когда значение неизвестно), compactions и transcript (read, pending до того, как инструмент его записал, missing, когда он должен быть на месте). Агенты и задачи имеют состояние running, completed, failed, stopped или scheduled. Codex использует свой файл rollout, не запуская ещё один app-server; context_tokens описывают последний запрос, а не суммарное использование. Только чтение; записывается в журнал аудита один раз на читателя и сессию каждые 15 минут. Неподдерживаемый инструмент отвечает 422; сессия, которой выданы секреты хранилища (vault), учётные данные репозитория или управляемые учётные данные, отвечает 409, как и сессия, использовавшая токен реестра пакетов, когда она остановлена или работает после resume, который следует за запуском с таким токеном
GET /runs/{ref}/activity/agents/{agent} Транскрипт одного субагента Claude Code простыми ходами (role, text). Только чтение, записывается в журнал аудита. 404 для неизвестного агента. Codex сообщает состояние дочерних агентов в корневом ответе Activity; чтение транскриптов дочерних агентов не предлагается
GET /runs/{ref}/messages Сообщения сессии Claude Code или Codex, читаются при каждом запросе из собственного транскрипта инструмента, страницами: items (id, role user или assistant, at, first_line), total, next, transcript (read, pending, missing). По умолчанию только то, что отправил человек; role=all добавляет ответы инструмента. q оставляет сообщения, содержащие эту фразу в любом месте (без учёта регистра, не более 256 байт); at (RFC 3339) оставляет сообщения не раньше этого времени, так что первый элемент является якорем; order — asc (по умолчанию) или desc, limit — не более 200, а cursor — id, с которого продолжается страница (next); элементы всегда идут от старых к новым. id читает одно сообщение целиком (text и later_same — сколько более поздних сообщений того же отправителя повторяют его первую строку; фильтры не применяются, а total — число сообщений сессии). text=1 добавляет text к каждому элементу страницы с тем же пределом 64 KiB на сообщение, что и при чтении по id, и без later_same; текст, обрезанный на этом пределе, заканчивается на [...], а его элемент несёт clipped: true, в том числе при чтении по id; такая страница содержит не более 50 сообщений; чтобы скопировать весь разговор, следуйте next. id сообщения — его позиция среди сообщений сессии, и он не меняется по мере роста транскрипта. Только чтение; записывается в журнал аудита один раз на читателя, сессию и окно в 15 минут, как sessions.run.messages, а чтение с text=1 — как sessions.run.messages.text. Неподдерживаемый инструмент отвечает 422; сессия, которой выданы секреты хранилища (vault), учётные данные репозитория или управляемые учётные данные, отвечает 409; неизвестный id — 404; недопустимый параметр — 400
DELETE /runs/{ref} Требует sessions:run:admin. Удаляет запись освобождённой сессии. Неосвобождённая сессия отвечает 409 session must be cleaned before delete (state=…). Записывается в журнал аудита как sessions.run.deleted в транзакции удаления
GET /runs/{ref}/diff Ветка сессии worktree относительно её исходной точки: branch, base, head и изменённые files (path, status). Без worktree — 404
GET /runs/{ref}/diff/file?path= Текст одного пути на base и на head (original, modified, каждый не больше меньшего из max_read_bytes workspace и 64 КиБ)

Для вызовов Codex Code Mode, аргументы плана которых не сохраняются в rollout, Activity также читает последнее уведомление turn/plan/updated, уже полученное живым мостом. Перезагрузка в браузере использует ту же серверную сессию; для обновления никакой app-server не запускается. После того как живой дескриптор исчез, можно прочитать только данные, которые сохранил сам Codex.

Для Claude Code окно берётся из нативного поля результирующего кадра modelUsage[model].contextWindow, которое сохраняется при остановке и повторном подключении. Совпадающий однозначный отчёт задаёт context_percent как 100 × context_tokens / context_window; иначе оба поля равны null, а CLI и консоль показывают токены с пометкой о неизвестном окне. Новый запуск инструмента очищает предыдущий отчёт об окне.

Задачи workflow могут включать workflow: run_id, name, duration_ms, agents_total, agents_done, agents_failed и phases. Каждая фаза имеет index, title, необязательные detail и state и те же счётчики агентов. Счётчики описывают агентов, наблюдавшихся к настоящему моменту. Пока сессия жива, состояние фазы описывает наблюдаемых работающих или завершившихся сбоем агентов. Завершение агента не доказывает, что скрипт покинул свою фазу, поэтому оно не помечает фазу завершённой и не указывает текущий шаг скрипта. Завершённые состояния фаз задаёт итоговая сводка workflow.

Живые снимки workflow берутся из вывода system/task_progress Claude Code, общего с потоком attach. Завершённый workflows/<runId>.json инструмента заполняет итоговую сводку по правилам транскрипта о домашнем каталоге, ссылках и размере. Чтение сводки ограничено 8 МиБ на файл и 64 МиБ на запрос; более крупные нативные журналы или результаты делают сводку нечитаемой, сохраняя доступный живой прогресс. Нечитаемые сводки и пропуски в ограниченном живом буфере вносят вклад в unreadable.

Сессия продолжается в другой учётной записи одним из двух способов, и консоль, а также olivares session move / olivares session handoff предлагают оба. Перенос (move) передаёт сохранённый разговор сессии Claude Code в другой профиль того же инструмента, поэтому переносить можно только сессии Claude Code. Передача (handoff) запускает новую сессию из разговора сессии Claude Code, Codex, Gemini CLI или OpenCode.

Запуск несёт limit, когда его инструмент завершил последний ход на лимите: {kind, resets_at, account_ref}. kind — usage (исчерпан лимит тарифного плана учётной записи) или rate (провайдер ограничивает запросы). resets_at — RFC 3339; присутствует, когда инструмент сообщает, когда лимит снимется, и отсутствует в остальных случаях, а account_ref — профиль, под которым выполнялся ход. Claude Code сообщает факт в собственном результате (api_error: usage_limit_reached или HTTP 429), а время сброса — в своём rate_limit_event; Codex сообщает факт в неудавшемся ходе с типом usageLimitExceeded или rateLimitExceeded, а время сброса — в окнах своего account/rateLimits/updated; когда исчерпаны два окна, записывается более позднее время сброса, а время сброса более чем через год от текущего момента опускается. Журнал получает одно событие limit_reached, когда факт записан впервые; повторная встреча того же факта не добавляет ни одного. Следующий успешный ход очищает limit, как и перенос в другую учётную запись. Результат любого другого вида никогда его не задаёт.

POST /runs/{ref}/move сохраняет ту же сессию. Ему нужна сессия в состоянии stopped или failed, чей разговор находится в домашнем каталоге её учётной записи, и целевой профиль того же инструмента, который принял бы запуск под ним (активный, среда этого узла, авторизованный источник). Движок копирует этот один разговор — транскрипт и файлы его субагентов и результатов инструментов — в целевой домашний каталог, но никогда не копирует вход, настройку или другой разговор, и перепривязывает строку запуска, живую строку и журнал в одной транзакции. Запуск сохраняет свой run_ref и id разговора у провайдера; журнал получает событие moved, в деталях которого оба профиля названы по ссылке и указано число перенесённых файлов, а сессия, завершившаяся сбоем, сохраняет свою reason. Исходный домашний каталог только читается. Отказ ничего не записывает и удаляет то, что создал перенос:

  • 409 для работающей сессии, сессии, которой выданы секреты хранилища (vault), учётные данные репозитория, управляемые учётные данные или токен реестра пакетов (нельзя доказать, что то, что она вывела, их не содержит), строки, чей домашний каталог не принадлежит её профилю, id разговора, уже привязанного к другой сессии под целевым профилем, цели, в которой хранится другая версия разговора, цели другого инструмента или файла, изменившегося во время копирования (повторите);
  • 422 для ссылки, второго имени файла или специального файла внутри разговора, а также для сессии другого инструмента.

Копия того же разговора, оставленная в цели предыдущим переносом, заменяется более новой. Ничего не запускается: следующий POST /runs/{ref}/resume — обычный, поэтому к нему применяются политика, бюджеты и одобрения целевого профиля. Сессия, у которой ещё нет разговора, переносится без чего-либо для переноса и запускается заново в цели.

GET /runs/{ref}/handoff и POST /runs/{ref}/handoff продолжают работу в другом инструменте, где нативного resume нет. Они читают сохранённый разговор сессии Claude Code, Codex, Gemini CLI или OpenCode (сессия Grok отвечает 422). Сессия может быть в состоянии stopped, failed, running или idle; ещё не запустившаяся отвечает 409. Предварительный просмотр читает работающую сессию как есть. POST сначала останавливает работающую сессию так же, как POST /runs/{ref}/stop, и читает её разговор после завершения её инструмента; каждый отказ, которому остановка не нужна (целевой профиль, секреты хранилища (vault), учётные данные репозитория), наступает до неё, а отказ после неё сообщает, что сессия была остановлена и её можно возобновить. Codex читается из его rollout, Gemini CLI — из его журнала чата, а OpenCode — через его собственную команду opencode export, запущенную один раз и офлайн под профилем сессии. Предварительный просмотр создаётся из сохранённого разговора без модели, чтобы человек мог просмотреть и изменить его, и каждое его чтение записывается в журнал аудита как sessions.run.handoff_preview. POST запускает новую сессию в выбранном профиле, в том же workspace и по тому же шаблону, первым ходом которой становятся просмотренные summary (создаются, если отсутствуют) и путь к транскрипту, записанному в домашний каталог конфигурации целевого профиля под собственным именем. Транскрипт несёт сообщения целиком до 256 КиБ каждое, вызовы и результаты инструментов сокращены, и он сообщает, сколько записей не смог прочитать. Новый запуск сообщает handoff_of, а журнал оригинала получает событие handed_off. Ответ несёт summary_state:

summary_state Значение
delivered Первый ход дошёл до новой сессии.
not_delivered Он не дошёл. first_turn содержит текст для отправки.
unknown Отправка была предпринята, результат не подтверждён; проверьте, прежде чем снова отправлять first_turn.
waits_for_approval Запуск удерживается для человека (202); первый ход автоматически не отправляется.

first_turn присутствует, только когда состояние не delivered, потому что он называет путь вложения. Исходный разговор отклоняется с 409, если его сессии выданы секреты хранилища (vault), учётные данные репозитория, управляемые учётные данные или токен реестра пакетов, потому что передача отправляет его другому провайдеру, и с 422 при размере более 256 МиБ или когда в нём есть одна запись крупнее 32 МиБ.

POST /runs принимает необязательное логическое поле worktree. Если оно true и workspace_ref указывает зарегистрированный workspace, который является корневой папкой репозитория git, сессия работает в новом git worktree на новой ветке этого репозитория (workspace_path — worktree, а запуск сообщает worktree_branch). Отсутствие поля, null или false сохраняют прежнее поведение. Движок возвращает 422 для workspace, который не является git worktree или не является корневой папкой репозитория, не имеет коммита, доступен только для чтения или имеет папки только для чтения, чья конфигурация git задаёт фильтр или включает файл; для изоляции, отличной от native, и для запуска без workspace; и 503, если на узле нет каталога worktree. POST /runs/{ref}/resume возвращается в тот же worktree.

POST /runs/{ref}/cleanup принимает необязательное тело {"discard_worktree": true}; без тела вызов работает как раньше, и сервер по-прежнему принимает любое тело: подтверждением является только явное true. Сессия с worktree освобождается, если её ветка слита в текущую ветку workspace, worktree находится на этой ветке и не имеет незакоммиченных файлов; иначе вызов отклоняется с 409 (неслитая работа, отсоединённый HEAD, worktree, недоступный узлу), а запуск остаётся остановленным. Вызов можно повторить с discard_worktree, чтобы всё равно удалить worktree и ветку, либо — для worktree, недоступного узлу, — освободить сессию и оставить worktree на месте. Событие журнала cleaned сообщает, что произошло с worktree, и вершину ветки.

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

  • PUT /workspaces/{ref}/setup-command принимает {"command":"npm ci"}. Точный текст UTF-8 сохраняется, включая пробельные символы; не более 8192 байт, без NUL. Пустая строка очищает команду. Требует администрирования workspace.
  • GET /workspaces/{ref} возвращает setup_command, setup_command_sha256 и, после одобрения, setup_approval с sha256, actor и at. setup_approved равно true только пока это одобрение покрывает текущий текст. После правки setup_approval остаётся как свидетельство, поэтому проверяйте setup_approved, а не наличие setup_approval.
  • POST /workspaces/{ref}/setup-command/approve принимает {"sha256":"<reviewed hash>"}. Требует администрирования workspace и отклоняет идентичность агента. Хеш должен совпадать с текущим сохранённым текстом; параллельная правка возвращает 409. Одобрение и его запись аудита sessions.workspace.approve-setup фиксируются вместе.

Запуск worktree возвращает 409, если у команды нет соответствующего одобрения, до создания worktree. Его сообщение называет команду и шаг одобрения. Изменение одного символа, включая пробельный, требует нового одобрения. Последнее одобрение остаётся как свидетельство; чтобы применяться, его хеш должен равняться setup_command_sha256, поэтому возврат команды к тексту, который был одобрен раньше, снова применяет то одобрение. Любой, кто может читать папку, может прочитать команду, поэтому не помещайте в неё секреты. POST /runs с "no_setup":true пропускает настройку только для этого запуска. Передача сессии, у которой есть worktree, запускает новый worktree и требует такого же одобрения; варианта пропуска у неё нет. Остальные запуски и resume сохраняют своё прежнее поведение.

В CLI задайте команду так: olivares agent workspace setup <ref> --command 'npm ci', прочитайте её так: olivares agent workspace setup <ref>, а показанный хеш одобрите так: olivares agent workspace approve-setup <ref> --sha256 <hash>. olivares session start --worktree --no-setup один раз пропускает настройку.

С worktree вызов POST /runs также принимает необязательный worktree_from: полный id коммита (40 или 64 строчных шестнадцатеричных цифры) или локальную ветку репозитория workspace. Новый worktree и его собственная новая ветка начинаются там вместо текущего коммита workspace; названная ветка и checkout workspace не перемещаются. Так получатель открывает работу, указанную в передаче, содержимое которой может иметь необязательные branch и sha. Git разрешает значение в полный id коммита; используется только этот id. Движок возвращает 422 до создания чего-либо для коммита, которого нет в репозитории, ветки, которой в нём нет, выражения ревизии, диапазона, опции, а также worktree_from без worktree. Если поле отсутствует, запуск, как и прежде, начинается от текущего коммита workspace.

GET /runs/{ref}/diff перечисляет пути, изменённые веткой worktree сессии с момента отделения от текущего коммита workspace (base — их база слияния, head — вершина ветки, оба полные id коммитов; максимум 200 путей, truncated сообщает о превышении), а GET /runs/{ref}/diff/file?path= возвращает текст одного пути на base и на head, пустой там, где файла нет. Он читает закоммиченные объекты git через низкоуровневые команды, поэтому незакоммиченные изменения в него не попадают; требуется то же разрешение, что и на чтение запуска. Он соблюдает файловые правила workspace: путь вне разрешённых подпутей не перечисляется и возвращает 404; запрещающая DLP-политика workspace даёт 403 (чтение аудируется, как чтение файла workspace), а файл больше 16 МиБ — 413. Сессия без worktree и запуск другого тенанта возвращают 404; исчезнувшая ветка или отсутствие общей истории с workspace — 409. worktree_from также возвращает 422 для id коммита, на который не указывает ни одна ветка, тег или удалённая ветка репозитория.

Повторное подключение после оборванного attach — GET …/attach?from={last+1} к тому же живому процессу. После потери процесса attach сообщает, что сессия не жива. Resume начинает новое поколение. Reconnect не выдумывает процесс-замену (SDD R04).

Конфигурация агента, которую несёт репозиторий

Заголовок раздела «Конфигурация агента, которую несёт репозиторий»

Клонированный репозиторий может нести конфигурацию агента, которая запускает программу или перенаправляет трафик. Движок считает её недоверенным вводом, когда сессия запускается в папке. Он читает перечисленные ниже файлы, никогда не выполняет их и собирает только перечисленные ключи. Пустое значение ({}, [], "", false, null) ничего не настраивает и не помечается.

Инструмент Файл Помечается
Claude Code settings.json и settings.local.json в папке .claude hooks, apiKeyHelper, statusLine, mcpServers, enableAllProjectMcpServers, enabledMcpjsonServers, awsAuthRefresh, awsCredentialExport, otelHeadersHelper, fileSuggestion, enabledPlugins, extraKnownMarketplaces и записи env с именем из последней строки
Claude Code .mcp.json mcpServers
Codex .codex/config.toml hooks, notify, mcp_servers, model_providers, otel, любой *_base_url верхнего уровня и записи shell_environment_policy.set с именем из последней строки; те же ключи в profiles.<name>
Gemini CLI .gemini/settings.json hooks, mcpServers, toolDiscoveryCommand, toolCallCommand, proxy, tools.discoveryCommand, tools.callCommand, mcp.serverCommand, telemetry.otlpEndpoint
Gemini CLI .gemini/.env, .env записи с именем из последней строки
Имена окружения NODE_OPTIONS, NODE_EXTRA_CA_CERTS, NODE_TLS_REJECT_UNAUTHORIZED, LD_PRELOAD, LD_LIBRARY_PATH, LD_AUDIT, DYLD_INSERT_LIBRARIES, BASH_ENV, PATH, PYTHONPATH, GIT_SSH_COMMAND, GIT_EXTERNAL_DIFF, SSL_CERT_FILE, CLAUDE_CODE_SHELL_PREFIX, ANTHROPIC_CUSTOM_HEADERS, AWS_ENDPOINT_URL* и любое имя, оканчивающееся на _BASE_URL, _API_BASE, _ENDPOINT или _PROXY (NO_PROXY только сужает прокси и не помечается)

Файл, который существует, но не читается в своём формате (недопустимый JSON или TOML, больше 1 МиБ, вложенность глубже 64 уровней, не обычный файл), считается помеченным, потому что его безопасность нельзя показать. В TOML каждый сегмент точечного ключа или заголовка таблицы — один уровень, как в разобранном документе, и прибавляется к скобкам вокруг него: заголовок из 30 сегментов над 35 вложенными встроенными таблицами — это 65 уровней. Когда в файле есть заголовок [[array]], сегменты заголовка считаются дважды, потому что каждый может называть массив и его элемент. Файл слишком большого размера хешируется целиком при каждой проверке. Папка, в которой ничего не помечено, запускается как прежде.

  • GET /workspaces/{ref}/project-config перечисляет помеченные ключи по файлам с их значениями (пароль внутри URL маскируется) и sha256 ровно этой помеченной части по файлам всех трёх инструментов, плюс approved и последнее approval. Он читает саму папку; worktree, запущенный от другого коммита, может нести другие отслеживаемые файлы, и его отказ называет собственный хеш.
  • POST /workspaces/{ref}/project-config/approve принимает {"sha256":"<reviewed hash>"}, требует администрирования workspace и отклоняет идентичность агента. Одобрение сохраняет, кто, когда и какой хеш, вместе с записью аудита sessions.workspace.approve-project-config в той же транзакции.

Запуск или resume инструмента, который читает помеченный файл, возвращает 409, если сохранённое одобрение не равно текущему хешу. Изменение одного символа помеченного значения либо добавление или удаление помеченного ключа требует нового одобрения; изменение ключей, которые не помечаются, — нет. Варианта пропуска проверки нет.

Сессия Claude Code, несущая hook движка, запускается с --setting-sources ""; в Claude Code 2.1.299 такая сессия не загружает ни файл настроек проекта или локальный, ни проектный .mcp.json, поэтому такой запуск не отклоняется. Запуск Claude Code без hook движка (удалённое управление или движок без эндпоинта hook) читает эти файлы и проверяется. Codex учитывает .codex/config.toml только для проекта, которому доверяет домашний каталог его учётной записи, и игнорирует файл недоверенного проекта; движок не может спросить инструмент, поэтому проверяет этот файл, и человек одобряет его один раз. Gemini CLI 0.64.0, запущенный так, как его запускает движок (gemini --acp), игнорирует .gemini/settings.json и .gemini/.env папки, которой не доверяет его домашний каталог учётной записи, а в доверенной папке выполняет tools.discoveryCommand, hooks и команды mcpServers и берёт базовый URL из .gemini/.env; движок проверяет эти файлы по той же причине. Он также загружает файлы родительских папок, которые эта проверка не читает.

В CLI используйте olivares agent workspace project-config <ref>, чтобы прочитать это, и olivares agent workspace approve-project-config <ref> --sha256 <hash>, чтобы одобрить.

Каждая официальная CLI запускается на том транспорте, который нужен её собственной форме operate; какой именно, объявляет cliruntime.LaunchTransport. Сегодня все три формы — протоколы поверх stdio, поэтому корень композиции подключает sessions.NewProcRunner(): stdin, stdout и stderr — каналы и остаются раздельными потоками.

Claude Code отклоняет терминал на stdin. Форма --print со stream-json отвечает Error: Input must be provided either through stdin or as a prompt argument when using --print и выходит с кодом 1, не выдав ни одного кадра протокола. Сервер приложений Codex и stdio-агент Grok говорят по JSON-RPC через те же потоки. Терминал нужен интерактивной форме; sessions.NewPTYRunner() остаётся доступен для неё в Linux, с stdin/stdout на сыром локальном PTY и stderr на канале. Ни один из них не запускает изоляцию container или sandbox. Хост с podman или Docker добавляет контейнерный раннер для isolation=container в stdio-форме; sandbox по-прежнему отклоняется (см. Топология 4).

Контракт драйвера находится в modules/sessions/cliruntime. Виды: claude, codex, grok. Соответствие всегда проверяется против внутрипроцессного fake и локального пира на обоих транспортах. Если claude / codex / grok есть в PATH, отдельный набор тестов прогоняет весь контракт на настоящем двоичном файле — запуск, attach, ввод, вывод, повторное подключение, остановка, resume — и не отправляет ни одного хода модели: каждое рукопожатие является протокольным, а каждый запуск получает свежий HOME и свой каталог конфигурации.