0.0.15 plan — terminal charts and diagrams¶
Status: published on 2026-10-05; every workstream is merged and the release test passed (see the release notes). Proposed on 2026-10-04, after the 0.0.14 cohort was published. The scope, and the decisions marked "decided", were agreed with the maintainer the same day. It tracks the first slice of milestone 5 (Diagrams & Visualisation). The scope tracker is #642.
Goal: draw data and structure in the terminal, natively.
- Charts you compose. Sparklines, bars, Braille line and scatter
charts, heatmaps, gauges, bullet charts, timelines, KPI cards and status
matrices, each a renderable that measures itself, fits the width it is
given, and sits inside a
Table, aPanel, aLayoutor aLivedisplay like anything else. Every one has an ASCII form and a reading that does not depend on colour. - Diagrams from real sources. One graph layout, extracted from the Mermaid crate so every diagram draws the same way, behind a DOT (Graphviz) plugin, Cargo dependency graphs and a JSON Schema visualiser.
What stays the same: core's behaviour. A default build still behaves
like upstream rich 15.0.0, and nothing under crates/rich/src changes.
Charts are renderables over core's public Renderable and Measure; no
core hook is needed.
Research behind this plan¶
A read-only survey on 2026-10-04:
- Nothing draws charts today. No sparkline, bar, heatmap or gauge
exists in any crate;
rich-ext'sDiagnosticsDashboardcounts levels in a table, andfidelity.rsonly names Braille as a sparkline glyph set. The milestone's issues are one or two sentences each, so this plan sets the scope. - A graph layout already exists, inside Mermaid.
crates/rich-mermaid/src/layout.rsis a layered (Sugiyama-style) layout: cycle breaking, longest-path ranks, dummy points for long edges, barycentre ordering to cut crossings, and orthogonal routing with a port per edge and a track per gap, drawn with box-drawing junctions. It takes aFlowchart, not a generic graph, so it has to be lifted out before DOT or Cargo can use it. - Braille is image-only.
rich-art'sBrailleArtmaps a decoded image to 2×4 dots per cell.rich-extdoes not depend onrich-art, so charts get their own small dot canvas rather than an image decoder. - The plugin seams are enough.
PluginRegistrar::rendererandfence_rendereralready carry Mermaid; a DOT plugin needs nothing new inrs-rich-plugin-api.
Workstreams¶
Each workstream lands as its own pull request, or a short stack, with
evidence in the PR and an entry under Delivered. Placement
follows AGENTS.md: nothing in core; renderables in rich-ext; the graph
layout in a new rs-rich-diagram crate; the CLI only composes.
1. Chart foundation and compact charts — ext¶
- A chart module,
rich_ext::chart, with what every chart shares: a numeric scale (linear, with nice ticks, min/max/zero handling and explicit bounds), value formatting, a glyph set chosen from the console (Unicode blocks, Braille, or ASCII when the console's encoding orfidelityasks for it), and a colour ramp that is never the only way to read a value. - Sparklines, bars and histograms (#221): a one-line sparkline with optional min/max marks and a threshold; horizontal and vertical bars with labels and values; a histogram that bins raw values. They measure to their content and shrink to the width they get.
- Braille line and scatter charts (#257): several series on a 2×4 dot
canvas per cell, axes with ticks and labels, a legend, and an ASCII form
that plots with
*and.at cell resolution.
Acceptance: each chart renders at widths 1 to 200 without overflowing,
inside a Table cell and a Panel; ASCII output holds no character above
U+007F; snapshot tests for every glyph set.
2. KPI and status renderables — ext¶
- Gauges and bullet charts (#251): a value against a range, with target and threshold bands, compact (one line) and full-width forms.
- Heatmaps (#250): a labelled grid with value scaling and a legend; the
ASCII form uses shade characters (
.:-=+*#%@), so it still reads in black and white. - Status matrices (#254): rows and columns of states (pass, fail, skip, flaky, or your own), each state a symbol and a colour, never colour alone, with a legend.
- KPI cards (#256): a label, a value, a delta with its direction, an
optional sparkline and a status, sized to sit in a
Columnsor a grid. - Timelines and Gantt strips (#252): labelled ranges on a time scale, overlapping ranges stacked, milestones, and compression when the range is wider than the terminal.
Acceptance: as workstream 1, plus a dashboard example that combines
cards, a matrix and a timeline in a Layout and updates in Live.
3. rs-rich-diagram: the graph layout — new crate¶
- A generic graph model: nodes with labels and shapes, directed and undirected edges with labels and arrowheads, subgraphs as clusters.
- The layered layout lifted out of
rich-mermaid, unchanged in behaviour, over the generic model. Mermaid's flowcharts render through it, and its existing snapshot tests must not move. - Box-drawing primitives (#227) and network graphs (#258): the layout's drawing as a renderable, with ASCII junctions as the fallback, and a builder API for drawing a diagram from code.
Acceptance: Mermaid's snapshots byte-identical before and after the
move; a diagram built in code renders the same as the equivalent Mermaid
source; AGENTS.md lists rich-diagram in its dependency graph
(rich-diagram ──▶ rich, with rich-plugin-api behind the plugin
feature, and rich-mermaid ──▶ rich-diagram) and its versioning table.
4. Diagrams from real sources — diagram, ext, CLI¶
- DOT (#240): a parser for the DOT subset people write by hand (graph
and digraph, node and edge statements, attributes for label, shape and
style, subgraphs as clusters), rendered natively through workstream 3. A
plugin registers a
dotfence renderer and source renderer, like Mermaid; an optional backend runs Graphviz'sdotfor SVG, under the same trust rule asmmdc. - Cargo dependency graphs (#248):
cargo metadataread into a tree (rich deps), with duplicate versions highlighted,--why CRATEfor the paths that pull a crate in, and--graphto draw it through the layout. - JSON Schema (#244): a schema rendered as a tree of properties with
types, required markers, constraints,
$refs resolved within the document, andoneOf/anyOfbranches;rich schema FILE, andrich schema OLD NEWfor what changed between two versions.
Acceptance: each source renders from a fixture in CI; DOT inputs the parser does not support fail with a message naming the construct, not a partial drawing.
5. The CLI, Python and docs — CLI, py, docs¶
rich chart: a chart from CSV, JSON or stdin (--kind spark|bar| line|scatter|heatmap,--x,--y,--width), so a shell pipeline can draw.- Python:
rs_rich.chartandrs_rich.diagrambindings for every renderable above. - Docs: a chart guide and a diagram guide with a screenshot of every
renderable, tapes for
rich chart,rich depsand adotfence in Markdown, and gallery entries.
6. 0.0.14 follow-ups¶
The known limits listed in the 0.0.14 release notes, fixed where they are small:
:micro:markup in titles, captions and Markdown, not only--print.- Real graphics, not the fallback, in
rich asset --kind microandrich explore --icons. Confirm,Pager,TextArea,ColorPicker,FormandFilePickermatching keys through their declared keymaps, so they can be rebound.rich micro previewno longer labels a still image with a frame time ("100 ms").
Plugin components over the dylib and WASM ABI stay out: they need an ABI change of their own.
Order of work¶
- Workstreams 1 and 3 in parallel. Charts and the graph layout share nothing.
- Workstream 2 after 1's scale and glyph sets settle.
- Workstream 4 after 3.
- Workstream 6 at any point; each item is independent.
- Workstream 5 last, since it shows everything else.
- Release test.
Decisions¶
Decided with the maintainer on 2026-10-04 unless marked as a default.
- Charts live in
rich-ext(rich_ext::chart) (decided), not a new crate. They are renderables with no new dependencies, which is what ext is for; a separate crate would only add a release step. - A new crate,
rs-rich-diagram(rich_diagram) (decided), for the graph model, the layout and the DOT parser. It depends on core only (and on the plugin API behind apluginfeature), so Mermaid can use it without pulling in ext. It starts at 0.0.1, with a first upload through the release workflow's new-crate path. This is the same exception to "new renderers go inrich-ext" thatrich-mermaidalready is (it owns its diagram renderable today), andrich-microandrich-interactafter it: a crate with its own reason to exist, added to the dependency graph and the versioning table inAGENTS.mdby the pull request that creates it. - DOT is parsed natively (decided), with Graphviz optional. The native renderer
covers the hand-written subset; full Graphviz layout and SVG come from
the
dotbinary when it is installed and the config is trusted. - No core change (default). If a chart needs something core does not expose, it
goes through an extension-point trait in
protocol.rs, recorded in DIVERGENCES, andrs-richmoves to 0.0.10. None is expected. - If the release has to shrink (default), drop in this order: the JSON Schema diff, Gantt strips, the Graphviz backend, then the Cargo graph view (its tree stays).
Not in this release¶
- The other diagram plugins: PlantUML (#241), D2 (#242) and Vega/Vega-Lite (#243).
- OpenAPI (#245), AsyncAPI (#246) and ER diagrams from database schemas (#247).
- Grouped progress dashboards (#255), treemaps (#253) and call and module graphs (#249).
- The rich-art and asset-pack milestone (milestone 9), and plugin components over the dylib and WASM ABI.
Package impact¶
| Package | Proposed | Reason |
|---|---|---|
rs-rich |
0.0.9 (unchanged) | No core change is planned |
rs-rich-ext |
0.0.13 | rich_ext::chart, the schema tree |
rs-rich-diagram |
0.0.1 (new) | Graph model, layered layout, DOT |
rs-rich-mermaid |
0.0.4 | Draws through rs-rich-diagram |
rs-rich-micro |
0.0.2 | Requires ext 0.0.13; markup in titles and Markdown |
rs-rich-interact |
0.0.3 | Requires ext 0.0.13; rebindable keymaps, real graphics in the explorers |
rs-rich-record |
0.0.3 | Manifest only: requires ext 0.0.13 |
rs-rich-cli |
0.0.15 | rich chart, rich deps, rich schema, the dot fence |
rs-rich (PyPI) |
0.0.4 | rs_rich.chart and rs_rich.diagram |
rs-rich-art, rs-rich-plugin-api, rs-rich-lumis, rs-rich-macros |
unchanged | Nothing they need changes |
Cargo reads a 0.0.x requirement as an exact version, so every crate that
depends on a bumped crate moves with it. RELEASES.toml records the order,
and python scripts/release_cohort.py tag publishes it.
Delivered¶
| Workstream | Pull request | Merged as |
|---|---|---|
| Plan | #643 | ae20b42 |
3. rs-rich-diagram |
#644 | d1be516 |
| 1. Charts | #645 | 57dd384 |
| 2. KPI and status | #646 | 2a2ccf5 |
| 4. DOT, Cargo, JSON Schema | #647, fixes in #648 | f84b31c, 8bcd927 |
| 6. 0.0.14 follow-ups | #655 | 2d2221f |
| 5. CLI, Python and docs | #656 | 733eb91 |
| Release test: three audits, 27 fixes, validation (release notes) | #657 | 61d031a |
Review focus¶
- Core is untouched.
git diffshows nothing undercrates/rich/src, and every golden and the differential corpus are byte-identical. - Mermaid did not move. Its snapshots are byte-identical after the layout is lifted out.
- Every chart reads without colour. Each has a test with colour off and one with ASCII output.
- Widths hold. No chart overflows the width it is given, from 1 cell up.