From c815caa38fc9ba15a7f75a31735eeafa7039a6e7 Mon Sep 17 00:00:00 2001 From: Joey Stanford Date: Tue, 11 Aug 2026 21:35:45 -0600 Subject: [PATCH 1/3] docs: clarify Reticulum ownership layers and RF-mesh protocol scope Document RNS vs LXMF-client vs mesh-client policy so automation is not mistaken for transport, and state that additional protocols need an RF mesh path while remaining open to everyone. --- AGENTS.md | 1 + CONTRIBUTING.md | 5 ++++ README.md | 2 ++ docs/agents/reticulum.md | 1 + docs/index.md | 2 ++ docs/reticulum.md | 54 +++++++++++++++++++++++++++++++++++++++- 6 files changed, 64 insertions(+), 1 deletion(-) diff --git a/AGENTS.md b/AGENTS.md index 2aeb9b128..f48199cee 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -164,6 +164,7 @@ Deep, file-level subsystem detail now lives in [`docs/agents/`](docs/agents/READ - Prefer `useProtocolFacade` and identity-scoped stores (`identityStore` / `nodeStore` / `messageStore` / `connectionStore`, keyed by `identityId`); SQLite→UI via `hydrateIdentityStoresFromDb`. - MeshCore zero-hop Status/Telemetry/Neighbors are pubkey-framed (no contact-list gate); multi-hop ping needs a hash-segment path (≥2 bytes), never the full destination pubkey. Do not change behavior guarded by `meshcoreZeroHopRepeaterWorkingState.test.ts` without explicit user request — see [`docs/agents/meshcore-repeaters.md`](docs/agents/meshcore-repeaters.md). - Reticulum connect = sidecar start (not `ConnectionDriver` RF); no Noble/MQTT for Reticulum's own stack (sidecar owns BLE RNode via `btleplug`); a Reticulum BLE RNode may yield Noble on macOS/Windows — see [`docs/agents/ble-serial.md`](docs/agents/ble-serial.md) and [`docs/agents/reticulum.md`](docs/agents/reticulum.md). +- Reticulum automation ownership: do **not** reimplement RNS pathfinding/announce flood in UI or sidecar; **do** own lxmd-parity LXMF client/PN loops in the sidecar; treat Auto demotion / multi-PN cascade / path-medium / DM probe as **product policy** — see [`docs/reticulum.md#ownership-rns-vs-lxmf-client-vs-mesh-client-policy`](docs/reticulum.md#ownership-rns-vs-lxmf-client-vs-mesh-client-policy). - LoRa BLE reconnect is single-owner via `rfReconnectController`; manual disconnect must not auto-reconnect. Dual-radio Noble startup is serialized from `App.tsx` `useLayoutEffect` — see [`docs/agents/ble-serial.md`](docs/agents/ble-serial.md). ## 9. Cursor / Claude indexing diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 511d28a0c..535665e65 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,6 +6,7 @@ Thank you for your interest in contributing. | ------------------------------------------------------------- | ------------------------------------------------------------------ | | Clone, prerequisites, commands, test harness, git hooks, i18n | [docs/development-environment.md](docs/development-environment.md) | | Code style, testing, architecture, security (AI assistants) | [AGENTS.md](AGENTS.md) | +| Protocol additions (RF mesh only) | [Protocol scope](#protocol-scope) | | PR flow and contribution expectations | **This file** | ## Code style & standards @@ -27,6 +28,10 @@ See [Test harness setup and local quality checks](docs/development-environment.m - Update `src/main/index.contract.test.ts` when CSP, build config, IPC limits, or log filters change. - Accessibility: vitest-axe in component tests; see **Accessibility / axe** in [AGENTS.md](AGENTS.md#5-testing). +## Protocol scope + +Mesh-Client focuses on **RF mesh** networking (LoRa and related radio meshes). Additional protocols are in scope when they support that kind of RF mesh path. Internet-only messaging is out of scope. Ham protocols are welcome under the same RF-mesh criteria; Mesh-Client is for everyone, everywhere, and is not gated or targeted specifically at people with a ham radio license. Protocols that already ship may still use internet transports _alongside_ RF. Product framing: [README — Why](README.md#why). + ## PR process 1. Describe your changes and what you tested diff --git a/README.md b/README.md index 1b1202ab2..3ca8d0b94 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,8 @@ With a dedicated local SQLite database, Mesh-Client keeps message history and me From real-time diagnostics to permanent message archives, Mesh-Client delivers the desktop visibility serious mesh users require. +**Protocol scope:** Mesh-Client focuses on **RF mesh** networking—LoRa and related radio meshes. We will consider additional protocols when they support that kind of RF mesh path. Internet-only messaging stacks are out of scope. Amateur-radio (ham) protocols are welcome when they meet the same RF-mesh bar; Mesh-Client is for everyone, everywhere, and is not gated or targeted specifically at people with a ham radio license. + **Known Bugs:** - **Linux BLE**: uses Web Bluetooth (Chromium's built-in BLE API), with a user-visible picker and user gesture requirement to select a device. **MeshCore** may prompt for the radio's PIN and run OS-level pairing (`bluetoothctl`) before the connection completes when BlueZ reports the device as not paired (see [docs/development-environment.md](docs/development-environment.md#linux-bluetooth-ble)). diff --git a/docs/agents/reticulum.md b/docs/agents/reticulum.md index d18002ba2..a2c86c653 100644 --- a/docs/agents/reticulum.md +++ b/docs/agents/reticulum.md @@ -2,6 +2,7 @@ Deep subsystem reference for AI assistants. Open this when a task touches the Reticulum sidecar, LXMF, propagation, Remote (rnsh/rncp), Nomad, RRC, voice, or games. Hard rules live in [`AGENTS.md`](../../AGENTS.md); this file holds the file-level detail. +- **Ownership (do not reimplement transport):** Reticulum automation has three layers — (1) **RNS transport** (path table, announce flood, Auto beacons, Links/proofs) stays in rsReticulum (+ overlays under `reticulum-sidecar/patches/`); (2) **LXMF client/PN** loops (delivery announces, Direct→Propagated driver, identity-from-announce, PN `/offer`/`/get`) are intentional **lxmd/Ratspeak parity** owned by the sidecar because rsLXMF is not a daemon; (3) **mesh-client policy** (Auto→private demotion, multi-PN cascade, path-medium preference, DM auto-probe, Nomad `force_path_refresh`) is product behavior above RNS — document it, do not mistake it for transport. Renderer mirrors WS/HTTP and configures policy; it must not invent pathfinding or announce flooding. Full write-up: [../reticulum.md#ownership-rns-vs-lxmf-client-vs-mesh-client-policy](../reticulum.md#ownership-rns-vs-lxmf-client-vs-mesh-client-policy). - **Sidecar:** `reticulum-sidecar/` (AGPL Rust binary `mesh-client-reticulum`; path deps under repo-local `.rsstack/` via `scripts/clone-ratspeak-stack.sh` — `rsReticulum`/`rsLXMF`/`rsNomad`/`rsLXST`/`lrgp-rs`); dev: `pnpm run reticulum:sidecar:dev`. **Listen-first:** HTTP binds before `attach_live`; `/api/v1/status` `status: ok` = listening; `rns_ready`/`lxmf_ready` false until live. PN messagestore load deferred; local-prop serve waits for load. LXMF send/reaction fail closed with live-required errors until live. - **IPC:** `reticulum:*` main handlers — `start` / `stop` / `getStatus` / `syncInterfaceIssueScope`, `proxyGet` / `proxyPost` / `proxyPut` / `proxyDelete`, **`factoryReset`** (blocked on generic proxy), config file read/import dialog, `showNomadContentSourceDialog`, `setNomadContentSource`, Remote `rncpSend` / `rncpFetch` / `setRncpListener` / `showRncpOpenFileDialog` / `showRncpSaveDirectoryDialog` / `revealInFolder`. Also `media:ensureCameraAccess`, `gps:exportGpx`, `db:setReticulumDestinationVerified`, Remote DB `db:listReticulumRemoteAddresses` / upsert / delete and `db:listReticulumInboundPolicy` / upsert / delete (`src/main/ipc/reticulum-db-handlers.ts`), `mesh-client:openUrl` / `electronAPI.deepLink.onOpenUrl`. Renderer uses `electronAPI.reticulum` proxy (no direct localhost). Proxy rate-limit soft-envelopes live inside the handler `try` (`settleReticulumProxyFailure`). `ReticulumStackPanel` + `useReticulumInterfaceSnapshot` sync enabled interface names after hydrate so TCP/TX issue banners clear when hubs are disabled — **do not** refresh interfaces on `announce.received` / `stats_update` (that flooded `GET /interfaces` after wake); poll + shared proxy backoff only. `reticulumSidecarIssueTracker` keeps that enabled set sticky while reading sidecar logs. - **Panels:** `ReticulumStackPanel` (Connection — stack lifecycle, interfaces, issue banner), `ReticulumNetworkPanel` (Network — identity **slots** + QR share/ingest, stack/announce settings, Propagation mode Off/Auto/Manual + rename/delete, config import), `ChatDmPaperControls` (Chat DM **Share as paper** + **Scan paper**), `ReticulumMapPanel` (Map — RMAP v4 discovery), `ReticulumRmapDiscoveryControls` / `ReticulumRmapConnectionStatus` (RMAP publish: Network enable-all eligible interfaces; Connection **X of Y** status), `ReticulumAdminPanel` (Admin — RNode flasher, factory reset), `ReticulumPeerListPanel` (Peers — **Peers / History / Contacts / Favorites** sub-tabs; path request + probe + verified badge; LXMFace avatars; History = messaged `last_heard`, Contacts = explicit `is_contact` / Save as contact only), `NomadNetworkPanel` (Nomad — browse + **My Pages** watched-folder static host via `NomadPageServerPanel`/rsNomad; `nomad_serving_enabled` + `nomad_serving_content_source` restore hosting after live stack start; lazy-mount keep-alive, dual-axis page scroll; fit-width default and open-width toggle), `ReticulumRemotePanel` (Remote — rnsh multi-session shell + rncp send/receive/fetch; Saved addresses + inbound policy; Chat DM send-file via `ChatDmRncpControl`), `RrcPanel` (RRC — multi-hub relay chat) diff --git a/docs/index.md b/docs/index.md index 1dbb168dc..8f0f516eb 100644 --- a/docs/index.md +++ b/docs/index.md @@ -18,6 +18,8 @@ Key outcomes: - Multi-language support (16 languages) with offline static bundles. - Cross-platform desktop support for macOS, Linux, and Windows. +**Protocol scope:** Mesh-Client focuses on RF mesh (LoRa and related). Internet-only stacks are out of scope; ham protocols are fine when they meet the RF-mesh bar. Mesh-Client is for everyone, everywhere—not gated or targeted specifically at licensed amateurs. See [README — Why](https://github.com/Colorado-Mesh/mesh-client/blob/main/README.md#why). + --- ## Visuals diff --git a/docs/reticulum.md b/docs/reticulum.md index c7679903b..f4db90d70 100644 --- a/docs/reticulum.md +++ b/docs/reticulum.md @@ -176,6 +176,58 @@ The renderer **must not** call the sidecar URL directly (sandbox). All HTTP/WS g **Listen-first connect:** The sidecar binds HTTP first, then `attach_live` brings up RNS/LXMF (path table, BLE Peer, deferred PN messagestore). Electron health is `GET /api/v1/status` with `status: "ok"` — not `rns_ready` / `lxmf_ready`. `useReticulumRuntime` marks connection **configured** once start succeeds and identity is known, then hydrates peers/DB in the background and dispatches `RETICULUM_CONFIGURED_EVENT`. TCP hubs and RRC can proceed after live attach; Chat LXMF send/reaction fail closed with `requires live rns-stack sidecar` until the bridge is up. **Cancel** / stop does not wait on cargo or BLE; Noble yield for an enabled BLE RNode starts only after health (fire-and-forget). Renderer LXMF/RRC proxy sends use a **15 s** IPC deadline (`RETICULUM_IPC_SEND_TIMEOUT_MS`). +### Ownership: RNS vs LXMF client vs mesh-client policy + +Reticulum is not one blob that “does everything automatically.” Before adding sidecar or UI automation, classify the work: + +```mermaid +flowchart TB + subgraph rns [RNS transport - library] + PathTable[Path table / RequestPath] + AnnounceFlood[Announce flood / Auto beacons] + Links[Links / proofs / Resources] + end + subgraph lxmf [LXMF app layer - client or lxmd must own] + DeliveryAnnounce[lxmf.delivery announces] + OutboundDriver[Direct then Propagated delivery] + PnHost[PN serve /get /offer] + IdentityLearn[Pubkey from announces / path responses] + end + subgraph mesh [mesh-client product policy] + AutoDemote[Auto vs private LAN demotion] + PnCascade[Multi-PN deposit and sync cascade] + PathMedium[Prefer RF vs network slots] + UiProbe[DM probe / Nomad force-path] + end + rns --> lxmf + lxmf --> mesh +``` + +| Layer | Owns | mesh-client role | +| ----------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **RNS transport** (rsReticulum) | Path table, announce flooding, AutoInterface beacons, RMAP discovery announce signing, Links / proofs / Resources | Call transport APIs (`RequestPath`, path table reads, destination register). Do **not** reimplement pathfinding or beacon loops in the sidecar or UI. Library gaps belong in overlays under [`reticulum-sidecar/patches/`](../reticulum-sidecar/patches/README.md), not a second routing plane. | +| **LXMF client / PN** (rsLXMF + sidecar orchestration) | `lxmf.delivery` announce schedules, Direct→Propagated outbound driver, identity learning for LRPROOF, local PN serve (`/offer`/`/get`), client inbox retrieve | Intentional **lxmd / Ratspeak parity**. rsLXMF is a library, not a full daemon — the sidecar owns these loops (`lxmf_delivery.rs`, `lxmf_outbound.rs`, `propagation_*`, `pn_inbound.rs`). Without them, Chat and offline delivery do not work. Documented elsewhere as “Host PN fabric → Chat (lxmd-style glue)”: mesh-client is PN + end-client on rsLXMF, **not** a second `lxmd` binary. | +| **mesh-client product policy** | AutoInterface demotion toward private TCP/UDP, multi-slot path failover before PN fallback, prefer path medium, multi-PN deposit/sync cascade (Off/Auto/Manual), Chat DM auto-probe, Nomad `force_path_refresh` | **Not** required by bare RNS. Exists for multi-hub / Auto+LAN / UX. Treat as intentional product behavior; do not mistake it for transport. | + +**Renderer rule:** UI mirrors sidecar events and configures policy (announce interval, Propagation mode, Path/Probe buttons, RMAP publish toggles, topology layout). It must not invent peer discovery, announce flooding, or a second pathfinder. Optimistic `announce.received` peer rows and Topology graphs are **views** over the RNS path table, not routing. + +**What looks “automatic” but is correct to own in the sidecar** + +- Periodic / startup **LXMF delivery** announces and Network **Announce now** (Ratspeak/lxmd parity; see Network tab). +- `LxmfOutboundDriver` Direct planning, path-request gating, retries, then Propagated cascade. +- PN hosting admission, peer `/offer` bookkeeping, silent `/get` catch-up, and renderer Auto/Manual **sync cascades** that call into those APIs. +- Registering announce/path-response handlers so Direct LRPROOF has peer public keys. + +**What is product policy above RNS** (keep intentional; cite when changing) + +- [`auto_path_policy.rs`](../reticulum-sidecar/src/stack/auto_path_policy.rs) — RNS correctly prefers 0-hop Auto; sidecar demotes unhealthy Auto toward a live **private** path for LXMF Direct (see [Path routing](#path-routing)). +- [`path_failover.rs`](../reticulum-sidecar/src/stack/path_failover.rs) + path-medium overlays — ranked slots / medium preference before giving up Direct. +- [`pn_cascade.rs`](../reticulum-sidecar/src/stack/pn_cascade.rs) + [`reticulumPropagationAutoApply.ts`](../src/renderer/lib/reticulum/reticulumPropagationAutoApply.ts) — multi-PN deposit and sync order. +- Chat DM auto-probe (`useReticulumDmPathProbe`) — reachability UX; RNS would still path on send. +- Nomad `force_path_refresh` — DropPath→RequestPath recovery for stale TCP hub paths. + +**Gate for new automation:** Is this RNS transport, LXMF client/PN (lxmd parity), or mesh-client policy? Prefer library/overlay for transport; prefer sidecar lxmd-shaped loops for LXMF; prefer explicit, documented policy modules for product overrides — never a parallel path table or announce flood in the renderer. + --- ## Interface management (Connection tab) @@ -324,7 +376,7 @@ IRC-style multi-pane client (`RrcPanel` + `rrcHubStore` / `rrcSessionStore`): ## Path routing -When a destination is reachable over more than one next hop, the sidecar keeps up to **three ranked path slots** (one active + backups). Failover promotes a backup (or rediscovers via another live interface) before giving up — Nomad page loads exhaust alternate paths inside one request; LXMF Direct does the same before the **multi-PN cascade**. See [troubleshooting](troubleshooting.md#nomad-network-pages-hang-or-almost-never-load) for triage. +When a destination is reachable over more than one next hop, the sidecar keeps up to **three ranked path slots** (one active + backups). Failover promotes a backup (or rediscovers via another live interface) before giving up — Nomad page loads exhaust alternate paths inside one request; LXMF Direct does the same before the **multi-PN cascade**. These failover / medium / Auto-demotion behaviors are **mesh-client product policy** on top of the RNS path table — see [Ownership](#ownership-rns-vs-lxmf-client-vs-mesh-client-policy). Triage: [troubleshooting](troubleshooting.md#nomad-network-pages-hang-or-almost-never-load). **AutoInterface vs private TCP/UDP:** Peers learned on Auto are normal 0-hop neighbors; RNS may keep Auto active even when a private LAN hub path exists (including equal-hop ties). For LXMF Direct, the sidecar **automatically** demotes Auto toward a live **private** path when Auto is unhealthy for delivery or Direct fails on Auto — then fails over private → public → multi-PN cascade (preferred remote → other enabled remotes hop-sorted → in Auto, up to 3 Discovered PNs → local-prop last). It does **not** rewrite healthy Auto Direct, and does **not** preempt Auto to public internet hubs. See [troubleshooting — local DMs hang with AutoInterface + private TCP hub](troubleshooting.md#reticulum-local-dms-hang-with-autointerface--private-tcp-hub). From 48fa92a89deca75331a01ecce03d8b1f0c3e2049 Mon Sep 17 00:00:00 2001 From: Joey Stanford Date: Tue, 11 Aug 2026 21:41:30 -0600 Subject: [PATCH 2/3] docs: align protocol-scope wording across README and docs index Use the same RF-mesh eligibility contract everywhere, including internet transports alongside RF for shipped protocols. --- README.md | 2 +- docs/index.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3ca8d0b94..188ad51cd 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ With a dedicated local SQLite database, Mesh-Client keeps message history and me From real-time diagnostics to permanent message archives, Mesh-Client delivers the desktop visibility serious mesh users require. -**Protocol scope:** Mesh-Client focuses on **RF mesh** networking—LoRa and related radio meshes. We will consider additional protocols when they support that kind of RF mesh path. Internet-only messaging stacks are out of scope. Amateur-radio (ham) protocols are welcome when they meet the same RF-mesh bar; Mesh-Client is for everyone, everywhere, and is not gated or targeted specifically at people with a ham radio license. +**Protocol scope:** Mesh-Client focuses on **RF mesh** networking—LoRa and related radio meshes. Additional protocols are in scope when they support that kind of RF mesh path. Internet-only messaging stacks are out of scope. Amateur-radio (ham) protocols are welcome when they meet the same RF-mesh bar; Mesh-Client is for everyone, everywhere, and is not gated or targeted specifically at people with a ham radio license. Protocols that already ship may still use internet transports _alongside_ RF. **Known Bugs:** diff --git a/docs/index.md b/docs/index.md index 8f0f516eb..47bb088c6 100644 --- a/docs/index.md +++ b/docs/index.md @@ -18,7 +18,7 @@ Key outcomes: - Multi-language support (16 languages) with offline static bundles. - Cross-platform desktop support for macOS, Linux, and Windows. -**Protocol scope:** Mesh-Client focuses on RF mesh (LoRa and related). Internet-only stacks are out of scope; ham protocols are fine when they meet the RF-mesh bar. Mesh-Client is for everyone, everywhere—not gated or targeted specifically at licensed amateurs. See [README — Why](https://github.com/Colorado-Mesh/mesh-client/blob/main/README.md#why). +**Protocol scope:** Mesh-Client focuses on RF mesh (LoRa and related). Additional protocols are in scope when they support that RF mesh path. Internet-only stacks are out of scope; ham protocols are fine when they meet the RF-mesh bar. Mesh-Client is for everyone, everywhere—not gated or targeted specifically at licensed amateurs. Protocols that already ship may still use internet transports _alongside_ RF. See [README — Why](https://github.com/Colorado-Mesh/mesh-client/blob/main/README.md#why). --- From bf342b487b3dda1500b55f2724e48686838acd6b Mon Sep 17 00:00:00 2001 From: Joey Stanford Date: Tue, 11 Aug 2026 21:42:14 -0600 Subject: [PATCH 3/3] docs: use asterisk emphasis in CONTRIBUTING protocol scope