Hermes Box v2 architecture

How Lima replaces smolvm, how the layers fit together, and how a box is created, operated, updated, and rebuilt.

The short answer

Lima replaces smolvm at the VM-runtime layer. It does not replace Hermes Box. Hermes Box is the product and policy layer; Lima manages the Linux VM, disk, SSH transport, and loopback forwarding; Apple Virtualization.framework (VZ) runs the virtual machine.

The layers

The cleanest mental model is four layers. Each has one job.

┌──────────────────────────────────────────────────────────────┐
│ Hermes Box                                                  │
│ Product policy, desired state, lifecycle, safety, recovery  │
├──────────────────────────────────────────────────────────────┤
│ Lima                                                         │
│ VM creation, persistent disks, SSH transport, port tunnels  │
├──────────────────────────────────────────────────────────────┤
│ Apple Virtualization.framework (VZ)                          │
│ Native Apple Silicon virtualization                         │
├──────────────────────────────────────────────────────────────┤
│ macOS + Apple Silicon                                       │
└──────────────────────────────────────────────────────────────┘
Who owns what
LayerResponsibilityWhat it does not decide
Hermes BoxConfiguration, lock verification, lifecycle, backups, updates, health, ownershipHow macOS executes a virtual CPU
LimaLinux VM and disk primitives, SSH connectivity, host/guest transport, port forwardingWhich Codex, Claude, Hermes, or Executor version is allowed
Apple VZHardware-accelerated virtualization on Apple SiliconBox lifecycle or application policy
Ubuntu guestRuns the tools, services, tmux session, and guest transaction engineHost ownership or backup retention policy

Is Lima a replacement for smolvm?

Yes, narrowly: v2 replaces smolvm with Lima as the host-side Linux machine runtime. It is also a broader architectural reset. v2 does not import, adopt, upgrade, or restore v1 smolvm machines or snapshots.

Runtime and product-model comparison
Concernv1 / smolvm modelv2 / Lima model
VM runtimesmolvmLima 2.1.3 over Apple VZ
Operating systemMutable machine/image lineageChecksum-pinned Ubuntu 26.04 cloud image
DurabilityRootfs snapshots and packaging conceptsOne explicit, independently persistent ext4 data disk
Platform upgradesPreserve or migrate an existing imageDelete and recreate the disposable root with rebuild
Desired versionsProvisioning and machine stateReviewed, input-only hermes-box.lock
SSHProject-managed machine connectivityLima-managed SSH transport
CompatibilityExisting v1 boxesNo v1 compatibility or adoption by design

Lima is attractive here because it exposes the boring primitives v2 needs: create/delete a VM, create/attach a persistent disk, connect over SSH, copy inputs, inspect state, and forward a loopback port. Hermes Box wraps those primitives in stricter ownership and recovery rules.

The complete system

Apple Silicon Mac
│
├── Repository-owned desired state
│   ├── hermes-box.yaml       human choices: name, CPU, memory, disks, port
│   └── hermes-box.lock       immutable URLs, versions, checksums, digests
│
├── hermes-box Go CLI
│   ├── config + lock validation
│   ├── exact resource ownership
│   ├── content-addressed artifact cache
│   ├── encrypted backups
│   ├── operation locks + host logs
│   └── macOS Keychain-backed age identity
│
├── Lima 2.1.3
│   ├── <name> VM              disposable Ubuntu root
│   ├── <name>-data disk       persistent ext4 state
│   ├── Lima-managed SSH
│   └── Executor loopback forwarding
│
└── Ubuntu 26.04 ARM64 guest
    ├── Disposable root disk
    │   ├── systemd + sshd + tmux
    │   ├── hermes-box-guest transaction helper
    │   ├── /opt/hermes-box/tooling/{node,uv}
    │   ├── /opt/hermes-box/releases/{claude,codex,hermes}
    │   ├── hermes.service
    │   ├── executor.service → Podman → pinned Executor image
    │   └── /var/lib/hermes-box applied state + recovery journals
    │
    └── Persistent /data disk
        ├── home/agent/.claude
        ├── home/agent/.codex
        ├── home/agent/.hermes
        ├── home/agent/workspace
        └── executor
