Blog
Engineering

Two kinds of offline: why we added Reticulum and Nostr

Gokul Santhosh
Gokul Santhosh · Aug 17, 2026
mesh sdkreticulumnostrengineering
Two kinds of offline: why we added Reticulum and Nostr

When we open sourced the Offline Protocol Mesh SDK, we made a simple argument: the internet should be a capability, not a prerequisite. That argument immediately raises a harder engineering question. What does an application do when the usual paths are gone?

Bluetooth Low Energy can reach across a room. Wi-Fi Direct can connect devices across a building or field site. An internet transport covers the ordinary case where both peers can reach the same service. Together, those paths handle a large part of what people call offline-first software. They do not handle every kind of offline.

Sometimes there is no conventional network at all. Devices are separated by kilometers, local infrastructure is damaged or absent, and a phone radio cannot close the distance. Sometimes a network exists, but the available path is filtered, fragile, centrally observable, or dependent on an endpoint the application does not control. Those are different network conditions, and they need different answers.

We added two transports to address them. Reticulum gives the SDK a path into long-range and infrastructure-sparse networks, including LoRa, serial, TCP, UDP, and I2P. Nostr gives it a decentralized relay path over infrastructure that no single operator needs to own. Both extend the same Offline Protocol transport layer into environments our direct radios and ordinary internet path cannot cover.

Resilience is not one fallback. It is the ability to keep finding an appropriate path as the operating environment changes.

One SDK, five network paths

An application using Offline Protocol should not need a separate messaging model for every radio or relay network underneath it. It produces a message, declares the relevant policy, and lets the transport layer evaluate the paths that are actually available. The Dynamic Offline Relay Switch, or DORS, scores Bluetooth LE, Wi-Fi Direct, internet, Reticulum, and Nostr using measured reliability, congestion, bandwidth, energy cost, proximity, and application preference. The application envelope, identity model, delivery semantics, and reliability rules remain consistent while the underlying path changes.

Reticulum and Nostr differ almost everywhere else, but they meet the same transport contract inside the SDK. Rust owns message queues, pending confirmations, delivery metrics, routing policy, and protocol state. The platform layer owns the live network connection. It reports availability, requests queued messages, confirms delivery outcomes, and returns incoming bytes to the core. That division keeps the coordination engine portable while allowing each operating system to use the runtime and networking behavior best suited to it.

┌─────────────────────────────────────────────────────────────┐
│ Application                                                 │
│ One message model, identity layer, policy, and event stream │
└────────────────────────────┬────────────────────────────────┘

┌────────────────────────────▼────────────────────────────────┐
│ Offline Protocol Rust core                                  │
│ DORS | queues | retry | deduplication | confirmations       │
└───────────────┬──────────────────────────┬──────────────────┘
                │ UniFFI                   │ UniFFI
      ┌─────────▼──────────┐     ┌─────────▼──────────┐
      │ Reticulum bridge   │     │ NostrManager       │
      │ Runtime or daemon  │     │ WebSocket pool     │
      └─────────┬──────────┘     └─────────┬──────────┘
                │                          │
      LoRa | serial | TCP | UDP      Independent relays

The confirmation loop is what turns those connections into routes DORS can evaluate. Every dequeued message is eventually confirmed or failed, and that outcome feeds the transport’s measured reliability. If a connection changes, the message remains available for another attempt or another path. The selector learns from observed delivery rather than assuming that an open socket is a healthy network.

Both transports are configured through the same application surface. In the current React Native SDK, enabling the two paths looks like this:

const protocol = new OfflineProtocol({
  appId: 'field-operations',
  profile: 'gateway-01',
  transports: {
    ble: { enabled: true },
    reticulum: {
      enabled: true,
      daemonAddress: 'localhost:4242',
      autoReconnect: true,
    },
    nostr: {
      enabled: true,
      relayUrls: [
        'wss://relay.damus.io',
        'wss://nos.lol',
        'wss://relay.nostr.band',
      ],
      sealingEnabled: true,
      coldContactEnabled: true,
      usernameDiscoveryEnabled: false,
    },
  },
  encryption: { enabled: true },
});

The Nostr route is derived from the device’s initialized off1... address, not its human-readable profile. Initializing the identity and MLS layer therefore establishes the address the transport uses for relay subscriptions and peer routing.

