команды · флаги · коды

Справочник CLI

Полная поверхность reviewgate: что можно запросить, что вернётся и что делать с каждой ошибкой. Если вы ещё не поставили бинарь и не выбрали, откуда берётся доступ к модели — начните с CLI, хук и MCP, там путь по шагам.

справка есть внутриКоманды, флаги, коды выхода и коды ошибок бинарь расскажет сам — без сети и без сайта. Здесь то же самое плюс то, что в терминал не влезает: схема отчёта, рецепты для CI и границы. В терминале быстрее reviewgate help.
язык выводаСам инструмент говорит по-английски: справка, ошибки аргументов и описания MCP-инструментов одноязычны — их читают терминал и ИИ-агент, а печатаются они раньше, чем известен репозиторий. Язык отчёта о ревью — другое дело: его задаёт language в .reviewgate/config.yml проекта, как и у бота. Эта страница переведена, а команды и коды в обеих локалях одни и те же.
терминал
reviewgate help              # overview: commands, flags, exit codes
reviewgate help review       # one command in detail
reviewgate review --help     # the same, if you already started typing
reviewgate help --json       # machine form (reviewgate.help/v1)
Тема справкиО чём
reviewgate help initчто и где создаёт init и почему существующие файлы не трогаются
reviewgate help migrateперенос конфигурации 1.x на канон 2.0: что мигрирует и как применить
reviewgate help reviewобласть ревью, глубина, порог, что читается из рабочей копии
reviewgate help rulesстандарты команды так, как их видит движок
reviewgate help doctorчто проверяется и что значит каждый исход
reviewgate help mcpинструменты для агента и подключение MCP-клиента
reviewgate help agent-setupинструкция ДЛЯ АГЕНТА: покажите ему вывод, и он настроит свою среду сам
reviewgate help serverревью без личного ключа LLM, через бот команды
reviewgate help configдомашний конфиг: все ключи, приоритет, границы
reviewgate help hookгейт до git push: событие, порог, диалекты ответа
reviewgate help errorsкоды ошибок и лечение каждого

Команды

КомандаЧто делает
reviewgate reviewПрогон ревью. Команда по умолчанию: без аргументов запускается именно она. Единственная команда, которая тратит токены.
reviewgate rulesСтандарты команды: пресет стека, правила из config.yml, порог гейта, ignore. Модель не вызывается — бесплатно. Отдельно сообщает, применилась ли политика вообще: нечитаемый config.yml не выдаётся за «правил нет».
reviewgate doctorСамодиагностика рабочего места: git, репозиторий, домашний конфиг и права на него, схема переменных, доступ к серверу ревью либо готовность LLM — с живым опросом endpoint‑а, без расхода токенов. Проверяется та дорога, по которой поедет прогон: с --local — локальная.
reviewgate mcpMCP-сервер на stdio: агент зовёт ревью и правила сам. Ничего не пишет в репозиторий.
reviewgate initСоздаёт недостающие скелеты конфигов: в репозитории — .reviewgate/config.yml в корне (язык, пресет по манифестам, severity_gate: off, закомментированные примеры правил) плюс личный конфиг; вне репозитория — только личный, целиком в комментариях и с правами 600 (Windows режим не хранит). Существующие файлы не трогаются, модель не зовётся, --force нет. --lang ru|en задаёт язык шаблонов; без флага init спросит в живом терминале (но не с --json и не с --quiet), а вне терминала возьмёт en.
reviewgate migrateПеренос конфигурации 1.x на канон 2.0: config.yml репозитория, личный конфиг и .env-файлы. По умолчанию — предпросмотр; --write применяет, оставляя рядом бэкап <файл>.bak. Секреты не печатаются и не трогаются; комментарии YAML сохраняются.
reviewgate versionВерсия движка ревью одной строкой.
reviewgate helpВстроенная справка целиком либо по теме.

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

Все флаги

