Skip to content

使用 Webhooks 自动生成 GitHub PR 评论

hermes agent 使用 Webhooks 自动生成 GitHub PR 评论

本指南将引导你把 Hermes Agent 连接到 GitHub,使它能够自动获取 pull request 的 diff,分析代码变更,并发布评论——由 webhook 事件触发,无需手动提示。

当 PR 被打开或更新时,GitHub 会向你的 Hermes 实例发送一个 webhook POST。Hermes 会使用一个 prompt 运行 agent,该 prompt 指示它通过 gh CLI 检索 diff,然后将响应发布回 PR thread。

:::caution:[Prompt injection 风险] Webhook payloads 包含攻击者可控的数据——PR 标题、commit messages 和 descriptions 可能包含恶意指令。当你的 webhook endpoint 暴露在互联网上时,请在沙箱环境中运行 gateway(Docker、SSH backend)。请参见下面的 安全部分。 :::

  • 已安装并正在运行 Hermes Agent(hermes gateway
  • 已在 gateway 主机上安装并认证 gh CLI(gh auth login
  • 你的 Hermes 实例拥有一个公网可访问的 URL(如果在本地运行,请参见使用 ngrok 进行本地测试)
  • 拥有 GitHub 仓库的管理员权限(管理 webhooks 需要)

将以下内容添加到你的 ~/.hermes/config.yaml

platforms:
webhook:
enabled: true
extra:
port: 8644 # 默认值;如果另一个服务占用了该端口,请修改
rate_limit: 30 # 每个 route 每分钟最大请求数(不是全局上限)
routes:
github-pr-review:
secret: "your-webhook-secret-here" # 必须与 GitHub webhook secret 完全匹配
events:
- pull_request
# 指示 agent 在 review 之前获取实际 diff。
# {number} 和 {repository.full_name} 会从 GitHub payload 中解析。
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_comment
deliver_extra:
repo: "{repository.full_name}"
pr_number: "{number}"

关键字段:

字段描述
secret(route 级别)此 route 的 HMAC secret。如果省略,则回退到 extra.secret 全局值。
events要接受的 X-GitHub-Event header 值列表。空列表 = 接受全部。
prompt模板;{field}{nested.field} 会从 GitHub payload 中解析。
delivergithub_comment 会通过 gh pr comment 发布。log 只会写入 gateway 日志。
deliver_extra.repo从 payload 中解析为例如 org/repo
deliver_extra.pr_number从 payload 中解析 PR 编号。
Terminal window
hermes gateway

你应该会看到:

[webhook] Listening on 0.0.0.0:8644 — routes: github-pr-review

验证它正在运行:

Terminal window
curl http://localhost:8644/health
# {"status": "ok", "platform": "webhook"}

步骤 3 —— 在 GitHub 上注册 webhook

Section titled “步骤 3 —— 在 GitHub 上注册 webhook”
  1. 进入你的仓库 → Settings → Webhooks → Add webhook

  2. 填写:

  • Payload URL:https://your-public-url.example.com/webhooks/github-pr-review
  • Content type:application/json
  • Secret:与你在 route 配置中为 secret 设置的值相同
  • Which events? → Select individual events → 勾选 Pull requests
  1. 点击 Add webhook

GitHub 会立即发送一个 ping 事件来确认连接。它会被安全忽略——因为 ping 不在你的 events 列表中——并返回 {"status": "ignored", "event": "ping"}。它只会以 DEBUG 级别记录,因此在默认日志级别下不会出现在控制台中。

创建一个分支,推送一个变更,并打开一个 PR。在 30–90 秒内(取决于 PR 大小和模型),Hermes 应该会发布一条 review comment。

要实时跟踪 agent 的进度:

Terminal window
tail -f "${HERMES_HOME:-$HOME/.hermes}/logs/gateway.log"

如果 Hermes 正在你的笔记本电脑上运行,请使用 ngrok 暴露它:

Terminal window
ngrok http 8644

复制 https://...ngrok-free.app URL,并将其用作你的 GitHub Payload URL。在免费 ngrok 层级中,每次 ngrok 重启时 URL 都会变化——每个 session 都需要更新你的 GitHub webhook。付费 ngrok 账号可以获得静态域名。

你可以直接使用 curl 对静态 route 进行冒烟测试——不需要 GitHub 账号,也不需要真实 PR。

Terminal window
SECRET="your-webhook-secret-here"
BODY='{"action":"opened","number":99,"pull_request":{"title":"Test PR","body":"Adds a feature.","user":{"login":"testuser"},"head":{"ref":"feat/x"},"base":{"ref":"main"},"html_url":"https://github.com/org/repo/pull/99"},"repository":{"full_name":"org/repo"}}'
SIG=$(printf '%s' "$BODY" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print "sha256="$2}')
curl -s -X POST http://localhost:8644/webhooks/github-pr-review \
-H "Content-Type: application/json" \
-H "X-GitHub-Event: pull_request" \
-H "X-Hub-Signature-256: $SIG" \
-d "$BODY"
# Expected: {"status":"accepted","route":"github-pr-review","event":"pull_request","delivery_id":"..."}

然后观察 agent 运行:

Terminal window
tail -f "${HERMES_HOME:-$HOME/.hermes}/logs/gateway.log"

GitHub 会为许多 actions 发送 pull_request 事件:openedsynchronizereopenedclosedlabeled 等。events 列表只会按 X-GitHub-Event header 值过滤——它不能在 routing 级别按 action 子类型过滤。

步骤 1 中的 prompt 已经通过指示 agent 对 closedlabeled 事件提前停止来处理这一点。

没有 Jinja2 或条件模板语法。{field}{nested.field} 是唯一支持的替换。其他任何内容都会原样传给 agent。

使用 skill 保持一致的 review 风格

Section titled “使用 skill 保持一致的 review 风格”

加载一个 Hermes skill,让 agent 拥有一致的 review persona。在 config.yaml 中,将 skills 添加到 platforms.webhook.extra.routes 内的 route:

platforms:
webhook:
enabled: true
extra:
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:
- review
deliver: github_comment
deliver_extra:
repo: "{repository.full_name}"
pr_number: "{number}"

注意:只会加载列表中找到的第一个 skill。Hermes 不会叠加多个 skills——后续条目会被忽略。

改为将响应发送到 Slack 或 Discord

Section titled “改为将响应发送到 Slack 或 Discord”

将你的 route 内的 deliverdeliver_extra 字段替换为目标平台:

# Inside platforms.webhook.extra.routes.<route-name>:
# Slack
deliver: slack
deliver_extra:
chat_id: "C0123456789" # Slack channel ID(省略则使用已配置的 home channel)
# Discord
deliver: discord
deliver_extra:
chat_id: "987654321012345678" # Discord channel ID(省略则使用 home channel)

目标平台也必须在 gateway 中启用并连接。如果省略 chat_id,响应会发送到该平台已配置的 home channel。

有效的 deliver 值:log · github_comment · telegram · discord · slack · signal · sms

同一个 adapter 也适用于 GitLab。GitLab 使用 X-Gitlab-Token 进行认证(普通字符串匹配,不是 HMAC)——Hermes 会自动处理两者。

对于 event filtering,GitLab 会将 X-GitLab-Event 设置为类似 Merge Request HookPush HookPipeline Hook 的值。请在 events 中使用精确的 header 值:

events:
- Merge Request Hook

GitLab payload 字段与 GitHub 不同——例如 MR 标题使用 {object_attributes.title},MR 编号使用 {object_attributes.iid}。发现完整 payload 结构的最简单方式,是使用 GitLab webhook 设置中的 Test 按钮,并结合 Recent Deliveries 日志。或者,从你的 route config 中省略 prompt——Hermes 随后会将完整 payload 作为格式化 JSON 直接传给 agent,而 agent 的响应(在 deliver: log 的 gateway 日志中可见)会描述其结构。

  • 永远不要在生产环境中使用 INSECURE_NO_AUTH——它会完全禁用签名验证。它仅用于本地开发。
  • 定期轮换你的 webhook secret,并同时在 GitHub(webhook 设置)和你的 config.yaml 中更新它。
  • 默认 rate limiting 为每个 route 每分钟 30 个请求(可通过 extra.rate_limit 配置)。超过限制会返回 429。
  • 重复 deliveries(webhook retries)会通过 1 小时 idempotency cache 去重。cache key 优先使用 X-GitHub-Delivery(如果存在),然后是 X-Request-ID,最后是毫秒级时间戳。当两个 delivery ID header 都没有设置时,retries 不会被去重。
  • Prompt injection:PR 标题、描述和 commit messages 都是攻击者可控的。恶意 PR 可能尝试操纵 agent 的行为。当暴露到公网时,请在沙箱环境(Docker、VM)中运行 gateway。
症状检查
401 Invalid signatureconfig.yaml 中的 secret 与 GitHub webhook secret 不匹配
404 Unknown routeURL 中的 route name 与 routes: 中的 key 不匹配
429 Rate limit exceeded超过了每个 route 每分钟 30 个请求——从 GitHub UI 重新发送 test events 时很常见;等待一分钟或提高 extra.rate_limit
没有发布 commentgh 未安装、不在 PATH 中,或未认证(gh auth login
Agent 运行了但没有 comment检查 gateway 日志——如果 agent 输出为空或只是 “SKIP”,仍然会尝试 delivery
端口已被占用修改 config.yaml 中的 extra.port
Agent 运行了但只 review PR descriptionprompt 没有包含 gh pr diff 指令——diff 不在 webhook payload 中
看不到 ping event被忽略的 events 会返回 {"status":"ignored","event":"ping"},且只在 DEBUG 日志级别记录——请检查 GitHub 的 delivery log(repo → Settings → Webhooks → your webhook → Recent Deliveries)

GitHub 的 Recent Deliveries tab(repo → Settings → Webhooks → your webhook)会显示每次 delivery 的精确 request headers、payload、HTTP status 和 response body。它是在不查看服务器日志的情况下诊断故障的最快方式。

platforms:
webhook:
enabled: true
extra:
host: "0.0.0.0" # 绑定地址(默认:0.0.0.0)
port: 8644 # 监听端口(默认:8644)
secret: "" # 可选的全局 fallback secret
rate_limit: 30 # 每个 route 每分钟请求数
max_body_bytes: 1048576 # payload 大小限制,单位字节(默认:1 MB)
routes:
<route-name>:
secret: "required-per-route"
events: [] # [] = 接受全部;否则列出 X-GitHub-Event 值
prompt: "" # 从 payload 中解析 {field} / {nested.field}
skills: [] # 加载第一个匹配的 skill(仅一个)
deliver: "log" # log | github_comment | telegram | discord | slack | signal | sms
deliver_extra: {} # github_comment 使用 repo + pr_number;其他平台使用 chat_id
  • Cron-Based PR Reviews —— 按计划轮询 PR,不需要公网 endpoint
  • Webhook Reference —— webhook platform 的完整配置参考
  • Build a Plugin —— 将 review 逻辑打包成可共享 plugin
  • Profiles —— 使用专用 reviewer profile 运行,拥有自己的 memory 和 config
-
0:000:00