Agent reference: Reticulum
September 11, 2026 · View on GitHub
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; 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, Nomadforce_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. Extra sidecar send/path/PN code is usually lxmd glue or product policy, not accidental Ratspeak duplication; Chat outbox/badge receipt correlation stays in the renderer. Full write-up: ../reticulum.md#ownership-rns-vs-lxmf-client-vs-mesh-client-policy. - Sidecar:
reticulum-sidecar/(AGPL Rust binarymesh-client-reticulum; path deps under repo-local.rsstack/viascripts/clone-ratspeak-stack.sh—rsReticulum/rsLXMF/rsNomad/rsLXST/lrgp-rs); dev:pnpm run reticulum:sidecar:dev. Listen-first: HTTP binds beforeattach_live;/api/v1/statusstatus: ok= listening;rns_ready/lxmf_readyfalse 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, RemoterncpSend/rncpFetch/setRncpListener/showRncpOpenFileDialog/showRncpSaveDirectoryDialog/revealInFolder. Alsomedia:ensureCameraAccess,gps:exportGpx,db:setReticulumDestinationVerified, Remote DBdb:listReticulumRemoteAddresses/ upsert / delete anddb:listReticulumInboundPolicy/ upsert / delete (src/main/ipc/reticulum-db-handlers.ts),mesh-client:openUrl/electronAPI.deepLink.onOpenUrl. Renderer useselectronAPI.reticulumproxy (no direct localhost). Proxy rate-limit soft-envelopes live inside the handlertry(settleReticulumProxyFailure).ReticulumStackPanel+useReticulumInterfaceSnapshotsync enabled interface names after hydrate so TCP/TX issue banners clear when hubs are disabled — do not refresh interfaces onannounce.received/stats_update(that floodedGET /interfacesafter wake); poll + shared proxy backoff only.reticulumSidecarIssueTrackerkeeps that enabled set sticky while reading sidecar logs; latches named TCP RST/EOF for Connection alerts. TCP hub fast-flap (RNS 1.4.0+):reticulumStackSessionTrackercounts stack starts (five in 12h, persisted; testers with long sessions still qualify); Connection amber banner usestcp_fast_flap/ unreachable+restart hint; auto stack restart is skipped; host TCP probes run only before sidecar ready. troubleshooting. - 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 = messagedlast_heard, Contacts = explicitis_contact/ Save as contact only),NomadNetworkPanel(Nomad — browse + My Pages watched-folder static host viaNomadPageServerPanel/rsNomad;nomad_serving_enabled+nomad_serving_content_sourcerestore 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 viaChatDmRncpControl),RrcPanel(RRC — multi-hub relay chat) - Deep links / QR: OS scheme is
lxm://(notmesh-client://);MeshClientDeepLinkHost,meshClientDeepLink.ts(lxmPaperMessagekind +looksLikeLxmPaperBlob; Gameslxm://game/<session>/ Ratspeaklrgp:<session>→lxmGameSession),handleReticulumQrIngest.ts(shared Network/Chat/OS paper + in-app contact ingest),applyLxmPaperIngest→POST /api/v1/lxmf/paper/ingest,QrIngestControl/QrCodeImage. OS contact / MeshCore imports confirm before upsert; paper OS deep links ingest without confirm; Games session links open Reticulum Games tab viaopenReticulumGameSession. - Decommissioned hubs:
src/shared/reticulumDecommissionedHubs.ts(Amsterdam only) — stack-start auto-disable + Add default backbones disables matching enabled TCP rows; UI badge + enable-block inReticulumInterfacesPanel.tsx(isDecommissionedReticulumTcpInterfaceRow); keep TS↔Rust synced viapnpm run check:reticulum-decommissioned-hubs. Default backbone picker + region-grouped interface list (Primary & Global / North America / Europe / Asia & Oceania / Specialty / User Defined) inreticulumDefaultHubPresets.ts+ReticulumDefaultHubsPickerModal.tsx; muted disabled rows + checkbox bulk delete;countEnabledDefaultHubPresets/ >3 enable warning - BLE RNode RSSI:
useReticulumBleRnodeRssiMapgates on sidecar running (not api-ready), burst-then-steady scans via nestedacquireReticulumBleScan, clears sticky targets immediately when all BLE RNodes are disabled - Propagation mode / sync: Network → Propagation nodes owns Off/Auto/Manual (default Off; persisted values including legacy App-panel
autoare honored). Auto one-time syncs viastartPropagationSyncCascade+ sidecardestination_hashsync in order: finite-hop discovered (no Add/Preferred) → configured remotes → unknown-hop discovered → local-prop (skips remotes when no enabled interfaces); runtime hookuseReticulumPropagationAutoSync. Sidecarstart_propagation_syncis client/get-primary (inbox retrieval; UI progress fromPropagationClient) — peer/offerinventory push stays on the local-host peer loop when serving (avoids AwaitingResponse hangs against non-peer remotes with a nonempty messagestore). Hard-fails withPROPAGATION_PATH_UNKNOWNwhenensure_path_for_directfails after announce settle (same path gate as offer probe). Manual uses Preferred, else picks the best configured remote for that sync only (no Preferred write), then the remaining remotes, then local-prop. Off = no PN support:startPropagationSyncCascadereturns early (per-row Sync is disabled in UI),hasEffectiveReticulumPropagationTarget/hasReticulumPnCascadeCapacityare false,ReticulumPropagationNoticeis hidden, and the sidecar disarms the outbound PN plus empties cascade candidates (propagation_modeinmesh_client_stack.json,POST /api/v1/propagation/mode,candidates_for_propagation_mode); renderer pushes the mode on change and on sidecar-ready. Ignore for Auto:POST/DELETE /api/v1/propagation/auto-blacklistpersistspropagation_auto_blacklist(32-hex, cap 256); filters Auto sync ranking and Auto deposit (auto_discovered_candidates+ configured retain in Auto); Manual Prefer/Sync still allowed. Ownership: mode in renderer localStorage (+ sidecar mirror); blacklist + deposit candidates in sidecar; sync cascade orchestration inreticulumPropagationAutoApply.ts;startSyncattempt stamps must be unique across same-ms supersession.reticulumPropagationStore/reticulumPropagationSync.ts— Establishing stall (~45s) + hard ceiling (~180s), auto-sync interval from last success with failure cooldown, error keys for identity / non-PN / path-unknown / peering stamp; stampslastPropagationSyncAttemptAt/activePropagationSyncAttemptAtfor WS correlation. Cancel mid-/getmust callPropagationClient::abort_transfer(rsLXMF overlay) or the next Sync staysPROPAGATION_RETRIEVE_BUSY. Silent Host/getterminal clear must only drop the latch whenpropagation_sync_targetstill equals that peer. Nothing-to-sync is not a failure: when the cascade contacts no node it writessyncNoTarget/syncLocalLoading/syncRetrieveBusy(never overwriting a real error from an attempted node), the local row reports sidecarstatus: "loading"while the messagestore reads (local_propagation_status+PropagationBridge::messagestore_load_pending, per-row Sync disabled), and the 30 s tick callsrefreshFromSidecarwhilehasPropagationCascadeCandidateis false so a fresh stack recovers on its own —refreshFromSidecarmust not clear the active attempt whilesync.active. Debug snapshotpropagationClientexposes mode/preferred/autoTarget/resolvedSyncTargetId/autoBlacklist. Auto also deposits on Discovered PNs: sidecarauto_discovered_candidates(pn_cascade.rs, Auto only, cap 3, hop-sorted withMAX_PLAUSIBLE_PROPAGATION_HOPS=32, skips inactive / self / already-configured / Auto-blacklist / overmax_peering_cost) appends after configured remotes and before local-prop, rebuilt from the sharedrebuild_pn_cascade_candidateshelper inlive.rs; capacity helpers count non-blacklisted discovered rows in Auto. Chat notice dismiss:chatNoticeDismissedwith Don't show again / Network toggle. Named sync target:startSyncstampssyncTargetId. Attempts settle before the cascade advances:startSyncreturnsaccepted|deferred|failed. Soft-defer (PROPAGATION_SYNC_OUTBOUND_BUSY/PROPAGATION_RETRIEVE_BUSY/PROPAGATION_STACK_NOT_LIVE) advances without 15‑min backoff; all-remote soft-defer + local-only settle must not advancelastPropagationSyncAtas a full success. Remote budgetPROPAGATION_CASCADE_BUDGET_MS(5 min); per-attempt ~60s; single-flight cascade. Auto/api/v1/interfacesprobe fails closed (treat read/rate-limit as no interfaces → local-only settle). Retrieval vs peer sync: User Sync progress is client/get-primary. Peer/offerruns only on the local Host peer loop. Logs:propagation-retrieve(retrieve_mode=get|get_post_peer|get_periodic|local); peer-offerpropagation-sync … peer_outcome=*(not retrieval).local-propSync usesdrain_local_inboxand returnsPROPAGATION_STACK_NOT_LIVEwhen live is absent. - Host PN fabric → Chat (lxmd-style glue): When local Host is enabled, mesh-client is both PN and end-client on rsLXMF (not a second lxmd). Path: outbound deposit → host peer
/offerpush (generation-gated; lxmd terminal bookkeeping:sync_complete/mark_offer_generation_processed/take_handled_updates+save_peer); inbound peer Resource accept →request_inbox_drain→ maintenancedrain_local_inbox→delivery_callback→ Chat; after host peer/offerCompletes for peerP, sequenced silent client/get(retrieve_mode=get_post_peer); while serving and quiet, ~90s periodic silent/getround-robin over peered remotes (Prefer/outbound first,retrieve_mode=get_periodic) for inbox catch-up — not a timed empty re-/offer. Re-/offerwhenoffer_generationadvances, offer policy changes, or a partial sync left work; maintenance polls every ~2s but only starts work when idle. Guards: coalesce drain; one internal/get; skip when user Sync target / outbound deposit owns the hash orsync_active/client_download_active. Do not re-attach peer/offerto the Sync button. Dual full-index exchange in one Link stays upstream rsLXMF; remote inventory for re-propagation arrives when peers/offerto our serve path. - PN hosting: Network Advanced PN hosting /
ReticulumPnHostingDangerZone; sharedpnHostingPolicy.ts+ sidecarpn_hosting_policy.rs/pn_hosting_apply.rs;POST /api/v1/propagation/hosting-policy; rsLXMF policy-setters overlay (ratspeak/rsLXMF#6). Messagestore loads in background on live attach; enabledlocal-propserve/announce waits until load completes. - Interface modes: rnsd
modeviareticulumInterfaceMode.ts+ sidecarnormalize_interface_mode(keep catalogs in sync —pnpm run check:reticulum-interface-modesin pre-commit/release.sh); add defaults TCP/UDP/I2P →boundary, RNode →access_point; UI inReticulumInterfacesPanel; default hub presets add/repair missing mode toboundary(do not overwrite valid non-boundary). Discoverable + Full/Roaming/Boundary stampsignore_config_warnings = Yes(reconcile_ignore_config_warnings/repair_ignore_config_warnings_in_config) so RNS does not auto-correct runtime mode to Access Point; Connection shows Effective: Access Point when liveruntime_modestill diverges. See ../reticulum.md#interface-modes and ../reticulum.md#rmap-publish-and-interface-mode. - Share instance defaults: missing keys bootstrap to
share_instance = No/instance_name = mesh-client(does not overwrite explicit Yes/default); SharedInstanceClient banner +disable_share_instancerepair; offline lint viareticulum:validateConfig/ Network Check config /pnpm run reticulum:config:check - LXMF replies: sidecar stamps
FIELD_REPLY_TO/ cappedFIELD_REPLY_QUOTEbefore sign; renderer ingest/Chat usereticulum_reply_to_hash+ quote preview + jump-by-hash - RNode flasher timeouts:
RNODE_COMMAND_TIMEOUT_MS(30 s serial),RNODE_BT_PAIRING_TIMEOUT_MS(90 s BLE pairing),ESP32_FLASH_STALL_TIMEOUT_MS/NRF52_DFU_STALL_TIMEOUT_MS(60 s no-progress →ESP32_FLASH_STALLED/NRF52_DFU_STALLED); humanized viaflasherErrorHumanize.ts - Peer aliases / History vs Contacts: LXMF/Nomad announce names overlay path-table peers; SQLite
reticulum_destinations.last_heard= History,is_contact= Contacts (Save as contact only — inbound/outbound LXMF does not auto-add Contacts; sidecar/contactswire rows are History hints unless SQLiteis_contact=1); default avatars via vendored LXMFace (lib/reticulum/lxmface.ts); renderer refresh +reticulumContactToNodeRecordPreservingLabelrefuse hash-prefix wipes of Chat/nodeStorelabels; ingest stamps History viapersistReticulumHistoryFromPayload+stampHistoryPeer; SQL upsert guard preserves real names over hash-prefix aliases; destination upsert requires exact 32-hex (lowercase) and omitsfavoritedon icon-only patches so favorites/icons survive path/probe refresh. Chat DMs arelxmf.deliveryonly —resolveReticulumChatLxmfDest.tsremapslxst.telephony(and other non-lxmf path-table rows) to that identity’s LXMF hash via identity activity; Peers Message / paste / send refuse when no LXMF announce is known (Voice badge on telephony-only rows). Existing open/active DM tabs canonicalize onto the LXMF fold when remapped (remapReticulumChatDmTabs.ts); filters/unread alias remappable aspects viareticulumChatDmNodeIdsEquivalent. - RRC
/who:RrcPanelsends/who <room>withK_ROOMset to the joined wire room (Python rrc-web parity; slash commands are handled before forward so this is not room chat). Never/whosynthetic[hub]/@dmrooms. Empty inboundK_ROOM→[hub](resolveRrcInboundChatRoom/RRC_HUB_STREAM_ROOM), never the focused room. First/whoNOTICE per named room may appear in the transcript (consumeWhoTranscriptSlot/shouldShowRrcWhoTranscript); later snapshots update the nicklist only. User-initiated Refresh / composer/whobypasses that slot. Stock rrcdemit_noticefor/who/actor JOINED is a singlePacket.send(no chunk/resource): if the roster exceeds Link MDU (typically 431) the hub drops it silently — observed on RNS Community28c7…with MDU 431 while Colorado Mesh who (~300 B) succeeds. Nicklist then grows from fanout JOINED + opportunistic chat; join-info NOTICE still seeds self into the roster when actor JOINED never arrives. - EX1-RRCD client parity: Advertise
CAP_RESOURCE_ENVELOPE/CAP_ACTION/CAP_DIRECT_NOTICEin HELLO; acceptT_RESOURCE_ENVELOPE(50) with SHA256 verify + notice/motd dispatch (blob ignored); parse WELCOME hub version + limits; JOINED bodies as full list or single/bare hash with advisoryK_NICKon fanout (merge, never wipe on empty); peerPARTEDupdates nicklist viarrc.room.peer_parted. Full busy-room roster still requires a hub that chunks/who(Ratspeakpush_notice_entries) or usessend_text_smart. - RRC stick-to-bottom: Owned by
RrcChatView+ sharedchatScrollUtils(TanStack VirtualfollowOnAppend/ pin ref); keep Chat/Rooms flexmin-h-0+ stream[overflow-anchor:none]parity so the message stream remains a real scroller. - Stores/lib:
reticulumIdentityStore.ts(session-global sidecar identity status shared byuseReticulumSidecarApi— distinct from identity-scopedidentityStore),reticulumPeerStore.ts(path-tablepeers+history+ savedcontacts; soft-TTL reads, forced?refresh=1, incrementalpeers_updatedroute-field patches, 50ms batching, name/appearance preservation, 30s/60s large-mesh poll),reticulumDiscoveryMapStore.ts,reticulumRmapDiscovery.ts,reticulumDiscoveryMapLayout.ts,nomadNetworkStore.ts,rrcHubStore.ts/rrcSessionStore.ts(RRC hubs + multi-hub sessions; hydrate/clear room history viarrcRoomHistory.ts; persist → SQLiterrc_messagesviarrcMessagePersist.ts+ipc/rrc-db-handlers.ts; prefs inrrcHubPrefs/rrcRoomPrefs/rrcRecentRooms; notifications inrrcInactiveNotifications/rrcMention(resolveRrcAlertType+ ApprrcUnreadAllRoomMessages, default all-room, IRC mention/DM opt-out)); Remote (rnsh/rncp):rncpTransferStore.ts,rnshSessionStore.ts,reticulumInboundPolicyStore.ts,reticulumRemoteAddressStore.ts,rncpEnableRequestStore.ts+ libremoteSettingsStorage.ts,pushRncpListenerPolicy.ts,rncpInboundPolicyLists.ts,sendRncpRequestEnable.ts,rncpRequestEnableRateLimit.ts,applyRncpReceiveDestShare.ts/rncpReceiveDestSharePending.ts(mark pending on request-enable; consume on ingest within TTL),hooks/useRemotePathCapability.ts,components/remote/*; WS eventsrmap.discovery,lxmf_outbound_status,nomadnetwork.node,rrc.*,rnsh.*/rncp.*inuseReticulumRuntime(sidecar also emitsnomad.serving_start/nomad.serving_stop; renderer polls serving status via HTTP, not those WS events) - LXMF outbound delivery: sidecar
lxmf_delivery.rs/lxmf_outbound.rs/pn_cascade.rs(Direct-first; after Direct exhausts multi-PN cascade: preferred remote → other enabled remotes hop-sorted → in Auto only, up to 3 heard-but-not-added Discovered PNs hop-sorted → local-prop last; intermediate WSsending+delivery_method: "propagated"or"stored_locally"; terminaldeliveredat remote PN vsstored_locallyfor local hosted PN). Local-prop is a full PN (in-process cascade deposit viaaccept_stamped_propagated_blob; host peer/offersync; auto Chat drain after peer ingress + post-peer silent/get; explicit local Sync viadrain_local_inbox) — not an outbox; clients need not Prefer you. Propagated link establishment timeout advances the cascade when other PNs remain (avoids Prefer-hash timeout storms). Sync vs deposit:PROPAGATION_SYNC_OUTBOUND_BUSY/PN_DEPOSIT_DEFER_ADVANCE_AFTER. RendererapplyReticulumOutboundDeliveryStatus.ts(WSlxmf_outbound_status→ Zustand + SQLitedelivery_status+delivery_method; early-status buffer; hash/status allowlist),reticulumOutboundFailureBridge.ts(shouldApplyLinkDeliveryTimeoutFailureBridgeskips the link-timeout Failed bridge when cascade capacity remains — remote or enabled local-prop; also skipspropagated/stored_locallyrows so cascade is not killed),markStaleReticulumOutbound.ts. Optimistic pending rows usereticulum-pending-*; send-path rekey passesreplaces_message_hashon SQLite upsert to delete the prior pending hash. Remote PN Completes UI: Stored at propagation node (ReticulumMessageStatusBadgePN + green check); local-prop Completes: deposited on your hosted node (PN + amber house; peer sync may still propagate). Mode Off has no cascade capacity, so the link-timeout bridge fails the row. Paper exception:createReticulumPaperMessage/ paper create Completes immediately (delivery_method: paper,ReticulumMessageStatusBadgePaper) vialxmf_message— nolxmf_outbound_status; sharedreticulumMessageTransport/reticulumPaperErrorskeep IPC allowlists and i18n codes aligned. - DM path reachability:
useReticulumDmPathProbe.ts,reticulumDmPathReachability.ts,ReticulumDmPathReachabilityBadge.tsx— Chat Probe matches Peer List (sidecar running check →/probe→ toast → refresh);applyProbeResult(forHash, …)applies the settle without a second/probeand ignores stale completions after DM switch; manual reprobe forces Checking… even when passive hops look reachable; Peers virtualizes above 100 rows viareticulumPeerListRows.ts; peer refresh policy inreticulumSidecarPeerRefreshEvents.ts - Inbound transport labels:
received_viaresolves the path-table interface name against local interface config type, so a TCP hub display name still renders as TCP. - Topology:
via_hashis an immediate transport id; sidecar synthesizes missing relay nodes.ReticulumTopologyPaneluses force layout; sidecar caps graph input at 2,000 peers, renderer ingest 800, drawn graph 400 after hop filters (same as LoRa Graph). Unknown hops only when All hops + Show distant. RF only checkbox keeps RNode/KISS/BLE spokes. - Retention: App defaults Reticulum destination age/count pruning to 30 days / 10,000 destinations (favorites preserved; count max 50,000); Reticulum message retention independently enabled at 4,000. RRC room history retention independently enabled by default at 10,000 messages (30-day age prune) via
rrcMessageRetention*settings anddb:pruneRrcMessagesByCount/db:pruneRrcMessagesByAge. - Self label / header:
reticulumSelfNodeLabel.ts(resolveReticulumSelfHeaderLabel— Network display name in app header) - Nomad errors:
lib/nomad/nomadPageErrorHumanize.ts(sidecar error codes → i18n); LinkClient Nomad overlay inreticulum-sidecar/patches/ - Nomad request bodies: MessagePack
field_*/var_*encode/decode lives in rsNomadnomad-core(encode_request_fields/decode_request_fields); sidecarnomad_request_payload.rsonly unwraps HTTP base64 JSON before calling encode - LXST voice:
hasLxstVoicegates Call buttons (Peers + Chat DM). Session helpers inreticulumVoiceSession.ts(dial/answer/hangup + mic PCM); UI storereticulumVoiceStore.ts; overlayReticulumVoiceOverlay(App mount). Dedicated IPCreticulum:voiceSendAudio+ push channelreticulum:voiceAudio(/ws/voice; preloadonVoiceAudio); control viaelectronAPI.reticulum.voice.*. Runtime WS:voice.update/voice.incoming/voice.stats/voice.terminated/voice.error(errors should carrylink_idwhen known; match by link/generation/remote). Establish-only media: Answer warms AudioContext; mic capture/TX starts only afterestablished; sidecar soft-drops pre-establish PCM (not_established). Outbound progress tones: dial → peer DTMF fold → UK double-ring (reticulumVoiceCallTones.ts/reticulumVoiceOutcome.ts/reticulumVoiceFeedback.ts); media-start coalesces bycallGenerationto avoid Answer mic thrash. Terminal reasons: treat sidecarestablished/terminatedas completed (not fail). - LXMF voice memos:
hasReticulumVoiceMemogates Chat DM mic (not LXST Call). Sidecar encodes Opus/AM_OPUS_OGGvia/api/v1/voice/memo/{start,audio,stop,cancel}+ dedicated IPCelectronAPI.reticulum.voiceMemo.*(reticulum:voiceMemoStart/voiceMemoSendAudio/voiceMemoStop/voiceMemoCancel; proxy blocked). Capture resamples to 24 kHz / 60 ms frames and serializes PCM IPC before stop. Ogg capped ~240 KiB under the 256 KiB LXMF field / default PN deposit. Key files:reticulumVoiceMemo.ts,sendReticulumVoiceMemo.ts,reticulumVoiceMemoStore.ts,reticulum-attachment-audio.ts,ReticulumVoiceMemoLine.tsx. Ingest stampsFIELD_AUDIO→ attachment jail + playback (chat:readReticulumAttachmentBytes). Oversize-for-PN emitsmessage_too_large_for_propagation(notice toast + Direct-only badge — never a PN-outage toast). Tap mic to record, tap again to send; Esc/DM-switch cancels; mic stays visible while recording even if the draft is non-empty. - LRGP games:
hasLrgpGamesgates Games tab + Challenge (Peers / Chat DM). Sidecargames_session+LrgpStore; companiongames_outbound.dbpersists last envelope +delivery_state(LXMF outbound bridge → session chips / Resend). Dedicated IPCelectronAPI.reticulum.games.*/reticulum:games*(proxy rejects/api/v1/games/*); WSgames.update/games.action_result. Parity: ../reticulum-games-parity.md. - Gating:
hasReticulumDiscoveryMap(Map tab);hasReticulumRemotePanel/hasRncpTransfer(Remote tab + Chat DM rncp);hasRrcPanel(RRC tab);hasLxstVoice(LXST Call);hasReticulumVoiceMemo(LXMF voice memos);hasLrgpGames(Games);hasReticulumInterfaceConfig/hasReticulumNetworkPanel/ProtocolCapabilities - rnsh/rncp: sidecar
stack/{rnsh_session,rncp_transfer,path_speed,link_task}.rs+ HTTP/api/v1/rnsh/*,/api/v1/rncp/*,/api/v1/remote/*; typedelectronAPI.reticulum.rnsh|rncp|remote; picker-gated send/fetch paths inreticulum-remote-paths.ts; LXMF enable-request sentinelmesh-client:request-rncp-receive:v1(rncpRequestEnable.ts); peer replymesh-client:rncp-receive-dest:v1:<hash>autofills viaapplyRncpReceiveDestShare(prefer pending frommarkRncpReceiveDestSharePending/sendRncpRequestEnable; still apply without pending for older peers); enable-request modal + dest-share side effects deduped by LXMFmessage_hash(rncpLxmfControlSideEffectDedup) so catch-up cannot re-fire; already-listening auto-share is once per peer per request-enable cooldown; inbound listener config persists (rncp_listener_*inmesh_client_stack.json) and restores on live stack start - Sidecar RRC:
rrc_codec/rrc_link/rrc_session/api/rrc.rs. Idle join-ack +/whoafter leaving the app alone is usually a real Link death (rrc.disconnected reason=timeout|transport_error|… will_reconnect=true), not a/whopoll — RNS initiator keepalive/stale (RTT-scaled, min ~5s/10s on fast TCP) tears the Link; sidecar auto-reconnects and re-JOINs.rrc_linkprefers sessionClosedreasons over a racingresource_offerschannel close (do not trustresource_offers_closedas primary). After timeout/transport/remote close, reconnect uses DropPath+RequestPath so LRPROOF can re-attach on a live iface instead of a dead via pin. - Runtime:
useReticulumRuntime,lib/sessions/reticulumSession.ts,lib/ingest/reticulumIngest.ts; connect starts sidecar, notConnectionDriverRF — marks configured when HTTP + identity ready (live attach may still run);RETICULUM_CONFIGURED_EVENTwakes RRC. Cancel/stop is fire-and-forget vs cargo/BLE (START_ABORTEDcheckpoints; next start does not rejoin a doomed promise). LXMF/RRC proxy sends: 15 sRETICULUM_IPC_SEND_TIMEOUT_MS. RRC auto-connect (useRrcStartupAutoConnect): ~500 ms while hubs pending, ~4 s steady. - Diagnostics:
ReticulumDiagnosticEngine.ts(Reticulum-native rows; no LoRa hop-goblin semantics) — includesreticulum/sidecar-unhealthy(60s grace; HTTP health, not listen-first ready lag),reticulum/rns-not-ready/reticulum/lxmf-not-ready,reticulum/propagation-sync-stuck,reticulum/propagation-sync-failing(1h TTL) - No Noble/MQTT for Reticulum's own connections (sidecar owns BLE RNode via
btleplug); gate UI withhasReticulumInterfaceConfig/hasReticulumNetworkPanel/ProtocolCapabilities. On macOS/Windows, connecting a Reticulum BLE RNode may still suspend/yield Noble so it does not contend with the sidecar's BLE scan — see Multi-protocol BLE in ble-serial.md. - Multi-protocol BLE: see ble-serial.md for the full coexistence contract (peripheral MAC registry, scan-only mutex, Reticulum BLE RNode Noble yield on macOS/Windows).
- Docs: ../reticulum.md, ../reticulum-sidecar-ipc.md