BLE Components in the V3 Architecture: How Bitchat Structures Its Bluetooth Stack
The Bitchat V3 BLE stack organizes functionality into four distinct layers—BLELinkLayer, Mesh Engine, Feature Modules, and App Boundary—that enforce strict concurrency contracts to eliminate deadlocks and enable deterministic mesh networking.
The permissionlesstech/bitchat repository implements a complete redesign of its Bluetooth Low Energy transport in the V3 architecture. This clean, layered approach separates radio-level operations from protocol logic, with each BLE component managing isolated state and communicating through well-defined interfaces. Understanding these boundaries is essential for developers extending the mesh protocol or optimizing connection handling.
The Four Core BLE Components
The V3 architecture divides responsibilities across four major components, each owning a distinct slice of state and behavior.
BLELinkLayer: Low-Level Radio Management
BLELinkLayer serves as the low-level link layer that directly interacts with CoreBluetooth. This component owns all scanning and advertising logic, duty-cycle scheduling, connection handling, MTU negotiation, and back-pressure buffers for writes and notifications. It also manages state restoration and communicates upward via LinkEvent and downward via LinkCommand. According to the architecture documentation, this layer confines all CoreBluetooth objects and timing-sensitive operations to the bleQueue.
Mesh Engine: Protocol State and Logic
The Mesh Engine operates as a single-writer serial queue that houses the entire mesh protocol state. It handles packet encoding and decoding, fragmentation, duplicate-packet deduplication, relay policies, and the peer registry. The engine also manages topology-gossip synchronization and Noise protocol orchestration. Pure-policy satellites plug into this engine unchanged, keeping the core free of feature-specific logic.
Feature Modules: Self-Contained Capabilities
Feature Modules represent self-contained units such as courier, board, pre-keys, private media, file transfer, voice, diagnostics, groups, and verification/vouch systems. Each module owns its own state and registers for specific message types, ensuring the engine remains free of feature-specific logic. This modularity allows new capabilities to be added without modifying the underlying mesh protocol.
App Boundary (Transport Core)
The App Boundary, also referred to as the Transport Core, acts as a small façade exposing a uniform Transport protocol to the rest of the application. It delegates concrete BLE work to the mesh engine and discovers additional capabilities through optional casting (e.g., MeshBridgingTransport, PanicResettingTransport, BluetoothStateReporting). This abstraction prevents the UI and business layers from depending on implementation details of the BLE stack.
Supporting Infrastructure and State Management
Beyond the high-level layers, several concrete BLE service files implement detailed state management responsibilities:
BLELinkStateStore.swift
BLELinkStateStore.swift stores link-layer state including queues and buffers, strictly confined to the bleQueue. This isolation ensures that CoreBluetooth callbacks never contend with protocol logic for shared mutable state.
BLELinkAuthState.swift
BLELinkAuthState.swift tracks authentication state for each link. In the V3 redesign, this state moved from the bleQueue to the engine to support atomic rebind checks during peer verification.
BLELinkBindings.swift
BLELinkBindings.swift maintains the mapping between physical links and logical peers. Like authentication state, these bindings are now owned by the serial engine rather than the link layer, enabling consistent state transitions during connection migration.
BLELinkEvent.swift and BLEEngineScheduler.swift
BLELinkEvent.swift defines the LinkEvent enum used for upward communication from the link layer to the engine, while BLEEngineScheduler.swift runs the serial engine queue and coordinates onEngine calls. The scheduler enforces the architecture's concurrency contract by ensuring all engine-confined state mutations occur on the serial queue.
Concurrency Contracts and Queue Architecture
The V3 architecture enforces a strict concurrency contract across all BLE components. Engine-confined state is mutated only on the serial engine queue, while bleQueue-confined state lives alongside CoreBluetooth objects. Lock-backed stores—such as the peer registry—provide safe cross-domain reads without blocking either queue. This design eliminates deadlocks, simplifies unit testing, and enables deterministic simulation of mesh behaviors.
Practical Implementation Examples
The following Swift snippets illustrate how V3 components interact in practice:
// Emit a link-layer event from BLELinkLayer when a packet arrives
let packet = Data(...)
let linkID = UUID()
BLEEngineScheduler.shared.emitLinkEvent(.frameDecoded(linkID: linkID, packet: packet))
// Engine-side handler processing events and routing through the mesh
BLEEngineScheduler.shared.onEngine { engine in
switch engine.handleLinkEvent(event) {
case .forward(let effect):
engine.apply(effect) // Update peer registry, schedule ack, etc.
case .drop(let reason):
break
}
}
// Access a lock-backed peer store from the main actor (read-only)
let isConnected = BLEPeerRegistryStore.shared.isPeerConnected(peerID)
// Query link authentication state (engine-owned) for a specific link
let authState = BLELinkAuthState.shared.state(for: linkID)
Summary
- BLELinkLayer manages all CoreBluetooth interactions, scanning, advertising, and connection state on the dedicated
bleQueue. - Mesh Engine processes all protocol logic—including packet fragmentation, deduplication, and peer registry updates—on a serial engine queue.
- Feature Modules register for specific message types while maintaining isolated state, preventing feature creep in the core engine.
- App Boundary exposes a clean
Transportprotocol to the application layer, delegating implementation details to the engine. - Strict concurrency contracts segregate state between the
bleQueue, serial engine queue, and lock-backed stores to prevent deadlocks.
Frequently Asked Questions
What is the role of BLELinkLayer in the V3 architecture?
BLELinkLayer is the low-level component that directly interfaces with CoreBluetooth. It manages scanning, advertising, connection establishment, MTU negotiation, and back-pressure buffers. It communicates upward to the Mesh Engine via LinkEvent enums and receives commands via LinkCommand, keeping all radio-specific logic isolated from protocol processing.
How does the Mesh Engine handle concurrent state access?
The Mesh Engine runs on a single-writer serial queue coordinated by BLEEngineScheduler.swift. All state mutations—including peer registry updates and packet processing—occur exclusively on this queue. Lock-backed stores provide thread-safe read access from other queues, ensuring the engine never blocks waiting for external locks while maintaining consistency.
What does BLELinkBindings.swift manage?
BLELinkBindings.swift maintains the mapping between physical BLE links (identified by hardware addresses or CoreBluetooth identifiers) and logical peers in the mesh network. In V3, this state moved from the link layer to the engine, enabling atomic updates when connections migrate or rebinding occurs during authentication handshakes.
How do Feature Modules communicate with the BLE stack?
Feature Modules register with the Mesh Engine to receive specific message types while maintaining their own isolated state. They do not interact directly with BLELinkLayer or the bleQueue. Instead, they send and receive data through the engine's serial queue, ensuring that feature-specific logic never interferes with low-level radio timing or connection state management.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →