0.0.19 plan: layout, editing, isolation, and docs you can see¶
Status: proposed on 2026-10-12, after the 0.0.18 cohort and rs-rich
0.0.6 on PyPI were published. It is stage 1 of the
plan to 1.0.0. Its four framework items were decided with the
maintainer on 2026-10-08 (see the 0.0.18 plan's
Not in this release); the docs workstream
was asked for on 2026-10-12. The decisions below were
answered on 2026-10-12. The tracker is
#732.
Goal: close the gaps a comparison with other terminal frameworks found, take the last known security edge out of rs-rich-embed, and make the docs show what the code does on every page.
- Flex alignment:
alignandjustify, andwrap, in layout and in the stylesheet, as Ink and iocraft have. - A text-area widget: a multi-line editor with syntax highlighting, selection and undo, as Textual has.
- One process per browser session in rs-rich-web, as textual-serve isolates each session.
- A
Surfacedrawing handle in rs-rich-ext: intuiTUIve's screen and damage-based painter moved down, with a smallsurface.draw(|s| …)API, so plain rich users get positioned rendering that repaints only what changed, as ratatui'sFramegives. - The Chrome web view's DevTools over a pipe, not a port other local users can reach. Moved to 0.0.20 on 2026-10-13: see workstream 5.
- Docs with an example and a picture on every page, and recordings of everything 0.0.18 added.
What stays the same: core. Nothing under crates/rich/src changes, and
every golden and the differential corpus stay byte-identical. The
intuiTUIve-against-ratatui benchmark gate keeps passing, now also with the
Surface underneath.
Research behind this plan¶
- The framework comparison (2026-10-08) behind the 0.0.18 plan's list:
Ink and iocraft lay out with flexbox alignment; Textual has a
TextAreawith highlighting; textual-serve runs a process per browser session; ratatui'sFramegives positioned, diffed drawing without a framework. - The code today (
mainate48551e): rich_intuituive::layoutsolves sizes along one axis (fixed, percent, flex, auto, with min/max clamps, as CSS resolves flexible lengths) and places children from the start; there is no cross-axis alignment, no main-axis distribution and no wrapping.sheet.rsknowssize,padding,gap,grid-rows,displayanddock, none for alignment.rich_interact::TextAreais a plain multi-line editor (rich write, #493): grapheme-aware editing and wrapping, no highlighting, selection or undo. intuiTUIve can host it as a text box.rs-rich-webruns each browser session's app on a thread in the server's process (http.rs);serve_commandalready runs each session's program on its own PTY.rich_intuituive::screenholds the cellScreenand thePainterthat writes only damaged cells;rich_ext::framealready hasFrame, its cell diff and graphics placement planning, which aSurfacecan build on.rs-rich-embed's Chrome engine starts Chrome with--remote-debugging-port=0, the known limit in the 0.0.18 notes.- A docs audit (2026-10-12) of every page under
docs/: - the Python site's 40 pages have examples but not one picture of what they print;
- these Rust guide pages have no screenshot at all: rs-rich-data (all three pages), ratatui interop, custom components in rs-rich-interact, sources, code highlighters and transforms in rs-rich-ext, intuiTUIve's web, embed and Python pages, getting started, tutorial step 6, and the overviews of the guide, the core guide, rs-rich-ext and micro assets; explorers in rs-rich-interact shows one of the explorers it describes;
- two guide pages are procedures, not output, and stay without one: the screen-reader checklist and the CLI smoke test;
- of 33 tapes, none shows a 0.0.18 feature: stylesheets, table sorting
and resizing, the lazy tree, tooltips, drag-and-drop, accessible and
linear mode,
rich serveor the terminal pane.
Workstreams¶
Each workstream lands as its own pull request, or a short stack, with an
entry under Delivered. Placement follows AGENTS.md: the
framework in rs-rich-intuituive, the drawing handle in rs-rich-ext, browser
serving in rs-rich-web, the web view in rs-rich-embed, Python in
crates/rich-py.
1. Flex alignment: intuituive¶
- Cross axis:
.align_items(Align::Start | Center | End | Stretch)on a container and.align_self(..)on a child.Stretchis today's behaviour and stays the default. - Main axis:
.justify(Justify::Start | Center | End | SpaceBetween | SpaceAround | SpaceEvenly), applied to what the flexible children leave; a container with a flexible child has nothing left, as in CSS. - Wrapping:
.wrap()on a row or column moves children that do not fit to a new line, each line solved as today;align_contentplaces the lines. - In the stylesheet:
align-items,align-self,justify-content,flex-wrapandalign-content, with CSS's names and values; code wins over the sheet, as for every other property. The inspector shows them. - Tests: solver unit tests against the rectangles CSS flexbox gives for the same boxes, each alignment in rows and columns, wrapped and not, and with min/max clamps.
2. A text-area widget: intuituive, interact, ext¶
text_area(text: Signal<String>)with.language("rust")for highlighting through the code highlighters (syntect by default, lumis when registered),.line_numbers(),.soft_wrap(bool)(horizontal scrolling when off),.read_only()and.placeholder(..).- Editing: grapheme-aware caret and editing shared with
rich_interact::TextAreaby moving its buffer intorich_interact::edit::Buffer, which both use; word moves (Ctrl+←/→), Home/End, PageUp/PageDown, indent and outdent with Tab and Shift+Tab. - Selection: Shift with any move, the mouse (drag, double-click a word, triple-click a line), select all; copy, cut and paste through OSC 52 and bracketed paste.
- Undo and redo (Ctrl+Z, Ctrl+Y or Ctrl+Shift+Z), grouping typed runs.
- Large text: stored by line, only the lines in view highlighted and drawn, so a 100,000-line file scrolls without a stall (a benchmark).
- Accessibility: a multi-line text box role, the caret line announced in linear mode.
- Python:
rs_rich.tui.text_area.
3. One process per browser session: web¶
serveruns each session in its own process. The server re-executes its own binary withRS_RICH_WEB_SESSIONset; the sameserve(addr, app)call in that child runs the app over a framed pipe instead of binding a port, so an app needs no change. The parent keeps the WebSocket and forwards input, resize, paste and output frames.- Limits per session: the process group is killed when the tab closes
or the server stops (as
serve_commanddoes since 0.0.18), and an optional memory and CPU-time limit (setrlimiton Unix). Isolation::Threadskeeps 0.0.18's behaviour for programs that cannot re-execute themselves (tests, embedded uses).- Python:
rs_rich.tui.servere-executes the interpreter with the same script and arguments. - Tests: a crash, a hang and a memory blow-up in one session leave the others and the server running.
4. A Surface drawing handle: ext, intuituive¶
rich_ext::surface::Surfaceowns a cell buffer, the previous frame and a writer.surface.draw(|s| { s.render(rect, &renderable); s.set_cursor(..) })renders any rich renderable into a rectangle, then writes only the cells that changed (rich_ext::frame's diff), in synchronized output where the terminal has it.- Alternate screen or inline (a fixed number of rows below the prompt), a resize handled by redrawing everything once, and graphics placements carried over from frames.
- intuiTUIve builds on it:
rich_intuituive::screen::{Screen, Painter}become re-exports of the ext types (names kept), so the benchmark gate measures the same code plain users get. - Python:
rs_rich.ext.Surface. - Docs: a guide page, "Positioned drawing", with the ratatui comparison.
5. DevTools over a pipe: embed¶
- Chrome starts with
--remote-debugging-pipe; the engine talks CDP over file descriptors 3 and 4 (NUL-separated JSON) and no port is opened. The descriptors are passed with thecommand-fdscrate, so the crate keepsunsafe_code = "deny". - Windows too (decision 6): Chrome takes the pipe there as two
inherited handles named by
--remote-debugging-io-pipes, whichstdcannot mark inheritable. The pipe ships on all three platforms or on none: if Windows cannot pass the handles withoutunsafein this workspace (through a maintained crate, ascommand-fdsdoes on Unix), the whole workstream moves to 0.0.20 and the port stays everywhere, still documented as a known limit. - Tests: no listening socket appears while a view is open, on Linux, macOS and Windows, and the existing CDP tests pass over the pipe.
- Moved to 0.0.20 (2026-10-13). Windows fails the test above. Chrome
takes the pipe there either as
--remote-debugging-io-pipes=READ,WRITE(two inheritable handle values in one switch) or as C runtime descriptors 3 and 4 (STARTUPINFO.lpReserved2).stdcan do neither,os_pipeandfiledescriptormake handles that are not inheritable, and the one crate that passes handles to a child,windows-spawn(one 0.1.0 release, August 2026), puts each handle in an argument of its own and cannot write both into one switch. So the port stays on every platform, still a known limit, and rs-rich-embed's 0.0.19 change is its manifest only. The workstream is first in line for 0.0.20 once Windows has a way through.
6. Docs: an example and a picture on every page¶
Docs only: no package versions move for this workstream, and it starts at once, beside the others.
- The Python site gets its pictures. Each Python page's examples move
into
crates/rich-py/examples/docs/<page>.py, rendered by a newscripts/capture_python_docs.pywithConsole(record=True)intodocs/python/media/*.svg, and shown under each example.--checkruns in the Python workflow, so a picture that no longer matches its code fails CI, ascapture_guide.py --checkdoes for Rust. - Every Rust guide page shows output. A
guide_*.rsexample and its screenshot for each page the audit listed, the overviews included, and for each explorer the explorers page describes, captured byscripts/capture_guide.pylike the rest. The two procedure pages are the exception. - Recordings of 0.0.18: tapes for the stylesheet (with hot reload),
table sorting, resizing and the cell cursor, the lazy tree, tooltips
and drag-and-drop, accessible and linear mode,
rich serveand the terminal pane; and for 0.0.19's own features as they land (alignment, the text area, the surface). Each is on the recordings page and on its guide page. - The browser pages: screenshots of the xterm.js page and the DOM renderer, taken with Playwright from a scripted session, on the web page.
- Runnable, not pasted: every new example is a compiled example program or a script CI runs, so the code on a page cannot drift from the code that made its picture.
Added on 2026-10-17 and after¶
More workstreams, taken into this release after the release test while nothing was tagged. Each lands in a package this cohort already moves, so the version numbers below stand; the release test runs again over them.
7. Windows: a session's process tree: web¶
Closes the Windows gap the release PR's review found: ending a session, or a killed server, ended only the session's process there.
- Each session's process goes in a job object the server creates and holds the only handle to, with kill-on-close: ending the session drops it, and the system closes it when the server dies, so the process and everything it started end either way, with no watcher.
- Through
win32job, a safe API, so the crate keepsunsafe_code = "deny". It cannot set a job's memory or CPU limits, so those stay Unix only. - A new required CI job,
windows-web, runs the Windows tests: a closed tab, a stopped server and a killed server each end the session's process and the program it started.
8. Responsive layout, an error state and snapshot tests: intuituive¶
Issues #712 and #713.
hide_below(columns),show_below(columns)and their height forms, and@media (max-width: N)in the stylesheet (CSS's names, cells for units);viewport()gives the size in a signal.:error(:invalidtoo) set byerror_when(condition), styled by the theme'serrorandborder.errorstyles, andaria-invalidfor assistive technology.intuituive::testing:assert_screen!snapshots of the screen as text (or markup), updated withUPDATE_SNAPSHOTS=1, and the driver'spress,type_textandassert_focused.- Python: the same builders,
viewport()and the snapshot helpers.
9. Wide and long tables: interact, intuituive, cli¶
Issues #717 and #716.
scroll_x()andfreeze_columns(n)on intuiTUIve tables andTableSelect: columns at their natural widths, scrolled across, with the header aligned,‹and›for what is out of view, and the cursor followed.Viewport::sticky(n),Pager::sticky_header(n)andPager::sticky_table_header(true), which finds a table's header in rendered lines;rich pagerkeeps a table's header on top by default.rich ... --pagerstill runs the system pager, as upstream does.
10. Reorderable lists and date and time pickers: interact, intuituive, cli¶
Issues #720 and #719. Each is in new modules (components/reorder.rs,
components/date.rs, datetime.rs in interact; reorder.rs,
datetime.rs in intuiTUIve).
- Reorder:
rich_interact::Reorder, and.reorderable(on_reorder)on an intuiTUIvelist. Alt or Ctrl with the arrows,K/Jfor any terminal, Space to grab, and a drag; without a terminal, the new order as numbers. - Dates and times:
rich_interact::datetime(Datemoved from intuiTUIve,Time,DateTime; hand-rolled, no dependency),DatePicker,TimePickerandDateTimePickerwith a range and a validator; the calendar's range,time_pickeranddatetime_pickerin intuiTUIve. rich date: a CLI binary-boundary convenience composing the public interact pickers, likerich color; recorded indocs/PORTING.md.- Python:
rs_rich.interact.Reorder,DatePicker,TimePicker,DateTimePicker;Node.reorderable,time_picker,datetime_pickerandcalendar_with(min=, max=)inrs_rich.tui.
11. The inspector: selection, timings and a trace: intuituive¶
Issues #714 and #721.
- Shift+F12 (or a click on the panel) gives the inspector the keys: select a node in the tree or pick one with the pointer, see its bounds, constraints, who set them, its states and the rule that hides it, with the node outlined on the app.
- Per-node draw counts and times, per-frame totals, and a trace of keys,
the mouse, focus, screens, signal writes (by the
file:linethat made and wrote the signal), timers and tasks, in a ring of 1,000 entries. - Nothing is measured while the inspector is closed; an app with a closed inspector sends the same bytes as one without.
- termwiz on Windows in CI's backends job; the
filesandscopeexamples take--backend NAME.
12. Org, AsciiDoc and man pages: ext, cli¶
Issues #591 to #595.
rich_ext::document: one registry of document formats, each with extensions, a content sniffer and a renderer that reports diagnostics. Markdown, reStructuredText, Org, AsciiDoc and man are built in; a plugin's source renderer joins through an adapter.- Org, AsciiDoc and man(7)/mdoc(7) parse into one small block and inline
model, drawn in the look of core's
Markdownwith itsmarkdown.*styles. - No input makes a parser panic; nesting is capped, inline parsing is linear, and a stress test feeds garbled input to all three.
rich --org,--asciidocand--man, the same names as subcommands, and detection by extension, with the content agreeing for.1to.9. A tape shows each format.
13. What ratatui draws: intuituive, ext¶
A comparison of intuiTUIve with ratatui 0.30, intuiTUIve against ratatui, ranks the gaps; three batches close the ones that fit this release, and ports of ratatui's demos show them.
- Blocks, text and layout: titles on both edges, every border kind, shadows, a style on any node, text alignment and overflow, ratio sizes and layout by hand, collapsed borders, drawing over children, layers and theme styles for a subtree.
- Widgets, input and the shell: list and table options (symbols, directions, footers, gaps, multi-line rows, no selection), scrollbars on every scrolling widget, tab strip options, single-line and number inputs, modal shadows and backdrops, printing above an inline app, and quitting with a value or an error.
- Charts, the canvas and colour (rs-rich-ext): charts fill their node; fill and line gauges, taller sparklines, grouped bars, area charts, more canvas markers, a world map from Natural Earth's public-domain coastlines, and the Tailwind and Material palettes; the calendar's events, surrounding days and first weekday.
- Demos: ratatui's
demoanddemo2, its widget galleries and some of its apps, rebuilt on intuiTUIve's API with credit to ratatui (MIT).
14. rich log: filters, follow mode and groups: ext, interact, cli¶
Issue #724.
--level warn+and--where 'latency_ms>500'(comparisons, regular expressions, presence), applied while the records stream.--follow, which reads a truncated or replaced file again; repeats folded into one line with a count; groups by trace, span or correlation id; a summary of levels and the groups with errors.- Plain-text lines read by logfmt,
LEVEL message, RFC 3339 and access-log parsers; a line none reads joins the record before it or shows as text. --output jsonl,--redact, and-i, a live view in rs-rich-interact (LogView) with a filter line, pause and expandable records.
15. rich deps: sizes, baselines and licence policy: ext, cli¶
Issues #706 and #704.
--sizes: each crate's artifact size from a target directory, or from cargo-bloat's JSON, with--source-sizes.--baselinewith--timingsor--sizes: a unit-by-unit comparison that fails (exit 5, as--auditdoes) when a unit grows past both a percentage and a floor;--savekeeps a report for the next run.--policy: allow and deny lists, in rich's format or cargo-deny's[licenses], with SPDXOR,ANDandWITHread properly; conflicts with the root crate's licence, labelled a heuristic; and--sbomfor SPDX and CycloneDX JSON.
16. Charts that read aloud, distributions and small multiples: ext¶
Issues #726 and #702.
- Every chart describes itself for a screen reader (
AccessibleText): its kind, ranges and key values; intuiTUIve'sdescribed(..)reads it in linear mode. DistributionandDistributionSet(quantiles, a box strip) andSmallMultiples, a grid of charts on one scale.VirtualTablewindows columns as it does rows, with frozen columns, and fetches only the columns in view.
17. Nested JSON Lines profiles and style rules: data, ext, cli¶
Issues #705 and #701.
rich profilereads JSON Lines path by path (a.b,items[].id), with presence, absence and the mix of JSON types per path;--flatkeeps the old profile.--style-rule 'latency>500:bold red',--rules FILEand[[rules]]in config profiles style tables by value;StyleRulein Python.
18. Micro assets over two rows: micro¶
Issue #711.
- Sizes up to 4×2; the rows a two-row asset needs are reserved in text, tables and panels, and drawn by Kitty, iTerm2, Sixel and half-blocks.
19. A PNG of the output and a redaction preview: record, ext, cli¶
Issues #723 and #722.
--export-pngbeside--export-svgand--export-html, drawn by the tape screenshots' renderer, so the same output gives the same image.--redact-previewonrich captureandrich log: every match, its rule and its replacement, and nothing written;Redactor::previewin the library.
20. An approval queue and a jump-to-anything navigator: interact, cli¶
Issues #471 and #484.
ApprovalQueue: approve, reject or skip items one by one or marked together, with reasons, a detail pane and a report;rich approvewrites decisions as JSON Lines.Jump: one fuzzy box over files, headings, symbols, commands and recent picks, in groups with prefixes;rich jump.
21. Banners, playback controls and shell integration: cli¶
Issues #708 and #715.
rich banner: FIGlet text with fonts, gradients, alignment and fitting.--speed,--fps,--max-framesand--max-durationfor GIFs.rich shell init bash|zsh|fish|powershell: completions, OSC 133 marks and a status line after each command;rich shell statusandlink.
Order of work¶
- Docs (6) starts at once; it needs nothing else.
- Surface (4) next among the code, because it moves intuiTUIve's screen and painter, which alignment and the text area draw through.
- Alignment (1) and the text area (2) in parallel after it.
- Process isolation (3) and the DevTools pipe (5) at any time; neither touches the others.
- The tapes for 1, 2 and 4 join workstream 6 as each lands.
- The release test: three independent audits, as for 0.0.18.
- The additions (7 to 21) after it, in parallel, then the release test again over them.
Decisions¶
Decided on 2026-10-12 (5 on 2026-10-08):
- Stylesheet names: CSS's (
align-items,justify-content,flex-wrap,align-self,align-content), as the sheet is a CSS subset. - Wrapping: in this release, with alignment.
- The text area's editing model: one buffer,
edit::Bufferin rs-rich-interact, shared withrich_interact::TextArea, so grapheme and paste fixes land once. - Process isolation by default for
serve, with threads as the opt-out. Surfacein rs-rich-ext. It bumps rs-rich-ext, so every crate that depends on it moves too (see Package impact).- The DevTools pipe ships on every platform or none. Windows does not keep the port while Linux and macOS move to the pipe; behaviour stays the same everywhere (see workstream 5).
- Browser screenshots are regenerated at release time, not checked in CI, since browser font rendering differs between machines. The terminal recordings stay CI-checked.
- More in this release (2026-10-17): Windows process-tree cleanup, intuiTUIve's responsive layout, error state and snapshot tests, wide and long tables, and reorderable lists with date and time pickers (workstreams 7 to 10); then the inspector and Org, AsciiDoc and man pages (11 and 12).
Not in this release¶
- An SSH front end for served apps (after process isolation).
- A visual stylesheet editor, sibling selectors,
!important, animations or transitions in the stylesheet. - Platform accessibility bridges (AT-SPI, UI Automation, the macOS API).
- Anything in core.
- Other feature work from the theme milestones; 0.0.20 and 0.0.21 are the parity releases.
Package impact¶
| Package | Proposed | Reason |
|---|---|---|
rs-rich-ext |
0.0.16 | Surface; Org, AsciiDoc and man pages; ratatui's charts; the log stream; dependency sizes, comparisons and licence policy |
rs-rich-interact |
0.0.7 | edit::Buffer, wide tables and sticky headers, Reorder, date and time pickers, LogView; requires ext 0.0.16 |
rs-rich-intuituive |
0.0.4 | Alignment, the text area, the surface; responsive layout, :error, snapshots, wide tables, reordering, date and time pickers |
rs-rich-web |
0.0.2 | Process per session, with job objects on Windows |
rs-rich-embed |
0.0.2 | Manifest only: requires intuituive 0.0.4 (the DevTools pipe moved to 0.0.20) |
rs-rich-micro |
0.0.5 | Two-row assets; requires ext 0.0.16 |
rs-rich-record |
0.0.7 | PNG rendering of any output; requires ext 0.0.16 |
rs-rich-data |
0.0.3 | Nested JSON Lines profiles; requires ext 0.0.16 |
rs-rich-ratatui |
0.0.4 | Manifest only: requires interact 0.0.7 |
rs-rich-cli |
0.0.19 | rich date, rich pager --sticky, --org, --asciidoc, --man, rich log's filters, follow mode and groups, rich deps --sizes, --baseline and --policy; requires the versions above |
rs-rich (PyPI) |
0.0.7 | text_area, Surface, process isolation, and the additions' bindings |
Core, the plugin API, macros, art, diagram, mermaid and lumis do not change.
Delivered¶
| Workstream | PR | Merged as |
|---|---|---|
| 1. Flex alignment | #745 | d019885 |
| 2. Text area | #746 | 8ecec8b |
| 3. Process per session | #747 | 0c6df8d |
4. Surface |
#744 | 208d350 |
| 5. DevTools pipe | — | Moved to 0.0.20 (why) |
| 6. Docs: examples and recordings | #734, #748 (the surface recording) | 28a13cb, f817c76 |
| 7. Windows process trees | The release PR (#750) | |
8. Responsive layout, :error, snapshots |
The release PR | |
| 9. Wide and long tables | The release PR | |
| 10. Reordering, date and time pickers | The release PR | |
| 11. The inspector | The release PR | |
| 12. Org, AsciiDoc and man pages | The release PR | |
| 13. What ratatui draws | The release PR | |
14. rich log |
The release PR | |
15. rich deps sizes, baselines, policy |
The release PR | |
| 16. Charts that read aloud | The release PR | |
| 17. Nested profiles, style rules | The release PR | |
| 18. Two-row micro assets | The release PR | |
| 19. PNG export, redaction preview | The release PR | |
| 20. Approval queue, navigator | The release PR | |
| 21. Banners, playback, shell integration | The release PR | |
| Release test | Audit fixes in #747, #748 and #749 (04d7cff); notes and validation in the release PR |
Review focus¶
- Alignment against CSS: every alignment and wrap case matches what a
browser lays out for the same boxes; nothing changes for a container
that sets none (
Stretch,Start, no wrap). - The text area under load: a 100,000-line file, a long line without wrapping, wide and combining characters, a paste with controls in it, undo across a paste.
- Isolation for real: a session that crashes, hangs or eats memory does not touch the others; no orphan process survives a closed tab, a server stop or a signal.
- The
Surfacemoves without a behaviour change for intuiTUIve: every intuiTUIve test, tape and the benchmark gate pass unchanged. - No
unsafeenters the workspace. (The web view's port stays until the pipe lands in 0.0.20; see workstream 5.) - Docs pictures match their code:
capture_guide.py --check,capture_python_docs.py --checkandrich record --checkall pass.