Agent stack build plans · № 4 · Hermes CI/CD healer

Set it up

Six stages. Do them in order — the webhook is last because a listener with no sandbox and no approvals is a foot-gun with a public URL.

1 · Install Hermes on the server

Linux / macOS / WSL2

curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash

Run hermes once interactively to connect a model provider — it’s model-agnostic (Nous Portal, OpenRouter, OpenAI, or your own endpoint). Config lands in ~/.hermes/config.yaml, secrets in ~/.hermes/.env. The gateway daemon is hermes gateway; the docs cover installing it as a systemd/launchd service so it survives reboots — do that now, not after the first missed webhook.

2 · Make port 8644 reachable — you build this

GitHub will POST to http://your-server:8644/webhooks/ci-heal, so that address must resolve and accept traffic from the public internet. Hermes provides the listener, not the reachability. Two sane options:

3 · Bake the sandbox image — you build this

The agent’s container needs git, the gh CLI, and your repo’s toolchain (the same versions CI uses — drift here produces “works in my sandbox” PRs). Build a small image and point the Docker backend at it. For GitHub auth, mint a fine-grained token scoped to one repo with contents + pull-requests write, put it in ~/.hermes/.env, and expose it to sandbox processes via terminal.env_passthrough — Hermes strips the environment from child processes by default, which is exactly what you want for everything else.

4 · Configure the webhook platform and route

~/.hermes/config.yaml — the shape

# 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).

The prompt template interpolates payload fields — the docs’ example syntax is {pull_request.title}; fields mirror the GitHub payload JSON. HMAC validation of X-Hub-Signature-256 is built in once secret is set. Generate the secret properly:

Generate the shared secret

openssl rand -hex 32

5 · Lock the approvals before the first delivery

In config.yaml: start with approvals.mode: manual and sit through one full run approving each command — you’ll learn exactly what the agent wants to do. Then move to smart (LLM risk-assessment) for unattended nights. Add approvals.deny globs for the unforgivables regardless of mode — deny patterns matching gh pr merge, git push --force, and pushes to your default branch. Do not run --yolo on an agent with repo write access; Hermes’s hardline blocklist (fork bombs, rm -rf /) survives even --yolo, but it guards the host, not your repository.

6 · Point GitHub at it

Repo → Settings → Webhooks → Add webhook: payload URL http://your-server:8644/webhooks/ci-heal (https if you put a proxy in front — do), content type application/json, the secret from stage 4, and select individual events → Workflow runs rather than “send me everything.” Then break something on purpose: push a failing commit to a scratch branch, or use the webhook’s Redeliver button on a past failed-run delivery. Watch the gateway logs, approve the commands manually, and read the PR it opens like you’d review a stranger’s.

Disagree? Pin a note on it →