Architecture¶
A sixteen-crate Cargo workspace, plus the Python bindings beside it, with a strict, one-directional dependency rule. Each crate versions independently. The manifest-version table tracks this checkout; registry badges show published versions.
┌────────────┐ ┌────────────┐ ┌───────────────────────────┐
│ rich-cli │ ──▶ │ rich-ext │ ──▶ │ rich (faithful core) │
│ (bin:rich) │ │ (our code) │ │ mirrors upstream `rich` │
│rs-rich-cli │ │rs-rich-ext │ │ rs-rich (crates.io name) │
└────────────┘ └────────────┘ └───────────────────────────┘
│ │ ▲ ▲
│ ├──────▶ rich-plugin-api ─┤ │
│ │ rs-rich-plugin-api │ │
│ │ macros feature │ │
│ ▼ │ │
│ ┌──────────────┐ │ │
│ │ rich-macros │ ───────────────┘ │
│ │rs-rich-macros│ (proc-macros) │
│ └──────────────┘ │
│ ┌──────────────┐ │
└──────────▶ │ rich-art │ ────────────────────┘
│ rs-rich-art │ (FIGlet, images, GIFs)
└──────────────┘
every arrow points towards the core; core depends on none of them
The diagram shows the original crates. The others follow the same rule:
rich-mermaid → rich-diagram → rich (with rich-plugin-api behind
features), rich-lumis → rich-plugin-api, and rich-record,
rich-interact, rich-micro and rich-data → rich-ext, and
rich-ratatui → rich (with rich-interact behind a feature), and
rich-intuituive → rich-interact, and rich-web → rich-intuituive and
rich-embed, and rich-embed → rich-intuituive and rich-record; the
CLI depends on rich-web only behind its off-by-default serve feature.
The full graph is in
AGENTS.md.
crates/rich— the faithful port of the Pythonrichlibrary. Mirrors upstream module-for-module. Which upstream release it reflects is recorded inUPSTREAM.toml, not in the crate version. Depends on nothing in this workspace and knows nothing about the other crates.crates/rich-ext— everything that is ours: extra highlighters, renderables (charts among them), the extension registry that hosts plugins, and the runtime plugin loaders. Independent SemVer. Talks to core only through public APIs and the extension traits.crates/rich-plugin-api— the plugin contract:Plugin,PluginMetadata,PluginRegistrar, the plugin-facing traits (SourceRenderer,TextTransform) andPLUGIN_API_VERSION. Depends onrichonly, so a plugin never needsrich-ext;rich-ext'sExtensionRegistryis the host that loads plugins. Independent SemVer. See PLUGINS.crates/rich-diagram— graph diagrams: a graph model with a builder, the layered layout, aDiagramrenderable, and a native DOT (Graphviz) parser with aDotrenderable. Behind itspluginfeature, adotfence and source renderer; behindgraphviz, Graphviz's own SVG through thedotprogram. Depends onrich(andrich-plugin-apiforplugin), never onrich-ext. The CLI uses it forrich dot,```dotfences andrich deps --graph. Independent SemVer.crates/rich-data— tabular data: a row source contract (column names, an optional schema inrich_ext::schema's model, rows ofrich_ext::table::Value), CSV/TSV (the port of Python'scsvsniffer and reader thatrich --csvandrich chartuse), JSON Lines and serde adapters, ArrowRecordBatches behind its off-by-defaultarrowfeature, opt-in type inference with evidence, and column statistics. Depends onrichandrich-ext's public API, never on core internals. Independent SemVer.crates/rich-ratatui— ratatui interop, both ways:RichWidgetdraws any rich renderable as a ratatui widget, thestyleandbuffermodules convert styles, colours, rich lines and buffer cells, and behind its off-by-defaultinteractfeatureRatatuiComponentruns ratatui widgets as arich-interactcomponent. Depends onrichandratatui-core(andrich-interactforinteract); nothing in the workspace depends on it, so ratatui stays out of every other crate's tree. Independent SemVer. See Using rich with ratatui.crates/rich-intuituive— intuiTUIve, the TUI framework: a per-app reactive runtime (signals, memos, timers), a retained tree of nodes drawn into its own cell screen (with hyperlinks) with a damaged diff, focus, key bubbling and clicks hit-tested against the retained layout, and headless testing. Built onrich-interact(its root is aComponent),rich-extandrich; ratatui is only a dev-dependency, for the benchmark CI gates it against. Independent SemVer. See Terminal apps and the design note.crates/rich-web— serving to a browser: one intuiTUIve app per WebSocket connection, each on its own thread, driven through intuiTUIve'sDriver, or one program per connection on a PTY (throughrich-embed'sPtyHost, held back when the page falls behind); an xterm.js page vendored in the crate (pinned by hash, embedded, never fetched from a CDN), or, for apps, a DOM renderer that carries the accessibility tree as ARIA. Synchronous (tungstenite, no async runtime); listens where it is told, with a URL token, anOrigincheck and a session cap. The CLI'srich serveuses it behind the off-by-defaultservefeature, so neither the framework nor the CLI's default build gains network code. Independent SemVer. See Serving an app to a browser.crates/rich-embed— other programs and web pages inside an intuiTUIve app: a terminal pane over aPtyHost(LocalPtythrough portable-pty,ReplayHostfor tests), its screen followed byrich-record's VT emulator; and a web view over aWebEngine(ProgramEngineruns a terminal browser the user installed; a headless Chrome over the DevTools protocol behind thechromefeature, Browsh's HTTP mode behindbrowsh). Its own crate so the framework gains no PTY, emulator or browser protocol;rich-webruns programs through itsLocalPty. Independent SemVer. See Embedding programs and pages.crates/rich-mermaid— Mermaid diagrams as a plugin: flowcharts drawn as text throughrich-diagram's layout, every diagram type through Mermaid's CLI (mmdc) behind itsmmdcfeature. Depends onrich,rich-plugin-api,rich-diagramand (formmdc)rich-art, never onrich-ext. The CLI registers it forrich mermaidand Markdown fences. Independent SemVer.crates/rich-lumis— the lumis (tree-sitter) syntax highlighter as aCodeHighlighter, with lumis's Neovim themes and upstream's ANSI themes, and a plugin that registers it as"lumis". Its own crate because lumis links tree-sitter's C runtime and grammars; it declares its own minimum Rust (lumis's). Depends onrichandrich-plugin-apionly. Independent SemVer.crates/rich-record— tapes: scripted terminal sessions run inbashon a PTY (portable-pty), followed by a VT emulator (vt100), and rendered as PNG, SVG and text screenshots, asciinema casts, GIF, MP4 and an HTML page, with an embedded DejaVu Sans Mono. The screen becomes arich_ext::frame::Frame, which gives the text grids, the SVGs (Frame::to_svg) and the page's HTML (Frame::to_html_with). Behindrich recordin the CLI (the defaultrecordfeature). Depends onrichandrich-ext. Independent SemVer.crates/rich-interact— interactive components between printing and a full TUI: aComponentstate machine, a blockingrunand anEventLoop, a terminalSessionrestored on every way out, a painter overrich_ext::framecell diffs, a headless driver for tests, and a policy that degrades to line prompts without a terminal. Ready-made pickers, input, confirm, forms, a pager, a text area, explorers and containers, with overlays and a keymap. Behindrich choose,filter,input,confirm,pager,write,file,color,assetandexplorein the CLI (the defaultinteractfeature), which paint on stderr. Depends onrichandrich-ext(andrich-microbehind itsmicrofeature). Independent SemVer.crates/rich-micro— micro assets: emoji-sized inline images written:micro:name:,.richmicropackages, a layered registry, an image pipeline, a built-in library, and drawing with Kitty, iTerm2, Sixel or half-blocks. Behindrich micro(the CLI's defaultartfeature). Depends onrich,rich-ext,rich-plugin-apiandrich-art. Independent SemVer.crates/rich-py— the Python bindings (rs-richon PyPI,import rs_rich), built with PyO3 and maturin. Rich's Python API over corerich, plus the port's own crates (rs_rich.ext,chart,diagram,mermaid,art,interact,micro,plugins) and therichcommand line: the compiled module converts arguments and writes output, and the Rust crates render. Outside the Cargo workspace (it needs a Python interpreter to build), with its own CI (python.yml) and release (pypi-release.yml). Never published to crates.io; see Python bindings.crates/rich-macros— procedural macros (richf!,style!,theme_key!,markup!,#[derive(Rich)]) that check markup and styles at compile time. Depends onrichonly (to parse markup and styles while expanding); users reach it throughrich-ext's optionalmacrosfeature. Independent SemVer.crates/rich-art— FIGlet banners, images as ASCII, Braille, blocks, quadrants or Sixel, animated GIFs and perceptual image diffs. Depends onrichonly. Independent SemVer.crates/rich-cli— the binary mirroring the Pythonrich-clitool (a separate upstream project with its own version). Built onrich,rich-extandrich-diagram, and behind its default featuresrich-artandrich-micro(art),rich-mermaid,rich-recordandrich-interact; its own commands are documented binary-boundary conveniences in PORTING.
Why the split: it makes upstream syncs a mechanical diff-and-port of crates/rich
only, and guarantees our features can never make that harder. See
AGENTS.md.
Render pipeline¶
&str (markup)
│ markup::render + Theme → Text (plain string + Style spans)
▼
Text crates/rich/src/text.rs
│ Highlighter(s) add spans (rich-ext, via Console)
│ Text::render(base, system) → Vec<Segment>
▼
Segment { text, style, control } crates/rich/src/segment.rs
│ Console applies color system (downgrade + SGR)
▼
ANSI bytes → stdout crates/rich/src/console.rs
ColorSystem (Standard / EightBit / Truecolor / Windows) is detected by the
Console and applied last: styles carry rich color information and are downgraded
to the target system at the final step via the redmean nearest-color search
(color::match_color, ported from rich.palette).
Key types¶
| type | file | upstream |
|---|---|---|
Color, ColorTriplet, ColorSystem |
color.rs |
rich.color |
Style |
style.rs |
rich.style |
Text, Span |
text.rs |
rich.text |
Segment |
segment.rs |
rich.segment |
Console, ConsoleBuilder |
console.rs |
rich.console |
Renderable, Highlighter (extension points) |
protocol.rs |
rich.protocol / rich.abc |
Theme |
theme.rs |
rich.theme |
See PORTING.md for the full module map and per-module status, and PLUGINS.md for the extension model.