Federation Handshake
What this page is
How two Stigmem nodes run by different organizations establish bilateral trust, exchange capability advertisements, and begin replicating facts — a three-phase protocol with cryptographic guarantees and no central authority.
The problem
Two Stigmem nodes run by different organizations want to share knowledge. But sharing means trusting: trusting that the other node won't inject malicious facts, won't escalate scope boundaries, won't replay old tokens, and won't forge provenance. You need a handshake protocol that establishes bilateral trust with cryptographic guarantees — without requiring a central authority.
Naive approaches and why they fail
Our model
Stigmem's federation handshake is a three-phase protocol: peer declaration, verification, and capability negotiation. The registration contract is defined in Spec-05-Federation-Trust.
Peer declaration
Node A sends a signed PeerDeclaration to Node B:
{
"node_url": "https://node-a.example.com",
"node_id": "stigmem://node-a.example.com",
"federation_pubkey": "<base64url Ed25519 public key>",
"allowed_scopes": ["public"],
"declaration_sig": "<Ed25519 sig over canonical JSON>",
"signed_at": "2026-05-01T00:00:00Z"
}
The allowed_scopes array is the authorization grant: Node A is
willing to share public-scoped facts with Node B. The signature
proves that Node A (holder of the private key) issued this
declaration.
Verification
Node B fetches Node A's /.well-known/stigmem to retrieve the
published federation_pubkey. It verifies declaration_sig against
that key. If the key in the declaration doesn't match the published
key, the peer is rejected — this prevents a third party from forging
declarations.
Mutual federation requires both sides to complete this handshake.
Replication does not begin until both peers are "active".
Capability negotiation
After verification, nodes exchange capability advertisements:
{
"relations_understood": ["memory:", "intent:", "roadmap:"],
"federation_mode": "pull",
"pull_interval_s": 30,
"contradiction_overrides": [
{ "relation": "roadmap:status", "policy": "latest" }
]
}
This tells each side what relations the peer understands, preventing silent contradiction storms on semantically opaque relations.
Replication
Once active, the subscriber pulls facts from the publisher using short-lived Ed25519-signed peer tokens.
PeerToken {
iss: "stigmem://node-a.example.com",
sub: "stigmem://node-b.example.com",
exp: <iat + 3600s max>,
nonce: <UUID>,
scopes: ["public"]
}
Tokens have a 1-hour maximum lifetime and carry a nonce for replay
protection. The receiving node verifies the signature, checks the
nonce cache, and validates the scopes claim against the
PeerDeclaration. The pull loop runs every 30 seconds by default,
using an HLC-based cursor for incremental replication.
Scope enforcement
Scope boundaries are enforced per-hop with a two-factor check:
fact.scope ∈ allowed_scopes(PeerDeclaration) ∩ token.scopes. A fact
is only federated if both the declaration and the token permit it.
localteamcompany"company"publicWhy this is non-obvious
Bilateral, not unilateral
Both nodes must independently register and verify. Node A's declaration to Node B doesn't grant Node B any access to Node A — B must also send a declaration, and A must verify it.
Company-scoped facts don't cascade
A company-scoped fact shared with Peer B is not automatically shareable by B with Peer C. The originating node's grant is non-transitive. Prevents a relay node with broader permissions from leaking internal knowledge.
Capability negotiation is required
Without it, a peer might replicate relations it doesn't understand (e.g., paperclip: lifecycle facts), leading to contradiction storms on semantically opaque data.
Pull-based default is deliberate
Push would be lower latency, but pull is operationally simpler: the subscriber controls cadence, backpressure is built in (429 → exponential backoff), and there's no need for the publisher to maintain push delivery state.
What it costs
Operational overhead
Each federation relationship requires a key exchange, mutual registration, and ongoing monitoring. For N nodes in a full mesh, that's N×(N-1) peer declarations.
Replication lag
Pull-based replication introduces a lag proportional to pull_interval_s (default 30 seconds). Relay nodes in multi-hop topologies can compound this lag.
Key rotation coordination
When a node rotates its federation keypair, it must keep the old key active for 24 hours. Peers re-fetch /.well-known/stigmem, but a race window exists during the transition.
No gossip protocol
Pairwise peer declarations, not gossip. Adding a new node to a 10-node network requires 10 separate handshakes. Linear, not logarithmic — acceptable for small-to-medium federations.