Reticulum extends the physical reach of the mesh

Reticulum is a networking stack designed to operate across a wide range of physical media. For Offline Protocol, its most consequential contribution is reach. A LoRa path can span several kilometers, and favorable terrain or line of sight can extend that much further. Serial links, packet radios, TCP, UDP, I2P, and other Reticulum interfaces allow the same application to move across networks that look nothing like a mobile data connection.

LoRa configurationRaw bitrateEffective throughputRelative range
SF7 / BW500kHz / CR4:5~21.9 kbps~2.7 KB/sShort
SF7 / BW125kHz / CR4:5~5.5 kbps~0.67 KB/sMedium
SF8 / BW125kHz / CR4:5~3.1 kbps~0.38 KB/sLong
SF12 / BW125kHz / CR4:5~0.29 kbps~0.04 KB/sMaximum

That range opens a different class of deployment. Field teams can carry coordination beyond phone-radio distance. Sensors and gateways can exchange essential state across sparse sites. Disaster-response systems can form paths through whatever radio infrastructure remains available. Remote industrial, agricultural, maritime, and environmental systems can keep a shared local workflow alive without requiring every participant to reach a tower or satellite connection directly.

The integration also teaches DORS to respect the physics of the medium. A practical LoRa link may deliver only a few kilobytes per second, or tens of bytes per second under more constrained settings. Reticulum therefore receives a 120-second confirmation window rather than the 15 seconds used by the ordinary internet transport. Reliability carries more weight than raw bandwidth, media receives a deliberate scoring penalty, and the low-power profile can make Reticulum increasingly valuable when Wi-Fi or cellular radios would spend more energy searching for infrastructure.

These are not special cases exposed to application code. They are transport characteristics translated into routing policy. A small signed message, a sensor reading, and a media file do not have the same delivery requirements, so DORS can evaluate Reticulum differently for each while preserving the same message model above it.

The current Reticulum scoring profile makes that policy explicit in the Rust router:

TransportType::Reticulum => TransportScoringProfile {
    weights: ScoringWeights {
        signal: 0.05,
        proximity: 0.20,
        bandwidth: 0.05,
        congestion: 0.15,
        energy: 0.25,
        reliability: 0.30,
        load: 0.0,
    },
    base_score: 0.0,
    media_bonus: 0.0,
    media_penalty: 40.0,
    bandwidth_max_bps: 2_700,
    bandwidth_default: 20.0,
    energy_baseline: 75.0,
    is_high_power: false,
    active_relay_energy_adjustment: 0.0,
    has_signal: true,
    default_signal_score: 60.0,
    tie_break_priority: 3,
},

The Mesh SDK provides the Reticulum adapter, queuing, confirmation behavior, delivery metrics, and manager surfaces for iOS and Android. Applications can connect that bridge to an embedded Reticulum runtime, a shared daemon, or a gateway based on the deployment. This modular boundary lets teams use the reference implementation and existing Reticulum ecosystem today without forcing a Python runtime or a particular network topology into every application that adopts the Rust core.

The platform bridge follows a small, measurable lifecycle:

Rust send queue     Platform bridge       Reticulum stack
      │                    │                      │
      │ get next message   │                      │
      ├───────────────────►│ send                │
      │                    ├─────────────────────►│
      │                    │ delivery outcome     │
      │ confirm or fail    │◄─────────────────────┤
      │◄───────────────────┤                      │
      │                    │ incoming bytes       │
      │◄───────────────────┴──────────────────────┤

At the API boundary, those steps map to reticulumGetNextMessage(), reticulumConfirmSent(messageId), reticulumSendFailed(messageId), and reticulumDataReceivedFrom(data, peerId). Unconfirmed sends expire after 120 seconds and become transport failures that DORS can act on.

Nostr adds a decentralized relay path

Nostr begins from a different condition. A device can reach the internet, but the application’s ordinary endpoint may be unavailable, blocked, overloaded, or simply the wrong dependency for a resilient peer workflow. Nostr replaces one required service with a network of independently operated relays that accept and forward signed events over WebSockets.

