docs: put swarm-controller in the repo map and the swarm doc

The crate was a workspace member with no entry in CLAUDE.md, which is the
index that auto-loads into every turn -- a member missing from it is
invisible to everyone who comes after.

Both entries carry the socket-directory constraint rather than just
naming the daemon, because that is the one thing about this service a
reader can get wrong from a position that looks correct.
This commit is contained in:
atlas 2026-08-05 11:39:15 +02:00 committed by mara
commit 0fe2babbee
2 changed files with 41 additions and 0 deletions

View file

@ -235,6 +235,36 @@ one store, because the receiver keys destinations by *agent* so a
migrating agent keeps one unbroken incremental chain. See
[snapshot-store.md](snapshot-store.md).
## Swarm controller
`services.hyperhive.swarm.controller.enable` runs the `swarm-controller`
daemon on this host. It is **off by default and deliberately not derived
from `services.hyperhive.enable`**: a swarm has one controller, so
enabling it is a statement about swarm topology, not about whether
hyperhive is installed. Every hive runs `hive-c0re` (which owns the
agents on that host); one hive additionally runs this (which owns what is
true across hives).
It serves HTTP over a unix socket — `socketPath`, default
`/run/swarm-controller/controller.sock` — rather than a TCP port. The
gateway's nginx is the only intended client and reaches the socket
through a bind-mount, and a listener that is never bound to an address
cannot be reached from off-host by mistake.
⚠️ **The socket's directory is its access control.** The socket itself is
`0666`, because nginx runs as a different user and `connect(2)` needs
write — the same arrangement hive-c0re uses for the per-agent sockets.
What keeps that safe is that the directory holds one socket and is
bind-mounted into exactly one container. Pointing `socketPath` at a
directory that carries anything else — `/run/hyperhive`, which holds the
host **admin** socket, above all — exposes everything in it to every
consumer that mounts it. Changing `socketPath` therefore means
re-checking the gateway bind-mount, not just the daemon.
Today the daemon serves a single `/health` endpoint and holds no state:
the unit exists so the swarm-level surfaces that follow have somewhere to
land.
## Cross-references
- `docs/snapshot-store.md` — the swarm's `btrfs receive` endpoint, and