Files
composes/hermes

hermes

Hermes Agent: an autonomous AI agent with persistent memory, scheduling and chat-platform gateways, from Nous Research's official image, with its built-in web dashboard.

One container. gateway run starts the agent gateway, and the image's s6 supervisor also starts the dashboard on port 9119: chat (the Hermes terminal UI in the browser), sessions, config, cron, skills and logs.

Setup

  1. Set HERMES_DASHBOARD_PUBLIC_URL, HERMES_DASHBOARD_PASSWORD, HERMES_DASHBOARD_SECRET and OPENROUTER_API_KEY.
  2. Map the domain to port 9119 and deploy.
  3. Open the domain and log in with HERMES_DASHBOARD_USERNAME / HERMES_DASHBOARD_PASSWORD.

Health check: GET /api/status, also the compose healthcheck.

Environment

Variable Default Purpose
HERMES_DASHBOARD_PUBLIC_URL — Full public URL, e.g. https://hermes.example.com
HERMES_DASHBOARD_USERNAME / HERMES_DASHBOARD_PASSWORD hermes / — Dashboard login
HERMES_DASHBOARD_SECRET — Signs dashboard sessions
OPENROUTER_API_KEY empty Model provider
ANTHROPIC_API_KEY, OPENAI_API_KEY, GOOGLE_API_KEY optional Other model providers

HERMES_DASHBOARD=1 turns the dashboard on. Bound to 0.0.0.0, it refuses to start without an auth provider, so the password is required. The image's username/password provider is the one that needs no outside identity service; upstream describes it as meant for trusted networks and recommends OAuth (Nous Portal) or self-hosted OIDC for a public domain.

HERMES_DASHBOARD_PUBLIC_URL adds the domain to the dashboard's Host and WebSocket Origin guard, which rejects requests for any other host.

HERMES_DASHBOARD_SECRET keeps sessions valid across restarts; without it each restart signs with a new random key and logs everyone out.

The uid/gid are pinned to 1000 in compose.yml; the Dockerfile depends on that (see Storage).

Storage

Volume Mount Holds
hermes-data /opt/data HERMES_HOME: config, .env, sessions, memory, skills, logs
hermes-workspace /workspace Files the agent works on

The image hard-blocks the agent's file tools from writing outside HERMES_WRITE_SAFE_ROOT, which it sets to /opt/data alone, so compose.yml adds /workspace to it. TERMINAL_CWD starts gateway and cron terminal sessions in /workspace. Upstream marks that variable deprecated in favour of terminal.cwd in config.yaml; it is used here so the setting stays in the compose file rather than on the volume.

The Dockerfile exists only to make /workspace writable. The image does not ship that directory and its init chowns only /opt/data, so a named volume on /workspace would come up root:root. Creating the directory in the image, owned by 1000:1000, fixes that: Docker seeds an empty named volume from the image directory, ownership included.

Image

nousresearch/hermes-agent:latest moves only on stable releases, roughly weekly; upstream publishes no major tag. The agent's code lives in the image, not a volume, so a new release takes effect on the next pull and recreate. The first start after an upgrade migrates config.yaml, keeping a timestamped backup.