Files
archy/reticulum-daemon/README.md
T
archipelagoandClaude Opus 5 cc00884b98 docs: repair links left dangling by the operations-doc removal
Untracking the ops docs broke every reference to them. Repoints or removes
those references across README, architecture, ROADMAP, the archive index,
lifecycle TESTING, the hardening plan, and the security docs — pointing at
the issue tracker where a live task list was meant, and dropping the entry
entirely where it only existed to link an internal file.

Also fixes two pre-existing broken links found by validating every relative
link in the tracked docs:
- README linked docs/OPEN_SOURCE_READINESS.md, which never existed
  (underscores vs hyphens).
- reticulum-daemon/README.md linked a local Claude session plan at
  ../../.claude/plans/enchanted-strolling-rocket.md — outside the repo, and
  a path that would have shipped publicly pointing at nothing.

All relative links in tracked markdown now resolve: 0 broken.
audit-secrets.sh still 5/5.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-07 10:10:25 -04:00

67 lines
3.2 KiB
Markdown

# reticulum-daemon
Host-supervised **Reticulum (RNS) + LXMF** bridge for Archipelago's Mesh tab. This is
the Python side of the Reticulum transport work:
archipelago spawns one of these per active Reticulum (RNode) radio, it owns the serial
port, and the Rust mesh subsystem drives it over a Unix-socket JSON-RPC.
Why a daemon (not the Rust `reticulum-rs` crate): the canonical Python `rns`/`lxmf`
guarantees interop with Sideband / NomadNet / MeshChat, and lets us derive the RNS
identity from the existing Archy key (proven in `spike_identity.py`).
## Layout
- `archy_rns_identity.py` — derive a **deterministic** RNS `Identity` from the 32-byte
Archy Ed25519 seed (`identity_dir/node_key`) via domain-separated HKDF. The node's
LXMF destination hash is a stable function of the Archy identity.
- `spike_identity.py`**Phase-0 gate #1** (no radio): proves that determinism.
- `reticulum_daemon.py` — the daemon: RNS bring-up, LXMF router, announce handler, and
the Unix-socket RPC. See its module docstring for the wire protocol.
- `requirements.txt` — pinned `rns==1.3.5`, `lxmf==1.0.1` (validated on Python 3.13).
## Dev setup
```sh
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt
```
## Run the spike / smoke tests (no hardware)
```sh
.venv/bin/python spike_identity.py # gate #1: identity determinism
.venv/bin/python reticulum_daemon.py --check \
--identity-key /path/to/node_key # print this node's dest hash
.venv/bin/python reticulum_daemon.py --selftest \
--identity-key /path/to/node_key # bring up RNS+LXMF, no radio
```
## Run against a real RNode (Phase-0 hardware gate, on .116 / .228)
```sh
.venv/bin/python reticulum_daemon.py \
--identity-key /var/lib/archipelago/identity/node_key \
--serial-port /dev/reticulum-radio \
--socket /run/archy/reticulum.sock \
--display-name "archy-228"
```
Then verify a two-node LXMF DM over LoRa and interop with a stock Sideband/MeshChat
client (Phase-0 gates #2 and #3).
## Packaging (Phase 1)
Ship as a **PyInstaller single binary** in the OTA next to `/usr/local/bin/archipelago`
(no provision-time `pip install`). archipelago supervises it: start on RNode detect,
kill on unplug/disable. The RPC socket and RNS config dir are archipelago-owned, 0600.
```sh
./build.sh # → dist/archy-reticulum-daemon (~16M, fully standalone)
```
`-d noarchive` is required, not optional — see the comment in `build.sh`: RNS computes
`RNS.Interfaces.__all__` via a `glob()` against its own `__file__` directory at import
time, which only works when PyInstaller keeps modules as loose files instead of zipping
them into the binary.
## Status
Phase-0 gate #1 (identity determinism) **passes**, verified in both the dev venv and the
packaged binary (same dest hash). The signed-identity announce (`ARCHY:2:{ed}:{x25519}` in
`_announce_app_data`, via `--archy-ed-pubkey-hex`/`--archy-x25519-pubkey-hex`) is wired and
the Rust side (`reticulum.rs`) already passes the node's real keys through. Packaging is
done and verified standalone. What's left is entirely hardware-dependent: the live LoRa
message path (Phase-0 gates #2/#3) needs a real RNode-flashed board.