ФлагЧто делает
--stagedревьюить только то, что добавлено в индекс (git add)
--refs base..headчто уйдёт в MR/PR: дифф от merge-base
--fullгенератор + независимый судья. По умолчанию
--fastодин проход генератора: дешевле, находки не отсужены
--jsonмашинный отчёт в stdout; при сбое — машинный объект ошибки
--quietбез прогресса в stderr; сообщения об ошибках остаются
--fail-on levelпорог этого запуска: blocker|critical|major|minor|info|off
--config pathдругой файл политики вместо .reviewgate/config.yml
--localсчитать своим ключом, даже когда настроен сервер ревью; doctor с этим флагом проверяет локальный путь, а не сервер
--team-llmигнорировать схему LLM домашнего конфига и прогнать ролями команды (doctor тоже); личные env-значения по-прежнему действуют там, где команда молчит
--hook-stdinрежим хука: событие раннера читается со stdin
--hook-format cc|exitдиалект ответа хука: cc — структура для Claude Code, exit — решение кодом выхода
--writemigrate: применить правки (по умолчанию — предпросмотр); бэкап кладётся рядом
--lang ru|eninit: язык создаваемых конфигов — ключа language: и комментариев шаблона; без флага init спросит в живом терминале (но не с --json и не с --quiet), а вне терминала возьмёт en
--help, -hсправка целиком либо по теме; с --json — машинно
--version, -Vверсия движка ревью

Выключатели принимают --флаг, --флаг=true и --флаг=false; флаги со значением — --флаг значение и --флаг=значение. Помните, что токен без -- считается значением предыдущего флага: команду ставьте первой (reviewgate review --json, а не reviewgate --json review).

Что ревьюить

Три области, взаимоисключающие. Указать две сразу — ошибка: молча выбрав одну, CLI отревьюил бы не то, что вы просили.

терминал
reviewgate review                     # uncommitted changes, new files included
reviewgate review --staged            # the index only (git add)
reviewgate review --refs main..HEAD   # what the pull request will contain
reviewgate review --refs origin/main  # head defaults to HEAD
ОбластьЧто попадает в ревью
по умолчаниювсё незакоммиченное относительно HEAD, включая новые файлы, ещё не добавленные в индекс — этим область отличается от git diff. Главный режим в цикле работы
--stagedтолько то, что добавлено git add — ревью ровно того, что уйдёт в коммит
--refs base..headдифф от merge-base, то есть «что уйдёт в MR/PR», а не разница двух вершин. Форма base...head значит то же. head без указания — HEAD
откуда читается код, а откуда правилаКод берётся с ревизии ревьюируемого изменения — судья видит ровно то, что ревьюит. А политика (.reviewgate/config.yml) — всегда из рабочей копии, даже при --refs и --staged: правку правил видно сразу, не коммитя её. Если рабочая копия правил расходится с ревизией, отчёт говорит об этом прямо.

В любой области удаления файлов и чистые переименования не ревьюятся — в них нечего проверять. Бинарные файлы пропускаются целиком.

Если в области не осталось ничего — дерево чистое, диапазон без новых коммитов, правки только в файлах под ignoreмодель не вызывается вовсе: отчёт честно пустой, код возврата 0, в usage.calls ноль записей. Это штатный исход в цикле агента и в хуке, и платить за него не нужно.

Глубина и цена

терминал
reviewgate review            # generator plus judge (the default)
reviewgate review --fast     # one pass: cheaper and faster
РежимЧто происходит
--full
по умолчанию
генератор ищет, независимый судья сверяет находки с целыми файлами и отбрасывает ложные. На командной схеме — тот же вердикт, что даст бот в merge request; при объявленной домашней схеме LLM глубина ваша, и вердикт — не бота
--fastодин проход. Дешевле и быстрее, но находки не отсужены — уместно в цикле правок, не для решения «мержить ли»

Судья из воздуха не берётся: он задаётся панелью llm.judges в конфиге репозитория либо LLM_JUDGES в личном окружении. Если судьи нет нигде, --full фактически проходит как --fast — и отчёт говорит об этом notice'ом, чтобы «полный прогон» не оказался словом без содержания. В режиме сервера ревью моделями распоряжается администратор бота.

Порог, вердикт и коды выхода

терминал
reviewgate review --fail-on major   # a threshold stricter than the team policy
reviewgate review --fail-on off     # fail nothing, just show
reviewgate review; echo "exit=$?"   # 0 clean · 2 threshold exceeded · 1 failure

Без --fail-on берётся severity_gate из конфига команды. Флаг меняет порог только этого запуска: ни политику команды, ни гейт бота на MR/PR он не трогает — у бота своё решение, и локальный флаг им управлять не может.

КодЗначение
0находок выше порога нет
2порог превышен — гейт не пройден
1сбой; при --json объект ошибки уходит в stdout

Уровни от строгого к мягкому: blocker, critical, major, minor, info — плюс off, чтобы не ронять ничего. Что означает каждый — на странице конфигурации.

частая неожиданность: всегда 0Продуктовый дефолт — severity_gate: off: бот не блокирует merge из коробки. Тот же дефолт действует и здесь, поэтому прогон вернёт 0 при любых находках, пока порог не задан. Если вы строите на коде возврата гейт — указывайте --fail-on явно либо включите severity_gate в политике команды.

Пока модель думает

Полный прогон — это минуты: генератор, за ним независимый судья, а при ансамбле ещё и арбитр. Чтобы ожидание не выглядело зависшим процессом, CLI показывает, на каком именно вызове стоит прогон и сколько он уже идёт — ⠙ Judge claude-opus-5 · 1:47. Индикатор пишется в stderr и только в интерактивном терминале: в конвейере и в CI вместо анимации печатается обычная строка → Judge claude-opus-5: waiting for a response…, поэтому лог не засоряется управляющими символами. --quiet убирает и то, и другое.

Машинный вывод

С --json в stdout уходит только отчёт, всё остальное — прогресс, предупреждения, логи — в stderr. Поэтому вывод можно передавать по конвейеру, не фильтруя. --quiet убирает и прогресс.

терминал
# the verdict in one line
reviewgate review --json --quiet | jq -r .verdict.gate

# blocking findings only, file and line
reviewgate review --json --quiet \
  | jq -r '.findings[] | select(.severity=="blocker" or .severity=="critical")
           | "\(.file):\(.line) \(.title)"'

# what the run cost
reviewgate review --json --quiet | jq '.usage.cost, .usage.calls'

Полезные поля отчёта reviewgate.report/v1:

ПолеЧто внутри
schemaидентификатор контракта: reviewgate.report/v1 — по нему потребитель узнаёт формат
engineVersionверсия движка, которым сделан прогон
run.llmSourcehome | team — чьей схемой LLM шёл прогон; home не предсказывает ревью бота. В отчётах, собранных сервером ревью, поля нет (там всегда team)
summaryсвязный текст прогона; секреты уже замаскированы конвейером
verdict.gatepass · fail · off — на командной схеме то же решение, что примет бот в merge request
verdict.failOnфактический порог прогона: --fail-on либо severity_gate
verdict.countsсколько находок каждого уровня (без заглушённых)
findings[]file, line, endLine, severity, title, body, ruleId
findings[].suggestedCodeготовая замена строк; committable: true — применяется как есть
findings[].judgeвердикт судьи: confirmed либо downgraded с причиной; null в режиме --fast
findings[].mutedниже min_severity: в списке есть, в гейт не входит
dropped[]находки, отклонённые судьёй, с причиной — прозрачность прогона
questions[]❓ неблокирующие вопросы автору (questions: true): file, line, text — инженерные сомнения, переквалифицированные из отказов судьи; на verdict.gate не влияют
run.scope, run.modeчто и как ревьюили: uncommitted|staged|refs, full|fast
run.refsбаза и вершина сравнения при режиме refs; null в остальных режимах
run.filesReviewed, run.durationMsсколько файлов вошло в прогон и сколько он занял
run.configпуть и факт находки config.yml, пресет, число правил, notices
run.partialпочему покрытие неполное: ignored_files, marker_files, context_budget, empty_diffs, scope_reduced, binary_files; в markedFiles — пути, снятые маркером внутри файла, вместе с причинами
usage.calls[]по вызову: роль (generator|validator|arbiter|extra:<имя>), модель, токены; failed: true — вызов был, но результата не дал, и токены его неизвестны; retries: N — вызов повторён после обрыва стрима (OpenAI-совместимые провайдеры), токены оборванной попытки не учтены
usage.costсумма и валюта либо null, если прайс модели не задан
diagnosticsготовый markdown-блок 🔬 (тот же, что в сводке MR/PR): вызовы, решения судей, бюджет; null — диагностика выключена
budgetсрез потолка трат: barrier (none·approaching·exceeded·stop), stopped и расход/лимит по бэкендам; null — лимиты не заданы
licenseплан, организация и причина, если ключ не применился; donateUrl — ссылка «поддержать проект» (только community, иначе null)
совместимостьПеречисления в отчёте открытые: незнакомое значение severity, роли вызова или причины неполноты потребитель обязан пережить, а не падать на нём. Имя схемы сменится только вместе с major-версией.

Ошибки и что с ними делать

При --json сбой тоже машинный: разбирайте code, а не текст сообщения — формулировки мы уточняем, коды нет.

терминал
$ reviewgate review --json
{
  "schema": "reviewgate.error/v1",
  "code": "server_forbidden",
  "message": "no access to project group/app: a Reporter role or above is required"
}
КодЛечение
invalid_argsопечатка в команде или флаге — сверьтесь со справкой
not_a_repoзапускать внутри git-репозитория
git_missingустановить git и проверить PATH
revision_not_foundревизия из --refs не найдена — опечатка либо поверхностный клон (GIT_DEPTH: 0)
config_not_foundфайл из --config не найден — проверьте путь
config_unreadableдомашний конфиг есть, но не читается — права (chmod 600) либо путь ведёт не к файлу
home_llm_configдомашний конфиг объявляет схему LLM без генераторов — добавьте llm.generators в ~/.config/reviewgate/config.yml, уберите ролевые ключи либо разово обойдите через --team-llm
server_unreachableнет сети до сервера ревью — VPN, адрес, доступность бота
server_forbiddenнет доступа: токен GitLab, членство в группе, права на репо
server_busyвсе слоты CLI заняты — повторить позже
server_disabledсервер не выполняет прогоны CLI вовсе — администратору нужен REVIEW_CONCURRENCY ≥ 2; повторять запрос бесполезно
quota_exceededлимит инсталляции исчерпан — к администратору бота
llm_unavailableключ провайдера не задан, отозван или нет баланса
llm_context_overflowизменение больше окна модели — сузить область или ignore
llm_output_truncatedответ обрезан по max_tokens — уменьшить область
llm_max_tokens_configLLM_MAX_TOKENS выше потолка модели — уменьшить
llm_refusedмодель отказалась отвечать — повторить или сменить модель
llm_overloadedпровайдер перегружен — повторить позже
llm_networkсеть или прокси до провайдера — проверить LLM_PROXY
llm_endpointendpoint или модель не найдены — проверить LLM_BASE_URL (нужен /v1) и LLM_MODEL
write_failedне удалось записать файл (migrate --write, init) — бэкап уже существует либо нет прав
internalнепредусмотренный сбой — текст ошибки в сообщении

Первый шаг при любом непонятном сбое — reviewgate doctor: он отвечает на вопрос «моя машина или сервер» и называет источник каждого значения. Его отчёт идёт в stderr и машинного формата не имеет — для скриптов пригоден только код возврата (0 — можно работать), а с --quiet он не печатает ничего. Разбор частых случаев на стороне бота — решение проблем.

В usage.calls[] у вызова может появиться truncatedRetry: ответ модели упёрся в потолок LLM_MAX_TOKENS, и запрос был повторён с пониженным усилием рассуждений. Ошибки нет — спасение сработало, — но знать об этом стоит: анализ шёл мельче заказанного, а токены в этой строке суммируют обе попытки, то есть прогон стоил заметно дороже обычного. Причина и лечение дублируются строкой в run.config.notices.

В те же run.config.notices попадает всё, что не применилось из личного конфига (~/.config/reviewgate/config.yml): ключ с опечаткой, неверно записанный список ролей, api_key_command, вернувшая пустоту. Такие строки начинаются с personal config и называют файл. Они идут и в stderr, но надёжный канал — отчёт: под --quiet stderr нет вовсе, а агент, который ведёт CLI, читает JSON. Зелёный вердикт с такой строкой значит, что прогон выполнен не тем, что вы настроили, — прочтите её, прежде чем доверять результату.

Готовность модели проверяется не по наличию ключа, а по тому, чем реально поедет прогон: локальной модели ключ не нужен, а OpenAI-совместимому провайдеру обязателен LLM_BASE_URL — без него запросу некуда идти. Затем endpoint опрашивается живьём (список моделей, токены не тратятся): так видно отозванный ключ, опечатку в адресе и мёртвый прокси. Endpoint, не отвечающий на этот метод, — предупреждение, а не отказ: он необязателен. Значки в отчёте: пройдено, ⚠️ предупреждение (работать можно), блокирует, не проверялось из-за проваленной предпосылки.

