Since that article, I've pushed 100+ builds to the OGP repository. Not polish. Not features. Fixes for things that broke the moment the protocol left my local machine. This is an honest accounting of what I got wrong, what held up, and where federation between AI agents actually stands today.
/.well-known/ogphostname:port as the peer identifier. username.gw.clawporate.example.com:3001. Seemed reasonable — each gateway has a unique address.302a300506032b65. This is stable across tunnel rotations, port changes, load balancer reconfigurations. The gateway URL becomes just an address. The public key is the identity.302a300506032b65 is always 302a300506032b65 — message signing and verification work regardless of URL. But the daemon still needs a current gatewayUrl to route outbound messages. Today, if a peer's ngrok URL rotates, the stored URL goes stale and messages fail to deliver until the peer re-federates with its new address. The fix for this is either persistent public URLs (Cloudflare Named Tunnels, paid ngrok) or a future re-announcement mechanism. Worth knowing if you're testing across machines with free tunnels.federation.ts that falls back to ${hostname}:${port} as the peer ID if no public key is present. It exists to handle legacy peers that haven't upgraded. In practice any peer running a current OGP build will have a keypair — but if you're connecting to something old, the shim can create an ID inconsistency. It'll be removed once legacy peer support is formally dropped.federation/request endpoint was creating peer objects, sending notifications, returning HTTP 200... and never actually persisting the peer to disk.addPeer()) was missing. Every request appeared successful. No peers were ever saved. I found this during testing with the 0.2.26 release candidate. The federation handshake reported success on both sides. Neither side could actually message the other because neither had stored the peer.addPeer(peerData). This is the kind of bug you only catch when two independent systems try to connect, not when you're testing locally with one daemon talking to itself.peer.id field instead of deriving the ID from the public key. This meant if a legacy gateway sent ogp.domain.com:18790 as its ID, the receiving gateway stored it that way, even though the receiving gateway expected 302a300506032b65.peer.id. It always derives the peer ID from publicKey.substring(0,16). If a peer already exists with that public key, it returns already-pending-or-approved. Identity is normalized at the point of receipt, not at the point of sending.
ogp federation approve 302a300506032b65checkAccess() in doorman.ts before processing. Scope violations return 403s before the agent ever sees them. Rate limit breaches return 429s with a Retry-After header. The rate limiting is sliding-window per peer per intent, configurable via --rate <requests>/<seconds> (default: 100 req/hour).off (block), summary (compressed), or full (deliver everything). So a peer spamming the general topic can be throttled or silenced without touching the federation itself.cloudflared tunnel --url) — on-demand, no domain required, no registration. But the URLs rotate on every restart just like free ngrok, and they've been flaky in testing._ogp.example.com TXT records so email addresses map to gatewaysWhat I got wrong was the implementation details. What held up was the architecture.
npm install -g @dp-pcs/ogp@latest
ogp setup
ogp start --background
ogp status # shows your federation URL