Skip to content

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, a Panel, a Layout or a Live display 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's DiagnosticsDashboard counts levels in a table, and fidelity.rs only 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.rs is 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 a Flowchart, not a generic graph, so it has to be lifted out before DOT or Cargo can use it.
  • Braille is image-only. rich-art's BrailleArt maps a decoded image to 2×4 dots per cell. rich-ext does not depend on rich-art, so charts get their own small dot canvas rather than an image decoder.
  • The plugin seams are enough. PluginRegistrar::renderer and fence_renderer already carry Mermaid; a DOT plugin needs nothing new in rs-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 or fidelity asks 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 Columns or 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 dot fence renderer and source renderer, like Mermaid; an optional backend runs Graphviz's dot for SVG, under the same trust rule as mmdc.
  • Cargo dependency graphs (#248): cargo metadata read into a tree (rich deps), with duplicate versions highlighted, --why CRATE for the paths that pull a crate in, and --graph to 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, and oneOf/anyOf branches; rich schema FILE, and rich schema OLD NEW for 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.chart and rs_rich.diagram bindings for every renderable above.
  • Docs: a chart guide and a diagram guide with a screenshot of every renderable, tapes for rich chart, rich deps and a dot fence 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 micro and rich explore --icons.
  • Confirm, Pager, TextArea, ColorPicker, Form and FilePicker matching keys through their declared keymaps, so they can be rebound.
  • rich micro preview no 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

  1. Workstreams 1 and 3 in parallel. Charts and the graph layout share nothing.
  2. Workstream 2 after 1's scale and glyph sets settle.
  3. Workstream 4 after 3.
  4. Workstream 6 at any point; each item is independent.
  5. Workstream 5 last, since it shows everything else.
  6. 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 a plugin feature), 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 in rich-ext" that rich-mermaid already is (it owns its diagram renderable today), and rich-micro and rich-interact after it: a crate with its own reason to exist, added to the dependency graph and the versioning table in AGENTS.md by 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 dot binary 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, and rs-rich moves 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

  1. Core is untouched. git diff shows nothing under crates/rich/src, and every golden and the differential corpus are byte-identical.
  2. Mermaid did not move. Its snapshots are byte-identical after the layout is lifted out.
  3. Every chart reads without colour. Each has a test with colour off and one with ASCII output.
  4. Widths hold. No chart overflows the width it is given, from 1 cell up.