4.6 KiB
PRD prd-new: smolmachines sidecar VM
- Status: Draft
- Author: codex
- Created: 2026-07-09
- Issue: #332
Summary
Run the smolmachines backend's trusted sidecar bundle as its own smolVM instead of a Docker container. A bottle then consists of an agent VM plus a sidecar VM, with the agent VM's TSI allowlist limited to the per-bottle agent-facing sidecar surface.
Problem
The smolmachines backend currently runs the agent in smolVM but keeps egress/git-gate/supervise in a Docker sidecar bundle. That hybrid launch path keeps Docker in the trusted runtime path and leaves smolmachines with a different isolation boundary than its agent VM design suggests.
The existing Docker sidecar path also uses Docker port publishing to bind only agent-facing services to the per-bottle host address. TSI is IP-only, so the smolVM replacement must preserve that scoping: publishing sidecar services on generic host localhost would let the agent reach unrelated host services or other bottle sidecars if those services share the allowed address.
Goals / Success Criteria
BOT_BOTTLE_BACKEND=smolmachines ./cli.py start <agent>runs with both the agent and sidecar as smolVMs.- The smolmachines launch path no longer uses
docker runfor the sidecar bundle. - Agent-facing egress, git-gate, and supervise endpoints are exposed only through the bottle's own published sidecar surface.
- Internal sidecar-only ports are not reachable from the agent VM.
- The agent VM TSI allowlist remains fail-closed and limited to the per-bottle address.
- Sidecar config, secrets, and state are delivered to the sidecar VM without exposing provider or forge credentials to the agent VM.
- Teardown removes both VMs and any host-side published port state.
Non-goals
- Rewriting the egress, git-gate, or supervise daemons.
- Changing the Docker backend's sidecar bundle behavior.
- Replacing the existing agent image build and pack pipeline except where shared helper extraction is needed for sidecar image packing.
- Weakening the current smolmachines TSI allowlist checks.
Design
The sidecar VM should continue to use the existing sidecar bundle image and
/app/sidecar_init.py supervisor. The launch flow builds the sidecar image,
packs it into a .smolmachine artifact, creates a per-bottle sidecar VM from
that artifact, passes the same daemon-selection environment the Docker bundle
uses today, mounts or copies the same daemon-private config/state inputs, starts
the sidecar VM, discovers the host-side published ports, then starts the agent
VM with --allow-cidr <per-bottle-address>/32.
Agent-facing URLs are stamped from the sidecar VM's published ports:
HTTP_PROXY/HTTPS_PROXYpoint at the published egress proxy port.GIT_GATE_URLpoints at the published git HTTP port when git-gate is enabled.MCP_SUPERVISE_URLpoints at the published supervise port when supervise is enabled.
Internal sidecar-only services stay bound inside the sidecar VM and are not published.
Open blocker
The implementation depends on host-side port publishing that can bind to the
per-bottle address. Current smolVM documentation and upstream source shape show
-p/--port accepting HOST:GUEST, with HOST represented as a port number,
not an IP address plus port. If smolVM cannot bind a guest port to a specific
host address such as 127.0.0.16:<random>, bot-bottle needs one of these before
implementation can proceed:
- smolVM support for address-scoped port publishing;
- a host-side forwarding layer that binds only the per-bottle address and forwards into the sidecar VM; or
- a different sidecar VM networking design that preserves the same IP-only TSI isolation property.
Publishing sidecar ports on generic host localhost is not acceptable because TSI's allowlist is IP-only and would no longer prove that the agent can reach only its own sidecar surface.
Implementation chunks
- Confirm or add an address-scoped sidecar VM port publishing mechanism.
- Extract the existing image-to-smolmachine pack helper so agent and sidecar artifacts share the same cache and registry path.
- Add a sidecar VM launch spec and lifecycle helpers: pack, create, start, publish/discover ports, stop, delete.
- Switch smolmachines launch from Docker sidecar bundle lifecycle to sidecar VM lifecycle.
- Update egress apply / reload paths for the sidecar VM supervisor.
- Add unit tests for argv shape, URL stamping, teardown, and fail-closed behavior.
- Add or update integration coverage for agent-to-sidecar reachability, host localhost denial, other-bottle alias denial, internal port denial, and teardown cleanup.