0.0.22 cohort: parity, the plugin marketplace and a terminal web browser¶
Published on 2026-10-25, every crate by one release run, with
rs-rich
0.0.10 on PyPI. See Publication.
0.0.22 finishes stage 2 of the plan to 1.0.0. The
core's promise, "renders what rich renders", is now checked row by row:
every widget, live display and document module is ported or recorded as a
divergence, scope.py is ported, and every divergence has a verdict. The
plugin marketplace ships end to end, from a signed index to
rich plugin install. intuiTUIve gains what three demo clones shared and
four controls whose labels and options change while they are shown, and a
new crate, Noctiluca, is a web browser for the
terminal built on them. The 0.0.22 plan says what
moved on to 0.0.23.
- Parity with rich 15.0.0. Twelve rendering-core rows, the widget and
layout rows (
padding,panel,align,constrain,table,layout,screen,bar,box,_ratio), the live display rows (livewith the alternate screen and the stdout/stderr redirect,progress,status,spinner,file_proxy) and the document rows are complete in PORTING, with 34, 47 and 86 new golden cases (parity_core.tsv,parity_widgets.tsv,parity_docs.tsv) andparity_live.tsv.scope.pyis ported (render_scope), and so ispretty.py's layout over a description of the Python object.console.pyis the one library row still partial; PORTING lists what it lacks. - Every divergence has a verdict. DIVERGENCES opens with a table: seven entries resolved in this release, the rest permanent, each with its reason.
- The differential fuzzer covers the documents.
scripts/diff_rich.pyalso generates Markdown, Tree, Columns, Progress frames, Pretty and JSON cases. Its first runs found six Markdown families, all fixed; one case remains a known divergence, #769. See Parity. - rs-rich-marketplace 0.0.1 (new). The marketplace client: it verifies the index's minisign signature, key chain, serial and expiry, reads listings, resolves a version against the host's plugin API and ABI, and installs over HTTPS within the declared size and SHA-256, with a lockfile. No terminal code. See Plugins.
rich plugin.search,info,install,update,remove,list,enable,disableandverify;rich plugin browse, the same in a selector with each package's provenance; andrich plugin publish, which checks a package and writes its listing for a pull request. An installed, enabled WASM plugin loads on every run without--plugin.installshows the tier, the capabilities and the permissions and asks before it writes anything.- WASM plugins on by default. rs-rich-cli's
wasm-pluginsfeature is a default, so a defaultrichloads sandboxed WASM plugins. Native plugins stay off by default. - The signing workflow and the compatibility job. The marketplace
repository's workflow (rebuild the index, bump the serial, sign in a
protected environment) is in
docs/marketplace-repo/; CI installs the official plugins and a fixture WASM plugin from a test marketplace. - The gaps three clones shared. Panel titles flush with the corner and
plain-text titles (Panels), a tree table
(Tables),
App::min_sizewith a node of its own or shorter forms of its message, and scope cycling that reveals a hidden pane. The clones drop their workarounds. - Live controls. Labels that change in place (
button_of,checkbox_of,switch_of), a three-state check box (CheckState), select and radio options known by key with a disabled reason, and a live action list: help and the palette update while open, and running a binding checks it again. See Buttons and form controls. - Made-up releases with two holds.
App::synthesize_releases_withtakesHolds { first, repeat }, so a game holds a key across the keyboard's repeat delay: rs-rich-doom's core gap 4. - Noctiluca 0.0.1 (new), a terminal web browser. A page opened in a
sandboxed headless Chrome, drawn in an intuiTUIve app: Chrome's layout
snapped to cells, or reader mode; forms as stock intuiTUIve widgets, link
hints, an address bar with keywords, back and forward, find, bookmarks,
per-site keys and the F1 overlay of every action. Sound is off unless
asked. Its guide has eleven pages: getting
started, reading, forms, every key and action, media, configuration,
privacy, the library, troubleshooting and what works today, with
recordings on every page and one against a real Chrome. Found while
writing it and fixed: a run's temporary Chrome profile is now removed on
every way out (it used to stay in the temporary directory), the
projection no longer shows the previous page after one is opened from
the
oprompt, andnonein[keys]unbinds a key while a bad key name skips only its own line. rs-rich-embed gainsDevTools::callandlisten, and switches for audio, downloads and a kept profile, all off by default. - Memo in the cartoon look, and a spot for every crate. Each crate's README and the crate tables show Memo with a prop that says what the crate does.
- The recorder. A tape writes an APNG only when its
Outputline or--formatnames it (0.0.22's decision 2), and a late read keeps a frame for each update inside it. macOS still keeps fewer frames: a known issue.
A default build of rs-rich still renders exactly like upstream rich
15.0.0, now against many more golden cases than before.
Independent package versions¶
| Package | Version | Release role |
|---|---|---|
rs-rich |
0.0.12 | Parity: twelve core rows, the widget, live and document rows, scope.py, pretty.py's layout; Live's alternate screen and FileProxy; Console::print_objects, line, rule, out, print_json, measure; more RichError variants |
rs-rich-macros |
0.0.6 | Manifest only; requires core 0.0.12 |
rs-rich-plugin-api |
0.0.6 | Requires core 0.0.12 |
rs-rich-art |
0.0.15 | Manifest only; requires core 0.0.12 |
rs-rich-diagram |
0.0.5 | Manifest only |
rs-rich-mermaid |
0.0.8 | Manifest only |
rs-rich-lumis |
0.0.6 | Manifest only |
rs-rich-ext |
0.0.19 | load_wasm_bytes; requires core 0.0.12 |
rs-rich-micro |
0.0.8 | Manifest only |
rs-rich-record |
0.0.10 | APNG only when asked (Formats::DEFAULT, Recording::default_formats); every update of a late read kept as a frame |
rs-rich-interact |
0.0.10 | Binding and Command gain unavailable; Palette::set_commands, Palette::focus_id, Help::set_bindings |
rs-rich-ratatui |
0.0.7 | Manifest only |
rs-rich-intuituive |
0.0.7 | Flush and plain-text titles, tree_table, min_size_with and min_size_forms, focus_scope_reveal, Holds; live labels, CheckState, SelectOption<K>, the live action list (action_overlay) |
rs-rich-embed |
0.0.5 | DevTools::call and listen; audio, download and profile switches, off by default; no engine end on a refused history request |
rs-rich-web |
0.0.5 | Manifest only; requires intuituive 0.0.7 and embed 0.0.5 |
rs-rich-data |
0.0.6 | Manifest only |
rs-rich-marketplace |
0.0.1 | New: the signed index, listings, resolution, verified installs and the lockfile |
noctiluca |
0.0.1 | New: the terminal web browser's reader phase |
rs-rich-cli |
0.0.22 | rich plugin (with browse and publish); wasm-plugins on by default; requires the versions above |
The Python package, rs-rich 0.0.10 on PyPI, builds against these crates.
Its AccessState gains mixed, and print(emoji=False) keeps emoji
codes.
Migration¶
Breaking changes in 0.0.x crates (the CHANGELOG has each):
- New public fields. A struct literal of these needs the new field:
rich_interact::Bindingandrich_interact::Command(unavailable: None),rich_intuituive::AccessState(mixed: false) andrich::r#box::Box(ascii). Their constructors and builders are unchanged, andAccessStateisDefault. rich::RichErrorhas new variants (Console,Style,MissingStyle,StyleStack,NotRenderable,Live): an exhaustivematchneeds arms for them, or a wildcard.wasm-pluginsis a default feature of rs-rich-cli. A build that must not carry the WASM runtime names its features withdefault-features = false.- Rendering that now matches upstream (each was a recorded divergence or a parity gap):
- a renderable without its own
measuremeasures as(0, max_width), soColumnsandMarkdownin a table cell size as upstream sizes them; - a printed
Screen, a printedLiveRenderand a titledRulewhoseendhas no newline end without a line break (Renderable::print_end_line, which defaults totrue); - a zero
heightonPanelandAlign, and a zerowidthonAlign, is read as unset;Constrainwith a zero width renders nothing; Text::from_markupreplaces:emoji:codes;AnsiDecoderdrops private escapes and splits lines as rich 15.0.0 does;- paging drops hyperlinks unless asked (
Console::page_with_links); - prompts parse numbers as Python does and take the default only for an empty answer.
- Tapes: a tape with no
Outputline no longer writes an APNG. AddOutput apng(or--format apng) to keep one. - Behaviour: running a binding from intuiTUIve's palette checks its condition again, so a command that stopped applying after the palette opened no longer runs.
Release test¶
- The release gate (
scripts/validate_release.py --tag release-0.0.22) onmainat9f8ea4bwith the notes on top, in a Linux container: fmt; clippy-D warningswith default features,--all-features, and the CLI without default features;cargo test --all(5,851 passed, 11 ignored, none failed), the CLI without default features (559 passed) and the plugin loaders (30 passed); the four release script suites (142 tests); the version tables,RELEASES.tomland the CLI reference up to date;cargo check --workspace --locked;check_packages.py(all 19 crates packaged and verified);release.py plan release-0.0.22selecting all 19. The tests were built without debug info, as the container's disk could not hold a debug build of the workspace's tests. - The golden fixtures (38 files, 4,766 cases) regenerate byte for byte from rich 15.0.0.
- The docs tapes: all 68 tapes, 257 screenshots, match with a release
build of the CLI and the examples, built with CI's features. The eleven
demo clones are intuiTUIve's examples: their suites ran in
cargo test --all, and their tapes are among the 68. - The docs:
mkdocs build --strictfor both sites. - The declared MSRV: CI's checks on Rust 1.90 (the workspace with every feature, and the CLI with CI's features) and on 1.91 (rs-rich-lumis, and the CLI with every feature).
- After the Noctiluca guide and fixes were merged (
66689219): fmt, the version and cohort checks andcargo check --workspace --locked; clippy-D warningswith every feature on noctiluca, rs-rich-embed and rs-rich-interact, the three crates the fixes touch, and their tests (noctiluca withfake-engine, rs-rich-embed withchrome); the four Noctiluca tapes (21 screenshots) with CI's build; andmkdocs build --strict. The fixes were also run against a real Chromium. CI runs the rest on this PR. - CI on #770's head (
531b9ba, which holds #768 too): 73 checks passed and 2 skipped (the docs publication jobs), including the feature matrix, the live browser job and the macOS and Windows jobs this pass did not run.
Not in this release¶
console.pystays partial. PORTING lists what it lacks (log,status, thescreen()context, capture,record=, render hooks, size setters and the colour system from the environment, among others).- One fuzzer case remains a known divergence:
#769, an
ordered Markdown item holding only an empty link under
justify="full". - The recorder's frame rate on macOS is still not fixed; the frame-rate test keeps its lower bound on Linux only.
- The marketplace's official keys are not compiled in yet: until they
are,
--marketplace-keysorRICH_MARKETPLACE_KEYSnames the keys to trust. - Moved to 0.0.23 by the maintainer:
rs-rich-doom's core gaps (all but gap 4), the
rich-rst2.2.0 pin, and Memo's illustrations revisited.
Known limits¶
See Known issues, which applies to this release. Still open: the recorder keeps fewer frames on macOS and Chrome's DevTools port on Windows.
Publication¶
- On 2026-10-25, on
mainat6e8e82e(#771), the 19 record tags (rs-rich-v0.0.12,rs-rich-macros-v0.0.6,rs-rich-plugin-api-v0.0.6,rs-rich-art-v0.0.15,rs-rich-diagram-v0.0.5,rs-rich-mermaid-v0.0.8,rs-rich-lumis-v0.0.6,rs-rich-ext-v0.0.19,rs-rich-micro-v0.0.8,rs-rich-record-v0.0.10,rs-rich-interact-v0.0.10,rs-rich-ratatui-v0.0.7,rs-rich-intuituive-v0.0.7,rs-rich-embed-v0.0.5,rs-rich-web-v0.0.5,rs-rich-data-v0.0.6,rs-rich-marketplace-v0.0.1,noctiluca-v0.0.1,rs-rich-cli-v0.0.22), thenrelease-0.0.22andpython-v0.0.10, each withRelease: 0.0.22andCommit:lines (17:15 UTC). - The one
release.ymlrun forrelease-0.0.22ran the full gate, then published every crate inRELEASES.toml's order and verified each version from crates.io (the publish job ran from 17:53 to 18:07 UTC; the uploads from 17:59 to 18:01; run). The two new crates,rs-rich-marketplaceandnoctiluca, went up with thecrates-ioenvironment's token, as a crate's first version must; every other crate went up through Trusted Publishing. - The Python package,
python-v0.0.10on6e8e82e, throughpypi-release.yml: built with the crates, then published to PyPI, finishing at 17:55 UTC (run). - The docs workflow ran on the tag push and succeeded.
Follow-up¶
- Registry. The maintainer adds the crates.io Trusted Publishing
entries for
rs-rich-marketplaceandnoctiluca(repositorybuchochelliq-labs/rs-rich-cli, workflowrelease.yml, environmentcrates-io), so their next versions publish without the token. See Registry authentication.