v0.1.0 · 3 tests

Two peers. No server.

The Quilt Mesh protocol. CRDT-based, broker-less, end-to-end. Watch two devices sync cells in real time — in this browser, in this tab, no internet required.

alice @home
t=0 · 3 cells
OFFLINE
bob @office
t=0 · 3 cells
Event log
0
events sent
0
events received
0
max lamport
The protocol

How the mesh works

Lamport clocks

Every event has a Lamport timestamp. Each peer ticks its clock on every send and observes the remote clock on every receive. This gives total causal order across the mesh — even with no central server and no synchronized clocks.

struct Lamport { pub t: u64 } impl Lamport { pub fn tick(&mut self) { self.t += 1; } pub fn observe(&mut self, other: Lamport) { self.t = self.t.max(other.t) + 1; } }

Per-peer version vectors

Each peer keeps a map from peer id to the highest Lamport it has seen from that peer. This lets a peer tell another peer exactly which events it needs — no diffing, no scan.

fn pending_for(&self, room, peer) -> Vec { let their_clock = self.versions.get(peer); self.events.iter() .filter(|e| e.lamport > their_clock) .cloned() .collect() }

CRDT merge

Each peer's history is a CRDT. Concurrent edits don't lose data — both writes survive, ordered by Lamport. Same-cell-same-time conflicts resolve deterministically by tiebreaker.

fn apply(&mut self, ev: Event) -> ApplyResult { if self.events.iter().any(|e| e.lamport == ev.lamport && e.author == ev.author) { return ApplyResult::Duplicate; } self.events.push(ev); ApplyResult::Applied }

Transports

WebSocket for online, BLE for proximity, LoRa for long-range, hardwired for fixed. The wire format is the same; the transport is pluggable. Pick what fits.

trait Transport { async fn send(&mut self, ev: Event); async fn recv(&mut self) -> Event; } // WebSocket, BLE, LoRa, anything else.

It's the same model, distributed.

A cell is a value, with a history, with an access policy, with formulas. The mesh just spreads the cell graph across many devices.

View source on GitHub → See all 11 repos