H繁中版
<!-- Source: https://hermesbible.com/docs/user-guide/messaging/webhooks -->

Section: Messaging Platforms · URL: https://hermesbible.com/docs/user-guide/messaging/webhooks

從外部服務(GitHub、GitLab、JIRA、Stripe 等)接收事件,並自動觸發 Hermes agent 執行。Webhook adapter 會運行一個 HTTP 伺服器,接受 POST 請求、驗證 HMAC 簽名、將 payload 轉換為 agent prompt,然後將回應路由回原始來源或其他已設定的平台。

Agent 會處理事件,並可以透過在 PR 上發佈留言、發送訊息到 Telegram/Discord,或記錄結果來回應。

影片教學

影片: 在 YouTube 上觀看


快速開始

  1. 透過 hermes gateway setup 或環境變數啟用
  2. config.yaml 中定義路由,使用 hermes webhook subscribe 動態建立
  3. 將你的服務指向 http://your-server:8644/webhooks/<route-name>

設定

有兩種方式可以啟用 webhook adapter。

透過設定精靈

hermes gateway setup

按照提示啟用 webhooks、設定連接埠,以及設定全域 HMAC 密鑰。

透過環境變數

~/.hermes/.env 中加入:

WEBHOOK_ENABLED=true
WEBHOOK_PORT=8644        # 預設值
WEBHOOK_SECRET=your-global-secret

驗證伺服器

Gateway 啟動後:

curl http://localhost:8644/health

預期回應:

{"status": "ok", "platform": "webhook"}

