Skip to main content

Protocol Overview

This documentation is preliminary and tracks the v2 protocol, defined in the protos/polycentric/v2 directory of the Polycentric code repository.

Polycentric is built on three ideas:

  • Asymmetric cryptography — every event is signed by a key the user controls.
  • Append-only event collections — each signer writes a sequentially numbered, hash-linked log.
  • Eventual consistency — clients reconcile events from multiple servers and converge on the same state, using CRDT semantics for mutable values.

There are two roles: clients and servers. A client chooses which servers to publish its events to. Other clients fetch those events from any server that holds them. Servers place limited trust in each other and clients place limited trust in servers — if a server is unavailable or hides data, clients read from elsewhere.

Identities and keys

An identity is not a server account. It is a document (Identity) describing a set of keys:

  • Rotation keys — a priority-ordered list of public keys that control the identity itself and can authorize new keys.
  • Signing keys — keys allowed to sign events but not to change the identity document.
  • Revocation bounds — when a key is revoked, the identity records the key's last valid position in each collection, so events it signed before revocation remain verifiable.

The identity is itself the first thing written, in a reserved collection (see below). An identity is referred to by its identity key — the SHA-256 hash of that initial identity content.

Collections

Each identity writes events into numbered collections. A collection is an append-only log; within a collection an event's sequence is its logical clock. The reserved collections are:

CollectionPurpose
1Identity
2Feed (posts)
3Profile
4Interactions (reactions, etc.)
5Social graph (follows)

An event is addressed by an EventKey: the tuple of (collection, identity, signed_by, sequence).

Events and content

To keep events small and cacheable, an Event references its content by digest rather than embedding it. The body lives in a separate Content message, and the event carries a ContentDigest (SHA-256 over the serialized content). The two travel together in an EventBundle, which lets a recipient verify that the content matches the digest the event signed.

An event is signed as a SignedEvent: the signature is computed over the serialized Event bytes, and those exact bytes are stored as-is so the signature stays verifiable regardless of how a library re-serializes the message.

Hash-linking and proofs

Within a collection, each event records:

  • previous_signature — the signature of the previous event by the same key, forming an immutable chain.
  • previous_root — an RFC 6962 Merkle root over that signer's prior signatures in the collection.

Later events therefore attest to the writer's history. An EventProof is a Merkle inclusion proof showing that a given event is a leaf in the tree rooted at some later event. This is what makes revocation safe: the identity's revocation bounds anchor verification at a known head, and proofs establish which events fall before the revocation point.

Vector clocks

An event's VectorClock records the sequence numbers, in other collections, that the signer was aware of when writing it. This lets consumers order events across collections under eventual consistency.

Mutable values (CRDTs)

Some state is a single mutable value rather than an append-only stream — a display name, an avatar, a follow relationship. These use last-writer-wins semantics so that concurrent updates from different devices converge. The current value is whatever the latest event in the relevant collection sets.

Servers and discovery

Basic synchronization (fetching a user's events) requires little trust: a client can ask any server for an identity's events and verify every signature itself. Search, recommendation, and curated feeds are different — they are computed by servers. A client queries several servers, deduplicates, and attributes results, so no single server fully controls what a user sees. See Protocol → gRPC for the feed and sync APIs.