Files
bot-bottle/docs/prds/prd-new-macos-container-backend.md
T

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-container and BOT_BOTTLE_BACKEND=macos-container are accepted by the existing backend selector.
  • Backend availability is true only on macOS hosts with container on PATH.
  • The backend has tested wrappers for Apple Container image build, image inspection, container exec, container cp, 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"
  • container is discoverable on PATH

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

  1. Register macos-container, add availability/preflight, bottle handle, utility wrappers, cleanup, active enumeration, unit tests, and this PRD.
  2. 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.
  3. Implement launch once the enforcement shape is proven. Reuse the existing sidecar bundle image and daemon subset env contract where possible.
  4. Add real-runtime integration tests guarded by container presence and macOS version.
  5. Consider moving smolmachines sidecar/image-building work to VM-contained or Apple Container-backed execution only after the macos-container launch 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 MacosContainerBottle command 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/-p can 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.