Skip to content

0.0.22 plan: parity, the marketplace, and round 7's last items

Status: published on 2026-10-25, every crate from main at 6e8e82e by one release run, with rs-rich 0.0.10 on PyPI (release notes). The plan (#767), the first wave (#768: parity, the marketplace crate, the recorder) and the second wave (#770: rich plugin, workstream 2, Noctiluca, the crate spots) are merged, and the release PR (#771) prepared the cohort from 9f8ea4b; console.py's remaining rows and one fuzzer case (#769) stay open, and rs-rich-doom's core gaps and rich-rst 2.2.0 move to 0.0.23 (see Delivered). Proposed on 2026-10-21, while the 0.0.21 cohort waited to be tagged from main at 29084d4 (release notes); 0.0.21 was published the same day. The versions were opened after 0.0.21's publication notes. It finishes stage 2 of the plan to 1.0.0: 0.0.21 grew into a widgets, text editing and docs release, so its parity workstreams, the marketplace crate, the gaps three clones share and the rest of round 7's list move here (0.0.21's Delivered table). The two decisions it needed were answered on 2026-10-21. The tracker is #766.

Goal: make the core's 1.0 promise, "renders what rich renders", true or written down; ship the marketplace end to end, from listing to rich plugin install; and close round 7's list.

  • Parity: every partial (🟡) row in PORTING is ported or recorded as a divergence, scope.py is ported, every open divergence gets a verdict, and the differential fuzzer covers the document renderers.
  • The marketplace: the rs-rich-marketplace crate, rich plugin and rich plugin browse, publishing, the signing workflow and the compatibility job in CI.
  • Round 7's last items: the recorder on macOS, APNG made opt-in, and rs-rich-doom on the current crates.
  • The gaps three clones share: flush panel titles, a tree table and App::min_size's own node.

Versions

The 0.0.21 versions stay on main until that cohort is tagged: a release tags the commit it is run from, and release_cohort.py tag reads the manifests there. The commit that moves every package one patch past 0.0.21 (and adds rs-rich-marketplace at 0.0.1) lands after the tags are pushed, with 0.0.21's publication date in the changelog and notes. The workstreams below change no manifest version until then.

Done on 2026-10-25: every package moved one patch past 0.0.21 in the commit after 0.0.21's publication notes (the commit docs-versions.toml names for 0.0.21's docs). rs-rich-marketplace is added at 0.0.1 by its own branch, when it lands.

Workstreams

1. Round 7's last items: record, intuituive

  • The recorder on macOS: CI kept 7 frames over 0.8 s where Linux keeps about 30 a second (known issues). Find whether the PTY's reads or the settling rule merge them, fix it, and give the frame-rate test its lower bound on every platform again.
  • APNG is written only when asked (decision 2): a tape writes an APNG only when an Output line names it or --format includes apng. The default outputs go back to what they were before 0.0.20; the docs, the CLI help and the tape reference say so.
  • rs-rich-doom moves its pin to the current crates and onto pixel cells, held keys, fixed_step and the stats handle, which replace its own frame conversion, key timing and fps counter. The saved review comes with it: check whether 0.0.20's image nodes cover a live in-memory frame source, design the public indices-plus-palette Sixel encoder in rs-rich-art, and measure that the style table settles over a long run. Doom's own repository joins the work only if it is attached; the rich-side findings do not wait for it. Done on 2026-10-25 in Doom's repository: it builds on the 0.0.21 crates, uses those four features and plays sound through intuiTUIve's audio output. Its core gaps list 13 generic pieces, the Sixel encoder among them. The maintainer moved them to 0.0.23, except gap 4 (made-up releases with a first-press hold and a repeat hold), which is small and lands here with workstream 2.

2. The gaps three clones share: intuituive

