для того, кто решает

Сервер ревью: доступ команде без раздачи ключа

Ревью в редакторе требует ключа LLM. Раздавать корпоративный ключ двадцати разработчикам никто не хочет, а свой купят единицы — и вторая точка контроля остаётся у меньшинства команды. Сервер ревью решает это: ключ остаётся на вашем сервере, разработчик получает личный доступ к нему.

Как это работает

Бинарь на машине разработчика собирает изменения обычным git и отправляет их вашему серверу ReviewGate — тому же, что проверяет MR/PR. Ревью выполняет он: своим ключом, своей моделью, через свою сеть. Разработчику ключ не нужен и не выдаётся.

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

Что включить на сервере

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

.env вашего сервера
# GitLab groups that grant access to the review server (comma-separated, full paths).
# Empty or unset — the mode is off and CLI runs are not accepted.
REVIEWGATE_CLI_GROUPS=dev/reviewgate-cli

# How many reviews the server runs at once. The mode needs at least 2.
REVIEW_CONCURRENCY=4
# How many of those may be taken by developers working locally.
# Half by default; must be strictly less than REVIEW_CONCURRENCY.
REVIEW_CLI_CONCURRENCY=2

# Session timings — rarely worth changing; the values below are the defaults.
# How long a run waits for a free slot before it is refused with «the server is busy».
REVIEW_CLI_QUEUE_WAIT_MS=60000
# Waiting for ONE file from the developer machine. Deliberately shorter than the session cap:
# the slot is held while the server waits, and a sleeping laptop would otherwise eat capacity.
REVIEW_CLI_FILE_TIMEOUT_MS=30000
# The lifetime cap of a session. A full run with an ensemble and an arbiter takes ~5 minutes.
REVIEW_CLI_SESSION_TIMEOUT_MS=900000

Пул для разработчиков ограничен сверху, и разница с общей ёмкостью — ваш резерв: столько проверок MR/PR стартует немедленно, что бы разработчики ни делали локально. Гейт не встанет в очередь за чужими прогонами. Сервер печатает эту гарантию словами при старте и отдаёт её же в /api/health.

Там же видно, кто занимает слоты прямо сейчас — это первое, что стоит посмотреть на жалобу «CLI отвечает, что сервер занят»: идёт ли проверка MR/PR, висит ли чужой прогон или ёмкости просто мало.

занятость сервера
curl -s http://localhost:3000/api/health
# {"status":"ok", ... "capacity":{
#   "total":4,"cli":2,"mrReserve":2,        <- the configuration
#   "inFlight":{"mr":1,"cli":2},            <- busy right now
#   "waiting":1                             <- waiting for a slot
# }}

В журнале сервера такие отказы — предупреждения, а не ошибки: сработавшая политика ёмкости не должна теряться среди настоящих сбоев.

Чем управляет разработчик, а чем вы

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

что ограничивает сервер, а что нетОграничивается число одновременных прогонов и доступ (членство в группе GitLab). Потолка по модели и по числу проходов у сервера нет, но расход прогона ограничить можно: opt-in потолок трат LLM_BUDGET_TOKENS (и его вариант на бэкенд) считает токены прогона с барьерами 80 / 100 / 300%, и на 300% прогон останавливается на ближайшем чекпойнте — прогоны CLI идут тем же конвейером, что и вебхук, поэтому бюджет действует и на них. Расход виден по метрикам: прогоны CLI пишутся в ту же таблицу, что ревью MR/PR, с логином разработчика.

Кому можно — решается в GitLab

Доступ выдаётся членством в группе GitLab, а не отдельным списком у нас. Добавили человека в группу — доступ есть. Убрали — нет. Заблокировали учётную запись при увольнении — доступ закрылся сам, без отдельного действия администратора.

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

Что можно ревьюить

Бинарь сообщает адрес origin своего репозитория, а сервер проверяет через API вашего GitLab, что такой проект у вас есть и у этого человека к нему доступ уровня Reporter или выше. Личный проект на стороннем хостинге проверку не пройдёт: корпоративный ключ тратится на ваш код, а не на что угодно.

Сервер принимает только запросы на ревью и отвечает списком находок. Это не прокси к языковой модели: вести через него диалог или получать произвольный текст нельзя.

Что видно вам

Каждый прогон попадает в журнал сервера: кто (логин GitLab), какой проект, сколько файлов и в каком режиме — там же, где остальные логи бота (логи и мониторинг). Кто сколько проверок сделал, видно по журналу.

Брошенный прогон денег не тратит: если разработчик прервал команду или потерял связь, сервер прекращает вызовы моделей — уже начатый ответ провайдер, скорее всего, посчитает, но следующие шаги (второй генератор, судья) не начинаются. В журнале такой прогон виден как отменённый, в метриках — со статусом cancelled.

Расход тоже виден: каждый прогон CLI пишет строку в те же метрики Postgres, что и проверки MR/PR — с логином разработчика, проектом, моделями и токенами по ролям. Запрос «кто сколько потратил за месяц» есть готовым на той же странице. Метрики включаются заданием DATABASE_URL; без него бот работает, но учёта не будет.

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

Что делает разработчик

Ставит бинарь (CLI, хук и MCP) и создаёт один файл в своём домашнем каталоге:

~/.config/reviewgate/config.yml
server:
  url: https://bot.вашакомпания.ru
  gitlab_token: glpat-...        # the developer's personal GitLab token

Токен — обычный personal access token GitLab самого разработчика, тот же, которым он ходит в GitLab. Ключ модели ему не нужен. Проверить готовность рабочего места:

терминал
reviewgate doctor

Команда скажет, есть ли доступ: назовёт логин разработчика и путь проекта, который увидел сервер, — либо причину отказа (токен не принят, нет доступа к репозиторию, нет сети). Занятость сервера она не проверяет: это состояние минуты, и узнаётся оно на самом прогоне — отказом «попробуйте позже», а не отказом в доступе.