An offline, serverless mesh messenger for Android — end-to-end encrypted, no internet, no accounts, no Google Play services.
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. 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.
- End-to-end encrypted. Direct and group messages are sealed per-message (AES-256-GCM), wrapped to each recipient (HPKE/X25519), and signed (Ed25519), so relays only ever carry ciphertext. Identity keys are hardware-backed and verifiable in person by safety number or QR code.
- 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.
- 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 |
| Website | getknit.app |
Android 10+ (API 29). Once installed, Knit can hand itself to a nearby phone over the mesh — 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.
docker run -p 9470:9470 -v spool-data:/data -e SPOOL_POW_BITS=20 ghcr.io/getknit/knit-spool:0.1.0
gh attestation verify oci://ghcr.io/getknit/knit-spool:0.1.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-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.