Files
homelab-infra/ops/hermes-agent

Hermes Agent for the Homelab

Phase 1 - Documentation Analysis

What Hermes Agent is

Hermes Agent is an autonomous AI agent from Nous Research with:

  • CLI/TUI usage
  • a messaging gateway for Telegram, Discord, Slack, WhatsApp, Signal, Email, Home Assistant and others
  • persistent memory and session search under ~/.hermes/
  • scheduled jobs via the gateway
  • multiple terminal backends (local, docker, ssh, modal, daytona, singularity)

The official docs describe it as an agent that lives on a server, remembers what it learns, and can be reached from different chat surfaces.

Official installation paths

Officially documented paths:

  • Linux/macOS/WSL2 installer via curl ... install.sh | bash
  • official Docker image nousresearch/hermes-agent
  • Nix / NixOS module
  • source / development install from the Git repository

For this repository and your current Unraid + Compose operating model, the Docker image is the cleanest officially documented runtime path.

Requirements from the docs

  • Git is the only prerequisite for the standard installer
  • the installer provisions uv, Python 3.11, Node.js v22, ripgrep, and ffmpeg
  • Hermes requires an LLM with at least 64k context
  • at least one provider must be configured
  • API keys and secrets belong in ~/.hermes/.env
  • non-secret settings belong in ~/.hermes/config.yaml

Operating modes relevant for homelab use

  • interactive CLI/TUI
  • persistent messaging gateway
  • optional OpenAI-compatible API server
  • optional dashboard
  • terminal execution backend selection
  • Home Assistant integration via token plus event filters

Security-relevant findings from the docs

  • the gateway denies unknown users by default unless they are allowlisted or paired
  • dangerous command approval applies to local and ssh terminal backends
  • the official Docker terminal backend is considered a strong isolation boundary and skips dangerous-command approval
  • the API server is localhost-only by default and becomes high-risk if bound to 0.0.0.0 without auth
  • persistent memory is injected into the prompt and is security-scanned before acceptance
  • the runtime Docker container itself runs as root by default according to the official Docker docs
  • the official Docker docs explicitly warn against running two gateway containers against the same data directory

Homelab relevance

Useful:

  • Docker runtime container
  • messaging gateway
  • API server only on an internal network
  • Home Assistant integration
  • persistent memory, sessions, cron, logs
  • SSH backend for separating tool execution from the NAS
  • OpenAI-compatible backends such as OpenAI API and Ollama

Usually not first choice for this homelab:

  • native installer directly on the NAS host
  • mounting the host Docker socket into the Hermes runtime container
  • internet-exposed API server
  • local backend on the NAS host
  • browser-heavy features unless explicitly needed

Phase 2 - Architecture Decision

Model A - Docker/Compose on NAS, terminal.backend=local

Criterion Assessment
Stability High
Security Medium
Wartability High
Homelab integration Very high
Complexity Low

Pros:

  • fully official Docker runtime path
  • best match to current Unraid/Compose/GitOps model
  • easiest deployment and upgrade

Cons:

  • terminal commands run inside the main Hermes service container
  • no second isolation layer between agent runtime and tool execution
  • package installs done by the agent are not a clean, persistent operating model

Model B - Native Hermes install in dedicated Linux VM/LXC, terminal.backend=docker

Criterion Assessment
Stability High
Security Very high
Wartability Medium
Homelab integration Medium
Complexity High

Pros:

  • closest match to the official security guidance for a production gateway
  • clean separation between Hermes runtime and Docker sandboxed commands
  • no NAS Docker socket exposed to a chat-facing container

Cons:

  • separate lifecycle from your current Compose-centric homelab
  • more moving parts to patch, back up, and monitor

Model C - Docker/Compose gateway on NAS, terminal.backend=ssh to dedicated Linux runner

Criterion Assessment
Stability High
Security High
Wartability High
Homelab integration High
Complexity Medium

Pros:

  • official Docker runtime path for Hermes itself
  • official SSH backend for command execution
  • no host Docker socket in the gateway container
  • clean separation between chat-facing service and execution environment
  • fits your existing NAS/Compose/GitOps model

Cons:

  • requires a dedicated runner VM/LXC
  • dangerous-command approval still applies on the SSH backend

Phase 3 - Clear Recommendation

