two¢ents

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.

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.

Disagree? Pin a note on it →