feat(supervise): Docker lifecycle + bottle integration (PRD 0013)
Phase 3 of PRD 0013. Wires the supervise sidecar into bottle launch: - Manifest: bottle.supervise (bool, default False). Opt-in for v1 so existing bottles are unchanged. - supervise.py: adds SupervisePlan + abstract Supervise(ABC) with a prepare template that stages the per-bottle queue dir on the host and the current-config dir under stage_dir (routes.json + allowlist + Dockerfile). Stdlib-only so it still runs as the in-container shared helper. - backend/docker/supervise.py: DockerSupervise concrete start/stop. No egress network (the sidecar doesn't make outbound calls); just the bottle's internal network with network-alias "supervise" and a bind-mount of the host queue dir at /run/supervise/queue. - Prepare wires supervise.prepare into the DockerBottlePlan, derives routes_content from cred_proxy_plan, allowlist_content from pipelock_effective_allowlist, and dockerfile_content from the repo's Dockerfile. supervise sidecar added to the orphan probe. - Launch starts the supervise sidecar after pipelock + cred-proxy but before the agent (so DNS resolution for `supervise` is up on the agent's first tool call). - Agent container gets a read-only bind-mount of the current-config dir at /etc/claude-bottle/current-config when supervise is enabled. - bottle_plan print + to_dict surface the supervise state. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -31,6 +31,7 @@ from .provision import cred_proxy as _cred_proxy
|
||||
from .provision import git as _git
|
||||
from .provision import prompt as _prompt
|
||||
from .provision import skills as _skills
|
||||
from .supervise import DockerSupervise
|
||||
|
||||
|
||||
class DockerBottleBackend(BottleBackend["DockerBottlePlan", "DockerBottleCleanupPlan"]):
|
||||
@@ -43,6 +44,7 @@ class DockerBottleBackend(BottleBackend["DockerBottlePlan", "DockerBottleCleanup
|
||||
self._proxy = DockerPipelockProxy()
|
||||
self._git_gate = DockerGitGate()
|
||||
self._cred_proxy = DockerCredProxy()
|
||||
self._supervise = DockerSupervise()
|
||||
|
||||
def _resolve_plan(self, spec: BottleSpec, *, stage_dir: Path) -> DockerBottlePlan:
|
||||
return _prepare.resolve_plan(
|
||||
@@ -51,6 +53,7 @@ class DockerBottleBackend(BottleBackend["DockerBottlePlan", "DockerBottleCleanup
|
||||
proxy=self._proxy,
|
||||
git_gate=self._git_gate,
|
||||
cred_proxy=self._cred_proxy,
|
||||
supervise=self._supervise,
|
||||
)
|
||||
|
||||
@contextmanager
|
||||
@@ -60,6 +63,7 @@ class DockerBottleBackend(BottleBackend["DockerBottlePlan", "DockerBottleCleanup
|
||||
proxy=self._proxy,
|
||||
git_gate=self._git_gate,
|
||||
cred_proxy=self._cred_proxy,
|
||||
supervise=self._supervise,
|
||||
provision=self.provision,
|
||||
) as bottle:
|
||||
yield bottle
|
||||
|
||||
Reference in New Issue
Block a user