Hermes Agent¶
Open Source AI Agent
Hermes Agent is an open-source AI agent by Nous Research. It runs as a long-lived process with its own conversation history, memory store, scheduled jobs, hooks, and skills โ all persisted under $HERMES_HOME (default ~/.hermes).
Official installation reference: hermes-agent.nousresearch.com/docs/getting-started/installation.
Why a Dedicated Container?¶
- Stateful โ sessions, memories, and skills accumulate over time and must outlive image rebuilds
- Unprivileged โ the agent has shell-execution capabilities, so it should not run as root
- Versioned โ upstream tags follow CalVer (
vYYYY.M.D), so image upgrades are frequent
Install¶
Infrastructure as Code
This Hermes Agent instance is deployed using OpenTofu with a custom Incus image. The infrastructure configuration manages container provisioning and a persistent storage volume for all agent data.
The canonical configuration is maintained at Benoit/OpenTofu.
Custom Hermes Agent Image
The Hermes Agent Incus image is built and maintained at forgejo.benoit.jp.net/Benoit/Laminar.
Image Layout¶
The Laminar job follows the "Non-sudo system service user" recipe from the official installation docs: it creates an hermes user (UID 1001) and runs the upstream curl โฆ | bash installer as that user with --skip-browser, producing the per-user (git) layout documented upstream:
| Path | Purpose |
|---|---|
/home/hermes/.hermes/hermes-agent/ |
Git checkout of the upstream repo (code, read-mostly) |
/home/hermes/.local/bin/hermes |
Entrypoint command |
/home/hermes/.hermes/.env |
API keys, model selection, runtime config |
/home/hermes/.hermes/sessions/ |
Conversation history |
/home/hermes/.hermes/memories/ |
Persistent memory store |
/home/hermes/.hermes/skills/ |
User-installed skills |
/home/hermes/.hermes/cron/ |
Scheduled jobs |
/home/hermes/.hermes/hooks/ |
User hooks |
/home/hermes/.hermes/logs/ |
Agent logs |
/home/hermes/.hermes/image_cache/ |
Cached images for vision tools |
/home/hermes/.hermes/audio_cache/ |
Cached audio for TTS |
/home/hermes/.hermes.skeleton/ |
Pristine copy of the above, baked into the image |
/home/hermes/.hermes/node/bin/claude |
Claude Code CLI, bundled via npm install -g @anthropic-ai/claude-code |
/home/hermes/hermes-webui/ |
hermes-webui web UI (code, image rootfs) |
/home/hermes/.hermes/webui/ |
hermes-webui state โ sessions, settings (persistent volume) |
The Playwright/Chromium browser stack is not installed in the image (--skip-browser). If you need the agent's browser tools, install it on the running container after first boot โ see Enable Browser Tools (Optional) below.
Infrastructure Configuration¶
The OpenTofu configuration provisions:
- Incus instance running the custom Hermes Agent image
- One persistent storage volume mounted at
/home/hermes/.hermesfor all agent state (sessions, memories, skills, config, logs)
resource "incus_storage_volume" "hermes_home" {
name = "hermes_home"
pool = incus_storage_pool.default.name
}
resource "incus_instance" "hermes" {
name = "hermes"
image = "laminar.incus:hermes-agent-2026.5.16-1benoitjpnet"
device {
name = "hermes_home"
type = "disk"
properties = {
path = "/home/hermes/.hermes"
source = incus_storage_volume.hermes_home.name
pool = incus_storage_pool.default.name
}
}
}
Deploy Infrastructure¶
First-Boot Bootstrap¶
Empty Volume Shadows Skeleton
A freshly-provisioned Incus volume mounts on top of /home/hermes/.hermes and hides the skeleton (.env, empty sessions/, memories/, etc.) that the image ships with. Seed it once from the pristine copy at /home/hermes/.hermes.skeleton/.
if [ ! -f /home/hermes/.hermes/.env ]; then
cp -a /home/hermes/.hermes.skeleton/. /home/hermes/.hermes/
chown -R hermes:hermes /home/hermes/.hermes
fi
The wizard writes API keys and model preferences into /home/hermes/.hermes/.env โ i.e. onto the persistent volume, so it survives image upgrades.
During the wizard you'll be asked for:
- Anthropic / Claude token โ paste an API key from console.anthropic.com when prompted. The wizard stores it in
/home/hermes/.hermes/.env.
Authenticate Claude Code (Optional)¶
Claude Code is pre-installed (see the Image Layout table) but ships unauthenticated. Authenticate as the hermes user:
incus exec hermes --user 1001 --env HOME=/home/hermes -- bash -c '
export PATH=/home/hermes/.hermes/node/bin:$PATH
claude setup-token
'
claude setup-token walks you through OAuth and prints a token suitable for non-interactive use. Paste it into the Hermes setup wizard when prompted for the Anthropic / Claude credential, or export it as ANTHROPIC_API_KEY in /home/hermes/.hermes/.env. Credentials Claude Code stores for itself live under /home/hermes/.claude/ โ outside the .hermes volume, so symlink that directory into .hermes or attach a second volume if you want it to survive image rebuilds.
hermes-webui¶
hermes-webui is pre-installed at /home/hermes/hermes-webui and starts automatically via systemd on every boot. On first start it sets up its Python venv and is then available at http://<container-ip>:8787.
Check the service status:
incus exec hermes -- systemctl status hermes-webui.service
incus exec hermes -- journalctl -u hermes-webui.service -f
To enable password protection, add to /home/hermes/.hermes/.env:
Then restart the service:
Enable Browser Tools (Optional)¶
The image is built with --skip-browser, so Playwright and Chromium are not present. To enable the agent's browser tools, run these on the live container after first boot:
incus exec hermes -- bash -c '
export PATH=/home/hermes/.hermes/node/bin:$PATH
cd /home/hermes/.hermes/hermes-agent
npx playwright install-deps chromium
'
incus exec hermes --user 1001 --env HOME=/home/hermes -- bash -c '
export PATH=/home/hermes/.hermes/node/bin:$PATH
cd /home/hermes/.hermes/hermes-agent
npx playwright install chromium
'
The Chromium binary and Playwright cache land in /home/hermes/.cache/ms-playwright/, which sits outside the /home/hermes/.hermes volume โ so this step has to be re-run after each image upgrade. If you want it persisted, mount a second volume at /home/hermes/.cache as well.
Upgrade¶
Incus Image Upgrade
Image upgrades replace /home/hermes/.hermes/hermes-agent/ (the code), but the persistent volume keeps every byte of agent state (sessions, memories, skills, config) untouched. No backup/restore step is required.
The persistent volume already holds everything stateful. No manual backup is needed before upgrade.
Update OpenTofu configuration
Edit your OpenTofu configuration file to update the image version:
Upgrade Complete
Your Hermes Agent instance is now running on the new Incus image with all sessions, memories, and skills intact.
Building a New Image Version¶
Bump the version in the Laminar job and queue it:
UPSTREAM_VER="2026.5.16" # update to the desired upstream tag (without leading v)
The job clones https://github.com/NousResearch/hermes-agent at tag v$UPSTREAM_VER, installs as the hermes user, and publishes the image as hermes-agent-$UPSTREAM_VER-1benoitjpnet.
Related Documentation:
- Infrastructure Overview - Complete self-hosting architecture
- Incus - Container orchestration platform
- Backup - Storage volume backup strategy