Layer 0

Ten ways to move a message

The bearer layer exposes a capability descriptor rather than a name, so the policy engine reasons about throughput, range and privacy instead of about Bluetooth. Adding a bearer later requires no change above the obfuscation layer.

Bearer Sustained throughput Range Voice Photos Privacy Notes
QUIC / internet full global yes yes Medium The baseline. Connection migration, TCP fallback. IP visible to a relay or peer.
Wi-Fi Direct 50–250 Mbps 50–200 m yes, + video yes High No iOS↔Android. AWDL is Apple-only.
BLE 100–300 kbps 10–100 m Opus @ 16–24 kbps slow High The cross-platform local bearer. iOS background is restricted but workable.
LoRa 0.3–5.5 kbps, duty-capped 2–15 km no yes, constrained High EU 868 is a 1% duty cycle; US 915 is not. See below.
QR (animated) ≈3.6 KB/s line of sight no thumbnail tier Highest Fountain-coded multi-frame. Fully air-gapped, no RF. Practical ceiling ≈100 KB.
Acoustic (cable) 1200–3600 bps radio-dependent no yes, constrained High Speaker and microphone into a radio or a phone line.
Acoustic (air) 8–1000 bps same room no glyph only Highest Air-gap transfer. No cable, no RF.
NFC ≈8–48 kbps 4 cm no thumbnail tier High Tap-to-pair contact exchange. No iPhone↔iPhone. Reliable link layer.
SMS / MMS 140 B per segment cellular no MMS only Lowest The carrier learns both phone numbers. Consent-gated, never automatic.
Acoustic (open) 1200–3600 bps radio-dependent no yes, constrained Clear Part 97 legal mode: signed, not encrypted. See below.

The platform gap to plan around

iOS cannot do Wi-Fi Direct with Android — AWDL is Apple-to-Apple. BLE is therefore the universal local bearer, and Wi-Fi Direct is an Android, Linux and Windows accelerator only. NFC is the same story from the other side: it pairs an iPhone with an Android phone, but not two iPhones.

Privacy as ink density

More protection, more ink

Bearers carry a privacy level, and a user is entitled to know which one a message is about to take. The level is rendered as density on every client — and never as colour alone, because the word is always written beside the swatch.

  • Highest

    Air-gapped. Animated QR, acoustic through air. No radio involved at all.

  • High

    Local RF. BLE, Wi-Fi Direct, LoRa, NFC. Nothing leaves the immediate area.

  • Medium

    An IP address is visible to a relay or peer. QUIC, TCP.

  • Lowest

    A carrier learns an identifier. SMS and MMS, and nothing else.

  • Clear

    Readable by anyone listening. The Part 97 profiles, struck out rather than dimmed.

Why cleartext leaves the ramp instead of sitting at the bottom of it

lora-open and acoustic-open transmit in the clear because amateur radio prohibits encryption. Rendering that as one step below lowest would be a lie told in colour, so the ramp is struck out rather than dimmed — hollow cells with a line through them on the desktop, ╱╱╱╱ in the terminal, the way a proof is marked not to print. Both are joined by the word CLEAR, because colour is never the only carrier.

The policy engine

Resolution, in the order it actually runs

A first-class subsystem rather than configuration. Preferences are consulted at step seven — after everything that is not a preference.

resolve(contact, payload) -> ordered Vec<Bearer>:

  1. candidates ← all registered bearers
  2. filter     ← bearer.enabled_globally
  3. filter     ← contact.bearer_overrides permits it
  4. filter     ← bearer.privacy_level >= user.privacy_floor
  5. filter     ← bearer.can_carry(size, latency_class)
  6. filter     ← bearer.currently_available()
  7. sort       ← by user's configured fallback order
  8. gate       ← requires_consent prompts, or drops

Airtime is charged for what goes on the air

can_carry() returns a cost estimate in airtime seconds rather than a boolean, and the engine keeps a rolling budget per bearer. The estimate deliberately over-counts: over-estimating refuses a transmission that would have fitted, while under-estimating breaks the law.

It has to count fragments and repair symbols, not the payload the caller handed in: at small sizes the repair floor dominates, so a short message costs several times its own length once it reaches the antenna. Accounting that measures the payload instead of the transmission under-counts on precisely the bearers carrying a legal duty cycle, which is why it sits on the wire side of fragmentation rather than above it.

Two invocation paths

Only one of them goes through the engine

Ordinary traffic is policy-selected. Contact exchange is not: nobody enqueues a contact bundle and lets a resolver pick a bearer — a person presses add contact and then taps or scans. The deciding factor there is ergonomics, which is not an input resolve() has or should have.

The user-initiated path is a closed list: contact exchange by QR or NFC, device linking, device-to-device history sync, and an explicit send this to the device in front of me. Ordinary message traffic never reaches it. It is not a fast lane for stuck messages.

The distinction that keeps it honest

Preferences may be bypassed; invariants may not

Bypassable, because directly choosing a bearer is a deliberate override: fallback ordering, the privacy floor as a filter, and global enable or disable.

Never bypassable, on any path: legal duty-cycle limits, cleartext disclosure, end-to-end encryption, and capability limits. A 4 MB photo does not traverse a 237-byte frame because somebody wanted it to — it queues for a capable bearer instead.

LoRa

Regulation, not radio, is the binding limit

Power buys range, not throughput. Spreading factor and bandwidth set the data rate; an amateur licence grants far greater reach and legal power at 433 MHz but the same bits per second.

