a73x

3432ac6b

docs: v0.0.4 release notes

a73x   2026-08-08 14:02

Commit message
docs: v0.0.4 release notes

Roll the release notes, upgrade steps and quickstart forward to v0.0.4: public
MCP at /mcp, the self-updating agent, key material sealed at rest, and the
staging-then-prod release pipeline.

ROADMAP.md
Old New
@@ -3,19 +3,19 @@
3 What shipped in each version is in the 3 What shipped in each version is in the
4 [release notes](https://eitri.sh/docs/releases/); this is what's ahead. 4 [release notes](https://eitri.sh/docs/releases/); this is what's ahead.
5 5
6 ## v0.0.4 — candidates 6 ## v0.0.5 — candidates
7 7
8 - Connectors: browser clients (claude.ai among them) sign in to the MCP
9 endpoint with OAuth rather than a pasted token—dynamic client registration
10 on eitri-oidc, so a connector enrols itself
8 - Bridged guest networking: a Linux host puts its guests on the operator's 11 - Bridged guest networking: a Linux host puts its guests on the operator's
9 own network — taps on a named bridge, the site's DHCP addresses the guests, 12 own network—taps on a named bridge, the site's DHCP addresses the guests,
10 the agent discovers the result 13 the agent discovers the result
11 - Public gateway: route inbound traffic to guest services through eitri, 14 - Public gateway: route inbound traffic to guest services through eitri,
12 building on published ports 15 building on published ports
13 - A PAT is enough: an opt-in eitri-managed tenant CA signs short-lived SSH 16 - Hot-reload trusted CAs into running guests: a CA added to the tenant reaches
14 certificates, so a bare token can reach its VMs—BYO CAs stay first-class, 17 guests that already exist—delivery over vsock or a host file mount that sshd
15 and a tenant that wants eitri holding no signing power keeps that 18 reads per connection, so no recreation and no SSH bootstrap problem. Needs
16 - Remote MCP: a hosted endpoint (api.eitri.sh/mcp) any client can connect 19 changing a tenant's trust set to demand more than a bearer PAT first, or a
17 to—streamable HTTP, per-tenant auth, TLS at the edge; its identity story 20 stolen token becomes access to every guest
18 is the managed tenant CA above
19 - Live cloud-hypervisor handover for running guests 21 - Live cloud-hypervisor handover for running guests
20 - Provider integration: provision on existing cloud infrastructure (aws, gcp,
21 proxmox, …)
docs/quickstart.md
Old New
@@ -69,6 +69,14 @@ mkdir -p ~/.local/bin && cp eitri-agent ~/.local/bin/
69 State lands in `~/.eitri/agent`, logs in `~/Library/Logs/eitri-agent.log`, and 69 State lands in `~/.eitri/agent`, logs in `~/Library/Logs/eitri-agent.log`, and
70 the agent starts with your session. 70 the agent starts with your session.
71 71
72 The agent dials its guests over vmnet, and macOS gates local-network dialing
73 per app: the agent needs the **Local Network** permission. Run from a
74 terminal, the agent is prompted for it; installed as a LaunchAgent, it may
75 never be. Grant it under System Settings → Privacy & Security → Local
76 Network. Without
77 it, guests boot and take a vmnet lease but stay unreachable through the
78 gate—`eitri ssh` fails with "cannot reach VM".
79
72 Keep the binary somewhere this account owns. The agent replaces its own binary 80 Keep the binary somewhere this account owns. The agent replaces its own binary
73 when it upgrades, so a root-owned prefix like `/usr/local/bin` would look tidy 81 when it upgrades, so a root-owned prefix like `/usr/local/bin` would look tidy
74 and quietly disable every future upgrade—the installer refuses rather than let 82 and quietly disable every future upgrade—the installer refuses rather than let
docs/releases.md
Old New
@@ -10,34 +10,54 @@ running VM.
10 A PAT is enough. Point an LLM client anywhere on the internet at 10 A PAT is enough. Point an LLM client anywhere on the internet at
11 `https://api.eitri.sh/mcp` with a personal access token and it gets the whole 11 `https://api.eitri.sh/mcp` with a personal access token and it gets the whole
12 eitri toolset: create a VM, run commands in it, publish a port, hand back the 12 eitri toolset: create a VM, run commands in it, publish a port, hand back the
13 address. No local install, no config file, no CA of your own. 13 address. No local install, no config file, no CA of your own. Around it, the
14 14 console is drawn in the site's own language.
15 **The MCP endpoint.** eitri-server serves MCP at `/mcp` over streamable HTTP, 15
16 stateless, authenticated with the same bearer token the API takes. One binary, 16 **MCP.** eitri-server serves MCP at `/mcp` over streamable HTTP, authenticated
17 one deploy: the tools call the API in-process, so tenant filtering and 17 with the same bearer token the API takes; a caller sees exactly the fleet its
18 authorization are the API's own, and a caller sees exactly the fleet its token 18 token can see. `api.eitri.sh` carries that one route and nothing else. The
19 can see. The stdio binary is unchanged and still there for local use—both 19 stdio binary is there for local use—both transports serve the same tools.
20 transports serve the same tools, from the same code. 20
21 21 **Delegated access, not a held key.** eitri never holds a signing key for your
22 **Delegated access, not a held key.** A token holder has no key to sign with, 22 guests. When a token-only caller needs SSH access, you delegate it: sign the
23 and eitri has none to lend: it holds no signing key for anyone. So the direction 23 public key eitri shows you with your own CA, on your own TTL (`ssh-keygen -s`).
24 reverses. eitri generates an ephemeral keypair, in memory only, and hands you 24 Revoke it by letting it expire or by deleting it — eitri's access ends when you
25 the public half; you sign it with your own CA on your own TTL (`ssh-keygen -s`) 25 say so. Because the certificate chains to a CA you already registered, VMs
26 and hand the certificate back. eitri authenticates as that key plus that 26 created before you delegated accept it too.
27 certificate until it expires, and holds nothing else. A restart drops the 27
28 delegation and you delegate again. Because the certificate chains to a CA you 28 **Your guests' host keys stay on your hosts.** A guest's SSH host key is born on
29 already registered, VMs created before you delegated accept it too. 29 the machine that runs it and never leaves it; the control plane signs only
30 30 public keys. The database now holds no private keys at all — keys stored by an
31 **Your guests' host keys stay on your hosts.** A guest's SSH host key is 31 earlier release are dropped the first time the new server opens it.
32 generated by the machine that runs it and never leaves it. The host reports the 32
33 public half, the control plane signs a certificate for the name on the VM's 33 `vm_create` reports what it is waiting for as it waits — usually seconds,
34 row, and the guest boots with a key nothing above its host has ever held. 34 minutes when a host downloads an image for the first time — so a long call reads
35 Opening the database clears every host key escrowed by an earlier release. 35 as a VM coming up rather than silence.
36 36
37 **Progress on the long call.** `vm_create` waits for the guest to boot and 37 **Upgrades read a host bundle.** A self-upgrading agent can now be handed the
38 cloud-init to settle, which can take minutes. It now reports what it is waiting 38 same tarball you would install by hand, verified against the release manifest
39 for as it waits, so a model watching a ten-minute call sees a VM coming up 39 as ever. `/dl` still carries bare binaries beside the bundles for agents from
40 rather than silence. 40 older releases.
41
42 **The console speaks the site's language.** We revamped the console:
43 monospace, hairline rules, light and dark mode—because we care.
44
45 **Known limits.**
46
47 - `/mcp` authenticates with a bearer token and nothing else. Browser
48 connectors that sign in with OAuth—claude.ai among them—cannot reach it.
49 - A delegation lives in memory. A control-plane restart or redeploy drops it
50 and you delegate again — one `ssh-keygen` against a public key that has not
51 changed. This is a property, not a bug: eitri's access to your guests ends
52 when its process does.
53 - An agent from an earlier release does not know how to generate a guest host
54 key, so a VM it creates against a v0.0.4 control plane boots with an
55 uncertified one and `eitri ssh` fails host verification with a clear error.
56 Upgrade the host's agent — from the console, as usual — and re-create the VM.
57 - Self-hosters: v0.0.4 adds a required `key_encryption_key` to `server.json`
58 (`openssl rand -hex 32`), and the server refuses to start without it. It
59 encrypts the fleet's own SSH CA and gate host key, so keep it outside your
60 database backups.
41 61
42 ## v0.0.3 62 ## v0.0.3
43 63
docs/upgrade.md
Old New
@@ -22,13 +22,57 @@ If a download fails, nothing is swapped; click again to retry. To roll back by
22 hand, stop the agent, move `eitri-agent.prev` back over the binary, and start 22 hand, stop the agent, move `eitri-agent.prev` back over the binary, and start
23 it again. 23 it again.
24 24
25 **Requirements.** The button lights up only when the running agent reports a 25 **Requirements.** The button lights up only when the running agent's version
26 release version (`vX.Y.Z`) or a pre-release of one (`vX.Y.Z-pre.N`, which orders 26 orders before the published release. Release tags (`vX.Y.Z`), pre-releases
27 below the release it leads to)—agents built from an untagged or dirty tree 27 (`vX.Y.Z-pre.N`, which order below the release they lead to), and git-describe
28 report a git hash instead and are never offered upgrades. The server needs 28 builds (`vX.Y.Z-N-g<hex>`, N commits past the tag) all order, so a
29 `release_manifest_url` reachable; set it to `""` in the server config to 29 hand-deployed describe build behind the latest release is offered the upgrade,
30 and one ahead of it is never offered a downgrade. Anything else—`dev`, a
31 `-dirty` tree—orders before nothing and is never offered anything. The server
32 needs `release_manifest_url` reachable; set it to `""` in the server config to
30 disable upgrade checks entirely. 33 disable upgrade checks entirely.
31 34
35 ## Agents, by hand
36
37 An agent whose version never orders—a `dev` or `-dirty` build—never gets the
38 button. The manual path is the same swap, done by you.
39
40 On Linux, set `V` to the release you want (shown at
41 [/dl](https://eitri.sh/dl/)); on an arm64 host, `_arm64` replaces `_amd64`
42 throughout:
43
44 ```sh
45 V=v0.0.3
46 curl -fsSLO "https://eitri.sh/dl/$V/eitri-agent_linux_amd64"
47 curl -fsSL "https://eitri.sh/dl/$V/SHA256SUMS" | grep ' eitri-agent_linux_amd64$' | sha256sum -c -
48 sudo cp /usr/local/bin/eitri-agent /usr/local/bin/eitri-agent.prev
49 sudo install -m 0755 eitri-agent_linux_amd64 /usr/local/bin/eitri-agent
50 sudo systemctl restart eitri-agent
51 ```
52
53 Running VMs survive the restart—the unit's `KillMode=process` (see Operations
54 below) leaves the guests alone. The `.prev` copy mirrors what the button path
55 keeps, so rollback is the same either way.
56
57 On a Mac the binary lives in the running account's own space (e.g.
58 `~/.local/bin/eitri-agent`). Overwrite it with `eitri-agent` from the darwin
59 bundle, then restart the LaunchAgent:
60
61 ```sh
62 launchctl kickstart -k gui/$(id -u)/sh.eitri.agent
63 ```
64
65 No `sudo` anywhere, same as the install. If guests turn unreachable through
66 the gate after the swap ("cannot reach VM"), check the agent's Local Network
67 permission—the quickstart's "Join a Mac" section covers it.
68
69 If the swapped-in agent reports it is not enrolled, it is running as a
70 different account than the one that joined: enrollment state is per-account
71 (`~/.eitri/agent` on macOS, `/var/lib/eitri-agent` on Linux), so under a new
72 account the binary is a new host. Join it fresh from the console, then
73 decommission the old host row it leaves behind. If that old agent is gone for
74 good, the delete needs force—the dead-hardware escape hatch on host delete.
75
32 ## The server 76 ## The server
33 77
34 The console banner links here when the published release differs from the 78 The console banner links here when the published release differs from the
@@ -43,6 +87,13 @@ reconciling and VMs keep running while it's away:
43 A newer server with older agents is safe: new fields in the sync protocol are 87 A newer server with older agents is safe: new fields in the sync protocol are
44 ignored by agents that predate them. 88 ignored by agents that predate them.
45 89
90 **One exception, from v0.0.4 on.** A guest's SSH host key is generated by the
91 host that runs it, and an agent from before v0.0.4 does not know how to do
92 that. A VM created on such a host boots with a host key nothing has certified,
93 and `eitri ssh` refuses it at host verification with a clear error. Existing
94 VMs are unaffected — they keep the host key and certificate they were built
95 with. Upgrade the host's agent, then re-create any VM created in the meantime.
96
46 ## cloud-hypervisor 97 ## cloud-hypervisor
47 98
48 Swap `/usr/local/bin/cloud-hypervisor` on the host. New and restarted VMs use 99 Swap `/usr/local/bin/cloud-hypervisor` on the host. New and restarted VMs use