Skip to content

feat(chopper): run hermes in a microvm - #120

Merged
devusb merged 1 commit into
mainfrom
feat/hermes-microvm
Sep 5, 2026
Merged

feat(chopper): run hermes in a microvm#120
devusb merged 1 commit into
mainfrom
feat/hermes-microvm

Conversation

@devusb

@devusb devusb commented Aug 30, 2026

Copy link
Copy Markdown
Owner

Adds a vm-hermes microvm guest on chopper running the official hermes-agent container image under podman. Replaces the host-native service dropped in 595c3f3.

Upstream keeps the NixOS module at Tier 2 and the Docker image at Tier 1. The image ships Node, uv and Playwright, so npx/uvx MCP servers run without the nix-ld shims the old hermes.nix needed.

  • --network=host, so the dashboard binds the guest's real loopback and OAuth callback listeners need no port plumbing
  • containers.img and hermes.img split podman's image store from /opt/data, which holds memory, skills and sessions
  • hermes on PATH shells into the container via the rootful podman socket; mhelton joins the podman group so it works without sudo
  • named vm-hermes so the Tailscale Service can own svc:hermes — nodes and services share a MagicDNS namespace, and a collision sticks

Serve config is set imperatively rather than from Nix: serve set-config registers a service as plain HTTP even when the endpoint should terminate TLS (tailscale/tailscale#18381). It persists in tailscaled state on the guest's /var/lib volume.

Setup

  1. Admin console → Services → Define a Service: name hermes, endpoint tcp:443. Must exist before a host can advertise for it.
  2. Approve vm-hermes under Service hosts, or:
    "autoApprovers": { "services": { "svc:hermes": ["tag:server"] } },
    { "src": ["autogroup:member"], "dst": ["svc:hermes"], "ip": ["443"] },
  3. On the guest: tailscale serve --service=svc:hermes --https=443 127.0.0.1:9119
  4. In /opt/data/config.yaml: dashboard.public_url: "https://hermes.springhare-egret.ts.net", plus an auth provider — setting public_url forces the auth gate on.
  5. hermes setup — the gateway crash-loops until it runs.

Not included: deploy-backup for /opt/data, and declarative provider credentials.

@devusb
devusb force-pushed the feat/hermes-microvm branch from 10a9fde to 4c4b3e3 Compare August 30, 2026 17:48
@devusb
devusb marked this pull request as ready for review September 5, 2026 13:14
@devusb
devusb force-pushed the feat/hermes-microvm branch 4 times, most recently from b575f4e to c79d011 Compare September 5, 2026 13:53
Hermes runs from the official container image rather than the NixOS
module, which upstream maintains only as a best-effort Tier 2 platform.
The image gives the agent an FHS userland to install into, so third party
integrations work without nix-ld shims.

The guest owns its tailnet identity and reaches the dashboard over a
Tailscale Service, so chopper does not proxy for it. That serve config is
set imperatively and lives in tailscaled state on the guest volume: the
nixpkgs module drives `serve set-config`, which registers a service as
plain HTTP rather than HTTPS (tailscale/tailscale#18381).

The guest is named vm-hermes so the meaningful name stays with the
Tailscale Service, which is the host-independent identity. Nodes and
services share a MagicDNS namespace, and a collision is resolved by a
suffix that sticks even after the conflict is gone.

Podman image storage and agent state get separate volumes so the image
store can be reclaimed without touching memory and skills. The hermes
wrapper reaches the rootful podman socket so it works without sudo.
@devusb
devusb force-pushed the feat/hermes-microvm branch from c79d011 to 13f1974 Compare September 5, 2026 14:27
@devusb
devusb merged commit e17d53b into main Sep 5, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant