Federation. Two pods, or two thousand. Same model.

Mazemaker federation is pod-to-pod memory propagation over HTTP(S). Every pod stays sovereign — its own DB, its own engine, its own license, its own vault key. When two pods are paired, each pulls a delta from the other every five minutes and re-stores it locally with a peer:<peer-id>: prefix. There is no central server holding memories. The hosted backend brokers identity and billing — never content. This page is how it works, three worked examples, and where it scales.

What it is. What it isn't.

The shape of federation is determined by the shape of mazemaker. Local-first stays local-first; nothing about pairing moves data into a hosted tier.

// what federation is

A direct Bearer-authenticated POST /peer/sync from one pod's peer_sync.py daemon to another pod's wonderland. Each side has the other side's key in peer-keys/peers/<peer-id>.key. Each relationship is independent. Adding a peer is a one-shot paste of a handshake URL; revoking a peer is one file delete.

// what federation is NOT

Not a global shared namespace. Not a hosted "Mazemaker Cloud" that ingests memories. Not silent — every peer is added by an explicit operator action and visible in the Architect's M06 PEERS panel. Not a leak of private memories: vault-encrypted content is skipped on the serving side, the peer would only see ciphertext anyway.

// what crosses the wire

Only memories whose label starts with a public-prefix (public:*, auto:*, decision:*, bug:*, ops:*, …) and whose content is NOT vault-encrypted. The label-prefix gate is enforced server-side — a wide scope = "*" can't get private memories out.

// what the operator controls

Every byte of the relationship: which peers exist, which scope each one pulls, the URL each one is reachable at, whether sync is on or off. All of it is one TOML file (~/.mazemaker/peers.toml) and a directory of 32-byte keys. The Architect M06 PEERS panel is just a UI over those files.

Identity. Handshake. Done.

Each pod has a stable identity generated once at first boot. Pairing is a one-shot paste of a handshake URL. There is no DNS, no IP, no shared secret beyond the keys the handshake URLs carry.

The handshake_url is the only token an operator copies. It looks like mzm-handshake://<pod-id>?key=<43-char-key>. Whoever holds it can authenticate to that pod's /peer/sync using the embedded key. That is the entirety of the trust hand-off.

Three topologies. Same model.

The wire protocol doesn't change with scale. Whether you're pairing two laptops on Tailscale, fanning a hub-and-spoke around your own machines, or standing up a public-https mesh across five operators, it's the same paste-handshake and the same five-minute tick.

// topology 1 — Tailscale pair (two operators)

Alice on alice-tpad.tail-foo.ts.net, Bob on bob-mbp.tail-foo.ts.net. Each runs the pod with wonderland exposed on :8765 over Tailscale. Paste-handshake both ways with the Tailscale URL as direct_url. Within five minutes auto:* memories flow both directions. M06 PEERS on both pods shows • ready.

// topology 2 — hub-and-spoke (one operator, many devices)

Laptop + workstation + always-on home server. The hub is the only box with a stable address; the leaves come and go. Leaves' peers.toml has one entry (the hub), with url = "https://hub.tail-foo.ts.net". The hub holds the master memory; leaves pull from it. For writes-that-converge, the operator's MCP client talks to the hub's wonderland directly; federation propagates back to the leaves on their next pull.

// topology 3 — WWW-scale mesh (research team, Cloudflare Tunnels)

Five operators, none on the same VPN. Each publishes their wonderland via a Cloudflare Tunnel hostname like https://wonder-alice.team.example. Each pair handshakes once. With N peers each pod has N−1 entries in peers.toml. Scope decision:* shares architectural decisions; public:* shares the explicit opt-in slice. The same model holds for arbitrarily many pods — the only limit is the operator's willingness to maintain key pairs.

// the constant across all three

Every relationship is a separate row in peers.toml + a separate file in peer-keys/peers/. Every relationship can be paused (sync = false), narrowed (scope = "public:*"), or revoked (one rm). The hosted backend is not in the path for any of it.

Trust. Per pair. No central authority.

The trust boundary of federation is the Bearer key pair between two pods. There is no PKI, no CA, no central trust authority — just two operators who agreed to exchange handshake URLs.

  • Per-pair keys. Compromising one peer's key only affects relationships that key was registered in. There is no master key.
  • https is the operator's responsibility. Tailscale, ZeroTier, Cloudflare Tunnels, LAN https with a private CA — whatever the operator trusts the network layer with.
  • Wide scope can't get private memories out. The server-side public-prefix gate is enforced even if the puller requests scope = "*".
  • Encrypted-at-rest stays encrypted. Memories whose content starts with AES: are skipped on the serving side. The peer's vault key is different from yours — they'd only see ciphertext.
  • Revocation is one operation. rm ~/.mazemaker/peer-keys/peers/<peer-id>.key + remove the peers.toml entry. The peer's Bearer no longer authenticates.

WWW-scale. Pods, not platforms.

"Infinite federation across the WWW" is not a marketing phrase. It is a property of the protocol: a pod's peers.toml can hold any number of peer entries. Each entry is an independent Bearer-key pair. There is no global registry. There is no upper limit other than the operator's willingness to manage the key files.

With N = 5 each pod has 4 peer entries — trivial. With N = 50, still manageable. With N = 500 the operator uses the rendezvous service shipped 2026-05-26 at api.mazemaker.dev/api/peers/*. Every pod heartbeats its current reachable URL every 60s; other pods resolve a stable peer_id → URL by presenting the pre-shared peer_key. The backend never sees memory content (TLS terminates on the destination wonderland). Verified cross-machine between two pods on 2026-05-26 — see the verified contract section below.

Verified contract — two pods, 2026-05-26.

Cross-machine federation tested between alca-7G (6356db37) on LAN 192.168.0.2 and tpad (f678a5fc) on LAN 192.168.0.242. Every step below was exercised end-to-end with real memory propagation. No placeholders, no “shipped soon” — actual receipts in the order they happened.

// rendezvous registration

Each pod auto-detects its LAN IP, heartbeats every 60s to POST /api/peers/register on api.mazemaker.dev with the license JWT and a SHA-256 of its peer_key. Backend stores (peer_id, url, peer_key_hash, expires_ts) only — no content. TTL 5min, refreshed on every heartbeat.

// resolution

When pod A wants to talk to pod B, it sees mzm-rendezvous://<B's peer_id> in peers.toml and calls GET /api/peers/lookup/<B's peer_id>?key=<B's peer_key>. Backend hashes the key, compares against stored hash, returns the URL. Resolved URL cached client-side for 240s.

// proof

Stored public:bidir-1779757812 on tpad → alca-7G's puller fetched 1 memory, forwarded into local engine, recall surfaces it. Round-trip including resolution + sync: < 200ms LAN. Reverse direction tested too.

// failure modes

tpad killed mid-sync → alca-7G logs err=request_failed, keeps trying. Backend still returns last URL for 5min grace (DHT-like). tpad restarted → auto-heartbeat resumes within 10s; sync resumes without operator intervention.

Pair two pods in 30 seconds.

The full UI lives in the Architect's M06 PEERS panel. The full CLI lives in curl. Both do the same thing.

// step 1 — copy your handshake URL
curl -s http://127.0.0.1:8765/peer/identity | jq -r .handshake_url
mzm-handshake://6356db37-…?key=mENKrJzy…

Send this URL to the peer. Any channel — chat, paper, QR.

// step 2 — paste theirs into /peer/add
curl -s -X POST http://127.0.0.1:8765/peer/add \
  -H 'Content-Type: application/json' \
  -d '{
    "handshake_url": "mzm-handshake://<peer-pod-id>?key=<key>",
    "direct_url":   "https://peer.tail-foo.ts.net",
    "sync": true,
    "scope": "public:*"
  }'

Inbound is live now. Outbound fires on the next 5-min tick — or run systemctl --user start mazemaker-peer-sync.service to trigger immediately.

// step 3 — verify in M06 PEERS

Open the Architect at architect.mazemaker.dev and click M06 PEERS. You should see the peer with status • ready. The peek() badge on the M06 tile reports the count ("N ready · M handshake-pending"). If it's ◖ handshake-pending, the URL is still the mzm-rendezvous:// placeholder — click SET URL to fix.

Two pods.
Or two thousand. Your call.

Sovereign federation: no central authority, no shared corpus, no silent indexing. Per-pair Bearer keys, public-prefix gate, five-minute tick.