Use Model C:

  • Hermes gateway and dashboard as official Docker containers on the NAS
  • terminal execution via the official ssh backend to a dedicated Linux runner
  • primary LLM via GPT/OpenAI API
  • Ollama on the gaming PC as optional secondary provider, not as required infrastructure
  • no Docker socket inside the Hermes gateway container
  • dashboard behind Traefik + Authelia
  • API server only on the internal hermes_net

Why this is the best fit here

This gives you the official containerized deployment the docs support, while avoiding the least-auditable shortcut: giving a chat-facing agent container direct host Docker control.

For the model layer, the most robust setup for your homelab is a hybrid:

  • OpenAI API as the primary inference backend
  • Ollama on the gaming PC as an optional alternate backend

Reason:

  • Hermes officially supports OpenAI-compatible endpoints, including Ollama
  • your gaming PC is useful compute, but it should not be the only dependency for the agent's baseline availability
  • with this split, Hermes still works when the gaming PC is off

Important inference:

The official docs clearly distinguish between:

  1. running Hermes in Docker
  2. using Docker as the terminal backend

I did not find an official deployment pattern that explicitly documents mounting the NAS Docker socket into the Hermes runtime container so that the runtime container itself manages sibling Docker sandboxes. The official runtime image docs list Python, Node, Playwright, ripgrep, and ffmpeg, but not the Docker CLI. Based on that, I treat "runtime container + host docker.sock for terminal backend" as a weakly documented path and do not recommend it for your production homelab.

Phase 4 - Implementation

Repository files

  • ops/hermes-agent/docker-compose.yml
  • ops/hermes-agent/stack.env.example
  • ops/hermes-agent/hermes.env.example
  • ops/hermes-agent/config/hermes/config.yaml

Host paths used by this setup

  • /mnt/user/appdata/hermes-agent/data
  • /mnt/user/appdata/hermes-agent/ssh
  • /mnt/user/appdata/secrets/hermes_runner_id_ed25519

Deployment layout

  • hermes-gateway stores state in /opt/data
  • repo-managed config.yaml is bind-mounted read-only into /opt/data/config.yaml
  • dashboard reads the same data volume but has no direct access to the SSH private key
  • only the dashboard joins frontend_net
  • the gateway stays off frontend_net and only exposes port 8642 internally on hermes_net

Reverse proxy

Use Traefik only for the dashboard.

  • yes for the dashboard
  • no for the gateway API by default
  • no public publish of 8642

Docker socket

Do not mount /var/run/docker.sock.

Runner preparation

On the dedicated Linux VM/LXC:

sudo useradd --create-home --shell /bin/bash hermes
sudo mkdir -p /srv/hermes-workspace
sudo chown hermes:hermes /srv/hermes-workspace
sudo chmod 755 /srv/hermes-workspace

sudo -u hermes mkdir -p /home/hermes/.ssh
sudo -u hermes chmod 700 /home/hermes/.ssh

Add the NAS-side public key to /home/hermes/.ssh/authorized_keys:

sudo -u hermes sh -c 'cat >> /home/hermes/.ssh/authorized_keys'
sudo -u hermes chmod 600 /home/hermes/.ssh/authorized_keys

Recommended runner packages:

sudo apt-get update
sudo apt-get install -y bash ca-certificates curl git jq python3 python3-venv ripgrep ffmpeg

Do not grant sudo unless you have a concrete use case and a reviewed sudoers policy.

NAS-side prep

mkdir -p /mnt/user/appdata/hermes-agent/data
mkdir -p /mnt/user/appdata/hermes-agent/ssh
chmod 700 /mnt/user/appdata/hermes-agent/ssh

Create the runner keypair on the NAS and keep the private key outside Git:

ssh-keygen -t ed25519 -f /mnt/user/appdata/secrets/hermes_runner_id_ed25519 -C hermes-runner
chmod 600 /mnt/user/appdata/secrets/hermes_runner_id_ed25519
chmod 644 /mnt/user/appdata/secrets/hermes_runner_id_ed25519.pub

First-time configuration

  1. Copy stack.env.example to stack.env.
  2. Copy hermes.env.example to /mnt/user/appdata/hermes-agent/data/.env.
  3. Fill the OpenAI API key and your chosen OpenAI model ID as the primary model.
  4. Optionally add the Ollama endpoint from the gaming PC as an alternate model profile.
  5. Fill API server key, messaging token(s), and SSH runner settings.
  6. Deploy the stack.

