Toolbox

Proximo integration

If you use proximo to reach your local-dev apps at https://<name>.test on the host, the toolbox makes those same URLs work from inside the container — for any client (curl, git, Node, Python, Playwright/Chromium, …), with proximo's certificate trusted so no -k / ignoreHTTPSErrors is needed. This file covers why that needs toolbox plumbing, how DNS + CA trust are established, and the bridge-backed lifecycle commands.

Why .test is unreachable from a sibling container

proximo makes any labelled Docker container reachable at https://<name>.<tld> (default .test): it runs Traefik publishing :80/:443 on the host, installs a host resolver mapping *.<tld> → 127.0.0.1, and trusts a local CA in the host OS + NSS stores. That works for the host browser. It does not work from inside a toolbox container: 127.0.0.1 there is the container's own loopback, not the host where Traefik listens, so DNS resolves but the connection refuses. proximo also never injects its CA into arbitrary containers, so even a reachable endpoint fails TLS verification.

Enablement is auto-detected (tri-state proximo)

config.Config.Proximo is a *bool, resolved into the Proximo Availability Gate by proximo.Resolve(host, cfg): an explicit true/false wins; omitted (nil) auto-detects — on iff proximo's root CA exists on the host (proximo install wrote it under ~/.proximo). So a host with proximo installed gets .test reachability in every shell with zero per-repo opt-in, and a host without it pays nothing. proximo: false opts a project out; proximo: true forces it on even when the CA is absent (the mount then soft-skips). *bool (vs a plain bool) is what makes nil mean "auto" rather than "off" — the same tri-state shape as bridge, but with an auto rather than always-on default.

The two host-side ingredients

internal/proximo supplies both. The toolbox CLI runs on the host alongside proximo, so it can discover routed hosts directly from Docker labels — no enumeration in .toolbox.yaml, no upstream proximo change, no shared Docker network.

Concern Mechanism Seam
DNS Every running container's proximo.hosts label value is read; each hostname is pinned to the Docker host-gateway and appended to HostConfig.ExtraHosts. host-gateway resolves to the host where Traefik publishes :443, bypassing Docker networks entirely. These --add-host pins are fixed at create; the in-container proximo-hosts command re-syncs them at runtime for stacks started later (see lifecycle). discovery: container/lifecycle.go augmentProximoHosts (needs the Docker client); pure parser: proximo.ExtraHosts
Cert proximo's root CA (path queried via proximo config ca-path — the stable contract from filippolmt/proximo#20; fallback ~/.proximo/tls/ca.pem, proximo's current state home, filippolmt/proximo#17) is bind-mounted RO at /etc/ssl/proximo-ca.pem. entrypoint.sh then establishes seamless trust for every client (see below). NODE_EXTRA_CA_CERTS (Node uses its own bundle) and TOOLBOX_PROXIMO_CA (path pointer for the certifi gap) are also exported. mount: the gate's CAMount injected in mountplan.Merge; env: the gate's Env appended in sessionplan.Plan; trust: entrypoint.sh proximo block

Trust establishment (entrypoint, self-gated on the mount)

entrypoint.sh runs a proximo block gated purely on [ -f /etc/ssl/proximo-ca.pem ] (the mount is the signal — no extra env). It is idempotent and every step is best-effort (|| true) so a trust failure never aborts boot:

Client Trusted via Notes
curl / git / wget / python (ssl, urllib) system bundle sudo cp into /usr/local/share/ca-certificates/proximo.crt + sudo update-ca-certificates (passwordless sudo; refreshed only when the cert changes via a cmp guard)
Chromium / Firefox (incl. Playwright's bundled browsers) NSS certutil -A -t C,, -n proximo into $HOME/.pki/nssdb (libnss3-tools, base apt layer). ~/.pki is a HOME subdir, not a bind-mount → ephemeral, rebuilt from the mounted CA every shell
Node / Playwright (node API) NODE_EXTRA_CA_CERTS additive, set by the gate's Env
python-requests uses certifi, not the system store; set REQUESTS_CA_BUNDLE="$TOOLBOX_PROXIMO_CA" (this is the one non-seamless client)

The generic CA-certificate folder (~/.toolbox/certs/) shares this same system bundle: when any cert is dropped there, its entrypoint block re-points NODE_EXTRA_CA_CERTS / REQUESTS_CA_BUNDLE at the full /etc/ssl/certs/ca-certificates.crt — a superset that still contains proximo's CA, so proximo trust is unaffected. Reach for that folder for any non-proximo CA (corporate proxy, internal runtime); proximo's CA is wired automatically and needs nothing dropped there.

Lifecycle from inside the container (bridge shim)

proximo up|down|status|errors|skill works inside toolbox shell via the bridge: the image ships /usr/local/bin/proximo (internal/build/assets/bin/proximo, sibling of the editor shims) which POSTs {"command": "<sub>", "args": [...]} to the daemon's /proximo endpoint; the daemon execs the host proximo binary and returns {"exit": N, "output": "…"}, which the shim prints and propagates. Running the real binary in-container cannot work — and the failure is silent, not loud: proximo materializes its compose stack under ~/.proximo and bind-mounts those paths, which the host Docker daemon resolves host-side where they don't exist, while the colliding compose project name makes up recreate the working host stack instead of refusing. Hence no proximo binary in the image and no catalog row: absence is the only robust boundary (ADR-0004).

Runtime host sync (proximo-hosts, automatic)

--add-host/ExtraHosts is computed once at ContainerCreate and is immutable for the container's life, so a proximo stack started after toolbox shell is invisible to those pins: <name>.test falls through to the host resolver, resolves to 127.0.0.1 (right for the host, wrong inside the container) and refuses. The in-container proximo-hosts command (internal/build/assets/bin/proximo-hosts) is the runtime complement: it re-discovers the proximo.hosts labels from the host daemon over the mounted /var/run/docker.sock (DooD — docker ps -q + docker inspect, whose .Config.Labels is a map), resolves the host-gateway IP (IPv4-first from the always-pinned host.docker.internal, with a default-route fallback), and rewrites a marker-delimited managed block in /etc/hosts (sudo, passwordless) pinning every routed hostname to that gateway. /etc/hosts is mutable at runtime, so reachability tracks the running stacks with no recreate. It is idempotent; the markers are emitted even when nothing is routed, so a brought-down stack self-clears.

It runs automatically. When proximo is enabled (the CA mount is present), entrypoint.sh launches proximo-hosts --watch in the background: an initial sync, then a re-sync on every start/die of a proximo.hosts-labelled container (docker events — a streaming long-poll, near-zero idle cost; the loop reconnects if the daemon restarts). So stacks brought up or down mid-session are pinned (or unpinned) with no manual step. Running proximo-hosts by hand stays available to force a sync. The watcher logs to ~/.toolbox-state/proximo-hosts.log.

Boundaries and caveats