Webhook
Hermes 可以接收来自 GitHub、GitLab、JIRA、Stripe 等外部服务的事件,并自动触发 agent 运行。webhook 适配器会启动一个 HTTP 服务,接收 POST 请求、校验 HMAC 签名、把 payload 转换为 agent prompt,然后把响应回传给源系统,或转发到其他已配置的平台。
agent 在处理完事件后,可以通过在 PR 上发表评论、向 Telegram / Discord 发消息,或写日志等方式给出结果。
Quick Start
- 通过
hermes gateway setup或环境变量启用 webhook - 在
config.yaml中定义 routes,或通过hermes webhook subscribe动态创建 - 让外部服务把 webhook 指向
http://your-server:8644/webhooks/<route-name>
设置
有两种方式启用 webhook 适配器。
通过设置向导
hermes gateway setup
按提示启用 webhooks、设置端口,并填写全局 HMAC secret。
通过环境变量
把以下内容加入 ~/.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
routes 定义了不同 webhook 来源的处理方式。每条 route 都是 config.yaml 中 platforms.webhook.extra.routes 下的一个命名条目。
Route properties
| Property | Required | Description |
|---|---|---|
events | No | 允许接收的事件类型列表;为空时接受全部事件 |
secret | Yes | 用于签名校验的 HMAC secret;若 route 自己未设置,则回退到全局 secret。仅测试时可用 INSECURE_NO_AUTH 跳过验证 |
prompt | No | 模板字符串,支持 {pull_request.title} 这种点路径访问 |
skills | No | 为本次 agent 运行加载的技能列表 |
deliver | No | 把响应投递到哪里,例如 github_comment、telegram、discord、slack、signal、sms、whatsapp、matrix、mattermost、homeassistant、email、dingtalk、feishu、wecom、weixin、bluebubbles、qqbot,或默认的 log |
deliver_extra | No | 额外投递配置,例如 repo、pr_number、chat_id;同样支持点路径模板 |
deliver_only | No | 若设为 true,完全跳过 agent,直接把渲染后的 prompt 作为消息投递出去 |
Full example
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"
Prompt Templates
prompt 支持用点路径访问 webhook payload:
{pull_request.title}→payload["pull_request"]["title"]{repository.full_name}→payload["repository"]["full_name"]{__raw__}→ 把整个 payload 以缩进 JSON 形式插入(最长 4000 字符)- 缺失字段会保留原始
{key}字面量,不报错 - 嵌套 dict / list 会序列化为 JSON,并在 2000 字符处截断
如果某条 route 没有配置 prompt,默认会把整个 payload 以缩进 JSON 形式注入。
Forum Topic Delivery
当把 webhook 响应投递到 Telegram 时,可以在 deliver_extra 中附带 message_thread_id(或 thread_id)来指定 forum topic:
webhooks:
routes:
alerts:
events: ["alert"]
prompt: "Alert: {__raw__}"
deliver: "telegram"
deliver_extra:
chat_id: "-1001234567890"
message_thread_id: "42"
如果 deliver_extra 中没有提供 chat_id,则会回退到目标平台已配置的 home channel。
GitHub PR Review (Step by Step)
1. 在 GitHub 中创建 webhook
- 进入仓库 → Settings → Webhooks → Add webhook
- Payload URL 设为
http://your-server:8644/webhooks/github-pr - Content type 设为
application/json - Secret 与 route 配置保持一致
- 在 Which events? 中勾选 Pull requests
- 点击 Add webhook
2. 添加 route 配置
把 github-pr 路由按上面的示例加入 ~/.hermes/config.yaml。
3. 确认 gh CLI 已登录
github_comment 投递类型依赖 GitHub CLI 发表评论:
gh auth login
4. 测试
创建一个 PR。webhook 触发后,Hermes 会处理该事件,并通过 gh CLI 在 PR 上发布评论。
GitLab Webhook Setup
GitLab webhook 与 GitHub 类似,但鉴权方式不同。GitLab 使用明文 X-Gitlab-Token 头,而不是 HMAC。
1. 在 GitLab 中创建 webhook
- 进入项目 → Settings → Webhooks
- URL 设为
http://your-server:8644/webhooks/gitlab-mr - 填入 Secret token
- 勾选 Merge request events(以及你需要的其他事件)
- 点击 Add webhook
2. 添加 route 配置
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 字段决定 agent 响应会投递到哪里:
| Deliver Type | Description |
|---|---|
log | 写入 gateway 日志。默认值,适合测试 |
github_comment | 通过 gh CLI 发表 PR / issue 评论 |
telegram | 投递到 Telegram |
discord | 投递到 Discord |
slack | 投递到 Slack |
signal | 投递到 Signal |
sms | 通过 Twilio 投递到 SMS |
whatsapp | 投递到 WhatsApp |
matrix | 投递到 Matrix |
mattermost | 投递到 Mattermost |
homeassistant | 投递到 Home Assistant |
email | 投递到 Email |
dingtalk | 投递到 DingTalk |
feishu | 投递到 Feishu/Lark |
wecom | 投递到 WeCom |
weixin | 投递到 Weixin |
bluebubbles | 投递到 BlueBubbles |
如果目标平台本身没有启用或未连接,跨平台投递自然也不会成功。若 deliver_extra 中未指定 chat_id,则会回退到该平台的 home channel。
Direct Delivery Mode
默认情况下,每个 webhook POST 都会触发一次 agent 运行,从而消耗 LLM token。若你只是想直接推送一条通知,可将 route 设置为:
deliver_only: true
此时会直接把渲染后的 prompt 投递到目标平台,不进入 agent 循环。
适合的场景包括:
- 数据库变更通知
- 监控告警转发
- agent 之间互发状态消息
- 后台任务完成通知
它的好处是:
- 零 LLM token:不会运行 agent
- 亚秒级投递:只做模板渲染与投递
- 仍保留同等安全保护:HMAC、限流、幂等性、body 大小限制等都照常生效
- 同步返回结果:成功时 POST 返回
200 OK,失败时返回502,方便上游做重试
Dynamic Subscriptions (CLI)
除了 config.yaml 中的静态 routes,你也可以通过 hermes webhook CLI 动态创建 webhook 订阅:
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"
相关命令:
hermes webhook list
hermes webhook remove github-issues
hermes webhook test github-issues
动态订阅会保存在 ~/.hermes/webhook_subscriptions.json 中,并在每次收到请求时自动热加载,无需重启网关。静态 routes 若与动态订阅重名,静态配置优先。
Security
webhook 适配器内置了多层安全保护:
HMAC signature validation
它会根据不同来源使用不同的校验方式:
- GitHub:
X-Hub-Signature-256(HMAC-SHA256,格式为sha256=前缀) - GitLab:
X-Gitlab-Token(明文 token 比对) - Generic:
X-Webhook-Signature(原始 HMAC-SHA256 hex digest)
如果已经配置了 secret,但请求中没有任何可识别的签名头,适配器会拒绝该请求。
Secret is required
每条 route 都必须有 secret,要么直接写在 route 上,要么继承全局 secret。缺少 secret 会导致适配器在启动时直接报错。只有开发 / 测试场景才应该使用 INSECURE_NO_AUTH 跳过验证。
Rate limiting
默认每条 route 每分钟最多 30 个请求。你可以在 config.yaml 中调整:
platforms:
webhook:
extra:
rate_limit: 60 # requests per minute
超限时会返回 429 Too Many Requests。
Idempotency
投递 ID(来自 X-GitHub-Delivery、X-Request-ID,或时间戳回退值)会缓存 1 小时,从而避免 webhook 重试触发重复 agent 运行。
Body size limits
默认会在读取 body 前就拒绝超过 1 MB 的 payload。可通过以下配置修改:
platforms:
webhook:
extra:
max_body_bytes: 2097152 # 2 MB
Prompt injection risk
Webhook payload 中的 PR 标题、提交信息、issue 描述等内容都可能由攻击者控制。如果你的 webhook 直接暴露在公网,请尽量把网关运行在隔离环境(如 Docker 或虚拟机)中,并考虑使用 Docker 或 SSH 终端 backend。
Troubleshooting
webhook 没有到达
- 确认端口已开放,并可被源系统访问
- 检查防火墙规则
- 确认 URL 路径正确:
http://your-server:8644/webhooks/<route-name> - 使用
/health端点确认服务已正常启动
签名校验失败
- 确认 route secret 与源系统配置完全一致
- GitHub 场景下检查
X-Hub-Signature-256 - GitLab 场景下检查
X-Gitlab-Token - 查看 gateway 日志中的
Invalid signature
事件被忽略
- 检查事件类型是否包含在 route 的
events列表中 - GitHub 常见事件值:
pull_request、push、issues - GitLab 常见事件值:
merge_request、push - 若
events为空,则默认接受所有事件
agent 没有响应
- 在前台运行
hermes gateway run查看日志 - 检查 prompt 模板渲染是否正确
- 确认目标投递平台已启用且已连接
Duplicate responses
- 幂等缓存本应阻止重复处理。检查 webhook 来源是否发送了
X-GitHub-Delivery或X-Request-ID - 投递 ID 会缓存 1 小时
gh CLI errors
- 在网关主机上执行
gh auth login - 确认认证用户对目标仓库具有写权限
- 确认
gh已安装并在 PATH 中
Environment Variables
| Variable | Description | Default |
|---|---|---|
WEBHOOK_ENABLED | 启用 webhook 平台适配器 | false |
WEBHOOK_PORT | 接收 webhook 的 HTTP 端口 | 8644 |
WEBHOOK_SECRET | 全局 HMAC secret(当 route 未单独设置 secret 时作为回退值) | (none) |