════════════════════════════════════════════════════════════════════════════════
 Node 1  ·  2400 baud  ·  40 msgs in 6 areas  ·  sysop randogoth
════════════════════════════════════════════════════════════════════════════════
════════════════════════════════════════════════════════════════════════════════
 Msg  : smolmail-clients                             Area : MINIMAL
 From : randogoth                                    Date : 13 Oct 2026
 Subj : Browser, Desktop and Phone smolmail Apps Keys : smolmail, rust, flutter
 Msg  : smolmail-clients
 Area : MINIMAL
 From : randogoth
 Date : 13 Oct 2026
 Subj : Browser, Desktop and Phone smolmail Apps
 Keys : smolmail, rust, flutter
════════════════════════════════════════════════════════════════════════════════

The last post ended on fumi-core, the Rust library underneath the reference client, and on the claim that everything in this post would be built on it. That turned out to be two thirds true, and the exception is the interesting one.

gsmol runs in a browser. There is no Rust in it at all: the sealing, the signing and the Noise handshake are reimplemented in JavaScript, about a thousand lines across crypto.js, noise.js and proto.js, because a browser tab cannot open a TCP socket and I wanted the client to be just a page. The Python part, bridge.py, is 154 lines and does nothing but relay bytes. It never sees a key and never sees a plaintext. The bridge binds to 127.0.0.1 and has no TLS of its own. That is fine on your own machine and nowhere else. That's a feature, not a limitation.

gsmol in a browser tab, light theme: a sidebar with Write, Inbox, Requests, Sent and contacts, three replies from kimmy@smol.place in the inbox, and the open one showing its message id, a green verified sender key badge and the sender's smol:// reply-to address

carrier is the desktop client, Rust on fumi-core, and it has been rewritten once already. It started on Iced, and then moved to GTK4 with Relm4 and libadwaita. It is at v0.2.0 now, with a Flatpak and a Windows installer built by CI, and the Flatpak sandbox keeps its config under ~/.var/app/com.randogoth.carrier, so installing it gives you a fresh identity. Closing a compose window from the sidebar saves it as a draft instead of losing it, custom Key: value headers are checked against the frontmatter rules and cannot override carrier's own fields, and strict first contact makes it pause before writing to a new address that carries no key, offering to fetch and pin the server's key so you can compare it against what the operator published.

carrier on the desktop, dark GTK4 window: Fetch and Write buttons over Inbox, Requests, Sent and Drafts, a contact list marked accepted or verified, five messages in the inbox and the open one, "lunch on friday?" from bob@example.org, with Reply and Delete below it

kirakira is the phone (plus desktop!), Flutter, at v1.0.0, and it is fumi-core again by a longer route: a Rust wrapper crate exposes a C ABI, that ships in the APK as libsmol_mail_native.so with SQLite bundled, and dart:ffi speaks to it from the Dart side. Addresses move around by QR code, and any smol:// link a camera or browser hands the device lands in a confirm-first import dialog. The on-device tests run under Patrol against a live local bunshin, driving onboarding, registration, fetch cancellation and key rotation on a real device, in an install that sits beside the real app with its data cleared between runs.

kirakira running as a desktop window, dark theme: a rail with Mail, Contacts and Settings, Inbox, Requests and Sent tabs, QR code and backup icons in the corner, and an empty inbox with a hand-drawn green mailbox above "Nothing here yet!"

Credit where it is due: kirakira began as FlashMail by sarthakkimtani, a Flutter UI template for a disposable-email app built on mail.tm. The protocol underneath it was replaced entirely, the UI it started from is why the thing looked finished long before it was.

The one invariant all three ended up sharing wasn't planned. In each of them the 32-byte seed is the only secret, it is shown exactly once at creation, and no backup file contains it. kirakira reads gsmol's v2 encrypted export, so a backup written in a browser restores on a phone. Three UI stacks agreed about that without being told to, which is a better argument for the protocol being the right size than anything in the spec.

Nine days ago smolmail was just one Python file for a server and one for a client, and what the protocol did was whatever those two files did. It isn't that any more. A browser tab, a GTK window and an Android app now disagree about nearly everything above the wire and about nothing on it.

Repository

gsmol · carrier · kirakira

--- RANDOGOTH BBS
 * Origin: randogoth.com (1:1/1)
────────────────────────────────────────────────────────────────────────────────
 [I]ndex   [K]eywords   [F]eed   Main [M]enu   
Command: