ui8kit

CLI to install and maintain UI8Kit primitives registries (per-runtime: React, Vue, Svelte, Solid, Web Components, Templ, Twig, Latte, Jinja2; file-based)
2,334
Install
npm install ui8kit
Latest Version:3.2.1
License:MIT
Last Updated:Oct 23, 2026
Links: GitHub  ·  npm
Maintainer: alexy-os

ui8kit CLI

UI8Kit 3 ecosystem

Pipeline: codegen (spec → generated/) → registry (pack r/<rt>/) → CDN (unpkg / jsDelivr) → cli (init / add) → app

Shadcn-style registry CLI: init / add / list / diff / info / scan / build. It fetches registry items from a CDN and writes source files into your app (not into node_modules), so Tailwind sees the classes.

npm package ui8kit@3.x · registry digest @ui8kit/registry@3 (per-runtime r/<runtime>/) · runtimes react, vue, svelte, solid, webcomponent · config contract 2.0.0

Docs: docs/README.md · Upgrading from 2.x: docs/migration-v3.md · Agents/maintainers: AGENTS.md

Idea

@ui8kit/registry@3/r/<runtime>/   →  npx ui8kit@3 init  →  {dir}/utils/…  +  .cursor/rules/ui8kit-primitives.mdc
                                  →  npx ui8kit@3 add   →  {dir}/ui/<brick>/…

Primitives are generated by ui8kit codegen and published per runtime; this CLI installs them.

Requirements

  • Node.js >=20 (or Bun)
  • A project with package.json (created by init if missing). Vite/React are not required.

Quick start

npx ui8kit@3 init --yes --framework react --dir src
npx ui8kit@3 add button text box

Primitives in @ui8kit/registry 3.2 (19): box, text, button, link, label, form, input, textarea, select, checkbox, radio, switch, image, icon, dialog, disclosure, meter, progress, separator (+ React-only slot). The CLI has no hard-coded list: add <name> / add --all read the registry index, so new primitives arrive with the registry.

  • init writes ui8kit.config.json, installs registry:utils into {dir}/utils (plus npm peers clsx, tailwind-merge) and the registry:rules item into .cursor/rules/ui8kit-primitives.mdc ({kit} → your primitives folder, {globs} → files under dir). Only folders of files actually written are created.
  • add installs bricks into {dir}/ui/<brick>/ and resolves registryDependencies (slot, utils, …).

Other runtimes: --framework vue|svelte|solid|webcomponent (Web Components install *.wc.ts + shared files).

Layout under {dir}

Path Role Registry type
ui/<brick>/ primitives (codegen) registry:ui
utils/ cn, variants, … — required by primitives (../../utils) registry:utils
.cursor/rules/ (app root) agent rules for the primitives registry:rules (installed by init only)
components/, blocks/, layouts/, lib/, variants/, widgets/ other item types (brand registries) registry:component / block / …

Remap safely at the same depth (e.g. "paths": { "ui": "kit" }); keep utils at {dir}/utils. Precedence: --path key=dir > config.paths > file target — see Configuration.

Registry version

  • Default = CLI major: ui8kit 3.x fetches @ui8kit/registry@3 → …/r/<runtime>/ (newest 3.x.y; not pinned).
  • Pin: --registry-version 3.0.0 or "registryVersion": "3.0.0" (ranges like 3.1 and dist-tags like canary work too).
  • Server runtimes (templ, latte, twig, jinja2) are first-class in 3.2 (r/<runtime>/ of @ui8kit/registry@3); see Server runtimes.

CDN order: --registry-url / registryUrl → cdnBaseUrls → built-in unpkg / jsDelivr. --strict-cdn + explicit URL → only that URL. URL registryDependencies resolve bare names against the item's own registry base. Details: docs/cdn-and-cache.md.

Server runtimes (templ, latte, twig, jinja2)

