/003

CleverKeys

“What if one person could ship a swipe keyboard that competes with the platform vendors’, and never phones home?”

Shipped Open source On-device ML · Android

// The question

Gesture typing is one of those features everyone assumes requires a platform company. Google and Microsoft ship it; the open-source keyboards mostly don’t, or do it badly, and the good ones route your keystrokes through someone else’s servers. The implicit belief: a swipe decoder that feels right needs a research team, a data pipeline, and a datacenter.

We wanted to know whether a single engineer could build one that holds up against the incumbents in daily use, with the model, the training data, and the app all public, and with the keyboard physically unable to transmit anything.

// The constraint

A swipe decoder is a real ML problem with real latency limits. The gesture has to become a word in well under a quarter of a second, on a phone, on the CPU, with no round-trip. It needs training data for every language, a tokenizer, a beam search, and an answer for every script the model was never trained on. Then it has to survive the Android input-method contract, which is hostile in its own special ways. Terminal emulators, for instance, corrupt or crash most keyboards’ swipe input.

Every one of those is individually tractable. Together they are the reason the field has been ceded to companies with keyboard departments.

// The attack

Build the whole stack in the open and make the privacy claim structural rather than promissory. The app requests zero network permissions. Not “we don’t collect,” but “the OS won’t let it.” Start from a proven open keyboard (Unexpected Keyboard) so the IME plumbing is inherited, and spend the effort where it matters: a CTC encoder with trie-constrained beam decoding whose model carries no alphabet at all. Keys are embedded from their own coordinates rather than their index, so one file decodes QWERTY, Dvorak or Cyrillic. Beside it runs a second, co-equal decoder: a from-scratch geometric matcher that needs no training data and serves every script the model does not.

Publish the training pipeline alongside the app so that every weight in the shipped model can be reproduced end to end. That’s not a nicety. It’s the difference between a keyboard you trust and one you’re asked to.

// The leverage

  • On-device inference runtimes. ONNX Runtime with XNNPACK makes a 2.9 MB fp16 model fast enough on a phone CPU that the “needs a server” argument simply evaporates.
  • Open ML tooling. Training a CTC gesture model is now a solved recipe with public tools; the expensive part was never the math, it was the willingness to publish the pipeline.
  • Inherited plumbing. A GPL keyboard base meant the boring, brutal IME integration was already done. Fork the plumbing, replace the brain.
  • Modern distribution. Reproducible builds plus Obtainium and F-Droid mean a one-person project ships signed releases to phones the moment they’re cut, with no store gatekeeper.

// The build

A complete Android keyboard, 100% Kotlin, GPL-3.0: on-device CTC swipe decoding, 208 customizable swipe gestures (eight directions per key, per layer), an unlimited clipboard that survives reboots without root, and fifteen languages, two active at once. The identical model file runs in a WebAssembly demo in the browser, byte-compared against the app’s own copy on every deploy, so anyone can watch the beam search unfold without installing anything. The model, tokenizer, datasets, training loop, and test harness are all public in a companion repo.

cleverkeys.app: CleverKeys landing page showing the on-device gesture keyboard and its specs
FIG. 003-1 · cleverkeys.app. Signed, reproducible APK; the web demo runs the identical decoder in WASM.

// The failures

  • The first decoders were accurate and too slow. Sub-200 ms on a mid-range phone was the line between “works” and “unusable,” and reaching it meant quantization, a trie to prune the beam, and abandoning anything that couldn’t run on XNNPACK.
  • The obvious design was broken in a way no amount of training could fix. Sampling a fixed cosine field at the 26 QWERTY key centers yields a rank-23 basis, leaving three emission directions structurally unreachable at any width, depth or dataset size. It was found by inspecting singular values, not by training longer.
  • Terminal emulators broke everything. Getting reliable swipe input inside Termux took dedicated work that no other open keyboard has bothered with, which is exactly why it became a differentiator.

// The result

Shipped, in daily use, and installable in under a minute. A test fails the build if median decode passes 150 ms or p90 passes 250 ms on a Pixel 7, measured through the production path. Zero network calls, because the app has no permission to make any. In our own use it holds up against the vendor keyboards on the thing that matters, swipe accuracy, and beats them outright on privacy, openness, and working inside a terminal. Version 1.3 added media clipboard, profiles, and short-swipe customization.

// The implication

“Only a platform company can ship that” is now a testable claim, and for gesture typing it tested false. One engineer, open tooling, on-device inference, and a distribution channel that doesn’t need permission. The same shape applies to a long list of features currently assumed to require a cloud and a department, and the privacy story gets stronger as the team gets smaller, because there is nobody to sell the data to.

Notebook The keyboard can’t phone home. That sentence used to be a promise. Now it’s a manifest entry.