EN /HU | Login

Changelog

The version history of rubbs, newest first, from the git history of engines/rubbs and the version bumps in bbs.gemspec. Each entry links to the manual page that documents the feature. Boards pin rubbs by tag or git revision in their Gemfile.lock; the version below is the s.version of the gemspec at that commit.

Version Date In one line
1.1.0 2026-11-02 Editor/Screen#edit autosave: seconds and a block (off by default, keeps the idle limit itself); Selector item_exits: and Screen#pick item_commands: act on the lit item
1.0.0 2026-11-02 The cleanup release: TUI, BBS::Color and unused widgets and Flow steps gone; one palette, one Selector, say(…, color:), edit, BBS.log, BBS.background, BBS::Wikipedia, the gateway calls public addresses only
0.34.0 2026-11-02 Gateway.new(translate: true): a C64 can call an ASCII/ANSI board
0.33.0 2026-11-01 Hardening (per-address limit, control-free text, capped telnet, bounded AI calls), BBS::SQLite and BBS::Store on it, BBS::HTTP, Cache, RateLimit, Text, Address
0.32.0 2026-11-01 BBS::Selector fill: keeps the menu's height when the items take fewer rows
0.31.0 2026-11-01 BBS::Gateway::Report for each call, connect_timeout:
0.30.0 2026-11-01 Art and graphics screens: Petscii::Canvas, Art, Petscii::CanvasMenu, Widgets::Scene, Season, art-preview
0.20.0 2026-10-29 Terminal.flow(petscii:) in place of c64:, the face is :petscii
0.19.0 2026-10-28 config.theme, on_idle, per-session idle_seconds and Panel layout work
0.18.2 2026-10-28 Full RDoc, releases by tag, the API reference on the wiki
0.18.1 2026-10-28 (tag only; its RDoc upload failed, see 0.18.2)
0.18.0 2026-10-28 BBS_MAX_SESSIONS, a log line for a turned-away caller
0.17.1 2026-10-27 Fixes found while writing the manual
0.17.0 2026-10-27 BBS::Gateway: a telnet gateway door to another board
0.16.1 2026-10-27 Terminal.flow switches the mouse on only with config.mouse
0.16.0 2026-10-27 BBS::Terminal: the modern-or-C64 question
0.15.0 2026-10-25 PETSCII: a Commodore 64 on the line
0.14.0 2026-10-22 Switchable windows
0.13.0 2026-10-22 on_tick, on_door, hidden status hints
0.12.0 2026-10-22 Moving and sizing windows
0.11.0 2026-10-22 AnsiArt.view
0.10.0 2026-10-22 Maximizable windows
0.9.0 2026-10-22 ZMODEM downloads, with_line; an audit
0.8.0 2026-10-21 AI facts, fallback, deflect
0.7.0 2026-10-21 Flow doors, a flow's own screens, SAUCE
0.6.0 2026-10-20 BBS::Door
0.5.0 2026-10-20 BBS::AI
0.4.0 2026-05-12 The Application layer (and everything up to 2026-10-20)
0.3.0 2026-05-11 TUI page navigation
0.2.0 2026-05-11 Page-based TUI DSL
0.1.0 2026-04-28 Flow, Telnet, Store, extracted from the Impostor BBS

1.0.0 — 2026-11-02

