12<html lang="en">3<head>4<meta charset="utf-8">5<meta name="viewport" content="width=device-width, initial-scale=1">6<title>NIP-BE - Nostr BLE Communications Protocol — Nostr Instruction Manual</title>7<meta name="description" content="NIP-BE: Nostr over Bluetooth Low Energy. GATT service, role assignment, DEFLATE batches, and half-duplex synchronization. Deprecated. Complete manual page.">8<link rel="preload" href="../assets/fonts/michroma-400-latin.woff2" as="font" type="font/woff2" crossorigin>9<link rel="preload" href="../assets/fonts/exo2-var-latin.woff2" as="font" type="font/woff2" crossorigin>10<link rel="preload" href="../assets/fonts/sairacondensed-600-latin.woff2" as="font" type="font/woff2" crossorigin>11<link rel="preload" href="../assets/fonts/sairacondensed-700-latin.woff2" as="font" type="font/woff2" crossorigin>12<link rel="preload" href="../assets/fonts/sairacondensed-500-latin.woff2" as="font" type="font/woff2" crossorigin>13<link rel="preload" href="../assets/fonts/sharetechmono-400-latin.woff2" as="font" type="font/woff2" crossorigin>14<link rel="preload" href="../assets/fonts/exo2-400i-latin.woff2" as="font" type="font/woff2" crossorigin>15<link rel="icon" href="../assets/favicon.svg" type="image/svg+xml">16<link rel="stylesheet" href="../assets/manual.css">17</head>18<body>1920<svg width="0" height="0" style="position:absolute">21 <defs>22 <marker id="arr" markerWidth="9" markerHeight="9" refX="7" refY="4.5" orient="auto">23 <path d="M1,1 L8,4.5 L1,8 Z" fill="#f26a00"/>24 </marker>25 <marker id="arrb" markerWidth="9" markerHeight="9" refX="7" refY="4.5" orient="auto">26 <path d="M1,1 L8,4.5 L1,8 Z" fill="#2e5f9e"/>27 </marker>28 </defs>29</svg>3031<div class="page">32 <span class="staple s1"></span><span class="staple s2"></span>3334 <header class="band">35 <a class="logo" href="../index.html">NOSTR<b>▸</b>PROTOCOL MANUAL</a>36 <span class="booklet-note">Chapter BE - Transport</span>37 </header>38 <nav class="tabs">39 <a href="../index.html">Contents</a>40 <a href="#overview" class="on">Overview</a>41 <a href="#spec">Spec</a>42 <a href="#examples">Examples</a>43 <a href="#history">History</a>44 </nav>4546 <div class="chapter">47 <div class="nipno" data-n="BE">BE</div>48 <div class="titles">49 <div class="kicker">Nostr Implementation Possibility - Hex № BE</div>50 <h1>Nostr BLE Communications Protocol</h1>51 <p class="sub">Run the Nostr client-relay conversation over Bluetooth Low Energy when no internet connection exists between two devices.</p>52 </div>53 <div class="stamp">Deprecated</div>54 </div>5556 <main class="spread">57 <div class="main">5859 <h2 class="bar" id="overview"><span class="num">1</span> Overview</h2>6061 <div class="box danger">62 <span class="tag">Deprecated</span>63 <p>This NIP is marked <strong>unrecommended</strong>. It was implemented only once, and it is unclear whether that implementation works. The spec requires review. No replacement NIP exists. For normal connectivity, use the WebSocket transport from <a href="01.html">NIP-01</a>.</p>64 </div>6566 <p>Nostr normally runs over WebSocket. A <strong>client</strong> connects to a <strong>relay</strong> and they exchange JSON messages. This NIP moves that same conversation onto Bluetooth Low Energy (BLE). Two nearby devices can then exchange and synchronize events with no internet at all.</p>67 <p>BLE follows a client-server pattern of its own, called GATT. This NIP maps the two models onto each other. The GATT Server plays the relay. The GATT Client plays the client. The NIP then adapts the message flow to BLE limits: tiny packets, one operation at a time, and connections that come and go.</p>68 <p>The NIP defines four things. A device advertisement, so devices can find each other. A GATT service with two characteristics, one for writes and one for reads. A batch format that compresses and splits large messages. A half-duplex workflow that synchronizes events with <a href="77.html">NIP-77</a> negentropy messages.</p>6970 <figure class="diagram">71 <div class="frame">72 <svg viewBox="0 0 560 190" role="img" aria-label="Two devices advertise over BLE, compare device UUIDs, and take the GATT Server and GATT Client roles">73 <rect class="d-actor" x="10" y="55" width="130" height="60" rx="8"/>74 <text class="d-actor-label" x="75" y="80" text-anchor="middle">Device A</text>75 <text class="d-note" x="75" y="98" text-anchor="middle">UUID C4F0…</text>76 <rect class="d-actor" x="420" y="55" width="130" height="60" rx="8"/>77 <text class="d-actor-label" x="485" y="80" text-anchor="middle">Device B</text>78 <text class="d-note" x="485" y="98" text-anchor="middle">UUID 21D7…</text>79 <path class="d-msg d-flow" d="M142,72 L417,72"/>80 <text class="d-label" x="280" y="64" text-anchor="middle">advertisement + device UUID</text>81 <path class="d-msg blue d-flow" d="M417,100 L142,100"/>82 <text class="d-label" x="280" y="118" text-anchor="middle">advertisement + device UUID</text>83 <text class="d-note" x="280" y="150" text-anchor="middle">C4F0… > 21D7… — Device A becomes GATT Server (relay),</text>84 <text class="d-note" x="280" y="166" text-anchor="middle">Device B becomes GATT Client (client) and connects.</text>85 <circle r="4" fill="#f26a00">86 <animateMotion dur="2.6s" repeatCount="indefinite" path="M142,72 L417,72"/>87 </circle>88 <circle r="4" fill="#2e5f9e">89 <animateMotion dur="2.6s" begin="1.3s" repeatCount="indefinite" path="M417,100 L142,100"/>90 </circle>91 </svg>92 </div>93 <figcaption>Fig. BE-1 — <b>Discovery and roles.</b> Both devices advertise. The higher device UUID takes the relay role.</figcaption>94 </figure>9596 <h2 class="bar" id="spec"><span class="num">2</span> Device Advertisement</h2>97 <p>A device announces itself with a standard BLE advertisement. The advertisement carries two values:</p>98 <div class="tscroll"><table class="ref">99 <caption>Advertisement contents</caption>100 <tr><th>Field</th><th>Value</th></tr>101 <tr><td class="btn">Service UUID</td><td><code>0000180f-0000-1000-8000-00805f9b34fb</code></td></tr>102 <tr><td class="btn">Data</td><td>The device UUID, encoded as a byte array.</td></tr>103 </table></div>104 <div class="box tech">105 <span class="tag">Tech Note</span>106 <p>The advertised service UUID <code>0000180f-…</code> is the Bluetooth SIG base-UUID slot for the standard <em>Battery Service</em> (0x180F). Reusing an assigned 16-bit identifier can collide with real battery-service devices during discovery. The source spec does not explain this choice.</p>107 </div>108109 <h2 class="bar"><span class="num">3</span> GATT Service</h2>110 <p>The device exposes a Nordic UART Service. The service has two characteristics. All traffic between the two devices flows through them.</p>111 <div class="tscroll"><table class="ref">112 <caption>GATT characteristics</caption>113 <tr><th>Characteristic</th><th>UUID</th><th>Properties</th></tr>114 <tr><td class="btn">Write</td><td><code>87654321-0000-1000-8000-00805f9b34fb</code></td><td>Write</td></tr>115 <tr><td class="btn">Read</td><td><code>12345678-0000-1000-8000-00805f9b34fb</code></td><td>Notify, Read</td></tr>116 </table></div>117 <p>The GATT Client writes messages to the Write Characteristic. The GATT Client reads messages from the Read Characteristic. The GATT Server uses the Notify property of the Read Characteristic to signal that new data waits.</p>118119 <h2 class="bar"><span class="num">4</span> Role Assignment</h2>120 <p>Each device advertises a device UUID. When a device finds another device that advertises the service, it reads the service data. It gets the peer's device UUID. It compares that UUID with its own advertised device UUID.</p>121 <ul>122 <li>The device with the <strong>highest</strong> device UUID takes the role of <strong>GATT Server</strong>. It acts as the relay.</li>123 <li>The other device takes the role of <strong>GATT Client</strong>. It acts as the client, and it establishes the connection.</li>124 </ul>125 <p>Some devices only ever serve one purpose. Such a device does not negotiate. It always advertises a fixed device UUID:</p>126 <div class="tscroll"><table class="ref">127 <caption>Fixed-role device UUIDs</caption>128 <tr><th>Role</th><th>Device UUID</th></tr>129 <tr><td class="btn">GATT Server</td><td><code>FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF</code></td></tr>130 <tr><td class="btn">GATT Client</td><td><code>00000000-0000-0000-0000-000000000000</code></td></tr>131 </table></div>132133 <h2 class="bar"><span class="num">5</span> Messages and Batching</h2>134 <p>All messages follow the <a href="01.html">NIP-01</a> message structure. Before transmission, the sender applies a DEFLATE compression stream to the message. The result is a byte array.</p>135 <p>A BLE packet is small. BLE 4.2 carries 20 to 23 bytes per message. Later BLE versions carry up to 256 bytes. When the compressed byte array does not fit in one packet, the sender splits it into batches. Each batch has this structure:</p>136 <div class="crt">137 <div class="titlebar">Batch format - one BLE packet</div>138<pre>[<span class="k">batch index</span> <span class="c">(first 2 bytes)</span>][<span class="k">batch n</span> <span class="c">(payload)</span>][<span class="k">is last batch</span> <span class="c">(last byte)</span>]</pre>139 </div>140 <p>The receiver collects all batches. It joins them in index order. It then decompresses the joined array with DEFLATE and gets the original message. These rules bound the transfer:</p>141 <ul>142 <li>Only one message is read or written at a time. This keeps the link reliable.</li>143 <li>The devices can negotiate the MTU in advance.</li>144 <li>The maximum size for a message is 64KB. The receiver rejects bigger messages.</li>145 </ul>146147 <figure class="diagram">148 <div class="frame">149 <svg viewBox="0 0 560 120" role="img" aria-label="A NIP-01 message is compressed with DEFLATE, split into indexed batches, and written one packet at a time">150 <rect class="d-actor" x="10" y="35" width="120" height="50" rx="8"/>151 <text class="d-actor-label" x="70" y="57" text-anchor="middle">Message</text>152 <text class="d-note" x="70" y="74" text-anchor="middle">NIP-01 JSON</text>153 <rect class="d-actor" x="180" y="35" width="110" height="50" rx="8"/>154 <text class="d-actor-label" x="235" y="57" text-anchor="middle">DEFLATE</text>155 <text class="d-note" x="235" y="74" text-anchor="middle">→ byte array</text>156 <rect class="d-actor" x="340" y="35" width="90" height="50" rx="8"/>157 <text class="d-actor-label" x="385" y="57" text-anchor="middle">Split</text>158 <text class="d-note" x="385" y="74" text-anchor="middle">[idx|data|last]</text>159 <rect class="d-actor" x="480" y="35" width="70" height="50" rx="8"/>160 <text class="d-actor-label" x="515" y="57" text-anchor="middle">Write</text>161 <text class="d-note" x="515" y="74" text-anchor="middle">1 at a time</text>162 <path class="d-msg d-flow" d="M132,60 L177,60"/>163 <path class="d-msg d-flow" d="M292,60 L337,60"/>164 <path class="d-msg d-flow" d="M432,60 L477,60"/>165 </svg>166 </div>167 <figcaption>Fig. BE-2 — <b>Batch pipeline.</b> Compress, split, send. The receiver runs the same steps in reverse.</figcaption>168 </figure>169170 <h2 class="bar"><span class="num">6</span> Workflows</h2>171172 <h3>Client to relay</h3>173 <ul>174 <li>Any message the client sends to the relay is a <strong>write message</strong> on the Write Characteristic.</li>175 <li>Any message the client receives from the relay is a <strong>read message</strong> on the Read Characteristic.</li>176 </ul>177178 <h3>Relay to client</h3>179 <p>A relay cannot push data over BLE the way a WebSocket relay can. Instead, when a new event matches a subscription's filters, the relay should send a Notify signal on the Read Characteristic. The client then reads the waiting messages from the relay.</p>180181 <h3>Device synchronization</h3>182 <p>A BLE connection between two devices can be extremely intermittent. Gaps of hours or even days are expected. The devices therefore need a defined synchronization process. This NIP uses the negentropy protocol from <a href="77.html">NIP-77</a>, adapted to BLE limits.</p>183 <p>After the two devices connect and settle the client-server roles, they communicate half-duplex. They take turns. Only one side transmits at a time.</p>184185 <h3>Half-duplex synchronization</h3>186 <p>Right after the two devices connect, the client starts the workflow. It sends the first message. The steps are:</p>187 <ol>188 <li>Client — writes a <a href="77.html">NIP-77</a> <code>NEG-OPEN</code> message.</li>189 <li>Server — sends <code>write-success</code>.</li>190 <li>Client — sends <code>read-message</code>.</li>191 <li>Server — responds with a <a href="77.html">NIP-77</a> <code>NEG-MSG</code> message.</li>192 <li>Client —193 <ol>194 <li>If the client has events that the server misses, it writes one <code>EVENT</code>.</li>195 <li>If the client has no events that the server misses, it writes <code>EOSE</code>. After that, the client's messages to the server stay empty while the server still claims more notes for the client.</li>196 </ol>197 </li>198 <li>Server — sends <code>write-success</code>.</li>199 <li>Client — sends <code>read-message</code>.</li>200 <li>Server —201 <ol>202 <li>If the server has events that the client misses, it responds with one <code>EVENT</code>.</li>203 <li>If it has none, it responds with <code>EOSE</code>. After that, its responses to the client stay empty.</li>204 </ol>205 </li>206 <li>If the client detects that the devices are not synchronized yet, jump to step 5.</li>207 <li>When both ends detect no more missing events, the workflow pauses at this point.</li>208 </ol>209 <div class="box tech">210 <span class="tag">Tech Note</span>211 <p>The source text of step 8.2 reads "If the <em>Client</em> doesn't have any messages missing on the Server". That condition belongs to step 5.2. In step 8 the server is the sender, so the intended condition is almost certainly "if the <em>server</em> has no events missing on the client". The spec never fixed this wording.</p>212 </div>213214 <figure class="diagram">215 <div class="frame">216 <svg viewBox="0 0 560 320" role="img" aria-label="Sequence diagram: client writes NEG-OPEN, server confirms, client polls with read-message, server answers NEG-MSG, then EVENT and EOSE alternate until synchronized">217 <line class="d-wire" x1="110" y1="40" x2="110" y2="305" stroke-dasharray="3 4"/>218 <line class="d-wire" x1="450" y1="40" x2="450" y2="305" stroke-dasharray="3 4"/>219 <rect class="d-actor" x="55" y="8" width="110" height="30" rx="6"/>220 <text class="d-actor-label" x="110" y="28" text-anchor="middle">Client</text>221 <rect class="d-actor" x="395" y="8" width="110" height="30" rx="6"/>222 <text class="d-actor-label" x="450" y="28" text-anchor="middle">Server</text>223 <path class="d-msg" d="M110,62 L445,62"/>224 <text class="d-label" x="280" y="55" text-anchor="middle">write: NEG-OPEN</text>225 <path class="d-msg blue" d="M450,92 L115,92"/>226 <text class="d-label" x="280" y="85" text-anchor="middle">write-success</text>227 <path class="d-msg" d="M110,122 L445,122"/>228 <text class="d-label" x="280" y="115" text-anchor="middle">read-message</text>229 <path class="d-msg blue" d="M450,152 L115,152"/>230 <text class="d-label" x="280" y="145" text-anchor="middle">NEG-MSG</text>231 <path class="d-msg d-flow" d="M110,190 L445,190"/>232 <text class="d-label" x="280" y="183" text-anchor="middle">write: EVENT (or EOSE)</text>233 <path class="d-msg blue" d="M450,220 L115,220"/>234 <text class="d-label" x="280" y="213" text-anchor="middle">write-success</text>235 <path class="d-msg" d="M110,250 L445,250"/>236 <text class="d-label" x="280" y="243" text-anchor="middle">read-message</text>237 <path class="d-msg blue d-flow" d="M450,280 L115,280"/>238 <text class="d-label" x="280" y="273" text-anchor="middle">EVENT (or EOSE) — repeat until synchronized</text>239 <text class="d-note" x="280" y="304" text-anchor="middle">Both ends report EOSE: the workflow pauses.</text>240 <circle r="4" fill="#f26a00">241 <animateMotion dur="2.6s" repeatCount="indefinite" path="M110,190 L445,190"/>242 </circle>243 </svg>244 </div>245 <figcaption>Fig. BE-3 — <b>Half-duplex synchronization.</b> The client takes turns with the server until neither side misses events.</figcaption>246 </figure>247248 <h3>Half-duplex event spread</h3>249 <p>Two connected and synchronized devices can drift again. One of them may receive a new event from another connected peer. Devices MUST track which notes they sent to each peer while connected. When a device detects that a connected, synchronized peer misses a newly received event, it spreads the event:</p>250 <ol>251 <li>If the peer is a <strong>server</strong>:252 <ol>253 <li>Client — writes the <code>EVENT</code>.</li>254 <li>Server — sends <code>write-success</code>.</li>255 </ol>256 </li>257 <li>If the peer is a <strong>client</strong>:258 <ol>259 <li>Server — sends an empty notification to the client.</li>260 <li>Client — sends <code>read-message</code>.</li>261 <li>Server — responds with the <code>EVENT</code>.</li>262 </ol>263 </li>264 </ol>265266 <h2 class="bar" id="examples"><span class="num">7</span> Worked Example</h2>267 <p>The source NIP ships one code example in Kotlin. One function compresses a byte array and splits it into chunks. The other function joins the chunks and decompresses them to recover the original bytes.</p>268 <div class="crt">269 <div class="titlebar">Kotlin - split and join batches (verbatim from the spec)</div>270<pre><span class="k">fun</span> splitInChunks(message: ByteArray): Array<ByteArray> {271 <span class="k">val</span> chunkSize = 500 <span class="c">// define the chunk size</span>272 <span class="k">var</span> byteArray = compressByteArray(message)273 <span class="k">val</span> numChunks = (byteArray.size + chunkSize - 1) / chunkSize <span class="c">// calculate the number of chunks</span>274 <span class="k">var</span> chunkIndex = 0275 <span class="k">val</span> chunks = Array(numChunks) { ByteArray(0) }276277 <span class="k">for</span> (i <span class="k">in</span> 0 until numChunks) {278 <span class="k">val</span> start = i * chunkSize279 <span class="k">val</span> end = minOf((i + 1) * chunkSize, byteArray.size)280 <span class="k">val</span> chunk = byteArray.copyOfRange(start, end)281282 <span class="c">// add chunk index to the first 2 bytes and last chunk flag to the last byte</span>283 <span class="k">val</span> chunkWithIndex = ByteArray(chunk.size + 2)284 chunkWithIndex[0] = chunkIndex.toByte() <span class="c">// chunk index</span>285 chunk.copyInto(chunkWithIndex, 1)286 chunkWithIndex[chunkWithIndex.size - 1] = numChunks.toByte()287288 <span class="c">// store the chunk in the array</span>289 chunks[i] = chunkWithIndex290291 chunkIndex++292 }293294 <span class="k">return</span> chunks295}296297<span class="k">fun</span> joinChunks(chunks: Array<ByteArray>): ByteArray {298 <span class="k">val</span> sortedChunks = chunks.sortedBy { it[0] }299 <span class="k">var</span> reassembledByteArray = ByteArray(0)300 <span class="k">for</span> (chunk <span class="k">in</span> sortedChunks) {301 <span class="k">val</span> chunkData = chunk.copyOfRange(1, chunk.size - 1)302 reassembledByteArray = reassembledByteArray.copyOf(reassembledByteArray.size + chunkData.size)303 chunkData.copyInto(reassembledByteArray, reassembledByteArray.size - chunkData.size)304 }305306 <span class="k">return</span> decompressByteArray(reassembledByteArray)307}</pre>308 </div>309 <div class="box tech">310 <span class="tag">Tech Note</span>311 <p>The example does not match the spec, and it clobbers data. The batch format in §5 reserves 2 bytes for the index; the code writes 1 byte and reads 1 byte back. The last byte should be an "is last batch" flag; the code stores the total chunk count instead. The code also copies the payload into offset 1 of a buffer sized <code>chunk.size + 2</code>, then overwrites the buffer's last byte — which is the payload's final byte. Finally, <code>chunkSize = 500</code> exceeds every packet limit stated in §5 (23 or 256 bytes). This mismatch is part of why the NIP requires review.</p>312 </div>313314 <p>The transcript below shows a full half-duplex synchronization pass between a phone (client) and a fixed relay device (server). Orange lines are client writes. Blue lines are server responses.</p>315 <div class="crt">316 <div class="titlebar">BLE session - half-duplex sync</div>317<pre><span class="c">-- roles settled: phone UUID 21D7… < relay UUID FFFF… → phone = client --</span>318<span class="send">→ write ["NEG-OPEN","sub1",{"kinds":[1]},"<initial negentropy msg>"]</span>319<span class="recv">← write-success</span>320<span class="send">→ read-message</span>321<span class="recv">← ["NEG-MSG","sub1","<negentropy reconciliation msg>"]</span>322323<span class="c">-- client has one event the server misses --</span>324<span class="send">→ write ["EVENT",{"id":"b1a649ebe8…","kind":1,"content":"sent over BLE",…}]</span>325<span class="recv">← write-success</span>326<span class="send">→ read-message</span>327<span class="recv">← ["EVENT",{"id":"9f2c11ab…","kind":1,…}]</span>328329<span class="c">-- nothing left on either side --</span>330<span class="send">→ write ["EOSE","sub1"]</span>331<span class="recv">← write-success</span>332<span class="send">→ read-message</span>333<span class="recv">← ["EOSE","sub1"]</span>334<span class="c">-- synchronized: workflow pauses until a new event arrives --</span></pre>335 </div>336 <p>Every message above travels as DEFLATE-compressed batches, one BLE packet at a time, per §5. The JSON shown is the payload after reassembly and decompression.</p>337338 <h2 class="bar" id="history"><span class="num">8</span> Version History</h2>339 <p>NIP-BE has a short history. It landed late in 2025 and was flagged as unrecommended half a year later. Notable changes, newest first:</p>340 <ul class="patchnotes">341 <li><span class="ver">2026</span><span class="when">2026-05</span>fiatjaf added the <code>unrecommended</code> tag and the warning to the NIP body: only implemented once, unclear whether it works, requires review.</li>342 <li><span class="ver">Origin</span><span class="when">2025-11</span>KoalaSat published the spec: BLE messaging and device synchronization, merged as PR <a href="https://github.com/nostr-protocol/nips/pull/1979">#1979</a>.</li>343 </ul>344345 <div class="credits">346 <h3 class="cardhead">Original Proposal - Credits</h3>347 <table>348 <tr><td>Author</td><td>KoalaSat</td></tr>349 <tr><td>First commit</td><td>2025-11-11 — “NIP-BE: Add BLE messaging and device synchronization” (<a href="https://github.com/nostr-protocol/nips/pull/1979">PR #1979</a>)</td></tr>350 <tr><td>Status</td><td>draft - unrecommended - optional — deprecated, requires review</td></tr>351 <tr><td>Source</td><td><a href="https://github.com/nostr-protocol/nips/blob/master/BE.md">BE.md on GitHub</a> - <a href="https://github.com/nostr-protocol/nips/commits/master/BE.md">full change history</a></td></tr>352 </table>353 </div>354355 <h2 class="bar"><span class="num">9</span> See Also</h2>356 <ul>357 <li><a href="01.html">NIP-01</a> — defines the message structure that every BLE payload carries.</li>358 <li><a href="77.html">NIP-77</a> — the negentropy sync protocol (<code>NEG-OPEN</code>, <code>NEG-MSG</code>) that the half-duplex workflow adapts.</li>359 <li><a href="b7.html">NIP-B7</a> — the previous chapter; unrelated in topic, adjacent in hex order.</li>360 </ul>361 </div>362363 <aside>364 <div class="cartridge">365 <div class="inner">366 <h3 class="cardhead">Spec Card</h3>367 <div class="lights"><span class="led err"></span><span class="led err"></span><span class="led err"></span></div>368 <dl>369 <dt>Status</dt><dd><span class="chip draft">draft</span><span class="chip unrecommended">unrecommended</span><span class="chip">optional</span></dd>370 <dt>Defines</dt><dd>BLE advertisement - GATT service - batch format - half-duplex sync</dd>371 <dt>Kinds</dt><dd>none — transport only</dd>372 <dt>Requires</dt><dd><a href="01.html">NIP-01</a> - <a href="77.html">NIP-77</a></dd>373 <dt>Transport</dt><dd>BLE GATT - Nordic UART Service</dd>374 <dt>Encoding</dt><dd>DEFLATE - indexed batches - 64KB max</dd>375 <dt>First commit</dt><dd>2025-11-11</dd>376 <dt>Last updated</dt><dd>2026-05-31</dd>377 </dl>378 </div>379 </div>380 </aside>381 </main>382383 <nav class="navbtns">384 <a href="b7.html">◀ NIP-B7: Blossom media</a>385 <a href="c0.html">NIP-C0: Code Snippets ▶</a>386 </nav>387388 <footer class="pagefoot">389 <a href="../index.html">Nostr Protocol Manual</a>390 <span class="pageno">NIP BE / F4</span>391 </footer>392</div>393394<script src="../assets/webmcp.js" defer></script>395</body>396</html>