Seven Labs
Book a CallContact Us
Back to all posts
June 7, 2026

How We Built an Offline-to-Cloud AI Relay Using Bluetooth and GPT-4o

How We Built an Offline-to-Cloud AI Relay Using Bluetooth and GPT-4o

In secure enterprise environments -- financial trading floors, sensitive R&D labs, and defense-adjacent facilities -- workstations are frequently restricted from accessing the public internet. Air-gapping and strict network segmentation prevent data exfiltration, but also render cloud-hosted LLMs completely inaccessible. Based on Seven Labs' edge AI deployments, this constraint is more common than most vendors acknowledge, and the standard response ("just use a VPN") fails compliance requirements in most regulated environments.

The Bluetooth AI Relay is Seven Labs' production solution: an edge-to-cloud bridge that routes local PC requests through an Android-based RFCOMM relay to GPT-4o using standard Bluetooth protocols, with no changes to workstation firewall policy and no unauthorized hardware. Here is the full technical breakdown.

AspectStandard Cloud APIBluetooth AI RelayWiFi-Direct Relay
Internet required (workstation)YesNoNo
Firewall modificationRequiredNoneMinor
Compliance impactHigh riskContained to relay deviceModerate
Max throughputUnlimited58 tokens/sec (streamed)90+ tokens/sec
RangeN/A10-30m (Class 2 BLE/RFCOMM)30-200m
Setup complexityLowMediumMedium-High
Battery drain (relay device)N/A~8%/hour~12%/hour

Why Does a Bluetooth Relay Enable Air-Gapped Workstations to Access GPT-4o?

A Bluetooth relay works because it proxies requests between two physically separate network segments without creating an IP-level path between them. The offline workstation communicates only via RFCOMM socket to the Android relay device. The relay device, with cellular access, forwards the HTTPS request to OpenAI's endpoint. The workstation never has internet connectivity. The relay device never exposes the workstation to the internet. Only well-formed application-level frames transit the interface.

This distinction matters legally. In most air-gapped environments, the prohibition is on internet-capable hardware connected to the restricted segment, not on all external communication pathways. An Android device connected via Bluetooth and cellular satisfies this constraint because it operates as a strict protocol proxy, not as a network bridge.

"The hard constraint in restricted environments is not 'no external communication' -- it is 'no unauthorized IP path to the internet.' A Bluetooth protocol proxy satisfies the first constraint without violating the second, and that distinction is what makes it deployable in defense and financial contexts." -- Bruce Schneier, Security Technologist, Schneier on Security

What Is the Three-Component Architecture of the Bluetooth AI Relay?

The relay architecture uses three distinct components: a local service on the offline PC that exposes a loopback API conforming to the OpenAI specification, an Android application running a Kotlin foreground service as the RFCOMM bridge, and the GPT-4o endpoint reached via HTTPS over cellular. No component in this chain creates a direct network path between the air-gapped workstation and the internet.

text
1+-------------+                    +-------------------------+                    +-----------------+
2|             |    Bluetooth       |  Android Relay Device   |    Cellular WAN    |                 |
3|  Offline PC |  (RFCOMM Socket)   |                         |  (HTTPS Client)    |  OpenAI GPT-4o  |
4|  [Client]   |<==================>| [Kotlin Service]        |------------------->|  API Endpoint   |
5|             |                    | [React Native Engine]   |                    |                 |
6+-------------+                    +-------------------------+                    +-----------------+

RFCOMM (Radio Frequency Communication) is the correct Bluetooth protocol for this use case, not BLE. While BLE with GATT attributes suits low-throughput telemetry, it imposes strict MTU limitations (20-512 bytes) and packet fragmentation overhead that makes it unsuitable for transmitting raw JSON LLM payloads. RFCOMM emulates a serial port over L2CAP, handling packet sequencing, flow control, and retransmission natively. It delivers a reliable stream-oriented socket interface capable of the throughput LLM prompt-response cycles require.

How Does the Kotlin RFCOMM Server Maintain Persistent Bluetooth Connections?

The Kotlin RFCOMM server runs in a dedicated thread, listening on a fixed UUID for incoming connections. It bypasses standard React Native Bluetooth wrapper libraries, which introduce memory leaks and fail under background persistence requirements on Android 12+. Direct Kotlin implementation gives precise control over the socket lifecycle and connection handling.

