colibri/docs/wiki/mother-hive.md
Sam & Claude 350c9ce3ba
Some checks are pending
CI / rust (pull_request) Waiting to run
CI / markdown (pull_request) Waiting to run
CI / port (pull_request) Waiting to run
CI / agent-jail-pkgs (pull_request) Waiting to run
fix(wiki): repair broken ../packaging/ links (EN+SL) + clean stray content dir
- 12 links in mother-hive.md (6 EN, 6 SL): ../packaging/ → ../../packaging/
  (packaging/ lives at repo root, not under docs/)
- Remove untracked astro/wiki/src/content/ (stray staging dir)
- Add src/content/ to astro/wiki/.gitignore
2026-06-26 14:26:10 +02:00

5.7 KiB

1|# Mother hive 2| 3|← index 4| 5|## What this is 6| 7|The mother node (OSA) coordinates USB operator nodes via MCP over SSH → 8|PostgreSQL. USB nodes send hardware profiles; mother derives capabilities and 9|maintains the hive registry. This page records the decisions behind the 10|implementation — the rationale the code can't express. For setup instructions, 11|architecture diagrams, and the first-run checklist, see 12|packaging/mother/MOTHER-SETUP.md. 13| 14|## Decisions 15| 16|### Forced-command SSH boundary (not a listening daemon) 17| 18|USB nodes reach mother by spawning ssh colibri@mother (no remote command). 19|On the mother side, authorized_keys enforces 20|command="/usr/local/bin/colibri-mcp-ssh",restrict,... — the connection 21|cannot run an interactive shell or any command except the wrapper. 22| 23|The wrapper (colibri-mcp-ssh) further allowlists SSH_ORIGINAL_COMMAND to 24|"" (stdio MCP mode) or "tools" (one-shot discovery). Every other value is 25|rejected. 26| 27|Why not a listening daemon (HTTP, gRPC, raw TCP): Tailscale encrypts the 28|wire, so the SSH layer adds authentication + confinement without extra 29|infrastructure (no TLS certs, no auth tokens, no open ports). The forced-command 30|boundary is a second lock on top of the SSH key — even a compromised USB that 31|holds the key can only invoke the wrapper, and the wrapper only delegates to 32|colibri-mcp. Defense in depth, deployed as one OpenSSH feature. 33| 34|→ colibri-mcp-ssh, MOTHER-SETUP.md §Security 35| 36|### Single home for mother infra (colibri, not clawdie-iso) 37| 38|The mother MCP scripts (node-register-mcp, geodesic-dome-mcp, etc.) were 39|originally copied into both repos. The clawdie-iso copy drifted — its 40|node-register-mcp used E'${...}' string interpolation (SQL-injectable) 41|while the colibri copy used parameterized psql -v :'variable'. The iso copy 42|was removed in clawdie-iso PR #129. 43| 44|Lesson: a script in two repos will drift. The wiki lint is single-repo 45|and can't see cross-repo duplicates. The mitigation is discipline: mother infra 46|lives in one place. 47| 48|→ naming-decisions §Structural ("Single home" row) 49| 50|### hive_nodes — not usb_nodes 51| 52|The original table name assumed only USB-booted nodes would register. But a 53|node is any host that joins the hive — USB, NVMe, a jail. Renamed to 54|hive_nodes with a node_type column (colibri #161). The derive_capabilities() 55|trigger is table-agnostic and auto-computes has_gpu, gpu_vendor, 56|can_run_local_llm, has_wifi, max_model on INSERT. 57| 58|→ mother_schema.sql, 59|naming-decisions (usb_nodes → hive_nodes row) 60| 61|### PostgreSQL peer auth (no passwords) 62| 63|The colibri OS user connects to mother_hive via peer authentication — the 64|kernel attests the Unix user, no password needed. node-register-mcp runs as 65|this user and inherits the trust. No pgpass files, no env vars, no credential 66|rotation. One moving part: the pg_hba.conf peer rule must precede any 67|catch-all local all all line (first-match). 68| 69|Why not a password or certificate: passwords rotate and leak; certificates 70|need a CA. Peer auth is built into PostgreSQL on every Unix and works for a 71|localhost connection with zero configuration beyond one pg_hba.conf line. 72| 73|→ MOTHER-SETUP.md §Setup step 6 74| 75|### Key on seed partition, not in the image 76| 77|The mother-mcp private key is placed on the CLAWDIESEED partition, not baked 78|into the ISO. The build script has a release guard that refuses to bake it 79|into a release image. The seed importer (clawdie-live-seed) installs it at 80|boot time. 81| 82|Why: a release ISO is a downloadable artifact. Baking a private key into it 83|would give every downloader access to the mother MCP. The seed partition is a 84|separate physical medium that the operator controls. Even without a seed, the 85|ISO boots and runs — the daemon's external MCP connection to mother fails 86|gracefully (SSH: "config file not found"), and the node operates standalone. 87| 88|→ naming-decisions ("Known residue"), clawdie-iso #133 89| 90|### Daemon user, not operator 91| 92|The colibri daemon runs as the colibri user (/var/db/colibri), not as the 93|operator (clawdie, /home/clawdie). The external MCP SSH connection to mother 94|is spawned by the daemon — so the SSH key, config, and known_hosts must be in 95|the daemon's home. The seed importer installs SSH material to both homes 96|(operator + daemon). 97| 98|Why not just put it in clawdie's home and sudo: the daemon is not the 99|operator. Running as a separate user means the blast radius of a daemon 100|compromise is limited to what the colibri user can do — MCP calls to mother, 101|not operator files or sudo. 102| 103|→ clawdie-live-seed (clawdie-iso), 104|MOTHER-SETUP.md §Key management 105| 106|## See also 107| 108|- agent-harness — the zot/Colibri split; autospawn 109|- naming-decisionsusb_nodes → hive_nodes, autospawn flag rename 110|- quality-gates — the gate that should catch drift at PR time 111|