The central design move

The root disk is cattle; the data disk is the box. Reattach the same data disk and apply the same reviewed lock to a fresh Ubuntu root, and the same working environment returns without restoring a mutated operating system.

Inside the guest

  • Claude Code and Codex are interactive commands with versioned releases on the disposable root and durable auth/session state under /data/home/agent.
  • Hermes Agent runs as agent under systemd; its release is reconstructable, while its config, auth, sessions, memory, and skills are durable.
  • Executor runs as a digest-pinned ARM64 container under system Podman. Its database and secrets live in /data/executor; Podman's image store is disposable.
  • Node and uv are independently pinned guest tooling with their own update and rollback paths.
  • tmux supplies the persistent interactive workspace: green status bar, clickable windows, Ghostty metadata, true color, clipboard passthrough, and extended keys.

What happens during create

  1. Load intent. Read hermes-box.yaml and the reviewed hermes-box.lock.
  2. Fail-fast preflight. Verify Apple Silicon, the exact Lima version, free loopback port, ownership, checksums, and every required artifact before creating resources.
  3. Prepare recovery identity. Create the box's age identity in macOS Keychain.
  4. Create durable storage. Ask Lima for the exact <name>-data disk.
  5. Create a fresh root. Ask Lima to boot the checksum-verified Ubuntu 26.04 ARM64 image through Apple VZ and attach the data disk.
  6. Bootstrap the guest. Cloud-init creates agent, mounts /data, installs the minimal OS surface, systemd units, tmux assets, and static guest helper.
  7. Materialize exact software. The host verifies locked artifacts, uploads them, and invokes one guest transaction.
  8. Stage before activation. The guest installs and smoke-tests Node, uv, Claude, Codex, Hermes, and Executor without making an unverified candidate current.
  9. Activate and verify. Atomic symlinks select native releases; systemd starts Hermes and Executor; health, versions, port binding, and MCP surfaces are checked.
  10. Create the first backup. Success is not returned until an encrypted recovery bundle verifies.
  11. Hand off human authentication. The CLI prints the ordered Claude, Codex, Hermes, Executor, and backup-key steps.
hermes-box create
       │
       ├─ verify everything
       ├─ Lima: disk create
       ├─ Lima: VM create + attach disk
       ├─ cloud-init: minimal guest bootstrap
       ├─ host: upload verified artifacts
       ├─ guest helper: stage → smoke → activate → health
       ├─ encrypted backup
       └─ human login/setup handoff

Daily operation

hermes-box ssh
  → Hermes Box asks Lima for the managed SSH connection
  → login as agent in /workspace
  → automatically run tm
  → create or attach tmux session "main"

start is intentionally boring: it starts only the releases already applied to the root and reports drift. It never installs software. stop stops services, syncs the data disk, and stops the VM. status and doctor are read-only.

Common operator loop
IntentCommandBehavior
Enter the workspacehermes-box sshAttach the persistent main tmux session
Run automationhermes-box exec -- …Run without tmux and preserve argument boundaries
Inspecthermes-box statusHealth, setup, desired/applied/running versions, storage, ports, backup
Diagnosehermes-box doctorBounded read-only host and guest checks
Use Executorhermes-box open executorVerify and open the loopback-only portal

Application update vs platform rebuild

Two intentionally different mutation paths
ChangeCommandWhat happens
Claude, Codex, Hermes, Executor, Node, uvupdate COMPONENTStage, verify, snapshot scoped durable state, activate, health-check, retain one previous release
Undo one componentrollback COMPONENTRestore its valid encrypted transaction snapshot and activate the previous release
Ubuntu, provisioner, Lima compatibilityrebuildVerify recovery inputs, back up, replace the root VM, reattach /data, apply the lock, verify

