# BitChat BLE Transport Architecture V3: Four-Layer Stack Explained

> Explore the BitChat BLE transport architecture V3. Understand the four isolated layers BLELinkLayer, Mesh Engine, Feature Modules, and App Boundary for deadlock-free operation.

- Repository: [permissionlesstech/bitchat](https://github.com/permissionlesstech/bitchat)
- Tags: architecture
- Published: 2026-08-19

---

**The BitChat BLE transport architecture V3 is a four-layer packet-radio stack composed of the BLELinkLayer, Mesh Engine, Feature Modules, and App Boundary, each isolated to specific serial queues to guarantee deadlock-free operation.**

The BitChat BLE transport architecture V3, documented in [`docs/BLE-ARCHITECTURE-V3.md`](https://github.com/permissionlesstech/bitchat/blob/main/docs/BLE-ARCHITECTURE-V3.md) inside the `permissionlesstech/bitchat` repository, restructures Bluetooth Low Energy messaging into a strictly layered, queue-isolated stack. This design replaces the previous monolithic transport with clearly separated responsibilities that scale from low-level radio control up to application-facing protocols.

## BLELinkLayer: The CoreBluetooth Radio Interface

The **BLELinkLayer** manages the direct CoreBluetooth interface and is the only component that touches the iOS Bluetooth stack. Its responsibilities include scanning and advertising, connection scheduling, MTU negotiation, and managing write and notification back-pressure buffers. It also handles link-state restoration and isolates all of this state on a dedicated BLE serial queue.

This layer communicates upward by emitting `LinkEvent` objects and downward by receiving `LinkCommand` instructions. In [`bitchat/BLELinkLayer.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/BLELinkLayer.swift), the `BLELinkLayer` type enforces that every buffer mutation occurs on `bleQueue`. For unit testing, the stack provides a `SimulatedLinkLayer` that mimics the same interface without hardware.

```swift
// Create a command to write bytes on the BLE link
let cmd = LinkCommand.send(data: payload, to: linkID)

// Dispatch the command on the BLE queue – the only place that can touch the link buffers
BLELinkLayer.shared.dispatch(command: cmd)

```

## Mesh Engine: The Protocol Heart

The **Mesh Engine** sits directly above the link layer and functions as the core of the BitChat BLE transport architecture V3. It owns a single serial queue (`mesh.message`) that holds all mesh-level state, including the packet codec, fragmentation, deduplication, relay policy, peer registry, topology, gossip sync, and Noise orchestration. All engine logic runs as synchronous single-writer code, which eliminates data races without locks.

The central entry point is implemented in [`bitchat/BLEMeshEngine.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/BLEMeshEngine.swift) as a synchronous handler with the signature `handle(event, now) -> [Effect]` that produces deterministic outputs. Supporting stores such as `BLEPeerRegistryStore`, defined in [`bitchat/BLEPeerRegistryStore.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/BLEPeerRegistryStore.swift), provide lock-backed state that the engine and transport layers share safely.

```swift
func handleLinkEvent(_ event: BLELinkEvent) {
    // Engine-confined entry point
    onEngine { engine in
        engine.ingestDecodedPacket(event.packet, from: event.linkID)
    }
}

```

## Feature Modules: Extensible Functional Components

**Feature Modules** represent individual capabilities within the BitChat BLE transport architecture V3. Each module owns its internal state and registers for the specific message types it handles, so adding a new capability requires creating a new module rather than modifying the engine core. Current modules include courier, board, pre-keys, private-media, file transfer, voice, diagnostics, groups, and verification or vouch logic.

Because module state lives on the same engine serial queue, they interact with the mesh through defined ports without introducing cross-thread chatter. Concrete examples include `BLEMeshPingTracker` and `BLEPrivateMediaSessionStore`.

```swift
final class StickerModule: FeatureModule {
    private var stickers = [Sticker]()
    
    init(engine: MeshEngine) {
        engine.register(messageType: .sticker, handler: self.handleSticker)
    }

    private func handleSticker(_ payload: Data) {
        // Process on the engine queue
        onEngine { _ in
            // … update stickers …
        }
    }
}

```

## App Boundary: The Transport Façade

The **App Boundary**, also referred to as the Transport Core, is a thin façade that insulates the rest of the application from the complexity of the underlying stack. It exposes a small `Transport` protocol in [`bitchat/Transport.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Transport.swift) that covers lifecycle, identity, snapshots, basic messaging, and Noise wrappers.

Capability protocols are discovered dynamically via `as?` casting. For example, the app can check for `MeshBridgingTransport` or `PanicResettingTransport` without depending on a monolithic god-protocol. This layer is main-thread and transport-confined; it calls into the engine through `onEngine` and never synchronously dispatches to the BLE queue.

```swift
if let meshTransport = transport as? MeshBridgingTransport {
    meshTransport.sendMessage(to: peerID, payload: data)
}

```

## Concurrency Contract and Deadlock Prevention

The BitChat BLE transport architecture V3 enforces a strict directional concurrency contract across all four layers. Data and commands always flow from the **main or test threads** into the **engine queue**, then into the **BLE queue**, and optionally into **crypto queues**. The stack never allows reverse-direction synchronous calls.

This unidirectional design guarantees deadlock-free operation because no lower layer can block waiting for a higher layer. [`BLELinkLayer.swift`](https://github.com/permissionlesstech/bitchat/blob/main/BLELinkLayer.swift) stays confined to `bleQueue`, [`BLEMeshEngine.swift`](https://github.com/permissionlesstech/bitchat/blob/main/BLEMeshEngine.swift) stays confined to `mesh.message`, and the app boundary stays on the main thread.

## Summary

- The **BLELinkLayer** owns the CoreBluetooth interface and all radio-level buffers on `bleQueue`.
- The **Mesh Engine** executes all protocol logic—codec, deduplication, Noise, and topology—on a single serial queue via synchronous handlers.
- **Feature Modules** extend functionality by registering for message types without modifying engine code.
- The **App Boundary** exposes a minimal `Transport` protocol and discovers capabilities like `MeshBridgingTransport` through casting.
- A **unidirectional concurrency contract** ensures main → engine → BLE → crypto queue ordering, preventing deadlocks.

## Frequently Asked Questions

### What are the four layers in the BitChat BLE transport architecture V3?

The four layers are the **BLELinkLayer**, the **Mesh Engine**, the **Feature Modules**, and the **App Boundary (Transport Core)**. Each layer has a single responsibility and is confined to its own serial queue or thread context.

### How does the BitChat V3 stack prevent deadlocks?

The architecture enforces a unidirectional concurrency contract where calls flow from the main thread to the engine queue, then to the BLE queue, and finally to optional crypto queues. Because lower layers never synchronously call upward, circular waits are impossible.

### What is the role of the Mesh Engine in BitChat BLE transport?

The **Mesh Engine** is the protocol heart that owns packet codec, fragmentation, deduplication, relay policy, peer registry, and Noise orchestration. It runs all logic on a dedicated serial queue and exposes a synchronous `handle(event, now) -> [Effect]` interface in [`BLEMeshEngine.swift`](https://github.com/permissionlesstech/bitchat/blob/main/BLEMeshEngine.swift).

### How do you add a new feature to BitChat without changing the engine?

You create a new **Feature Module** that conforms to the module interface, owns its own state, and registers for the message types it handles with the engine. The engine does not need modification, as demonstrated by existing modules like `BLEMeshPingTracker` and `BLEPrivateMediaSessionStore`.