From 90c72d91311f6fbba3e64b024368020a83b28983 Mon Sep 17 00:00:00 2001 From: damocles Date: Sun, 31 May 2026 16:17:36 +0200 Subject: [PATCH] docs/gateway.md: section on the #784 unix-socket upstream chain (mara on #832) --- docs/gateway.md | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/docs/gateway.md b/docs/gateway.md index 91f4bb74..39a85342 100644 --- a/docs/gateway.md +++ b/docs/gateway.md @@ -67,6 +67,43 @@ Per-vhost timeouts + body-size limits live in the location blocks: SSH for forge stays direct on `cfg.sshPort` — separate listener protocol, not HTTP-over-nginx. +## Per-agent unix-socket upstream (#784) + +Sub-agent `/agent//` upstreams flip from TCP loopback to a +unix-domain socket as each agent opts in. The mechanism: + +1. **Agent side** (`hyperhive.web.useUnixSocket = true` in + `agent.nix`, #815). Sets `HIVE_WEB_SOCKET=/run/hive-agent//web.sock` + on the harness service env; `web_ui::serve` binds a `UnixListener` + at that path instead of TCP. +2. **Host side**. `hive-c0re` bind-mounts the per-agent subdir + (`/run/hive-agent//`) into the agent's container (#813). Dir + bind, not file bind — file bind-mounts don't survive the + harness's `unlink + bind(2)` cycle on socket replace. Per-agent + subdir keeps each agent's container blind to siblings' + sockets (mara on #800). +3. **Marker gate**. After successful `bind_unix`, the harness drops + `/.bound` next to the socket. c0re's `agent_sockets::write` + filters its JSON map by marker presence — only agents whose + harness has actually bound the socket appear there (#784 atlas + gate). Without this filter, the gateway would `proxy_pass` to a + non-existent socket for every sub-agent that hasn't opted in yet. +4. **Gateway side** (#829). Reads `agent-sockets.json` at + request-handling time and routes `/agent//` to + `http://unix:/run/hive-agent//web.sock:/`. Whole + `/run/hive-agent/` is bind-mounted read-only into the gateway + container so it can reach every published socket. + +c0re re-fires `agent_sockets::write` every 10s so newly-bound +markers get picked up without needing a container-start hook in +every lifecycle path. `write()` is idempotent: steady-state cost is +one stat per agent per tick. + +Transition: agents that haven't flipped `useUnixSocket = true` still +appear in `agent-ports.json` (the legacy TCP map) and the gateway +falls back to TCP for them. Step 4 of #784 will drop the TCP map + +the harness's TCP bind once every agent's flipped. + ## Sequencing history - #15 v0 (per-agent routing, #740) — first sub-app behind the gateway, JSON port table from c0re. @@ -74,6 +111,7 @@ SSH for forge stays direct on `cfg.sshPort` — separate listener protocol, not - #749 / #754 — forge to sub-domain (mara: sub-domain over sub-path). - #747 / #764 — matrix sub-domain vhost + `.well-known` delegation. - #772 / #775 — fluffychat hops from `/matrix/` to `matrix./`. +- #784 / #800 / #813 / #815 / #822 / #829 — sub-agent UI flips to unix-domain socket upstream, opt-in per agent. Next-up tracked separately: #14 (container netns isolation), TLS (#594).