Hermes-agent webhook-subscriptions
Create and manage webhook subscriptions for event-driven agent activation, or for direct push notifications (zero LLM cost). Use when the user wants external services to trigger agent runs OR push notifications to chats.
git clone https://github.com/NousResearch/hermes-agent
T=$(mktemp -d) && git clone --depth=1 https://github.com/NousResearch/hermes-agent "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/devops/webhook-subscriptions" ~/.claude/skills/nousresearch-hermes-agent-webhook-subscriptions-570fc0 && rm -rf "$T"
skills/devops/webhook-subscriptions/SKILL.mdWebhook Subscriptions
Create dynamic webhook subscriptions so external services (GitHub, GitLab, Stripe, CI/CD, IoT sensors, monitoring tools) can trigger Hermes agent runs by POSTing events to a URL.
Setup (Required First)
The webhook platform must be enabled before subscriptions can be created. Check with:
hermes webhook list
If it says "Webhook platform is not enabled", set it up:
Option 1: Setup wizard
hermes gateway setup
Follow the prompts to enable webhooks, set the port, and set a global HMAC secret.
Option 2: Manual config
Add to
~/.hermes/config.yaml:
platforms: webhook: enabled: true extra: host: "0.0.0.0" port: 8644 secret: "generate-a-strong-secret-here"
Option 3: Environment variables
Add to
~/.hermes/.env:
WEBHOOK_ENABLED=true WEBHOOK_PORT=8644 WEBHOOK_SECRET=generate-a-strong-secret-here
After configuration, start (or restart) the gateway:
hermes gateway run # Or if using systemd: systemctl --user restart hermes-gateway
Verify it's running:
curl http://localhost:8644/health
Commands
All management is via the
hermes webhook CLI command:
Create a subscription
hermes webhook subscribe <name> \ --prompt "Prompt template with {payload.fields}" \ --events "event1,event2" \ --description "What this does" \ --skills "skill1,skill2" \ --deliver telegram \ --deliver-chat-id "12345" \ --secret "optional-custom-secret"
Returns the webhook URL and HMAC secret. The user configures their service to POST to that URL.
List subscriptions
hermes webhook list
Remove a subscription
hermes webhook remove <name>
Test a subscription
hermes webhook test <name> hermes webhook test <name> --payload '{"key": "value"}'
Prompt Templates
Prompts support
{dot.notation} for accessing nested payload fields:
— GitHub issue title{issue.title}
— PR author{pull_request.user.login}
— Stripe payment amount{data.object.amount}
— IoT sensor reading{sensor.temperature}
If no prompt is specified, the full JSON payload is dumped into the agent prompt.
Common Patterns
GitHub: new issues
hermes webhook subscribe github-issues \ --events "issues" \ --prompt "New GitHub issue #{issue.number}: {issue.title}\n\nAction: {action}\nAuthor: {issue.user.login}\nBody:\n{issue.body}\n\nPlease triage this issue." \ --deliver telegram \ --deliver-chat-id "-100123456789"
Then in GitHub repo Settings → Webhooks → Add webhook:
- Payload URL: the returned webhook_url
- Content type: application/json
- Secret: the returned secret
- Events: "Issues"
GitHub: PR reviews
hermes webhook subscribe github-prs \ --events "pull_request" \ --prompt "PR #{pull_request.number} {action}: {pull_request.title}\nBy: {pull_request.user.login}\nBranch: {pull_request.head.ref}\n\n{pull_request.body}" \ --skills "github-code-review" \ --deliver github_comment
Stripe: payment events
hermes webhook subscribe stripe-payments \ --events "payment_intent.succeeded,payment_intent.payment_failed" \ --prompt "Payment {data.object.status}: {data.object.amount} cents from {data.object.receipt_email}" \ --deliver telegram \ --deliver-chat-id "-100123456789"
CI/CD: build notifications
hermes webhook subscribe ci-builds \ --events "pipeline" \ --prompt "Build {object_attributes.status} on {project.name} branch {object_attributes.ref}\nCommit: {commit.message}" \ --deliver discord \ --deliver-chat-id "1234567890"
Generic monitoring alert
hermes webhook subscribe alerts \ --prompt "Alert: {alert.name}\nSeverity: {alert.severity}\nMessage: {alert.message}\n\nPlease investigate and suggest remediation." \ --deliver origin
Direct delivery (no agent, zero LLM cost)
For use cases where you just want to push a notification through to a user's chat — no reasoning, no agent loop — add
--deliver-only. The rendered --prompt template becomes the literal message body and is dispatched directly to the target adapter.
Use this for:
- External service push notifications (Supabase/Firebase webhooks → Telegram)
- Monitoring alerts that should forward verbatim
- Inter-agent pings where one agent is telling another agent's user something
- Any webhook where an LLM round trip would be wasted effort
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"
The POST returns
200 OK on successful delivery, 502 on target failure — so upstream services can retry intelligently. HMAC auth, rate limits, and idempotency still apply.
Requires
--deliver to be a real target (telegram, discord, slack, github_comment, etc.) — --deliver log is rejected because log-only direct delivery is pointless.
Security
- Each subscription gets an auto-generated HMAC-SHA256 secret (or provide your own with
)--secret - The webhook adapter validates signatures on every incoming POST
- Static routes from config.yaml cannot be overwritten by dynamic subscriptions
- Subscriptions persist to
~/.hermes/webhook_subscriptions.json
How It Works
writes tohermes webhook subscribe~/.hermes/webhook_subscriptions.json- The webhook adapter hot-reloads this file on each incoming request (mtime-gated, negligible overhead)
- When a POST arrives matching a route, the adapter formats the prompt and triggers an agent run
- The agent's response is delivered to the configured target (Telegram, Discord, GitHub comment, etc.)
Troubleshooting
If webhooks aren't working:
- Is the gateway running? Check with
orsystemctl --user status hermes-gatewayps aux | grep gateway - Is the webhook server listening?
should returncurl http://localhost:8644/health{"status": "ok"} - Check gateway logs:
grep webhook ~/.hermes/logs/gateway.log | tail -20 - Signature mismatch? Verify the secret in your service matches the one from
. GitHub sendshermes webhook list
, GitLab sendsX-Hub-Signature-256
.X-Gitlab-Token - Firewall/NAT? The webhook URL must be reachable from the service. For local development, use a tunnel (ngrok, cloudflared).
- Wrong event type? Check
filter matches what the service sends. Use--events
to verify the route works.hermes webhook test <name>