Skip to content

Friends and the relay ​

Friends lets people share tasks between their own Ponds. It is off until you turn it on. Each agent still runs only on its owner's Mac, with its owner's own Claude sign-in. A friend can never type into, steer or stop your agent.

What the friends relay seesTwo Macs exchange items through the relay. Each item is sealed on the sending Mac and opened only on the receiving Mac. The relay stores and forwards sealed bytes. It sees inbox ids, public keys, token hashes, group ids, item kind and size bucket, times, and the IP address of an open connection. It does not see task text, names, code, or any key that opens an item. Code moves through your own git remote, never through the relay.Your Macseals each itemkeys stay in theKeychainFriend's Macopens and checksthe sender's keyRelaySeesinbox ids, public keys, token hashesgroup ids, item kind, size bucket, timeIP of an open connection (memory only)Never seestask text, names, code, promptsany key that opens an itemsealedsealedYour own git remotecode, only with Sync turned on

Identity and invites ​

Turning Friends on creates an Ed25519 signing key and an X25519 agreement key in the Keychain. Keys are exchanged only through invite links, never through the relay.

  • An invite link is good for 48 hours and works once.
  • Both sides see the same safety code before they add each other.
  • The inviter confirms the join.

Sealing ​

Every item is sealed on your Mac before it is sent.

  • Between two friends: HPKE (RFC 9180) in auth mode, with X25519, HKDF-SHA256 and ChaCha20-Poly1305, and a fresh ephemeral key per item. An item opens only with the sender's static key, and it names its sender and recipient, so it cannot be passed on to someone else.
  • In a group: ChaCha20-Poly1305 under a key derived from the group's current epoch key. The poster signs the item inside the ciphertext. When a member is removed, the rest move to a new epoch.
  • Padding: plaintext is padded up to a size bucket, so the relay sees a bucket, not an exact length.

What the relay does ​

The relay is a small Go server built with the standard library only. It stores and forwards sealed items and never parses them. It checks only their length.

Owner requests are signed with the inbox's Ed25519 key, over the method, target, time, a nonce and a hash of the body. The time must be within two minutes, and a nonce cannot be used twice. Senders use tokens. The relay stores only the tokens' SHA-256 hashes, and tokens travel in headers, never in URLs.

Delivery uses one server-sent event stream per inbox. Mail is deleted when acknowledged and expires after 24 hours otherwise.

What the relay sees, and what it does not ​

The relay seesThe relay never sees
inbox ids and public keystask titles or bodies
token hashesnames of people, projects or branches
group idscode or diffs
the kind and size bucket of each itemprompts or terminal text
timesany key that opens an item
the IP address of an open connection

By design, after the next relay update:

  • client IP addresses stay in memory for at most 10 minutes and are never written to disk;
  • the relay's saved state holds ids, key hashes, token hashes and sealed items, never IPs or raw tokens;
  • logs carry only fixed lines with counts, never payloads, tokens, ids or IPs.

Limits ​

The relay's limits are part of the design. The running relay was deployed before the latest changes, so every limit below, and the privacy rules above, apply after the next relay update. Until then they are the design, not a guarantee.

  • Per IP address (per /64 for IPv6): 120 requests a minute, and 3 new inboxes per 10 minutes.
  • Per admin: at most 4 groups and 16 MB of group log in total.
  • Per inbox: at most 20 invite records, and mailbox caps on items and bytes.
  • One item is at most about 16 KB.
  • Connections time out on slow requests, and the relay caps open connections.
  • If the relay loses its state, it starts with a new instance id. Clients see the new id and fetch again from the start. An inbox or group id stays bound to its owner's key hash, so a stranger cannot claim it after a restart.
  • Appear offline is enforced at the relay, so friends see you offline while it is on.

Code does not go through the relay ​

Code moves through your own git remote, and only for projects where you turned on Sync with GitHub. That is off by default and asks first with a sheet naming the remote. Pond fetches from your own origin, fast-forwards clean, idle worktrees only, and never force-pushes. It uses your own git credentials and never stores a token.

Nothing starts by itself ​

A task from a friend never starts your agent unless you set Auto for that group, project and member. Auto is off by default and shows a warning that you must click through. It has caps on agents at once and starts per day, and it never takes a task that another agent posted. Agent posts to a group wait for your OK by default.

Pond is not released yet. These docs describe the current build.