For the Mesh SDK, that creates a widely reachable path with relay diversity built into its topology. Applications can select relays appropriate to their users and environment, move between them without changing the Offline Protocol message format, and retain the same identity, retry, deduplication, and routing behavior used by the other transports. Mobile integrations use the platform networking stack so WebSocket connections follow the lifecycle expectations of iOS and Android rather than hiding those responsibilities inside a portable core.

┌──────────────────────────┐
│ Rust NostrTransport      │
│ seal | sign | queue      │
│ confirmations | queries  │
└────────────┬─────────────┘
             │ UniFFI
┌────────────▼─────────────┐
│ Platform NostrManager    │
│ WebSocket pool           │
│ REQ subscriptions        │
│ OK and EOSE correlation  │
└────────────┬─────────────┘
             │ wss://
┌────────────▼─────────────┐
│ Independent Nostr relays │
└──────────────────────────┘

Messages sent through the Nostr transport are sealed as NIP-59 gift wraps with NIP-44 v2 encryption. The public event contains a standard gift-wrap kind, a fresh single-use public key, an opaque recipient routing tag, a timestamp shifted into the recent past, and encrypted padded content. The Offline Protocol envelope, application metadata, message type, priority, hop state, and stable sender identity remain inside the sealed payload.

[
  "EVENT",
  {
    "kind": 1059,
    "pubkey": "<fresh single-use public key>",
    "tags": [["p", "<recipient routing tag>"]],
    "created_at": "<jittered into the past>",
    "content": "<NIP-44 v2 ciphertext>"
  }
]

The implementation deliberately separates three cryptographic jobs. A routing tag derived from the recipient’s self-certifying Offline Protocol address identifies the inbox a device monitors. A record-seal key uses a separate derivation context to protect bootstrap frames and published key-package records. A signing key derived from a per-install random secret signs addressable records and other stable Nostr events, while each NIP-59 wrapper uses a fresh single-use author key. Offline Protocol identity and message authentication remain inside the sealed protocol layer.

ValueDerived fromWho can compute itPurpose
Routing tagSHA-256(address)Anyone holding the addressPublic rendezvous label only
Record-seal keyDomain-separated HKDF over the addressAnyone holding the addressSeals bootstrap frames and published records
Install signing keyDomain-separated HKDF over a random per-install secretOnly that installationSigns stable Nostr records and events

The routing API accepts a parsed Address rather than an arbitrary string:

pub fn routing_tag_for_address(address: &Address) -> Result<String>

That signature turns the correct input into a compiler-enforced property instead of a convention every caller must remember.

The latest transport also supports cold first contact. With coldContactEnabled, an installation maintains five single-use MLS key packages as sealed NIP-33 addressable events and queries a peer’s records across every connected relay. A peer known by address can therefore establish an encrypted session over Nostr without first exchanging key material over Bluetooth, Wi-Fi Direct, or the ordinary internet transport. Human-readable username discovery is a separate, default-off feature because it publishes a discoverable name-to-address claim; when enabled, resolution returns the complete verified claimant set rather than pretending the directory is authoritative.

Sealing substantially reduces what a relay can learn from stored events and broad event scraping. A relay still observes the connection subscribing to a routing tag, along with traffic timing and volume, so relay selection remains part of an application’s threat model. That boundary is documented once and clearly, while the transport focuses on the practical improvement: decentralized reach without exposing the Offline Protocol message envelope to the relay carrying it.

A transport layer that reflects the real world

Reticulum and Nostr make the SDK more capable because they introduce genuinely different network properties, not simply two more names in a transport list.

ReticulumNostr
Extends the SDK intoLong-range and infrastructure-sparse environmentsDecentralized relay infrastructure across reachable internet paths
Network surfacesLoRa, serial, TCP, UDP, I2P, and other Reticulum interfacesWebSockets to independently operated relays
Routing priorityReliability, reach, energy, and message suitabilityRelay availability, delivery behavior, congestion, and application policy
Confirmation window120 seconds30 seconds
Strongest fitRemote, off-grid, disaster-response, and sparse infrastructureResilient relay routing when one application endpoint is not enough

The default DORS tie-break order remains conservative: internet, Wi-Fi Direct, Bluetooth LE, Reticulum, then Nostr. That order gives established direct paths priority when scores are otherwise equal. It does not lock an application into that sequence. Reticulum or Nostr moves ahead whenever observed conditions and application policy make it the better route.

Production details matter here because routing quality depends on honest measurements. Contact-record publishing is separated from message-delivery health so housekeeping cannot distort reliability. Receive watermarks reject future-dated events before persisting progress. Nostr payload limits are measured after sealing and serialization, when encryption, padding, and event encoding have produced the bytes a relay will actually receive. Pending confirmations expire into measurable outcomes rather than leaving the selector with an unrealistically healthy view of a stalled path.

Together, these choices create a transport layer that can adapt without making the application reinvent its communication model. A system can use Bluetooth LE for immediate nearby exchange, Wi-Fi Direct when greater local capacity is available, internet for ordinary backhaul, Reticulum when distance exceeds local-radio range, and Nostr when a decentralized relay route is the most suitable reachable path.

What developers can build with the expanded mesh

The immediate value is continuity across a wider range of environments. A field system can coordinate handhelds, sensors, vehicles, and gateways even as the available network changes across a route. Remote telemetry can move locally, remain available to nearby operators, and continue upstream when an appropriate backhaul path becomes available. Disaster-response teams can combine short-range phone radios with longer-range Reticulum links rather than committing the entire deployment to one physical medium.

The same transport expansion also strengthens the SDK’s higher-level capabilities. OfflineID gives devices a stable identity they can verify without a server. Service discovery allows nearby nodes to advertise, discover, authenticate, and invoke capabilities. MLS protects encrypted sessions. Opt-in telemetry exposes protocol events and route transitions to an application-provided sink. Reticulum and Nostr extend where those primitives can operate without changing how applications reason about them.

That matters as more computation moves into phones, vehicles, robots, gateways, and on-device models. These systems need to discover peers, verify identity, exchange data, invoke local capabilities, and coordinate decisions across networks that change underneath them. Some interactions belong on a nearby radio. Some need long-range low-bandwidth delivery. Some benefit from a decentralized relay path. Others should continue to the cloud or an enterprise system when the route is available. One coordination layer lets the application make those distinctions without becoming five separate networking products.

Connectivity is not a boolean. The transport layer should not behave as if it is.

Building the next paths in the open

Reticulum and Nostr demonstrate the transport architecture we want to keep expanding. A transport adapter contributes real reach, measurable behavior, and a clear operating model. The core contributes consistent identity, routing, reliability, security, observability, and application policy across every path.

Open source makes the choices inside that system inspectable. Reticulum operators can challenge our assumptions about radio performance. Nostr developers can review the sealing and relay model. Mobile engineers can improve platform lifecycle behavior. Application teams can test routing policy against the exact devices, failure conditions, and infrastructure constraints they expect in production.

This is how the coordination layer becomes useful beyond the environments we already understand. Not by claiming that one radio or relay network solves every form of disconnection, but by giving developers a common surface for combining the paths their systems actually need.

Explore the implementation

Read the Reticulum transport documentation, the Nostr transport documentation, or inspect the complete Offline Protocol Mesh SDK on GitHub.

Install the React Native package:

npm install @offline-protocol/mesh-sdk

If you are building with long-range radios, decentralized relays, remote telemetry, field operations, or another environment where the network cannot be treated as fixed, build with the SDK or talk to us about how Offline Protocol can support your product and deployment. We are opening a limited number of design-partner engagements for teams ready to test these paths in real operating conditions.

Gokul Santhosh
Gokul Santhosh
CTO, Offline Protocol

Gokul is the CTO of Offline Protocol. He came to the disconnected edge through more than half a decade across infrastructure protocols, distributed systems, and developer tooling, where systems that cannot rely on a central server force you to get the fundamentals right: state that syncs eventually, identity that proves itself locally, transport that finds a path.

Much of that philosophy took shape in his open-source work, mostly Rust developer tools like wrkflw, Snipt, and Feedr that have earned thousands of stars, and the same open, verifiable ethos runs through everything he ships. Off the keyboard he is usually rock climbing, on a motorcycle, or backpacking somewhere with no signal, which is probably not a coincidence.

More posts
Announcement · Aug 13, 2026

Open sourcing the coordination layer for the disconnected edge