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 上觀看
快速開始
- 透過
hermes gateway setup或環境變數啟用 - 在
config.yaml中定義路由,或使用hermes webhook subscribe動態建立 - 將你的服務指向
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.yaml 中 platforms.webhook.extra.routes 下的一個具名條目。
路由屬性
| 屬性 | 必要 | 描述 |
|---|---|---|
events | 否 | 要接受的事件類型清單(例如 ["pull_request"])。若為空,則接受所有事件。事件類型從 payload 中的 X-GitHub-Event、X-GitLab-Event 或 event_type 讀取。 |
secret | 是 | 用於簽名驗證的 HMAC 密鑰。若路由未設定,則回退至全域 secret。僅供測試時設為 "INSECURE_NO_AUTH"(跳過驗證)。 |
prompt | 否 | 使用點號表示法存取 payload 的模板字串(例如 {pull_request.title})。若省略,完整的 JSON payload 會被導入 prompt。 |
skills | 否 | Agent 執行時載入的 skill 名稱清單。 |
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)。值支援與 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
- 前往你的 repository → 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 路由加入你的 ~/.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
- 前往你的專案 → 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: "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.repo 和 deliver_extra.pr_number。gh 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 Unauthorized | HMAC 簽名無效或缺失。 |
400 Bad Request | JSON body 格式錯誤。 |
404 Not Found | 未知的路由名稱。 |
413 Payload Too Large | Body 超過 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-IDheader — 以相同 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 簽名:
- GitHub:
X-Hub-Signature-256header — 以sha256=為前綴的 HMAC-SHA256 十六進位摘要 - GitLab:
X-Gitlab-Tokenheader — 純文字密鑰字串比對 - 通用:
X-Webhook-Signatureheader — 原始 HMAC-SHA256 十六進位摘要
若設定了密鑰但未提供可識別的簽名 header,則請求會被拒絕。
密鑰為必要條件
每個路由都必須設有密鑰 — 可以直接在路由上設定,或從全域 secret 繼承。沒有密鑰的路由會導致 adapter 在啟動時因錯誤而失敗。僅供開發/測試時使用,你可以將密鑰設為 "INSECURE_NO_AUTH" 以完全跳過驗證。
INSECURE_NO_AUTH 僅在 gateway 綁定到回送地址(127.0.0.1、localhost、::1)時才被接受。若與非回送地址(如 0.0.0.0 或區域網路 IP)搭配使用,adapter 會拒絕啟動 — 這可以防止在公開介面上意外暴露未認證的端點。
速率限制
每個路由預設限制為每分鐘 30 個請求(固定時間窗口)。可全域設定:
platforms:
webhook:
extra:
rate_limit: 60 # 每分鐘請求數
超過限制的請求會收到 429 Too Many Requests 回應。
冪等性
傳送 ID(來自 X-GitHub-Delivery、X-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_request、push、issues等值(X-GitHub-Eventheader 的值) - GitLab 事件使用
merge_request、push等值(X-GitLab-Eventheader 的值) - 若
events為空或未設定,則接受所有事件
Agent 未回應
- 以前台模式運行 gateway 以查看 logs:
hermes gateway run - 確認 prompt 模板正確渲染
- 確認傳送目標已設定且已連線
重複回應
- 冪等性快取應可防止此問題 — 確認 webhook 來源有傳送 delivery ID header(
X-GitHub-Delivery或X-Request-ID) - Delivery ID 快取時間為 1 小時
gh CLI 錯誤(GitHub 留言傳送)
- 在 gateway 主機上執行
gh auth login - 確認已驗證的 GitHub 使用者對該 repository 有寫入權限
- 確認
gh已安裝且在 PATH 中
環境變數 {#environment-variables}
| 變數 | 描述 | 預設值 |
|---|---|---|
WEBHOOK_ENABLED | 啟用 webhook 平台 adapter | false |
WEBHOOK_PORT | 接收 webhooks 的 HTTP 伺服器連接埠 | 8644 |
WEBHOOK_SECRET | 全域 HMAC 密鑰(在路由未指定時作為回退) | (無) |