в режиме сервера ревьюСбой, случившийся на стороне бота, приезжает под кодом internal, а точное имя (например llm_unavailable) указано в тексте сообщения в скобках: код мы за сервер не придумываем. Отличить «сервер недоступен» от «сервер посчитал и не смог» это не мешает — первое приходит своим кодом server_unreachable.

Переменные окружения

ПеременнаяНазначение
REVIEWGATE_SERVERадрес сервера ревью; пусто — считаем своим ключом
REVIEWGATE_GITLAB_TOKENличный токен GitLab для сервера ревью
REVIEWGATE_CONFIGпуть домашнего конфига вместо стандартного
REVIEWGATE_LICENSEключ лицензии
LLM_API_KEYключ провайдера; принимается и ANTHROPIC_API_KEY
LLM_PROVIDERanthropic (по умолчанию) · yandex · ollama · openai · openrouter · vllm
LLM_MODELмодель генератора
LLM_JUDGESyour default judge panel (`[backend:]model[@effort]`, comma-separated, at most 2); it applies when llm.judges is not set in the repository config
LLM_BUDGET_TOKENSпотолок трат прогона для основного провайдера (токены; барьеры 80/100/300 фиксированные); для бэкендов — LLM_BACKEND_<ИМЯ>_BUDGET_TOKENS
LLM_BASE_URLendpoint корпоративного шлюза или локальной модели
LLM_FOLDER_IDкаталог Yandex Cloud — обязателен при provider yandex
LLM_PROXYпрокси до провайдера (CONNECT-туннель)

Полный справочник переменных бота — на странице установки; выбор модели и локальная LLM — LLM и свой ключ. Переменные LLM_* у CLI и у бота называются одинаково — настройка провайдера переносится между ними как есть. Остальные переменные бота (GitLab, Redis, база) для CLI смысла не имеют.

Остальные переменные LLM_* (LLM_MAX_TOKENS, LLM_GENERATORS, LLM_ARBITER, LLM_DIFF_CHAR_BUDGET и прочие) движок читает те же, что у бота — их справочник на странице установки. Обратите внимание: сам прогон схему переменных не проверяет — опечатку в имени или значении покажет только reviewgate doctor.

Домашний конфиг

Чтобы не задавать переменные в каждой сессии терминала, положите их в файл. Путь: $REVIEWGATE_CONFIG, иначе ~/.config/reviewgate/config.yml ($XDG_CONFIG_HOME уважается), на Windows — %APPDATA%\reviewgate\config.yml.

~/.config/reviewgate/config.yml
server:                       # needed if the team bot computes the review
  url: https://bot.your-company.com
  gitlab_token: glpat-...
  # gitlab_token_command: pass show work/gitlab

llm:                          # needed if you compute with your own key
  provider: anthropic
  api_key: sk-...
  # api_key_command: op read op://dev/anthropic/credential
  model: claude-sonnet-5
  # Your own schema for local runs. Declaring generators/judges/arbiter here
  # replaces the TEAM schema entirely: it is taken as a whole and must carry
  # generators. Such a run does not predict the bot review (--team-llm does).
  # A role without backend: runs on the provider above — name a backend from
  # llm.backends to use another vendor.
  # generators:
  #   - model: claude-haiku-4-5
  # judges:
  #   - model: claude-sonnet-5
  # max_tokens: 64000        # answer ceiling; reasoning models (DeepSeek v4) spend it on thinking too
  #                          #   (64000 stays within the Sonnet 5 ceiling)
  # effort: medium           # reasoning depth: low | medium | high | xhigh | max
  # timeout_ms: 600000       # timeout of a single request
  # json_mode: none          # DeepSeek as the main provider: it rejects json_schema, and json_object
  #                          #   returns an empty content on a real review run (a long prompt) —
  #                          #   the prompt and the parser hold the shape
  # base_url: https://llm.your-company.com/v1
  # proxy: http://proxy.your-company.com:3128
  # backends:                 # a second vendor for the ensemble
  #   deepseek:
  #     provider: openai
  #     api_key: sk-...
  #     # api_key_command: pass show work/deepseek
  #     base_url: https://api.deepseek.com/v1
  #     model: deepseek-v4-pro
  #     json_mode: none         # rejects json_schema; json_object returns empty content on long prompts
  #     max_tokens: 64000       # the reasoning eats the same ceiling as the answer

license: eyJhbGciOi...

