An offline, serverless mesh messenger for Android and iPhone — end-to-end encrypted, no internet, no accounts.
Your phones talk directly to each other over Wi-Fi Aware and Bluetooth LE, and relay for one another hop by hop.
Knit needs no internet connection, no cell service, no accounts, and no servers. It forms an ad-hoc mesh directly over Wi-Fi Aware (NAN) and Bluetooth LE, running both radios at once. Send a message and it goes to every device in range; each of those re-transmits it onward, so messages leap-frog across phones with no infrastructure at all. Duplicates are discarded, hop-count and TTL bound the flood, and a store-and-forward layer carries what a single flood doesn't reach.
┌─────────┐ Wi-Fi Aware / BLE ┌─────────┐ Wi-Fi Aware / BLE ┌─────────┐
│ Phone A │ ────────────────────► │ Phone B │ ────────────────────► │ Phone C │
└─────────┘ send + relay └─────────┘ relay (dedup) └─────────┘
│ │ │
originates a overhears & re-floods (jittered, delivers — even though
signed, encrypted suppressed) — only carries ciphertext A was never in its range
frame once it can't decrypt
- Two radios, no GMS. On Android, Wi-Fi Aware and Bluetooth LE run simultaneously behind one transport seam, with no Google Nearby dependency. A device with only one of the two still meshes over that one.
- Android and iPhone on one mesh. Knit for iOS speaks the same protocol over Bluetooth LE, so an iPhone links straight to the Android phones around it, relays for them, and reaches Wi-Fi Aware, LoRa and spools through them.
- End-to-end encrypted, with forward secrecy. Direct and group messages are sealed per-message (AES-256-GCM) and signed (Ed25519), so relays only ever carry ciphertext. Between current builds the keys rotate — a DM session bootstraps X3DH-style from a signed prekey in the peer's profile and rekeys as the conversation turns over, and groups run a sender-key ratchet on top — so recorded traffic stops being readable once its keys age out. Identity keys are hardware-backed and verifiable in person by safety number or QR code. The public Nearby room is plaintext by design: it has nobody in particular to encrypt to.
- Store-and-forward. A message whose recipient isn't in range is held in encrypted custody and re-offered when a path to them appears, so phones that meet only briefly still backfill each other.
- A whole messenger, not a demo. A public Nearby room, 1:1 DMs and group chats; photos, files, voice notes, reactions and @-mentions, with link previews and shared locations as opt-ins; search across every chat; files far too big to attach, handed to a nearby contact over a direct Wi-Fi link; and on-device screening for abusive text and explicit images that never leaves the phone.
- Kilometres of range from a Meshtastic radio, if you want them. Pair a LoRa board over Bluetooth and the Nearby room and your 1:1 messages get a hop measured in kilometres, shared by every phone meshed with yours. It sits idle until you pair one.
- An optional Internet plane, off until you switch it on. When no radio path exists, Knit can park the same sealed frame on a small relay — a spool — that hands it over the next time the other phone connects. See below.
- Reproducible builds. F-Droid rebuilds each release from source and byte-compares it against the APK we publish before distributing it.
| F-Droid | f-droid.org/packages/app.getknit.knit |
| Google Play | play.google.com/store/apps/details?id=app.getknit.knit |
| Signed APK | github.com/getknit/knit/releases |
| iPhone | Headed for the App Store — source at github.com/getknit/knit-ios |
| Website | getknit.app |
Android 10+ (API 29); iOS 18+ for the iPhone app. Once installed, Knit can hand itself to a nearby phone over Quick Share or Bluetooth — no store and no network required.
Proximity meshing is the product; a spool is the fallback for when nobody is in range. A spool is a scoped, blinded store-and-forward relay. It holds, per conversation scope, a bounded set of end-to-end-sealed frames and a digest over them, streams new arrivals to subscribers, and heals divergence by digest anti-entropy.
┌─────────┐ push ┌────────────┐ event ┌─────────┐
│ Phone A │─────────►│ spool-1 │──────────►│ Phone B │
│ seals │ └────────────┘ │ unions │
│ frame │ push ┌────────────┐ pull │ + opens │
│ once │─────────►│ spool-2 │◄──────────│ │
└─────────┘ └────────────┘ └─────────┘
no spool-to-spool link, ever
- It stays off until you turn it on. Enabling it takes an explicit consent sheet that spells out what a spool can and cannot see, so a fresh install still makes no network calls.
- A spool sees an opaque 32-byte scope id, blob ids, ciphertext, sizes, and timing. It never sees node ids, plaintext, rosters, delivery facts, or which other spools a client uses.
- No spool is load-bearing. Spools never talk to each other; clients multi-home across several and union the results, so overlap is all two members need, and a wiped spool is refilled by any one conversation member.
- The spec is the product.
docs/SPOOL_PROTOCOL.mdis normative, with executable §13 test vectors. Third-party implementations are first-class —knit-spoolships a conformance CLI that validates any live spool over the wire. - Cheap to run. Kotlin + Ktor on JDK 21, CBOR over one WebSocket (
wss://host/spool/v1), SQLite for persistence, idling in ~128–256 MB on the smallest VPS tier. Onedocker composefile brings it up behind Caddy with certificates issued and renewed for you, and the app takes a whole relay — address, token and all — from onegetknit.app/rinvite link, behind a sheet that says what the relay will see.
docker run -p 9470:9470 -v spool-data:/data -e SPOOL_POW_BITS=20 ghcr.io/getknit/knit-spool:0.2.0
gh attestation verify oci://ghcr.io/getknit/knit-spool:0.2.0 --repo getknit/knit-spoolMulti-arch (amd64 + arm64), mirrored on Docker Hub as
getknit/knit-spool.
HOSTING.md covers what a spool needs
from a box; deploy/ has the TLS compose
files.
| Repository | What it is |
|---|---|
| knit | The Android app, plus the normative spool protocol spec — Kotlin, Jetpack Compose, GPL-3.0-or-later |
| knit-ios | The iPhone app, on the same mesh as Android over Bluetooth LE — Swift, SwiftUI, GPL-3.0-or-later |
| knit-spool | The reference spool daemon and conformance suite — Kotlin, Ktor, AGPL-3.0-or-later |
Knit is free and open source, with no ads, no tracking, and no accounts — funded entirely by tips, which buy no special treatment.