Example local validation before shipping to Komodo:

docker compose --env-file stack.env config
docker compose --env-file stack.env up -d

Phase 5 - Validation

1. Container health

docker compose --env-file stack.env ps
docker compose --env-file stack.env logs --tail=100 hermes-gateway
docker compose --env-file stack.env logs --tail=100 hermes-dashboard

2. API server / dashboard path

From the NAS:

docker exec hermes-gateway python3 -c "import urllib.request; print(urllib.request.urlopen('http://127.0.0.1:8642/health', timeout=3).read().decode())"

Expected: {"status":"ok"} or equivalent health JSON.

3. Hermes self-check

docker exec -it hermes-gateway hermes doctor
docker exec -it hermes-gateway hermes config

Use hermes doctor first whenever provider or backend setup is suspect.

4. SSH backend check

Inside Hermes, issue a harmless command such as:

Run `hostname` and `pwd`.

Expected:

  • hostname is the runner VM/LXC, not the NAS
  • working directory is /srv/hermes-workspace

5. Model/provider check

Inside Hermes:

Tell me which provider and model you are using.

Then run one simple, no-tool prompt and one tool-using prompt. If the base provider works but web tools fail, the likely issue is missing web-tool credentials rather than a broken main model.

Recommended operator check:

  • first validate with the primary GPT/OpenAI backend
  • then temporarily switch to the Ollama endpoint and confirm Hermes can still answer and call tools
  • treat Ollama as optional capacity, not as required uptime dependency

6. Persistence / memory check

After at least one session and one saved memory:

ls -la /mnt/user/appdata/hermes-agent/data
ls -la /mnt/user/appdata/hermes-agent/data/memories

Check for:

  • config.yaml
  • .env
  • memories/
  • sessions/
  • logs/
  • state.db

7. Home Assistant check

If HASS_TOKEN is set:

  • verify Hermes sees the homeassistant toolset
  • ask it to list a few entities
  • trigger a watched entity and confirm the gateway receives an event

If no HA events arrive, first check watch_domains, watch_entities, and ignore_entities.

Common misconfiguration signals

  • dashboard unhealthy: API server not enabled or not reachable on 0.0.0.0:8642
  • Hermes cannot run terminal commands: SSH key, host, user, or remote permissions are wrong
  • web tools missing: no supported web-search provider configured
  • HA tools missing: HASS_TOKEN not set
  • unknown users can message the bot: allowlist or pairing policy not configured

Phase 6 - Hardening

Minimal rights

  • keep cap_drop: [ALL]
  • keep no-new-privileges:true
  • keep the gateway off frontend_net
  • do not mount the Docker socket
  • do not run Hermes directly on the NAS host
  • do not grant the runner user blanket sudo

Secrets handling

  • keep provider keys and bot tokens in /mnt/user/appdata/hermes-agent/data/.env
  • keep the SSH private key in /mnt/user/appdata/secrets/hermes_runner_id_ed25519
  • limit file permissions to 600
  • if Komodo injects secrets as stack env vars, use that only where Hermes upstream requires env-only config

Tool isolation

  • terminal execution goes only to the dedicated runner
  • use the Home Assistant token only if HA control is needed
  • reduce enabled tools with hermes tools once the base deployment is stable

Network boundaries

  • expose only the dashboard through Traefik
  • keep 8642 internal unless you intentionally integrate a frontend such as Open WebUI
  • if you later expose the API server beyond hermes_net, keep bearer auth enabled and scope it tightly

Model strategy

  • keep GPT/OpenAI as the default production path
  • use Ollama when you explicitly want local inference or lower marginal cost
  • do not design the base service around the assumption that the gaming PC is always on

Updates

  • current official Docker tag used here: nousresearch/hermes-agent:v2026.4.16
  • update deliberately, test with hermes doctor, then roll forward
  • avoid latest in production if you want reproducibility

Backups

Back up at least:

  • /mnt/user/appdata/hermes-agent/data/.env
  • /mnt/user/appdata/hermes-agent/data/config.yaml
  • /mnt/user/appdata/hermes-agent/data/auth.json
  • /mnt/user/appdata/hermes-agent/data/memories/
  • /mnt/user/appdata/hermes-agent/data/sessions/
  • /mnt/user/appdata/hermes-agent/data/cron/
  • /mnt/user/appdata/hermes-agent/ssh/known_hosts
  • /mnt/user/appdata/secrets/hermes_runner_id_ed25519

