Skip to content

Name the component sources, and export in the formats agents install - #3

Merged
houko merged 1 commit into
mainfrom
feat/component-sources
Sep 20, 2026
Merged

houko merged 1 commit into
mainfrom
feat/component-sources

Conversation

@houko

@houko houko commented Sep 20, 2026

Copy link
Copy Markdown
Member

The workflow this serves is the lazy one: point a coding agent at a good component library, let it pick, adapt and paste. That only works if the agent knows where to look and what it is looking at. This makes both halves real — a typed table of where the good stuff is, and two export formats an agent can act on without being told how.

The finding worth leading with

None of the five libraries ships a marketing page section. No hero, no testimonials, no team grid, no footer anywhere in the set.

Source What it actually is Machine-readable Licence
shadcn/ui 63 accessible primitives over Radix, plus the registry spec the others target llms.txt, /r/index.json MIT
beUI 85 animated components as a shadcn-compatible registry llms.txt, /r, MCP MIT (Pro tier separate)
Rare UI ~20 single-file animated widgets llms.txt, /r/registry.json MIT
Transitions ~44 CSS motion snippets, not components /cli/free-manifest.json Custom, not OSI
Beautiful UI 21 primitives for AI application interfaces none — browser only MIT

They are primitives, motion and app-shaped widgets. A source improves a block loom already renders; it never replaces one. That framing is in role, in the file header, in the generated AGENTS.md and in the README, because an agent told otherwise goes looking for a hero in shadcn/ui, finds /blocks/login, and either gives up or invents something.

lib/sources.ts

Each source carries its role, licence, install command, verified endpoints, the loom slots it can improve, and the caveat that bites whoever pastes it in without reading. Every field was fetched and checked rather than recalled.

npm run sources re-checks that, because the table rots:

shadcn/ui — primitives
  ✓ 200 https://ui.shadcn.com/llms.txt                 59 components
  ✓ 200 https://ui.shadcn.com/r/index.json             63 components
beUI — motion
  ✓ 200 https://beui.dev/llms.txt                      85 components
  ✓ 200 https://beui.dev/r                             85 components
  ✓ 200 https://mcp.beui.dev/mcp                       4 tools
Rare UI — widgets
  ✓ 200 https://www.rareui.com/llms.txt                20 components
  ✓ 200 https://www.rareui.com/r/registry.json         22 components
Transitions — motion
  ✓ 200 https://transitions.dev/cli/free-manifest.json 32 components
Beautiful UI — primitives
  ·   browser only, no machine-readable surface to check

8/8 endpoints answered; 4 of 5 sources enumerable without a browser, 1 browser only.

The counts are the useful number, not a green tick, and they already disagree with themselves: shadcn/ui documents 59 components in llms.txt but ships 63 in /r/index.json; Rare UI's registry has two registry:lib items its llms.txt omits; Transitions' free manifest holds 32 of roughly 44 snippets. mcp.beui.dev is probed with an initialize + tools/list handshake rather than a GET, because a healthy MCP server answers a plain GET with 406.

It stays a script rather than a test because it needs the network.

Two new exports

site.registry.json — a shadcn registry item. Three of the five sources already speak this format, so it is the one interchange format they agree on:

$ npx shadcn@latest add ./site.registry.json
✔ Checking registry.
✔ Created 1 file:
  - src/components/site.tsx
✔ Updating src/app/globals.css

Run against the real CLI in a scratch project. All 17 tokens land in :root and the Tailwind v4 @theme inline bridge builds cleanly, including the radius scale:

:root {
  --accent: #9a5b2d;
  --radius: 16px;
  ...
}
@theme inline {
  --color-accent: var(--accent);
  --radius-lg: var(--radius);
  --radius-xl: calc(var(--radius) * 1.4);
  ...
}

cssVars keys carry no leading --, and that is load-bearing rather than cosmetic. The CLI's declaration writer normalises either spelling, so a naive "does it install" check passes both ways — but the plugin that runs immediately after strips the property and not the value, so --accent emits --color-accent: var(----accent). Four dashes, resolves to nothing, zero diagnostics. The radius expansion matches the literal key radius and silently skips --radius. A test pins the convention by reproducing the CLI's own value expression rather than matching strings.

