I built a forum with no interface, no passwords, made for the terminal
I like forums. Debates, questions, answers, opinions, etc. That feeling of an asynchronous community, where answers are thought through and content lasts, is what makes the internet an interesting place. That is why I like reading them and taking part in them. But I had never designed or built one. In my spare time I started sketching one, and I ended up building my humble headless, federated forum, with simple, modern technologies and open standards.
And I learned a lot along the way. A forum looks simple, but it hides the classic problems of any server. Who can do what? How do you tell a moderator from a regular user? What happens when you have to ban someone? How do you stop someone from stealing an account? Roles, permissions, bans and security. I had to solve them one by one, and you don't learn that by reading.
Let me tell you how I made Tyrtulia.
A forum with no interface
The server only offers a solid, documented API. It is REST with hypermedia: the client only knows one route, GET /, and discovers everything else by following links. Underneath there are some very boring standards:
- RFC 9110: HTTP semantics, with
ETagandIf-Matchso edits don't overwrite each other. - RFC 9457: errors.
- RFC 7396: partial updates with
PATCH. - RFC 6570: URL templates.
- RFC 4287: Atom feeds.
- RFC 9562: UUIDv7 identifiers.
- JSON Schema: validation.
- Server-Sent Events: real-time events.
There is no web interface, no forms, no advanced authentication systems, no file handling (images, attachments, etc.), and nothing that isn't strictly needed to read and write messages.
That is why it is so light. It uses between 60 and 70 MB of RAM and about 50 MB of disk. It only needs Python and SQLite to run.
An API that discovers itself
How does a client know what it can do? The server tells it with links. Look at the same request, GET /, made by a guest (simplified):
{
"name": "Forum of example.org",
"_links": {
"self": {"href": "/", "method": "GET"},
"latest": {"href": "/threads", "method": "GET"},
"search": {"href": "/search{?q,author,in}", "method": "GET", "templated": true},
"login": {"href": "/sessions", "method": "POST", "schema": "/schemas/session"}
}
}
And now by alice, logged in:
{
"name": "Forum of example.org",
"_links": {
"self": {"href": "/", "method": "GET"},
"latest": {"href": "/threads", "method": "GET"},
"search": {"href": "/search{?q,author,in}", "method": "GET", "templated": true},
"createThread": {"href": "/threads", "method": "POST", "schema": "/schemas/thread"},
"notifications": {"href": "/notifications", "method": "GET"},
"events": {"href": "/events", "method": "GET", "type": "text/event-stream"}
}
}
If I change a route tomorrow, no client breaks, because none of them knew it in advance. They just follow the links the server gives them.
Why not use one that already exists?
I know there are very complete free software forums:
- Discourse: the most popular one today.
- Flarum: PHP with MySQL.
- NodeBB: Node.js, with MongoDB, Redis or PostgreSQL. It stands out for real time with WebSockets.
Or the good old classic: phpBB.
They are all fantastic, but they are designed to be used from a web browser. They also have an ambitious scope. That is ideal for large communities, but too much for a small, light forum.
That said, Tyrtulia doesn't give up on the browser: it can be indexed by search engines and anyone can read it on the web.
No passwords
No OAuth, no OpenID, no sign-up forms. There are two ways to authenticate:
- Your Unix user: the client talks to the forum through a Unix socket. The operating system tells the forum which user is on the other side. No sign-up, no login. Your user is your account.
- SSH key: the client connects over HTTP and the forum sends it a challenge. The client signs it with your private SSH key and the forum verifies it with your public key.
There is no registration over HTTP. If you have a Unix user on the server, you already have an account: it is created the first time you connect through the socket. From there you can add your SSH keys to log in from outside. If you don't have a user on the machine, the administrator creates an account for you with your public key from the command line. On a tilde, having a Unix user is already the invitation.
Easy to use, secure, and no passwords to steal.
What changes compared to BBJ
The idea isn't mine. I was inspired by BBJ, a bulletin board for the terminal built for small communities or clubs (tildes, pubnixes, club servers, etc.). I took its spirit and brought it to my own ground. Still, there are important differences.
First, the foundations.
| BBJ | Tyrtulia | |
|---|---|---|
| API style | RPC: everything is POST /api/<endpoint> |
REST with hypermedia (HAL): only GET / is known |
| Permissions | The client asks (is_admin, edit_query) |
Links that appear or disappear |
| Authentication | Unsalted SHA-256 hash of the password on every request | No passwords: Unix socket or SSH-signed challenge |
| Errors | 6 custom numeric codes | RFC 9457 with a catalog of types |
| Pagination | Everything at once | Cursor based |
| Concurrency | The last edit wins, silently | ETag and If-Match |
| Text format | Custom language ([bold: ...], [red: ...]) |
Standard Markdown |
| Validation | A db_validate endpoint |
JSON Schema linked from each form |
| Configuration | config.json |
TOML |
Then, the features I missed.
| BBJ | Tyrtulia | |
|---|---|---|
| Reply to a specific post | >>N quotes in the text |
Linked replies, with a tree view |
| Mentions | No | Yes |
| Notifications | No (pending since 2017) | Inbox with replies, mentions and alerts |
| Real time | No, you have to poll | Server-Sent Events, with resume |
| Edit history | No, editing overwrites | Full, with diffs and revert |
| Deletion | Deletes the row | Tombstone: numbering is preserved |
| Search | Each client searches what it has downloaded | Server-side full text, accent and case insensitive |
| Feeds | No | Atom for the forum and each thread |
| Moderation | Admin or not | Roles, hidden posts, reports and a public log |
| Rate limiting | No | Per user and per IP |
What they share is a small server built on SQLite and several text clients against a documented API.
Clients
A headless forum needs clients, no way around it.
Tyrtulia TUI
Tyrtulia TUI is the terminal client, built with Textual.
:quality(85)/https://andros.dev/media/blog/2026/10/tyrtulia-tui-thread.png)
tyrtulia.el
If you know me a little, you know this package was a must: tyrtulia.el.
:quality(85)/https://andros.dev/media/blog/2026/10/tyrtulia-el-thread.png)
Tyrtulia Web
Tyrtulia Web is more a mirror of the content than a client. Its goal is to let search engines index the forum and let anyone read it from a browser.
:quality(85)/https://andros.dev/media/blog/2026/10/tyrtulia-web-thread.png)
It has an unstyled theme and another one that mimics my website.
Federation
You can connect to one forum or set up several. Federation happens in the clients: servers don't talk to each other or copy messages between them. Each forum is independent, with its own users, rules and moderators.
Instead of splitting them into tabs or accounts, the clients mix the threads of all of them into a single list.
:quality(85)/https://andros.dev/media/blog/2026/10/tyrtulia-el-forums.png)
Of course, you can only write in the forums where you have an account. In the rest you can only read.
I think it's a pretty cool feature, because it keeps the API code much simpler and lets you explore other forums at zero cost.
Try it
It has been fun to design and build. Of course there are more complete forums, more powerful federation systems, and even decentralized systems that leave Tyrtulia in the dust (Aether, Nostr...). But its niche is very specific: a light, closed-access, federated, indexable, secure forum with text clients. For everything else, there are better things out there.
If you feel like trying it, the installation guide is in the Tyrtulia repository.
I look forward to your feedback.
- A forum with no interface
- An API that discovers itself
- Why not use one that already exists?
- No passwords
- What changes compared to BBJ
- Clients
- Tyrtulia TUI
- tyrtulia.el
- Tyrtulia Web
- Federation
- Try it
This work is under a Attribution-NonCommercial-NoDerivatives 4.0 International license.
Help me keep writing
Every coffee gives me a push toward the next article.
Sure, it's on me!
Comments
There are no comments yet.