npx ui8kit@3 init --yes --framework templ --dir internal     # or latte / twig / jinja2 (e.g. --dir templates)
npx ui8kit@3 add button
  • init writes only ui8kit.config.json (typescript: false), ui8kit.lock.json, .cursor/rules/ and {dir}/utils (templ), {dir}/runtime (twig/latte) or {dir}/ui8kit_jinja (jinja2). No package.json, no tsconfig; add does not require a package.json either.
  • Toolchain deps are never installed automatically and never go to npm. After init / add the CLI prints the exact commands once (deduped) from the item meta: go get github.com/a-h/templ@v…, composer require "twig/twig:^3.0", pip install "Jinja2>=3.1,<4" (double quotes: works in bash, PowerShell and cmd).
  • templ: generated code imports github.com/ui8kit/codegen/generated/templ/utils. With a go.mod in the app root the CLI rewrites it (in *.templ and *.go) to <module>/<utils dir>, e.g. example.com/app/internal/utils. Without go.mod the import is left as is and a warning prints the fix: go mod init <module> + ui8kit add <items> --force, or replace the import by hand. Then templ generate && go build ./....
  • twig / latte: the CLI prints a PSR-4 snippet ("UI8Kit\\Twig\\": "<dir>/runtime/" / UI8Kit\\Latte\\) for your composer.json; it never edits composer.json. Run composer dump-autoload. Twig: $twig->addExtension(new \UI8Kit\Twig\TwigExtension()).
  • jinja2: ui8kit_jinja/ sits next to ui/; from ui8kit_jinja import environment → environment().get_template("ui/button/button.html.j2").render(p={...}, children=...).
  • *_templ.go is generated: registry ≥ 3.1 (rebuilt) ships only *.templ; run templ generate after every add (and in CI). check covers only files the CLI wrote, so generated *_templ.go never shows up as drift. Old installs that still have a locked *_templ.go will show it as modified after templ generate — remove those *_templ.go keys from ui8kit.lock.json, or delete the lock and run ui8kit check --adopt (re-creates it from files matching the registry).

Config (ui8kit.config.json)

{
  "$schema": "https://cdn.jsdelivr.net/npm/@ui8kit/registry@3/schema/schema.json",
  "contractVersion": "2.0.0",
  "framework": "react",
  "runtime": "react",
  "typescript": true,
  "dir": "src",
  "globalCss": "src/index.css",
  "aliases": { "@": "./src" },
  "registry": "@ui8kit",
  "importStyle": "alias"
}

--import-style package (@ui8kit/core imports) is deprecated: it still works but prints a warning.

For app developers: lock, check, versions

ui8kit.lock.json

init and add record every installed file in ui8kit.lock.json: the registry it came from (source, the URL actually used), the exact version (3.0.0, never a range) and a sha256 per file. Commit it — it is how you (and CI) know the kit on disk is exactly what the registry shipped. Do not edit it by hand.

npx ui8kit@3 check            # offline, no network; exit 1 on errors
npx ui8kit@3 check --json     # machine-readable report

Add npx ui8kit@3 check to CI (see CI scenario). Existing app installed before 3.1 (no lock): run npx ui8kit@3 check --adopt once — it fetches the registry, hashes what each item would install and adopts only files that match; others are listed as not-adopted (decide: re-install with add <name> --force, or keep as your own file). Commit the lock.

check error Meaning Fix
missing a locked file was deleted npx ui8kit@3 add <name> --force
modified file content differs from what was installed — a local edit, or aliases / importStyle / paths changed after install (import rewrites change content) revert the edit (add <name> --force) and move styling to className / tokens; after a deliberate config change re-install the items with --force
mixed-versions primitives from one registry are on different versions (e.g. button 3.0.0, text 3.1.0) npx ui8kit@3 add <outdated…> --force (or add --all --force) so all share one version
rules-version .cursor/rules/ui8kit-primitives.mdc is from another version than the primitives re-run npx ui8kit@3 init with your flags (refreshes utils + rules), or bring the primitives to the rules version

Line endings: hashes are computed with CRLF normalized to LF, so git config core.autocrlf true on Windows is not reported as modified.

Registry version

The default registry is the CLI major (ui8kit@3 → @ui8kit/registry@3, newest 3.x.y). To make installs reproducible, pin an exact digest: "registryVersion": "3.0.0" in ui8kit.config.json (or --registry-version 3.0.0). Upgrade deliberately: change the pin, add --all --force, init (rules), check, commit.

Brand registries

A brand registry (e.g. https://registry.buildy.tw/react) ships blocks / composites that depend on the primitives by URL (registryDependencies: ["https://cdn.jsdelivr.net/npm/@ui8kit/registry@3.0.0/r/react/components/ui/button.json"]) and records the digest it was built against in registry.json top-level meta (copied to index.json):

{ "meta": { "primitives": { "registry": "@ui8kit/registry", "version": "3.0.0" } } }

Brand items get their own lock entries (key per registry identity), separate from @ui8kit/registry.

Primitives are not forked. Do not edit files under your kit folder ({dir}/ui, {dir}/utils) — check reports it, and add --force would overwrite it. Brand styling goes through className on the primitives and design tokens (CSS variables / Tailwind theme); new UI goes into your own components or a brand registry.

Commands

Command Purpose
init config + utils + agent rules
add <names…> / add --all install items (--runtime, --dry-run, --force, --path key=dir)
check [--json] [--adopt] verify files against ui8kit.lock.json
list / diff browse registry / compare local files (read registry settings from config)
info [--cdn] environment and resolved CDN order
scan / build author a registry: src/registry.json → r/
cache clear / registry clean / reset maintenance

Full reference: docs/commands.md.

Development

npm install
npm run type-check
npm test
npm run build
npm run pack:check

Scripts: scripts/README.md. Changelog: CHANGELOG.md.

License

MIT © UI8Kit

Installing primitives with the ui8kit CLI

This repo is the installer. Exact flags below are taken from src/index.ts (verified with node dist/index.js <cmd> --help).

Quick start per runtime

Always call the CLI with a pinned major: npx ui8kit@3. add all and add --all are equivalent.

# JS runtimes (writes package.json peers clsx + tailwind-merge for utils)
npx ui8kit@3 init --yes --framework react        --dir src && npx ui8kit@3 add button
npx ui8kit@3 init --yes --framework vue          --dir src && npx ui8kit@3 add button
npx ui8kit@3 init --yes --framework svelte       --dir src && npx ui8kit@3 add button
npx ui8kit@3 init --yes --framework solid        --dir src && npx ui8kit@3 add button
npx ui8kit@3 init --yes --framework webcomponent --dir src && npx ui8kit@3 add button
npx ui8kit@3 add --all            # everything in r/<runtime>/index.json

# Server runtimes (no package.json is written or required)
npx ui8kit@3 init --yes --framework templ  --dir internal  && npx ui8kit@3 add button
npx ui8kit@3 init --yes --framework twig   --dir templates && npx ui8kit@3 add button
npx ui8kit@3 init --yes --framework latte  --dir templates && npx ui8kit@3 add button
npx ui8kit@3 init --yes --framework jinja2 --dir templates && npx ui8kit@3 add button

Post-install for server runtimes (the CLI prints the exact commands from item meta; it never runs them and never edits composer.json / go.mod):

  • templ: go get github.com/a-h/templ@<printed version> → templ generate (after every add, and in CI; *_templ.go is generated, not shipped) → go build ./.... With go.mod present the utils import is rewritten to <module>/<dir>/utils.
  • twig / latte: composer require "twig/twig:^3.0" (or the printed latte package), add the printed PSR-4 entry to composer.json, then composer dump-autoload:
    { "autoload": { "psr-4": { "UI8Kit\\Twig\\": "templates/runtime/" } } }
    
    (UI8Kit\\Latte\\ for latte). Twig: $twig->addExtension(new \UI8Kit\Twig\TwigExtension()).
  • jinja2: pip install "Jinja2>=3.1,<4"; from ui8kit_jinja import environment → environment().get_template("ui/button/button.html.j2").render(p={...}, children=...).

Commands and flags (ui8kit 3.2)

Global: -c, --cwd <dir>, -v, --verbose, --no-cache, -V, --version.

Command Flags
init -y, --yes, --framework <react|vue|svelte|solid|webcomponent|templ|latte|twig|jinja2|none>, --runtime <name> (defaults to framework), --dir <path>, --skip-core, -r, --registry <type> (default ui), --registry-url <url>, --registry-version <v>, --strict-cdn, --import-style <alias|package> (package deprecated)
add [components...] -a, --all (or add all), -f, --force, --runtime <name>, --path <key=dir> (repeatable, e.g. ui=kit), --dry-run, --retry, -r, --registry <type>, --registry-url, --registry-version, --strict-cdn
check offline verify vs ui8kit.lock.json; --json, --adopt (fetches registry, adopts only matching files), --runtime, --registry-url, --registry-version, --strict-cdn (the last three only with --adopt)
list --json, -r, --registry, --registry-url, --registry-version, --strict-cdn
diff [component] --json, -r, --registry, --registry-url, --registry-version, --strict-cdn
info --json, --cdn (resolved CDN order and overrides)
scan -r, --registry <type|path>, -o, --output <file>, -s, --source <dir>
build [registry] default ./src/registry.json; -o, --output <path> (default ./packages/registry/r)
cache clear —
registry clean --dry-run, --all, -f, --force
reset --dry-run, --with-cache, -y, --yes, -f, --force

Where registries live

  • Default: @ui8kit/registry@<CLI major> from npm via CDN, tried in order unpkg → jsDelivr:
    • https://unpkg.com/@ui8kit/registry@3/r/<runtime>/index.json
    • https://cdn.jsdelivr.net/npm/@ui8kit/registry@3/r/<runtime>/index.json
  • Per runtime (react, vue, svelte, solid, webcomponent, templ, twig, latte, jinja2) under r/<runtime>/:
    • index.json — catalogue
    • components/ui/<name>.json — primitives (e.g. button.json)
    • utils/utils.json — registry:utils (installed by init)
    • rules/rules.json — registry:rules → .cursor/rules/ui8kit-primitives.mdc (installed by init)
  • $schema: https://cdn.jsdelivr.net/npm/@ui8kit/registry@3/schema/{schema,registry,registry-item}.json (config / index / item).
  • Version: --registry-version or "registryVersion" in ui8kit.config.json accepts exact (3.1.0), range (3.1) or dist-tag (canary); default is the CLI major (3 → newest 3.x.y).

Version with a custom --registry-url

--registry-version / registryVersion rewrites an npm-style name@<version> segment of a custom URL (…/@ui8kit/registry@latest/r/react, …/my-kit@2/r, …@3.1.0/…). A URL without such a segment (brand domain, self-hosted path like https://kit.example.com/v3/r/react) is used unchanged and the CLI warns that --registry-version is ignored: version those registries through their own path.

slot is React-only

slot (Slot / asChild) exists only in r/react; React bricks pull it in via registryDependencies. Other runtimes compose with their native mechanism (slots/children), so add slot --runtime vue (or any non-React runtime) prints a clear "React-only" error and skips it.

  • Resolution order: --registry-url / registryUrl → cdnBaseUrls (config) → built-in unpkg / jsDelivr. With --strict-cdn (or strictCdn) and an explicit URL, only that URL is used.
  • Brand registries: @ui8kit/registry ships primitives only. Brand kits (blocks, composites) host their own registry, e.g. --registry-url https://registry.buildy.tw/react, and reference primitives by absolute URL in registryDependencies (pinned digest, recorded in meta.primitives). Brand items get their own lock entries.
  • Lock: init / add write ui8kit.lock.json (source URL, exact version, sha256 per file). Commit it; verify with npx ui8kit@3 check (offline, exit 1 on missing / modified / mixed-versions / rules-version). No lock yet → npx ui8kit@3 check --adopt once.

Where source lives

codegen  specs/ + bricks/ ─gen─▶ generated/<rt>/   (build output, NOT committed)
registry pack:runtimes  ──────────▶ r/<rt>/*.json     (published: @ui8kit/registry)
npm ──▶ unpkg / jsDelivr ──▶ cli: ui8kit init / add ──▶ app {dir}/ui, {dir}/utils + ui8kit.lock.json

Fix a primitive in codegen, repack in registry, publish, then add <name> --force in the app. Never fix it in the app or in r/ by hand.

Related Packages

@ravox-ui/cli

Add Ravox Kit components, blocks and themes to your project (React, Vue, Svelte...

628
@tesserai/cli

Install a tesserai design system into your project as components you own, keep i...

2,584 0
jsrepo

A CLI to add shared code from remote repositories.

503,567 629
@barocss/math-editor

Embeddable math editor with a framework-independent model, React UI, and native...

2,067
@esvigy/cli

Official CLI for Esvigy — add customizable, animated illustrations directly to y...

375 3

Version History

Version Released License
3.2.1 MIT
3.2.0 MIT
3.1.1 MIT
3.0.1 MIT
3.0.0 MIT