Автоматические комментарии к PR на GitHub через вебхуки
Это руководство покажет, как подключить Hermes Agent к GitHub, чтобы он автоматически получал diff пул-реквеста, анализировал изменения в коде и публиковал комментарий — срабатывая от события вебхука без необходимости ручного запроса.
Когда PR открывается или обновляется, GitHub отправляет POST-запрос через вебхук на ваш экземпляр Hermes. Hermes запускает агента с промптом, который предписывает получить diff с помощью CLI gh, а ответ публикуется обратно в обсуждение PR.
tip Хотите более простую настройку без публичного эндпоинта?
Если у вас нет публичного URL или вы хотите быстро начать, ознакомьтесь с Build a GitHub PR Review Agent — используется cron для опроса PR по расписанию, работает за NAT и файрволами.
info Справочная документация
Полную справку по платформе вебхуков (все опции конфигурации, типы доставки, динамические подписки, модель безопасности) см. в разделе Webhooks.
warning Риск инъекции промпта
Полезная нагрузка вебхука содержит данные, контролируемые атакующим — заголовки PR, сообщения коммитов и описания могут содержать вредоносные инструкции. Когда ваш вебхук-эндпоинт доступен из интернета, запускайте gateway в изолированном окружении (Docker, SSH backend). См. раздел безопасности ниже.
Предварительные требования
Hermes Agent установлен и запущен (hermes gateway)
CLI gh установлен и аутентифицирован на хосте gateway (gh auth login)
Права администратора в репозитории GitHub (требуется для управления вебхуками)
Шаг 1 — Включите платформу вебхуков
Добавьте в ваш ~/.hermes/config.yaml следующее:
platforms:webhook:enabled:trueextra:port:8644# значение по умолчанию; измените, если порт занят другим сервисомrate_limit:30# макс. запросов в минуту на маршрут (не глобальный лимит)routes:github-pr-review:secret:"your-webhook-secret-here"# должен точно совпадать с секретом вебхука GitHubevents:-pull_request# Агенту предписывается получить актуальный diff перед ревью.# {number} и {repository.full_name} извлекаются из полезной нагрузки GitHub.prompt:|A pull request event was received (action: {action}).PR #{number}: {pull_request.title}Author: {pull_request.user.login}Branch: {pull_request.head.ref} → {pull_request.base.ref}Description: {pull_request.body}URL: {pull_request.html_url}If the action is "closed" or "labeled", stop here and do not post a comment.Otherwise:1. Run: gh pr diff {number} --repo {repository.full_name}2. Review the code changes for correctness, security issues, and clarity.3. Write a concise, actionable review comment and post it.deliver:github_commentdeliver_extra:repo:"{repository.full_name}"pr_number:"{number}"
Ключевые поля:
Поле
Описание
secret (на уровне маршрута)
HMAC-секрет для данного маршрута. Если не указан, используется глобальный extra.secret.
events
Список значений заголовка X-GitHub-Event для приёма. Пустой список = принимать все.
prompt
Шаблон; {field} и {nested.field} подставляются из полезной нагрузки GitHub.
deliver
github_comment публикует через gh pr comment. log просто записывает в лог gateway.
deliver_extra.repo
Подставляется, например, как org/repo из полезной нагрузки.
deliver_extra.pr_number
Подставляется как номер PR из полезной нагрузки.
note Полезная нагрузка не содержит код
Полезная нагрузка вебхука GitHub включает метаданные PR (заголовок, описание, имена веток, URL), но не diff. Приведённый выше промпт предписывает агенту выполнить gh pr diff для получения актуальных изменений. Инструмент terminal включён в набор по умолчанию hermes-webhook, поэтому дополнительная настройка не требуется.
Secret: то же значение, которое вы указали в secret в конфигурации маршрута
Which events? → Выберите отдельные события → отметьте Pull requests
Нажмите Add webhook
GitHub немедленно отправит событие ping для подтверждения соединения. Оно безопасно игнорируется — ping отсутствует в вашем списке events — и возвращает {"status": "ignored", "event": "ping"}. Оно логируется только на уровне DEBUG, поэтому не появится в консоли при уровне логирования по умолчанию.
Шаг 4 — Откройте тестовый PR
Создайте ветку, отправьте изменения и откройте PR. В течение 30–90 секунд (в зависимости от размера PR и модели) Hermes опубликует ревью-комментарий.
Чтобы следить за прогрессом агента в реальном времени:
Если Hermes запущен на вашем ноутбуке, используйте ngrok для его публикации:
ngrokhttp8644
Скопируйте URL вида https://...ngrok-free.app и используйте его как Payload URL на GitHub. На бесплатном тарифе ngrok URL меняется при каждом перезапуске ngrok — обновляйте вебхук GitHub в каждой сессии. Платные аккаунты ngrok предоставляют статический домен.
Вы можете протестировать статический маршрут напрямую через curl — без аккаунта GitHub или реального PR.
tip Используйте deliver: log при локальном тестировании
Замените deliver: github_comment на deliver: log в вашей конфигурации во время тестирования. Иначе агент попытается опубликовать комментарий в фейковый репозиторий org/repo#99 из тестовой полезной нагрузки, что приведёт к ошибке. Верните deliver: github_comment обратно, когда результат промпта вас устроит.
hermes webhook test <name> работает только для динамических подписок, созданных через hermes webhook subscribe. Он не читает маршруты из config.yaml.
Фильтрация по конкретным действиям
GitHub отправляет события pull_request для многих действий: opened, synchronize, reopened, closed, labeled и т.д. Список events фильтрует только по значению заголовка X-GitHub-Event — он не может фильтровать по подтипу действия на уровне маршрутизации.
Промпт из Шага 1 уже обрабатывает это, предписывая агенту остановиться для событий closed и labeled.
warning Агент всё равно запускается и расходует токены
Инструкция «остановиться» предотвращает полноценное ревью, но агент всё равно выполняется до конца для каждого события pull_request независимо от действия. Вебхуки GitHub могут фильтровать только по типу события (pull_request, push, issues и т.д.) — не по подтипу действия (opened, closed, labeled). Фильтрации на уровне маршрутизации для поддействий нет. Для репозиториев с высокой нагрузкой примите это как неизбежные затраты или отфильтруйте upstream с помощью GitHub Actions workflow, который вызывает ваш URL вебхука условно.
Синтаксис Jinja2 или условных шаблонов отсутствует. {field} и {nested.field} — единственные поддерживаемые подстановки. Всё остальное передаётся агенту как есть.
Использование навыка для единообразного стиля ревью
Загрузите навык Hermes, чтобы задать агенту единообразную персону для ревью. Добавьте skills в ваш маршрут внутри platforms.webhook.extra.routes в config.yaml:
platforms:webhook:enabled:trueextra:routes:github-pr-review:secret:"your-webhook-secret-here"events:[pull_request]prompt:|A pull request event was received (action: {action}).PR #{number}: {pull_request.title} by {pull_request.user.login}URL: {pull_request.html_url}If the action is "closed" or "labeled", stop here and do not post a comment.Otherwise:1. Run: gh pr diff {number} --repo {repository.full_name}2. Review the diff using your review guidelines.3. Write a concise, actionable review comment and post it.skills:-reviewdeliver:github_commentdeliver_extra:repo:"{repository.full_name}"pr_number:"{number}"
Примечание: Загружается только первый найденный навык из списка. Hermes не накладывает несколько навыков — последующие записи игнорируются.
Отправка ответов в Slack или Discord вместо GitHub
Замените поля deliver и deliver_extra в вашем маршруте на нужную платформу:
# Внутри platforms.webhook.extra.routes.<route-name>:# Slackdeliver:slackdeliver_extra:chat_id:"C0123456789"# ID канала Slack (опустите, чтобы использовать настроенный домашний канал)# Discorddeliver:discorddeliver_extra:chat_id:"987654321012345678"# ID канала Discord (опустите, чтобы использовать домашний канал)
Целевая платформа также должна быть включена и подключена в gateway. Если chat_id опущен, ответ отправляется в настроенный домашний канал этой платформы.
Допустимые значения deliver: log · github_comment · telegram · discord · slack · signal · sms
Поддержка GitLab
Тот же адаптер работает с GitLab. GitLab использует X-Gitlab-Token для аутентификации (простое сравнение строк, не HMAC) — Hermes обрабатывает оба варианта автоматически.
Для фильтрации событий GitLab устанавливает заголовок X-GitLab-Event со значениями вроде Merge Request Hook, Push Hook, Pipeline Hook. Используйте точное значение заголовка в events:
events:-Merge Request Hook
Поля полезной нагрузки GitLab отличаются от GitHub — например, {object_attributes.title} для заголовка MR и {object_attributes.iid} для номера MR. Самый простой способ изучить полную структуру полезной нагрузки — кнопка Test в настройках вебхука GitLab в сочетании с журналом Recent Deliveries. Альтернативно, опустите prompt в конфигурации маршрута — Hermes передаст полную полезную нагрузку в виде форматированного JSON напрямую агенту, и ответ агента (видимый в логе gateway с deliver: log) опишет её структуру.
Заметки по безопасности
Никогда не используйте INSECURE_NO_AUTH в продакшене — он полностью отключает проверку подписи. Только для локальной разработки.
Регулярно меняйте секрет вебхука и обновляйте его как в GitHub (настройки вебхука), так и в вашем config.yaml.
Ограничение скорости — 30 запросов/мин на маршрут по умолчанию (настраивается через extra.rate_limit). Превышение возвращает 429.
Повторные доставки (повторные попытки вебхука) дедуплицируются через кэш идемпотентности на 1 час. Ключ кэша — X-GitHub-Delivery (если присутствует), затем X-Request-ID, затем метка времени в миллисекундах. Если ни один из заголовков ID доставки не установлен, повторы не дедуплицируются.
Инъекция промпта: Заголовки PR, описания и сообщения коммитов контролируются атакующим. Вредоносные PR могут пытаться манипулировать действиями агента. Запускайте gateway в изолированном окружении (Docker, VM) при публичном доступе из интернета.
Устранение неполадок
Симптом
Что проверить
401 Invalid signature
Секрет в config.yaml не совпадает с секретом вебхука GitHub
404 Unknown route
Имя маршрута в URL не соответствует ключу в routes:
429 Rate limit exceeded
Превышен лимит 30 запросов/мин на маршрут — часто случается при повторной доставке тестовых событий из интерфейса GitHub; подождите минуту или увеличьте extra.rate_limit
Комментарий не опубликован
gh не установлен, не в PATH или не аутентифицирован (gh auth login)
Агент запускается, но комментария нет
Проверьте лог gateway — если вывод агента был пустым или содержал только «SKIP», доставка всё равно будет предпринята
Порт уже занят
Измените extra.port в config.yaml
Агент запускается, но ревьюит только описание PR
В промпте отсутствует инструкция gh pr diff — diff не входит в полезную нагрузку вебхука
Не видно событие ping
Игнорируемые события возвращают {"status":"ignored","event":"ping"} только на уровне DEBUG — проверьте журнал доставки GitHub (репозиторий → Settings → Webhooks → ваш вебхук → Recent Deliveries)
Вкладка Recent Deliveries на GitHub (репозиторий → Settings → Webhooks → ваш вебхук) показывает точные заголовки запроса, полезную нагрузку, HTTP-статус и тело ответа для каждой доставки. Это самый быстрый способ диагностировать ошибки без обращения к логам сервера.
Полная конфигурация
platforms:webhook:enabled:trueextra:host:"0.0.0.0"# адрес привязки (по умолчанию: 0.0.0.0)port:8644# порт прослушивания (по умолчанию: 8644)secret:""# опциональный глобальный секрет по умолчаниюrate_limit:30# запросов в минуту на маршрутmax_body_bytes:1048576# ограничение размера полезной нагрузки в байтах (по умолчанию: 1 МБ)routes:<route-name>:secret:"required-per-route"events:[]# [] = принимать все; иначе список значений X-GitHub-Eventprompt:""# {field} / {nested.field} подставляются из полезной нагрузкиskills:[]# загружается первый подходящий навык (только один)deliver:"log"# log | github_comment | telegram | discord | slack | signal | smsdeliver_extra:{}# repo + pr_number для github_comment; chat_id для остальных