Entity: Hermes Agent (AI Agent Service)

This page is the repository hub for the Hermes Agent Proxmox KVM deployment.

Overview

Hermes Agent is deployed as a dedicated KVM VM (VM 501 hermes) on the Proxmox node tazlab, migrated from the old LXC container (CT 105) on 2026-08-12 via the CRISP project hermes-agent-redesign. The deployment lives in a standalone repository (github.com/tazzo/hermes-agent) with Terraform + Ansible + shell orchestrators — no longer part of ephemeral-castle.

Data persistence follows the same pet/cattle principle as the old LXC deployment, adapted to VM semantics: the root disk is ephemeral (destroyed with the VM), while a dedicated 20G data disk survives destroy/create cycles via an lvrename out-of-convention trick.

Architecture

Proxmox node "tazlab" (192.168.1.200)
└── VM 501 "hermes" (KVM, Ubuntu 26.04 LTS "resolute")
    ├── 4 vCPU, 8 GB RAM, static IP 192.168.1.205/24 (gw 192.168.1.1)
    ├── virtio0: root disk 30 GB (local-lvm) — EPHEMERAL, destroyed with VM
    ├── virtio1: data disk 20 GB (local-lvm:vm-501-disk-2) — PERSISTENT pet
    │   └── /home/hermes (whole home = Hermes state + code, option A)
    ├── Hermes v0.20.0 (bare-metal via install.sh)
    │   ├── hermes-gateway.service
    │   └── hermes-dashboard.service (port 9119, bind 0.0.0.0 + basic auth)
    └── Users: bootstrap (admin, sudo NOPASSWD), hermes (UID 10000, no sudo)

Repository Structure

hermes-agent/                     # github.com/tazzo/hermes-agent
├── create.sh                     # 8-phase orchestrator (enterprise logging)
├── destroy.sh                    # unlink data disk → lvrename → qm destroy
├── terraform/                    # VM 501 resource (root disk ONLY — data disk outside state)
├── ansible/                      # 4 playbooks + roles (baseline, agent, configure, verify)
├── configs/
│   └── runtime.env               # VM_ID, IP, CORES, MEMORY, DISK sizes
└── logs/                         # Timestamped, rotated (keep 20)

Quick Facts

PropertyValue
VM ID501 (KVM)
Hostnamehermes
IP192.168.1.205
OSUbuntu 26.04 LTS (resolute)
Resources4 vCPU, 8 GB RAM
Root disk30 GB local-lvm (ephemeral)
Data disk20 GB local-lvm:vm-501-disk-2 (persistent pet, mounted at /home/hermes)
Dashboardhttp://192.168.1.205:9119 (basic auth: user hermes, password in gopass infra/hermes-vm/dashboard-password)
LLM BackendConfigurato dall’utente via dashboard al primo accesso (30+ provider)
Hermes versionv0.20.0 (2026.8.3)
Userhermes (UID 10000, non-root, no sudo)
Bootstrap userbootstrap (sudo NOPASSWD, maintenance)
Repogithub.com/tazzo/hermes-agent (default branch main)
Old deploymentCT 105 LXC — destroyed 2026-08-12

Canonical Starting Pages for Agents

Deployment & Lifecycle

  • VM Deployment Architecture — KVM architecture, persistence model, lifecycle, key discoveries
  • LXC Deployment ArchitectureSUPERSEDED (see hermes-lxc-deployment.md banner, historical only)

CRISP Project (source of truth)

  • Project: skills/crisp/projects/hermes-agent-redesign/ (RESEARCH/DESIGN/PLAN/tasks/retrospective)
  • Report: skills/memory/reports/2026-08-12_hermes-agent-vm-redesign.md

Secrets (gopass)

  • infra/hermes-vm/dashboard-password — dashboard basic auth
  • infra/hermes-vm/bootstrap-password + infra/hermes-vm/hermes-password — SSH passwords
  • infra/ssh-host-keys/hermes-agent/ed25519 — SSH host key (injected post-boot via Ansible)
  • bootstrap/proxmox/token-id + bootstrap/proxmox/token-secret — Proxmox API for create/destroy

Key Discoveries (2026-08-12, destructive tests)

  • qm destroy deletes by naming convention: removes ALL vm-501-* volumes even unused, even with --destroy-unreferenced-disks 0. Fix: lvrename the data volume to vm-501-data-orphan before destroy, rename back on create.
  • Data disk OUTSIDE Terraform state: if declared in .tf, terraform destroy deletes it. Managed via pvesm alloc + qm set/qm unlink.
  • gopass multi-line: gopass show -o returns only first line (35B vs 411B for SSH keys) — use gopass cat.
  • Ansible 2.21 become non-root bug: sudo -u hermes pattern instead of become_method: su.
  • Dashboard auth: scrypt hash must be STANDARD base64 with padding + maxmem=0 (urlsafe fails). Hash computed locally where gopass exists.
  • agent.wait_for_ip.disabled = true: skips IP wait (static via cloud-init) → apply drops from ~15 min to <1 min.

Known Issues / Technical Debt

TDAreaSummary
TD-056gopass cacheGPG cache expires ~45 min — long builds fail with “gopass locked”; show -o truncates multi-line secrets (use cat)

Relationships

  • Infrastructure: ephemeral-castle — former home; ephemeral-castle/hermes/ removed (commit 504f353); now standalone repo
  • GitOps cluster: tazlab-k8s — talks to the cluster via LLM provider
  • Semantic memory: mnemosyne-mcp-server
  • Context governance: AGENTS.ctx — operational memory and rules

See Also