# 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 1. `BOT_BOTTLE_BACKEND=smolmachines ./cli.py start ` runs with both the agent and sidecar as smolVMs. 2. The smolmachines launch path no longer uses `docker run` for the sidecar bundle. 3. Agent-facing egress, git-gate, and supervise endpoints are exposed only through the bottle's own published sidecar surface. 4. Internal sidecar-only ports are not reachable from the agent VM. 5. The agent VM TSI allowlist remains fail-closed and limited to the per-bottle address. 6. Sidecar config, secrets, and state are delivered to the sidecar VM without exposing provider or forge credentials to the agent VM. 7. 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 /32`. Agent-facing URLs are stamped from the sidecar VM's published ports: - `HTTP_PROXY` / `HTTPS_PROXY` point at the published egress proxy port. - `GIT_GATE_URL` points at the published git HTTP port when git-gate is enabled. - `MCP_SUPERVISE_URL` points 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:`, bot-bottle needs one of these before implementation can proceed: 1. smolVM support for address-scoped port publishing; 2. a host-side forwarding layer that binds only the per-bottle address and forwards into the sidecar VM; or 3. 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 1. Confirm or add an address-scoped sidecar VM port publishing mechanism. 2. Extract the existing image-to-smolmachine pack helper so agent and sidecar artifacts share the same cache and registry path. 3. Add a sidecar VM launch spec and lifecycle helpers: pack, create, start, publish/discover ports, stop, delete. 4. Switch smolmachines launch from Docker sidecar bundle lifecycle to sidecar VM lifecycle. 5. Update egress apply / reload paths for the sidecar VM supervisor. 6. Add unit tests for argv shape, URL stamping, teardown, and fail-closed behavior. 7. Add or update integration coverage for agent-to-sidecar reachability, host localhost denial, other-bottle alias denial, internal port denial, and teardown cleanup.