docs: draft smolmachines sidecar vm prd
This commit is contained in:
@@ -0,0 +1,104 @@
|
|||||||
|
# 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 <agent>` 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 <per-bottle-address>/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:<random>`, 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.
|
||||||
Reference in New Issue
Block a user