Skip to main content

Quick Start

Basic Setup

Register your event listeners synchronously, right after construction. The SDK subscribes to native events inside its own constructor, so events can arrive before your handlers are attached. Only two event types are held and replayed for a late listener (internet_session_superseded and mesh_stopped_by_user); everything else is dropped when unlistened.

Your address

The device’s identity is not something your app chooses. The SDK mints an Ed25519 identity key on first run and derives a self-certifying off1… address from it. Peers verify an address by re-deriving it from the key its owner presents.
It is null until startup completes, because the key lives in storage that is not open before then. The identity_ready event carries the same value the moment it becomes known. profile is a separate thing: it selects which stored identity this instance runs as, and it never leaves the device.

Identity & Addressing

How addressing works, how to reach a peer, and how to migrate from userId.

Advanced Configuration

See the Configuration reference for every option.

Protocol Lifecycle

Complete Flow Example

ProtocolState is a string enum ("Stopped", "Running", "Paused"). It held numeric values through v0.19.0, so state === ProtocolState.Running now works where it previously could never be true. If your app persisted a ProtocolState itself, the old numeric value matches nothing, so treat an unrecognized persisted value as Stopped.

Event Sequence Timeline

What Happens Under the Hood

On protocol.start()

  1. Native protocol is created (lazily; the constructor does not create it)
  2. MLS initializes against iOS Keychain / Android EncryptedSharedPreferences, before transports start, so a peer can never be discovered before key exchange is possible
  3. identity_ready fires with this device’s off1… address
  4. BLE Manager initializes, scanning for the Offline Protocol service UUID, and advertising this device with mesh metadata (degree, free slots, battery, uptime)
  5. Configured transports auto-enable: internet, Nostr, and Reticulum
start() throws if the protocol is already started.

On Peer Discovery

  1. BLE scan detects an advertisement from another device
  2. MeshController evaluates the candidate: connection budget (default max 4), peer score (RSSI, availability, battery, uptime, stability, load), and whether this is a cluster bridge opportunity
  3. If accepted, the BLE connection is established and neighbor_discovered fires with the peer’s canonical off1… address as peer_id
  4. If at capacity, a lower-scoring peer may be evicted to make room

On protocol.sendMessage()

  1. Message created with a unique ID, TTL, timestamp, and priority
  2. message_sent fires immediately
  3. DORS selects a transport across BLE, Wi-Fi Direct, Internet, Reticulum, and Nostr
  4. ACK tracking begins
  5. On ACK, message_delivered fires
  6. On a failed attempt, message_retrying fires with the scheduled retry time
  7. If no transport is available, message_deferred fires and the message is persisted to the outbox
  8. If the relay reports the recipient unreachable, message_undeliverable fires and the message is parked. This repeats on an escalating probe and is not terminal
  9. Only message_failed is terminal

On protocol.stop()

  1. BLE scanning and advertising stop
  2. All peer connections close
  3. neighbor_lost fires for each disconnected peer
  4. The protocol core stops

Diagnostic Events

Next Steps

Explore the configuration reference