agent-ui-render is a native CLI for agent-authored UI previews. Coding agents
write compact, governed JSON; the CLI validates, normalizes, plans, and renders
that data into browser-openable HTML, no-JS static HTML, or a Vue handoff bundle.
The runtime is Rust. The visual renderer is authored in Vue during development
and embedded into the release binary, so installed users do not need Node,
Bun, npm, Vue, or node_modules.
- Give coding agents a small, safe UI output contract instead of asking them to hand-write HTML, CSS, Vue, React, or JavaScript.
- Convert compact model-authored
version: 1semantic reports,version: 2advanced chart payloads, andversion: 3native multi-panel reports into validated runtime data before anything is rendered. - Produce portable preview artifacts for reports, tables, metric cards, charts, alerts, and markdown narrative.
- Keep release artifacts as single native binaries plus installer scripts.
Anthropic's Using Claude Code: The unreasonable effectiveness of HTML makes a point this project agrees with: HTML is a useful artifact boundary for agent work because it is portable, inspectable, and immediately useful in a browser.
agent-ui-render optimizes a different part of that workflow. Having an LLM
agent directly author full HTML, CSS, and JavaScript is expressive, but for
report-like UIs it spends expensive output tokens on repeated tags, styles,
boilerplate, and layout code. Output tokens are also typically priced higher than
input tokens, so repeating UI markup is a poor place to spend model budget when
the underlying result is mostly data plus visual intent.
This project keeps the useful HTML artifact, but moves verbose rendering into a tool:
+----------------------------+ compact data +------------------+
| LLM agent | -----------------------> | agent-ui-render |
| facts + visual intent | | validate/render |
+----------------------------+ +--------+---------+
|
v
+------------------+
| HTML artifact |
| browser-ready |
+------------------+
The model emits a compact dataset-oriented payload; the trusted CLI expands it into validated runtime data and renders the HTML. That reduces output-token usage, centralizes rendering and safety rules, and gives agents a smaller, repeatable contract for charts, tables, metrics, alerts, and markdown narrative.
The historical v0.1 baseline benchmark used claude-sonnet-5 at medium effort
across 10 report cases, with three repetitions per configuration: 30 direct-HTML
runs and 30 agent-ui-render runs. Both configurations produced 30/30 artifacts
that passed the same fact-preservation, structure, and headless-browser checks.
The exact project commit was ca173c9; treat these numbers as a reproducible
baseline rather than a fresh measurement of the current renderer and Skill.
The compact payload reduced mean model output from 5,184 to 344 tokens, a 93.4% reduction (95% CI: 92.4% to 94.2%). The full Skill and reference context increased effective input tokens, so raw input-plus-output volume rose 37.1%. This project therefore claims lower model output, not lower total context volume.
Actual measured API cost fell from $0.0817 to $0.0098 per accepted artifact, an 88.0% reduction (95% CI: 85.3% to 89.9%). These costs include prompt caching and the single repair call required by each configuration.
The benchmark also reduced mean model duration from 37.25 seconds to 3.82
seconds. See the formal benchmark report and
machine-readable summary for the complete method, caveats,
confidence intervals, and reproducible harness. Fresh runs can publish sanitized
aggregate evidence with benchmarks/token-ab/run.py --publish-dir <directory>;
see the harness README for the required explicit spend envelope.
The same compact payload can render as different host-selected themes without asking the agent to rewrite the UI.
| Report Light | Executive Clean | Technical Dark |
|---|---|---|
![]() |
![]() |
![]() |
The showcase payload lives at
docs/assets/screenshots/markdown-brief.input.json; regenerate all three shots
from the same source and renderer commit with make showcase-screenshots.
Compact v3 renders accessible desktop tabs and a labelled mobile section selector while keeping the report in one offline file:
The fully synthetic 11-panel payload is
examples/v3-tabbed-fleet.input.json. Render it with
agent-ui-render render html examples/v3-tabbed-fleet.input.json report.html.
Regenerate its light, dark, and mobile captures with
make v3-showcase-screenshots.
base="https://github.com/NeoHsu/agent-ui-render/releases/latest/download"
curl --proto '=https' --tlsv1.2 -LsSf \
"$base/agent-ui-render-installer.sh" | sh$base = "https://github.com/NeoHsu/agent-ui-render/releases/latest/download"
irm "$base/agent-ui-render-installer.ps1" | iex| Platform | Asset |
|---|---|
| Apple Silicon macOS | agent-ui-render-aarch64-apple-darwin.tar.xz |
| Intel macOS | agent-ui-render-x86_64-apple-darwin.tar.xz |
| ARM64 Linux | agent-ui-render-aarch64-unknown-linux-gnu.tar.xz |
| x64 Linux | agent-ui-render-x86_64-unknown-linux-gnu.tar.xz |
| x64 Windows | agent-ui-render-x86_64-pc-windows-msvc.zip |
Each archive contains the prebuilt agent-ui-render executable plus release
metadata. Checksums are published next to the release assets, and each platform
archive has GitHub build-provenance attestation. Verify a download before use:
gh attestation verify <archive> --repo NeoHsu/agent-ui-rendermise use -g github:NeoHsu/agent-ui-renderIn mise.toml:
[tools]
"github:NeoHsu/agent-ui-render" = "latest"From the published repository:
cargo install --git https://github.com/NeoHsu/agent-ui-render agent-ui-renderFrom a local checkout:
mise install
make setup
make generate
cargo install --path crates/agent-ui-render-cliVerify the install:
agent-ui-render --version
agent-ui-render --helpInstall the bundled AI agent skill so coding agents know how to author compact Agent UI payloads instead of hand-writing HTML, CSS, JavaScript, or arbitrary UI components.
From the published repository:
npx skills add NeoHsu/agent-ui-render --skill agent-ui-renderFrom a local checkout of this repo:
npx skills add . --skill agent-ui-renderFor non-interactive setup across all supported agents, add --agent '*' -y:
npx skills add . --skill agent-ui-render --agent '*' -yUse --copy if you want the installed skill to be a standalone copy instead of
a symlink back to the repo checkout:
npx skills add . --skill agent-ui-render --copyThe CLI install gives agents a renderer; the skill install gives agents the payload contract and safety rules. Keep them from the same release and verify the installed pair using the Skill directory reported by the installer:
agent-ui-render --warnings-as-errors skill check --discoverFor a local checkout, the equivalent check is:
agent-ui-render --warnings-as-errors skill check skills/agent-ui-render --discoverThe machine-readable skills/agent-ui-render/compatibility.json records the
Skill version, minimum/recommended CLI versions, input versions, and required
schemas. A missing manifest identifies a legacy Skill; a newer CLI reports an
older Skill before its capabilities are silently missed. This is an offline
pairing check, not a network update check: two equally old installations cannot
know that a newer GitHub release exists. Discovery is bounded to explicit,
AGENT_UI_RENDER_SKILL_DIR, project, and common user-level Skill paths; it never
recursively scans the home directory.
Create a compact input file:
cat > /tmp/revenue.input.json <<'JSON'
{
"version": 1,
"t": "Revenue Overview",
"d": [
[
"sales",
[["month", "s"], ["revenue", "cur", "USD"]],
[["Jan", 120000], ["Feb", 135000]]
]
],
"v": [["t", 0, 0, [1]], ["r", 0]]
}
JSONValidate and render it:
agent-ui-render validate /tmp/revenue.input.json
agent-ui-render render html /tmp/revenue.input.json /tmp/revenue.html
agent-ui-render render static-html /tmp/revenue.input.json /tmp/revenue.static.htmlOpen /tmp/revenue.html in a browser.
+------------------------------+
| Compact payload (v1/v2/v3) |
+---------------+--------------+
|
v
+------------------------------+
| agent-ui-render validate |
| - structure and references |
| - unsafe content and limits |
+---------------+--------------+
|
v
+------------------------------+
| Normalize to domain::Report |
+---------------+--------------+
|
+-------+-------+----------------+
| | |
v v v
+---------------+ +-------------+ +----------------+
| plan ui.spec | | render html | | render vue |
| JSON | | or static | | handoff bundle |
+---------------+ +-------------+ +----------------+
{
"version": 1,
"t": "Revenue Overview",
"d": [["sales", [["month", "s"], ["revenue", "cur", "USD"]], [["Jan", 120000]]]],
"v": [["t", 0, 0, [1]], ["r", 0]]
}The compact wire format uses dataset indexes and short view/alert codes to keep
LLM output small. Compact code mappings live in wire::compact; normalize
expands them into the clean domain::Report model with
schema: "ui.input.normalized" with the matching input version before planning
or rendering. Version 2 adds governed chart opcodes backed internally by
Vega-Lite. Version 3 adds governed report panels, methodology metadata, and an
optional runtime light/dark control while reusing global datasets and existing
view tuples. Raw Vega-Lite specs, images, isotypes, and maps are not accepted.
Tabs organize content but are not access control: hidden panel data remains in
the same single-file artifact. See docs/tabbed-reports-v3.md.
agent-ui-render validate <input.json>
agent-ui-render normalize <input.json> [output.json]
agent-ui-render plan <input.json> [output.json]
agent-ui-render render html <input.json> <output.html>
agent-ui-render render static-html <input.json> <output.html>
agent-ui-render render vue <input.json> <output.vue>
agent-ui-render skill check [<skill-dir>] [--discover]
agent-ui-render schema print \
<compact|compact-v2|compact-v3|normalized|normalized-v2|normalized-v3|spec|spec-v2|spec-v3|config|skill-compatibility>
agent-ui-render completion <shell>Global flags:
-o, --output <human|json>
--warnings-as-errors
--quiet
--pretty
--config <path>Use an explicit config file to override runtime guardrails and trusted host color tokens:
agent-ui-render --config agent-ui-render.config.json render html input.json report.html{
"documentLanguage": "en",
"limits": {
"maxInputBytes": 5242880,
"maxRowsPerDataset": 2000,
"maxCellsPerDataset": 100000,
"maxTotalRows": 20000,
"maxTotalCells": 250000,
"maxFindings": 200,
"warnOutputHtmlBytes": 5242880,
"maxOutputHtmlBytes": 10485760
},
"themeTokens": {
"page": "#0b1220",
"bg": "#111827",
"surface": "#1f2937",
"text": "#f9fafb",
"primary": "#8b5cf6",
"series1": "#8b5cf6",
"series2": "#06b6d4"
}
}Limits and theme tokens are host/runtime policy and are never read from the
untrusted payload. Theme tokens map to --agent-* CSS custom properties and are
validated as safe CSS color literals before render output is written.
make setup # recreate renderer dependencies from the frozen lockfile
make generate # build full/lite renderer JS plus shared CSS
make generated-check # reject generated asset drift from the index
make version-check # verify release-coupled versions agree
make test # run renderer and Rust tests
make coverage # enforce Rust and Vue coverage thresholds
make security-check # scan secrets, dependency policy, and advisories
make msrv # check all Rust targets with Rust 1.91
make workflow-check # validate workflow syntax and Action pins
make workflow-security-check # audit workflows with zizmor
make performance-check # enforce renderer raw/gzip budgets
make dist-smoke-check # self-test archive/installer verification
make dev # run the CLI help from source
make check # run release-quality checksBuild/runtime architecture:
+--------------------------+ bun + Vite +---------------------------+
| renderer-vue/src | ------------------> | generated/ |
| Vue + CSS + TS sources | | renderer-lite.js (v1 or |
| | | legacy-only v3) |
+--------------------------+ | renderer.js (v2/v3 Vega) |
| renderer.css |
+-------------+-------------+
|
| include_str!
v
+-------------------------+
| agent-ui-render binary |
| selects smallest bundle |
+-------------------------+
CONTRIBUTING.md- contributor setup, architecture boundaries, and PR gates.CHANGELOG.md- release history and current Unreleased changes.docs/usage.md- consumer workflow for creating, validating, and rendering compact payloads.docs/agent-reference.md- task routing for coding agents using or modifying this repository.docs/development.md- maintainer setup, change maps, and verification.docs/troubleshooting.md- common failures and recovery steps.docs/architecture.md- runtime, build-time, and source-of-truth model.docs/cli-reference.md- command reference and exit codes.docs/compatibility.md- versioning and contract-change policy.docs/charts-v2.md- governed advanced chart coverage and v2 behavior.docs/tabbed-reports-v3.md- native panels, navigation, runtime themes, static output, compatibility, and hidden-data guidance.docs/components.md- component catalog and presentation style reference.SECURITY.md- private vulnerability reporting and release verification.CODE_OF_CONDUCT.md- contributor community standards and enforcement.docs/security-model.md- trust boundaries and unsafe-content rules.docs/renderer-development.md- Vue renderer development and handoff bundle.docs/release.md- release process and cargo-dist publishing flow.skills/agent-ui-render/references/ui-input.md- compact payload contract.skills/agent-ui-render/references/dataset.md- dataset tuple rules.schemas/v1/*.schema.json,schemas/v2/*.schema.json,schemas/v3/*.schema.json, andschemas/config.schema.json- JSON Schema mirrors for integration checks.



