How LAN sync works

Update, September 2026: the TCP transport described below is gone. RECN now runs on Iroh: encrypted QUIC connections dialled by device key, on the local network and across the internet. The merge and blob design still stands. A new write-up is coming.

This describes the sync architecture in the working build as of July 12, 2026.

RECN has two awkward requirements: it should work without waiting for a server, and it has to move recordings that are much larger than the notes around them.

Lattice is the layer built for that.

The shape of the stack

The apps work with familiar types: recordings, notes, projects, annotations, transcripts, and sessions. Type descriptors turn those models into generic Lattice entities.

RECN UI and services

RECN type descriptors

LatticeStore
  ├── SQLite: entities, clocks, vectors, outbox, blob metadata
  └── Filesystem: audio, images, and analysis bytes

mDNS → SyncEngine → one PeerConnectionManager per device → TCP

The Lattice runtime does not know what a recording is. It knows fields, clocks, entities, peers, and attached blobs. That separation lets the same merge and transport rules serve every kind of work RECN adds.

One idea, two payloads

Small structured facts and large media behave differently, so Lattice does not force them through one representation.

An entity carries fields such as a recording name, project ID, duration, or update time. Each field carries merge metadata.

A blob has metadata describing its identity, size, format, hash, and known replicas. The bytes themselves live outside the entity store.

This matters for audio. A tiny title edit can converge without resending a 600 MB rehearsal. When the recording does need to travel, it can move in chunks and resume after a disconnect.

Filesystem paths are deliberately absent from the wire. /Users/me/… is true only on one computer. Every device resolves its own local copy.

Discovery and approval

RECN advertises a local service through mDNS. A nearby app can see that a RECN device exists and where it is listening.

Pairing is a separate, user-confirmed TCP exchange. Once accepted, the device identity is persisted and the sync engine will reconnect when that peer becomes reachable again.

This is practical trust, not cryptographic identity. The current fingerprint helps recognise a reinstall; it is not proof backed by a private key. Account-backed, offline-verifiable device trust belongs to the next architecture and should not be confused with what ships today.

One state machine per peer

Every paired device gets its own connection manager:

idle → discovering → connecting → handshaking → catchingUp → live
                                              ↘ backingOff

The handshake negotiates protocol compatibility and confirms which device is on the other end. Catch-up compares what each side has already seen. Live mode then forwards new local writes.

Connections use heartbeats and a watchdog. Failed peers back off exponentially, from a short retry to a one-minute ceiling, instead of spinning against a missing machine.

Catch-up without overwriting

Entity fields use a last-writer-wins register driven by a hybrid logical clock: physical time, a logical counter, and a device ID tie-break.

Two consequences matter:

Deletion is represented by a tombstone rather than immediately forgetting that an entity existed. That gives other replicas something concrete to merge.

This is convergence, not Google-Docs-style collaboration. A note body is still one merged field on main; per-block and character-level collaboration are later work.

Moving the recording

When blob metadata arrives and the local file is missing, RECN can queue a fetch from a peer that advertises a copy.

The current transfer path is:

request → offer → chunk window → acknowledgement → next window

                                  resume from known offset

                                length guard + SHA-256

Chunks are 1 MiB, with a small in-flight window. A partial file stays partial until its final length and digest match. Only then does the local replica become complete.

The digest detects corruption or the wrong bytes. It is an integrity check, not encryption.

Where the current design bends

On main, metadata, blobs, and heartbeats share one TCP connection and one send queue. Under a large transfer, control traffic can wait behind bulk traffic.

The newer integration harness reproduces the serious version of that weakness: in a contended three-device mesh, a heartbeat can starve behind blob backlog and the connection oscillates.

Other limits are related:

These are reasons for the next protocol, not details to hide behind a “private sync” label.

What has landed off main

The optimization branch already contains foundational changes that are not yet part of the public working build:

The next dependency chain is deliberate:

identity → control/bulk transport → connection rebuild → piece blobs
         → app-facing sync kit → scopes → optional cloud mailbox

Control and bulk traffic separate first. Blob transfers then become piece-verified and able to use more than one source. Only after the LAN foundation behaves under realistic loss, latency, and congestion does the optional cloud layer begin.

LAN first is therefore not a slogan about avoiding servers forever. It is an ordering decision: make nearby devices work directly and honestly before adding a remote safety net.