Skip to main content

hermes-rich-ui

❖ Communityv0.1.0

Rich, evidence-backed answer cards — tables, charts, metrics, timelines, sources — rendered inline in the desktop transcript

Open in Hermes Desktop
hermes plugins install hermes-rich-ui

Screenshots

What it adds

Tools 1

rich_present

README

From the reviewed commit 754ae51 ↗; it updates when the author re-pins.

hermes-rich-ui

Publish rich, read-only answer cards from Hermes agents. One rich_present tool call turns an agent's real, gathered data — table rows, chart series, metrics, a dated sequence, cited sources — into an A2UI v1.0 createSurface record against the read-only hermes-rich-ui/1 catalog (18 component types). The agent's reply carries a ::richui{id="<card_id>"} directive that the Hermes desktop transcript expands into an inline card, rendered by the zod-stubbed Renderer from @json-render/react 0.21.0 with uPlot 1.6.32 charts. Nothing renders until a stdlib-only admission engine has validated the record against the frozen docs/CONTRACTS.md budgets — a rejected card is rejected before a byte is written to the card store.

All three images are pixel-real captures of the renderer (no mockups): a metrics card showing every value format — including null rendering as unavailable, never as 0 — a four-kind chart card, and an all-components fixture card (timeline, tabs, accordion, table, chart, sources).

The two halves

Half Runs on Installs to
Gateway (tools, admission, card store, REST) the machine running hermes serve ~/.hermes/plugins/hermes-rich-ui/
Desktop (transcript renderer) the APP machine ~/.hermes/desktop-plugins/hermes-rich-ui/plugin.js

No patched core required. This is a pure Hermes plugin: the gateway half registers its tools through the public plugin API, and the desktop half is one bundled ESM file loaded through the public desktop-plugin mechanism. Nothing here forks, patches, or reaches into Hermes internals.

Quickstart

Both halves must be installed for cards to render; each is harmless alone (INSTALL.md has the negative-control walkthrough for one-half-installed cases).

Half 1 — gateway (on the hermes serve machine):

cp -r dashboard/ engine/ catalog/ skill/ ~/.hermes/plugins/hermes-rich-ui/

Enable it in ~/.hermes/config.yaml, then restart:

plugins:
  enabled:
    - hermes-rich-ui
hermes serve

The serve log must print Mounted plugin API routes: /api/plugins/hermes-rich-ui/, and curl -s http://<gateway>/api/plugins/hermes-rich-ui/health must return {ok:true, ...}.

Half 2 — desktop (on the machine running the Hermes desktop app):

mkdir -p ~/.hermes/desktop-plugins/hermes-rich-ui
cp desktop/plugin.js ~/.hermes/desktop-plugins/hermes-rich-ui/plugin.js
sha256sum -c desktop/plugin.js.sha256    # Linux  (macOS: shasum -a 256 -c)

Then open Settings → Plugins (Capabilities) in the app, flip hermes-rich-ui on, and reload. From then on, agents can call rich_present and paste the returned directive line into their reply.

Philosophy: read-only, evidence-first

  • 18 read-only component types. No forms, no actions, no scripts, no network calls from the card. Local interaction (sort/filter/page, chart hover, tabs, expand) is built into the renderer, never authored in the spec.
  • The agent authors only content; the gateway mints identities, admits the record against docs/CONTRACTS.md budgets (rejects, never truncates), stores it under $HERMES_HOME/rich-ui/cards/, and returns the directive.
  • Every bound value is a data binding ({"path": "/data/..."} / {"path": "/meta/..."}). Unknown values are null and render as "unavailable", never as 0.
  • External claims carry sources and per-element sourceIds; computed values carry derivations with method and input paths. Fabricating series, prices, or history to fill a card is forbidden by the authoring contract (skill/SKILL.md).
  • Chart engine is one library: uPlot 1.6.32 (bar / line / histogram / scatter).

Security posture

  • Read-only catalog. No actions, no data-model writeback, no event handlers, no catalogId overrides. Cards cannot ask for refresh or push data anywhere; interactive refresh belongs to trusted chrome, never to spec fields.
  • SDK-only renderer. The desktop bundle imports only react, react/jsx-runtime, and @hermes/plugin-sdk. Every attempt to bypass the sandbox is caught at build time by a banned-surface scan that rejects window.hermesDesktop, localStorage, document.querySelector, innerHTML, eval, new Function, dynamic import(), and bare document/window (one content-allowlisted uPlot environment guard is the sole exception) — any hit fails the build.
  • Admission before persistence. The stdlib-only Python engine (no third-party imports anywhere in the gateway half) validates structure, budgets, binding paths, and URL schemes (https:// only) and rejects the whole card on any violation; nothing is written to the card store until admission passes.
  • No self-updater. Nothing downloads or swaps code at runtime. The committed bundle is the artifact, and CI rebuilds it and fails on any diff.

The 18 types (catalog hermes-rich-ui/1)

# component purpose
1 Card the card itself: title, subtitle, children
2 Stack vertical/horizontal arrangement
3 Grid 1–4 column layout
4 Divider section separation, optional label
5 Tabs switch between 1–8 child views
6 Accordion 1–12 expandable sections
7 Heading level 1–3 heading
8 Text plain explanatory text, tone/variant
9 Callout takeaway, limit, or uncertainty
10 Badge compact categorical label
11 Metric one salient scalar (null ⇒ unavailable)
12 Progress completed/total, or indeterminate
13 KeyValueList compact label/value facts
14 Image https-only image with required alt
15 DataTable typed, sortable, pageable rows
16 Chart bar / line / histogram / scatter (uPlot)
17 Timeline dated or labeled sequence
18 SourceList evidence and provenance

Props are frozen in docs/CONTRACTS.md §2; authoring guidance lives in skill/SKILL.md with complete recipe examples in skill/references/recipes.md.

Where to go next

Contributions keep the tree publish-clean: python3 scripts/make_public.py /tmp/public-tree (also run by tests/test_public_strings.py in CI) audits every shipped file for machine-specific strings and refuses to export if any un-allow-listed hit remains.

MIT licensed — see LICENSE (Jacob Hausler).

← Back to the catalog · catalog built Sep 28, 2026