6.5 KiB
PRD prd-new: macOS Container backend
- Status: Draft
- Author: Codex
- Created: 2026-06-10
- Issue: #220
Summary
Add an experimental macos-container backend that integrates Apple's
container CLI as a host runtime on macOS. The first shipped slice
registers the backend, implements the reusable host primitives
(build, exec, cp, image inspection, cleanup, active
enumeration), and blocks full launch behind an explicit network
enforcement guard. This creates a real integration point without
weakening bot-bottle's sidecar egress model.
Problem
bot-bottle currently has two local execution paths:
docker, which runs the whole bottle topology through Docker Compose.smolmachines, which runs the agent in smolvm but still depends on Docker for the sidecar bundle and image-building pipeline.
Issue #220 explored removing Docker as a host dependency. A follow-up
review comment verified that smolvm can publish guest ports back to
host loopback and that another smolvm guest can reach that service
through the existing per-bottle loopback alias plus --allow-cidr
path. That keeps the VM-contained sidecar direction viable and rejects
the host-process sidecar fallback.
Apple's container CLI is another macOS-native way to run OCI images
as lightweight Linux VMs. Its current command surface includes
Docker-like build, run, exec, cp, port publishing, image
inspection, and user-defined networks. That makes it a plausible local
backend, but it does not remove the need to preserve bot-bottle's
sidecar enforcement property: the agent must not have a direct egress
path around the egress sidecar.
Goals / Success Criteria
--backend=macos-containerandBOT_BOTTLE_BACKEND=macos-containerare accepted by the existing backend selector.- Backend availability is true only on macOS hosts with
containeronPATH. - The backend has tested wrappers for Apple Container image build,
image inspection, container
exec, containercp, cleanup, and active-agent enumeration. - Full launch fails loudly with an operator-facing message until the sidecar network enforcement design is implemented.
- The PRD records the remaining launch work so the next PR can make the backend runnable without revisiting registration or wrapper plumbing.
Non-goals
- Do not remove or deprecate the Docker backend.
- Do not change the default backend from
smolmachines. - Do not run sidecar daemons as host processes.
- Do not launch a degraded backend where the agent can bypass the egress sidecar through direct network access.
- Do not require Docker Desktop as part of the macOS Container backend.
Design
Backend name
The selectable backend name is macos-container. The Python package
uses bot_bottle.backend.macos_container because module names cannot
contain hyphens.
Availability and preflight
MacosContainerBottleBackend.is_available() returns true only when:
platform.system() == "Darwin"containeris discoverable onPATH
prepare() calls require_container(), which produces a concrete
install pointer and rejects non-macOS hosts.
Implemented primitives
The backend owns an Apple Container wrapper module instead of reusing Docker wrappers. The wrapper maps bot-bottle's backend needs to Apple's CLI:
| bot-bottle need | Apple Container command |
|---|---|
| Build provider image | container build -t <ref> [-f Dockerfile] <context> |
| Run agent commands | container exec [--interactive --tty] <id> ... |
| Copy files into guest | container cp <host> <id>:<path> |
| Inspect image identity | container image inspect <ref> |
| Cleanup stale containers | container delete --force <id> |
| Cleanup stale networks | container network delete <name> |
| Active enumeration | container list --quiet |
The bottle handle mirrors DockerBottle: it builds a host argv for
foreground agent execution, pipes shell snippets through stdin for
Bottle.exec, and exposes cp_in for provisioning.
Launch guard
launch() is intentionally not enabled in the first slice. It exits
with a fatal message explaining that sidecar network enforcement still
needs implementation.
This is deliberate. A runnable backend that places the agent on a normal outbound network while relying on environment variables for proxying would violate bot-bottle's egress model. The runnable version must prove one of these shapes:
- Apple Container supports the equivalent of Docker's two-network sidecar topology: agent on an internal-only network, sidecar on both internal and egress networks.
- The sidecar bundle runs as a separate VM/container with published loopback ports, and the agent runtime can be constrained to only reach that per-bottle loopback alias.
- Apple Container init/network hooks can enforce the egress sidecar as the only outbound path before the agent process starts.
Implementation chunks
- Register
macos-container, add availability/preflight, bottle handle, utility wrappers, cleanup, active enumeration, unit tests, and this PRD. - Spike Apple Container networking against real macOS 26 hosts:
repeated
--network, internal network egress behavior, published loopback reachability from another container, DNS behavior, and labels/JSON output stability. - Implement launch once the enforcement shape is proven. Reuse the existing sidecar bundle image and daemon subset env contract where possible.
- Add real-runtime integration tests guarded by
containerpresence and macOS version. - Consider moving smolmachines sidecar/image-building work to
VM-contained or Apple Container-backed execution only after the
macos-containerlaunch path is trustworthy.
Testing Strategy
- Unit tests cover backend registration through
known_backend_names. - Unit tests cover availability/preflight behavior without requiring macOS.
- Unit tests cover
MacosContainerBottlecommand construction and stdin-based shell execution. - Unit tests cover cleanup and active enumeration parsing.
- Future integration tests must run on a host with Apple Container installed and should verify egress cannot bypass the sidecar.
References
- Issue #220 review comment:
smolvm
--port/-pcan expose a guest service to host loopback, and another smolvm guest can reach it through the existing per-bottle loopback alias path. - Apple Container command reference:
container run,build,exec, port publishing, and network commands.