From the gap note's "Round 7" section, only those three or more clones asked for:

  • Panel titles flush with the corner, ratatui's look, and plain-text titles (git, music, http).
  • A tree table, a table whose rows nest (top, tasks; bottom's and Taskwarrior's views).
  • App::min_size with a node of its own and shorter forms of the message (blocks, disk), with focus-scope cycling past hidden panes (http, top) folded in.
  • Made-up releases with a first-press hold and a repeat hold (App::synthesize_releases_with(Holds)), gap 4 of rs-rich-doom's core gaps: landed.

Each clone's workaround comes out as its gap closes.

Added on 2026-10-25, from the Noctiluca design: four generic controls the browser's web widgets need, each useful to any app:

  • Button and checkbox labels that change in place (button_of), so a label such as Play/Pause updates without rebuilding the node.
  • A three-state checkbox (CheckState { Off, On, Mixed }), with the accessible "mixed" state.
  • Keyed select and radio options (SelectOption<K>), each with its own enabled flag and reason, so reordering keeps the selection.
  • A live action list: help and the palette update while open, a binding can carry a reason it is disabled, and running one re-checks it.

3. Parity: the rendering core: rich

segment, text, console, style, color, markup, measure, ansi, highlighter, errors, containers, terminal_theme, protocol. For each partial row: a short list of what is missing (in PORTING itself), golden cases captured from rich 15.0.0 for each, then the port or a divergence entry. The rich crate's default build keeps matching upstream byte for byte.

4. Parity: widgets and layout: rich

panel, padding, align, constrain, table, layout, screen, bar, box's substitution, _ratio, columns, rule and the rest of PORTING's widget rows; the same method as workstream 3.

5. Parity: live display: rich

live, progress, status, spinner, live_render, file_proxy, including the alternate screen and the stdout/stderr redirect deferred in DIVERGENCES §17.

6. Parity: documents, scope.py, and the verdicts: rich, scripts

  • markdown, syntax, json, pretty, traceback, prompt, emoji, filesize, pager, _log_render, export.
  • Port scope.py (render_scope), the one module not started that 1.0 needs.
  • Every open divergence gets a verdict: fixed, or permanent with its reason, in DIVERGENCES.
  • The differential fuzzer grows to Markdown, Tree, Columns, Progress frames, Pretty and JSON, so parity is measured rather than sampled.
  • Sync any upstream release that appeared meanwhile. The rich-rst pin's move from 1.3.2 to 2.2.0 went to 0.0.23 on 2026-10-25.

7. The marketplace crate: marketplace (new), plugin-api

On 0.0.21's listing format, schemas and version checks (design):

  • rs-rich-marketplace (new crate): reads the index and verifies its minisign signature, the key chain, the serial and the expiry; reads and checks listings against the index; resolves a version against the running host's plugin API and ABI; downloads over HTTPS within the declared size, checks the SHA-256, checks the artifact by kind, then moves it into place and writes the lockfile. No terminal code.
  • Tests: a fixture marketplace signed with a test key: a good install, a bad hash, a bad signature, a wrong key id, a rolled-back serial, an expired index, a yanked version, an ABI the host cannot load.

