← All work

achat and irc.austn.net

A terminal IRC client with a three-pane TUI, built for the IRC server I run.

I run an IRC server at irc.austn.net. It's Ergo, a modern IRC server in Go, behind TLS with a real certificate. IRC is old and it still works, and it's a nice thing for friends and bots to share.

achat is the client I wanted for it: three panes, channels on the left, messages in the middle, users on the right, and a prompt at the bottom. It connects over TLS, authenticates with SASL the way the protocol intends, reconnects cleanly, and stays out of the way.

achat in a terminal: channels pane on the left with #general selected, the message pane showing a join line and a hello message, a users pane on the right, the prompt at the bottom, and a key hint bar
Connected to irc.austn.net over TLS as a guest. The hint bar always shows what the keys do.

How it's put together

The protocol library never leaks past the service, so the state and the UI are tested without a network.
  • The protocol stays behind one wall. irc-framework handles parsing, capabilities and SASL, and a thin IrcService turns its events into a single typed union. Nothing else in the app sees the library.
  • The service owns membership. IRC's quit and nick events don't say which channels they touched, so the client tracks who is in each channel itself and re-sorts the user list by prefix on every change.
  • Secrets stay in one file, written with 600 permissions and ignored by git. Flags on the command line override it, but the password never goes on the command line.
  • The UI is tested headless with ink-testing-library, plus a smoke test that runs the real binary in a pseudo-terminal.

I wrote the brief and ran the build as an agent, and kept a DECISIONS.md with every choice, the reason, and the alternative that lost. It's a good way to build a small tool: the decisions are the part worth reading later.