tx9
| Name | Last commit date |
|---|---|
| backups | 4 months ago |
| docs | 4 months ago |
| guest | 4 months ago |
| provision | 4 months ago |
| tests | 4 months ago |
| .gitignore | 4 months ago |
| box | 4 months ago |
| box.env | 4 months ago |
| Makefile | 4 months ago |
| README.md | 4 months ago |
hermes-box-lite
Small, isolated agent VMs with Claude Code, Codex, Hermes, and Executor.
Each box runs on smolvm, has no host filesystem
mounts, and keeps portable user state under /data.
This is deliberately simpler than full Hermes Box: there are no release locks, offline artifact closures, or transactional component updates. The reliability boundary is narrower: safe lifecycle operations and verified state backups.
Model
./box new alpha
│ Ubuntu VM + current toolchain
▼
smolvm "alpha"
│ managed tools: /opt/hermes-box and /usr/local
│ portable state: /data/home/agent
│ .claude · .codex · .hermes · .executor · workspace · XDG state
│
│ ./box save alpha
▼
backups/alpha-<timestamp>.tar.gz.gpg
encrypted, validated state archive plus runtime-version manifest
The VM protects the host filesystem. Networking is always enabled because
provisioning and the agent tools require internet access. Tools inside one box
share the agent account, credentials, network, and passwordless guest sudo;
they are one trust domain.
/data is an organizational boundary on the VM's persistent root overlay, not
a separate virtual disk. Deleting or losing the VM loses live state, so keep
current backups for anything important.
Quick start
Host prerequisites:
- macOS with the smolvm-supported virtualization stack, or Linux on x86_64 or
arm64 with KVM available and the current user allowed to access
/dev/kvm; smolvm, GPG, curl, jq, tar, awk, and standard Bash command-line tools; and- a graphical opener for
box open(openon macOS, orxdg-open/gioon Linux). On another desktop, setBOX_BROWSERto a graphical opener. It receives the secret authenticated URL directly as its sole argument, so do not use a wrapper that logs arguments.
On Linux, verify KVM access before creating a box:
test -r /dev/kvm -a -w /dev/kvm
smolvm machine ls
./box new alpha
./box doctor alpha
./box enter alpha
# Inside: hermes setup --portal, claude, codex
./box open alpha
./box save alpha
# Restore elsewhere. The archive is decrypted and validated before a VM is made.
./box load backups/alpha-20260625-120000.tar.gz.gpg beta
Set BOX_PASSPHRASE for unattended encryption/decryption. Otherwise GPG
passphrases are read from the terminal without echo.
Commands
| Command | Behavior |
|---|---|
box new <name> |
Create, provision, wire MCP, and health-check a box; attempt verified cleanup on failure |
box enter <name> |
Log in as agent and attach persistent tmux session main |
box ls [--all] |
List managed boxes, or every smolvm VM |
box open <name> |
Open the authenticated Executor UI without printing its token |
box doctor <name> |
Check required tools, durable state, guest MCP, and the host MCP endpoint when exposed |
box repair <name> |
Re-run provisioning, refresh managed assets, and re-check health |
box stop / start <name> |
Stop or start a VM under a per-box mutation lock |
box save <name> [out] |
Pause Executor, archive /data, validate, encrypt, and verify without overwriting |
box load <file> [name] |
Validate first, provision a clean VM, restore while Executor is paused, then verify |
box extract <file> [dir] |
Validate and extract an archive without creating a VM |
box rm <name> [--force] |
Show backup status and require exact-name confirmation unless forced |
Mutating commands use local lock directories so concurrent operations cannot modify the same box or registry entry.
Executor and MCP
Executor runs continuously on guest 127.0.0.1:4788. If web exposure is
enabled, smolvm forwards a unique host-loopback port in the configured
4790–4999 range. box open reads Executor's stable local token and hands the
authenticated URL directly to the browser without printing the credential.
The workload keeps one Executor daemon alive. Claude and Codex connect to that
daemon's authenticated Streamable HTTP endpoint; they do not launch executor mcp as a second process. The bearer token remains under /data in Executor's
mode-0600 auth file and a mode-0600 Codex environment file. Set
WIRE_EXECUTOR_MCP=0 before provisioning to disable registration.
The guest doctor check—and the host check when web exposure is enabled—performs
a complete MCP handshake: it uses jq to validate the JSON initialize
result and negotiated protocol version, sends the
initialized notification, and closes the session best-effort. Requests have
bounded timeouts. A listening socket, malformed result, 404 page, or HTTP 500
response does not count as healthy. Without an exposed port, doctor explicitly
reports that the host endpoint check was skipped.
Inside a box:
hb status
hb doctor
hb versions
hb down # durable pause; the workload will not immediately restart it
hb up
hb wire-mcp # replace stale/legacy wiring with authenticated HTTP MCP
hb logs executor
Backup and restore guarantees
box save:
- acquires the box mutation lock;
- gracefully pauses Executor and waits for its port to close;
- atomically writes a mode-0600 runtime-version manifest at
~/.config/hermes-box/runtime-manifestand archives/datainside the guest; - copies the archive using
smolvm machine cp; - validates its paths and required durable-home layout;
- encrypts to a unique temporary destination;
- decrypts and lists the encrypted result as a verification pass; and
- publishes it without overwriting an existing backup.
Host and guest plaintext temporaries and operation locks are removed by exit and signal traps. Guest plaintext is removed before Executor is resumed, even when a later save step fails. Do not actively edit workspace files during a save; Executor is quiesced, but arbitrary editor or agent processes are not frozen.
box load decrypts and validates before spending time or creating resources.
It restores while Executor is paused, removes hidden as well as normal old
state, refreshes repository-owned guest assets, starts a fresh daemon against
the restored database, repairs MCP wiring, and runs the doctor. A failed new or
load operation—including interruption by HUP, INT, or TERM—attempts to remove
only an incomplete destination VM proven to have been created by that
invocation. Registry metadata is removed only after VM absence is verified. If
cleanup cannot delete the VM or acquire the registry lock, it preserves
metadata and prints recovery guidance. An unmanaged or ambiguous same-named
smolvm machine is never deleted.
Backups are state-portable, not reproducible machine images. Restoring later provisions the then-current Ubuntu packages and upstream tool releases before injecting saved state. The included runtime manifest helps diagnose version drift but does not eliminate it.
Tool installation and state
| Tool | Installation | Durable state |
|---|---|---|
| Claude Code | current npm package under /opt/hermes-box |
~/.claude |
| Codex | current npm package under /opt/hermes-box |
~/.codex |
| Hermes | official headless installer | ~/.hermes |
| Executor | current npm package under /opt/hermes-box |
~/.executor plus XDG directories |
| Neovim | Ubuntu package | XDG config/data/state |
Configuration lives in box.env. The provisioning script installs a root-owned
copy at /etc/hermes-box.env, so guest helpers honor INSTALL_HERMES,
INSTALL_EXECUTOR, EXECUTOR_PORT, and WIRE_EXECUTOR_MCP consistently.
Local validation
make check
This requires ShellCheck, Python 3, and jq, and runs Bash syntax checks, static contract checks, protocol-health regressions, and local archive/lifecycle smoke tests. It does not create a VM or contact upstream installers. There is intentionally no CI configuration yet.