2.1 KiB
Portainer Hermes Runtime Design
Goal
Make the Hermes control-plane stack boot reliably in Portainer while preserving existing Hermes, Codex, Claude, and Gemini authentication files from host bind mounts.
Architecture
Hermes application code and its Python virtual environment are baked into the
control-plane image at /opt/hermes-agent. Mutable Hermes state remains at
/home/hermes/.hermes, and provider-specific state remains at the native
/home/hermes/.codex, /home/hermes/.claude, and /home/hermes/.gemini
paths.
The runtime executable is /opt/hermes-agent/venv/bin/hermes. Mounting an
empty or existing /home/hermes/.hermes directory therefore cannot hide the
executable.
Host Bind Mount Contract
The stack keeps these configurable host bind mounts:
HERMES_HOME_HOST->/home/hermes/.hermesCODEX_HOME_HOST->/home/hermes/.codexCLAUDE_HOME_HOST->/home/hermes/.claudeGEMINI_HOME_HOST->/home/hermes/.gemini
Any provider directory may be empty. Provider discovery remains dynamic and must not assume Codex, Claude, or Gemini authentication exists.
Startup Behavior
Every Hermes-backed service starts through /app/docker-entrypoint.sh. The
entrypoint:
- Creates missing mutable state directories.
- Seeds
config.yamlonly when it does not already exist. - Refuses to start with a clear error if the baked Hermes executable is missing.
- Executes the requested control-plane, proxy, or gateway command.
Existing config and authentication files are never overwritten.
Nginx Proxy Manager
NPM forwards the HTTPS hostname to the control-plane HTTP port. The hostname
does not participate in Hermes provider-state discovery. Published host ports
remain bind-address configurable through HERMES_PUBLISHED_BIND_IP.
Verification
- Compose contract tests verify the baked executable path and retained host bind mounts.
- Entrypoint tests verify empty-state initialization and preservation of existing config.
- The Docker image build verifies the baked Hermes executable exists and can report its version.
- Existing application tests continue to pass.