AGENTS.md — the brief that makes the rest actionable: which file is authoritative (spec.json; hand edits to the generated Site.tsx die at the next export), the seventeen tokens printed with their values, the blocks on this page, and the sources filtered to those blocks with the caveat attached. A source with no install command renders as "Browser only — nothing to run" rather than a command that would fail when pasted.

It is deliberately short. The convention specifies nothing beyond the filename, which is an open invitation to emit Setup Commands / Testing / PR Guidelines headings that say nothing true about three files in a folder and cost the receiving agent context.

Blocks list in SLOT_ORDER, not the order the caller planned them. The first version printed the planning order under the words "in that order" — a small lie an agent pays for with a scroll. Two tests cover it, both mutation-verified.

Verification

npx tsc --noEmit     exit 0
npx vitest run       13 files, 199 tests, all passing
npm run build        compiled successfully
npm run sources      8/8 endpoints answered

End to end through the real editor with Playwright in demo mode: five export buttons render, both new ones download under the right filename, and the emitted registry item installs with the real shadcn CLI.

40 new tests. lib/sources.test.ts cross-checks every blocks entry against SLOT_ORDER, so a renamed slot fails here instead of producing a dead row in an exported brief; it also asserts sourcesFor("team") is empty — team is the one slot none of the five covers — with a failure message telling the next person to update the docs.

Not in scope

npm run dev under Next 16 writes an untracked AGENTS.md and CLAUDE.md at the repo root. They are removed here rather than committed, but nothing gitignores them, so they will come back for anyone who runs the dev server. Worth a separate line in .gitignore.

…stall

The workflow this serves is the lazy one: point a coding agent at a good component library, let it pick, adapt and paste. That only works if the agent knows where to look and what it is looking at, so `lib/sources.ts` makes the five libraries data rather than a bookmark folder — role, licence, install command, verified machine-readable endpoints, the loom slots each can improve, and the caveat that bites.

Every field was fetched and checked rather than recalled, and the check is repeatable: `npm run sources` re-probes each endpoint and reports how many components it still lists. Today all eight answer. shadcn/ui's llms.txt documents 59 components while /r/index.json ships 63, Rare UI's registry carries two `registry:lib` items its llms.txt omits, and Transitions' free manifest holds 32 of the roughly 44 snippets — the counts are the useful number, not a green tick.

The uncomfortable finding belongs in the data, so it is in the header comment and in `role`: none of the five ships a marketing page section. No hero, no testimonials, no team grid, no footer anywhere in the set. They are primitives, motion and app-shaped widgets, so a source improves a block loom already renders and never replaces one. An agent told otherwise goes looking for a hero in shadcn/ui, finds /blocks/login, and either gives up or invents something.

Two new exports carry that outward, taking the total from three to five.

`site.registry.json` is a shadcn registry item. `npx shadcn@latest add ./site.registry.json` writes the component, merges the theme tokens into the project stylesheet and installs dependencies in one command, from a local path with no hosting — the CLI documents its argument as "name, url or local path". Three of the five sources already speak this format, so it is the one interchange format they agree on. Verified against the real CLI: 17 tokens land in `:root` and the Tailwind v4 `@theme inline` bridge builds cleanly.

`cssVars` keys carry no leading `--`, and that detail is load-bearing rather than cosmetic. The CLI's declaration writer normalises either spelling, so a naive "does it install" check passes both ways — but the plugin that runs immediately after strips the property and not the value, so `--accent` emits `--color-accent: var(----accent)`, and the radius scale expansion matches the literal key `radius` and silently skips `--radius`. Four dashes, no diagnostics, no theme. A test pins the convention by reproducing the CLI's own value expression rather than matching strings.

`AGENTS.md` is the brief: which file is authoritative, the seventeen tokens printed with their values, the blocks on this page in render order, and the sources filtered to those blocks. It is deliberately short. The convention specifies nothing beyond the filename, which is an open invitation to emit Setup Commands / Testing / PR Guidelines headings that say nothing true about three files in a folder and cost the receiving agent context.

Blocks are listed in SLOT_ORDER rather than the order the caller planned them. The first version printed the planning order under the words "in that order", which is a small lie an agent pays for with a scroll.
@houko
houko force-pushed the feat/component-sources branch from 1274877 to 82fe511 Compare September 20, 2026 11:15
@houko
houko merged commit 5f34183 into main Sep 20, 2026
1 check passed
@houko
houko deleted the feat/component-sources branch September 20, 2026 11:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant