docs: simplify README — one mode, remove seed section
Remove the "two modes" framing and always-on seed quickstart; seed setup is standard radicle-node configuration, not part of this codebase. Remove --lora references and dead commands. Keep quickstart, interface config, and architecture note. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
63267e5789
commit
6a11905500
215
README.md
215
README.md
|
|
@ -1,27 +1,27 @@
|
||||||
# radicle-reticulum
|
# 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.
|
Bridges [Radicle](https://radicle.xyz) (decentralized Git) over [Reticulum](https://reticulum.network) mesh networking — LoRa, packet radio, serial, I2P, and more.
|
||||||
|
|
||||||
|
`rad push` and `rad fetch` work normally. The bridge is transparent: radicle-node sees ordinary TCP peers, unaware it is talking over a mesh.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
- [Radicle](https://radicle.xyz/install) (`rad` CLI + `radicle-node`)
|
- [Radicle](https://radicle.xyz/install) — `rad` CLI + `radicle-node`
|
||||||
- [uv](https://docs.astral.sh/uv/getting-started/installation/)
|
- [uv](https://docs.astral.sh/uv/getting-started/installation/)
|
||||||
- Git
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Install
|
## Install
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
git clone rad:z4NMdcKbw2TETQ56fbQfbibFHtZqZ # via radicle
|
git clone rad:z4NMdcKbw2TETQ56fbQfbibFHtZqZ
|
||||||
# or: git clone https://github.com/youruser/radicle-reticulum
|
|
||||||
cd radicle-reticulum
|
cd radicle-reticulum
|
||||||
uv sync
|
uv sync
|
||||||
```
|
```
|
||||||
|
|
||||||
Optional: faster push detection (inotify-based, Linux/macOS):
|
Optional — faster push detection (inotify, Linux/macOS):
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
uv sync --extra watch
|
uv sync --extra watch
|
||||||
|
|
@ -29,21 +29,9 @@ uv sync --extra watch
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Two modes
|
## Quick start
|
||||||
|
|
||||||
### Bridge mode — peer-to-peer
|
### 1. Tell radicle-node to listen on localhost
|
||||||
|
|
||||||
Each machine runs a bridge. They discover each other over RNS, then radicle-node syncs through the tunnel as if both nodes were on the same network.
|
|
||||||
|
|
||||||
### Seed mode — always-on relay
|
|
||||||
|
|
||||||
One machine runs a dedicated seed radicle-node plus a bridge. Other machines' bridges discover and register the seed automatically. The seed self-populates: it calls `rad seed <RID>` for any repo announced by gossip peers.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Quick start: bridge mode
|
|
||||||
|
|
||||||
### Step 1 — Configure radicle-node to listen on localhost
|
|
||||||
|
|
||||||
Edit `~/.radicle/config.json`:
|
Edit `~/.radicle/config.json`:
|
||||||
|
|
||||||
|
|
@ -53,34 +41,33 @@ Edit `~/.radicle/config.json`:
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Restart radicle-node:
|
Restart:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
rad node start
|
rad node start
|
||||||
rad node status # "listening for inbound connections on 127.0.0.1:8776"
|
rad node status # should show "listening … 127.0.0.1:8776"
|
||||||
```
|
```
|
||||||
|
|
||||||
### Step 2 — Start the bridge on both machines
|
### 2. Start the bridge on both machines
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
uv run radicle-rns bridge
|
uv run radicle-rns bridge
|
||||||
```
|
```
|
||||||
|
|
||||||
Within ~30 s the bridges discover each other via RNS announce, connect automatically, and register each other's NIDs with radicle-node:
|
The bridges announce themselves over RNS and discover each other within about a minute. When a peer is found its radicle NID is registered automatically:
|
||||||
|
|
||||||
```
|
```
|
||||||
[+] Discovered bridge: <hash> (NID: z6Mk...)
|
[+] Discovered bridge: <hash> (NID: z6Mk...)
|
||||||
[Status] Tunnels: 0, Remote bridges: 1, TX: 0, RX: 0
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Once radicle-node syncs through the bridge:
|
Once radicle-node connects through the tunnel:
|
||||||
|
|
||||||
```
|
```
|
||||||
Tunnel 1 opened
|
Tunnel 1 opened
|
||||||
[Status] Tunnels: 1, Remote bridges: 1, TX: 1551, RX: 1831
|
[Status] Tunnels: 1, Remote bridges: 1, TX: 1551, RX: 1831
|
||||||
```
|
```
|
||||||
|
|
||||||
### Step 3 — Use radicle normally
|
### 3. Use radicle normally
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
# Machine A
|
# Machine A
|
||||||
|
|
@ -91,122 +78,13 @@ rad push # prints RID: rad:z3...
|
||||||
rad clone rad:z3...
|
rad clone rad:z3...
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
That's it. `rad push`, `rad fetch`, and `rad sync` all work as usual — they talk to the local daemon, which syncs through the bridge.
|
||||||
|
|
||||||
## Quick start: seed mode
|
|
||||||
|
|
||||||
Run this once to initialise the seed identity:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
uv run radicle-rns setup # checks prerequisites and prints instructions
|
|
||||||
RAD_HOME=~/.radicle-seed rad auth
|
|
||||||
```
|
|
||||||
|
|
||||||
Then start the seed (keeps running, restarts cleanly):
|
|
||||||
|
|
||||||
```sh
|
|
||||||
uv run radicle-rns seed
|
|
||||||
```
|
|
||||||
|
|
||||||
Other machines running `radicle-rns bridge` (or `seed`) discover the seed automatically over RNS. The seed begins tracking any repo announced by gossip peers.
|
|
||||||
|
|
||||||
Register the seed in your local radicle-node (one-time, per machine):
|
|
||||||
|
|
||||||
```sh
|
|
||||||
rad node connect <SEED_NID>@127.0.0.1:8777
|
|
||||||
```
|
|
||||||
|
|
||||||
The seed NID is printed by `radicle-rns seed` on startup.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Gossip relay
|
|
||||||
|
|
||||||
The gossip relay watches local Radicle storage for ref changes and sends small notifications (~100–200 B) to peer relays over RNS. On receipt, the peer calls `rad sync --fetch` against the announcing node. Seed mode enables gossip automatically; for bridge mode run it separately:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
uv run radicle-rns gossip rad:z3... # auto-detected from CWD if omitted
|
|
||||||
```
|
|
||||||
|
|
||||||
Gossip broadcasts only the changed refs (delta mode), so a one-commit push sends ~120 B instead of the full ref list.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Commands
|
|
||||||
|
|
||||||
```
|
|
||||||
radicle-rns bridge # TCP↔RNS bridge
|
|
||||||
radicle-rns seed # dedicated seed node + bridge + gossip
|
|
||||||
radicle-rns gossip [RID ...] # standalone gossip relay
|
|
||||||
radicle-rns setup # check prerequisites, print fix instructions
|
|
||||||
radicle-rns identity generate # create identity
|
|
||||||
radicle-rns identity info # show DID and RNS hash
|
|
||||||
```
|
|
||||||
|
|
||||||
Global flags: `-v` verbose logging, `--identity PATH` (default `~/.radicle-rns/identity`).
|
|
||||||
|
|
||||||
### bridge flags
|
|
||||||
|
|
||||||
| Flag | Default | Description |
|
|
||||||
|------|---------|-------------|
|
|
||||||
| `-l, --listen-port` | 8777 | Base TCP port (first discovered bridge gets this) |
|
|
||||||
| `--radicle-port` | 8776 | Port radicle-node listens on |
|
|
||||||
| `-c, --connect <hash>` | — | Connect to a specific remote bridge by RNS hash |
|
|
||||||
| `--nid <NID>` | auto-detect | Override local radicle NID |
|
|
||||||
| `--no-auto-connect` | — | Disable auto-connect on discovery |
|
|
||||||
| `--no-auto-seed` | — | Disable auto-registering remote NIDs |
|
|
||||||
| `--announce-retry-delays` | 5,15,30 | Startup re-announce delays (seconds, comma-separated) |
|
|
||||||
|
|
||||||
### seed flags
|
|
||||||
|
|
||||||
| Flag | Default | Description |
|
|
||||||
|------|---------|-------------|
|
|
||||||
| `--seed-home` | `~/.radicle-seed` | RAD_HOME for the seed radicle-node |
|
|
||||||
| `--seed-port` | 8776 | TCP port for the seed radicle-node |
|
|
||||||
| `--bridge-port` | 8778 | TCP listen port for the seed bridge |
|
|
||||||
| `--poll-interval` | 30 | Seconds between gossip ref polls |
|
|
||||||
|
|
||||||
### gossip flags
|
|
||||||
|
|
||||||
| Flag | Default | Description |
|
|
||||||
|------|---------|-------------|
|
|
||||||
| `--nid` | auto-detect | Local radicle NID to advertise |
|
|
||||||
| `--bridge-port` | 8777 | TCP port of the local bridge |
|
|
||||||
| `--poll-interval` | 30 | Seconds between ref polls |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Architecture
|
|
||||||
|
|
||||||
```
|
|
||||||
radicle-node ─TCP─ RadicleBridge ──RNS Link── RadicleBridge ─TCP─ radicle-node
|
|
||||||
(Machine A) (Machine A) (Machine B) (Machine B)
|
|
||||||
│ │
|
|
||||||
GossipRelay ──RNS Packet── GossipRelay
|
|
||||||
```
|
|
||||||
|
|
||||||
Each discovered remote bridge gets its own OS-assigned TCP listen port, so radicle-node connections always route to the correct peer. The tunnel uses `RNS.Buffer` over `RNS.Channel` for ordered, reliable delivery — Reticulum handles retransmission transparently across all interface types including LoRa.
|
|
||||||
|
|
||||||
- **`identity.py`** — Ed25519 DID ↔ RNS identity; saved to `~/.radicle-rns/identity`
|
|
||||||
- **`bridge.py`** — TCP↔RNS tunnel via `RNS.Buffer`, per-bridge port allocation, path maintenance
|
|
||||||
- **`gossip.py`** — ref-change notifications, delta broadcasts, auto-seed for unknown repos
|
|
||||||
- **`seed.py`** — dedicated radicle-node process lifecycle (separate RAD_HOME)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Development
|
|
||||||
|
|
||||||
```sh
|
|
||||||
uv run pytest # 97 tests
|
|
||||||
uv run pytest -x -q # stop on first failure
|
|
||||||
mypy src/ # type check
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Reticulum interfaces
|
## Reticulum interfaces
|
||||||
|
|
||||||
On the same LAN, Reticulum auto-discovers peers via UDP multicast — no config needed. For LoRa / serial / I2P, edit `~/.reticulum/config`:
|
On a LAN, Reticulum auto-discovers peers via UDP multicast — no config needed. For LoRa, serial, or I2P, edit `~/.reticulum/config`:
|
||||||
|
|
||||||
```ini
|
```ini
|
||||||
[[lora_interface]]
|
[[lora_interface]]
|
||||||
|
|
@ -219,3 +97,64 @@ On the same LAN, Reticulum auto-discovers peers via UDP multicast — no config
|
||||||
```
|
```
|
||||||
|
|
||||||
See the [Reticulum manual](https://reticulum.network/manual/) for the full interface list.
|
See the [Reticulum manual](https://reticulum.network/manual/) for the full interface list.
|
||||||
|
|
||||||
|
Initial clones over LoRa are impractical (pack objects can be megabytes; LoRa is ~1–5 kbps). Clone over a fast link first, then sync incrementally over the mesh.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Commands
|
||||||
|
|
||||||
|
```
|
||||||
|
radicle-rns bridge # TCP↔RNS bridge
|
||||||
|
radicle-rns gossip [RID ...] # ref-change relay (auto-detected from CWD)
|
||||||
|
radicle-rns setup # check prerequisites
|
||||||
|
radicle-rns identity generate # create identity
|
||||||
|
radicle-rns identity info # show DID and RNS hash
|
||||||
|
```
|
||||||
|
|
||||||
|
Global flags: `-v` verbose logging, `--identity PATH` (default `~/.radicle-rns/identity`).
|
||||||
|
|
||||||
|
### bridge flags
|
||||||
|
|
||||||
|
| Flag | Default | Description |
|
||||||
|
|------|---------|-------------|
|
||||||
|
| `-l, --listen-port` | 8777 | Base TCP port for incoming radicle-node connections |
|
||||||
|
| `--radicle-port` | 8776 | Port radicle-node listens on |
|
||||||
|
| `-c, --connect <hash>` | — | Connect to a specific bridge by RNS hash |
|
||||||
|
| `--nid <NID>` | auto-detect | Local radicle NID to announce |
|
||||||
|
| `--no-auto-connect` | — | Disable auto-connect on discovery |
|
||||||
|
| `--no-auto-seed` | — | Disable auto-registering remote NIDs |
|
||||||
|
| `--announce-retry-delays` | 5,15,30 | Startup re-announce delays (seconds, comma-separated) |
|
||||||
|
|
||||||
|
### gossip flags
|
||||||
|
|
||||||
|
| Flag | Default | Description |
|
||||||
|
|------|---------|-------------|
|
||||||
|
| `--nid` | auto-detect | Local radicle NID to advertise |
|
||||||
|
| `--bridge-port` | 8777 | TCP port of the local bridge |
|
||||||
|
| `--poll-interval` | 30 | Seconds between ref polls |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## How it works
|
||||||
|
|
||||||
|
```
|
||||||
|
radicle-node ─TCP─ RadicleBridge ──RNS Link── RadicleBridge ─TCP─ radicle-node
|
||||||
|
(Machine A) (Machine A) (Machine B) (Machine B)
|
||||||
|
│ │
|
||||||
|
GossipRelay ──RNS Packet── GossipRelay
|
||||||
|
```
|
||||||
|
|
||||||
|
The bridge tunnels radicle-node's TCP stream over an `RNS.Buffer` — an ordered, reliable channel that works across all Reticulum interfaces including LoRa. Reticulum handles peer discovery, routing, encryption, and retransmission transparently.
|
||||||
|
|
||||||
|
The gossip relay is a lightweight side-channel (~300 bytes per event) that wakes peers when refs change, useful when the bridge TCP session is not yet live.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
```sh
|
||||||
|
uv run pytest # 97 tests
|
||||||
|
uv run pytest -x -q # stop on first failure
|
||||||
|
mypy src/
|
||||||
|
```
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue