Set it up
Do these in order. The webhook comes last, because a listener with no sandbox and no approvals is a public URL that runs an agent.
1 · Install Hermes on the server
Linux / macOS / WSL2
curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash
Run hermes once to connect a model provider,
then install hermes gateway as a systemd or launchd service now,
so it survives reboots. Config goes in ~/.hermes/config.yaml,
secrets in ~/.hermes/.env.
2 · Open port 8644 (you build this)
GitHub needs to reach
http://your-server:8644/webhooks/ci-heal.
- A VPS is always on and needs one firewall rule plus a TLS proxy.
- A tunnel from a homelab box behind NAT works, but when it drops, nobody notices.
3 · Build the sandbox image (you build this)
Include git, gh and your toolchain at the versions CI uses,
or you’ll get “works in my sandbox” PRs. Point the Docker
backend at it. Create a fine-grained GitHub token for one
repo with contents and pull-requests write, put it in
~/.hermes/.env, and pass only that through
terminal.env_passthrough. Hermes hides everything else in your
environment from child processes by default.
4 · Configure the webhook and route
The shape of ~/.hermes/config.yaml
# Key names below are verified against the Hermes webhook docs,
# July 2026 (v0.19.0). Check docs > messaging > webhooks for the
# exact nesting in your release before pasting blind — or use
# prompt 1 on the prompts page and let the agent write this file.
platforms:
webhook:
extra:
port: 8644
secret: ${WEBHOOK_SECRET} # value lives in ~/.hermes/.env
rate_limit: 30 # deliveries/min — the documented default
max_body_bytes: 1048576
# routes: each has events, filters, a prompt template,
# deliver targets, and an optional script hook.
# ci-heal route: accept workflow-failure events for your repo,
# filter OUT runs on ci-heal/* branches (loop-breaker),
# prompt: see prompts page, stage 2,
# deliver: github_comment (plus telegram or discord if you like).
Template fields mirror the GitHub payload JSON in the
docs’ {pull_request.title} syntax. Once
secret is set, X-Hub-Signature-256 checking is on.
Generate it with:
Generate the shared secret
openssl rand -hex 32
5 · Lock approvals
Start with approvals.mode: manual and approve one full run by
hand, so you see what the agent does. Then switch to smart (an
LLM rates the risk) for unattended nights. In any mode, add
approvals.deny globs for gh pr merge,
git push --force and pushes to your default branch. Never use
--yolo here. The hardline blocklist (fork bombs,
rm -rf /) still holds under --yolo, but it protects
the host and does nothing for your repo.
6 · Point GitHub at it
Repo → Settings → Webhooks → Add webhook. Use
http://your-server:8644/webhooks/ci-heal (https behind your
proxy), content type application/json, the secret from stage 4,
and only the Workflow runs event. Then push a failing commit
to a scratch branch (or hit Redeliver on an old failure),
approve each command, and review the PR as if a stranger wrote it.