Окружение процесса побеждает файл в значениях связи и исполнения (ключ, base_url, max_tokens…). Так CI и раннер агента управляют настройками без правки файлов на машине, а LLM_API_KEY=... reviewgate review остаётся рабочим обходом, если файл устарел. Единственное исключение — домашняя схема LLM ниже: ролевые ключи ЭТОГО файла побеждают всё, а ролевые переменные (LLM_GENERATORS, LLM_JUDGES, LLM_ARBITER) остаются на обычном месте — ниже конфига репозитория.

Своя схема LLM для локальных прогонов

Объявленные llm.generators / llm.judges / llm.arbiter в домашнем конфиге задают вашу схему для локальных прогонов — дешёвую проверку в моменте, пока merge request получает дорогую. Схема замещает роли команды целиком: она берётся из одного источника, поэтому один только judges — это отказ прогона (home_llm_config), а не заимствование генераторов у команды: склейка, которую никто не задумывал, хуже отказа. Такой прогон не предсказывает ревью бота, и отчёт говорит об этом в run.config.notices и в run.llmSource (home | team). Прогнать ровно как бот — --team-llm. Схема действует только локально: прогон через сервер ревью идёт командной; политика (правила, ignore, пороги) всегда остаётся за репозиторием.

Любой секрет можно не хранить в открытом виде: вместо api_key и gitlab_token укажите api_key_command / gitlab_token_command — команду вашего менеджера паролей. Это работает и для ключей дополнительных бэкендов в llm.backends: запрет plaintext-секретов касается всех ключей, а не только ключа основного вендора. Её вывод нигде не сохраняется и в логи не попадает. Если файл доступен не только вам, doctor и прогон скажут об этом: в нём секреты, нужен chmod 600.

Отсутствие файла — норма, нечитаемость — нет. Если файла нет, настройки берутся из окружения и это штатный случай. Но когда файл существует, а прочитать его не удаётся (права, по пути каталог, неразвёрнутая ~ в REVIEWGATE_CONFIG — в конфигах MCP-клиентов её никто не раскрывает), прогон останавливается с кодом config_unreadable. Молча продолжить нельзя: в файле мог быть адрес сервера ревью и токен, и работа ушла бы на ваш личный ключ вместо ключа инсталляции — незаметно до самого счёта.

Две мелочи, на которых легко потерять время. — настройки просто не применяются, а предупреждение уходит в stderr; если «настройки не подхватились», начните с reviewgate doctor. И имя дополнительного бэкенда в llm.backends должно быть из латиницы и цифр без подчёркиваний — иначе бэкенд пропускается с предупреждением.

чего в этом файле не будет никогдаПолитики ревью: правил, ignore, пресета, severity_gate, min_severity. Политика командная и версионируется вместе с кодом. Пустить её в домашний файл — значит дать каждому разработчику свою, и локальный прогон перестанет предсказывать вердикт бота. Причём незаметно: у вас зелено, бот на MR/PR роняет гейт, и виноватым выглядит бот. Правило одной строкой: домашний конфиг задаёт, куда ходить, но не что считать проблемой. Написанное здесь правило или порог не подействуют — и reviewgate doctor скажет об этом прямо, а не оставит гадать.

Там же назовут и опечатки: нераспознанный ключ, и особенно server: https://…, записанный одним значением вместо секции с url:. Последнее стоит денег: сервер команды в таком виде не настраивается, и прогон уходит считать на вашем личном ключе, хотя вы рассчитывали на ключ компании.

Кто кого перебивает

Настройка может прийти из четырёх мест: флаги запуска, окружение процесса, ваш домашний конфиг и .reviewgate/config.yml репозитория. Правило простое: политику задаёт репозиторий, связь и ключи — вы, а флаг меняет только текущий запуск.

что настраиваемоткуда можнокто выигрывает
правила, ignore, пресет, min_severityтолько .reviewgate/config.ymlрепозиторий — больше неоткуда
severity_gate (порог вердикта)репозиторий, --fail-onфлаг — но только для этого запуска; политику команды он не меняет
модель, судья, усилиерепозиторий, окружение, домашний конфигрепозиторий; если команда не зафиксировала — окружение, затем ваш файл
ключ, base_url, прокси, лицензияокружение, домашний конфигокружение, затем ваш файл. Из репозитория — никогда
адрес сервера ревью и токенокружение, домашний конфиг, --local--local выключает сервер; иначе окружение, затем ваш файл
область и глубина (--staged, --refs, --fast)только флагифлаг запуска; в MCP аргумент вызова перекрывает флаг процесса
когда ваш прогон отличается от ботаЕсли команда не зафиксировала модель или судью, а у вас они заданы — прогон пойдёт вашими, и отчёт скажет об этом строкой: на MR/PR тот же код проверит бот своими настройками, поэтому состав находок может отличаться. Это не запрещено — проверить себя строже полезно, — но знать об этом нужно, иначе «у меня зелено, а бот уронил» выглядит ошибкой бота.

