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 host-side ingredients

internal/proximo supplies reachability and trust. The toolbox CLI runs on the host alongside proximo; no route enumeration belongs in .toolbox.yaml, and the toolbox never joins proximo's private network.

Concern Mechanism Seam
DNS Proximo's effective-route inventory supplies only the local bare and qualified names it actually serves. Each is pinned to the Docker host gateway, which reaches the host where Traefik publishes :443. The inventory directory is queried with proximo config inventory-dir, mounted read-only, and projected into /etc/hosts by proximo-hosts before shell startup and throughout the session. An older proximo falls back to its declared proximo.hosts labels, which cannot include generated qualified names. path and mount: internal/proximo; projection: bin/proximo-hosts
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 gates CA trust purely on [ -f /etc/ssl/proximo-ca.pem ]. It is idempotent and every step is best-effort (|| true) so a trust failure never aborts boot. Route projection has a separate enablement marker so a forced-on integration can still project routes when that CA is absent: Gate.Env emits TOOLBOX_PROXIMO_ENABLED=1, while withholding every trust path.

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|doctor|update|version 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)

The in-container proximo-hosts command (internal/build/assets/bin/proximo-hosts) owns the Proximo Route Projection in a marker-delimited /etc/hosts block. It reads the mounted routes.json, selects only bare and qualified, resolves the host-gateway IPv4, and pins those names there. claimed, collision and peer names are deliberately ignored: they are not local names the route currently answers on. The inventory is replaced atomically by proximo, so the command polls the document rather than racing proximo's watcher on the same Docker event. Rewriting is idempotent, and an empty inventory clears the managed names.

It runs automatically. When proximo is enabled (signalled by the CA mount for compatibility or TOOLBOX_PROXIMO_ENABLED=1), entrypoint.sh makes one bounded, best-effort foreground sync before the interactive shell can start, then launches proximo-hosts --watch in the background. A failed initial discovery never blocks shell access; the watcher retries immediately. If the inventory directory is not mounted because proximo predates that contract, both modes retain the old label discovery and the watcher follows Docker events; bare hosts keep working, while upgrading proximo and recreating the toolbox container adds qualified-host support. A mounted inventory is authoritative even while routes.json is temporarily absent or unreadable: the command preserves the last valid managed block rather than falling back to declarations. Running proximo-hosts by hand stays available to force a sync. Logs go to ~/.toolbox-state/proximo-hosts.log.

Boundaries and caveats