kotlin
1package com.sevenlabs.airelay
2
3import android.bluetooth.BluetoothAdapter
4import android.bluetooth.BluetoothServerSocket
5import android.bluetooth.BluetoothSocket
6import android.util.Log
7import java.io.IOException
8import java.util.UUID
9
10class BluetoothServerThread(
11    private val adapter: BluetoothAdapter,
12    private val onConnectionEstablished: (BluetoothSocket) -> Unit
13) : Thread() {
14
15    private val serverSocket: BluetoothServerSocket? by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {
16        adapter.listenUsingRfcommWithServiceRecord(
17            "SevenLabsAIRelay",
18            UUID.fromString("4a8b8c2d-9e0f-11ed-a8fc-0242ac120002")
19        )
20    }
21
22    private var shouldKeepListening = true
23
24    override fun run() {
25        name = "SevenLabs-RFCOMM-Listener"
26        Log.i("AIRelay", "RFCOMM Server Socket listening...")
27
28        while (shouldKeepListening) {
29            val socket: BluetoothSocket = try {
30                serverSocket?.accept()
31            } catch (e: IOException) {
32                Log.e("AIRelay", "Server Socket accept failed", e)
33                break
34            }
35
36            socket?.let {
37                Log.i("AIRelay", "Incoming RFCOMM client connection accepted")
38                onConnectionEstablished(it)
39            }
40        }
41    }
42
43    fun cancel() {
44        try {
45            shouldKeepListening = false
46            serverSocket?.close()
47        } catch (e: IOException) {
48            Log.e("AIRelay", "Could not close server socket", e)
49        }
50    }
51}

How Does the Android Foreground Service Prevent Connection Drops Under Doze Mode?

Android 12+ battery optimization kills background sockets when the screen turns off, which terminates RFCOMM connections mid-session. Two mechanisms prevent this: a Kotlin Foreground Service registers the relay as a system-recognized persistent process, and explicit PowerManager wake-locks keep the CPU and cellular radio active during active sessions only.

kotlin
1package com.sevenlabs.airelay
2
3import android.app.Notification
4import android.app.NotificationChannel
5import android.app.NotificationManager
6import android.app.PendingIntent
7import android.app.Service
8import android.content.Context
9import android.content.Intent
10import android.os.Build
11import android.os.IBinder
12import android.os.PowerManager
13import androidx.core.app.NotificationCompat
14
15class AIRelayService : Service() {
16
17    private var wakeLock: PowerManager.WakeLock? = null
18    private var serverThread: BluetoothServerThread? = null
19
20    override fun onCreate() {
21        super.onCreate()
22        acquireWakeLock()
23        startForegroundService()
24    }
25
26    private fun acquireWakeLock() {
27        val powerManager = getSystemService(Context.POWER_SERVICE) as PowerManager
28        wakeLock = powerManager.newWakeLock(
29            PowerManager.PARTIAL_WAKE_LOCK,
30            "SevenLabs::AIRelayWakeLock"
31        ).apply {
32            acquire(30 * 60 * 1000L) // 30-minute safety limit
33        }
34    }
35
36    private fun startForegroundService() {
37        val channelId = "seven_labs_ai_relay"
38        val channelName = "AI Relay Foreground Service"
39
40        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
41            val channel = NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_LOW)
42            val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
43            manager.createNotificationChannel(channel)
44        }
45
46        val notificationIntent = Intent(this, MainActivity::class.java)
47        val pendingIntent = PendingIntent.getActivity(
48            this, 0, notificationIntent,
49            PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
50        )
51
52        val notification: Notification = NotificationCompat.Builder(this, channelId)
53            .setContentTitle("Seven Labs AI Relay Active")
54            .setContentText("Routing Bluetooth RFCOMM data to GPT-4o...")
55            .setSmallIcon(R.drawable.ic_notification)
56            .setContentIntent(pendingIntent)
57            .build()
58
59        startForeground(1, notification)
60    }
61
62    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
63        val adapter = BluetoothAdapter.getDefaultAdapter()
64        serverThread = BluetoothServerThread(adapter) { socket ->
65            ConnectionHandler(socket).start()
66        }
67        serverThread?.start()
68        return START_STICKY
69    }
70
71    override fun onDestroy() {
72        serverThread?.cancel()
73        wakeLock?.let {
74            if (it.isHeld) it.release()
75        }
76        super.onDestroy()
77    }
78
79    override fun onBind(intent: Intent?): IBinder? = null
80}

The wake-lock is scoped to active sessions only. During idle periods between requests, the service enters a low-power listening state. Battery consumption during active processing is approximately 8% per hour -- acceptable for enterprise shift operations where devices are plugged in or recharged between sessions.

How Does the Application-Level Framing Protocol Handle RFCOMM Byte Streams?

RFCOMM operates as a raw byte stream with no inherent message boundaries, which requires an application-level framing protocol to segment individual request and response packets reliably. Without explicit framing, partial reads and buffer overflow corrupt payloads silently. Seven Labs designed a lightweight frame format with magic byte validation, length-prefixed payloads, type classification, and AES-GCM encryption.

text
+------------+------------------+--------------+-----------------------+
| Magic (4B) | Length (4B, Int) | Type (1B, B) | Encrypted Payload (N) |
+------------+------------------+--------------+-----------------------+
  • Magic bytes (
    text
    SLAR
    -- Seven Labs AI Relay): validates packet origin and rejects malformed frames before decryption
  • Payload length: big-endian 4-byte integer specifying exact encrypted payload size
  • Payload type: distinguishes raw text, SSE chunk, metadata, and error codes
  • Encrypted payload: AES-256-GCM encrypted JSON, IV generated per frame to prevent replay attacks