Свой ключ или сервер команды

Режим сервера включается сам, едва задан адрес — отдельной команды нет, и выключается он только флагом --local. В этом режиме ваши локальные LLM_* и REVIEWGATE_LICENSE в прогоне не участвуют: модель, лицензия и стоимость — серверные.

Если в конфиге (или в окружении) задан адрес сервера ревью, прогон уходит на бот компании: ключ модели вам не нужен, вы предъявляете личный токен GitLab. Флаг --local возвращает прогон на ваш собственный ключ — вне сети компании, при эксперименте с моделью или когда сервер занят. Заданный адрес без токена — ошибка, а не тихий уход в локальный режим: иначе прогон незаметно ушёл бы на ваш ключ.

Как это устроено и что видит администратор — сервер ревью для команды.

MCP: то же ревью как инструмент агента

reviewgate mcp поднимает MCP-сервер на stdio — подключение и строки для файла-инструкции проекта (без них агент об инструментах не узнает) показаны на странице CLI, хук и MCP. Аргументы инструментов:

инструменты MCP
review_changes
  scope: "uncommitted" | "staged" | { base, head }   # uncommitted by default
  mode:  "full" | "fast"                             # full by default
  # any other value is a tool error, not a silent fallback to the default

get_team_rules
  no arguments

Оба инструмента ходят через тот же прогон, поэтому сервер ревью для них включается автоматически, а репозиторий определяется рабочим каталогом процесса — MCP-клиент должен запускаться из репозитория. Ошибку инструмент возвращает с признаком isError, а не обрывом протокола: в тексте — объект reviewgate.error/v1 с тем же кодом, что печатает команда, поэтому агент ветвится по коду, а не разбирает сообщение регулярками.

Прогоны идут по одному — второй вызов ждёт первого, не деля с ним бюджет и лимиты провайдера; короткие методы протокола при этом отвечают сразу. Отмена вызова прекращает ревью: не начинаются следующие вызовы моделей (судья, ансамбль, арбитр), а ответ на отменённый вызов не отправляется. Уже начатый ответ провайдер посчитает в любом случае — обещать экономию на нём было бы неправдой.

Флаги, с которыми запущен сам процесс reviewgate mcp, задают умолчания для вызовов: --config меняет путь политики (несуществующий файл — ошибка, а не тихий откат на дефолты), --fail-on — порог вердикта. Область и режим приходят в аргументах вызова и перекрывают только их. Нераспознанные аргументы отвергаются: незнакомый mode или scope — ошибка инструмента, а не тихий откат к значению по умолчанию, иначе агент получил бы «чисто» вместо того ревью, которое просил. Аргументы, присланные JSON-строкой (так делают мосты поверх function-calling), разбираются.

Рецепты

Миграция конфигурации 1.x → 2.0

После апгрейда со схемы 1.x снесённые ключи (validate_model, extra_generators, env-ручки LLM_VALIDATE_* и другие) бот и CLI встречают именными миграционными ошибками с готовой строкой замены. Применить все замены разом:

перенос на канон 2.0
reviewgate migrate            # dry run: repository config + personal config
reviewgate migrate --write    # apply it; a <file>.bak backup stays next to the original
reviewgate migrate deploy/.env.bot --write   # an explicit file (.yml or .env)

Таблица соответствия — Конфиг → миграция со схемы 1.x.

Гейт перед push без агента

Обычный git-хук: не даёт отправить ветку с блокирующими находками. Рецепт различает коды выхода: блокирует только 2 (гейт не пройден), а 1 — сбой самого ревью — пропускает с предупреждением: сломанный ревьюер не должен запирать разработчика в ветке (тот же принцип, что у --hook-stdin ниже). Тот же текст работает и в husky-хуке (.husky/pre-push): husky запускает хуки с set -e, поэтому код выхода перехватывается через || code=$?. Под set -e любой ненулевой код reviewgate завершает хук раньше голого case $?: блокирующая находка push и так остановит (husky напечатает «script failed (code 2)» вместо нашего сообщения), но код 1 — сбой самого ревью — остановит его тоже, и сломанный ревьюер запрёт разработчика в его ветке. Теряется именно мягкая ветка, а не блокировка.

