<header> <h1>Hermes Box Lite</h1> <p class="dek">A practical guide to creating, using, backing up, restoring, and repairing isolated agent boxes.</p></header> <div class="callout note"> <span class="ico" aria-hidden="true">i</span> <div class="body"> <div class="title">The operating model</div> <p>Tools are replaceable; state is precious. Claude Code, Codex, Hermes, Executor, and Neovim live in an isolated smolvm VM. User state lives under <code>/data</code> and travels through encrypted backups.</p> </div></div> <div class="page-layout"> <aside class="section-nav" aria-label="On this page"> <p class="label">On this page</p> <nav> <ul> <li><a href="#quick-start">Quick start</a></li> <li><a href="#daily-use">Daily use</a></li> <li><a href="#backup-restore">Backup and restore</a></li> <li><a href="#health-repair">Health and repair</a></li> <li><a href="#configuration">Configuration</a></li> <li><a href="#security">Security model</a></li> <li><a href="#troubleshooting">Troubleshooting</a></li> </ul> </nav> </aside> <div class="page-content"> <section id="quick-start"> <h2>Quick start</h2> <p>Run these commands from the <code>hermes-box-lite</code> repository on macOS, or on x86_64/arm64 Linux with KVM available and your user allowed to access <code>/dev/kvm</code>. Install <code>smolvm</code>, GPG, curl, jq, tar, awk, and standard Bash command-line tools first.</p> <p>On Linux, verify virtualization access before creating a box:</p> <pre><code>test -r /dev/kvm -a -w /dev/kvmsmolvm machine ls</code></pre> <h3>1. Create and verify a box</h3> <pre><code>./box new alpha./box doctor alpha</code></pre> <p>Creation boots Ubuntu with configurable CPU, memory, and a 64 GiB default overlay, installs the toolchain and a full-SHA-pinned Hermes checkout, starts Executor, registers its authenticated HTTP MCP endpoint with Claude and Codex, and runs health checks. Hermes begins durably disabled until setup or a migration cutover is complete.</p> <h3>2. Enter and authenticate</h3> <pre><code>./box enter alpha</code></pre> <p>You enter as <code>agent</code> in a persistent tmux session under <code>~/workspace</code>. Authenticate the tools you intend to use:</p> <pre><code>hermes setup --portalclaudecodex</code></pre> <h3>3. Open Executor and save the state</h3> <pre><code>./box open alpha./box save alpha</code></pre> <p><code>box open</code> waits for the authenticated forwarded endpoint, then launches the Executor UI without printing its bearer token. <code>box save</code> quiesces Hermes and Executor, checkpoints and verifies SQLite, excludes transient/native caches and locks, validates and encrypts the archive, then selectively restores the prior service state.</p> </section> <section id="daily-use"> <h2>Daily use</h2> <p>The full command reference (every <code>box</code> subcommand and what it does) lives in <a href="../README.md#commands">the README's Commands table</a> — kept there as the single source of truth so it can't drift out of sync with this page.</p> <h3>Inside the box</h3> <pre><code>hb statushb versionshb doctorhb logs executorhb logs hermeshb verify-statehb acknowledge-active-pathshb cutover-ready</code></pre> <p>The workload supervises Executor and the Hermes gateway without duplicate processes. Doctor is read-only and treats deliberate quiescence as policy, while start and repair remain explicit mutations. Gateway enable requires the full single-writer confirmation phrase printed by <code>hb gateway-enable</code>.</p> </section> <section id="backup-restore"> <h2>Backup and restore</h2> <p>The exact guarantees each of these commands makes — what gets quiesced, validated, excluded, and verified, step by step — are documented once, in <a href="../README.md#backup-and-restore-guarantees">README's Backup and restore guarantees</a>, so they can't quietly drift out of sync with this walkthrough. What follows here is the practical "what do I actually type" version.</p> <h3>Create a backup</h3> <pre><code>./box save alpha</code></pre> <p>By default, this creates <code>backups/alpha-<timestamp>.tar.gz.gpg</code> and refuses to overwrite an existing destination. Set a passphrase in the environment for unattended use:</p> <pre><code>BOX_PASSPHRASE='your-local-secret' ./box save alpha</code></pre> <h3>Restore into a new box</h3> <pre><code>./box load backups/alpha-20260625-120000.tar.gz.gpg beta</code></pre> <p>The archive is decrypted and validated before a VM is even created. The Hermes gateway stays disabled afterward, so a restore rehearsal can never accidentally claim a live messaging identity.</p> <h3>Import from Eventide or another Hermes host</h3> <pre><code>./box import-hermes alpha hermes-backup.zip --map /Users/davis=/data/home/agent</code></pre> <p>Validates and atomically imports native Hermes state with the gateway left disabled. Review the import manifest, run <code>hb acknowledge-active-paths</code>, then require <code>hb cutover-ready</code> before enabling the gateway — see the README link above for exactly what the import does and skips.</p> <h3>Inspect a backup without a VM</h3> <pre><code>./box extract backups/alpha-20260625-120000.tar.gz.gpg</code></pre> <p>Extraction validates the archive and writes to a new directory under <code>backups/</code>. Treat extracted contents as sensitive: they can contain credentials, sessions, private work, and Executor data.</p> <div class="callout warn"> <span class="ico" aria-hidden="true">!</span> <div class="body"> <div class="title">Backups preserve state, not an exact machine</div> <p>Hermes is pinned by full Git SHA and can be seeded from an ignored local Git bundle for a custom Eventide commit. Other OS and tool packages can still drift; this remains a state backup, not an offline VM image.</p> </div> </div> </section> <section id="health-repair"> <h2>Health and repair</h2> <p>Start with the doctor whenever a box feels partly broken:</p> <pre><code>./box doctor alpha</code></pre> <p>Doctor performs a bounded, authenticated MCP handshake through the guest-local endpoint and, when web exposure is enabled, the forwarded host endpoint. It uses jq to validate the HTTP 200 JSON <code>initialize</code> result, negotiated protocol version, response content type, and session ID, sends the initialized notification, then closes the session best-effort. A bare listener, malformed result, 404, or HTTP 500 response fails health. Without an exposed port, doctor reports the host check as skipped.</p> <p>If managed tools, profiles, or MCP wiring need repair, re-run provisioning:</p> <pre><code>./box repair alpha</code></pre> <p>Repair quiesces Hermes and Executor, refreshes packages and repository-owned guest assets, checks out the configured Hermes SHA exactly, resumes the prior service policy, repairs MCP wiring, and runs the doctor.</p> <h3>Remove a box safely</h3> <pre><code>./box rm alpha</code></pre> <p>The command reports whether it can find a recent backup and requires the exact box name as confirmation. For intentional non-interactive deletion:</p> <pre><code>./box rm alpha --force</code></pre> </section> <section id="configuration"> <h2>Configuration</h2> <p>Edit <code>box.env</code> before creating or repairing a box.</p> <div class="table-wrap" role="region" aria-label="Hermes Box Lite configuration" tabindex="0"> <table> <caption>Where each setting lives</caption> <thead> <tr><th scope="col">Topic</th><th scope="col">See</th></tr> </thead> <tbody> <tr><th scope="row">Every setting and its effect</th><td><code>box.env</code> itself — each key has an inline comment, and it's the literal source of truth this page would otherwise just be restating.</td></tr> <tr><th scope="row">Tool installation paths and durable state</th><td><a href="../README.md#tool-installation-and-state">README's Tool installation and state table</a>.</td></tr> </tbody> </table> </div> <p>Provisioning installs a root-owned copy at <code>/etc/hermes-box.env</code>, so guest helpers use the same settings as the host workflow.</p> </section> <section id="security"> <h2>Security model</h2> <ul> <li>The VM has no host filesystem mounts.</li> <li>Executor's forwarded web port is host-loopback-only.</li> <li>Hermes API forwarding is disabled by default and host-loopback-only when enabled.</li> <li>Networking is always enabled for provisioning and agent tools.</li> <li>Claude, Codex, Hermes, Executor, and plugins share one guest account and credential set.</li> <li>The <code>agent</code> user has passwordless sudo inside the guest.</li> <li>Encrypted backups and extracted state should be handled as secret material.</li> </ul> <p>The VM is the host-protection boundary. Tools inside a box are not isolated from one another. A compromised tool, plugin, MCP source, or prompt-injected agent may access the other tools' credentials and workspace.</p> </section> <section id="troubleshooting"> <h2>Troubleshooting</h2> <h3>Executor or MCP is unhealthy</h3> <pre><code>./box doctor alpha./box repair alpha</code></pre> <p>Inside the box, inspect <code>hb status</code> and <code>hb logs executor</code>. Run <code>hb wire-mcp</code> to replace stale legacy stdio wiring with the authenticated HTTP configuration.</p> <h3><code>box open</code> reports success but no browser appears</h3> <p>This is expected on a headless host reached over SSH or Tailscale rather than at its console — see <a href="../README.md#executor-and-mcp">README's Executor and MCP section</a> for how to reach the UI from a separate client machine instead.</p> <h3>An operation says the box is locked</h3> <p>Another mutation may be running. Locks contain an owning PID and stale locks are recovered automatically after that process exits. Do not manually remove a lock while a save, load, repair, or delete is active.</p> <h3>A restore fails before VM creation</h3> <p>The passphrase may be incorrect, or the decrypted archive may be corrupt or unsafe. This failure intentionally occurs before provisioning so it does not leave an orphan VM.</p> <h3><code>box new</code> fails with a Hermes installer checksum error</h3> <p>Upstream has rotated <code>install.sh</code> since <code>HERMES_INSTALLER_SHA256</code> in <code>box.env</code> was last pinned. Run <code>make check-hermes-pin</code> to confirm the drift and see the current upstream hash, review the new installer, then update <code>box.env</code> yourself.</p> <h3>Validate the repository</h3> <pre><code>make check</code></pre> <p>This requires ShellCheck, Python 3, and jq, then runs Bash/Python syntax checks, static contracts, protocol-health regressions, encrypted archive round trips, native Hermes ZIP/import safety tests, validation-before-VM tests, cleanup checks, and mock failure rollback.</p> </section> </div></div>
<header>
<h1>Hermes Box Lite</h1>
<p class="dek">A practical guide to creating, using, backing up, restoring, and repairing isolated agent boxes.</p>
</header>
<div class="callout note">
<span class="ico" aria-hidden="true">i</span>
<div class="body">
<div class="title">The operating model</div>
<p>Tools are replaceable; state is precious. Claude Code, Codex, Hermes, Executor, and Neovim live in an isolated smolvm VM. User state lives under <code>/data</code> and travels through encrypted backups.</p>
</div>
</div>
<div class="page-layout">
<aside class="section-nav" aria-label="On this page">
<p class="label">On this page</p>
<nav>
<ul>
<li><a href="#quick-start">Quick start</a></li>
<li><a href="#daily-use">Daily use</a></li>
<li><a href="#backup-restore">Backup and restore</a></li>
<li><a href="#health-repair">Health and repair</a></li>
<li><a href="#configuration">Configuration</a></li>
<li><a href="#security">Security model</a></li>
<li><a href="#troubleshooting">Troubleshooting</a></li>
</ul>
</nav>
</aside>
<div class="page-content">
<section id="quick-start">
<h2>Quick start</h2>
<p>Run these commands from the <code>hermes-box-lite</code> repository on macOS, or on x86_64/arm64 Linux with KVM available and your user allowed to access <code>/dev/kvm</code>. Install <code>smolvm</code>, GPG, curl, jq, tar, awk, and standard Bash command-line tools first.</p>
<p>On Linux, verify virtualization access before creating a box:</p>
<pre><code>test -r /dev/kvm -a -w /dev/kvm
smolvm machine ls</code></pre>
<h3>1. Create and verify a box</h3>
<pre><code>./box new alpha
./box doctor alpha</code></pre>
<p>Creation boots Ubuntu with configurable CPU, memory, and a 64 GiB default overlay, installs the toolchain and a full-SHA-pinned Hermes checkout, starts Executor, registers its authenticated HTTP MCP endpoint with Claude and Codex, and runs health checks. Hermes begins durably disabled until setup or a migration cutover is complete.</p>
<h3>2. Enter and authenticate</h3>
<pre><code>./box enter alpha</code></pre>
<p>You enter as <code>agent</code> in a persistent tmux session under <code>~/workspace</code>. Authenticate the tools you intend to use:</p>
<pre><code>hermes setup --portal
claude
codex</code></pre>
<h3>3. Open Executor and save the state</h3>
<pre><code>./box open alpha
./box save alpha</code></pre>
<p><code>box open</code> waits for the authenticated forwarded endpoint, then launches the Executor UI without printing its bearer token. <code>box save</code> quiesces Hermes and Executor, checkpoints and verifies SQLite, excludes transient/native caches and locks, validates and encrypts the archive, then selectively restores the prior service state.</p>
</section>
<section id="daily-use">
<h2>Daily use</h2>
<p>The full command reference (every <code>box</code> subcommand and what it does) lives in
<a href="../README.md#commands">the README's Commands table</a> — kept there as the single
source of truth so it can't drift out of sync with this page.</p>
<h3>Inside the box</h3>
<pre><code>hb status
hb versions
hb doctor
hb logs executor
hb logs hermes
hb verify-state
hb acknowledge-active-paths
hb cutover-ready</code></pre>
<p>The workload supervises Executor and the Hermes gateway without duplicate processes. Doctor is read-only and treats deliberate quiescence as policy, while start and repair remain explicit mutations. Gateway enable requires the full single-writer confirmation phrase printed by <code>hb gateway-enable</code>.</p>
</section>
<section id="backup-restore">
<h2>Backup and restore</h2>
<p>The exact guarantees each of these commands makes — what gets quiesced, validated,
excluded, and verified, step by step — are documented once, in
<a href="../README.md#backup-and-restore-guarantees">README's Backup and restore guarantees</a>,
so they can't quietly drift out of sync with this walkthrough. What follows here is the
practical "what do I actually type" version.</p>
<h3>Create a backup</h3>
<pre><code>./box save alpha</code></pre>
<p>By default, this creates <code>backups/alpha-<timestamp>.tar.gz.gpg</code> and refuses to overwrite an existing destination. Set a passphrase in the environment for unattended use:</p>
<pre><code>BOX_PASSPHRASE='your-local-secret' ./box save alpha</code></pre>
<h3>Restore into a new box</h3>
<pre><code>./box load backups/alpha-20260625-120000.tar.gz.gpg beta</code></pre>
<p>The archive is decrypted and validated before a VM is even created. The Hermes gateway stays disabled afterward, so a restore rehearsal can never accidentally claim a live messaging identity.</p>
<h3>Import from Eventide or another Hermes host</h3>
<pre><code>./box import-hermes alpha hermes-backup.zip --map /Users/davis=/data/home/agent</code></pre>
<p>Validates and atomically imports native Hermes state with the gateway left disabled. Review the
import manifest, run <code>hb acknowledge-active-paths</code>, then require <code>hb cutover-ready</code>
before enabling the gateway — see the README link above for exactly what the import does and skips.</p>
<h3>Inspect a backup without a VM</h3>
<pre><code>./box extract backups/alpha-20260625-120000.tar.gz.gpg</code></pre>
<p>Extraction validates the archive and writes to a new directory under <code>backups/</code>. Treat extracted contents as sensitive: they can contain credentials, sessions, private work, and Executor data.</p>
<div class="callout warn">
<span class="ico" aria-hidden="true">!</span>
<div class="body">
<div class="title">Backups preserve state, not an exact machine</div>
<p>Hermes is pinned by full Git SHA and can be seeded from an ignored local Git bundle for a custom Eventide commit. Other OS and tool packages can still drift; this remains a state backup, not an offline VM image.</p>
</div>
</div>
</section>
<section id="health-repair">
<h2>Health and repair</h2>
<p>Start with the doctor whenever a box feels partly broken:</p>
<pre><code>./box doctor alpha</code></pre>
<p>Doctor performs a bounded, authenticated MCP handshake through the guest-local endpoint and, when web exposure is enabled, the forwarded host endpoint. It uses jq to validate the HTTP 200 JSON <code>initialize</code> result, negotiated protocol version, response content type, and session ID, sends the initialized notification, then closes the session best-effort. A bare listener, malformed result, 404, or HTTP 500 response fails health. Without an exposed port, doctor reports the host check as skipped.</p>
<p>If managed tools, profiles, or MCP wiring need repair, re-run provisioning:</p>
<pre><code>./box repair alpha</code></pre>
<p>Repair quiesces Hermes and Executor, refreshes packages and repository-owned guest assets, checks out the configured Hermes SHA exactly, resumes the prior service policy, repairs MCP wiring, and runs the doctor.</p>
<h3>Remove a box safely</h3>
<pre><code>./box rm alpha</code></pre>
<p>The command reports whether it can find a recent backup and requires the exact box name as confirmation. For intentional non-interactive deletion:</p>
<pre><code>./box rm alpha --force</code></pre>
</section>
<section id="configuration">
<h2>Configuration</h2>
<p>Edit <code>box.env</code> before creating or repairing a box.</p>
<div class="table-wrap" role="region" aria-label="Hermes Box Lite configuration" tabindex="0">
<table>
<caption>Where each setting lives</caption>
<thead>
<tr><th scope="col">Topic</th><th scope="col">See</th></tr>
</thead>
<tbody>
<tr><th scope="row">Every setting and its effect</th><td><code>box.env</code> itself — each key has an inline comment, and it's the literal source of truth this page would otherwise just be restating.</td></tr>
<tr><th scope="row">Tool installation paths and durable state</th><td><a href="../README.md#tool-installation-and-state">README's Tool installation and state table</a>.</td></tr>
</tbody>
</table>
</div>
<p>Provisioning installs a root-owned copy at <code>/etc/hermes-box.env</code>, so guest helpers use the same settings as the host workflow.</p>
</section>
<section id="security">
<h2>Security model</h2>
<ul>
<li>The VM has no host filesystem mounts.</li>
<li>Executor's forwarded web port is host-loopback-only.</li>
<li>Hermes API forwarding is disabled by default and host-loopback-only when enabled.</li>
<li>Networking is always enabled for provisioning and agent tools.</li>
<li>Claude, Codex, Hermes, Executor, and plugins share one guest account and credential set.</li>
<li>The <code>agent</code> user has passwordless sudo inside the guest.</li>
<li>Encrypted backups and extracted state should be handled as secret material.</li>
</ul>
<p>The VM is the host-protection boundary. Tools inside a box are not isolated from one another. A compromised tool, plugin, MCP source, or prompt-injected agent may access the other tools' credentials and workspace.</p>
</section>
<section id="troubleshooting">
<h2>Troubleshooting</h2>
<h3>Executor or MCP is unhealthy</h3>
<pre><code>./box doctor alpha
./box repair alpha</code></pre>
<p>Inside the box, inspect <code>hb status</code> and <code>hb logs executor</code>. Run <code>hb wire-mcp</code> to replace stale legacy stdio wiring with the authenticated HTTP configuration.</p>
<h3><code>box open</code> reports success but no browser appears</h3>
<p>This is expected on a headless host reached over SSH or Tailscale rather than at its console — see <a href="../README.md#executor-and-mcp">README's Executor and MCP section</a> for how to reach the UI from a separate client machine instead.</p>
<h3>An operation says the box is locked</h3>
<p>Another mutation may be running. Locks contain an owning PID and stale locks are recovered automatically after that process exits. Do not manually remove a lock while a save, load, repair, or delete is active.</p>
<h3>A restore fails before VM creation</h3>
<p>The passphrase may be incorrect, or the decrypted archive may be corrupt or unsafe. This failure intentionally occurs before provisioning so it does not leave an orphan VM.</p>
<h3><code>box new</code> fails with a Hermes installer checksum error</h3>
<p>Upstream has rotated <code>install.sh</code> since <code>HERMES_INSTALLER_SHA256</code> in <code>box.env</code> was last pinned. Run <code>make check-hermes-pin</code> to confirm the drift and see the current upstream hash, review the new installer, then update <code>box.env</code> yourself.</p>
<h3>Validate the repository</h3>
<pre><code>make check</code></pre>
<p>This requires ShellCheck, Python 3, and jq, then runs Bash/Python syntax checks, static contracts, protocol-health regressions, encrypted archive round trips, native Hermes ZIP/import safety tests, validation-before-VM tests, cleanup checks, and mock failure rollback.</p>
</section>
</div>
</div>