How PraisonAIUI vendors BeautifulUI React primitives so
upgrades are repeatable and licence obligations are explicit.
!!! info "Related planning"
Epic #292 (integration
strategy) and the adapter/pin policy in
#294.
BeautifulUI (MIT, © Shane Levine / Turbo) is a library of React primitives aimed at
AI-native interfaces — thinking traces, streaming answers with inline sources,
human-in-the-loop approval cards, tool chips, task rows, context chunks, and a reference
chat harness.
It is a shadcn registry + copy-paste library — not an npm package. There is no
published beautiful-ui package. You install components by resolving a registry URL, and
beautiful-ui
the source is copied into your tree (like any other shadcn/ui primitive).
Upstream stack (Next.js 15 · React 19 · Tailwind CSS v4 · TypeScript) is closely aligned
with PraisonAIUI's src/frontend (Vite · React 19 · Tailwind v4 · shadcn/Radix), which is
src/frontend
why copy-paste vendoring works without a framework shim.
PraisonAIUI already carries the shadcn/ui foundation that BeautifulUI primitives depend on:
src/frontend/components.json
style: new-york
baseColor: neutral, iconLibrary: lucide, cssVariables: true). Its registries
baseColor: neutral
iconLibrary: lucide
cssVariables: true
registries
map is where pinned BeautifulUI registry URLs are added (see §3).
src/praisonaiui/themes.py
(--background, --foreground, --primary, --radius, …) at build time for all 22
--background
--foreground
--primary
--radius
official presets, offline. BeautifulUI's foundation CSS (upstream app/globals.css)
app/globals.css
must only contribute new tokens/utilities; it must not redefine variables that
themes.py already owns, or theme switching and dark mode break.
themes.py
Rule: when merging upstream app/globals.css, diff it against the variables emitted by
themes.py and keep only the additive slices (new keyframes, component-scoped utilities).
Record what was merged in the pin doc (§3).
1. Install with a pinned registry URL from src/frontend/:
src/frontend/
The registry resolves dependencies and CSS slices. Commit the resulting
package-lock.json change in the same PR.
package-lock.json
2. Re-export through the adapter — add the component to
src/frontend/src/components/index.ts (@praisonaiui/react). Consumers never import
src/frontend/src/components/index.ts
@praisonaiui/react
the raw vendored path (see §4).
3. Update the pin record — create/update docs/frontend/BEAUTIFULUI_UPSTREAM.md with:
docs/frontend/BEAUTIFULUI_UPSTREAM.md
the upstream git SHA, the date, the registry base URL, and the **component
list** vendored so far. This file is the single source of truth for "what version are
we on". (It is created the first time a real primitive is vendored — do not add it
empty.)
4. Rebuild & sync the bundle — the committed frontend bundle must be regenerated:
(See AGENTS.md → "Frontend Build".)
AGENTS.md
5. Run frontend CI — .github/workflows/ci.yml (ruff + pytest) must pass, plus the
.github/workflows/ci.yml
frontend build step.
Consumers import from @praisonaiui/react only — never from raw vendored paths such as
@/components/ui/... or any upstream module.
@/components/ui/...
This keeps the upstream surface behind one file (components/index.ts), so a BeautifulUI
components/index.ts
bump changes vendored source but not consumer imports.
(src/praisonaiui/templates/frontend/plugins/*) remain the fallback and are kept working.
src/praisonaiui/templates/frontend/plugins/*
BEAUTIFULUI_UPSTREAM.md
rebuilt bundle move together in one commit), and disable the flag. No consumer import
changes are needed because everything routes through the adapter (§4).
BeautifulUI is MIT, © Shane Levine. The full licence text is retained in
THIRD_PARTY_NOTICES.md
at the repository root. Any PR that vendors or bumps BeautifulUI source must keep that
notice present and current.
Do not use @central-icons-react without a licence — it is commercial. PraisonAIUI
@central-icons-react
standardises on lucide-react (iconLibrary: lucide in components.json). If an
lucide-react
components.json
upstream BeautifulUI primitive imports commercial icons, swap them for lucide equivalents
during vendoring.