D 2026-10-13T02:27:53.183 L index N text/x-markdown U dmestas W 4734 # EdgeSync Distributed Fossil repository synchronization over [NATS](https://nats.io/). Replace Fossil's HTTP sync on leaf nodes with NATS messaging — the master Fossil server stays untouched. ## Architecture ``` pikchr right R1: cylinder "repo" color white fill 0x3a3a3a width 0.7 height 0.5 rad 3px move 0.3 LA: box "Leaf Agent" color white fill 0x2a6b3a width 1.3 height 0.5 rad 5px move 0.3 N: cylinder "NATS" color white fill 0x2a4a6b width 0.8 height 0.6 rad 5px move 0.3 BR: box "Bridge" color white fill 0x6b5a2a width 1.0 height 0.5 rad 5px move 0.3 FS: box "Fossil Server" color white fill 0x6b2a2a width 1.4 height 0.5 rad 5px move 0.3 R2: cylinder "master" color white fill 0x3a3a3a width 0.7 height 0.5 rad 3px arrow from R1.e to LA.w color white thick arrow from LA.e to N.w color white thick arrow from N.e to BR.w color white thick arrow from BR.e to FS.w color white thick arrow from FS.e to R2.w color white thick ``` Every sync round is **bidirectional** — the leaf pushes local artifacts AND pulls remote changes in the same request/reply exchange. Data flows both directions through NATS and the bridge. ## How It Works 1. Developer A does `fossil commit` on Leaf A — repo SQLite updated 2. Leaf A's agent polls (every 5s), detects new artifacts 3. Leaf A syncs over NATS: sends what it has, asks for what it's missing 4. Bridge forwards to Fossil server via HTTP, relays response back 5. **Leaf B** polls, syncs, gets Developer A's changes from the server 6. All leaves converge through the Fossil server as source of truth The Fossil server never knows NATS exists. It just sees normal HTTP `/xfer` traffic. ## Components ### [Leaf Agent](wiki:Leaf%20Agent) A Go daemon that sits next to a Fossil repo and keeps it synced. ``` pikchr right R: cylinder "repo" color white fill 0x3a3a3a width 0.7 height 0.5 rad 3px move 0.3 A: box "Leaf Agent" color white fill 0x2a6b3a width 1.3 height 0.5 rad 5px move 0.3 N: cylinder "NATS" color white fill 0x2a4a6b width 0.8 height 0.5 rad 5px arrow from R.e to A.w color white thick arrow from A.e to N.w color white thick ``` - Polls repo every 5s for new artifacts (configurable) - Push AND pull in each sync round - `SIGUSR1` for immediate sync, `SIGINT`/`SIGTERM` for shutdown ``` leaf-agent --repo /path/to/repo.fossil --nats nats://localhost:4222 ``` ### [Bridge](wiki:Bridge) A proxy that translates NATS to Fossil's HTTP protocol. ``` pikchr right N: cylinder "NATS" color white fill 0x2a4a6b width 0.8 height 0.5 rad 5px move 0.3 B: box "Bridge" color white fill 0x6b5a2a width 1.0 height 0.5 rad 5px move 0.3 F: box "Fossil Server" color white fill 0x6b2a2a width 1.4 height 0.5 rad 5px arrow from N.e to B.w color white thick arrow from B.e to F.w color white thick ``` - Subscribes to NATS, forwards to Fossil server via HTTP - Returns empty response on errors (never leaves the leaf hanging) ``` bridge --fossil http://fossil:8080 --project ``` ## Multi-Leaf Sync ``` pikchr down A: box "Leaf A" color white fill 0x2a6b3a width 0.9 height 0.35 rad 5px move 0.15 B: box "Leaf B" color white fill 0x2a6b3a width 0.9 height 0.35 rad 5px move 0.15 C: box "Leaf C" color white fill 0x2a6b3a width 0.9 height 0.35 rad 5px N: cylinder "NATS" color white fill 0x2a4a6b width 0.8 height 0.5 rad 5px \ at 1.5 right of B BR: box "Bridge" color white fill 0x6b5a2a width 0.9 height 0.35 rad 5px \ at 1.5 right of N FS: box "Fossil" color white fill 0x6b2a2a width 0.9 height 0.35 rad 5px \ at 1.5 right of BR arrow from A.e to N.nw color white arrow from B.e to N.w color white thick arrow from C.e to N.sw color white arrow from N.e to BR.w color white thick arrow from BR.e to FS.w color white thick ``` Leaf A pushes changes. Leaf B and C pull them on their next sync cycle. All leaves converge through the Fossil server. ## NATS Subject Scheme ``` ..sync ``` Default prefix: `fossil`. Configurable via `--prefix`. ## Design Principles - **Master stays vanilla** — no patches to Fossil - **Transport-agnostic** — `sync.Transport` interface accepts any transport - **Repo format preserved** — `fossil ui` works on any synced repo - **NATS WebSocket** — browser leaves connect via `wss://` ## Built With - **[go-libfossil](https://fossil.craftdesign.group/go-libfossil)** — Pure Go Fossil library (12 packages) - **[NATS](https://nats.io/)** — Messaging transport - **Go 1.25.4** ## Clone ``` fossil clone https://fossil.craftdesign.group/edgesync edgesync.fossil ``` Z 7824ce191ecc2bd6e43be9fa5a76d856