Region / band Duty cycle Raw @ SF7 Effective Encryption
US 915 — FCC Part 15 none, 400 ms dwell 5470 bps ≈680 B/s yes
US 433 — Part 97, licensed none 5470 bps ≈680 B/s no
EU 868 — ETSI 1% 5470 bps ≈7 B/s yes

The regional difference is not throughput but recovery

A 7.7 KB handshake occupies the channel for about eleven seconds either side of the Atlantic. What differs is what may follow: ETSI requires silence proportional to what was just sent — 99× the transmission at a 1% duty cycle — so an EU device that handshakes then cannot transmit for roughly nineteen minutes, ordinary traffic included. The US imposes no such obligation. The handshake is affordable, about eleven seconds against a thirty-six second hourly allowance; it simply buys a long silence. Expensive implies budgeting for it. Impossible would have implied designing around it.

One image, two very different experiences

Tier Encoding Size US 915 EU 868
Glyph AVIF 32×32, grayscale option ≈200 B ≈0.3 s ≈30 s
Thumb AVIF 96×96 ≈1.5 KB ≈3 s ≈3.8 min
Detail AVIF 160×160 ≈4 KB ≈7 s ≈10 min — impractical

The glyph tier sends automatically

Higher tiers require an explicit request by the recipient, so nobody burns ten minutes of shared airtime unprompted. There is a hard cap of 2 KB per LoRa image payload regardless of tier.

The original is not lost

The full-resolution image stays content-addressed and upgrades over a fatter bearer later, against the same hash. What arrived over LoRa is not a downgrade — it is the first representation.

Mesh airtime is shared

On a Meshtastic-style network one user sending images degrades everyone, so the airtime budget is per-network rather than per-device.

Acoustic packet modem

Data as audio, into anything with a microphone

Encoded through the speaker, decoded through the microphone. It couples to any radio with a mic input — ham HF, VHF and UHF, licensed land-mobile, satellite handsets — or to a phone call, an intercom, or simply the air between two devices in a room.

Profile Rate Use
Robust — FSK, ggwave-class 8–100 bps Acoustic through air, noisy
AFSK 1200 — Bell 202 1200 bps Classic packet radio, very well proven
PSK/QAM adaptive 2000–3600 bps Cable-coupled into a 3 kHz SSB channel

The ladder is negotiated by measured channel signal-to-noise. Half-duplex with push-to-talk keying, so the delivery layer treats it as a strictly turn-taking link.

The constraint

Amateur radio prohibits encryption

FCC Part 97.113(a)(4) bars messages encoded for the purpose of obscuring their meaning, and most ITU jurisdictions have an equivalent rule. Part 95 services — GMRS, FRS, MURS — prohibit ciphers as well. Transmitting this system's normal encrypted traffic over amateur or GMRS bands is generally illegal, and no amount of protocol design changes that.

The encrypted profile is lawful on Part 90 licensed land-mobile and other commercial spectrum, on satellite voice channels, over ordinary phone calls and intercoms, and for air-gapped transfer in the same room.

The answer

Signed, not secret

Part 97 prohibits obscuring meaning. It does not prohibit authentication — a digital signature proves who sent a message without hiding what it says. So the bearer ships two profiles: Acoustic-Private with full end-to-end encryption, and Acoustic-Open, signed and integrity-protected with a plaintext payload.

The open profile attaches to operation under Part 97, not to acoustics — a licensed operator running LoRa at 433 MHz is subject to the same rule. Station identification is a protocol element, a periodic plaintext callsign frame the bearer emits itself, rather than a setting a user can forget.

Declaring a licence is a trade, not an upgrade

The client ships a region and licence setting that gates which profiles are offered, which duty cycles the airtime accounting enforces, and whether identity operations are permitted over LoRa at all. It defaults to the most restrictive interpretation and must be set deliberately. Declaring an amateur licence unlocks the higher-power Part 97 bands and simultaneously restricts those bands to the open profile — a user who declares a callsign and then finds encrypted traffic refused on 433 MHz should have been told why before they got there.

Selecting a cleartext profile is a per-message deliberate act and never a fallback. A system whose defining promise is confidentiality must not silently transmit in the clear.

Contact exchange

Two devices, no network, no third party

Adding a contact is the one operation where a human is physically present and choosing, so it is deliberately kept out of the policy engine's hands.

Animated QR

Fountain-coded frames, not numbered chunks

A contact bundle is larger than one QR code, so it is transmitted as a sequence of frames. With RaptorQ the receiver needs any K plus a little, not specific frames — so a camera that misses one simply keeps watching instead of waiting for a particular frame to come round again.

Fully air-gapped, no RF, and it generalises: what starts as contact exchange is a bearer in its own right at roughly 3.6 KB/s, with a practical ceiling around 100 KB. Exchange is two-pass, and verification is a safety number drawn from the PGP word list — chosen because it is meant to be read aloud.

NFC

Four centimetres is the security property

A tap is unambiguous in a way that scanning across a room is not: at 4 cm, the device you exchanged with is the one you were holding. The link layer is reliable, and the interaction is a ritual people already understand from payment terminals.

Two things not to oversell: it does not work between two iPhones, and short range is not secrecy — proximity establishes which device, not that nobody observed the exchange. Verification still happens through the safety number.

The bearer layer is one of nine

Everything above it — identity, session, delivery, policy — is written against capability descriptors rather than bearer names, which is what lets a bearer be added without a flag day.