---
title: 'Starbase BBS'
url: 'https://wiki.teletypegames.org/services/starbase-bbs'
markdown: 'https://wiki.teletypegames.org/services/starbase-bbs.md'
lang: en
date: '2026-11-03'
description: "A Star Trek library for the BBS network: every series and film with its episodes, the day each first aired, its directors and writers, what first aired on this day, and the articles of Memory Alpha, the fans' wiki, read a section at a time. Live at teletypegames.org:2333, in the browser on bbsweb,…"
taxonomy:
  tag:
    - howto
---

# Starbase BBS

> A Star Trek library for the BBS network: every series and film with its episodes, the day each first aired, its directors and writers, what first aired on this day, and the articles of Memory Alpha, the fans' wiki, read a section at a time.
> 
> **Live at `teletypegames.org:2333`**, in the browser on [bbsweb](https://bbsweb.teletypegames.org), and through [TTG Gate BBS](https://wiki.teletypegames.org/services/ttg-gate-bbs)

# Overview

A Ruby app on the [**rubbs**](https://git.teletypegames.org/engines/rubbs) gem, like [Alexandria BBS](https://wiki.teletypegames.org/services/alexandria-bbs) and [Commodex BBS](https://wiki.teletypegames.org/services/commodex-bbs).

It has two faces on one port:

- **Modern**: ANSI colours, windows, menus and the mouse (SyncTERM, NetRunner, PuTTY, bbsweb). The series, a series' episodes and the episodes aired on this day in two-pane windows with the picked one's card on the right, the library computer (a search of Memory Alpha) in a dialog, and an article with its sections on the left.
- **Commodore 64**: PETSCII on a 40×25 screen, for a C64 terminal program (CCGMS, Novaterm, UltimateTerm) behind a WiFi modem. Cursor menus, the series, their seasons and episodes as numbered lists, an episode's card a page, an article as its contents and each section paged.

A call starts with rubbs' `BBS::Terminal` question: RETURN takes the guess, `1` picks the modern face, `2` the C64.

Star Trek is a trademark of Paramount. This is a fan library, not affiliated with Paramount; the board shows no scripts, transcripts or pictures.

# Where the data comes from

| What | Source | Licence |
|---|---|---|
| The catalog: series and their years, episodes with season, number, first air date, directors, writers; the films | [Wikidata](https://www.wikidata.org): every Star Trek episode (Q61220733) and every film of the franchise (P8345 = Q1092), read with rubbs' `BBS::Wikidata` | CC0 |
| The articles | [Memory Alpha](https://memory-alpha.fandom.com), read on demand from its Action API with rubbs' `BBS::MediaWiki`, cut into sections by `BBS::MediaWiki::Extract` | CC BY-NC, credited under every article |

About 1,000 episodes and films in 15 series. A snapshot of the catalog ships with the board (`config/catalog.json.gz`); the running board reads Wikidata again once a week and keeps the new copy in `data/`. A failed refresh keeps the old snapshot. An episode's Memory Alpha article is the one Wikidata names (its Fandom article id, P6262); without one the board opens the article of its title, else the first search hit.

Memory Alpha is asked at most three times a second, all callers together, and its answers are kept for half an hour. Both faces can show an article's address as a QR code (rubbs' `BBS::QR`), by its page id, so a phone opens it with the pictures.

# Using it

**On a modern terminal:**

| Key | Action |
|---|---|
| F2 | Series |
| F3 | On this day: what first aired on today's date |
| F4 | Library computer: search Memory Alpha |
| F7 | A random article |
| Enter | A series' episodes; an episode's article |
| Alt-Q | The article's QR code (in an article window) |
| F10 | The menu |
| Alt-X | Log off |

**On a Commodore 64** the main menu is `S` series and films, `T` on this day, `L` library computer, `R` a random article, `Q` log off. A series with seasons asks for the season first. Under an episode's card `R` reads its article; an article is its list of sections, and `C` shows its QR code.

A typed title opens its article even in another case ("data" opens Data); other words bring the search results.

# Configuration and data

| Variable | Default |  |
|---|---|---|
| `STARBASE_BBS_CATALOG_SEED` | `config/catalog.json.gz` | the snapshot shipped with the image |
| `STARBASE_BBS_CATALOG` | `data/catalog.json.gz` | the snapshot a refresh writes |
| `STARBASE_BBS_CATALOG_TTL` | `604800` | seconds before Wikidata is read again |

The board keeps no other data and has no secrets. `bin/refresh-catalog` writes a new seed from Wikidata in a dev checkout.

# Under the hood

A push to master deploys it from Woodpecker (RuboCop, the tests, compose check, `ci-deploy starbase-bbs`); the container is `starbase-bbs`, in `/srv/stacks/starbase-bbs`, and `data/` stays between deploys.

The code follows the house layering: `lib/domain` (`SeriesModel`, `EpisodeModel`, `ArticleModel`; the Wikidata, catalog and Memory Alpha repositories; `CatalogService`, `LibraryService`; the composition root `StarbaseBBS`) knows nothing of telnet, and `lib/ui` holds `UI::Modern` and `UI::Petscii`. The catalog lives in memory (the whole board takes about 30 MB). The Wikipedia-only client of rubbs became `BBS::MediaWiki` for this board in rubbs 1.4.0, with `BBS::MediaWiki::Extract` and `BBS::Wikidata` beside it.

'; var prevLevel = 2; for (var i = 0; i < headings.length; i++) { var h = headings\[i\]; var text = h.textContent.trim(); var slug = text.toLowerCase() .replace(/\[áàâä\]/g,'a').replace(/\[éèêë\]/g,'e').replace(/\[íìîï\]/g,'i') .replace(/\[óòôöő\]/g,'o').replace(/\[úùûüű\]/g,'u') .replace(/\[^a-z0-9\]+/g, '-').replace(/^-|-$/g, ''); if (!slug) slug = 'heading-' + i; if (used\[slug\]) { slug += '-' + i; } used\[slug\] = true; h.id = slug; var level = parseInt(h.tagName.charAt(1)); var cls = level > 2 ? ' class="toc-child"' : ''; html += '- [' + text + '](#'%20+%20slug%20+%20')
'; } html += '
'; toc.innerHTML = html; // Scroll-spy: highlight current heading var links = toc.querySelectorAll('a'); var ids = \[\]; for (var j = 0; j < links.length; j++) ids.push(links\[j\].getAttribute('href').slice(1)); function updateActive() { var current = ''; for (var k = 0; k < ids.length; k++) { var el = document.getElementById(ids\[k\]); if (el && el.getBoundingClientRect().top <= 80) current = ids\[k\]; } for (var m = 0; m < links.length; m++) { links\[m\].parentNode.classList.toggle('active', links\[m\].getAttribute('href') === '#' + current); } } window.addEventListener('scroll', updateActive, { passive: true }); updateActive(); })();

---

## Navigation

- Parent: [Services](https://wiki.teletypegames.org/services.md)
- Previous: [Scriptorium BBS](https://wiki.teletypegames.org/services/scriptorium-bbs.md)
- Next: [Discord Thread Scheduler](https://wiki.teletypegames.org/services/statusbot.md)
