ChatTy — Terminal Chat App
A terminal-based, peer-to-peer chat app for Ubuntu & macOS — first hand-built solo before AI coding tools, now re-engineered from scratch in Go with AI-assisted workflows. A deliberate before/after in one project.
- Go
- PostgreSQL
- MQTT
- SQLite
- Bubble Tea
- goreleaser
ChatTy is the project I’m proudest of as a pure engineering exercise — first designed and built entirely by hand, solo, before AI coding tools were part of how I work. Every piece, from the backend to the terminal client to the cross-platform packaging, was reasoned through from first principles. It’s now getting a ground-up rebuild — same architecture, a sharper stack.
What it is
A real-time chat app that runs in the terminal on Ubuntu and macOS. Users register and log in from the command line, exchange a short token, and talk directly with each other — no GUI, no fuss. The backend is deliberately kept out of the message path: it only handles accounts and sets up the chat, so it never sees message content.
The original build (by hand)
- A signalling backend in Node.js / Express + MongoDB — accounts, JWT auth, and chat provisioning — deliberately kept out of the message path.
- A peer-to-peer message layer over MQTT — once a chat is established, messages flow directly between the two clients on paired directional topics; the backend only relays the initial request.
- A Python terminal client — health checks, register / login, token exchange, and a threaded live send/receive loop.
- Cross-platform packaging — Debian packages, a systemd unit (Linux), and a launchd plist (macOS), with install scripts.
Re-engineering it in Go
Keeping the zero-knowledge, peer-to-peer architecture intact, I’m rebuilding the implementation from scratch on a stack that fits a distributed CLI far better:
- A Go terminal client — a single static binary (Charm’s Bubble Tea TUI, local SQLite history), cross-compiled to Ubuntu and macOS from one machine. This deletes the old PyInstaller packaging and the Node file-watcher supervisor the Python client relied on.
- A Go + PostgreSQL signalling backend — one language across client and server with shared
domain types, compile-checked SQL via
sqlc, and real transactions for token issuance. The data was always relational, so Postgres replaces MongoDB. - A private, authenticated, TLS MQTT broker — moved off the public test broker onto a hardened, self-hosted Mosquitto (auth + TLS), deployed with an end-to-end runbook covering the two-firewall and DNS gotchas that make cloud brokers hang.
- One-command distribution with goreleaser → GitHub Releases + a Homebrew tap, retiring the legacy apt-repo and manual packaging.
What’s next
End-to-end encryption, secrets moved fully into the environment, local chat history and search, and one-line installers. A deliberate before/after: a hand-built foundation, now accelerated with AI-assisted development. Packaged installers will land under Products.