本指南将引导你把 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 主机上安装并认证
ghCLI(gh auth login) - 你的 Hermes 实例拥有一个公网可访问的 URL(如果在本地运行,请参见使用 ngrok 进行本地测试)
- 拥有 GitHub 仓库的管理员权限(管理 webhooks 需要)
步骤 1 —— 启用 webhook 平台
Section titled “步骤 1 —— 启用 webhook 平台”将以下内容添加到你的 ~/.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 中解析。 |
deliver | github_comment 会通过 gh pr comment 发布。log 只会写入 gateway 日志。 |
deliver_extra.repo | 从 payload 中解析为例如 org/repo。 |
deliver_extra.pr_number | 从 payload 中解析 PR 编号。 |
步骤 2 —— 启动 gateway
Section titled “步骤 2 —— 启动 gateway”hermes gateway你应该会看到:
[webhook] Listening on 0.0.0.0:8644 — routes: github-pr-review验证它正在运行:
curl http://localhost:8644/health# {"status": "ok", "platform": "webhook"}步骤 3 —— 在 GitHub 上注册 webhook
Section titled “步骤 3 —— 在 GitHub 上注册 webhook”-
进入你的仓库 → Settings → Webhooks → Add webhook
-
填写:
- 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
- 点击 Add webhook
GitHub 会立即发送一个 ping 事件来确认连接。它会被安全忽略——因为 ping 不在你的 events 列表中——并返回 {"status": "ignored", "event": "ping"}。它只会以 DEBUG 级别记录,因此在默认日志级别下不会出现在控制台中。
步骤 4 —— 打开一个测试 PR
Section titled “步骤 4 —— 打开一个测试 PR”创建一个分支,推送一个变更,并打开一个 PR。在 30–90 秒内(取决于 PR 大小和模型),Hermes 应该会发布一条 review comment。
要实时跟踪 agent 的进度:
tail -f "${HERMES_HOME:-$HOME/.hermes}/logs/gateway.log"使用 ngrok 进行本地测试
Section titled “使用 ngrok 进行本地测试”如果 Hermes 正在你的笔记本电脑上运行,请使用 ngrok 暴露它:
ngrok http 8644复制 https://...ngrok-free.app URL,并将其用作你的 GitHub Payload URL。在免费 ngrok 层级中,每次 ngrok 重启时 URL 都会变化——每个 session 都需要更新你的 GitHub webhook。付费 ngrok 账号可以获得静态域名。
你可以直接使用 curl 对静态 route 进行冒烟测试——不需要 GitHub 账号,也不需要真实 PR。
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 运行:
tail -f "${HERMES_HOME:-$HOME/.hermes}/logs/gateway.log"过滤到特定 actions
Section titled “过滤到特定 actions”GitHub 会为许多 actions 发送 pull_request 事件:opened、synchronize、reopened、closed、labeled 等。events 列表只会按 X-GitHub-Event header 值过滤——它不能在 routing 级别按 action 子类型过滤。
步骤 1 中的 prompt 已经通过指示 agent 对 closed 和 labeled 事件提前停止来处理这一点。
没有 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 内的 deliver 和 deliver_extra 字段替换为目标平台:
# Inside platforms.webhook.extra.routes.<route-name>:
# Slackdeliver: slackdeliver_extra: chat_id: "C0123456789" # Slack channel ID(省略则使用已配置的 home channel)
# Discorddeliver: discorddeliver_extra: chat_id: "987654321012345678" # Discord channel ID(省略则使用 home channel)目标平台也必须在 gateway 中启用并连接。如果省略 chat_id,响应会发送到该平台已配置的 home channel。
有效的 deliver 值:log · github_comment · telegram · discord · slack · signal · sms
GitLab 支持
Section titled “GitLab 支持”同一个 adapter 也适用于 GitLab。GitLab 使用 X-Gitlab-Token 进行认证(普通字符串匹配,不是 HMAC)——Hermes 会自动处理两者。
对于 event filtering,GitLab 会将 X-GitLab-Event 设置为类似 Merge Request Hook、Push Hook、Pipeline Hook 的值。请在 events 中使用精确的 header 值:
events: - Merge Request HookGitLab 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 signature | config.yaml 中的 secret 与 GitHub webhook secret 不匹配 |
404 Unknown route | URL 中的 route name 与 routes: 中的 key 不匹配 |
429 Rate limit exceeded | 超过了每个 route 每分钟 30 个请求——从 GitHub UI 重新发送 test events 时很常见;等待一分钟或提高 extra.rate_limit |
| 没有发布 comment | gh 未安装、不在 PATH 中,或未认证(gh auth login) |
| Agent 运行了但没有 comment | 检查 gateway 日志——如果 agent 输出为空或只是 “SKIP”,仍然会尝试 delivery |
| 端口已被占用 | 修改 config.yaml 中的 extra.port |
| Agent 运行了但只 review PR description | prompt 没有包含 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。它是在不查看服务器日志的情况下诊断故障的最快方式。
完整配置参考
Section titled “完整配置参考”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接下来做什么?
Section titled “接下来做什么?”- Cron-Based PR Reviews —— 按计划轮询 PR,不需要公网 endpoint
- Webhook Reference —— webhook platform 的完整配置参考
- Build a Plugin —— 将 review 逻辑打包成可共享 plugin
- Profiles —— 使用专用 reviewer profile 运行,拥有自己的 memory 和 config