.git/hooks/pre-push
#!/bin/sh
# .git/hooks/pre-push — an ordinary git hook, no agent involved.
# Replace main with your own default branch.
# ONLY exit code 2 (the gate did not pass) blocks the push. Code 1 is a failure
# of the review itself (no network, no key, no model): we warn and let it through —
# a broken reviewer must not lock a developer inside their branch.
# The code is captured with `|| code=$?` on purpose: under husky (set -e) any non-zero
# exit of reviewgate ends the hook before `case` — code 2 still blocks, but code 1 (a
# failure of the review itself) blocks too, and the soft branch below is lost.
code=0
reviewgate review --refs origin/main --fail-on blocker --quiet || code=$?
case $code in
  0) ;;
  2) echo "reviewgate: blocking findings — push stopped" >&2; exit 1 ;;
  *) echo "reviewgate: the review did not run (failure) — push allowed unchecked" >&2 ;;
esac

Вариант для раннера ИИ-агента (Claude Code и совместимые) — --hook-stdin, описан на странице CLI, хук и MCP. Порог у него тот же, что у команды: без --fail-on хук блокирует по severity_gate — то, что бот на MR/PR пропустит, он не запрещает. Исключение одно: если гейт у команды выключен (а это дефолт), хук применяет свой major и говорит об этом — хук, который никогда не блокирует, бессмыслен.

проверить хук руками не получитсяreviewgate review --hook-stdin, набранный в терминале, ничего не ревьюит: событие читается со stdin, а в интерактивной консоли его нет — команда честно отвечает {} и выходит с нулём. Пустое событие тоже пропускается. Чтобы проверить по-настоящему, скормите похожее на настоящее — команду для этого дадим ниже — либо просто попросите агента сделать push.
проверка хука
echo '{"hook_event_name":"PreToolUse","tool_name":"Bash","tool_input":{"command":"git push"}}' | reviewgate review --hook-stdin

В GitLab CI

.gitlab-ci.yml
review:
  stage: test
  variables:
    GIT_DEPTH: 0   # a merge base cannot be computed on a shallow clone
    RANGE: "origin/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME..$CI_COMMIT_SHA"
  script:
    - reviewgate review --refs "$RANGE" --fail-on major --json > review.json
  artifacts:
    paths: [review.json]
    when: always
нужен ли CLI в CI, если есть ботОбычно нет: гейт на MR/PR ставит бот, и вторая копия ревью в пайплайне просто удваивает расход токенов. Такая джоба уместна, когда бота ещё нет либо ревью нужно в пайплайне без MR/PR — например, на защищённой ветке. Учтите: код возврата 1 — это сбой, а не находки, и джобу он тоже уронит.

Что работает только на MR/PR

Политика одна, но часть её опирается на метаданные MR/PR, которых у локального диффа нет. В локальном прогоне поэтому не действуют: integration_branches (правило «ревьюить только в такие-то ветки»), пропуск черновиков, инкрементальность по новым коммитам. Плейсхолдеры вида {mr:author} в правилах и в review_prompt локально подставлять нечем — блок метаданных MR/PR в промпт не попадает. Всё это остаётся работой бота на MR/PR; расхождения вердикта из-за этого редки, но знать о них стоит.

Границы: чего CLI не делает

Не делаетПочему
не пишет в GitLabни комментариев, ни статусов: точка до MR/PR не должна подменять независимый гейт. Это работа бота
не меняет ваши файлыфиксы отдаются текстом (suggestedCode); применять их — решение человека или агента
не логирует код и диффв отчёт и вывод попадают метаданные прогона и тексты находок, не содержимое файлов
не берёт сеть и ключи из репозиторияendpoint и секреты — только из окружения и домашнего каталога: клон чужого репозитория не должен уводить ваш дифф на чужой endpoint
WindowsПроверено на Windows Server 2019. В консоли выполните chcp 65001, иначе не-ASCII символы отчёта — среди них эмодзи-маркеры и нелатинский текст находок — выведутся нечитаемо. На --json это не влияет: в stdout всегда UTF-8.