Skip to main content

Hermes

AI agent gateway with an OpenAI-compatible API and a live dashboard.

ToolUse for
Hermes dashboardSessions, skills, and agent configuration
Open WebUIDay-to-day conversations
decree routinesWork with nobody present — agent-task files the answer into workspace/ai/

Every surface points at the gateway (https://hermes-agent.<domain>/v1, HERMES_API_KEY as the API key), so they share the same models, skills and memory.

Not a coding backend

Don't point a coding agent at the gateway to work on this repo. Hermes is itself an agent running its own tool loop, and opencode's streaming parser rejects hermes' custom event: hermes.tool.progress frames outright — see Why not OpenCode. Edit the stack with a dedicated coding agent on the host, against a frontier model. Hermes' agent work belongs where it works: in a container, on workspace/.

Services​

ContainerPurposePort
hermes-agentGateway API + dashboard8642 (API), 9119 (dashboard) — not published to the host; reach them through Caddy

Architecture​

hermes-agent is the long-running gateway. It exposes an OpenAI-compatible HTTP API on :8642 and a dashboard on :9119. Open WebUI connects to it over the internal exist network.

volumes/hermes_agent_data is bind-mounted at /opt/data for agent config, sessions, skills, and memory.

Profiles​

With GATEWAY_MULTIPLEX_PROFILES=1 the gateway serves more than one agent from the same container. The default profile answers at /v1; every other profile lives at /p/<name>/v1 with its own HERMES_HOME under /opt/data/profiles/<name>/, and therefore its own toolsets, MCP servers and skills.

That separation is what makes routing affordable. A profile's system prompt carries a schema for every tool it owns — roughly 2.4 KB each — so the default profile's 21 tools cost about 17,000 tokens on every single call. A router that only has to pick a department needs no tools at all, so it runs at about 650 tokens: a 64x reduction on a decision made for every incoming message.

Each profile needs its own API_SERVER_KEY — one profile's key will not authenticate against another, and an unknown profile name returns 404. ai/hermes/entrypoint.sh creates one profile per directory in ai/hermes/profiles/ on every boot, reading each department's declared description, toolsets and MCP servers out of its profile.yml. It is idempotent, so a restart only fills in what is missing.

See Routing to Departments for how a message reaches the right one.

Model configuration​

The model: block in config.yaml is kept in step with .env.shared — change EXIST_MODEL_CHAT or the chat endpoint and the next ./existential.sh moves hermes with the rest of the stack. That only applies while the block still points at a local model server (provider: custom and a :11434 endpoint). Point it at Anthropic, OpenRouter or anything else and it becomes yours: every line is left alone from then on, except context_length, which is a fact about how the model was built rather than a preference.

Triggering automation​

Hermes has no mount into automation/ and shouldn't be given one — decree's routine scripts are read-only from inside the daemon on purpose. If a task calls for running a decree routine (now, or as a scheduled follow-up), the supported path is workspace/outbox/, which Hermes already has file access to: see Triggering decree from workspace/. agent-task, which is what answers most Hermes-routed work, already tells the model this in its system prompt.

Authentication​

HERMES_API_KEY in ai/hermes/.env.exist is the shared secret for the gateway. It is the gateway's API_SERVER_KEY; Open WebUI sends it as OPENAI_API_KEY.

Upgrading​

docker compose pull && docker compose up -d

hermes_agent_data (mounted at /opt/data) is a host bind mount, not a Docker-managed volume — there's nothing to docker volume rm. The entrypoint's provisioning is idempotent and re-runs on every start, so a fresh image is picked up on the next restart with no manual cache-clearing step.

Debugging​

docker compose logs hermes-agent