Teletype BBS is the clubhouse of the Teletype Games BBS Network: a Telnet, Synchronet-style bulletin board with message boards, mail, chat and the doors that live only here.
Live at
teletypegames.org:2323
A Ruby app on the rubbs gem, our in-house BBS framework — it provides the ANSI interface, menubar, stacked modal windows, Telnet server and xterm mouse support. The teletype-bbs repo holds only the Teletype-specific parts: the domain (services wired to their stores), the windows and menus of the modern face, the PETSCII face, the doors and the characters.
The board was the first of the network, so once everything of Teletype Games was in it. Since 2026-11-01 it keeps the community and the doors that live only here; what another board carries is not repeated, the board only tells where it is:
| Looking for | Where it is |
|---|---|
| our games and files (C64, Plus/4; ZMODEM, XMODEM) | WarpEngine BBS, teletypegames.org:2329 |
| the wiki: guides, how-tos, the DOS corner | TTG Wiki BBS, teletypegames.org:2325 |
| the blog | TTG Blog BBS, teletypegames.org:2328 |
| ANSI and PETSCII art | Pixelia BBS, teletypegames.org:2332 |
| the debrief terminal of Definitely not an Impostor | Impostor BBS, teletypegames.org:2324 |
| Wikipedia, news feeds, books, the C64 game compendium | Alexandria BBS 2326, Feedia BBS 2327, Scriptorium BBS 2330, Commodex BBS 2331 |
| all of them from one port | TTG Gate BBS, teletypegames.org:2399 |
| the FTP tree for old machines | ftp.teletypegames.org, and on plain HTTP at archive.teletypegames.org |
Board > BBS Network (and Help > Where are the games, files, wiki?, N on the C64) shows them as the town map on the clubhouse wall, and the TTG Master answers the same.
Since 2026-11-01 the board looks like what it is, a clubhouse (see The clubhouse below). A call starts the old way: the modem dials and connects (CONNECT 38400/ARQ/V42BIS), then the caller stands at the entrance: the door under its lamp, the bell, the coats of the callers inside on the rack, and the open guestbook with the last three guests and the number of this entry (the caller number). The name (blank = Anonymous) and a registered name's password are written into the guestbook; any other name is a guest. Then the logon sequence: Welcome back, the caller number, your calls (first, last, time on line), and the scans of the old boards — new letters, new messages on each board since you last read it, polls waiting for your vote — and the quote of the day, a member's motto. ENTER opens the full-screen shell on the dashboard, the clubhouse from the street: a lit window for every caller inside, smoke from the chimney while the live chat talks, the mailbox flag for your letters, then who is inside, the notice board and the graffiti wall, refreshed every few seconds; Board > Dashboard closes every window and brings it back. While a menu is open, the bottom line tells what the highlighted item does. Every window wears the colour and the icon of its menu: Board pale teal ☼, Messages green ✉, People pink ☺, Doors salmon ♫, You grey ♥, Help yellow ¿. Board > Log off (Alt-X) puts the lamps of the clubhouse out one by one, with the coat ticket (the caller number and the time on line), a tagline, +++, ATH0, NO CARRIER.
The statusbar shows the node, the clock and the time on line.
The board
F1, the button in the desktop's corner, Help) — the sysop who answers callers' questions about the board: where things are, what is coming up, and which board of the network carries what this one does not. The code looks up the facts (a knowledge file of the menus and of the other boards, the latest releases, the events, the games), the model only words them, and the code checks that the wording kept the facts and invented no menu; if not, the caller gets the fact itself.Community
data/boards/. New posts use a multi-line TextArea, max 1000 chars. A registered name sees the number of its unread messages next to each board.F7) — private letters between registered names: Write, Reply, Delete. Feedback to the Sysop… is a letter anyone with a name can write; every sysop reads it. A letter arriving during a call rings the bell. The Discord feed gets only that feedback came, never what it says.lib/content/polls.yml; one is filled from the catalog (your favourite Teletype Games title), one from the doors. Results as bars; a name votes and can change its vote.TELETYPE_BBS_SYSOPS that logged in with their password.TELETYPE_BBS_DISCORD_WEBHOOK webhook, with mentions disabled.Doors — programs the BBS hands the telnet line to, and takes it back from when they exit (rubbs' BBS::Door). Only the programs that live here are doors. Doors > Games Room… shows them as the five stations at the back of the clubhouse, a lamp burning over each one somebody is in; Doors > Door Lobby… lists them with what each one is, the screen it needs and who is inside.
sermo gem): type a command, or just talk to it; EXIT returns to the BBS. What you say in words goes to its Lapis-ACP, a small local model (Qwen3.5 0.8B) with a persona from the 1977 canon; it is slow, short-spoken and sometimes wrong, on purpose and otherwise.READY. prompt (blue C64 screen, grey Plus/4 screen, 40 columns) with a small BASIC V2: 10 PRINT CHR$(205.5+RND(1)); : GOTO 10 draws the maze, any key is RUN/STOP. The disk holds our games for that machine: LOAD"$",8 then LIST shows the directory (block counts from the real .prg sizes in the FTP server's /WARP, as the catalog API carries no sizes), LOAD"NAME",8 (wildcards work) loads a game, LIST shows it and RUN prints its card with the catalog link. The Plus/4 also knows DIRECTORY and DLOAD; SYS 64738 resets the C64; EXIT returns to the BBS.RIDDLE asks a riddle of the pyramid, which the code checks (HINT, SKIP); solve three and Ra blesses you. GAME tells where the game is.lib/content/trivia.yml; the best ten games are its hall of fame.Technical
data/, a Docker volume, so they survive restarts.A Commodore 64 (CCGMS, StrikeTerm, SyncTERM in C64 mode, or a C64 behind a WiFi modem) gets the board in PETSCII, 40×25. The pictures (the entrance, the main menu, the town map, the games room, the trophies, the room cards, leaving) are drawn in the C64's uppercase/graphics set, the whole screen once and then only what changes; the reading screens (posts, letters, the chat, the bulletins, the Master) stay in the lowercase set. The main menu is the clubhouse: the house at the top, lit from the same scene as the modern face, who is calling and what comes next, and the rooms as a cursor menu: M Cork board, E Mailbox, O Graffiti wall, L Sofa chat, I Radio (IRC), P Ring the bell, U Notice board, D Workshop, C Guestbook, H Trophies, V Ballot box, S You, R Games room, N Town map, T Ask the bar (the TTG Master), Q Leave; ? help, Y system info. A reading room shows its card once a call. In the games room the C64 and the Plus/4 open; SERMO, Chat of Ra and TTG Trivia need 80 columns and are on the modern face. Our games come to a C64 by XMODEM from the WarpEngine BBS.
* swaps the pictures for the old menu of plain text and back; a caller whose name comes in capitals gets it at once, as UltimateTerm (the C64 Ultimate's terminal) in its ANSI mode swaps the case and cannot show the graphics.
The board is the clubhouse of the network: not a library and not a store — those are the other buildings of the town —, but the place where a caller sits down, signs the guestbook, sees who is in, leaves a note and plays a game at the back. Every big picture shows something of the board's own data (the nodes, the chat, the mail, the new posts, the doors in use, the guestbook, the events, the wall), the same on both faces; nothing is asked of the outside world, and the town map is static.
| Menu (modern) | Room (C64 key) | Live in the picture |
|---|---|---|
| the logon | the entrance: door, lamp, bell, guestbook | the last three guests, the entry number, the coats on the rack (the nodes) |
| Board > Dashboard | the clubhouse from the street | a lit window a node, the door and the lamp, chimney smoke (a chat line in the last minute), the mailbox flag and count |
| Messages > Boards… | the cork board (M) |
the new notes |
| Messages > Mail… | the mailboxes (E) |
the flag on the mailbox |
| Messages > Oneliners | the graffiti wall (O) |
the wall under the house |
| Messages > Live Chat | the sofa corner (L) |
the smoke |
| People > Who is Online, Last Callers | the guestbook (C) |
— |
| People > Hall of Fame | the trophy case (H) |
the names on the cups |
| Board > Bulletins…, Dev Log | the notice board (U), the workshop (D) |
— |
| Board > BBS Network | the town map (N) |
static |
| Doors > Games Room… | the games room (R) |
a lamp over each station in use |
| Help > Ask the TTG Master | the bar (T) |
— |
| Log off | leaving (Q) |
the lamps go out, the coat ticket |
The house follows the time of day in Budapest (dawn, day, dusk, night) and the season: snow from December to February, pumpkins in the last week of October, fireworks on New Year's Eve, bunting on the days of a game jam.







On the C64 the same rooms, drawn separately in PETSCII:







The pictures are rubbs' BBS::Art YAML under lib/content/art/, drawn twice, separately for each machine: modern/ in code page 437 and 256 colours, c64/ in the C64's uppercase/graphics set. The places the board fills from its data are the hotspots of a picture; the seasons are layers, one for each time of day. rubbs' art-preview checks a picture while it is drawn (ANSI on the terminal, the PETSCII bytes, a C64 screenshot). The town map reads lib/content/network.yml: every board with its name, port, building, colours and the place of its building; a new board is a row there and its two buildings (building_ID.yml, 12×4 and 3×3).
The C64 line is slow, so the pictures have budgets, measured with bin/c64-bytes: the main menu 1105–1123 bytes at every time of day and season (at most 1.2 KB), a move of its bar 146–205, a puff of smoke about 60, the entrance about 1.1 KB, the town map 1000 (a step 161–209), the games room 770, the trophy case 609, a room card 231–265, leaving 570 with the lamps going out in 29–78 bytes each.
Port 2323 is open to the internet, so telnet password-guessing bots call every few seconds and type root, admin and the like as their name. Until 2026-10-20 all of them landed in the last-callers list. Now:
., _ and -; anything else (GET / HTTP/1.1) becomes Anonymous.| Menu | Items |
|---|---|
| Board | Dashboard · Bulletins… · Dev Log · System Info · BBS Network · Log off |
| Messages | Boards… · New Post… · Mail… · Oneliners · Live Chat · IRC #teletypegames · Voting Booth · Feedback to the Sysop… · Page the Sysop |
| People | Who is Online · Last Callers · User Listing · Hall of Fame · Team |
| Doors | Games Room… · Door Lobby… · SERMO · Commodore 64 · Commodore Plus/4 · Chat of Ra · TTG Trivia |
| You | Your Stats · Profile… · Register… · Sysop Console (logged-in sysops only) |
| Help | Ask the TTG Master… · What is coming up? · Where do I start? · Where are the games, files, wiki? · Which doors are there? · New to BBSes? · Keys · About |
Every item has a hint: while it is highlighted, the bottom line tells what it does.
| Key | Action |
|---|---|
Alt+letter |
Open the matching top menu |
F10 |
Open the leftmost menu |
F1 |
Ask the TTG Master |
F2 |
Message Boards |
F3 |
Quick post |
F4 |
Chat |
F7 |
|
Alt-X |
Log off |
Tab / Shift-Tab |
Move focus inside a window |
Enter |
Activate the focused button / submit |
F5 / Alt-Enter |
Full screen and back, for the windows with much to read; also the [↑] / [↕] gadget or a double click on the title bar |
F6 / Shift-F6 |
Bring the next / previous window to the front; a click on a window does it too |
Alt-1 … Alt-9 |
Bring the window with that number (on the right of its top frame) to the front |
Ctrl-F5 |
Move the window with the arrows, size it with Shift+arrows (Tab switches), Enter ends (F6 too while it is the only window); with the mouse, drag the title bar or the ┘ corner |
letter / Alt+letter |
Press the window's button with that hotkey (Alt in a text field) |
Esc |
Close the top window or menu |
Copy env-example to .env:
| Variable | Default | Description |
|---|---|---|
BBS_PORT |
2323 |
TCP port. |
TELETYPE_BBS_SYSOPS |
empty | Comma-separated sysop names. Their accounts are created only with bin/account. |
TELETYPE_BBS_DISCORD_WEBHOOK |
empty | Discord webhook for new posts and sysop broadcasts; empty = off. |
TELETYPE_BBS_ACCOUNTS_PATH |
data/accounts.csv |
Registered names, salted PBKDF2-SHA256 hashes, file mode 600. |
TELETYPE_BBS_BOARDS_PATH |
data/boards |
Per-board CSV files. |
TELETYPE_BBS_MESSAGES_PATH |
data/messages.dat |
Legacy single-board file; migrated into General on first run. |
TELETYPE_BBS_LAST_CALLERS_PATH |
data/last_callers.csv |
Finished calls. |
TELETYPE_BBS_PROFILE_PATH |
data/profiles.csv |
User profiles. |
TELETYPE_BBS_ONELINERS_PATH |
data/oneliners.csv |
The oneliners wall. |
TELETYPE_BBS_MAIL_PATH |
data/mail.csv |
Private mail and feedback, file mode 600. |
TELETYPE_BBS_LAST_READ_PATH |
data/last_read.csv |
How far each registered name has read each board. |
TELETYPE_BBS_VOTES_PATH |
data/votes.csv |
The Voting Booth's ballots. |
TELETYPE_BBS_TRIVIA_SCORES_PATH |
data/trivia_scores.csv |
TTG Trivia games. |
TELETYPE_BBS_FTP_HOST |
ftp.teletypegames.org |
The FTP server whose /WARP sizes give the Commodore doors the blocks of each game. |
TELETYPE_BBS_IRC_SERVER |
irc.libera.chat |
IRC server of the read-only channel window (TLS); empty = off. |
TELETYPE_BBS_IRC_PORT |
6697 |
Its TLS port. |
TELETYPE_BBS_IRC_CHANNEL |
#teletypegames |
The channel the board listens on. |
TELETYPE_BBS_IRC_NICK |
ttgbbs |
The board's nick there; taken at login → ttgbbs_. |
TELETYPE_BBS_IRC_PASSWORD |
empty | NickServ password of the nick (SASL PLAIN); empty = no login. |
SERMO_LLM_URL |
set by compose | SERMO's model, http://llm:8080; empty = canned replies only. |
SERMO_LLM_MODEL |
set by compose | The model's name in the model service, qwen3.5-0.8b. |
SERMO_LLM_API_KEY |
empty | SERMO's key to the model service; without it SERMO answers with canned replies. |
TELETYPE_BBS_LLM_URL / _MODEL / _API_KEY |
SERMO's | The model of Ra and the TTG Master; unset or empty falls back to the SERMO_LLM_* value. |
A name in TELETYPE_BBS_SYSOPS cannot be registered over telnet, so nobody can claim it first. Create the account, or reset any password, from the server shell:
docker exec -it teletype-bbs bin/account Tasi
docker compose up --build # or, with Ruby 3.x: bundle install && ruby bbs.rb
telnet localhost 2323
Compose starts one container, teletype-bbs. The model behind SERMO, Qwen3.5 0.8B, runs in the server's shared model service, reached as http://llm:8080 on the interstack network; until it answers, SERMO uses canned replies. docker-compose.dev.yaml keeps the model next to the BBS instead: a teletype-bbs-acp container with llama.cpp's llama-server, no key.
A door is one entry of TeletypeBBS#doors (lib/domain/teletype_bbs.rb): its name, the program, the label with its hotkey, the narrowest screen it draws for, and three texts (tag for the C64's list, hint for the statusbar, about for the Door Lobby). The modern face declares them all, and its Doors menu lists them by itself; the PETSCII face offers the ones of 40 columns.
Door.new(name: :c64, program: Commodore.os(Commodore::C64, games: @games, sizes: @warp_sizes),
label: '&Commodore 64', cols: 40, tag: 'c64 + our games',
hint: 'A Commodore 64 at READY., with our C64 games on its disk: LOAD"$",8 lists them',
about: 'A Commodore 64 at its READY. prompt, with a small BASIC V2. …')
A door is a BBS::FakeOS definition (SERMO, the Commodores) or a callable. The sermo gem is pinned to a revision in Gemfile.lock; the entrypoint updates only rubbs on start. After a change in sermo-bbs, raise it with bundle lock --update sermo and redeploy.
Ra and the TTG Master run on Qwen3.5 0.8B in the model service, through rubbs' BBS::AI. A model this small is good at a short reply in a voice and bad at facts, so the code keeps the facts: Ra's riddles and the game's address come from the code, deflect rules answer what the model gets wrong however it is asked (code, poems, "are you a bot"), and the Master's wording is checked against the facts before it is shown. The Master's knowledge (lib/characters/master_knowledge.yml, and master_knowledge_c64.yml for the C64 face) names a menu path only for what is on this board, and the board and port for what another board carries.
Personas are tuned by measuring, not by single replies: bin/persona-eval ra|master|master_c64 3 asks the eval questions (lib/characters/eval/) several times and counts the slips: out of character, markdown, too long, and for the Master a miss (a wrong menu path or a lost fact).
docker exec teletype-bbs bin/persona-eval master 3
bbs.rb entry point: the terminal question, then a face
bin/account create an account / reset a password
bin/persona-eval count a character's slips over many runs
bin/c64-bytes the bytes of the C64 pictures on the line
lib/
domain/teletype_bbs.rb the board: services wired to their stores, the doors,
the network list, what a call does across services
domain/
repository/ nodes, boards, catalog, site (events, members), accounts,
last callers, profiles, oneliners, FTP (file sizes),
Gitea, mail, read marks, votes, the network (town map);
http_json (GET + 5-min cache)
service/ online, board, games, site, account, chat, IRC, last callers,
profile, oneliner, WARP sizes, dev log, discord_notifier,
mail, voting, taglines, network, scene (what the
clubhouse pictures show, for both faces)
model/ value objects (MessageModel, GameModel, …)
doors/commodore.rb the C64 and Plus/4 doors; commodore/basic.rb is their BASIC
doors/ra.rb Chat of Ra
doors/trivia.rb TTG Trivia
content/ polls, Trivia questions, taglines, bulletins, network.yml
content/art/ the clubhouse pictures: modern/ (cp437) and c64/ (PETSCII)
characters/ Ra and the TTG Master: personas, riddles, knowledge, eval questions
ui/arts.rb loads and keeps the pictures
ui/modern.rb the modern face: modem, entrance, windows, menus, doors
ui/modern/ the dashboard, the picture rooms (town map, games room),
the entrance, leaving, cards, trophies, the formatters
ui/petscii.rb, ui/petscii/ the C64 face: entrance, the clubhouse pictures
(petscii/clubhouse.rb), the reading sections
data/
boards/<id>.csv per-board messages (auto-created)
last_callers.csv finished calls
profiles.csv user profiles
accounts.csv registered names
oneliners.csv the oneliners wall
mail.csv, last_read.csv,
votes.csv, trivia_scores.csv
https://git.teletypegames.org/bbs/teletype-bbs