Repository navigation
Reach a paired computer through the relay sync uses - #2073
Merged
Merged
Conversation
codeaf serve and chat --at fall back to the relay sync resolves, the relay client keeps the relay address's path, the carrier rides a WebSocket (with a fallback to the raw upgrade for older relays), the hosted relay gains the machine doors, and upstream failures become plain sentences. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A full machine answers 429 on both relays, a registration being decided is not taken over, a closed stream is not closed twice, a running serve waits out a redeploying relay, frames reuse one buffer, the door paths are one constant, per-address limits match codeaf relay, and the hosted README lists the binding, the migration and the doors. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
santoshkumarradha
marked this pull request as ready for review
October 30, 2026 15:26
8 tasks
AbirAbbas
added a commit
that referenced
this pull request
Oct 30, 2026
…2076) Relay streams get deadlines so silent dials and a lone pair byte end at 30 s; only the same key may replace a silent registration; the hosted front limits each caller (30 dials, 10 registrations a minute) and refuses impossible names before any object exists; serve backs off properly and answers lost sync with a back line; the upgrade honours proxies and leaks nothing on 426; upstream bodies become one-sentence facts. Hand-tested against the Worker under wrangler dev. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #2071.
Summary
A machine whose chats already sync can now run
codeaf servewith no settings and be reached withcodeaf chat --at <name>, through the same relay sync uses.sequenceDiagram participant Serve as codeaf serve (machine A) participant W as Hosted relay Worker participant DO as MachineDO (one per machine name) participant At as chat --at (machine B) Serve->>W: WebSocket /fabric/v1/engine W->>DO: idFromName(name) DO-->>Serve: challenge → proof → verdict (handshake.go, ported) At->>W: WebSocket /fabric/v1/dial/<name> W->>DO: same object DO-->>Serve: opOpen; then opData both ways (payload never read)What changed:
internal/relay: base path kept; WebSocket carrier with raw fallback;codeaf relayaccepts both carriers; the machine pings over the WebSocket so a hosted relay can stay asleep; frames reuse one buffer and go out in one write; a non-101 answer becomes a fact (ErrNoDoor,ErrUnreachablefor 5xx,ErrTooManyfor 429) instead of an upstream body.internal/pair,cmd/codeaf:Relay/RelayFor/Reach.Synctake sync's answer as the last fallback.codeaf servesayslost sync — trying againonce per outage, and waits out its own stale name or a redeploying relay instead of quitting.relay/hosted:/v1/engineand/v1/dial/<name>served byMachineDO(newMACHINEbinding, migrationv4-machines). Every socket hibernates; routing lives in socket tags and attachments. A live name is never taken over; a name whose socket no longer answers a ping within 5 s is replaced. Stream ceiling 16 (429), and 30 dials / 10 registrations a minute per network and name.Evidence
Before (issue):
codeaf servewith no settings →no sync address is set up on this machine…; with the hosted address →Error: error code: 522.After, two separate codeaf homes standing for two computers, model
deepseek/deepseek-v4.1-flashfor every role (the call log on the serving machine records only that model forturn,memory,routerandreflex):this machine is reachable as mustang-cactus-73+ pairing code, keeps running--atfrom a second computerMARKER-A-… ran-in-wsA: 2 tool calls ran in the first machine's folder--at name:<path>/sub/project→MARKER-PROJECT-…read in that folderlost sync — trying again(once); relay back: name and code printed again,--atanswers, serve never restarted--atreached itTestARelayAddressKeepsItsPath(/fabric,/a/relay, with and without slash, and root)TestServeAtPairingAndSyncResolveOneRelay(variable, saved pairing relay, hosted default)the service at https://codeaf.agentfield.ai/fabric syncs chats but does not connect machines — run your own with codeaf relay …; a dead address:… cannot be reached from here — check this machine's network …;TestUpstreamFailuresBecomeFactspins thaterror code: 522is never showncodeaf relay→ serve +--atround trip with a tool call;TestTheCarrierCrossesAWebSocketOnlyFrontAndAnOlderRelaycovers a raw-only (older) relayThe two-computer runs were done against
wrangler devofrelay/hostedwithBASE_PATH=/fabric, against a staging deployment of this branch on Cloudflare, and againstcodeaf relay.internal/relay/hosted_test.go(CODEAF_RELAY_HOSTED_URL=<relay>) passes on the staging deployment: round trip, a 400 KB echo, several surfaces, a live name refused, a freed name reusable, an unknown name, the stream ceiling as busy.Tests:
go test -race ./internal/relay,./internal/pair,./internal/relayserve,./cmd/codeaffocused;make test-quick;make pr-ready;relay/hostednpm test(includingtest/engine.test.js, which pins the JS name derivation and possession proof to values the Go code computes);make test-packed-manual manual-gates; relay conformance against the staging deployment.Merge Danger
Door: two-way for the code; one-way for the hosted deployment that follows.
The client change is backward compatible: a new client falls back to the raw upgrade on 426, and an old client keeps using the raw upgrade with
codeaf relay. The hosted relay is currently an older build; deploying this branch to it also ships the directory upgrade already on dev, which upgrades each identity in place and cannot be rolled back (seerelay/hosted/README.md). The deploy is a separate step after merge: staging first, then production with the previous version id recorded.Blast Radius: remote.
codeaf serve,chat --atand pairing through a relay. Sync's store and directory routes are unchanged. Limits: a dial to a machine that is not connected waits for the surface's own handshake timeout; a secondcodeaf servestarted while the first is in an outage keeps the name, and the first keeps saying it lost sync until it is closed; the savedv3/remote/relayfile still overrides sync's relay, as an explicit choice.🤖 Generated with Claude Code