Phase 7 - Ops Monitor (homelab-ops-monitor)

Was es ist

Ein Skill + Script das Hermes zum kontextuellen Ops-Assistenten macht. Wenn ein Service ausfaellt, bekommt er nicht eine rohe Fehlermeldung, sondern einen angereicherten Alert: Abhaengigkeiten, letzter Backup-Dump, erster Diagnoseschritt.

Laufzeit-Architektur (Stand 2026-05-06)

  • Hermes laeuft als Docker-Container auf dem Unraid-Host (hermes-gateway, hermes_net)
  • Terminal-Backend SSH-Ziel: 192.168.178.143 (dedizierte Linux-VM, Model C)
  • Hermes-User auf der VM: hermes
  • Repo-Clone auf der VM: /srv/hermes-workspace/homelab-infra/
  • Workspace-Verzeichnis auf der VM: /srv/hermes-workspace/

Wichtig fuer KI-Agenten und Betreiber: Das Terminal laeuft auf der VM, nicht auf dem Unraid-Host. /mnt/user/...-Pfade sind von der VM aus nicht direkt erreichbar. Docker-CLI ist auf der VM nicht vorhanden und wird nicht benoetigt.

Dateien

Datei Pfad im Repo Pfad auf VM
Wissensbasis ops/hermes-agent/services.json /srv/hermes-workspace/homelab-infra/ops/hermes-agent/services.json
Health-Script ops/hermes-agent/scripts/check_health.py /srv/hermes-workspace/homelab-infra/ops/hermes-agent/scripts/check_health.py
Skill-Prompt ops/hermes-agent/skills/homelab-ops-monitor.md /srv/hermes-workspace/homelab-infra/ops/hermes-agent/skills/homelab-ops-monitor.md

check_health.py

  • Keine externen Abhaengigkeiten — nur Python-Standardbibliothek (json, urllib, ssl)
  • Kein Docker CLI, kein pip, kein Root noetig
  • Prueft Services mit URL via HTTP GET (2xx/3xx/4xx = healthy, 5xx/Timeout = unhealthy)
  • Interne Services ohne URL (Datenbanken, Redis) werden als "internal" markiert — kein Fehler
  • Dump-Timestamps werden gelesen falls /mnt/user/backups/borg/dumps/latest erreichbar ist (optional)
  • services.json wird relativ zum Script-Verzeichnis gesucht (../services.json)

Verwendung auf der VM:

cd /srv/hermes-workspace/homelab-infra
python3 ops/hermes-agent/scripts/check_health.py --summary        # Tier 1+2
python3 ops/hermes-agent/scripts/check_health.py paperless-ngx    # gezielt
python3 ops/hermes-agent/scripts/check_health.py --all            # alle Tiers

services.json

Maschinenlesbare Wissensbasis abgeleitet aus docs/SERVICE_CATALOG.md. Enthaelt fuer jeden Service: Tier, Container-Name, Abhaengigkeiten, Dump-Dateiname, Datenpfade, first_check-Hinweis und betriebliche Notizen.

Bei Aenderungen am Service Catalog: services.json und services.yaml parallel aktualisieren.

Skill importieren

„Bitte erstelle einen neuen Skill namens homelab-ops-monitor. Lies dazu die Datei
/srv/hermes-workspace/homelab-infra/ops/hermes-agent/skills/homelab-ops-monitor.md
und lege den Skill mit diesem Inhalt an."

Nach Repo-Aenderungen auf der VM pullen:

cd /srv/hermes-workspace/homelab-infra && git pull

Bekannte Einschraenkungen

  • Interne Services (PostgreSQL, Redis, MongoDB) koennen nicht extern geprueft werden
  • Dump-Timestamps nur lesbar wenn /mnt/user/backups/ per NFS oder Mount erreichbar ist
  • Docker-Healthstatus der Container ist von der VM aus nicht pruefbar (kein Docker-Socket)
  • Alerting via ntfy erfordert dass ntfy selbst healthy ist (Fallback: Telegram)

Official sources used