---
title: 'WarpEngine BBS'
url: 'https://wiki.teletypegames.org/services/warp-engine-bbs'
markdown: 'https://wiki.teletypegames.org/services/warp-engine-bbs.md'
lang: en
date: '2026-10-31'
description: 'The file area of the BBS network: the shelves the WarpEngine of teletypegames.org keeps for machines without a web browser. Pick a shelf, pick a title, and take it home by ZMODEM or, on a Commodore 64, by XMODEM. Live at teletypegames.org:2329, and in the browser on bbsweb, and through TTG Gate BB…'
taxonomy:
  tag:
    - howto
---

# WarpEngine BBS

> The file area of the BBS network: the shelves the WarpEngine of teletypegames.org keeps for machines without a web browser. Pick a shelf, pick a title, and take it home by ZMODEM or, on a Commodore 64, by XMODEM.
> 
> **Live at `teletypegames.org:2329`**, and 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 the [Teletype BBS](https://wiki.teletypegames.org/services/teletype-bbs), [Feedia BBS](https://wiki.teletypegames.org/services/feedia-bbs) and [TTG Blog BBS](https://wiki.teletypegames.org/services/ttg-blog-bbs). It is the telnet sibling of [WARP64U](https://wiki.teletypegames.org/stores/warp64u): the same shelves, but the C64 needs only a terminal program and a modem, no store client.

It has two faces on one port:

- **Modern**: ANSI colours, windows, menus and the mouse (SyncTERM, NetRunner, PuTTY, bbsweb). Downloads by **ZMODEM**, **XMODEM-1K** or **XMODEM**.
- **Commodore 64**: PETSCII on a 40×25 screen, for a C64 terminal program (CCGMS, Novaterm, UltimateTerm) behind a WiFi modem. Downloads by **XMODEM-1K** or **XMODEM**.

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

# The shelves

| Shelf | Folder on the archive |
|---|---|
| Commodore 64 | `http://archive.teletypegames.org/C64/` |
| Commodore Plus/4 | `http://archive.teletypegames.org/PLUS4/` |

The WarpEngine fills them on every release of a C64 or Plus/4 title (see [WARP64U](https://wiki.teletypegames.org/stores/warp64u)). Each has an `INDEX.TXT` in the shelf format (`#SHELF 1`, `file|version|size|crc32|title|author|description`), and the board reads it again after five minutes. A file goes out only when its size and CRC-32 match its index line; a title updated meanwhile asks the caller to read the shelf again.

# Downloading

**On a modern terminal** the shelves open in a two-pane window, then the titles of the shelf with the one picked on the right: its version, size, author, download count, description, and the buttons.

| Key | Action |
|---|---|
| Enter or Alt-Z | ZMODEM: SyncTERM, NetRunner, Qodem and bbsweb start it by themselves |
| Alt-K | XMODEM-1K |
| Alt-M | XMODEM |
| Alt-R | Read the shelf again |
| F2 | The shelves |
| Alt-X | Log off |

**On a Commodore 64** the menu lists the shelves by number, a shelf its titles by number, and a title opens on a page of its own. Then `1` sends it by XMODEM-1K, `X` by XMODEM, `Q` goes back. `H` in the menu explains it on the C64.

XMODEM carries no file name. After choosing it, start the download in the terminal (its download or receive menu), give the name the board shows (the shelf name without `.PRG`), and the file lands on the disk as a program: `LOAD"ARIADNE",8,1` and `RUN`. The board waits a minute for the terminal; Esc or RUN/STOP gives up. XMODEM fills its last block up, so the file can be longer by up to 127 bytes (XMODEM) or 1023 (XMODEM-1K). A Commodore program loads all the same.

The transfers are rubbs' `BBS::Zmodem` and `BBS::Xmodem` (rubbs 0.26.0): the bytes go out past the PETSCII encoder, 0xFF as a doubled telnet IAC, and XMODEM asks the line into telnet BINARY mode for the transfer. Through TTG Gate BBS the downloads work the same: its gateway passes the BINARY request on to the caller's terminal (rubbs 0.26.1).

# Configuration and data

| Variable | Default |  |
|---|---|---|
| `WARP_ENGINE_BBS_ARCHIVE_URL` | `http://archive.teletypegames.org` | the archive's plain HTTP |
| `WARP_ENGINE_BBS_SHELVES` | `config/shelves.yml` | the shelves and their folders |
| `WARP_ENGINE_BBS_INDEX_TTL` | `300` | seconds a shelf's `INDEX.TXT` is kept |
| `WARP_ENGINE_BBS_DOWNLOAD_MAX` | `1048576` | the largest file sent, in bytes |
| `WARP_ENGINE_BBS_DOWNLOADS` | `data/downloads.jsonl` | the downloads that went through, one JSON line each |

A new shelf is an entry in [`config/shelves.yml`](https://git.teletypegames.org/bbs/warp-engine-bbs/src/branch/master/config/shelves.yml) (`id`, `name`, `path`, `about`); a push to master deploys it. The download log feeds the counts shown with the titles. The board has no secrets.

# Under the hood

A push to master deploys it from Woodpecker (RuboCop, compose check, `ci-deploy warp-engine-bbs`); the container is `warp-engine-bbs`, in `/srv/stacks/warp-engine-bbs`, and `data/` stays between deploys. The entrypoint updates rubbs on start.

The code follows the house layering: `lib/domain` (`ShelfModel`, `TitleModel`, the shelf, archive and download repositories, `CatalogService`, the composition root `WarpEngineBBS`) knows nothing of telnet, and `lib/ui` holds `UI::Modern`, `UI::Petscii` and `UI::Transfer`, the protocols both faces share.

'; 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: [Discord Updater Bot](https://wiki.teletypegames.org/services/updater.md)
- Next: [TTG Wiki BBS](https://wiki.teletypegames.org/services/wiki-bbs.md)
