Scrapwire Protocol
Scrapwire is a private, peer-to-peer messaging protocol that runs entirely on the Veilid network. All transport and persistence use Veilid-backed records and routes, so the network layer never learns who is talking to whom by address; the specification forbids referencing IP addresses, hostnames, ports, sockets, or ICE/STUN/TURN rendezvous material. The design is layered: Veilid transport and persistence at the base, Scrapwire's service and protocol logic in the middle, and the interface layer on top, keeping protocol logic independent of any single frontend.
The full specification is currently Draft v1.
Read the full specification (PROTOCOL.md)
Versioned envelopes and safe extensibility
The wire format is forward-compatible. Each message is an Outer Frame (ciphertext plus
minimal sync metadata such as conversation_id, feed_id, segment_index, and seq)
that wraps an Inner Envelope carrying a version, epoch, author, sequence, causal
parents, timestamp, payload kind, and body. The outer frame never exposes the payload
type or plaintext.
Because envelopes are versioned, new features can be added without breaking older
clients. Unknown or unsupported payload kinds must fail safe: a client that does not
understand a kind preserves conversation integrity, either ignoring it or surfacing it
as unsupported, and never corrupts the transcript. Peers also advertise and negotiate
capabilities (for example attachment.v1) during handshake, and a sender must not use
an optional feature until the peer advertises support rather than silently downgrading
privacy or security.
Segmented Veilid-backed feeds
Each logical feed is stored as an ordered chain of sealed and active segments (one active segment per writable feed) rather than a single, ever-growing record. This respects Veilid record size limits while preserving an append-only history. Deterministic ordering comes from causal parent tracking, which also enables consistent ordering and deduplication across a conversation.
Encryption per conversation scope
Scrapwire has three conversation scopes, each with encryption suited to it:
- Direct messages bootstrap asynchronously from an invitation, then protect content with the Double Ratchet, giving forward secrecy. Each participant writes their own content feed, and the two are merged locally.
- Groups use MLS (RFC 9420) for membership and epoch state, with a control feed plus one content feed per writing member. Content is bound to an MLS epoch, and new members do not receive plaintext history from before the epoch in which they were admitted.
- Publications follow a one-publisher, many-followers broadcast model with a single writer and simpler shared-key crypto than groups. Followers never need to reveal themselves to other followers in order to read.
Invitations and publications
Invitations come in one-time and persistent variants for contacts, groups, and publications. They are capability-based and never require learning the inviter's network location. This supports the one-publisher, many-followers publication model: private publications can use one-time invitations for controlled follower admission, while public publications can use persistent, multi-use invitations for open onboarding.
Wire format
All on-wire structures are defined using a protobuf wire format
(scrapwire-service/proto/scrapwire.proto). Encrypted blobs and images travel as Blob
References fetched through a named Blob Transport Profile, with integrity binding verified
before decryption.
Reserved for the future
Real-time voice and media calling is not implemented. The protocol only reserves
call.* payload kinds (offer, accept, reject, update, hangup) as future extension points
so that call setup and signaling can be added later without breaking text chat, group
chat, or attachment delivery.