設定路由 {#configuring-routes}

路由定義了不同 webhook 來源的處理方式。每個路由是 config.yamlplatforms.webhook.extra.routes 下的一個具名條目。

路由屬性

屬性必要描述
events要接受的事件類型清單(例如 ["pull_request"])。若為空,則接受所有事件。事件類型從 payload 中的 X-GitHub-EventX-GitLab-Eventevent_type 讀取。
secret用於簽名驗證的 HMAC 密鑰。若路由未設定,則回退至全域 secret。僅供測試時設為 "INSECURE_NO_AUTH"(跳過驗證)。
prompt使用點號表示法存取 payload 的模板字串(例如 {pull_request.title})。若省略,完整的 JSON payload 會被導入 prompt。
skillsAgent 執行時載入的 skill 名稱清單。
deliver回應的傳送目標:github_commenttelegramdiscordslacksignalsmswhatsappmatrixmattermosthomeassistantemaildingtalkfeishuwecomweixinbluebubblesqqbotlog(預設)。
deliver_extra額外的傳送設定 — 鍵值取決於 deliver 類型(例如 repopr_numberchat_id)。值支援與 prompt 相同的 {dot.notation} 模板。
deliver_only若為 true,則完全跳過 agent — 渲染後的 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"

Prompt 模板

Prompt 使用點號表示法來存取 webhook payload 中的巢狀欄位:

  • {pull_request.title} 會解析為 payload["pull_request"]["title"]
  • {repository.full_name} 會解析為 payload["repository"]["full_name"]
  • {__raw__} — 特殊 token,將整個 payload 以縮排 JSON 輸出(截斷於 4000 字元)。適用於監控告警或需要完整上下文的通用 webhook。
  • 缺失的鍵會保留為字面 {key} 字串(不會報錯)
  • 巢狀字典和列表會被 JSON 序列化並截斷於 2000 字元

你可以混用 {__raw__} 與一般模板變數:

prompt: "PR #{pull_request.number} by {pull_request.user.login}: {__raw__}"

若路由未設定 prompt 模板,完整的 payload 會以縮排 JSON 輸出(截斷於 4000 字元)。

相同的點號表示法模板也可用於 deliver_extra 的值。

論壇主題傳送

將 webhook 回應傳送到 Telegram 時,可以透過在 deliver_extra 中加入 message_thread_id(或 thread_id)來指定特定的論壇主題:

webhooks:
  routes:
    alerts:
      events: ["alert"]
      prompt: "Alert: {__raw__}"
      deliver: "telegram"
      deliver_extra:
        chat_id: "-1001234567890"
        message_thread_id: "42"

deliver_extra 中未提供 chat_id,則會回退至目標平台已設定的首頁頻道。


GitHub PR Review(逐步教學){#github-pr-review}

本教學將設定每個 pull request 的自動程式碼審查。

1. 在 GitHub 中建立 webhook

  1. 前往你的 repository → SettingsWebhooksAdd webhook
  2. Payload URL 設為 http://your-server:8644/webhooks/github-pr
  3. Content type 設為 application/json
  4. Secret 設為與你的路由設定相符(例如 github-webhook-secret
  5. Which events? 下方,選擇 Let me select individual events 並勾選 Pull requests
  6. 點擊 Add webhook

2. 加入路由設定

github-pr 路由加入你的 ~/.hermes/config.yaml,如上方範例所示。

3. 確認 gh CLI 已完成驗證

github_comment 傳送類型使用 GitHub CLI 來發佈留言:

gh auth login

4. 測試

在 repository 上開啟一個 pull request。Webhook 會觸發,Hermes 處理事件,並在 PR 上發佈審查留言。


GitLab Webhook 設定 {#gitlab-webhook-setup}

GitLab webhook 的運作方式類似,但使用不同的認證機制。GitLab 將密鑰以純文字 X-Gitlab-Token header 傳送(完全字串比對,非 HMAC)。

1. 在 GitLab 中建立 webhook

  1. 前往你的專案 → SettingsWebhooks
  2. URL 設為 http://your-server:8644/webhooks/gitlab-mr
  3. 輸入你的 Secret token
  4. 選擇 Merge request events(以及其他你想要的事件)
  5. 點擊 Add webhook

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 欄位控制 agent 在處理 webhook 事件後的回應傳送目標。

傳送類型描述
log將回應記錄到 gateway log 輸出。這是預設值,適用於測試。
github_comment透過 gh CLI 將回應發佈為 PR/issue 留言。需要 deliver_extra.repodeliver_extra.pr_numbergh CLI 必須安裝在 gateway 主機上並完成驗證(gh auth login)。
telegram將回應路由到 Telegram。使用首頁頻道,或在 deliver_extra 中指定 chat_id
discord將回應路由到 Discord。使用首頁頻道,或在 deliver_extra 中指定 chat_id
slack將回應路由到 Slack。使用首頁頻道,或在 deliver_extra 中指定 chat_id
signal將回應路由到 Signal。使用首頁頻道,或在 deliver_extra 中指定 chat_id
sms透過 Twilio 將回應路由到 SMS。使用首頁頻道,或在 deliver_extra 中指定 chat_id
whatsapp將回應路由到 WhatsApp。使用首頁頻道,或在 deliver_extra 中指定 chat_id
matrix將回應路由到 Matrix。使用首頁頻道,或在 deliver_extra 中指定 chat_id
mattermost將回應路由到 Mattermost。使用首頁頻道,或在 deliver_extra 中指定 chat_id
homeassistant將回應路由到 Home Assistant。使用首頁頻道,或在 deliver_extra 中指定 chat_id
email將回應路由到 Email。使用首頁頻道,或在 deliver_extra 中指定 chat_id
dingtalk將回應路由到 DingTalk。使用首頁頻道,或在 deliver_extra 中指定 chat_id
feishu將回應路由到 Feishu/Lark。使用首頁頻道,或在 deliver_extra 中指定 chat_id
wecom將回應路由到 WeCom。使用首頁頻道,或在 deliver_extra 中指定 chat_id
weixin將回應路由到 Weixin(微信)。使用首頁頻道,或在 deliver_extra 中指定 chat_id
bluebubbles將回應路由到 BlueBubbles(iMessage)。使用首頁頻道,或在 deliver_extra 中指定 chat_id

若要跨平台傳送,目標平台也必須在 gateway 中啟用並連線。若 deliver_extra 中未提供 chat_id,則回應會傳送到該平台已設定的首頁頻道。


直接傳送模式 {#direct-delivery-mode}

預設情況下,每個 webhook POST 都會觸發 agent 執行 — payload 成為 prompt,agent 處理它,然後 agent 的回應被傳送出去。每次事件都會消耗 LLM token。

如果你只想推送純文字通知 — 不需要推理、不需要 agent 迴圈,只須傳送訊息 — 則在路由上設定 deliver_only: true。渲染後的 prompt 模板會成為實際的訊息內容,adapter 會直接將其分發到已設定的傳送目標。

何時使用直接傳送

  • 外部服務推送 — Supabase/Firebase webhook 在資料庫變更時觸發 → 即時通知 Telegram 使用者
  • 監控告警 — Datadog/Grafana alert webhook → 推送到 Discord 頻道
  • Agent 間通知 — Agent A 通知 Agent B 的使用者長時間運行的任務已完成
  • 背景工作完成 — Cron job 完成 → 將結果發佈到 Slack

優點:

  • 零 LLM token — 永遠不會呼叫 agent
  • 亞秒級傳送 — 單次 adapter 呼叫,無推理迴圈
  • 與 agent 模式相同的安全性 — HMAC 驗證、速率限制、冪等性、body 大小限制全部適用
  • 同步回應 — POST 在傳送成功時回傳 200 OK,若目標拒絕則回傳 502,讓你的上游服務可以智慧重試

範例:從 Supabase 推送到 Telegram

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 edge function 使用 HMAC-SHA256 對 payload 簽名,然後 POST 到 https://your-server:8644/webhooks/antenna-matches。Webhook adapter 驗證簽名、從 payload 渲染模板、傳送到 Telegram,然後回傳 200 OK

範例:透過 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"

回應代碼

狀態碼含義
200 OK傳送成功。Body:{"status": "delivered", "route": "...", "target": "...", "delivery_id": "..."}
200 OK(status=duplicate)在冪等性 TTL(1 小時)內重複的 X-GitHub-Delivery ID。不會重新傳送。
401 UnauthorizedHMAC 簽名無效或缺失。
400 Bad RequestJSON body 格式錯誤。
404 Not Found未知的路由名稱。
413 Payload Too LargeBody 超過 max_body_bytes 限制。
429 Too Many Requests超過路由速率限制。
502 Bad Gateway目標 adapter 拒絕了訊息或發生錯誤。錯誤會記錄在伺服器端;回應 body 為通用的 Delivery failed,以避免洩露 adapter 內部細節。

設定注意事項

  • deliver_only: true 需要 deliver 為真實目標。deliver: log(或省略 deliver)會在啟動時被拒絕 — 若 adapter 發現設定錯誤的路由,會拒絕啟動。
  • skills 欄位在直接傳送模式下會被忽略(不會執行 agent,因此無處注入 skill)。
  • 模板渲染使用與 agent 模式相同的 {dot.notation} 語法,包含 {__raw__} token。
  • 冪等性使用相同的 X-GitHub-Delivery / X-Request-ID header — 以相同 ID 重試會回傳 status=duplicate不會重新傳送。

動態訂閱(CLI){#dynamic-subscriptions}

除了 config.yaml 中的靜態路由外,你也可以使用 hermes webhook CLI 指令動態建立 webhook 訂閱。這在 agent 本身需要設定事件驅動觸發器時特別有用。

建立訂閱

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"

這會回傳 webhook URL 和自動產生的 HMAC 密鑰。將你的服務設定為 POST 到該 URL。

列出訂閱

hermes webhook list

移除訂閱

hermes webhook remove github-issues

測試訂閱

hermes webhook test github-issues
hermes webhook test github-issues --payload '{"issue": {"number": 42, "title": "Test"}}'

動態訂閱的運作方式

  • 訂閱儲存在 ~/.hermes/webhook_subscriptions.json
  • Webhook adapter 在每個收到的請求時都會熱重載此檔案(基於 mtime 門控,開銷可忽略不計)
  • config.yaml 中的靜態路由永遠優先於同名的動態路由
  • 動態訂閱使用與靜態路由相同的路由格式和功能(events、prompt 模板、skills、deliver)
  • 不需要重新啟動 gateway — 訂閱後立即生效

Agent 驅動的訂閱

Agent 可以透過終端工具建立訂閱(需由 webhook-subscriptions skill 引導)。向 agent 說「幫我為 GitHub issues 設定一個 webhook」,它會執行適當的 hermes webhook subscribe 指令。


安全性 {#security}

Webhook adapter 包含多層安全機制:

HMAC 簽名驗證

Adapter 使用每個來源的對應方法來驗證傳入的 webhook 簽名:

  • GitHubX-Hub-Signature-256 header — 以 sha256= 為前綴的 HMAC-SHA256 十六進位摘要
  • GitLabX-Gitlab-Token header — 純文字密鑰字串比對
  • 通用X-Webhook-Signature header — 原始 HMAC-SHA256 十六進位摘要

若設定了密鑰但未提供可識別的簽名 header,則請求會被拒絕。

密鑰為必要條件

每個路由都必須設有密鑰 — 可以直接在路由上設定,或從全域 secret 繼承。沒有密鑰的路由會導致 adapter 在啟動時因錯誤而失敗。僅供開發/測試時使用,你可以將密鑰設為 "INSECURE_NO_AUTH" 以完全跳過驗證。

INSECURE_NO_AUTH 僅在 gateway 綁定到回送地址(127.0.0.1localhost::1)時才被接受。若與非回送地址(如 0.0.0.0 或區域網路 IP)搭配使用,adapter 會拒絕啟動 — 這可以防止在公開介面上意外暴露未認證的端點。

速率限制

每個路由預設限制為每分鐘 30 個請求(固定時間窗口)。可全域設定:

platforms:
  webhook:
    extra:
      rate_limit: 60  # 每分鐘請求數

超過限制的請求會收到 429 Too Many Requests 回應。

冪等性

傳送 ID(來自 X-GitHub-DeliveryX-Request-ID,或基於時間戳記的回退值)會快取 1 小時。重複的傳送(例如 webhook 重試)會被靜默跳過並回傳 200,以防止重複的 agent 執行。

Body 大小限制

超過 1 MB 的 payload 會在讀取 body 前被拒絕。可設定:

platforms:
  webhook:
    extra:
      max_body_bytes: 2097152  # 2 MB

Prompt 注入風險

警告

Webhook payload 包含攻擊者控制的資料 — PR 標題、提交訊息、issue 描述等都可能包含惡意指令。當暴露於網際網路時,請在沙箱環境(Docker、VM)中運行 gateway。建議使用 Docker 或 SSH 終端後端來隔離。


疑難排解 {#troubleshooting}

Webhook 未到達

  • 確認連接埠已暴露且可從 webhook 來源存取
  • 檢查防火牆規則 — 連接埠 8644(或你設定的連接埠)必須開放
  • 確認 URL 路徑正確:http://your-server:8644/webhooks/<route-name>
  • 使用 /health 端點確認伺服器正在運行

簽名驗證失敗

  • 確保路由設定中的密鑰與 webhook 來源設定的密鑰完全一致
  • GitHub 的密鑰是 HMAC 驗證 — 檢查 X-Hub-Signature-256
  • GitLab 的密鑰是純文字比對 — 檢查 X-Gitlab-Token
  • 檢查 gateway logs 是否有 Invalid signature 警告

事件被忽略

  • 確認事件類型在你路由的 events 清單中
  • GitHub 事件使用 pull_requestpushissues 等值(X-GitHub-Event header 的值)
  • GitLab 事件使用 merge_requestpush 等值(X-GitLab-Event header 的值)
  • events 為空或未設定,則接受所有事件

Agent 未回應

  • 以前台模式運行 gateway 以查看 logs:hermes gateway run
  • 確認 prompt 模板正確渲染
  • 確認傳送目標已設定且已連線

重複回應

  • 冪等性快取應可防止此問題 — 確認 webhook 來源有傳送 delivery ID header(X-GitHub-DeliveryX-Request-ID
  • Delivery ID 快取時間為 1 小時

gh CLI 錯誤(GitHub 留言傳送)

  • 在 gateway 主機上執行 gh auth login
  • 確認已驗證的 GitHub 使用者對該 repository 有寫入權限
  • 確認 gh 已安裝且在 PATH 中

環境變數 {#environment-variables}

變數描述預設值
WEBHOOK_ENABLED啟用 webhook 平台 adapterfalse
WEBHOOK_PORT接收 webhooks 的 HTTP 伺服器連接埠8644
WEBHOOK_SECRET全域 HMAC 密鑰(在路由未指定時作為回退)(無)


BlueBubbles(iMessage)