The cleanup release: one way to do each thing. Most boards change only three things (the first three below); UPGRADING.md in the repository lists every removed or renamed API with its replacement and a grep that finds it.

  • Petscii::Screen#say and #rule take the colour as a keyword: say(text, color: GN), rule(color: DG).
  • Screen#editor is gone: edit(title:, max:), which returns nil when the caller quits. Petscii::Screen::MENU is gone: BBS::Selector::COLORS is the default.
  • The gateway calls only public addresses: a board that dials its neighbours (host.docker.internal, a container) says public_only: false; a refused call ends with BBS::Gateway::Refused (Doors).
  • Removed: BBS::TUI and the Flow's tui step, BBS::Color, the widgets ProgressBar, Spinner, HBox, VBox, Panel and AnsiArt (use Art + Widgets::Scene), the Flow steps set, line, section, rows, table, wait_enter, fetch, pick, body, output, os (use call), the colour-named Flow styles, Menubar#add_menu, the public Terminal.choose (use Terminal.flow), Petscii::Screen.plain (BBS::Petscii.plain), Dialogs.wrap (FrameBuffer.wrap_ansi).
  • One of each: one palette (BBS::Ansi; Petscii::Colors are its C64 names), one cursor menu (a Flow's menu is a BBS::Selector now), one word-wrap, one PETSCII glyph table, one telnet parser (BBS::Telnet::Parser). Flow steps are objects; a call block's runner answers context, ask, select and line (Flow).
  • Themes as data: Theme::PRESETS, Theme.fetch(name), frozen themes, an unknown role raises (Drawing).
  • New: BBS.log and config.log_tag (every log line of the library starts with the board's name), BBS.background (work in a thread with retry), BBS::Wikipedia, RateLimit.allow_all?, room?/record and counters in SQLite, Text.line, HTTP.get(to: io) and HTTP::TooLarge, Cache#refresh, broken CSV rows set aside on import, Store#open!, and the error rule: repositories raise, services decide (Data and network).
  • Text.clean(keep_newlines: false) turns a line end into a space instead of gluing the words; Telnet#settle returns the session or nil.

0.34.0 — 2026-11-02

  • BBS::Gateway.new(translate: true): a Commodore 64 can call a board made for ASCII and ANSI terminals; the board's text reaches it as PETSCII, its keys reach the board as an ANSI terminal's (Doors).

0.33.0 — 2026-11-01

Hardening, and the blocks every content board used to write for itself (Data and network).

  • Limits: max_sessions_per_ip (6) per public address; NAWS at most 255×100; input and the frame buffer keep no control characters; a text field holds at most 64 KiB; gateway subnegotiations and ZMODEM restarts capped; SIGTERM stops the server like Ctrl-C.
  • AI: a deadline (120 s) and a reply cap per call, at most ai_concurrency (2) requests at once, BBS::AI::Busy and the persona's fallback when the model is taken (AI characters).
  • BBS::SQLite with migrations, and BBS::Store on it: a .csv path means the .sqlite3 beside it, the old CSV is imported once (Telnet and the store).
  • BBS::HTTP, BBS::Cache, BBS::RateLimit, BBS::Text, BBS::Address. Ruby 3.2 or newer; sqlite3 is a dependency.

0.32.0 — 2026-11-01

  • BBS::Selector with fill: keeps its height when the items take fewer rows, so a status row stays at the bottom of the screen.

0.31.0 — 2026-11-01

  • BBS::Gateway hands its block a Report of the call (connected, error, address, connect time, bytes received, who hung up) and takes connect_timeout: (Doors).

0.30.0 — 2026-11-01

The shared building blocks of the TTG Clubhouse look: pictures drawn as text, for both faces. Everything is new; nothing existing changes behaviour. (The versions between 0.20.0 and 0.30.0 are in the git history of engines/rubbs.)

  • BBS::Petscii::Canvas: the C64 screen as cells in the uppercase/graphics set, raw PETSCII out (whole frame, spans, patches, update), moved here from TTG Gate BBS with the same bytes; feed plays PETSCII back for tests.
  • BBS::Art: drawings as YAML (chars, colours, reverse, cp437 backgrounds, hotspots, layers), out to ANSI, a FrameBuffer or a Canvas, with errors that name the cell.
  • BBS::Petscii::CanvasMenu: BBS::Selector drawn on a Canvas, patches of the changed cells, an idle hook for animation.
  • BBS::Widgets::Scene, BBS::Season and the art-preview tool. See Art and graphics screens.

0.20.0 — 2026-10-29

The PETSCII face is named after the line it speaks, not after one machine that speaks it. This breaks the call of every two-faced board; ours all changed with it.

  • BBS::Terminal.flow(title:, modern:, petscii:) takes the PETSCII face's Flow under petscii: (was c64:), and Terminal.guess / Terminal.choose answer :modern or :petscii (was :c64); Terminal::FACES has the same keys (Commodore).
  • The boards follow the same name: their faces are UI::Modern and UI::Petscii (lib/ui/petscii), the Impostor flow is Impostor::Modern / Impostor::Petscii.

0.19.0 — 2026-10-28

Four things that were documented but did nothing now work. No board of ours used them, so none changes behaviour.

  • config.theme is the theme of every Application without a theme call of its own, and the base of a theme do … end block given none (Getting started).
  • on_idle { … } runs when the caller reaches the idle limit; :keep keeps them on, anything else drops the line (Application).
  • Session#idle_seconds is the limit the Application loop and the TUI read, and setting it changes the socket timeout too: one caller can get more time (Telnet, session and store).
  • Widgets::Panel#layout gives its children the area inside the border (Widgets).

0.18.2 — 2026-10-28

  • The whole API is documented in the source (rdoc -C lib: 100%), and the RDoc is on the wiki: API reference, all versions on RDoc. CI fails below 100%, and the repo's CLAUDE.md makes it the rule.
  • Releases are tags from now on: vX.Y.Z, matching the gemspec; earlier versions were tagged retroactively (v0.1.0 … v0.18.0).
  • Comments that disagreed with the code now say what it does: the AnsiArt options (fill_parent, not width) and SAUCE stripping (everything from the first \x1A), the five theme presets, and three settings that nothing reads yet: Config#theme, Application.new(on_idle:) and Session#idle_seconds.
  • 0.18.1 has the same code; its tag pipeline could not install RDoc on the slim image, so 0.18.2 is the first published reference.

0.18.0 — 2026-10-28

  • max_sessions can be set from the environment: BBS_MAX_SESSIONS (default 100), so a deployment sizes it to the container's memory without touching the board's code (Telnet, session and store).
  • A caller turned away at the limit is logged: BBS busy: N callers on, turned one away.

0.17.1 — 2026-10-27

Fixes found while writing this manual.

  • open_door works from any handler: it stops the event loop itself, so a window button (Info, Form, MasterDetail actions) or a MasterDetail on_activate leaves through the door without a following stop!. Application#line_lost? tells a run that ended because the line did (a hang-up, the idle limit); Builder#run opens no door after it, where a door picked just before a hang-up used to open. See Application and Doors.
  • The Flow app step runs the application through Builder#run, so its doors work there too (Flow).
  • theme :name without a block takes that preset (it used to store the Symbol and crash the first redraw), and theme without arguments returns the theme set so far instead of resetting it (Drawing).
  • ask ... validate: takes a Proc or Method as well; a falsy answer fails like :non_empty (Flow).
  • A menu item's enabled: may be a lambda, asked on the application each time the menu is drawn or used; Menubar::MenuItem#enabled? is the answer (Application).
  • Store#upsert ignores fields that are not headers on update too; it used to append them as an extra column (Telnet, session and store).
  • Session#resize!(cols, rows): the gateway hands the caller's resize to this board's session as well, so the board has the new size after the crossing (Doors, Telnet, session and store).
  • The README's Gemfile line points at git.teletypegames.org.

0.17.0 — 2026-10-27

  • BBS::Gateway.new(host:, port:, name:): a door to another telnet board, the telnet gateway of the old BBSes. The caller's line goes on to that board as it is and comes back when it hangs up, so a board can offer another one without running its code. See Doors.
  • Towards the other board the gateway is the telnet client: it answers the negotiation, reports the caller's window size and passes resizes on. A PETSCII line reports none, so a two-faced board on the other side takes the caller for a C64 (Commodore 64).
  • session.line exposes the caller's socket, for a door that hands the line on (Telnet, session and store).
  • The caller's side wakes the other side with shutdown, never close: a thread killed halfway through IO#close leaves the descriptor open.

The Teletype BBS reaches Alexandria BBS and Feedia through it.

0.16 — 2026-10-27

0.16.1

  • Terminal.flow calls enable_mouse after a modern pick only when the board has config.mouse on. Before, a two-faced board without a mouse (Impostor BBS) still had reporting switched on for a modern caller. See Commodore 64.

0.16.0

  • BBS::Terminal: the first question of a board with a modern and a C64 face, moved into the gem from the three boards that each had their own copy. See Commodore 64.
    • Terminal.guess(session) guesses from the telnet answers: wider than 40 columns is modern, 40 or no window size at all is a C64.
    • Terminal.choose(session, title:) asks in plain ASCII capitals and names the protocols: 1 - MODERN (ANSI/XTERM, 256 COLORS), 2 - COMMODORE 64 (PETSCII, 40 COLUMNS). A key picks, RETURN takes it (the input of WikiProxy), and 60 seconds of silence takes the pick or the guess.
    • Terminal.flow(title:, modern:, c64:) asks, switches the line (petscii! or mouse reporting) and runs the chosen face's Flow.

Used by the Teletype BBS, Impostor BBS, TTG WIKI BBS, Alexandria BBS and Feedia.

0.15 — 2026-10-25

  • PETSCII: session.petscii! turns a session into a C64's: 40×25, the lowercase character set, no mouse. See Commodore 64.
  • Everything written then goes through BBS::Petscii::Encoder, so a board keeps writing UTF-8 with ANSI colours and cursor moves: letters swap case the PETSCII way, box drawing and blocks become the C64's glyphs, ANSI colours its colours, CR LF one RETURN, and a line of exactly 40 characters gets no empty line after it.
  • readkey and readline read the C64's keys; RUN/STOP and ← are :escape.
  • session.settle(timeout:) waits for the telnet answers and drops the typeahead, so a board can guess the terminal before it asks (Telnet, session and store).
  • config.mouse_on_connect (default true) lets the flow switch mouse reporting on later, after a question a C64 must not see an escape sequence before.

0.14 — 2026-10-22

  • Switchable windows, Turbo Vision style: several windows open at once cover each other in the order they were last used. A click on a window behind the active one brings it to the front, F6 / Shift-F6 step through them, Alt-1 … Alt-9 picks one by the number on its frame. The active window has a double frame. See Windows.
  • Modal windows (the Dialogs) keep the front until they close; the BBS::Windows types are no longer modal.
  • F6 moves a window only while it is the only one; Ctrl-F5 always does.
  • app.raise_window, cycle_windows, switchable_windows do it from code (Application).

0.13 — 2026-10-22

  • on_tick { … } in the Application DSL runs once a second while the caller is idle (a statusbar clock). on_door { |door, context| … } runs just before the line goes to a door. See Application.
  • status_hint(key, label, hidden: true) binds a key without taking room on the statusbar.
  • Fixes: Enter in Dialogs.input's field presses OK; a door that raises brings the caller back to the board instead of ending the call; an indented line under a Markdown list item continues the item.

0.12 — 2026-10-22

  • Moving and sizing windows: a window that is not maximized can be moved, a resizable one sized. The mouse drags the title bar or the bottom right corner (┘); from the keyboard, Ctrl-F5 or F6 starts it, the arrows move, Shift+arrows size, Tab switches, Enter or Esc ends. movable: false turns it off; move_to(x, y, w, h) from code. See Windows.
  • Mouse reporting is xterm 1002 now (motion while a button is held), so drags arrive.
  • The telnet reader returns xterm's modifiers: :shift_up, :ctrl_f5, :alt_home, :ctrl_shift_right (Telnet, session and store). A window hands a modified arrow nothing takes to its widget as the plain key.

0.11 — 2026-10-22

  • AnsiArt.view(session, lines, title:): art on the whole screen, centred, scrolled with the arrows, PgUp/PgDn and Home/End when taller than the screen; a status line with the title; any other key returns. It runs inside Application#with_line. See Widgets.

0.10 — 2026-10-22

  • Maximizable windows: maximizable: true (w.maximizable true in the window DSL) gives a window a zoom gadget: [↑] fills the desktop between menubar and statusbar, [↕] restores it; F5, Alt-Enter and a double click on the title bar do the same. Off by default. See Windows.
  • Windows that can lay out at any size say resizable? and implement normal_rect and place(x, y, w, h): MasterDetail, Stream, Form and a scrolling Info do. Stream, Form and Info now follow a terminal resize.
  • Application#desktop_rect; ESC CR reads as :alt_enter.

0.9 — 2026-10-22

  • ZMODEM downloads: BBS::Zmodem.send_files sends files to the caller's terminal (SyncTERM, NetRunner, Qodem, rz behind telnet, zmodem.js in a web terminal). Control characters are ZDLE-escaped and 0xFF goes as a doubled telnet IAC. See Doors.
  • Application#with_line { |session| … } hands the raw line to a block and repaints afterwards; Telnet#read_raw_byte reads for it.
  • MasterDetail takes on_activate (Enter on an item) and replace_items, so a window can browse folders in place (Windows).
  • An audit of the whole gem, among others:
    • NAWS is clamped (one 65535×65535 report made every render allocate gigabytes), subnegotiations and lines are capped;
    • sockets get the idle limit as read/write timeout, connections are capped (max_sessions), EMFILE no longer spins the accept loop;
    • readline returns UTF-8, Backspace removes a whole character, readkey reads UTF-8 characters;
    • CR LF is one Enter, a lone Esc no longer waits for the next key, SS3 arrows and X10 mouse reports no longer leak as keys;
    • Esc and function keys get past a TextInput; button hotkeys work; on_close runs once;
    • narrow terminals, a wheel event over a window's padding, a handler's exception and a FakeOS command's exception no longer end the call.

See Telnet, session and store for the limits.

0.8 — 2026-10-21

  • Chat#reply(text, ctx, facts:, fallback:): facts go into the system prompt for one request, and fallback replaces the persona's canned reply when the model is missing or fails. A persona's deflect rules are answered by the code before the model is asked. See AI.
  • TextInput#value= puts the cursor at the end of the new value: the second line typed into a Stream window used to raise IndexError and hang the caller up.

0.7 — 2026-10-21

  • Flow doors: a door may be a BBS::Flow. It runs on a copy of the caller's context and asks for ENTER before handing the line back. See Doors.
  • Flow.define(screens_dir:) keeps a flow's ERB screens next to it, so a flow shipped in a gem renders inside any board; FlowRunner takes context: to seed the flow's context (Flow).
  • FakeOS base colour: every reset returns to it and cls fills the screen with it, so a coloured background (a C64's blue) survives prompts and new lines.
  • AnsiArt.sauce(path) reads the SAUCE record of an art file (Widgets).

0.6 — 2026-10-20

  • BBS::Door: hand the line to a program and take it back. Declared with door :name, program, label:, listed in a menu with doors, opened from any handler with open_door. Builder#run runs the door the application was left through and builds the application again, with the same context. The program is a FakeOS definition or a callable(session, context). See Doors.

0.5 — 2026-10-20

  • BBS::AI: characters a caller can talk to. A persona from a YAML file (system prompt, example turns, request options, canned replies), a streaming client for any OpenAI-compatible chat endpoint, a chat that keeps a short history in the caller's context and falls back to the canned replies, and a typewriter that word-wraps the streamed reply onto a FakeOS console. See AI.

0.4 — 2026-05-12

0.4.0 brought the third layer, the widget framework (the commit "new framework"):

  • BBS::Application with an event loop, Event, FocusManager, a menubar, a statusbar, Dialogs, Window, Container and the widgets (Label, Button, TextInput, TextArea, Checkbox, ListBox, ScrollView, ProgressBar, Spinner). See Application and Widgets.
  • BBS::Theme presets; xterm mouse reporting (1000 + SGR 1006) and the key decoder in the telnet reader.
  • BBS::Store got its in-memory cache and Mutex: new rows are appended, updates rewrite the file (Telnet, session and store).

The version stayed 0.4.0 until 2026-10-20, while these landed:

  • 2026-05-12 – 05-13: Widgets::AnsiArt (CP437 art), the theme DSL and more presets, the Markdown renderer, the pre-built window types (Info, Form, MasterDetail, Stream, ButtonBar) and the window DSL (window :name, type:). See Windows and Drawing.
  • 2026-06-05: GFM tables in Markdown; mouse-wheel scrolling in ScrollView. BBS::FakeOS, a character-mode OS simulator as configuration (Doors).
  • 2026-06-11: open windows re-lay out on a terminal resize.
  • 2026-08-17: a CI check; 2026-09-09: the MIT license.
  • 2026-10-16: Store survives invalid UTF-8 in the CSV and cleans values before writing them.
  • 2026-10-19: a client hang-up is logged as a dropped session, not an error.
  • 2026-10-20: readline(mask:) for passwords, and naws_reported?.

0.3 — 2026-05-11

  • A nav DSL in TUI::Page; helpers accumulates across calls. (Removed in 1.0.0.)

0.2 — 2026-05-11

  • The page-based TUI DSL (BBS::TUI.define, pages, a router), on the TUI runner added the same day, with NAWS terminal-size negotiation and sizes that follow it. (Removed in 1.0.0.)
  • Followed on 2026-05-12 by the double-buffered FrameBuffer with delta rendering (Drawing).

0.1 — 2026-04-28

  • The first version, extracted from the Impostor BBS's gems/bbs: BBS::Flow and FlowRunner (screen, banner, ask, say, menu, persist, …), ERB screens (Renderer), Banner, BBS::Store, the threaded Server, Session and the telnet layer. See Getting started and Flow.
  • 2026-04-28 – 04-30, still 0.1.0: the call step and config.on_session_end; the Flow primitives line, section, text, rows, table, wait_enter, fetch, pick, body, output; BBS::Color with the c() helper.

See also