█████▄ ▄███▄ █▓▄██▄ █▓███▄ ▄███▄ ▄█████ ▄███▄ ███▓██ ██ ██ ▓▒ ▀▒▓ ▓▒▀ ▀▒▓ ▓▒▀ ▀▒▓ ▓▒ ▀▒▓ ▓▒▀ ▀▒▓ ▓▒▀ █▒ ▓▒▀ ▀▒▓ ▓▒ ▓▒ ▒▓ ▒░ ░▒ ▒░ ░▒ ▒░ ░▒ ▒░ ░▒ ▒░ ░▒ ▒░ ▒░ ░▒ ▒░ ▒░ ░▒ ░ ▄ ▀ ░ ░ ░ ░ ░ ░ ░ ░ ░ ██░ ░ ░ ░ ░ ░ ░ ▄ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░▒ ▀▒░ ░▒ ▒░ ░▒ ▒░ ░▒ ▒░ ░▒ ▒░ ░▒ ░▒ ░▒ ▒░ ░▒ ░▒ ▒░ ▒▓ ▓▒ ▒▓ ▓▒ ▒▓ ▓▒ ▒▓ ▓▒ ▒▓ ▓▒ ▒▓ ▓▒ ▒▓ ▓▒ ▒▓ ▒▓ ▓▒ ▓█ █▓ ▓█ █▓ ▓█ █▓ ▓█ ▄█▓ ▓█▄ ▄█▓ ▓█▄ █▓ ▓█▄ ▄█▓ ▓█ ▓█ █▓ ██ ██ ██ ██ ██ ██ ██████▀ ▀███▀ ▀█████ ▀███▀ ██ ██ ██
════════════════════════════════════════════════════════════════════════════════
Node 1 · 2400 baud · 36 msgs in 6 areas · sysop randogoth
════════════════════════════════════════════════════════════════════════════════
════════════════════════════════════════════════════════════════════════════════
Msg : itsybitsy Area : MINIMAL From : randogoth Date : 06 Oct 2026 Subj : One Document, Five Front Doors Keys : rust, itsybitsy, gemini
Msg : itsybitsy
Area : MINIMAL
From : randogoth
Date : 06 Oct 2026
Subj : One Document, Five Front DoorsKeys : rust, itsybitsy, gemini
════════════════════════════════════════════════════════════════════════════════
Gopher predates the web it sometimes gets mistaken for a joke about. It's 1991: plain menus, plain text, nothing styled because there was nothing to style with yet. Gemini Protocol and her feral little sister Spartan aren't that old, they are from the last decade, built by people who looked at the modern web and wanted the opposite of it on purpose: no tracking, no JavaScript, nothing a server can do but hand over a document.
WAP is neither of those things. It is what made the web accessible to dumbphones before the smartphone existed, and some of them are still switched on somewhere. And even if not, it's a handy minimalist format that I think should still be used today.
Being able to serve the same content to all four of those rebellious formats, plus ordinary HTTP (WAP 2.0!), from one source, is the idea itsybitsy exists to prove.
It parses a folder of Markdown once into a single internal representation, then hands that to whichever renderer the request calls for: gemtext, WML, plain wrapped text, or ordinary X-HTML. A Gemini client, a feature phone and a browser can all point at the same site and never know the others also exist.
This isn't the first attempt at the idea: smolweb, the direct predecessor, did the same job in Python, built on two libraries from an earlier project, md2txt, that I had already written to turn Markdown into all kinds of esotetic text formats. Living with smolweb for a while found the actual seams. md2txt shipped two different text renderers, one that inlines links and one that numbers them.
Two separate libraries meant two incompatible ways to write a directive in the Markdown itself, one card-and-include syntax for WML and one MultiMarkdown attribute syntax, neither aware the other existed. And parsing once per output format, instead of once per document, meant a table that worked in HTML silently vanished in the text and Gopher output, because that parser had never been taught tables existed. You see, this all escalated into more and more PITA.
itsybitsy is the overdue rewrite that treats those as bugs rather than quirks. One renderer, not two. Markdown's own syntax for everything a document actually needs, instead of two invented grammars for the same handful of things. One parse feeding every format, so a table or a piece of ASCII art shows up everywhere it can be shown, not only in whichever format's renderer happened to support it.
What it deliberately does not do, is terminate its own TLS. Gemini wants encryption, and itsybitsy expects something else to have handled that before a request reaches it: a real terminator ("I'll be back!"). Building a TLS stack to save someone a reverse proxy wasn't worth it, and the README openly owns it.
Four protocols invented across four different decades, each for its own reason, served from one Markdown file each time. That's the whole "smolnet" idea in one sentence, and it took several implementations to get it right.
--- RANDOGOTH BBS * Origin: randogoth.com (1:1/1)
────────────────────────────────────────────────────────────────────────────────
[I]ndex [K]eywords [F]eed Main [M]enu
Command: