Справочник CLI
Полная поверхность reviewgate: что можно запросить, что вернётся и что делать с каждой ошибкой. Если вы ещё не поставили бинарь и не выбрали, откуда берётся доступ к модели — начните с CLI, хук и MCP, там путь по шагам.
reviewgate help.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 mcp | MCP-сервер на 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 — решение кодом выхода |
--write | migrate: применить правки (по умолчанию — предпросмотр); бэкап кладётся рядом |
--lang ru|en | init: язык создаваемых конфигов — ключа 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, чтобы не ронять ничего. Что означает каждый — на странице конфигурации.
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.llmSource | home | team — чьей схемой LLM шёл прогон; home не предсказывает ревью бота. В отчётах, собранных сервером ревью, поля нет (там всегда team) |
summary | связный текст прогона; секреты уже замаскированы конвейером |
verdict.gate | pass · 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_config | LLM_MAX_TOKENS выше потолка модели — уменьшить |
llm_refused | модель отказалась отвечать — повторить или сменить модель |
llm_overloaded | провайдер перегружен — повторить позже |
llm_network | сеть или прокси до провайдера — проверить LLM_PROXY |
llm_endpoint | endpoint или модель не найдены — проверить 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_PROVIDER | anthropic (по умолчанию) · yandex · ollama · openai · openrouter · vllm |
LLM_MODEL | модель генератора |
LLM_JUDGES | your 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_URL | endpoint корпоративного шлюза или локальной модели |
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.
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 аргумент вызова перекрывает флаг процесса |
Свой ключ или сервер команды
Режим сервера включается сам, едва задан адрес — отдельной команды нет, и выключается он только флагом --local. В этом режиме ваши локальные LLM_* и REVIEWGATE_LICENSE в прогоне не участвуют: модель, лицензия и стоимость — серверные.
Если в конфиге (или в окружении) задан адрес сервера ревью, прогон уходит на бот компании: ключ модели вам не нужен, вы предъявляете личный токен GitLab. Флаг --local возвращает прогон на ваш собственный ключ — вне сети компании, при эксперименте с моделью или когда сервер занят. Заданный адрес без токена — ошибка, а не тихий уход в локальный режим: иначе прогон незаметно ушёл бы на ваш ключ.
Как это устроено и что видит администратор — сервер ревью для команды.
MCP: то же ревью как инструмент агента
reviewgate mcp поднимает MCP-сервер на stdio — подключение и строки для файла-инструкции проекта (без них агент об инструментах не узнает) показаны на странице CLI, хук и 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 встречают именными миграционными ошибками с готовой строкой замены. Применить все замены разом:
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 — сбой самого ревью — остановит его тоже, и сломанный ревьюер запрёт разработчика в его ветке. Теряется именно мягкая ветка, а не блокировка.
#!/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
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Что работает только на MR/PR
Политика одна, но часть её опирается на метаданные MR/PR, которых у локального диффа нет. В локальном прогоне поэтому не действуют: integration_branches (правило «ревьюить только в такие-то ветки»), пропуск черновиков, инкрементальность по новым коммитам. Плейсхолдеры вида {mr:author} в правилах и в review_prompt локально подставлять нечем — блок метаданных MR/PR в промпт не попадает. Всё это остаётся работой бота на MR/PR; расхождения вердикта из-за этого редки, но знать о них стоит.
Границы: чего CLI не делает
| Не делает | Почему |
|---|---|
| не пишет в GitLab | ни комментариев, ни статусов: точка до MR/PR не должна подменять независимый гейт. Это работа бота |
| не меняет ваши файлы | фиксы отдаются текстом (suggestedCode); применять их — решение человека или агента |
| не логирует код и дифф | в отчёт и вывод попадают метаданные прогона и тексты находок, не содержимое файлов |
| не берёт сеть и ключи из репозитория | endpoint и секреты — только из окружения и домашнего каталога: клон чужого репозитория не должен уводить ваш дифф на чужой endpoint |
chcp 65001, иначе не-ASCII символы отчёта — среди них эмодзи-маркеры и нелатинский текст находок — выведутся нечитаемо. На --json это не влияет: в stdout всегда UTF-8.