sidebar_position: 13 title: "Webhooks" description: "Receive events from GitHub, GitLab, and other services to trigger Hermes agent runs" lang: ru
Вебхуки
Получайте события от внешних сервисов (GitHub, GitLab, JIRA, Stripe и т. д.) и автоматически запускайте триггерный агент Hermes. Адаптер веб-перехватчика запускает HTTP-сервер, который принимает запросы POST, проверяет подписи HMAC, преобразует полезные данные в запросы агента и направляет ответы обратно к источнику или на другую настроенную платформу.
Агент обрабатывает событие и может отреагировать, публикуя комментарии к PR, отправляя сообщения в Telegram/Discord или записывая результат.
Видеоурок
Быстрый старт
- Включите через
hermes gateway setupили переменные среды. - Определите маршруты в
config.yamlили создавайте их динамически с помощьюhermes webhook subscribe. - Укажите свой сервис по адресу
http://your-server:8644/webhooks/<route-name>.
Настройка
Есть два способа включить адаптер веб-перехватчика.
Через мастер настройки
hermes gateway setup
Следуйте инструкциям, чтобы включить веб-перехватчики, установить порт и глобальный секрет HMAC.
Через переменные среды
Добавьте в ~/.hermes/.env:
WEBHOOK_ENABLED=true
WEBHOOK_PORT=8644 # default
WEBHOOK_SECRET=your-global-secret
Проверьте сервер
Как только шлюз заработает:
curl http://localhost:8644/health
Ожидаемый ответ:
{"status": "ok", "platform": "webhook"}
Настройка маршрутов {#configuring-routes}
Маршруты определяют, как обрабатываются различные источники веб-перехватчиков. Каждый маршрут представляет собой именованную запись под platforms.webhook.extra.routes в вашем config.yaml.
Свойства маршрута
| Недвижимость | Требуется | Описание |
|---|---|---|
events |
Нет | Список типов событий, которые можно принять (например, ["pull_request"]). Если пусто, принимаются все события. Тип события считывается из X-GitHub-Event, X-GitLab-Event или event_type в полезных данных. |
secret |
Да | Секрет HMAC для проверки подписи. Возвращается к глобальному значению secret, если оно не установлено на маршруте. Установите "INSECURE_NO_AUTH" только для тестирования (пропускает проверку). |
prompt |
Нет | Строка шаблона с доступом к полезной нагрузке в виде точечной записи (например, {pull_request.title}). Если этот параметр опущен, в командную строку выгружается вся полезная нагрузка JSON. |
skills |
Нет | Список названий навыков, которые нужно загрузить для запуска агента. |
deliver |
Нет | Куда отправить ответ: github_comment, telegram, discord, slack, signal, sms, whatsapp, matrix, mattermost, homeassistant, email, dingtalk, feishu, wecom, weixin, bluebubbles, qqbot или log (по умолчанию). |
deliver_extra |
Нет | Дополнительная конфигурация доставки — ключи зависят от типа deliver (например, repo, pr_number, chat_id). Значения поддерживают те же шаблоны {dot.notation}, что и prompt. |
deliver_only |
Нет | Если true, полностью пропустите агент — визуализированный шаблон prompt станет буквальным сообщением, которое будет доставлено. Нулевая стоимость LLM, доставка за доли секунды. Варианты использования см. в разделе Режим прямой доставки. Требуется, чтобы deliver была реальной целью (а не log). |
Полный пример
platforms:
webhook:
enabled: true
extra:
port: 8644
secret: "global-fallback-secret"
routes:
github-pr:
events: ["pull_request"]
secret: "github-webhook-secret"
prompt: |
Review this pull request:
Repository: {repository.full_name}
PR #{number}: {pull_request.title}
Author: {pull_request.user.login}
URL: {pull_request.html_url}
Diff URL: {pull_request.diff_url}
Action: {action}
skills: ["github-code-review"]
deliver: "github_comment"
deliver_extra:
repo: "{repository.full_name}"
pr_number: "{number}"
deploy-notify:
events: ["push"]
secret: "deploy-secret"
prompt: "New push to {repository.full_name} branch {ref}: {head_commit.message}"
deliver: "telegram"
Шаблоны подсказок
В подсказках используется точечная нотация для доступа к вложенным полям в полезной нагрузке веб-перехватчика:
{pull_request.title}превращается вpayload["pull_request"]["title"]{repository.full_name}превращается вpayload["repository"]["full_name"]{__raw__}— специальный токен, который выводит всю полезную нагрузку в виде JSON с отступом (обрезанным до 4000 символов). Полезно для мониторинга оповещений или общих веб-перехватчиков, когда агенту требуется полный контекст.- Отсутствующие ключи остаются в виде буквальной строки
{key}(без ошибок). - Вложенные словари и списки сериализуются в формате JSON и усекаются до 2000 символов.
Вы можете смешивать {__raw__} с обычными переменными шаблона:
prompt: "PR #{pull_request.number} by {pull_request.user.login}: {__raw__}"
Если для маршрута не настроен шаблон prompt, вся полезная нагрузка выгружается в виде JSON с отступом (обрезанным до 4000 символов).
Те же шаблоны точечной записи работают со значениями deliver_extra.
Доставка тем форума
При отправке ответов через веб-перехватчик в Telegram вы можете настроить таргетинг на конкретную тему форума, включив message_thread_id (или thread_id) в deliver_extra:
webhooks:
routes:
alerts:
events: ["alert"]
prompt: "Alert: {__raw__}"
deliver: "telegram"
deliver_extra:
chat_id: "-1001234567890"
message_thread_id: "42"
Если chat_id не указан в deliver_extra, доставка возвращается на домашний канал, настроенный для целевой платформы.
PR-обзор GitHub (шаг за шагом) {#github-pr-review}
В этом пошаговом руководстве настраивается автоматическая проверка кода для каждого запроса на включение.
1. Создайте вебхук в GitHub.
- Перейдите в свой репозиторий → Настройки → Вебхуки → Добавить вебхук.
- Установите для URL полезной нагрузки значение
http://your-server:8644/webhooks/github-pr - Set Content type to
application/json - Set Secret to match your route config (e.g.
github-webhook-secret) - Under Which events?, select Let me select individual events and check Pull requests
- Click Add webhook
2. Add the route config
Add the github-pr route to your ~/.herm es/config.yaml as shown in the example above.
3. Ensure gh CLI is authenticated
The github_comment delivery type uses the GitHub CLI to post comments:
gh auth login
4. Test it
Open a pull request on the repository. The webhook fires, Hermes processes the event, and posts a review comment on the PR.
GitLab Webhook Setup {#gitlab-webhook-setup}
GitLab webhooks work similarly but use a different authentication mechanism. GitLab sends the secret as a plain X-Gitlab-Token header (exact string match, not HMAC).
1. Create the webhook in GitLab
- Go to your project → Settings → Webhooks
- Set the URL to
http://your-server:8644/webhooks/gitlab-mr - Введите свой Секретный токен.
- Выберите События запроса на слияние (и любые другие события, которые вы хотите).
- Нажмите Добавить вебхук.
2. Добавляем конфигурацию маршрута
platforms:
webhook:
enabled: true
extra:
routes:
gitlab-mr:
events: ["merge_request"]
secret: "your-gitlab-secret-token"
prompt: |
Review this merge request:
Project: {project.path_with_namespace}
MR !{object_attributes.iid}: {object_attributes.title}
Author: {object_attributes.last_commit.author.name}
URL: {object_attributes.url}
Action: {object_attributes.action}
deliver: "log"
Варианты доставки {#delivery-options}
Поле deliver определяет, куда направляется ответ агента после обработки события веб-перехватчика.
| Тип доставки | Описание |
|---|---|
log |
Регистрирует ответ на вывод журнала шлюза. Это значение по умолчанию и полезно для тестирования. |
github_comment |
Публикует ответ в виде комментария к PR/проблеме через gh CLI. Требуется deliver_extra.repo и deliver_extra.pr_number. gh CLI должен быть установлен и проверен на узле шлюза (gh auth login). |
telegram |
Направляет ответ в Telegram. Использует домашний канал или укажите chat_id в deliver_extra. |
discord |
Направляет ответ в Discord. Использует домашний канал или укажите chat_id в deliver_extra. |
slack |
Направляет ответ в Slack. Использует домашний канал или укажите chat_id в deliver_extra. |
signal |
Направляет ответ в Signal. Использует домашний канал или укажите chat_id в deliver_extra. |
sms |
Направляет ответ на SMS через Twilio. Использует домашний канал или укажите chat_id в deliver_extra. |
whatsapp |
Направляет ответ в WhatsApp. Использует домашний канал или укажите chat_id в deliver_extra. |
matrix |
Направляет ответ в Matrix. Использует домашний канал или укажите chat_id в deliver_extra. |
mattermost |
Направляет ответ на Mattermost. Использует домашний канал или укажите chat_id в deliver_extra. |
homeassistant |
Направляет ответ Home Assistant. Использует домашний канал или укажите chat_id в deliver_extra. |
email |
Направляет ответ на электронную почту. Использует домашний канал или укажите chat_id в deliver_extra. |
dingtalk |
Направляет ответ на DingTalk. Использует домашний канал или укажите chat_id в deliver_extra. |
feishu |
Направляет ответ Фейшу/Жаворонок. Использует домашний канал или укажите chat_id в deliver_extra. |
wecom |
Направляет ответ в WeCom. Использует домашний канал или укажите chat_id в deliver_extra. |
weixin |
Направляет ответ в Weixin (WeChat). Использует домашний канал или укажите chat_id в deliver_extra. |
bluebubbles |
Направляет ответ в BlueBubbles (iMessage). Использует домашний канал или укажите chat_id в deliver_extra. |
Для кросс-платформенной доставки целевая платформа также должна быть включена и подключена к шлюзу. Если chat_id не указан в deliver_extra, ответ отправляется на настроенный домашний канал этой платформы.
Режим прямой доставки {#direct-delivery-mode}
По умолчанию каждый веб-перехватчик POST запускает запуск агента — полезные данные становятся приглашением, агент обрабатывает их и доставляет ответ агента. Это стоит токенов LLM на каждом мероприятии.
Для случаев, когда вы просто хотите отправить простое уведомление — без рассуждений, без цикла агента, просто доставить сообщение — установите deliver_only: true на маршруте. Отрисованный шаблон prompt становится буквальным телом сообщения, и адаптер отправляет его непосредственно в настроенную цель доставки.
Когда использовать прямую доставку
- External Service Push — веб-хук Supabase/Firebase срабатывает при изменении базы данных → мгновенно уведомляет пользователя в Telegram.
- Оповещения мониторинга — веб-хук оповещений Datadog/Grafana → отправить на канал Discord
- Межагентские проверки — агент А уведомляет пользователя агента Б о завершении длительной задачи.
- Завершение фонового задания — задание Cron завершается → отправьте результат в Slack.
Преимущества:
- Ноль токенов LLM — агент никогда не вызывается.
- Доставка за доли секунды — один вызов адаптера, без цикла рассуждений.
- Та же безопасность, что и в режиме агента — аутентификация HMAC, ограничения скорости, идемпотентности и ограничения размера тела по-прежнему применяются.
- Синхронный ответ — POST возвращает
200 OKпосле успешной доставки или502, если цель отклоняет его, поэтому ваша вышестоящая служба может разумно повторить попытку.
Пример: отправка Telegram из Supabase
platforms:
webhook:
enabled: true
extra:
port: 8644
secret: "global-secret"
routes:
antenna-matches:
secret: "antenna-webhook-secret"
deliver: "telegram"
deliver_only: true
prompt: "🎉 New match: {match.user_name} matched with you!"
deliver_extra:
chat_id: "{match.telegram_chat_id}"
Ваша пограничная функция Supabase подписывает полезную нагрузку с помощью HMAC-SHA256 и POSTs на https://your-server:8644/webhooks/antenna-matches. The webhook adapter validates the signature, renders the template from the payload, delivers to Telegram, and returns 200 OK.
Example: Dynamic subscription via CLI
hermes webhook subscribe antenna-matches \
--deliver telegram \
--deliver-chat-id "123456789" \
--deliver-only \
--prompt "🎉 New match: {match.user_name} matched with you!" \
--description "Antenna match notifications"
Response codes
| Status | Meaning |
|---|---|
200 OK |
Delivered successfully. Body: {"status": "delivered", "route": "...", "target": "...", "delivery_id": "..."} |
200 OK (status=duplicate) |
Duplicate X-GitHub-Delivery ID within the idempotency TTL (1 hour). Not re-delivered. |
401 Несанкционировано |
HMAC signature invalid or missing. |
400 Неверный запрос |
Malformed JSON body. |
404 Не найден |
Unknown route name. |
413 Полезная нагрузка слишком велика |
Body exceeded max_body_bytes. |
429 Слишком много Запросы |
Route rate limit exceeded. |
502 Неверный шлюз |
Target adapter rejected the message or raised. The error is logged server-side; the response body is a generic Ошибка доставки to avoid leaking adapter internals. |
Configuration gotchas
deliver_only: truerequiresdeliverto be a real target.deliver: log(or omittingdeliver) is rejected at startup — the adapter refuses to start if it finds a misconfigured route.- The
skillsfield is ignored in direct delivery mode (no agent runs, so there's nothing to inject skills into). - Template rendering uses the same
{dot.notation}syntax as agent mode, including the{__raw__}token. - Idempotency uses the same
X-GitH ub-Delivery/X-Request-IDheader — retries with the same ID returnstatus=dudicateand do NOT re-deliver.
Dynamic Subscriptions (CLI) {#dynamic-subscriptions}
In addition to static routes in config.yaml, you can create webhook subscriptions dynamically using the hermes webhook CLI command. This is especially useful when the agent itself needs to set up event-driven triggers.
Create a subscription
hermes webhook subscribe github-issues \
--events "issues" \
--prompt "New issue #{issue.number}: {issue.title}\nBy: {issue.user.login}\n\n{issue.body}" \
--deliver telegram \
--deliver-chat-id "-100123456789" \
--description "Triage new GitHub issues"
This returns the webhook URL and an auto-generated HMAC secret. Configure your service to POST to that URL.
List subscriptions
hermes webhook list
Remove a subscription
hermes webhook remove github-issues
Test a subscription
hermes webhook test github-issues
hermes webhook test github-issues --payload '{"issue": {"number": 42, "title": "Test"}}'
How dynamic subscriptions work
- Subscriptions are stored in
~/.hermes/webhook_subscriptions.json - The webhook adapter hot-reloads this file on each incoming request (mtime-gated, negligible overhead)
- Static routes from
config.yamlalways take precedence over dynamic ones with the same name - Dynamic subscriptions use the same route format and capabilities as static routes (events, prompt templates, skills, delivery)
- No gateway restart required — subscribe and it's immediately live
Agent-driven subscriptions
The agent can create subscriptions via the terminal tool when guided by the webhook-subscriptions skill. Ask the agent to "set up a webhook for GitHub issues" and it will run the appropriate hermes webhook подписаться command.
Security {#security}
The webhook adapter includes multiple layers of security:
HMAC signature validation
The adapter validates incoming webhook signatures using the appropriate method for each source:
- GitHub:
X-Hub-Signature-256header — HMAC-SHA256 hex digest prefixed withsha256= - GitLab:
X-Gitlab-Tokenheader — plain secret string match - Generic:
X-Webhook-Signatureheader — raw HMAC-SHA256 hex digest
If a secret is configured but no recognized signature header is present, the request is rejected.
Secret is required
Every route must have a secret — either set directly on the route or inherited from the global secret. Routes without a secret cause the adapter to fail at startup with an error. For development/testing only, you can set the secret to "INSECURE_NO_AUTH" to skip validation entirely.
Rate limiting
Each route is rate-limited to 30 requests per minute by default (fixed-window). Configure this globally:
platforms:
webhook:
extra:
rate_limit: 60 # requests per minute
Requests exceeding the limit receive a 429 Слишком много Запросы response.
Idempotency
Delivery IDs (from X-GitHub-Delivery, X-Request-ID, or a timestamp fallback) are cached for 1 hour. Duplicate deliveries (e.g. webhook retries) are silently skipped with a 200 response, preventing duplicate agent runs.
Body size limits
Payloads exceeding 1 MB are rejected before the body is read. Configure this:
platforms:
webhook:
extra:
max_body_bytes: 2097152 # 2 MB
Prompt injection risk
⚠️ Warning
Webhook payloads contain attacker-controlled data — PR titles, commit messages, issue descriptions, etc. can all contain malicious instructions. Run the gateway in a sandboxed environment (Docker, VM) when exposed to the internet. Consider using the Docker or SSH terminal backend for isolation.Troubleshooting {#troubleshooting}
Webhook not arriving
- Verify the port is exposed and accessible from the webhook source
- Check firewall rules — port
8644(or your configured port) must be open - Verify the URL path matches:
@@UR000 5@@<имя-маршрута> - Use the
/healthendpoint to confirm the server is running
Signature validation failing
- Ensure the secret in your route config exactly matches the secret configured in the webhook source
- For GitHub, the secret is HMAC-based — check
X-Hub-Signature-256 - For GitLab, the secret is a plain token match — check
X-Gitlab-Token - Check gateway logs for
Invalid подписьwarnings
Event being ignored
- Check that the event type is in your route's
eventslist - GitHub events use values like
pull_request,push,issues(theX-GitHub-E ventheader value) - GitLab events use values like
merge_request,push(theX-GitLab-Eventheader value) - If
eventsis empty or not set, all events are accepted
Agent not responding
- Run the gateway in foreground to see logs:
hermes шлюз run - Check that the prompt template is rendering correctly
- Verify the delivery target is configured and connected
Duplicate responses
- The idempotency cache should prevent this — check that the webhook source is sending a delivery ID header (
X-GitHub-DeliveryorX-Request-ID) - Delivery IDs are cached for 1 hour
gh CLI errors (GitHub comment delivery)
- Run
gh auth входon the gateway host - Ensure the authenticated GitHub user has write access to the repository
- Check that
ghis installed and on the PATH
Environment Variables {#environment-variables}
| Variable | Description | Default |
|---|---|---|
WEBHOOK_ENABLED |
Enable the webhook platform adapter | false |
WEBHOOK_PORT |
HTTP server port for receiving webhooks | 8644 |
WEBHOOK_SECRET |
Глобальный секрет HMAC (используется как запасной вариант, когда в маршрутах не указаны собственные) | (нет) |