Join the Agent Deck Discord Server!
Check out the Agent Deck community on Discord – hang out with 357 other members and enjoy free voice and text chat.
Knit is an offline-first, serverless messenger. Your phone relays messages to nearby devices over Bluetooth and Wi-Fi, with end-to-end encrypted direct and group chats. No internet or servers required
SocialKotlin · PythonGitHub @getknitOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
Offline, serverless, end-to-end-encrypted mesh messenger for Android — runs Wi-Fi Aware and Bluetooth LE simultaneously, with no servers and no Google Play Services.
Taken from the repository README
Loading the full README. The saved excerpt is shown below.
Message the people around you when there is no network at all — an end-to-end-encrypted mesh messenger for Android.
Phones talk straight to each other over Wi-Fi Aware and Bluetooth LE, relaying for one another hop by hop, so a message reaches further than any one radio does. No internet, no accounts, no Google Play services.
The public Nearby room, relayed over Wi-Fi Aware + BLE with no internet — photos, link previews,
and a line that came the long way over a LoRa radio.Read the full README ↗Message the people around you when there is no network at all — an end-to-end-encrypted mesh messenger for Android.
Phones talk straight to each other over Wi-Fi Aware and Bluetooth LE, relaying for one another hop by hop, so a message reaches further than any one radio does. No internet, no accounts, no Google Play services.
🌐 getknit.app — the Knit website
The public Nearby room, relayed over Wi-Fi Aware + BLE with no internet — photos, link previews, and a line that came the long way over a LoRa radio.
Knit keeps nearby phones talking when nothing else is available — no internet, no cell service, no accounts, no servers. It forms an ad-hoc mesh directly over Wi-Fi Aware (NAN) and Bluetooth LE, running both radios at once. A message you send goes to every device in range, and each of those passes it on, so it leap-frogs across phones to people you were never in range of yourself. Duplicates are discarded, hop-count and TTL bound the flood, and a store-and-forward layer carries what a single flood misses to whoever comes into range later. Above all that sits an ordinary modern messenger: conversation list, bubbles, reactions, attachments.
Bridgefy, Briar, and Meshtastic go after the same problem. What Knit does differently is run two radios at once (Wi-Fi Aware + BLE) behind one transport seam, with no Google Nearby / GMS dependency and end-to-end encryption on direct and group messages — and it needs no hardware beyond an Android phone, though it will happily use a Meshtastic board if you have one.
| Category | Offline / off-grid mesh messenger (proximity, peer-to-peer, delay-tolerant) |
| Platform | Android 10+ (API 29), Kotlin + Jetpack Compose (Material 3). An iPhone port, Knit for iOS, joins the same mesh over Bluetooth LE and is headed for the App Store |
| Radios | Wi-Fi Aware (NAN) and Bluetooth LE, running simultaneously — no Google Play services |
| Encryption | E2E on 1:1 DMs & group chats, forward-secret between current builds (X3DH-style bootstrap + epoch ratchet, AES-256-GCM, Ed25519); at-rest DB via SQLCipher |
| Works without | Internet, cellular, Wi-Fi routers, accounts, phone numbers, or any server |
| Optional extras | A Meshtastic LoRa board for kilometre-scale hops; Internet relays for when nobody is in range — each off until you turn it on |
| Calls | 1:1 voice calls, over Wi-Fi Direct to someone nearby or the Internet to someone further off, and a walkie-talkie over the mesh when neither path exists — see Calls |
| Watch | A Wear OS 3+ app, tile, and five complications that read the mesh from your phone — in preview |
| License | GPL-3.0-or-later — free and open source |
[!NOTE] Knit is a complete messenger: a "Nearby" public broadcast room, 1:1 direct messages, and multi-member group chats, with profiles (name / status / avatar), emoji reactions, @-mentions, photos, files, and voice notes. Direct and group messages are end-to-end encrypted — the body, mentions, and attachments are readable only by the people they were sent to, even though every message floods through other people's phones on the way. The public Nearby room is plaintext by design: a room with no fixed recipient set has nobody in particular to encrypt to. See the Security note.
Knit needs Android 10 (API 29) or newer — see Requirements. Both channels ship the same app; pick one and stay on it (see the note below).
[!IMPORTANT] Play and non-Play installs carry different signatures and can't upgrade one another. Play App Signing re-signs the app with Google's key, so switching between the Play build and the F-Droid/APK/offline-shared build requires uninstalling first — which erases your local message history and identity key. The F-Droid, GitHub-Release, and offline-shared APKs all share one signature, so those three interoperate and update in place.
┌─────────┐ 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
Every message is a signed CBOR frame that relays forward byte-for-byte (they rewrite only
TTL/hop-count), so the originator's Ed25519 signature survives every hop. A relay that can't decrypt or
even recognize a frame still forwards it — an old build is never a black hole. See
docs/ARCHITECTURE.md for the full protocol.
Knit is built for situations where there's no reliable network but people are physically nearby:
MeshTransport seam (CompositeMeshTransport), with no Google Nearby / GMS.
Knit advertises, discovers, connects, and floods with hop-count/TTL bounds and dedup; relays
rebroadcast on a jitter with overhear suppression, so a dense cluster doesn't storm itself. A
phone with only one of the two radios still meshes over that one. Where both phones support
Bluetooth's long-range mode (Coded PHY), they find each other from further apart, and a link drifting
out of range switches to it to stay up.Knit can call your contacts too, one to one. Call someone your phone meshes with and you don't need the Internet. The two phones raise a Wi-Fi Direct link between themselves, the same kind a big-file transfer uses, and the call runs over it. For someone further away the call goes over the Internet: it rings as a sealed direct message through the mesh or your relays, and your voice goes straight to the other phone where the network allows it, or through a TURN server where it doesn't.
When neither path exists, Knit places a mesh call instead, which works like a walkie-talkie: hold the button to talk and your words stream across the mesh in small chunks, playing about a second behind you between neighbours. Nothing is stored, and no burst lands in the chat. A contact's profile has a Mesh call button too, for when you'd rather start one yourself.
Only the two of you hear a call. A live call's audio is encrypted with DTLS-SRTP under keys each phone checks against the other's Knit identity, so a TURN server relays only ciphertext. Walkie chunks are sealed like any direct message, and the phones that carry them can't read them. A live call does show each phone's IP address to the other, and Relay all calls in Settings → Calls hides yours by routing every call through a TURN server instead.
Calls register with Android as calls, so a Bluetooth headset, a watch or a car can answer and hang up, and the audio follows your headset. Each call leaves a line in the chat, like "Missed call · 9:15 AM". Knit can also write each walkie burst out as text while it plays, and caption the other person on a live call. The speech recognition runs on the phone, and the words are never sent anywhere. Its model is a one-time download from getknit.app that starts only when you tap for it.
Knit is coming to Wear OS. The watch app shows who your phone can reach without you taking the phone out of your pocket. Its map draws a line to each person in the style of the radio that links you: thin for Bluetooth, a wide ribbon for Wi-Fi Aware, a wave for LoRa, dots for an Internet relay. People reached only over LoRa or a relay sit further out as hollow circles. The Knit tile is a swipe away from the time, and five complications can put the mesh state, people nearby, messages relayed today, messages carried for others, or a breakdown of your day on your watch face. It needs Wear OS 3 or newer.
The watch gets all of this from the Knit app on the phone it's paired with, directly over Bluetooth, so neither end needs Google Play services. The phone answers only a device it's paired with, over an encrypted connection, and what it sends names nobody: counts, the mesh state, and which radios reach each person, with no ids, names, or keys. The watch keeps the history of your day to itself.
The watch app is a preview for now. Release builds of the phone app don't serve it yet, and it's headed for Google Play once they do. To try it from source, see Build.
NEARBY_WIFI_DEVICES on API 33+, falling back to
ACCESS_FINE_LOCATION (location-scoped, no ICM) on API 29–32. The location permissions are
declared on every version for Send location, which asks for them the first time you pick it from
a chat's menu.| Area | Choice |
|---|---|
| Language / UI | Kotlin 2.4.21 · Jetpack Compose (Material 3) + Navigation Compose |
| Build | AGP 9.4.1 / Gradle 9.7.1 · JDK 21 · minSdk 29 / targetSdk 36 / compileSdk 37.1 |
| DI | Koin (pure-Kotlin, no Gradle plugin) |
| Storage | Room 3 + SQLCipher (encrypted at rest) · DataStore |
| Wire format | kotlinx.serialization CBOR (layered WireEnvelope) |
| Crypto | Google Tink — HPKE/X25519 key-wrap, AES-256-GCM, Ed25519 signatures |
| Radios | Wi-Fi Aware + Bluetooth LE (framework APIs — no external transport dependency) |
| On-device ML | LiteRT / TFLite (NSFW image + toxicity text classifiers) |
| Calls | WebRTC (Opus over DTLS-SRTP) · Jetpack core-telecom · Moonshine on-device speech recognition |
| Networking (opt-in planes only) | OkHttp — WebSocket to relays you configure, the sender-side link-preview fetch, and (debug builds) the ticket key swap; confined to three files |
| Images & video | Coil 3 · Media3 Transformer (on-device video re-encode) |
| Verification | ZXing (safety-number QR) |
| App sharing | ARSCLib + apksig (on-device split-APK merge & re-sign) |
| Quality | detekt · ktlint · Kover (all pinned; detekt/ktlint run as Gradle plugins) |
The bleeding-edge toolchain forces several non-obvious choices — Koin over Hilt, a Kotlin override off AGP's bundled compiler, and Gradle-plugin linting. See
AGENTS.mdbefore touching build config or dependencies.
The source lives at https://github.com/getknit/knit. You need JDK 21 and the
Android SDK — Android Studio is optional. When building from the command line without
Studio, point Gradle at your SDK first: create a git-ignored local.properties containing
sdk.dir=/path/to/Android/Sdk, or export ANDROID_HOME.
git clone https://github.com/getknit/knit.git
cd knit
./gradlew :app:assembleDebug # build the debug APK (does NOT compile test sources)
./gradlew :app:compileDebugKotlin # fast compile check of main sources
./gradlew :app:testDebugUnitTest # JVM unit tests — mesh router, flood suppression, dedup, CBOR codec,
# crypto, store-and-forward, + Robolectric Room/DAO & migration tests
./gradlew installDebug # install on a connected device
./gradlew detekt ktlintCheck # static analysis & style (Gradle plugins; ktlintFormat autoformats)
./gradlew :app:koverHtmlReportDebug # test coverage report
The debug APK lands at app/build/outputs/apk/debug/app-debug.apk.
Every build includes calls; debug builds add their transcripts. A release build adds transcripts with
-Pstt=true, and -Pcalls=false leaves calls out of any build.
The Wear OS app is a separate module that is in the build only when you ask for it:
./gradlew :wear:assembleDebug -Pknit.wear=true
adb -s <watch-serial> install wear/build/outputs/apk/debug/wear-debug.apk
It shares the phone app's package name, so install it with an explicit -s (or ANDROID_SERIAL): a
./gradlew installDebug -Pknit.wear=true with a phone attached can replace the phone app with the watch
build. Debug builds of the phone app serve the watch; release builds don't yet.
The Knit watch face (Wear OS 6+) is a second module behind the same switch; install it next to the watch app and pick "Knit" in the watch's face picker:
./gradlew :watchface:assembleDebug -Pknit.wear=true
adb -s <watch-serial> install watchface/build/outputs/apk/debug/watchface-debug.apk
./gradlew :watchface-monogram:assembleDebug -Pknit.wear=true # the analog "Knit Monogram"
adb -s <watch-serial> install watchface-monogram/build/outputs/apk/debug/watchface-monogram-debug.apk
scripts/check-watchface.sh # both faces: Google's WFF validator and memory budget
The mesh drives the Wi-Fi Aware and Bluetooth LE radios directly, so it needs physical devices:
The app launches and the UI works on an emulator, but an emulator cannot form a real mesh (it has no
Wi-Fi Aware or BLE peer radio), so use real devices for connectivity testing. Debug builds carry a
headless am broadcast bridge (…debug.SEND / SENDIMG / STATE / STORE / REACT / XFER / LORA /
SPOOL and more) so the send→verify loop can be driven over adb without screenshots — see
AGENTS.md.
JVM unit tests — ./gradlew :app:testDebugUnitTest (mesh/protocol/data logic, plus Robolectric +
in-memory Room DAO/migration and Compose-*ScreenContent tests). No device.
Mesh in a box — app/src/test/…/mesh/lab/ runs several complete, real Knit stacks in one JVM (the
real router, custody, key exchange and both ratchets over Robolectric's in-memory SQLite), linked by an
in-process transport with no radio — plus real LoRa and relay planes when a scenario asks for them. It
is where the bugs that live between two nodes get caught, so a change to what two phones exchange gets
a scenario here that ends in a convergence check, not only a single-node test against mocks. Part of
the same testDebugUnitTest run.
Seeded UI instrumentation tests — a Compose/Espresso suite (app/src/androidTest/…/ui/) that renders
every screen fully populated with no radios, to hunt device/API-specific UI quirks. It runs the
demo-seeded build (-PseedDemo=true: a no-op transport + a seeded conversation history), so it works on an
emulator or any device:
./gradlew :app:connectedDebugAndroidTest -PseedDemo=true # on every attached adb device/emulator
./gradlew :app:pixel7api33DebugAndroidTest -PseedDemo=true # on a Gradle-managed emulator only (Pixel 7 @ API 33)
The pixel7api33 variant is a Gradle Managed Device: Gradle boots a headless emulator, runs the suite,
and tears it down — it never touches attached physical devices (which the plain connected… task would).
Because the suite is radio-less it also runs unmodified on Firebase Test Lab physical devices: build the
debug and debug-androidTest APKs (with -PseedDemo=true) and submit them with gcloud firebase test android run (Android Test Orchestrator, per-test isolation), capturing a screenshot per test per device. See
AGENTS.md for the recommended device/API matrix and the free-tier budget.
Black-box UIAutomator tests — a UIAutomator suite (app/src/androidTest/…/uiauto/) that drives the
real running app through the accessibility / resource-id layer, so it reaches what the in-process Compose
suite can't: the system notification shade, process lifecycle (Home / Recents / rotation), and real
dropdown-menu / dialog . It shares the same demo-seeded, radio-less build. Run of them
locally on the Gradle-managed emulator (no physical device, no involvement):
Does Knit need the internet or a cell signal? No. Knit works entirely offline. Nearby phones connect directly over Wi-Fi Aware and Bluetooth LE and relay messages for each other, so it needs neither internet, cellular, nor a Wi-Fi router.
Does it require Google Play services or an account? No. There is no Google Nearby / GMS dependency — the radios are driven through framework APIs — and there are no accounts, sign-ups, phone numbers, or servers.
If it's offline, why does the app declare the INTERNET permission?
Because Android gates local sockets behind it. Wi-Fi Aware forms a direct radio link between two phones
and runs a TCP socket over that local link (link-local IPv6, no router or gateway), and a big-file
transfer does the same over a Wi-Fi Direct link the two phones raise between themselves — neither sends a
byte off the mesh, and either alone would require the permission. Two opt-in features use it for real:
the Internet relay plane, once you switch it on, and link previews, once you switch those
on — your own phone fetches a page's title and picture for a link you type and sends them with the
message, so the people you send to never contact the site. Both are off on a fresh install, which
therefore makes no network calls at all. A call over the Internet and a relay's free ticket both go
through the relay plane, and the speech model for call transcripts is downloaded from getknit.app only
when you tap for it. (ACCESS_NETWORK_STATE is how the app checks that the default network actually
reaches the Internet before it opens any of these sockets, so a phone that is only on the mesh never
tries.) Knit bundles no analytics or telemetry, and a crash is
kept on the phone for you to copy into a bug report, never uploaded. The same goes for the field log, which is off
unless you turn it on in Diagnostics: a three-day record of how your radios behaved, with no names, messages
or ids in it, that you can share if you want to help tune Knit. You can confirm all of it from the source and the deliberately
GMS-free dependency list.
Why does the app declare the location permission?
For two things, and it only ever asks for the permission when it needs one of them. On Android 10–12,
finding peers over Wi-Fi Aware and Bluetooth LE requires it, so onboarding asks there — on Android 13+ it
does not, and onboarding stays location-free. And for Send location, in the menu at the top of a
chat: it reads your position once, between that tap and the send, shows you what it found, and puts it in
the message as a geo: line the other phone draws as a card and can open in any maps app. That is the
only place the app reads your position, never at start and never in the background. The first tap
explains it, then lets Android ask.
How far can messages travel? Further than any one radio reaches. Each phone relays for the others, so a message hops device to device across the mesh, and a store-and-forward layer carries it onward to people who only come into range later. Pair a Meshtastic LoRa board and the Nearby room and 1:1 messages get hops measured in kilometres on top of that.
Are messages encrypted? 1:1 direct messages and group chats are end-to-end encrypted (only the intended recipients can read the body, mentions, and attachments; relays carry only ciphertext), and between phones on a current build they are forward-secret: the keys rotate as the conversation goes on and old ones are deleted, so recording traffic today and getting hold of a phone later does not open the older messages. Delivery receipts and reactions are encrypted too. The public "Nearby" broadcast room is plaintext by design, since it has no fixed recipient set. The local database is encrypted at rest with SQLCipher.
Can I call someone? Yes: 1:1 voice calls over a Wi-Fi Direct link to someone nearby or over the Internet to someone further away, and a walkie-talkie over the mesh when neither path exists. See Calls.
What phones does it support? Android 10 (API 29) and newer, with Wi-Fi Aware and/or Bluetooth LE. Almost all phones have BLE; Wi-Fi Aware is on Pixel 3+ and many recent devices. A phone with only one of the two radios still meshes over it. An iPhone port, Knit for iOS, speaks the same protocol and links with Android phones over Bluetooth LE; it is headed for the App Store and not released yet.
Is it free and open source? Yes — Knit is free software under the GNU General Public License v3.0 or later. There are no ads and no tracking, and Knit is funded by its supporters (see Support Knit).
How is it different from Bridgefy / Briar / Meshtastic? Knit runs two radios at once (Wi-Fi Aware + Bluetooth LE) behind a single transport seam, has no Google Play services dependency, end-to-end encrypts DMs and groups, and needs no hardware beyond an Android phone — where Meshtastic needs a LoRa radio. Meshtastic is complementary rather than a rival: pair one of its boards over Bluetooth and Knit carries the Nearby room and 1:1 messages across it, kilometres past phone-to-phone range, for every phone meshed with yours. Group chats and attachments stay on the phone mesh or an optional relay, and the radio sits idle until you pair a board.
AGENTS.md — build/test commands, toolchain constraints, architecture, conventions, and
the hard-won gotchas (start here before changing build config, the mesh layer, or the DI graph).docs/ARCHITECTURE.md — detailed design: mesh algorithm, wire protocol, data
flow, background survival, build-tooling decisions, and testing strategy.docs/WIRE_COMPAT.md — the wire format's compatibility contract and break
record; read before changing any wire type.docs/FORWARD_SECRECY_RATCHET.md — the DM ratchet: keys and
derivations, epoch advance rules, session races and reset, and an honest account of what a device
compromise still exposes.docs/GROUP_FORWARD_SECRECY.md — the group sender-key scheme built
on those DM sessions, including seed distribution, recovery, and what a member's departure costs.docs/ENCRYPTED_RECEIPTS_REACTIONS.md — receipts and
reactions as sealed control frames, and the store-and-forward trade that came with them.docs/SPOOL_PROTOCOL.md — the normative spec for the optional Internet
relay plane ("spools"): scope derivation, sealing, the relay protocol, and test vectors.docs/CONTACT_CARD.md — the contact card behind QR codes and share links:
layout, golden vectors, and what importing one does and does not establish.docs/RELAY_INVITE.md — the relay invite link (): what one
carries, why it is a bearer link, and the consent sheet it is only ever applied through.Implemented & verified: broadcast room · 1:1 DMs · multi-member group chats · profiles · reactions ·
mentions · photos, videos, files and voice notes · at-rest DB encryption (SQLCipher) · E2E encryption +
identity verification for DMs and groups · forward secrecy for both (an epoch ratchet for DMs, a
sender-key ratchet for groups) · encrypted delivery receipts and reactions · dual Wi-Fi Aware +
Bluetooth LE transports behind MeshTransport (no GMS) · store-and-forward delay-tolerant
delivery · key-request / retransmit for messages received before a sender's key is known · contacts
by QR or shared link · on-device toxicity + NSFW moderation · offline app sharing · big files phone
to phone over Wi-Fi Direct · voice calls, with a walkie-talkie over the mesh and on-device
transcripts · search across chats, contacts and messages · the Your mesh screen · drafts ·
backup and restore · low-power mode.
Shipped, and off until you turn it on: a Meshtastic LoRa bridge carrying the Nearby room and 1:1 DMs kilometres past phone range, Internet relays, link previews, and sending your location.
The relay layer is the largest of those. It carries DMs and group messages, and their photos and files,
between contacts you already have when no radio path exists, keeping the mesh's delay-tolerant behaviour and running through small
relays ("spools") that hold sealed frames without learning whose they are or what is in them. Turning it
on takes an explicit consent sheet in the relay settings screen that spells out what a spool can see —
your IP address, when you send, and roughly how much — and what it cannot: your messages, who you are
talking to, or who else is in a group. A relay's operator can hand you their relay as one invite link
(getknit.app/r); it opens the same sheet before anything is added. Until you say yes, a fresh install
makes no network calls at all. Some relays carry photos and files only for phones holding a ticket from
their operator; where the operator gives out free ones, Knit fetches one on the days it sends something
through that relay, and a switch in Internet relays turns that off. The protocol is specified in docs/SPOOL_PROTOCOL.md with executable test
vectors; the client implements it, and the reference spool daemon lives in
getknit/knit-spool. Knit is built around proximity meshing
either way.
In preview, debug builds only: a Wear OS app with a tile and five complications that read the mesh from your phone (On your watch).
Explicitly deferred (don't start without direction):
Direct and group messages are end-to-end encrypted. Each message's content (body, mentions, attachments) is sealed with AES-256-GCM and the whole envelope is signed with the sender's Ed25519 key. Relays, which flood every message hop-by-hop, only ever see ciphertext, and only the addressed recipient(s) can decrypt. Each device's identity keypair is generated on first run and stored wrapped under a hardware-backed AndroidKeyStore key, outside the database.
Between current builds the encryption is forward-secret. A DM session starts from an X3DH-style
handshake against a signed prekey the peer publishes in their profile, then rekeys per epoch: each
side mints a fresh X25519 pair as the conversation turns over, and message keys are deleted once used.
Group chats layer a sender-key ratchet on those DM sessions, so every member drives their own chain and
distributes its seed inside sealed DMs. Taking a device's identity key therefore no longer opens the
whole archive; what a compromise exposes is bounded by how long the ratchet keeps state, and
docs/FORWARD_SECRECY_RATCHET.md §9 and
docs/GROUP_FORWARD_SECRECY.md §9 state exactly what stays
recoverable and for how long. Delivery receipts and reactions are sealed the same way, so an observer
cannot read when a DM landed or who reacted to what.
Peers' keys are pinned on first use (TOFU); if a peer's key later changes, verification is reset and flagged. Confirm a contact's key out of band — compare the safety number in person or scan their QR code — to defend against a relay substituting keys.
Caveats: the public Nearby broadcast room is plaintext by design (no fixed recipient set), and its receipts and reactions stay cleartext with it. Forward secrecy is epoch-granular, not per-message — a bounded window of messages shares one compromise fate. A conversation with a phone that hasn't updated falls back to the older static-key scheme, which has none; one member on an old build pins a whole group to it, and a group's info screen says which scheme it is on. Relays still see who is talking to whom and how often, since DMs flood the mesh rather than being routed. On a paired LoRa board the content stays sealed, but a DM's sender, recipient, timing, and size ride the board's shared rendezvous channel at kilometre range — Private messages over LoRa on the radio screen turns that off while the Nearby room keeps going. The at-rest database is encrypted with SQLCipher.
To report a vulnerability, see SECURITY.md — please do not open a public issue for
security problems.
Knit is free and open source, with no ads and no tracking. Most of the help it needs costs nothing:
Knit is also funded by its supporters, through GitHub Sponsors and Ko-fi. Knit is its developer's full-time job. Supporters help pay their bills and keep Knit's servers running.
Liberapay supports the developer directly, and carries no supporter perks.
Knit thanks its supporters with a supporter badge in the app and with Knit Anywhere: calls through Knit's own call relay (a TURN server), and larger files in chats over Knit's free public relay. Relaying calls and storing files costs real money for every person who uses them, so Knit offers them as a thank-you to the people who pay for them. The level that comes with them is on the supporter page.
Everything else is free for everyone: the app, nearby messaging, messages over the internet, calls wherever a direct path exists, and small files over Knit's public relay. Anyone can also run knit-spool (AGPL-3.0-or-later), the software behind Knit's own relay, with any attachment size and their own TURN server, unrestricted. Knit is GPLv3 and stays that way.
Knit is free software, licensed under the GNU General Public License v3.0 or later
(COPYING).
Copyright (C) 2026 Jeffrey Walter Mixon
This program is free software: you can redistribute it and/or modify it under the terms of the
GNU General Public License as published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not,
see <https://www.gnu.org/licenses/>.
Contributions are welcome under the same license — see CONTRIBUTING.md, which
also sets out the (deliberately modest) support expectations.
Knit redistributes third-party open-source libraries, all under GPL-compatible licenses (Apache-2.0,
BSD, MIT) and with no Google Play services; see THIRD-PARTY-NOTICES.md for
the full component list and their licenses. The same list ships in the app (Open-source licenses, from
the menu on the Settings screen) with every license text readable offline, and a test pins it to both
that file and the release classpath so the two cannot drift.
The on-device moderation models and data bundled under app/src/main/assets/moderation/ are third-party
works, redistributed under their own licenses (full notices in
app/src/main/assets/moderation/README.md):
unbiased-small, ALBERT albert-base-v2), used under the Apache License 2.0.nsfw_model
(MobileNetV2), used under the MIT License, © 2020 The nsfw_model Developers.app/src/main/assets/emoji/) — generated from Unicode's
emoji-test.txt (Emoji 17.0), used under the
Unicode License v3, © Unicode, Inc. (full notice in
app/src/main/assets/emoji/README.md).See docs/CONTENT_MODERATION.md for how they are used.
geo: line the other phone opens in any maps app — the only place the app ever reads
where you are.docs/CONTENT_MODERATION.md.Draft: until it goes.adb./gradlew :app:pixel7api33DebugAndroidTest -PseedDemo=true \
-Pandroid.testInstrumentationRunnerArguments.package=app.getknit.knit.uiauto
Drop the -P…package filter to run the seeded Compose suite alongside it, or submit the same APKs to Firebase
Test Lab for the isolated physical-device pass. (Run a single class with
…arguments.class=app.getknit.knit.uiauto.OverflowNavigationUiAutomatorTest.)
Accessibility (ATF) suite — app/src/androidTest/…/a11y/ runs Google's Accessibility Test Framework,
the same checks behind the Play Console pre-launch report, over every seeded screen: missing labels,
small touch targets, and (on a physical device) text and image contrast. Errors fail the run; every
finding is written out per screen. It needs API 34+, so run it with the pixel8api34 managed device or
on Firebase Test Lab (…arguments.package=app.getknit.knit.a11y).
Screenshot tests — every public @Preview is rendered and compared against a reference PNG with
./gradlew :app:validateDebugScreenshotTest, on the JVM with no device. After changing a preview,
regenerate the wrappers with scripts/gen-screenshot-tests.py, re-render with
./gradlew :app:updateDebugScreenshotTest, and review the PNG diff before committing.
getknit.app/rdocs/CONTENT_MODERATION.md — on-device abusive-text / explicit-image
moderation: design, hook points, and the bundled models.docs/BACKUP_FORMAT.md — the backup file: what it carries and leaves out, how
the recovery key seals it, and how a restore is staged.docs/FIELD_LOG.md — the opt-in field log: every event it records, and why none
of them can name a person.docs/SUPPORTER_BADGE.md — the supporter badge: the credential, how a
phone carries it, and how every receiver checks it.docs/VOICE_CALLS.md — voice calls (a draft spec): signaling, TURN from relays,
the Wi-Fi Direct leg, the walkie-talkie, the audio route, and transcripts.