# radicle-reticulum Bridges [Radicle](https://radicle.xyz) (decentralized Git) over [Reticulum](https://reticulum.network) mesh networking — LoRa, packet radio, serial, I2P, and more. Enables offline-first code collaboration without internet infrastructure. **Why:** Radicle requires publicly reachable seed nodes; Reticulum routes over any physical medium. Both use Ed25519 keys — a natural fit. ## Install ```sh pip install uv # once uv sync # install deps into .venv ``` QR encoding (optional): ```sh uv sync --extra qr # ASCII QR output pip install pillow pyzbar # image encode/decode ``` ## Quickstart: bridge two machines over mesh **Machine A** (or any node on the mesh): ```sh uv run radicle-rns bridge # prints: RNS address: ``` **Machine B**: ```sh uv run radicle-rns bridge --connect ``` **Both machines** — configure radicle-node to use the bridge as a seed: ```toml # ~/.radicle/node/config.toml [[seeds]] address = "127.0.0.1:8777" ``` Then start radicle-node and use it normally: ```sh rad node start rad clone rad:z3xyz... rad push / rad pull ``` The bridge auto-detects your local NID via `rad self` and auto-registers discovered remote NIDs with radicle-node (`--no-auto-seed` to disable). ## Commands ``` radicle-rns bridge # TCP↔RNS bridge (main command) radicle-rns node # lightweight peer-announce node radicle-rns peers # discover peers on the mesh radicle-rns ping # RTT probe to a peer radicle-rns identity generate # create/show identity radicle-rns sync # LXMF store-and-forward sync radicle-rns bundle create # pack a repo into a bundle radicle-rns bundle apply # unpack a bundle radicle-rns bundle info # inspect a bundle radicle-rns bundle qr-encode # print ASCII QR (≤2953 bytes) radicle-rns bundle qr-decode # decode QR back to bundle ``` Global flags: `-v` verbose, `--identity PATH` (default `~/.radicle-rns/identity`). ## Air-gapped / QR transfer For truly offline transfers (tiny incremental bundles ≤ 2953 bytes): ```sh # Sender radicle-rns bundle create myrepo --incremental --basis prev.refs.json radicle-rns bundle qr-encode myrepo-*.radicle-bundle # Receiver (photograph the QR, then:) radicle-rns bundle qr-decode qr-photo.png -o received.radicle-bundle radicle-rns bundle apply received.radicle-bundle ./myrepo ``` ## Bridge flags | Flag | Default | Description | |------|---------|-------------| | `-l, --listen-port` | 8777 | TCP port radicle-node connects to | | `--radicle-port` | 8776 | Port radicle-node listens on | | `-c, --connect ` | — | Manually connect to a remote bridge | | `--nid ` | auto | Override local radicle NID | | `--no-auto-connect` | — | Disable auto-connect on discovery | | `--no-auto-seed` | — | Disable auto-registering remote NIDs | ## Architecture ``` radicle-node ──TCP:8777── RadicleBridge ──RNS Link── RadicleBridge ──TCP:8776── radicle-node │ │ RNS announce RNS announce (auto-discovery) (auto-discovery) ``` - **Identity** (`identity.py`) — Ed25519 DID ↔ RNS destination mapping; persisted to `~/.radicle-rns/identity` - **Adapter** (`adapter.py`) — peer discovery via RNS announces - **Link** (`link.py`) — buffered RNS Link with state machine - **SyncManager** (`sync.py`) — LXMF store-and-forward bundles; auto-push on refs announce - **AdaptiveSyncManager** (`adaptive.py`) — picks FULL/INCREMENTAL/MINIMAL/QR by RTT + throughput - **GitBundle** (`git_bundle.py`) — full and incremental Git bundles - **QR** (`qr.py`) — visual air-gap transfer for tiny bundles ## Development ```sh uv run pytest # 158 tests uv run pytest -x -q # stop on first failure ``` ## Reticulum interfaces Reticulum auto-discovers local peers via UDP multicast. For LoRa / serial / I2P, configure `~/.reticulum/config`: ```ini [[lora_interface]] type = RNodeInterface port = /dev/ttyUSB0 frequency = 868000000 bandwidth = 125000 spreadingfactor = 7 codingrate = 5 ``` See [Reticulum docs](https://reticulum.network/manual/) for the full interface list.