Вебхуки
Получайте события от внешних сервисов (GitHub, GitLab, JIRA, Stripe и др.) и автоматически запускайте агентов VibeOS. Адаптер вебхуков запускает HTTP-сервер, который принимает POST-запросы, проверяет HMAC-подписи, преобразует полезные данные в промпты для агента и направляет ответы обратно источнику или на другую настроенную платформу.
Агент обрабатывает событие и может ответить, оставляя комментарии к PR, отправляя сообщения в Telegram/Discord или записывая результат в лог.
Видеоурок
Быстрый старт
- Включите через
vibeos gateway setupили переменные окружения - Определите маршруты в
config.yamlили создайте их динамически с помощьюvibeos webhook subscribe - Направьте ваш сервис на
http://your-server:8644/webhooks/<имя-маршрута>
Настройка
Есть два способа включить адаптер вебхуков.
Через мастер настройки
vibeos gateway setup
Следуйте подсказкам, чтобы включить вебхуки, установить порт и задать глобальный HMAC-секрет.
Через переменные окружения
Добавьте в ~/.vibeos/.env:
WEBHOOK_ENABLED=true
WEBHOOK_PORT=8644 # по умолчанию
WEBHOOK_SECRET=ваш-глобальный-секрет
Проверка сервера
После запуска шлюза:
curl http://localhost:8644/health
Ожидаемый ответ:
{"status": "ok", "platform": "webhook"}
Настройка маршрутов
Маршруты определяют, как обрабатываются разные источники вебхуков. Каждый маршрут — это именованная запись в разделе 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: "глобальный-запасной-секрет"
routes:
github-pr:
events: ["pull_request"]
secret: "секрет-вебхука-github"
prompt: |
Проверьте этот pull request:
Репозиторий: {repository.full_name}
PR #{number}: {pull_request.title}
Автор: {pull_request.user.login}
URL: {pull_request.html_url}
URL diff: {pull_request.diff_url}
Действие: {action}
skills: ["github-code-review"]
deliver: "github_comment"
deliver_extra:
repo: "{repository.full_name}"
pr_number: "{number}"
deploy-notify:
events: ["push"]
secret: "секрет-развёртывания"
prompt: "Новый push в {repository.full_name} ветка {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} от {pull_request.user.login}: {__raw__}"
Если для маршрута не настроен шаблон prompt, все полезные данные выгружаются в виде форматированного JSON (обрезается до 4000 символов).
Те же шаблоны точечной нотации работают в значениях deliver_extra.
Доставка в тему форума
При доставке ответов вебхука в Telegram вы можете указать конкретную тему форума, включив message_thread_id (или thread_id) в deliver_extra:
webhooks:
routes:
alerts:
events: ["alert"]
prompt: "Оповещение: {__raw__}"
deliver: "telegram"
deliver_extra:
chat_id: "-1001234567890"
message_thread_id: "42"
Если chat_id не указан в deliver_extra, доставка возвращается к домашнему каналу, настроенному для целевой платформы.
Проверка PR на GitHub (пошагово)
Это руководство настраивает автоматическую проверку кода для каждого pull request.
1. Создайте вебхук в GitHub
- Перейдите в ваш репозиторий → Settings → Webhooks → Add webhook
- Установите Payload URL на
http://your-server:8644/webhooks/github-pr - Установите Content type на
application/json - Установите Secret в соответствии с конфигурацией маршрута (например,
github-webhook-secret) - В разделе Which events? выберите Let me select individual events и отметьте Pull requests
- Нажмите Add webhook
2. Добавьте конфигурацию маршрута
Добавьте маршрут github-pr в ваш ~/.vibeos/config.yaml, как показано в примере выше.
3. Убедитесь, что CLI gh аутентифицирован
Тип доставки github_comment использует GitHub CLI для публикации комментариев:
gh auth login
4. Протестируйте
Откройте pull request в репозитории. Вебхук срабатывает, VibeOS обрабатывает событие и публикует комментарий с проверкой в PR.
Настройка вебхука GitLab
Вебхуки GitLab работают аналогично, но используют другой механизм аутентификации. GitLab отправляет секрет как обычный заголовок X-Gitlab-Token (точное совпадение строк, не HMAC).
1. Создайте вебхук в GitLab
- Перейдите в ваш проект → Settings → Webhooks
- Установите URL на
http://your-server:8644/webhooks/gitlab-mr - Введите ваш Secret token
- Выберите Merge request events (и любые другие события, которые вам нужны)
- Нажмите Add webhook
2. Добавьте конфигурацию маршрута
platforms:
webhook:
enabled: true
extra:
routes:
gitlab-mr:
events: ["merge_request"]
secret: "ваш-секретный-токен-gitlab"
prompt: |
Проверьте этот merge request:
Проект: {project.path_with_namespace}
MR !{object_attributes.iid}: {object_attributes.title}
Автор: {object_attributes.last_commit.author.name}
URL: {object_attributes.url}
Действие: {object_attributes.action}
deliver: "log"
Варианты доставки
Поле deliver определяет, куда направляется ответ агента после обработки события вебхука.
| Тип доставки | Описание |
|---|---|
log | Записывает ответ в лог шлюза. Это значение по умолчанию, полезно для тестирования. |
github_comment | Публикует ответ как комментарий к PR/issue через CLI gh. Требует deliver_extra.repo и deliver_extra.pr_number. CLI gh должен быть установлен и аутентифицирован на хосте шлюза (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 | Направляет ответ по Email. Использует домашний канал или укажите chat_id в deliver_extra. |
dingtalk | Направляет ответ в DingTalk. Использует домашний канал или укажите chat_id в deliver_extra. |
feishu | Направляет ответ в Feishu/Lark. Использует домашний канал или укажите 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, ответ отправляется в настроенный домашний канал этой платформы.
Режим прямой доставки
По умолчанию каждый POST-запрос вебхука запускает агента — полезные данные становятся промптом, агент обрабатывает их, и ответ агента доставляется. Это расходует токены LLM на каждое событие.
Для случаев, когда вы просто хотите отправить простое уведомление — без рассуждений, без цикла агента, просто доставить сообщение — установите deliver_only: true на маршруте. Отрендеренный шаблон prompt становится буквальным телом сообщения, и адаптер отправляет его напрямую на настроенную цель доставки.
Когда использовать прямую доставку
- Внешний push сервиса — вебхук Supabase/Firebase срабатывает при изменении базы данных → мгновенно уведомить пользователя в Telegram
- Мониторинговые оповещения — вебхук оповещения Datadog/Grafana → отправить в канал Discord
- Межагентные пинги — Агент A уведомляет пользователя Агента B о завершении длительной задачи
- Завершение фоновых задач — Cron-задача завершена → отправить результат в Slack
Преимущества:
- Нулевые токены LLM — агент никогда не вызывается
- Доставка за доли секунды — один вызов адаптера, без цикла рассуждений
- Та же безопасность, что и в режиме агента — HMAC-аутентификация, лимиты запросов, идемпотентность и ограничения размера тела всё ещё применяются
- Синхронный ответ — POST возвращает
200 OKпосле успешной доставки или502, если цель отклонила его, так что ваш вышестоящий сервис может интеллектуально повторить попытку
Пример: Push в Telegram из Supabase
platforms:
webhook:
enabled: true
extra:
port: 8644
secret: "глобальный-секрет"
routes:
antenna-matches:
secret: "секрет-вебхука-антенны"
deliver: "telegram"
deliver_only: true
prompt: "🎉 Новое совпадение: {match.user_name} совпал с вами!"
deliver_extra:
chat_id: "{match.telegram_chat_id}"
Ваша edge-функция Supabase подписывает полезные данные с помощью HMAC-SHA256 и отправляет POST на https://your-server:8644/webhooks/antenna-matches. Адаптер вебхуков проверяет подпись, рендерит шаблон из полезных данных, доставляет в Telegram и возвращает 200 OK.
Пример: Динамическая подписка через CLI
vibeos webhook subscribe antenna-matches \
--deliver telegram \
--deliver-chat-id "123456789" \
--deliver-only \
--prompt "🎉 Новое совпадение: {match.user_name} совпал с вами!" \
--description "Уведомления о совпадениях антенны"
Коды ответов
| Статус | Значение |
|---|---|
200 OK | Успешно доставлено. Тело: {"status": "delivered", "route": "...", "target": "...", "delivery_id": "..."} |
200 OK (status=duplicate) | Дубликат ID X-GitHub-Delivery в пределах TTL идемпотентности (1 час). Не доставляется повторно. |
401 Unauthorized | HMAC-подпись недействительна или отсутствует. |
400 Bad Request | Некорректное JSON-тело. |
404 Not Found | Неизвестное имя маршрута. |
413 Payload Too Large | Тело превысило max_body_bytes. |
429 Too Many Requests | Превышен лимит запросов маршрута. |
502 Bad Gateway | Целевой адаптер отклонил сообщение или вызвал ошибку. Ошибка логируется на стороне сервера; тело ответа — общее Delivery failed, чтобы не раскрывать внутренности адаптера. |
Особенности конфигурации
deliver_only: trueтребует, чтобыdeliverбыл реальной целью.deliver: log(или опусканиеdeliver) отклоняется при запуске — адаптер отказывается запускаться, если находит неправильно настроенный маршрут.- Поле
skillsигнорируется в режиме прямой доставки (агент не запускается, поэтому некуда внедрять навыки). - Рендеринг шаблона использует тот же синтаксис
{dot.notation}, что и в режиме агента, включая токен{__raw__}. - Идемпотентность использует тот же заголовок
X-GitHub-Delivery/X-Request-ID— повторные попытки с тем же ID возвращаютstatus=duplicateи НЕ доставляются повторно.
Динамические подписки (CLI)
В дополнение к статическим маршрутам в config.yaml вы можете создавать подписки на вебхуки динамически с помощью команды CLI vibeos webhook. Это особенно полезно, когда самому агенту нужно настроить триггеры, управляемые событиями.
Создание подписки
vibeos webhook subscribe github-issues \
--events "issues" \
--prompt "Новый issue #{issue.number}: {issue.title}\nОт: {issue.user.login}\n\n{issue.body}" \
--deliver telegram \
--deliver-chat-id "-100123456789" \
--description "Триаж новых issues GitHub"
Это возвращает URL вебхука и автоматически сгенерированный HMAC-секрет. Настройте ваш сервис на отправку POST на этот URL.
Список подписок
vibeos webhook list
Удаление подписки
vibeos webhook remove github-issues
Тестирование подписки
vibeos webhook test github-issues
vibeos webhook test github-issues --payload '{"issue": {"number": 42, "title": "Test"}}'
Как работают динамические подписки
- Подписки хранятся в
~/.vibeos/webhook_subscriptions.json - Адаптер вебхуков горячо перезагружает этот файл при каждом входящем запросе (с проверкой mtime, минимальные накладные расходы)
- Статические маршруты из
config.yamlвсегда имеют приоритет над динамическими с тем же именем - Динамические подписки используют тот же формат маршрута и возможности, что и статические (события, шаблоны промптов, навыки, доставка)
- Перезапуск шлюза не требуется — подпишитесь, и оно сразу работает
Подписки, управляемые агентом
Агент может создавать подписки через инструмент терминала, когда им руководит навык webhook-subscriptions. Попросите агента «настроить вебхук для issues GitHub», и он выполнит соответствующую команду vibeos webhook subscribe.
Безопасность
Адаптер вебхуков включает несколько уровней безопасности:
Проверка HMAC-подписи
Адаптер проверяет входящие подписи вебхуков, используя соответствующий метод для каждого источника:
- GitHub: заголовок
X-Hub-Signature-256— шестнадцатеричный дайджест HMAC-SHA256 с префиксомsha256= - GitLab: заголовок
X-Gitlab-Token— простое совпадение строки секрета - Общий: заголовок
X-Webhook-Signature— сырой шестнадцатеричный дайджест HMAC-SHA256
Если секрет настроен, но распознанный заголовок подписи отсутствует, запрос отклоняется.
Секрет обязателен
Каждый маршрут должен иметь секрет — либо заданный непосредственно на маршруте, либо унаследованный от глобального secret. Маршруты без секрета вызывают ошибку при запуске адаптера. Только для разработки/тестирования вы можете установить секрет в "INSECURE_NO_AUTH", чтобы полностью пропустить проверку.
INSECURE_NO_AUTH принимается только тогда, когда шлюз привязан к адресу loopback (127.0.0.1, localhost, ::1). Если он используется с не-loopback привязкой, такой как 0.0.0.0 или LAN IP, адаптер отказывается запускаться — это предотвращает случайное раскрытие неаутентифицированной конечной точки на публичном интерфейсе.
Лимитирование запросов
Каждый маршрут ограничен 30 запросами в минуту по умолчанию (фиксированное окно). Настройте это глобально:
platforms:
webhook:
extra:
rate_limit: 60 # запросов в минуту
Запросы, превышающие лимит, получают ответ 429 Too Many Requests.
Идемпотентность
ID доставки (из X-GitHub-Delivery, X-Request-ID или запасной вариант с меткой времени) кэшируются на 1 час. Дублирующиеся доставки (например, повторные попытки вебхука) молча пропускаются с ответом 200, предотвращая повторные запуски агента.
Ограничения размера тела
Полезные данные, превышающие 1 МБ, отклоняются до чтения тела. Настройте это:
platforms:
webhook:
extra:
max_body_bytes: 2097152 # 2 МБ
Аутентификация не означает доверие
HMAC-валидация аутентифицирует отправителя, а не содержимое. Действительная подпись только доказывает, что запрос пришёл от стороны, владеющей секретом маршрута (например, GitHub). Она ничего не говорит о том, кто написал бизнес-поля внутри полезных данных — заголовки PR, сообщения коммитов, описания issues и любой другой текст из вышестоящего источника созданы произвольными третьими лицами и должны рассматриваться как ненадёжные.
Это та же модель доверия, которая применяется ко всему, что читает агент: веб-страницы, файлы и вывод инструментов — всё это ненадёжный ввод. VibeOS не может и не должен надёжно очищать ненадёжный текст с помощью блок-листа; формулировки, кодировка и перевод делают это тривиально обходимым. Граница доверия — это поверхность возможностей агента, а не канал ввода. Укрепляйте её:
- Изолируйте среду выполнения. Запускайте шлюз с бэкендом Docker или SSH-терминала (или в VM) при доступе из интернета, чтобы захваченный поворот не мог затронуть хост.
- Ограничьте набор инструментов. Отключайте инструменты
terminal,fileи исходящие действия на сессиях, запущенных вебхуками, если маршруту нужно только читать и обобщать. Меньше возможностей — меньше радиус поражения, если поле полезных данных содержит внедрённые инструкции. - Оставьте подтверждения включёнными для любых деструктивных или исходящих операций, чтобы внедрённая инструкция не могла действовать без присмотра.
- Шаблонизируйте узко. Предпочитайте конкретный
promptс именованными полями ({pull_request.title}) вместо{__raw__}или пустого шаблона, который выгружает все полезные данные, чтобы в промпт попадали только те поля, которые вы планируете.
Устранение неполадок
Вебхук не приходит
- Проверьте, что порт открыт и доступен из источника вебхука
- Проверьте правила брандмауэра — порт
8644(или ваш настроенный порт) должен быть открыт - Проверьте, что путь URL совпадает:
http://your-server:8644/webhooks/<имя-маршрута> - Используйте конечную точку
/health, чтобы убедиться, что сервер работает
Ошибка проверки подписи
- Убедитесь, что секрет в конфигурации маршрута точно совпадает с секретом, настроенным в источнике вебхука
- Для GitHub секрет основан на HMAC — проверьте
X-Hub-Signature-256 - Для GitLab секрет — это простое совпадение токена — проверьте
X-Gitlab-Token - Проверьте логи шлюза на наличие предупреждений
Invalid signature
Событие игнорируется
- Проверьте, что тип события находится в списке
eventsвашего маршрута - События GitHub используют значения, такие как
pull_request,push,issues(значение заголовкаX-GitHub-Event) - События GitLab используют значения, такие как
merge_request,push(значение заголовкаX-GitLab-Event) - Если
eventsпуст или не задан, принимаются все события
Агент не отвечает
- Запустите шлюз в режиме переднего плана, чтобы увидеть логи:
vibeos gateway run - Проверьте, что шаблон промпта рендерится правильно
- Убедитесь, что цель доставки настроена и подключена
Дублирующиеся ответы
- Кэш идемпотентности должен предотвращать это — проверьте, что источник вебхука отправляет заголовок ID доставки (
X-GitHub-DeliveryилиX-Request-ID) - ID доставки кэшируются на 1 час
Ошибки CLI gh (доставка комментариев GitHub)
- Запустите
gh auth loginна хосте шлюза - Убедитесь, что аутентифицированный пользователь GitHub имеет права на запись в репозиторий
- Проверьте, что
ghустановлен и находится в PATH
Переменные окружения
| Переменная | Описание | По умолчанию |
|---|---|---|
WEBHOOK_ENABLED | Включить адаптер платформы вебхуков | false |
WEBHOOK_PORT | Порт HTTP-сервера для приёма вебхуков | 8644 |
WEBHOOK_SECRET | Глобальный HMAC-секрет (используется как запасной, когда маршруты не указывают свой) | (нет) |