Skip to content

0.0.15 cohort: terminal charts and diagrams

Published on 2026-10-05. Every workstream in the 0.0.15 plan is merged, the release test below passed on the integrated tree, and every package is on crates.io and PyPI; see Publication.

0.0.15 draws data and structure in the terminal, natively:

  • Charts you compose, in rich_ext::chart: sparklines, horizontal and vertical bars, histograms, Braille line and scatter charts, gauges and bullet charts, heatmaps, status matrices, KPI cards and timelines. Each is a renderable that measures itself, fits the width it is given, sits in a Table, Panel, Layout or Live, has an ASCII form, and reads without colour.
  • Diagrams, in a new crate, rs-rich-diagram: a graph model, the layered layout lifted out of Mermaid (which now draws through it), a builder API, and a parser for the DOT (Graphviz) subset people write by hand, with a dot fence renderer and an optional Graphviz backend.
  • Sources: Cargo dependency trees (rich deps, with --why and --graph) and JSON Schema trees and diffs (rich schema).
  • From the shell and Python: rich chart draws CSV, JSON or a pipe; rich dot draws DOT; rs_rich.chart and rs_rich.diagram bind it all.
  • 0.0.14's known limits fixed: :micro: markup in titles, captions and Markdown; real graphics in rich asset --kind micro and rich explore --icons; every built-in component rebindable.

A default build of rs-rich is unchanged, still 0.0.9, and still renders exactly like upstream rich 15.0.0.

Independent package versions

Package Version Release role
rs-rich-diagram 0.0.1 (new) Graph model, layered layout, Diagram, DOT parser and Dot; plugin and graphviz features
rs-rich-mermaid 0.0.4 Draws through rs-rich-diagram; its flowchart types are re-exports
rs-rich-ext 0.0.13 rich_ext::chart, deps and schema
rs-rich-micro 0.0.2 :micro: in Markdown (PreparedMarkdown, MarkdownView); requires ext 0.0.13
rs-rich-record 0.0.3 Manifest only: requires ext 0.0.13
rs-rich-interact 0.0.3 Keymap dispatch and rebind in every built-in component, run_with_graphics; requires ext 0.0.13
rs-rich-cli 0.0.15 rich chart, rich dot, rich deps, rich schema, ```dot fences, --dot-backend, micro markup in labels and Markdown
rs-rich on PyPI 0.0.4 rs_rich.chart and rs_rich.diagram

rs-rich 0.0.9, rs-rich-macros 0.0.3, rs-rich-plugin-api 0.0.3, rs-rich-art 0.0.12 and rs-rich-lumis 0.0.3 do not change.

What changed

The changelog has the full list. By workstream:

Workstream Pull request
Plan #643
1. Chart foundation, sparklines, bars, histograms, Braille charts (#221, #257) #645
2. Gauges, heatmaps, status matrices, KPI cards, timelines (#250–#252, #254, #256) #646
3. rs-rich-diagram: graph model and layout (#227, #258) #644
4. DOT, Cargo dependency graphs, JSON Schema (#240, #244, #248) #647, fixes in #648
5. rich chart, Python bindings, recordings; no blank line after charts and diagrams #656
6. 0.0.14 follow-ups #655
Release test #657

Migration

  • Charts, diagrams and Mermaid no longer end with a blank line. Every rich_ext::chart renderable, rich_diagram::{Diagram, Dot} and rich_mermaid::Mermaid used to end its last line with its own newline, so print left a blank line after it. They now leave that newline to print, like core's renderables, and an empty chart prints nothing. Output that relied on the blank line has one line fewer.
  • Mermaid's flowchart types are re-exports. flowchart::{Direction, Shape, Node, Edge, Stroke, Head} are rich_diagram's types (same variants and fields) and layout::Diagram is an alias of rich_diagram::Drawing.
  • Limits on drawn graphs. rich_diagram::layout::draw refuses more than 2,000 edges or 5,000 nodes before laying out, and DOT sources are capped at 64 KiB, 500 nodes, 2,000 edges and 64 levels of nesting, with an error naming the limit (Mermaid's caps, now shared).
  • Keymaps: a rebound or installed key now takes precedence over an earlier action's declared key in the same context, instead of being ignored. FilePicker::rebind sends its own actions (open, up, hidden) only to the picker; use select.<action> for the list's.
  • --watch keeps the :micro: fallback, single file or several.
  • rich deps clears RUSTC_WRAPPER and RUSTC_WORKSPACE_WRAPPER (and their CARGO_BUILD_ forms) when it runs cargo metadata; see Running Cargo.

Release test (2026-10-05)

Check Result
python scripts/validate_release.py --tag rs-rich-cli-v0.0.15, on main before the fixes and again on this branch Every step passes: fmt, three Clippy configurations, 2,495 Rust tests in 162 suites (0 failed, 2 ignored), the lean CLI tests (396) and plugin-loader tests (28), the release, readiness, package and cohort tests (69), version and CLI-reference checks, locked build and check, staged packages for every crate, tag plan
capture_golden.py against real rich 15.0.0 (own venv, no rich-cli) Every golden file regenerates byte-identically; the 28 golden tests pass
diff_rich.py 57 cases match Python rich 15.0.0
release_cohort.py tag --dry-run and release.py plan per tag Exactly the eight packages below, each tag selecting its own package at the expected version; python-v0.0.4 belongs to pypi-release.yml
Packages rs-rich-diagram 0.0.1 packages to 39 KB (README, LICENSE, sources) and verifies against crates.io; the other crates verify as staged packages, since each needs a sibling that is not yet published
Consumer use A scratch crate with path dependencies renders charts, a code-built Diagram, Dot, the dot source renderer and a ```dot fence; cargo install --path crates/rich-cli gives rich 0.0.15, and rich chart, rich dot, rich deps --metadata and rich schema work
Docs tapes rich record --check passes for every tape (80 screenshots, 25 tapes)
Python wheel maturin build --release (rs_rich-0.0.4-cp39-abi3), installed into a fresh venv with rich==15.0.0, pytest and pillow: the whole suite passes against the installed wheel (1,231 passed, 1 skipped); rich-rs --version reports the 0.0.15 CLI
Python sdist maturin sdist installed from source into a fresh venv (on main before the fixes): builds; rs_rich.chart and rs_rich.diagram import; rich-rs chart and rich-rs dot work
MSRV cargo +1.90 check with the CI job's commands (on main before the fixes)
Security cargo audit: no vulnerabilities in 356 dependencies
Docs mkdocs build --strict passes for the main site and the Python site; gen_python_api.py --check (101 pages), gen_versions.py --check, gen_cli_reference.py --check and micro_gallery.py --check match