Version selection never happens inside the running box. An update begins as a normal Git change to hermes-box.lock, passes review and qualification, then an operator applies it. If the lock contains a platform change, the correct operation is a rebuild, not an in-place Ubuntu upgrade.

Application change: lock PR → merge → update codex
Platform change:    lock PR → merge → rebuild

rebuild:
  verify current + desired artifacts
  → encrypted backup
  → stop and delete disposable VM root
  → create fresh Ubuntu root through Lima
  → reattach existing <name>-data
  → apply reviewed lock
  → health checks
  → automatic prior-root reconstruction if desired state fails

State, backup, and recovery

What is durable and what is reconstructable
LocationExamplesTreatment
Disposable rootUbuntu, systemd units, Podman image store, application binaries, applied metadataRecreate from the lock
/dataWorkspace, agent auth/sessions, Hermes memory/config, Executor database/secretsPersist across stop/start and rebuild
Host artifact cacheVerified immutable install inputsReconstructable optimization
Encrypted backup/data, applied lock, exact reconstruction artifactsPortable recovery unit
macOS KeychainAge backup identityExport separately for disaster recovery

A backup deliberately includes credentials and private work, so it is encrypted by default. It also embeds the exact reconstruction artifacts, avoiding a future dependency on an old npm tarball, GitHub release, container registry entry, Ubuntu package, Python archive, or wheel still being available.

The security boundary

One honest boundary

The VM protects the host. Claude, Codex, Hermes, Executor, and the passwordless-sudo agent user are not security-isolated from one another inside the guest.

v2 provides

  • No host-directory mounts, SSH-agent forwarding, Docker socket, or host credential-store forwarding.
  • Lima-managed SSH instead of a project-owned long-lived SSH key.
  • Executor exposed only on host loopback.
  • Checksum-, SRI-, or digest-verified software inputs.
  • Encrypted backups and reviewed immutable pins.
  • Exact VM/disk ownership; destructive operations never discover targets by broad prefix.

v2 does not claim

  • Containment between tools inside the guest.
  • Offline or firewall-backed strict networking.
  • Protection from guest-root data exfiltration through allowed egress.
  • An out-of-band root repair console; recovery replaces the root instead.

Lima itself supports host mounts and several forwarding/networking modes. Hermes Box deliberately uses a narrower subset and disables host mounts because the product's boundary is stricter than Lima's general-purpose defaults.

Complete command surface

Hermes Box v2 CLI
CommandOutcome
createCreate, apply, verify, back up, and print the setup handoff
start / stopStart applied versions or cleanly stop and sync the box
ssh / execInteractive tmux workspace or noninteractive remote execution
status [--check]Health, state, drift, setup, backup, and optional upstream discovery
logsBounded Hermes, Executor, or recovery service logs
open executorOpen the verified loopback-only Executor portal
setup executorSafely connect Executor's reviewed MCP surface to Hermes
update / rollbackTransactional application mutation with one retained prior release
backup / restoreEncrypted self-contained recovery and absent-destination restore
rebuildReplace the root while retaining the persistent data disk
doctorRead-only diagnostics and exact repair guidance
key exportExport the backup decryption identity with mode 0600
destroy [--force]Final-backup-gated removal of the exact owned VM and disk
completion / version / helpShell integration and reference information

Current qualification status

The implementation is present, but normal create is intentionally unavailable until the generated candidate lock passes the native ARM64 artifact build, isolated Lima lifecycle matrix, immutable publication, exact-URL re-download, and final reviewed root-lock promotion.

The missing repository-root hermes-box.lock is therefore a safety state, not an installation bug. Lima is also an operator-installed, version-qualified prerequisite; Hermes Box verifies it but never upgrades it.

What the local demo needs

Lima 2.1.3 plus the qualified and promoted lock. Once both exist, the user-facing path is intentionally short: clone, hermes-box create, then hermes-box ssh.

Primary references