# How BitChat's BLE Mesh Network Enables Offline Communication

> Discover how BitChat's BLE mesh network acts as a store-and-forward packet radio, enabling seamless offline communication by storing and delivering messages when users reconnect.

- Repository: [permissionlesstech/bitchat](https://github.com/permissionlesstech/bitchat)
- Tags: deep-dive
- Published: 2026-08-22

---

**BitChat implements a Bluetooth Low Energy mesh network that functions as a store-and-forward packet radio system, allowing messages to be stored locally and delivered when recipients reconnect.**

BitChat, an open-source messaging application developed by permissionlesstech, leverages a custom BLE mesh network to enable communication without internet connectivity. This article explains how the mesh architecture processes, routes, and stores messages for offline delivery using the Swift implementation found in the [permissionlesstech/bitchat](https://github.com/permissionlesstech/bitchat) repository.

## BitChat BLE Mesh Architecture

The BitChat BLE mesh network is organized into a four-layer architecture that separates concerns between radio hardware, protocol logic, feature modules, and the application interface.

### Four-Layer Stack

- **BLE Link Layer**: Handles direct CoreBluetooth interaction including scanning, advertising, connection scheduling, and MTU management. Key implementations include `BLELinkStateStore` and `BLERadioController` in [`bitchat/Services/BLE/BLERadioController.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Services/BLE/BLERadioController.swift).

- **Mesh Engine**: Contains the serial-queue core that owns all protocol state including packet codecs, fragmentation, deduplication, and relay policies. This layer implements the primary `handle(event) -> [Effect]` loop in `BLEService` located at [`bitchat/Services/BLE/BLEService.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Services/BLE/BLEService.swift), utilizing helpers like `BLEFragmentAssemblyBuffer` and `BLEMeshPingTracker`.

- **Feature Modules**: Encapsulate specific capabilities such as courier services, message boards, and file transfer. Each module owns its state independently and registers for specific packet types without accessing engine internals. Examples include `CourierStore`, `BoardStore`, and `PrekeyBundleStore`.

- **App Boundary**: Provides a thin `Transport` façade that the UI consumes through `Transport` protocol extensions on `BLEService`. This layer handles capability discovery and forwards high-level events to view models while abstracting mesh complexity.

## Store-and-Forward Flow for Offline Communication

When a recipient device is unreachable, BitChat's mesh engine queues messages in the `CourierStore`, creating a store-and-forward system that functions similarly to packet radio networks.

### Message Transmission Pipeline

1. **Message Creation**: The UI invokes `sendMessage(to:payload:ttl:completion:)` on the `Transport` protocol, which is implemented by `BLEService`.

2. **Fragmentation**: Payloads exceeding the BLE MTU are split by `BLEFragmentAssemblyBuffer` into fragments queued in `BLEOutboundFragmentTransferScheduler`.

3. **Routing Decision**: The engine selects a next-hop based on `MeshTopologyTracker` and gossip policy thresholds. If the destination peer is unreachable, the packet routes to `CourierStore` for offline storage.

4. **Encryption**: Each fragment receives Noise protocol encryption via `NoiseSessionManager`, binding the fragment to the specific physical link that authenticated it through `BLELinkAuthState` and `BLELinkBindings`.

5. **Transmission**: `BLELinkLayer` writes bytes to BLE peripherals or centrals, respecting back-pressure buffers including `pendingPeripheralWrites` and `pendingNotifications`.

6. **Reception**: Remote devices receive fragments through the link layer, which hands raw bytes to the engine's `ingestDecodedPacket` method for reassembly and Noise tag validation.

7. **Delivery or Storage**: If the destination is online, the engine forwards the complete packet to feature modules via `BitchatDelegate`. If offline, the envelope persists in `CourierStore`—a lock-backed, main-actor cache that respects per-peer quotas defined by `CourierDepositTier` until the recipient reconnects.

## Key Source Files and Components

Understanding the implementation requires familiarity with these specific files in the repository:

- [`bitchat/Services/BLE/BLEService.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Services/BLE/BLEService.swift): Central class implementing the mesh engine queue, peer registry, link state management, and courier store integration.

- [`bitchat/Services/BLE/BLERadioController.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Services/BLE/BLERadioController.swift): Implements the link layer that emits `LinkEvent` objects and consumes `LinkCommand` objects while managing CoreBluetooth interactions.

- [`bitchat/Services/BLE/BLELinkStateStore.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Services/BLE/BLELinkStateStore.swift): Maintains per-link connection states and back-pressure buffers for unreliable link management.

- [`bitchat/Services/BLE/BLEFragmentAssemblyBuffer.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Services/BLE/BLEFragmentAssemblyBuffer.swift): Handles packet fragmentation and reassembly when payloads exceed BLE MTU limitations.

- [`bitchat/Services/Courier/CourierStore.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Services/Courier/CourierStore.swift): Persistent store-and-forward cache enabling offline message retention with quota management.

- [`docs/BLE-ARCHITECTURE-V3.md`](https://github.com/permissionlesstech/bitchat/blob/main/docs/BLE-ARCHITECTURE-V3.md): Design document detailing the layered stack, concurrency contracts, and mesh topology algorithms.

## Practical Implementation Examples

### Sending an Offline-Capable Message

To send a message that will be stored for offline delivery if necessary:

```swift
// Transport is a BLEService instance conforming to the Transport protocol
let transport: Transport = bleService
let payload = "Hello offline world!".data(using: .utf8)!

transport.sendMessage(
    to: .broadcast,
    payload: payload,
    ttl: TransportConfig.messageTTLDefault
) { result in
    switch result {
    case .success:
        print("Queued for mesh delivery or offline storage")
    case .failure(let error):
        print("Transmission failed: \(error)")
    }
}

```

This call traverses `BLEService` into `BLEOutboundFragmentTransferScheduler`, then `BLELinkLayer`. If no peers accept the packet, the engine stores it in `CourierStore` as implemented in `BLEService` around lines 258-260.

### Receiving Messages via Delegate

Implement `BitchatDelegate` to handle incoming messages after the mesh engine verifies and reassembles them:

```swift
class ChatViewModel: BitchatDelegate {
    func didReceivePublicMessage(_ packet: BitchatPacket) {
        // Update UI with verified payload
        displayMessage(packet.payload)
    }
}

// Assign delegate to receive events exclusively through this interface
bleService.delegate = self

```

The delegate receives packets only after the engine successfully validates Noise tags and reassembles fragments via `BLEFragmentAssemblyBuffer`.

### Accessing Offline Storage

When a peer reconnects, retrieve and attempt delivery of stored messages:

```swift
func handlePeerConnected(_ peerID: PeerID) {
    let pendingEnvelopes = CourierStore.shared.envelopesForPeer(peerID)
    
    pendingEnvelopes.forEach { envelope in
        bleService.tryDeliver(envelope)
    }
    
    CourierStore.shared.removeDelivered(envelopes: pendingEnvelopes)
}

```

`CourierStore` enforces `CourierDepositTier` quotas and provides lock-backed access suitable for main-actor consumption without blocking the mesh engine.

## Concurrency and Safety Architecture

The mesh engine guarantees thread safety through strict queue separation. The **engine queue operates serially**, ensuring all state mutations—including peer registry updates, routing table changes, and Noise session management—occur without locks, preventing deadlocks. The **link-layer queue** handles only I/O operations and never touches engine state, maintaining a one-way synchronization edge from `main` to `engine` to `bleQueue` as documented in [`BLE-ARCHITECTURE-V3.md`](https://github.com/permissionlesstech/bitchat/blob/main/BLE-ARCHITECTURE-V3.md).

## Deterministic Simulation and Testing

BitChat validates its offline logic through `SimulatedLinkLayer`, allowing the mesh engine to run off-device. The test suite in [`bitchatTests/Simulation/SimulatedMesh.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitchatTests/Simulation/SimulatedMesh.swift) drives the identical code paths used in production without real radios, proving that store-and-forward logic functions correctly even when devices remain out of range for extended periods.

## Summary

- BitChat implements a **four-layer BLE mesh architecture** separating radio hardware from protocol logic and application interfaces.
- **Offline communication** works via `CourierStore`, a persistent cache that retains messages when recipients are unreachable and delivers them upon reconnection.
- **Fragmentation and encryption** occur at the mesh engine layer using `BLEFragmentAssemblyBuffer` and `NoiseSessionManager`, ensuring data integrity across multiple hops.
- **Strict concurrency controls** use serial queues to eliminate deadlocks while maintaining high-throughput packet processing.
- **Comprehensive simulation** via `SimulatedMesh` validates offline behavior without hardware dependencies.

## Frequently Asked Questions

### How does BitChat handle message delivery when the recipient is completely out of range?

When the recipient is unreachable, the mesh engine stores the message in `CourierStore`, a lock-backed cache that persists envelopes until the destination peer reconnects. The store enforces per-peer quotas through `CourierDepositTier` to prevent resource exhaustion, ensuring messages survive temporary network partitions.

### What encryption does BitChat use for mesh messages?

BitChat implements the Noise protocol through `NoiseSessionManager`, binding each packet fragment to the specific authenticated link that transmitted it. This link-bound encryption in `BLELinkAuthState` ensures fragments are only accepted on the physical link that originally authenticated them, preventing interception on alternate paths.

### Can BitChat's mesh network simulate offline scenarios for testing?

Yes, the codebase includes `SimulatedLinkLayer` and `SimulatedMesh` in the test suite, which execute the identical mesh engine logic without hardware. These simulations validate store-and-forward behavior, fragmentation, and routing decisions in deterministic environments where devices are programmatically taken offline and brought back online.

### What is the maximum message size supported by the BLE mesh?

The mesh handles payloads exceeding standard BLE MTU through `BLEFragmentAssemblyBuffer`, which automatically fragments large messages and reassembles them at the destination. While specific size limits depend on available `CourierStore` quota and memory constraints, the fragmentation layer abstracts MTU limitations from the application layer.