131 lines
4.3 KiB
Markdown
131 lines
4.3 KiB
Markdown
# 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: <HASH>
|
|
```
|
|
|
|
**Machine B**:
|
|
```sh
|
|
uv run radicle-rns bridge --connect <HASH-FROM-A>
|
|
```
|
|
|
|
**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 <hash> # RTT probe to a peer
|
|
radicle-rns identity generate # create/show identity
|
|
radicle-rns sync <repo> # LXMF store-and-forward sync
|
|
radicle-rns bundle create <repo> # pack a repo into a bundle
|
|
radicle-rns bundle apply <bundle> <repo> # unpack a bundle
|
|
radicle-rns bundle info <bundle> # inspect a bundle
|
|
radicle-rns bundle qr-encode <bundle> # print ASCII QR (≤2953 bytes)
|
|
radicle-rns bundle qr-decode <image.png> # 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 <hash>` | — | Manually connect to a remote bridge |
|
|
| `--nid <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.
|