Size: L · Area: backend · Depends on: #164 · Part of #161
Net-new brain code: today the brain only configures Caddy via the admin API — it never launches it (dev runs Caddy standalone; dev/docker-compose.yml says so). Production requires the brain to bring up Caddy, malmo-ui, and the docker-socket-proxy on startup. Carries the second spec-collision risk (socket-proxy vs. compose CLI).
Spec / source of truth: CONTROL_PLANE.md # Locked: Caddy is malmo substrate / # Locked: the dashboard UI is a brain-launched container / # Locked: Docker socket exposure mitigated by socket proxy
Do:
- On brain startup, reconcile the control-plane stack from the M0 compose (Caddy +
malmo-ui + socket-proxy), the same way lifecycle.Reconcile handles app containers.
- Ensure the
malmo Docker network exists before the stack comes up (in dev it's an external network the compose assumes; on a real box something must create it).
- Reach Caddy's admin API by service name (
http://malmo-caddy:2019), not localhost:2019 — the natively-run dev brain uses localhost; a containerized brain cannot. Audit internal/caddy/ for the hardcoded endpoint.
- Stand up
tecnativa/docker-socket-proxy and switch the brain to DOCKER_HOST=tcp://docker-proxy:2375.
- Validate the socket-proxy ↔ compose-CLI integration (open risk): confirm
docker compose works through the proxy allowlist; if endpoint families are insufficient, widen the allowlist or escalate — a CONTROL_PLANE.md # Locked: Docker socket exposure revisit + a DECISIONS.md entry.
Touch: internal/lifecycle/, cmd/brain/, the control-plane compose, internal/caddy/.
Done when: booting the VM yields Caddy + malmo-ui + socket-proxy all launched by the brain; the dashboard SPA loads through Caddy; the brain reaches Docker only via the proxy (raw socket not mounted). The socket-proxy validation outcome is recorded.
Size: L · Area: backend · Depends on: #164 · Part of #161
Net-new brain code: today the brain only configures Caddy via the admin API — it never launches it (dev runs Caddy standalone;
dev/docker-compose.ymlsays so). Production requires the brain to bring up Caddy,malmo-ui, and the docker-socket-proxy on startup. Carries the second spec-collision risk (socket-proxy vs. compose CLI).Spec / source of truth:
CONTROL_PLANE.md# Locked: Caddy is malmo substrate / # Locked: the dashboard UI is a brain-launched container / # Locked: Docker socket exposure mitigated by socket proxyDo:
malmo-ui+ socket-proxy), the same waylifecycle.Reconcilehandles app containers.malmoDocker network exists before the stack comes up (in dev it's an external network the compose assumes; on a real box something must create it).http://malmo-caddy:2019), notlocalhost:2019— the natively-run dev brain uses localhost; a containerized brain cannot. Auditinternal/caddy/for the hardcoded endpoint.tecnativa/docker-socket-proxyand switch the brain toDOCKER_HOST=tcp://docker-proxy:2375.docker composeworks through the proxy allowlist; if endpoint families are insufficient, widen the allowlist or escalate — aCONTROL_PLANE.md# Locked: Docker socket exposure revisit + aDECISIONS.mdentry.Touch:
internal/lifecycle/,cmd/brain/, the control-plane compose,internal/caddy/.Done when: booting the VM yields Caddy +
malmo-ui+ socket-proxy all launched by the brain; the dashboard SPA loads through Caddy; the brain reaches Docker only via the proxy (raw socket not mounted). The socket-proxy validation outcome is recorded.