Hive Topology

You open a shell on the road and type ssh manoir. It works. Two weeks later you type the same string from the chalet Mini and it works again. Nobody renumbered a subnet. Nobody published a Tailscale subnet route. The laptop did not need a special VPN profile for “vacation mode.” The string was the product.
The failure mode this chapter exists to prevent is the opposite story: one flat 10.0.0.0/24 fantasy spanning two basements, a Firewalla that advertises the wrong site as a mesh, and a fine-tuned model that hardcodes “the Mini is always .10” as if there were only one Mini in the world. Multi-site Sanctum is a fleet of complete organisms, not one organism with two basements.
The product in one sentence
Section titled “The product in one sentence”Same design map at every site. Cross-site by node name only. Never merge L3.
| Plane | What it is | What it is not |
|---|---|---|
| Body | Per-site LAN design map (.1 FW · .2 Orbi · .3 HA · .10 Mini) | A global address space |
| Hive | Tailscale + MagicDNS + nodes.* roster + vault / agents | Subnet routes of whole hauses |
| Mind | Shared topology priors for prompts and fine-tunes | Per-haus fork of those priors (not the P5 predictor) |
Open mesh (signed LoRA champions between hauses) is a sibling plane — see Champion Gate. Do not overload it as the multi-site control plane.
Body — isomorphic enclave
Section titled “Body — isomorphic enclave”Every site reuses the same local map. Numbers collide across sites on purpose and stay safe because those prefixes are never advertised as Tailscale subnet routes.
| Role | Design IP | Identity pin (Firewalla) |
|---|---|---|
| Firewalla | 10.0.0.1 | gateway |
| Orbi AP | 10.0.0.2 | model / hostname match |
| HA Green (when present) | 10.0.0.3 | homeassistant |
| Mini / brain | 10.0.0.10 | model + Bonjour / dhcp name |
Those 10.0.0.x values are the design map (documentation-range style anchors for the isomorphic body). Live LAN discovery still goes through endpoint resolution — the hive never treats them as cross-site addresses.
Implementation: identity-rebind in openclaw-skills/firewalla-toolkit (config/identity-pins.json, install scripts on each box). Match by durable identity, not MAC, so Private Wi‑Fi rotation cannot orphan the pin. Sites are separated by Firewalla lan_uuid so manoir’s pins never apply on the chalet Purple and vice versa.
Hive — name-only nervous system
Section titled “Hive — name-only nervous system”Cross-site traffic uses node names. Naming is a product surface.
sanctum node names # cheat sheetsanctum node listsanctum node resolve chalet # preferred MagicDNS stemsanctum node whoami # .node_id must equal roster keyssh neo@manoir # MagicDNS when the machine is named manoir| Do | Don’t |
|---|---|
manoir, chalet, mbp | Display codes (MM64, MBP128) as addresses |
manoir-fw, manoir-ha | Dual live names without a deliberate recovery map |
Agent names for agents (ahsoka) | Agent names as Tailscale hosts |
| Resolve at call time | Hardcoded 100.x (endpoint resolution) |
Naming contract (Apple-simple)
Section titled “Naming contract (Apple-simple)”Jobs test: What do you call it when you talk to it? That string is the only name — roster key, ~/.sanctum/.node_id, and MagicDNS stem are the same.
| Kind | Pattern | Examples |
|---|---|---|
| Site brain (Mini) | {place} | manoir, chalet |
| Mobile | {device} | mbp |
| Site infra on TS | {place}-{role} | manoir-fw, manoir-ha, chalet-fw |
| Agent | Jedi seat | yoda, ahsoka — never a TS host |
# Live contract — one name, no dual identitymbp: type: mobile tailscale_name: mbpLegacy stems (berts-mbp, manoir-firewalla, …) may still appear in hive-names.yaml as recovery matches so a device that reappears under an old control-plane Name can be re-converged. They are not live aliases and must not be what you put in scripts.
Converging MagicDNS — apply-hive-names
Section titled “Converging MagicDNS — apply-hive-names”Control-plane renames (the MagicDNS Name, not only the device HostName) go through the Tailscale API. The durable path is the toolkit, live via symlink:
# Live path == repo (Durability Doctrine)# ~/.sanctum/tailnet → openclaw-skills/tailnet-toolkit~/.sanctum/tailnet/tools/apply-hive-names.sh status~/.sanctum/tailnet/tools/apply-hive-names.sh plan~/.sanctum/tailnet/tools/apply-hive-names.sh apply --sync-roster| Piece | Role |
|---|---|
hive-names.yaml | Declarative want-names + match / reject / recovery exact-map |
apply-hive-names.sh | Plan / apply / status; stem comparison (FQDN → first label) |
ha-check.sh | manoir-ha peer + HTTP + optional LAN probe |
seed-oauth.sh | One-time OAuth client → SOPS (+ keychain cache) |
tools/lib/ts-auth.sh | Shared mint; never logs secrets |
Declarative SoT for names: hive-names.yaml.
Declarative SoT for API credentials: Mini SOPS store ~/.sanctum/keychain-secrets.enc.json keys tailscale-oauth-client-id / tailscale-oauth-secret. Keychain entries with the same service names are a cache for GUI sessions; headless tools prefer SOPS (ts-auth resolution order).
OAuth client scopes: ACL write + Devices › Core write (plus tags if you tag devices). Mint check:
source ~/.sanctum/tailnet/tools/lib/ts-auth.sh && ts_auth_check# expect: auth=ok devices=200Unit smoke (no network): python3 ~/.sanctum/tailnet/tools/test-hive-names-match.py.
Roster — instance.yaml nodes
Section titled “Roster — instance.yaml nodes”topology: design: isomorphic-enclave hive: name-only
nodes: manoir: type: hub tier: primary # primary | peer | edge site: manoir ssh_user: neo tailscale_name: manoir capabilities: - vault_authority - inference - ha_site
chalet: type: satellite tier: edge site: chalet ssh_user: neo tailscale_name: chalet sync: hub: manoir capabilities: - local_inference - satellite
mbp: type: mobile tier: edge tailscale_name: mbp| Field | Meaning |
|---|---|
type | hub · satellite · mobile · sensor |
tier | primary (config SoT) · peer (multi-hub) · edge |
site | Design-map / identity-pins site id |
tailscale_name | MagicDNS stem for sanctum node resolve |
capabilities | Static offers for hive work placement |
CLI surface (hive roster + routing):
sanctum node list | get | whoami | resolve | validatesanctum node offers | can <capability> | route <capability> [--prefer local|fastest|primary|hub:NAME]sanctum node vault-host # primary hop for Memory Vault (name-only)sanctum node ensure-hub | declare-peer NAME | export-councilCouncil-router config/nodes.json stores hive names, not drift-prone 100.x. Delivery resolves at call time. Vault hop: memory-vault/scripts/vault-hive-hop.sh or sanctum node vault-host.
Capability routing
Section titled “Capability routing”| Capability | Typical offer |
|---|---|
vault_authority | primary hub only |
inference / inference_heavy | primary + peer hubs |
local_inference | satellites + mobile |
ha_site | hubs with HA Green |
train / mesh_seed / council | hubs |
sanctum node route inference --prefer primarysanctum node route local_inference --prefer localMulti-hub (peer join)
Section titled “Multi-hub (peer join)”Exactly one primary hub (config SoT, vault authority, adopt authority). Additional peer hubs keep the same body map and join the hive by name — no renumbering, no LAN merge.
sanctum node declare-peer montreal --tailscale-name montreal --site montreal# On that Mac: echo montreal > ~/.sanctum/.node_id# Deploy identity-rebind on that site's Firewalla with a new site block- Same local design map + identity-rebind for that site’s Firewalla.
- Tailscale node online; MagicDNS name stable.
sanctum node declare-peer <name>(or hand-edit roster)..node_idmatches the roster key.- Sync policy: pull config from primary; never dual-write
instance.yamlsilently. - Offer metal via
capabilities— route with--prefer hub:<name>.
Fine-tune mental model (“Sanctum-space”)
Section titled “Fine-tune mental model (“Sanctum-space”)”A model fine-tuned for Sanctum may assume:
- Every site has the design roles above (when the gear exists).
- Local
.10is this site’s Mini; other brains are named hubs/satellites. - Cross-site actions use node names, never guessing which
10.0.0.0/24is which. - Offline satellite prefers local metal; online hive may route to primary/peer capacity.
- Vault authority lives on the primary hub unless a capability says otherwise.
Site-specific facts (room names, people, Nuheat zones) belong in memory / RAG, not in weights that hardcode one haus’s LAN quirks.
Why not merge the mesh?
Section titled “Why not merge the mesh?”| Merge L3 | Hive (this design) |
|---|---|
| Must renumber at least one site | Clone site N without renumber |
| Subnet routers = critical path + blast radius | Failure stays in the enclave |
| Optimizes bare IPs | Optimizes names (the product) |
| Breaks “same mental model” if maps diverge | Same map → one curriculum |
Subnet routes remain a special feature for dumb IoT that cannot run Tailscale — never the default architecture.
EETISMAD smoke
Section titled “EETISMAD smoke”| Letter | Proof for this feature |
|---|---|
| E2E Tested | ts_auth_check; apply-hive-names plan is a no-op when perfect; ha-check.sh; match unit test |
| in Sanctum-docs | This page + sidebar |
| Merged | openclaw-skills tailnet-toolkit + SOPS store on Mini config repo |
| And Deployed | ~/.sanctum/tailnet symlink → toolkit; live MagicDNS stems |
If plan invents renames forever, the stem comparison regressed (FQDN vs short name). If auth fails, re-seed OAuth into SOPS first, then keychain cache.
Related
Section titled “Related”- Node topology — hub / satellite / mobile roles
- Endpoint resolution — discovery, no hardcoded IPs
- Naming — place layer + retired ledger
- Engineering discipline — EETISMAD shipping bar
- Satellite setup — adopt flow
- Home Assistant — Green at design
.3on the hub site