8. rich plugin and publishing: cli, marketplace

  • rich plugin: search, info, install, update, remove, list, enable, disable and verify; an installed plugin loads on the next run without --plugin. install shows the permissions and tier and asks before it writes anything; --yes for scripts.
  • rich plugin browse (#463): the same operations in rs-rich-interact's selector and preview, with provenance for each entry.
  • rich plugin publish: checks a package locally and writes its listing, to be submitted as a pull request to the marketplace repository.
  • The signing workflow (decision 1), in rs-rich-marketplace's repository: when a listing pull request merges, CI rebuilds index.json, bumps the serial and signs it with the main key, held as a secret of a protected environment (marketplace-signing) that needs the maintainer's approval and runs only from main.
  • Compatibility tests: every official plugin (Mermaid, DOT, lumis) and a fixture WASM plugin are installed from a test marketplace in CI against the current host, so a host change that breaks installed plugins fails a pull request.

9. Noctiluca, a terminal web browser: noctiluca (new), embed

A new crate, noctiluca (no rs-rich prefix), built on intuiTUIve and rs-rich-embed's Chrome engine: page text stays terminal text, images, GIFs and video play in media regions, and controls come from the page's accessibility tree as stock intuiTUIve widgets. The design note holds the architecture, the phases and the decisions; the user's own proof of concept supplies its rules and its fixtures.

  • 0.0.1, the spike (done on its branch): a local page read with one DevTools snapshot and printed as rich Text; embed's DevTools::call and a navigation fix.
  • In this release: the reader phase (0.1 in the note): text, links, forms with web widgets over the controls of workstream 2, images, history, the live F1 action overlay, link hints, and a PTY end-to-end test; embed's switches for audio and downloads (off by default).
  • Reserved early: noctiluca joins RELEASES.toml, and its 0.0.1 may be published on its own crate tag once it is on main.
  • Later releases: forms and tables, layout projection and GIFs, then video, then the automation API.
  • Status: the reader phase is done on 022-browser, with sound (asked for in this release: --audio, media controls, verified through an ALSA sink) and the web widgets on workstream 2's controls; noctiluca is in RELEASES.toml with publish = false removed. The design note's "Where things stand" has the detail.

Order of work

  1. First, in parallel: workstream 1's APNG change and macOS recorder (small, self-contained), workstream 7 (the crate the commands need), and the four parity workstreams (3 to 6), one agent each, each in its own module area so they rarely meet.
  2. Then: workstream 8 on the crate, workstream 2 (with the four controls Noctiluca needs), workstream 9, and rs-rich-doom.
  3. Then: the eleven clones' suites and tapes re-run against all of it.
  4. Release test: audits, validation, notes, the cohort.

Decisions

Answered on 2026-10-21:

  1. Where the marketplace keys live: the main key is a GitHub secret, with its password, in a protected marketplace-signing environment of rs-rich-marketplace that needs the maintainer's approval and runs only from main, so CI signs each index. The backup key never enters GitHub: it stays offline and signs only key rotations, so a leaked main key can be rotated out. Both pairs are made by the maintainer with minisign -G; only the public halves enter either repository. This replaces the offline main key of 0.0.21's decision 3 (see the design note).
  2. APNG as a default tape output: no. A tape writes an APNG only when its Output or --format names it.

Answered on 2026-10-25, for Noctiluca (workstream 9): the engine trait in noctiluca; C1 to C4 into intuiTUIve core; embed's audio and download switches, off by default; an opt-in kept profile; the system Chrome first; a browser in CI with live tests as a normal user; the PoC's code may be copied where it fits intuiTUIve's architecture; noctiluca reserved soon. See the design note's decisions.

Answered on 2026-10-25: rich-rst 2.2.0 moves to 0.0.23, and so do rs-rich-doom's core gaps, except gap 4 (workstream 1).

Still open: none.

Not in this release

  • API review and stability tooling: stage 3, 0.1.0.
  • The DevTools pipe on Windows: after a crate can pass the handles; not before 1.0 unless one appears.
  • New demo-loop apps and the gaps fewer than three clones asked for: a round 8 of the loop, if it runs, after parity.
  • Python bindings for 0.0.21's new intuiTUIve widgets: with 0.1.0's Python contract, unless one is asked for sooner.
  • rs-rich-doom's core gaps (except gap 4) and the rich-rst 2.2.0 pin: 0.0.23.

Package impact

Against the 0.0.21 cohort's versions (published 2026-10-21). The versions are open: every package moved one patch past 0.0.21, as below, in a commit after 0.0.21's publication notes (see Versions); the new marketplace crate is added when it lands.

Package Proposed Reason
rs-rich 0.0.12 Parity: the partial rows ported, scope.py, divergence fixes
rs-rich-marketplace 0.0.1 (new) Index and listings, verification, resolution, downloads, the lockfile
noctiluca 0.0.1 (new) The terminal browser's reader phase
rs-rich-plugin-api 0.0.6 Requires core 0.0.12
rs-rich-ext 0.0.19 Requires core 0.0.12
rs-rich-art 0.0.15 Manifest only (the public indexed Sixel encoder moved to 0.0.23)
rs-rich-record 0.0.10 APNG opt-in; the macOS frame rate
rs-rich-intuituive 0.0.7 Flush titles, the tree table, min_size's node; live labels, the three-state checkbox, keyed options, the live action list
rs-rich-cli 0.0.22 rich plugin; requires the versions above
The rest one patch each Manifest only: their exact requirements on core and ext move. Opened as macros 0.0.6, diagram 0.0.5, Mermaid 0.0.8, lumis 0.0.6, micro 0.0.8, interact 0.0.10, ratatui 0.0.7, embed 0.0.5, web 0.0.5, data 0.0.6
rs-rich (PyPI) 0.0.10 Bindings for anything public that moves

Delivered

Tested SHA: 9f8ea4b (main after #770; its tree is #770's head, 531b9ba, where CI passed), with the release PR's prep commits on top (9f8ea4b..022-release: docs and the changelog only, no code or manifest). See the release notes.

Workstream PR Merged as
Tracker #766
Plan, versions opened, 0.0.21's publication notes #767: the plan and its decisions, Noctiluca's workstream, every package one patch past 0.0.21 0eaae1b
1. Round 7's last items #768: APNG only when asked; a late read split into its updates. Not done: macOS still keeps fewer frames (known issue). rs-rich-doom on the 0.0.21 crates, in its own repository; its core gaps but gap 4 move to 0.0.23 a010f93
2. The gaps three clones share, and C1 to C4 #770: flush and plain-text titles, tree_table, min_size_with and min_size_forms, focus_scope_reveal, synthesize_releases_with (Doom's gap 4); live labels, CheckState, keyed options, the live action list 9f8ea4b
3. Parity: the rendering core #768: twelve rows complete, parity_core.tsv, §41 to §45. console.py stays partial (PORTING lists what it lacks) a010f93
4. Parity: widgets and layout #768: ten rows complete, parity_widgets.tsv, §7, §12 and §29 resolved a010f93
5. Parity: live display #768: the alternate screen, FileProxy, Status and Progress, parity_live.tsv, §16 and §17 settled a010f93
6. Parity: documents, scope.py, verdicts #768: scope.py and pretty.py's layout, parity_docs.tsv, a verdict for every divergence, the fuzzer on the document renderers. One case is a known divergence, #769. rich-rst 2.2.0 moves to 0.0.23 a010f93
7. The marketplace crate #768: rs-rich-marketplace 0.0.1, tested on a fixture marketplace. The official keys are not compiled in yet a010f93
8. rich plugin and publishing #770: the nine commands, browse, publish, wasm-plugins on by default, the signing workflow in docs/marketplace-repo/, the compatibility job 9f8ea4b
9. Noctiluca #770: noctiluca 0.0.1, the reader phase with sound, its docs page and iconography; embed's DevTools calls and switches; CI's live browser job 9f8ea4b
Added: Memo's crate spots #770: the cartoon look and a spot per crate. Revisiting the art moves to 0.0.23 9f8ea4b
The clones re-run The clones are intuiTUIve's examples: their suites run in cargo test --all and their tapes in the tape check, both in the release test
Release test The release PR: validation on 9f8ea4b, notes, the changelog heading; then Noctiluca's guide and three fixes (the profile left behind, the stale projection, none in [keys]), re-checked for the crates they touch Tested at 9f8ea4b, and the fixes at 66689219; CI runs the whole PR; merged as 6e8e82e (#771), where the cohort was tagged