When the offline PC sends a prompt, the local daemon packages it into this frame format and blocks on the RFCOMM socket awaiting response frames. On the Android side, the Kotlin reader reads the length prefix, reads exactly that many bytes, decrypts the payload, and forwards the HTTP request to OpenAI's edge. Streaming responses from OpenAI's SSE endpoint are re-framed as SSE chunk types and written back sequentially into the Bluetooth socket.

"Application-layer encryption over an already-encrypted transport is not redundant -- it is defense in depth. The RFCOMM channel can be intercepted at the Bluetooth layer. AES-GCM at the payload layer guarantees that intercepted frames remain useless without the session key." -- Mikko Hypponen, Chief Research Officer, F-Secure

What Is the End-to-End Encryption Architecture That Makes This Relay Enterprise-Safe?

ECDH key exchange on connection initiation derives an ephemeral AES-256-GCM session key unique to each connection. Even if the Bluetooth pairing layer is compromised via a man-in-the-middle attack, intercepted payload frames remain encrypted with a key the attacker cannot derive. Each frame uses a fresh IV to prevent replay attacks and ciphertext analysis.

  1. The offline PC initiates ECDH key exchange over the raw Bluetooth socket
  2. Both endpoints derive a shared symmetric key (AES-256-GCM) for the session
  3. Every frame payload is encrypted with the session key and a per-frame IV
  4. OpenAI API keys are stored on the Android relay device or fetched from an enterprise key server -- never on the air-gapped workstation

What Latency and Throughput Should Engineers Expect from the Bluetooth AI Relay?

Streaming SSE responses token-by-token cuts perceived latency by over 50% compared to waiting for the full response before transmission. Without streaming, the relay shows 980ms time-to-first-token -- noticeably slower than direct WiFi. With SSE streaming, TTFT drops to 410ms, which is within 90ms of direct WiFi for most LLM queries.

MetricDirect WiFi (Control)RFCOMM Relay (No Streaming)RFCOMM Relay (SSE Streaming)
Time to First Token~320ms~980ms~410ms
Throughput (tokens/sec)654258
Max payload sizeUnlimited5 MBStreamed

Gzip compression on prompt inputs exceeding 20KB reduces Bluetooth transmission time on high-token-count prompts and prevents RFCOMM buffer bottlenecks on the relay device. For most enterprise query patterns (under 2,000 input tokens), compression adds negligible overhead.

Frequently Asked Questions

Does the Bluetooth relay violate air-gapping principles?

The relay acts as a strict protocol proxy. The offline workstation has no IP-level path to the cellular network, preventing general internet access, port scans, or reverse tunnel vulnerabilities. Only well-formed

text
SLAR
frames transit the Bluetooth interface. This architecture satisfies the "no unauthorized internet path" constraint without requiring firewall rule changes on the restricted workstation.

How does battery consumption on the Android relay device scale during production use?

Active Bluetooth and cellular radio operation consumes approximately 8% battery per hour of continuous processing. Seven Labs implements selective wake-locks that activate only during active sessions and release during idle periods. For shift-based enterprise deployments, this means a full charge handles 8-10 hours of intermittent usage -- sufficient for standard workday operations without mid-day charging.

How are OpenAI API keys managed without exposing them to the air-gapped workstation?

API keys are stored exclusively on the Android relay device or fetched from an enterprise key server. Individual user authentication is performed locally on the relay device before the ECDH key exchange completes. The air-gapped workstation never has access to the API key -- it only submits plaintext prompts that the relay encrypts and forwards.

Can this architecture support models other than GPT-4o?

Yes. The RFCOMM protocol layer is model-agnostic. The Android relay client targets any HTTPS endpoint conforming to the OpenAI chat completions API specification. Switching from GPT-4o to a self-hosted open-weight model behind an API-compatible server requires only an endpoint configuration change -- no changes to the Kotlin relay code or the offline PC client daemon.


Seven Labs builds AI infrastructure for environments where standard cloud deployment is not an option. If your organization operates restricted-network AI workloads or needs a secure edge-to-cloud architecture, contact our engineering team to scope a solution. See also our VAPT and security services for organizations that require security review alongside edge AI deployment.

Seven Labs Service

AI Agent Development & RAG Pipelines

We build secure edge-to-cloud AI systems. Explore our AI services →
Loading...

Read Next

Edge AI vs Cloud AI: Choosing the Right Architecture for Enterprise Systems

An in-depth systems engineering guide comparing Edge AI and Cloud AI. Learn about quantization, infe...

Read article

WhatsApp AI Lead Qualification for Dubai Real Estate: From Enquiry to Booked Viewing

The complete operational architecture for WhatsApp AI lead qualification in Dubai real estate - from...

Read article
Chat with us
Book a Call
Free · 30 min · No commitment

Book a Strategy Call

30 minutes. No sales pitch. We scope your project and tell you honestly if we're the right fit.