What the release test found and fixed

Three independent audits covered the whole 0.0.15 delta: the charts, rich chart and rs_rich.chart; the diagram crate, DOT, rich deps and rich schema (correctness and security); and the 0.0.14 follow-ups with every place the trailing-newline change could affect layout. They found 27 issues. Each was reproduced first, then fixed with a regression test that failed (or aborted, or hung) before the fix. The main ones:

  • Denial of service from small inputs. About 20 KB of nested DOT braces overflowed the stack and aborted the process (the CLI, a ```dot fence in Markdown, and Python's parse_dot); a 6 KB DOT cross product expanded to 360,000 edges and hung the layout; a 3 KB JSON Schema whose $refs fan out down a chain grew the tree and the diff exponentially; and an additionalProperties chain reset the diff's depth guard. DOT now has nesting, size, node and edge limits checked while groups expand, the layout refuses oversized graphs before working, and schema trees and diffs have budgets that say when they stop.
  • rich deps in workspaces. A workspace member reached through another member lost its dev-dependencies, depending on member order, so on this repository --why trybuild printed nothing; members appeared as (*) at the top level; deep chains overflowed the stack; and --why printed nothing (exit 0) when the chosen kinds reached no match. rich deps also ran a project's configured rustc wrappers through cargo metadata.
  • Charts with large values. Years, timestamps and other values of 1,000 and up on a short span were squashed onto a 2.0k axis; histogram edges were written as duplicates ([1.0k, 1.0k)) and a value on an edge was counted in the bin whose label excludes it. Labels the compact form cannot write exactly are now written in full, and edges are exact.
  • Crashes: ValueFormat::Fixed with 65,536 or more decimals panicked (reachable from Python); huge widths and heights overflowed or allocated without bound; ranges spanning ±1e308 collapsed to NaN labels.
  • :micro: in Markdown was drawn inside indented code blocks, fences in quotes and list items, and code spans across lines, and replaced tokens in link and image URLs. Code and link ranges now come from the Markdown parser itself.
  • Behaviour: rich chart turned 1e400, nan and inf into silent gaps and dropped cells past the header; Confirm no longer answered a lowercase press for an uppercase choice key (a regression from 0.0.14); rebinding FilePicker's up moved the list's cursor key; a rebound key held by an earlier action was ignored; single-file --watch drew micro images; DOT ignored \E, \T and \H, mis-lexed numerals and refused a comment before =; ASCII consoles got …, × and µ in notes and legends; a non-finite KPI delta read ▲ +-.

The docs were refreshed across the README, the guides, the Python pages, the crate READMEs and AGENTS.md's dependency graph, and the refresh found two CLI slips that are fixed: rich doctor did not report the record, interact and plugin-loading features, and --help did not list .mmd, .mermaid, .dot and .gv among the auto-detected types.

Known limits

  • DOT clusters are drawn without their frames (the layout cannot draw them yet; a note names them, as Mermaid does for subgraphs). rank constraints are ignored, and invisible and outline-free (plaintext, none) nodes are drawn as boxes, with a note.
  • rich deps runs Cargo in the target directory, so that project's Cargo configuration still applies (other than the rustc wrappers, which are cleared), including index fetches. --metadata FILE runs nothing.
  • Large schemas stop at 10,000 tree entries or diff changes, with a note.
  • A narrow line chart can drop an x-axis label between its first and third, because the first label is pinned to the left edge.
  • Rustdoc links to feature-gated items (plugin loading, Diagnostic adapters, the rich_println macros, rich_diagram's plugin and graphviz items) render as plain text in a default-features build.
  • Real graphics terminals. As in 0.0.14, the PTY tests check the bytes and cells around every protocol but not the images; the pickers now draw them too. See Before publishing.

Before publishing

One check cannot run in CI: open the graphics paths in a real terminal.

RICH_MICRO=kitty rich asset --kind micro          # Kitty or WezTerm: images in the picker
echo '{"ok": true, "skip": null}' | RICH_MICRO=kitty rich explore --icons -   # icons in the explorer
printf '# Build :micro:status/success:\n\n`:micro:fun/cat:` stays text\n' | rich -m -
rich -p done --panel rounded --title 'Deploy :micro:status/success:'

Each should draw the images in their cells, leave the code span as text, and leave nothing behind after the command ends or Ctrl+C.

Publication

RELEASES.toml lists every package's version in publication order. Tag what is due on the merged commit on main:

python3 scripts/release_cohort.py status          # what is published, tagged, or due
python3 scripts/release_cohort.py tag --dry-run   # what it would tag
python3 scripts/release_cohort.py tag             # tag and wait, one at a time

tag skips the five packages already on crates.io and pushes one annotated tag at a time, waiting for each version to appear on its registry before the next:

  1. rs-rich-diagram-v0.0.1, the new crate, then its Trusted Publishing entry;
  2. rs-rich-mermaid-v0.0.4;
  3. rs-rich-ext-v0.0.13;
  4. rs-rich-micro-v0.0.2;
  5. rs-rich-record-v0.0.3;
  6. rs-rich-interact-v0.0.3;
  7. rs-rich-cli-v0.0.15;
  8. python-v0.0.4.

crates.io offers Trusted Publishing only on a crate that already exists, so rs-rich-diagram 0.0.1 uploads with the crates-io environment's CARGO_REGISTRY_TOKEN: the workflow sees that the crate is new and uses it for that upload only. See Registry authentication.

All eight tags went out from main at 61d031a (the #657 merge) with release_cohort.py tag, and every release run ended green, including its exact-version verification. Two needed re-runs, both for GitHub runners rather than code, and neither had uploaded anything when it stopped:

  • rs-rich-mermaid-v0.0.4: feature-matrix jobs were never picked up ("The job was not acquired by Runner of type hosted even after multiple attempts"), so the gate failed before the publish job. Re-running only those jobs passed on the fourth attempt.
  • rs-rich-cli-v0.0.15: the rs-rich-record feature-matrix job was cancelled a minute into its test step with no failing test, after passing on the same commit in three earlier release runs. One re-run passed.

The other six ran once: rs-rich-diagram-v0.0.1, rs-rich-ext-v0.0.13, rs-rich-micro-v0.0.2, rs-rich-record-v0.0.3, rs-rich-interact-v0.0.3 and python-v0.0.4.