# shadcn-ui/ui — codebase unpack

> Canonical page: https://codevetter.com/unpack/ui

This is a deterministic Repo Unpack scan of shadcn-ui/ui — a structural map, not a review, security audit, or maintainer-endorsed description.

- Scanned commit: 98a1fe67b439324ddc857f47fbdce056600a4329 (2026-09-21)
- Last upstream commit: docs(registry): update the @7ovr description (#11972)
- Generated by codevetter 1.12.0 on 2026-09-22
- 3999 files scanned · 14.7 MB

## Languages

- TypeScript: 3869 files
- JSON: 1009 files
- Markdown: 378 files
- JavaScript: 70 files
- CSS: 69 files
- YAML: 52 files
- HTML: 5 files
- TOML: 3 files

## Repository structure

- apps/ — 2976 files
- packages/ — 704 files
- templates/ — 248 files
- skills/ — 23 files
- .github/ — 20 files
- .claude/ — 2 files
- .changeset/ — 2 files
- scripts/ — 1 files

Probable source entrypoint: `packages/` (inferred from the tree, not upstream docs)

## Package

- package.json: ui v0.0.1 — 36 declared dependencies

## Structural health signals

Average score 6.3/10 across 96 files; 60 hotspots. These are deterministic review leads, not proof of a bug.

## Recent history

- 98a1fe67b439 (2026-09-21) docs(registry): update the @7ovr description (#11972)
- 1add195262d8 (2026-09-21) feat(registry): add ten community registries (#11976)
- cd80d215ef35 (2026-09-21) chore(ci): close PRs with unverified commits after 14 days (#11977)
- a87a63b2ca25 (2026-09-17) feat(registry): add nine community registries (#11925)
- ec6490f1740b (2026-09-17) feat(registry): add nine community registries (#11924)

## Overview

shadcn/ui is a pnpm+turbo monorepo centered on the `shadcn` CLI (packages/shadcn, v4.21.0), which scaffolds projects and copies registry-hosted component source files directly into a user's codebase, transforming imports/CSS vars/RSC markers per project config. apps/v4 is ui.shadcn.com — a Next.js 16 + fumadocs site that authors the component registry (registry/bases, registry/styles) and publishes it as static JSON under public/r, which the CLI fetches by default from https://ui.shadcn.com/r. Supporting published packages are @shadcn/react (unstyled primitives) and @shadcn/helpers (AI/chat utilities); the CLI also embeds a stdio MCP server and ships agent skills under skills/.

## System map

The repo is a pnpm 10 + turbo monorepo. The shippable core is packages/shadcn (the `shadcn` CLI, commander-based, bundled to dist/ by tsup). apps/v4 is the Next.js site that both documents components and produces the installable registry JSON consumed by the CLI. packages/react and packages/helpers are small published support libraries. templates/* are standalone starter apps (outside the pnpm workspace) used by `shadcn init`. skills/ holds agent-facing SKILL.md bundles. CI is GitHub Actions; releases go through changesets plus npm publish scripts.
- Monorepo orchestration: root package.json scripts delegate to turbo (build/lint/typecheck/format) and pnpm filters; pnpm-workspace.yaml scopes workspaces to apps/* and packages/* — templates/* are deliberately NOT workspace packages and are synced via scripts/sync-templates.sh. — [package.json](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/package.json) [pnpm-workspace.yaml](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/pnpm-workspace.yaml) [turbo.json](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/turbo.json) [scripts/sync-templates.sh](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/scripts/sync-templates.sh)
- CLI entrypoint: packages/shadcn/src/index.ts creates a commander program named 'shadcn' and registers 13 subcommands (init/create, apply, add, diff, docs, view, search, migrate, eject, info, build, mcp, preset, registry) then calls program.parse(). — [packages/shadcn/src/index.ts#L23-52](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/index.ts#L23-L52)
- The CLI ships as the `shadcn` npm package with bin=dist/index.js, built by tsup (ESM, minified, dts) with subpath exports ./registry, ./schema, ./mcp, ./utils, ./icons, ./preset, and ./tailwind.css (copied post-build via tsup onSuccess). — [packages/shadcn/package.json](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/package.json) [packages/shadcn/tsup.config.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/tsup.config.ts)
- apps/v4 is the ui.shadcn.com site: Next.js 16.3.3 with fumadocs docs, an app router tree under app/(app) (docs, blocks, charts, examples, create flow) plus dynamic route handlers (app/r/registries.json/route.ts, app/(app)/llm/[[...slug]]/route.ts, app/api/search/route.ts). — [apps/v4/package.json](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/apps/v4/package.json) [apps/v4/app/r/registries.json/route.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/apps/v4/app/r/registries.json/route.ts) [apps/v4/app/api/search/route.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/apps/v4/app/api/search/route.ts) [apps/v4/source.config.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/apps/v4/source.config.ts)
- The site doubles as the default registry server: `pnpm registry:build` builds @shadcn/react, @shadcn/helpers, and shadcn, then runs scripts/build-registry.mts, which exports installable item JSON into apps/v4/public/r (871 generated files are committed to git). — [apps/v4/package.json](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/apps/v4/package.json) [apps/v4/scripts/build-registry.mts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/apps/v4/scripts/build-registry.mts)
- The CLI's default registry endpoint is https://ui.shadcn.com/r (REGISTRY_URL env override) and the built-in '@shadcn' namespace maps to `${REGISTRY_URL}/styles/{style}/{name}.json`. — [packages/shadcn/src/registry/constants.ts#L5-46](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/registry/constants.ts#L5-L46)
- @shadcn/react publishes unstyled React primitives (message-scroller, questionnaire, use-render) with both node and browser vitest configs; @shadcn/helpers publishes AI chat/stream helpers split into core, ai-sdk, and tanstack-ai modules. — [packages/react/package.json](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/react/package.json) [packages/react/vitest.browser.config.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/react/vitest.browser.config.ts) [packages/helpers/package.json](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/helpers/package.json)
- Project scaffolding uses a template registry (packages/shadcn/src/templates/index.ts) mapping keys next/vite/start/react-router/astro/laravel to createTemplate configs whose templateDir resolves under SHADCN_TEMPLATE_DIR (dev) pointing at templates/*-app / *-monorepo dirs. — [packages/shadcn/src/templates/index.ts#L11-18](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/templates/index.ts#L11-L18) [packages/shadcn/src/templates/create-template.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/templates/create-template.ts) [packages/shadcn/package.json](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/package.json)
- An MCP server is embedded in the CLI: `shadcn mcp` loads env files then connects a @modelcontextprotocol/sdk Server over StdioServerTransport; `shadcn mcp init` writes client config for claude, cursor, vscode, codex, and opencode. — [packages/shadcn/src/commands/mcp.ts#L90-107](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/commands/mcp.ts#L90-L107) [packages/shadcn/src/mcp/index.ts#L27-53](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/mcp/index.ts#L27-L53)
- Test orchestration is a vitest workspace joining the root config (unit tests, fixtures/templates excluded) with packages/tests (e2e). The root `pnpm test` first builds the v4 registry and starts the site on :4000 via start-server-and-test. — [vitest.workspace.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/vitest.workspace.ts) [vitest.config.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/vitest.config.ts) [package.json](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/package.json)
- Releases are driven by changesets (.changeset/config.json ignores v4 and tests) and .github/workflows/release.yml, which publishes the shadcn package to npm on main pushes and on PRs labeled 'release: beta'/'release: rc' (pub:beta/pub:rc/pub:next/pub:release scripts). — [.changeset/config.json](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/.changeset/config.json) [.github/workflows/release.yml](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/.github/workflows/release.yml) [packages/shadcn/package.json](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/package.json)
- skills/ ships agent-facing skill bundles: skills/shadcn (SKILL.md + cli.md/mcp.md/registry.md + rules/ + evals/) and skills/migrate-radix-to-base (mapping docs) — consumed by AI coding tools, not by the CLI at runtime. — [skills/shadcn/SKILL.md](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/skills/shadcn/SKILL.md) [skills/migrate-radix-to-base/SKILL.md](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/skills/migrate-radix-to-base/SKILL.md)
- Node engine requirement is >=20.18.1 and packageManager is pinned to pnpm@10.33.4; pnpm-workspace.yaml sets minimumReleaseAge=2880 (48h) with explicit excludes for fresh deps — a supply-chain guard. — [packages/shadcn/package.json](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/package.json) [package.json](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/package.json) [pnpm-workspace.yaml](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/pnpm-workspace.yaml)

## Feature catalog

User-facing surface is dominated by the CLI's subcommands plus the website's create/registry endpoints. The CLI covers project init/scaffolding, component add/search/view/docs, migrations, registry authoring (build/validate/add), presets, dry-run/diff, an MCP server for AI clients, and eject. The site adds docs pages, a /init endpoint returning registry:base items for the create flow, an LLM docs feed, registry directory, and fuzzy search API.
- `shadcn init` (alias `create`): scaffolds new projects from templates or initializes existing ones; flags include --template, --base (base/radix/aria), --monorepo, --preset, --defaults, --rtl/--no-rtl, --pointer, --reinstall, --css-variables; resolves presets to /init URLs and merges a registry:base item into config. — [packages/shadcn/src/commands/init.ts#L125-163](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/commands/init.ts#L125-L163)
- `shadcn add`: installs registry items addressed by name, URL, local file, github: address, or @namespace/item; supports --all, --overwrite, --path, --dry-run, --diff [path], --view [path]; falls back to an interactive multiselect over the registry index filtered to registry:ui entries. — [packages/shadcn/src/commands/add.ts#L50-66](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/commands/add.ts#L50-L66) [packages/shadcn/src/commands/add.ts#L330-385](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/commands/add.ts#L330-L385)
- `shadcn build`: compiles a registry.json (default ./registry.json) into per-item JSON files under an output dir (default ./public/r), supporting include-resolution via readRegistryWithIncludes and writing a catalog registry.json alongside items. — [packages/shadcn/src/commands/build.ts#L21-102](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/commands/build.ts#L21-L102) [packages/shadcn/src/registry/loader.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/registry/loader.ts)
- `shadcn search` performs fuzzy search across configured registries using fuzzysort over item names/descriptions with type filtering and pagination (SEARCH_CONCURRENCY=8). — [packages/shadcn/src/commands/search.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/commands/search.ts) [packages/shadcn/src/registry/search.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/registry/search.ts)
- `shadcn view` prints item details and `shadcn docs` returns docs/API/usage examples for components; `shadcn info` reports project config (used by the agent skill via `info --json`). — [packages/shadcn/src/commands/view.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/commands/view.ts) [packages/shadcn/src/commands/docs.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/commands/docs.ts) [packages/shadcn/src/commands/info.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/commands/info.ts) [skills/shadcn/SKILL.md](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/skills/shadcn/SKILL.md)
- `shadcn migrate` runs codemods living in src/migrations: migrate-radix (Radix→Base UI), migrate-icons, migrate-base-color, migrate-rtl, migrate-cn. — [packages/shadcn/src/commands/migrate.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/commands/migrate.ts) [packages/shadcn/src/migrations/migrate-radix.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/migrations/migrate-radix.ts) [packages/shadcn/src/migrations/migrate-icons.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/migrations/migrate-icons.ts)
- `shadcn apply` applies a preset to an existing project; `shadcn preset` groups decode/url/open/resolve subcommands for preset codes; `shadcn eject` inlines shadcn/tailwind.css and removes the dependency; `shadcn diff` is deprecated in favor of `add --diff`. — [packages/shadcn/src/commands/apply.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/commands/apply.ts) [packages/shadcn/src/commands/preset.ts#L216-217](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/commands/preset.ts#L216-L217) [packages/shadcn/src/commands/eject.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/commands/eject.ts) [packages/shadcn/src/commands/diff.ts#L42-43](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/commands/diff.ts#L42-L43)
- `shadcn registry` group currently exposes `registry add` (add registries to components.json) and `registry validate` (validate a shadcn registry); deprecated/unused registry:mcp and registry build modules exist under commands/registry but are not registered. — [packages/shadcn/src/commands/registry/index.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/commands/registry/index.ts) [packages/shadcn/src/commands/registry/add.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/commands/registry/add.ts) [packages/shadcn/src/commands/registry/validate.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/commands/registry/validate.ts) [packages/shadcn/src/commands/registry/mcp.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/commands/registry/mcp.ts)
- The MCP server exposes 7 tools: get_project_registries, list_items_in_registries, search_items_in_registries, view_items_in_registries, get_item_examples_from_registries, get_add_command_for_items, get_audit_checklist — all reading the project's components.json via getMcpConfig. — [packages/shadcn/src/mcp/index.ts#L55-187](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/mcp/index.ts#L55-L187)
- Site create flow: GET /init returns a registry:base item JSON built from query params (theme/font/base/radius) via buildRegistryBase/parseDesignSystemConfig; /init/md returns markdown setup instructions; /init/v0 is a separate v0 variant; ?track=1 fires a Vercel analytics 'create_app' event. — [apps/v4/app/(app)/(create)/init/route.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/apps/v4/app/(app)/(create)/init/route.ts) [apps/v4/app/(app)/(create)/init/md/route.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/apps/v4/app/(app)/(create)/init/md/route.ts) [apps/v4/app/(app)/(create)/lib/parse-config.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/apps/v4/app/(app)/(create)/lib/parse-config.ts) [apps/v4/registry/config.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/apps/v4/registry/config.ts)
- Site registry surface: /r/registries.json route serves the registries index; public/r/** serves per-item JSON; /llm/[[...slug]] emits LLM-friendly MDX (base detection for base/radix/aria styles); /api/search is fumadocs createFromSource. — [apps/v4/app/r/registries.json/route.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/apps/v4/app/r/registries.json/route.ts) [apps/v4/app/(app)/llm/[[...slug]]/route.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/apps/v4/app/(app)/llm/%5B%5B...slug%5D%5D/route.ts) [apps/v4/app/api/search/route.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/apps/v4/app/api/search/route.ts)
- Registry item taxonomy: registryItemTypeSchema enumerates types (registry:ui, block, component, lib, hook, theme, style, base, font, file, item, example, internal, page, etc.) driving install behavior (e.g. registry:theme/style/base skip style-index install and trigger CSS-var overwrite prompts). — [packages/shadcn/src/registry/schema.ts#L81-100](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/registry/schema.ts#L81-L100) [packages/shadcn/src/commands/add.ts#L117-153](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/commands/add.ts#L117-L153)
- Namespaces: items can be addressed as @registry/item with per-registry URL templates in components.json registries; ensureRegistriesInConfig can discover registries from the served registries index and package.json-declared registries. — [packages/shadcn/src/registry/builder.ts#L22-56](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/registry/builder.ts#L22-L56) [packages/shadcn/src/utils/registries.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/utils/registries.ts) [packages/shadcn/src/registry/namespaces.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/registry/namespaces.ts)
- Deprecated/hidden component gating: DEPRECATED_COMPONENTS (toast, toaster) hard-exit with a warning on Tailwind v4 projects unless allowed per base; COMPONENTS_HIDDEN_FROM_SELECTION hides sonner for base projects. — [packages/shadcn/src/registry/constants.ts#L179-203](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/registry/constants.ts#L179-L203) [packages/shadcn/src/commands/add.ts#L387-430](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/commands/add.ts#L387-L430)

## Data flow

Input boundaries are CLI args, components.json (cosmiconfig), env files (.env*), and registry item JSON fetched over HTTP(S)/local disk/GitHub. Zod schemas validate all external data. Resolution turns item addresses into URLs via per-registry templates with {name}/{style} placeholders and ${ENV} expansion; resolveRegistryTree recursively merges items+dependencies into one install tree. Updaters then write package.json deps, tailwind config, env files, fonts, transformed source files, and finally CSS. The website's build-registry.mts is the upstream producer of the JSON the CLI consumes.
- Config input: a cosmiconfig explorer (searchPlaces: ['components.json']) loads raw config, rawConfigSchema validates, then resolveConfigPaths resolves tsconfig/jsconfig path aliases (components/ui/lib/hooks/utils) into resolvedPaths — tsconfig load failure throws. — [packages/shadcn/src/utils/get-config.ts#L26-116](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/utils/get-config.ts#L26-L116)
- Item address resolution order in fetchRegistryItems: github: scheme → fetchGitHubRegistryItem; local file → fetchRegistryLocal (with ~ expansion, zod parse); URL → fetchRegistry+parse; '@ns/item' → resolveRegistryItemsFromRegistries; bare name → `styles/{config.style ?? 'new-york-v4'}/{name}.json` under REGISTRY_URL. — [packages/shadcn/src/registry/resolver.ts#L81-133](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/registry/resolver.ts#L81-L133) [packages/shadcn/src/registry/fetcher.ts#L143-176](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/registry/fetcher.ts#L143-L176)
- Registry URL building substitutes {name} and {style} placeholders, expands ${ENV_VAR} via expandEnvVars (from AsyncLocalStorage registry env context), appends configured query params, and builds auth headers that are dropped if expansion leaves them empty. — [packages/shadcn/src/registry/builder.ts#L58-146](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/registry/builder.ts#L58-L146) [packages/shadcn/src/registry/env.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/registry/env.ts) [packages/shadcn/src/registry/context.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/registry/context.ts)
- HTTP fetch path: fetchRegistry → resolveRegistryUrl (v0 /chat/b/ URLs get /json suffix; relative paths prefixed with REGISTRY_URL) → fetchWithProxy (manual redirect loop, SOCKS via ALL_PROXY, EnvHttpProxyAgent for HTTP(S)_PROXY, per-origin header re-scoping) → status-mapped errors (401/403/404/410) → response.json(). — [packages/shadcn/src/registry/fetcher.ts#L26-127](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/registry/fetcher.ts#L26-L127) [packages/shadcn/src/registry/builder.ts#L155-168](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/registry/builder.ts#L155-L168) [packages/shadcn/src/registry/proxy.ts#L93-173](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/registry/proxy.ts#L93-L173)
- resolveRegistryTree recursively resolves registryDependencies (re-rewriting @namespaced deps through the registries config, erroring RegistryNotConfiguredError when unset) and merges each item's files/cssVars/css/envVars/dependencies/devDependencies/fonts into a single install tree validated by registryResolvedItemsTreeSchema. — [packages/shadcn/src/registry/resolver.ts#L148-200](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/registry/resolver.ts#L148-L200) [packages/shadcn/src/registry/schema.ts#L272](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/registry/schema.ts#L272)
- Install pipeline: addComponents → getWorkspaceConfig decides monorepo path (addWorkspaceComponents routes files to ui/hooks/lib workspace targets) vs addProjectComponents; both run resolveAndValidateRegistryTree → massageTreeForFonts → updateDependencies → updateTailwindConfig → updateEnvVars → updateFonts → updateFiles → updateCss (CSS written last so watchers rebuild after files land). — [packages/shadcn/src/utils/add-components.ts#L53-152](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/utils/add-components.ts#L53-L152) [packages/shadcn/src/utils/add-components.ts#L154-392](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/utils/add-components.ts#L154-L392)
- File writing: updateFiles resolves each file's target path (alias-aware, src-dir aware, --path override), skips identical content via isContentSame, merges .env files instead of overwriting, and runs the transformer chain: transformImport, transformRsc, transformCssVars, transformTwPrefixes, transformIcons, transformMenu, transformAsChild, transformRtl, conditional transformNext (Next 16 middleware), transformFont, transformCleanup. — [packages/shadcn/src/utils/updaters/update-files.ts#L107-220](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/utils/updaters/update-files.ts#L107-L220)
- Env input boundary: loadEnvFiles loads .env.local, .env.development.local, .env.development, .env from cwd via @dotenvx (no overload) so private-registry ${ENV} placeholders in URLs/headers/params resolve at fetch time. — [packages/shadcn/src/utils/env-loader.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/utils/env-loader.ts) [packages/shadcn/src/registry/env.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/registry/env.ts) [packages/shadcn/src/commands/add.ts#L75](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/commands/add.ts#L75)
- components.json write path (init): existing config (or backup) is deepmerged with new config; discovered registries are appended (built-ins filtered out); registry:base config merged last; design settings (menuColor/menuAccent/rtl/iconLibrary) are propagated into each workspace package's components.json; file written with 2-space JSON. — [packages/shadcn/src/commands/init.ts#L713-823](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/commands/init.ts#L713-L823)
- Registry production: authored sources live in apps/v4/registry/bases/{base,radix,aria} plus registry/styles/style-*.css; build-registry.mts builds STYLE_COMBINATIONS (base × style), invokes the shadcn CLI to export public/r/styles/<style>/*.json, emits ui-rtl variants for nova styles, and formats outputs. — [apps/v4/scripts/build-registry.mts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/apps/v4/scripts/build-registry.mts) [apps/v4/registry/styles](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/apps/v4/registry/styles) [apps/v4/registry/bases](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/apps/v4/registry/bases)
- Dependency writes: updateDependencies resolves the package manager (npm/pnpm/yarn/bun/deno/expo special-cased) and execa's an install of registry-declared dependencies/devDependencies; React 19 + npm triggers a peer-deps warning pointing at ui.shadcn.com/react-19. — [packages/shadcn/src/utils/updaters/update-dependencies.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/utils/updaters/update-dependencies.ts)
- In-process caching: fetchRegistry dedupes in-flight fetches in a module-level Map keyed by url + sha256 of sorted headers; registry headers themselves live in AsyncLocalStorage context set by setRegistryHeaders and cleared via clearRegistryContext in each command's finally. — [packages/shadcn/src/registry/fetcher.ts#L20-24](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/registry/fetcher.ts#L20-L24) [packages/shadcn/src/registry/context.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/registry/context.ts) [packages/shadcn/src/commands/add.ts#L325-327](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/commands/add.ts#L325-L327)
- Init URL contract: the site's /init endpoint emits a registry:base item whose `config` field the CLI reads via resolveRegistryBaseConfig; the CLI also strips the 'track' param before fetching and force-sets the 'base' param on the first component URL. — [apps/v4/app/(app)/(create)/init/route.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/apps/v4/app/(app)/(create)/init/route.ts) [packages/shadcn/src/commands/init.ts#L558-578](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/commands/init.ts#L558-L578) [packages/shadcn/src/preset/presets.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/preset/presets.ts)

## Behavior traces

Traced flows: CLI startup, `init` (including empty-project scaffold and registry:base merge), `add` (including missing-config fallback into runInit and dry-run), the install pipeline inside addComponents, the registry fetch pipeline, `build`, the MCP server, and the website's registry:build production path.
- Startup: node dist/index.js → imports 13 command modules → new Command().name('shadcn').version(pkg.version) → addCommand(init, apply, add, diff, docs, view, search, migrate, eject, info, build, mcp, preset, registry) → program.parse() → per-command .action handler; SIGINT/SIGTERM exit 0. — [packages/shadcn/src/index.ts#L1-52](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/index.ts#L1-L52)
- init flow: initOptionsSchema.parse → validate --template/--preset → monorepo-root guard → existing components.json overwrite prompt + optional --reinstall component enumeration → template/base/preset prompts → resolveInitUrl → loadEnvFiles → createFileBackup(components.json) → resolveRegistryBaseConfig(first URL) → runInit. — [packages/shadcn/src/commands/init.ts#L163-601](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/commands/init.ts#L163-L601) [packages/shadcn/src/utils/file-helper.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/utils/file-helper.ts)
- runInit: resolveTemplate(template,{monorepo}) → (skip preflight for monorepo template init) preFlightInit → on MISSING_DIR_OR_EMPTY_PROJECT createProject() → getProjectConfig → template.init(...) early-return for template-managed init, else promptForMinimalConfig/promptForConfig → confirm write → ensureRegistriesInConfig → write components.json → getWorkspaceConfig propagation → explorer.clearCaches() → addComponents(['index', url..., 'button']) → templatePostInit. — [packages/shadcn/src/commands/init.ts#L603-842](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/commands/init.ts#L603-L842) [packages/shadcn/src/preflights/preflight-init.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/preflights/preflight-init.ts) [packages/shadcn/src/utils/create-project.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/utils/create-project.ts)
- add flow: addOptionsSchema.parse → loadEnvFiles → getConfig (createConfig fallback) → ensureRegistriesInConfig → getProjectInfo → warnForDeprecatedComponents → getRegistryItems([first]) to learn item type (theme/style/base skip index, universal items short-circuit to addComponents) → promptForRegistryComponents if none → preFlightAdd → on MISSING_CONFIG prompt then runInit(...) → on MISSING_DIR createProject+runInit → dryRunComponents+formatDryRunResult if --dry-run/--diff/--view → addComponents → updateAppIndex for v0 /chat/b/ blocks. — [packages/shadcn/src/commands/add.ts#L67-328](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/commands/add.ts#L67-L328) [packages/shadcn/src/preflights/preflight-add.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/preflights/preflight-add.ts) [packages/shadcn/src/utils/update-app-index.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/utils/update-app-index.ts)
- Install internals: addComponents → getWorkspaceConfig → addWorkspaceComponents (files grouped by TargetAliasKey ui/hooks/lib, per-target updateFiles) or addProjectComponents → resolveAndValidateRegistryTree → validateFilesTarget → massageTreeForFonts → getSupportedFontMarkers → updateDependencies → updateTailwindConfig → updateEnvVars → updateFonts → updateFiles → resolveOverwriteCssVars → updateCss → log tree.docs. — [packages/shadcn/src/utils/add-components.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/utils/add-components.ts)
- Fetch trace: resolveRegistryItemsFromRegistries (URL+headers per item, setRegistryHeaders) → fetchRegistryItems → per-item dispatch → fetchRegistry → resolveRegistryUrl → getRegistryHeadersFromContext → fetchWithProxy manual redirect loop → non-ok maps to RegistryUnauthorized/NotFound/Gone/Forbidden/FetchError with RFC-7807 detail parsing → registryItemSchema.parse → RegistryParseError on failure. — [packages/shadcn/src/registry/resolver.ts#L46-133](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/registry/resolver.ts#L46-L133) [packages/shadcn/src/registry/fetcher.ts#L26-141](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/registry/fetcher.ts#L26-L141) [packages/shadcn/src/registry/errors.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/registry/errors.ts)
- build trace: preFlightBuild(resolvePaths) → readRegistryWithIncludes(registryFile) → createRegistryCatalog → per item createRegistryItem → mkdir+write outputDir/<name>.json (nested names OK) → write/copy registry.json to outputDir. — [packages/shadcn/src/commands/build.ts#L35-102](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/commands/build.ts#L35-L102) [packages/shadcn/src/registry/loader.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/registry/loader.ts) [packages/shadcn/src/preflights/preflight-registry.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/preflights/preflight-registry.ts)
- mcp serve trace: shadcn mcp → loadEnvFiles(cwd) → new StdioServerTransport → server.connect → ListToolsRequestSchema returns 7 tools → CallToolRequestSchema → withRegistryContext(handleCallTool, {onGitHubAuthNotice}) → per-tool zod arg parse → getMcpConfig(process.cwd()) → searchRegistries/getRegistryItems → text content responses; errors return isError content blocks. — [packages/shadcn/src/commands/mcp.ts#L98-107](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/commands/mcp.ts#L98-L107) [packages/shadcn/src/mcp/index.ts#L189-598](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/mcp/index.ts#L189-L598)
- Site registry:build trace: pnpm registry:build → build @shadcn/react → @shadcn/helpers → shadcn → bun scripts/build-registry.mts → STYLE_COMBINATIONS from BASES×STYLES → writes registry/bases/__index__.tsx, temp registry/<base-style> trees, registry/__index__.tsx, examples/__index__.tsx → exports public/r/* via the shadcn CLI → copies compiled ui/* into styles/<style>/ui (+ui-rtl for nova) → prettier → cleanup. — [apps/v4/package.json](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/apps/v4/package.json) [apps/v4/scripts/build-registry.mts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/apps/v4/scripts/build-registry.mts) [apps/v4/registry/bases.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/apps/v4/registry/bases.ts) [apps/v4/registry/styles.tsx](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/apps/v4/registry/styles.tsx)
- Dry-run trace: --dry-run/--diff/--view short-circuit before writes — ensureRegistriesInConfig with writeFile:false → dryRunComponents(components, config, {overwrite}) runs the same resolve+transform machinery in memory → formatDryRunResult prints per-file diff or content. — [packages/shadcn/src/commands/add.ts#L289-311](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/commands/add.ts#L289-L311) [packages/shadcn/src/utils/dry-run.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/utils/dry-run.ts) [packages/shadcn/src/utils/dry-run-formatter.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/utils/dry-run-formatter.ts)

## Testing signals

Vitest is the single framework. packages/shadcn has dense colocated unit tests plus fixture dirs; packages/tests is a heavier e2e layer that executes the built CLI against copied project fixtures and a stub registry server; @shadcn/react adds browser-mode tests. apps/v4 has only a handful of tests and no coverage config exists anywhere. The root `pnpm test` gate requires building the registry and running the v4 dev server on :4000.
- Root vitest workspace = ./vitest.config.ts (excludes node_modules/fixtures/templates/packages/tests) + ./packages/tests/vitest.config.ts; vite-tsconfig-paths plugin resolves the '@/src/*' alias used throughout packages/shadcn. — [vitest.workspace.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/vitest.workspace.ts) [vitest.config.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/vitest.config.ts)
- packages/shadcn unit tests are colocated *.test.ts across commands/, registry/, utils/, migrations/, preflights/, preset/ (e.g. resolver.test.ts 2588 LOC, update-files.test.ts 2634 LOC) with 8s testTimeout; fixtures live in test/fixtures (config-*, frameworks/*, project-* variants). — [packages/shadcn/vitest.config.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/vitest.config.ts) [packages/shadcn/src/registry/resolver.test.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/registry/resolver.test.ts) [packages/shadcn/test/fixtures](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/test/fixtures)
- HTTP mocking uses msw (devDep); proxy.ts deliberately keeps globalThis.fetch because MSW's Node adapter patches it — importing undici fetch would bypass interception and break registry tests (documented in-code). — [packages/shadcn/package.json](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/package.json) [packages/shadcn/src/registry/proxy.ts#L144-147](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/registry/proxy.ts#L144-L147)
- packages/tests e2e: vitest globals, 120s timeouts, maxConcurrency 4, globalSetup src/utils/setup.ts; helpers copy fixtures (next-app, vite-app, remix-app, vite-monorepo-imports, registry, etc.) to a temp dir and run `node packages/shadcn/dist/index.js` via execa with CI=true. — [packages/tests/vitest.config.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/tests/vitest.config.ts) [packages/tests/src/utils/helpers.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/tests/src/utils/helpers.ts) [packages/tests/src/utils/setup.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/tests/src/utils/setup.ts)
- e2e registry isolation: src/utils/registry.ts spins a real http server (default port 4444) serving fake /r endpoints incl. registries.json; REGISTRY_URL env (default http://localhost:4000/r) points tests at the v4 dev server for the full suite. — [packages/tests/src/utils/registry.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/tests/src/utils/registry.ts) [packages/tests/src/utils/helpers.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/tests/src/utils/helpers.ts)
- e2e coverage: packages/tests/src/tests covers init, add, apply, view, search, registries, typeset — asserting written components.json shape, lib/utils.ts content, package.json deps, and globals.css variables. — [packages/tests/src/tests/init.test.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/tests/src/tests/init.test.ts)
- CI test.yml runs three jobs per PR: `pnpm test` (root — which itself spins up v4 on :4000), `pnpm --filter=@shadcn/react test`, `pnpm --filter=@shadcn/helpers test`, all on Node 22 + pnpm 10.33.4; browser-tests.yml additionally runs @shadcn/react browser tests only when packages/react changes. — [.github/workflows/test.yml](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/.github/workflows/test.yml) [.github/workflows/browser-tests.yml](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/.github/workflows/browser-tests.yml) [package.json](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/package.json)
- @shadcn/react has dedicated browser tests (vitest.browser.config.ts + vitest.browser.setup.ts) including a perf browser test for message-scroller; @shadcn/helpers has colocated unit tests for core/ai-sdk modules. — [packages/react/vitest.browser.config.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/react/vitest.browser.config.ts) [packages/react/src/message-scroller/message-scroller.perf.browser.test.tsx](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/react/src/message-scroller/message-scroller.perf.browser.test.tsx) [packages/helpers/src/core/chat.test.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/helpers/src/core/chat.test.ts)
- apps/v4 is sparsely tested: only a few *.test.ts exist (registry/calendar.test.ts, registry/config.test.ts, app/r/registries.json/route.test.ts); the Next.js UI, create-flow routes, and build-registry.mts pipeline have no direct tests — correctness relies on registry:health/monitor CI jobs. — [apps/v4/registry/calendar.test.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/apps/v4/registry/calendar.test.ts) [apps/v4/app/r/registries.json/route.test.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/apps/v4/app/r/registries.json/route.test.ts) [apps/v4/scripts/monitor-registries.mts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/apps/v4/scripts/monitor-registries.mts)
- Registry integrity is CI-gated: validate-registries.yml runs scripts/validate-registries.mts (and blocks reserved namespaces) when apps/v4/registry/directory.json changes; monitor-registries.yml runs phased health prepare/check/publish scripts. — [.github/workflows/validate-registries.yml](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/.github/workflows/validate-registries.yml) [apps/v4/scripts/validate-registries.mts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/apps/v4/scripts/validate-registries.mts) [apps/v4/registry/directory.json](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/apps/v4/registry/directory.json)
- No coverage tooling, snapshots exist only for transformers/updaters (__snapshots__ dirs), and there are no tests for the MCP tools layer (mcp/utils.test.ts exists but server handlers are untested) — likely gap areas. (inferred) — [packages/shadcn/src/utils/transformers/__snapshots__](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/utils/transformers/__snapshots__) [packages/shadcn/src/mcp/utils.test.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/mcp/utils.test.ts) [packages/shadcn/src/mcp/index.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/mcp/index.ts)

## Risk map

The dominant risk is supply-chain-style: remote registry JSON drives arbitrary file writes, env-file edits, and package installs inside user projects. Mitigations exist (isSafeTarget path validation, per-origin header scoping on redirects, typed errors, header-safe token checks) but content itself is trusted. Secondary risks: a huge init.ts action with process.exit calls, dead command modules, committed generated registry output, canary deps in the site, and an always-`latest` MCP install instruction.
- Registry items are a remote-code trust boundary: fetched file.content is written into the user's project after validateFilesTarget checks each target/path with isSafeTarget (null bytes, iterative URL-decode traversal, drive letters, absolute-path containment inside cwd) — paths are guarded, file contents are not. — [packages/shadcn/src/utils/add-components.ts#L452-471](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/utils/add-components.ts#L452-L471) [packages/shadcn/src/utils/is-safe-target.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/utils/is-safe-target.ts)
- Private-registry secrets ride in headers/params expanded from ${ENV}; fetchWithProxy follows up to 5 redirects manually and re-attaches caller headers only for same-origin hops (Accept/User-Agent survive cross-origin) — deliberate leak prevention that must be preserved. — [packages/shadcn/src/registry/proxy.ts#L84-132](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/registry/proxy.ts#L84-L132) [packages/shadcn/src/registry/builder.ts#L84-146](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/registry/builder.ts#L84-L146)
- Shell-out surface: updateDependencies execa's package-manager installs of registry-declared deps; `mcp init` runs `<pm> add -D shadcn@latest`; github-cli transport execa's `gh api` with 15s timeout — item-controlled dependency names reach the package manager. — [packages/shadcn/src/utils/updaters/update-dependencies.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/utils/updaters/update-dependencies.ts) [packages/shadcn/src/commands/mcp.ts#L155-217](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/commands/mcp.ts#L155-L217) [packages/shadcn/src/registry/github-cli.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/registry/github-cli.ts)
- GitHub item fetching supports GH_TOKEN/GITHUB_TOKEN tokens or the `gh` CLI; tokens are validated against a printable-ASCII pattern before use and GitHubTransportError carries only sanitized fields — raw subprocess output is intentionally never attached. — [packages/shadcn/src/registry/github-cli.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/registry/github-cli.ts) [packages/shadcn/src/registry/github-auth.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/registry/github-auth.ts) [packages/shadcn/src/registry/github.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/registry/github.ts)
- init.ts is a 1049-line commander action with ~10 process.exit calls inside prompts; components.json is backed up via FILE_BACKUP_SUFFIX and restored through a process 'exit' listener — fragile control flow where early exits must not leak backups or half-written config. — [packages/shadcn/src/commands/init.ts#L163-601](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/commands/init.ts#L163-L601) [packages/shadcn/src/utils/file-helper.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/utils/file-helper.ts)
- Dead command modules: packages/shadcn/src/commands/registry/build.ts and commands/registry/mcp.ts are exported but never registered — the `registry` command only adds `add` and `validate`; stale duplicates of live functionality (build lives at commands/build.ts). — [packages/shadcn/src/commands/registry/index.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/commands/registry/index.ts) [packages/shadcn/src/commands/registry/build.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/commands/registry/build.ts) [packages/shadcn/src/commands/registry/mcp.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/commands/registry/mcp.ts) [packages/shadcn/src/commands/build.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/commands/build.ts)
- Generated output is committed: 871 files under apps/v4/public/r are tracked in git while also being build-registry.mts 'persistent outputs' — drift between authored registry sources and committed artifacts is possible if build is skipped before commit. — [apps/v4/scripts/build-registry.mts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/apps/v4/scripts/build-registry.mts) [apps/v4/package.json](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/apps/v4/package.json)
- Registry items can merge env vars into user .env files (updateEnvVars + env-file merge logic in update-files) — a malicious registry could inject or overwrite environment config. — [packages/shadcn/src/utils/updaters/update-env-vars.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/utils/updaters/update-env-vars.ts) [packages/shadcn/src/utils/updaters/update-files.ts#L137-142](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/utils/updaters/update-files.ts#L137-L142) [packages/shadcn/src/utils/env-helpers.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/utils/env-helpers.ts)
- apps/v4 pins canary/prerelease deps (@ai-sdk/* canary builds, ai: 'canary', @tanstack/ai betas) — the site/registry build is exposed to upstream instability. — [apps/v4/package.json](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/apps/v4/package.json)
- MCP install instructions hardcode `shadcn@latest` (SHADCN_MCP_VERSION='latest') and tell clients to run `npx shadcn@latest mcp` — no version pinning for the server AI clients will execute. — [packages/shadcn/src/commands/mcp.ts#L20-88](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/commands/mcp.ts#L20-L88)
- Module-level registryCache in fetcher.ts persists for the process lifetime keyed by url+headers hash; in the long-lived MCP server this can serve stale items (mitigated by useCache:false in MCP tool calls). (inferred) — [packages/shadcn/src/registry/fetcher.ts#L20-24](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/registry/fetcher.ts#L20-L24) [packages/shadcn/src/mcp/index.ts#L284-292](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/mcp/index.ts#L284-L292)
- init propagates design settings into every workspace package's components.json (writes outside the top-level cwd's own config) — a failed run mid-loop could leave inconsistent workspace configs. (inferred) — [packages/shadcn/src/commands/init.ts#L779-823](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/commands/init.ts#L779-L823)

## Extension points

Primary plug-in surfaces: the templates registry + createTemplate factory for new frameworks; the ordered transformer array for content rewrites; the updaters pipeline for new install concerns; registry item types + FILE_TYPE_TO_CONFIG_KEY for new artifact kinds; the components.json registries map for third-party registries; migrations registry for codemods; commander command table and MCP tools array for new CLI/MCP surface; presets and the /init URL contract for create flows; directory.json + validation for the public registry index.
- New framework templates: add a templates/<name>-app (+ -monorepo) dir and a createTemplate entry in src/templates (fields: scaffold/create/init/postInit/files/monorepo overrides, frameworks list for getTemplateForFramework inference). — [packages/shadcn/src/templates/index.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/templates/index.ts) [packages/shadcn/src/templates/create-template.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/templates/create-template.ts)
- Content transforms: add a Transformer module under utils/transformers and append it to the ordered transform() array in update-files.ts (position matters — e.g. transformCleanup runs last, transformNext is conditional). — [packages/shadcn/src/utils/updaters/update-files.ts#L164-198](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/utils/updaters/update-files.ts#L164-L198) [packages/shadcn/src/utils/transformers/index.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/utils/transformers/index.ts)
- Install concerns plug in as updaters under utils/updaters invoked from addProjectComponents/addWorkspaceComponents in a fixed order (deps → tailwind config → env vars → fonts → files → css). — [packages/shadcn/src/utils/add-components.ts#L104-147](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/utils/add-components.ts#L104-L147)
- New registry item types require extending registryItemTypeSchema/registryItemSchema (discriminated union on type) plus the FILE_TYPE_TO_CONFIG_KEY map that routes files to workspace targets, with parity on the site schema. — [packages/shadcn/src/registry/schema.ts#L81-193](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/registry/schema.ts#L81-L193) [packages/shadcn/src/utils/add-components.ts#L227-246](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/utils/add-components.ts#L227-L246)
- Third-party registries: users add entries to components.json `registries` with {name}/{style}/${ENV} templated URLs (+ optional headers/params); `shadcn registry add` writes them and ensureRegistriesInConfig auto-discovers @namespaces from item addresses and the registries index. — [packages/shadcn/src/registry/schema.ts#L6-26](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/registry/schema.ts#L6-L26) [packages/shadcn/src/registry/builder.ts#L22-56](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/registry/builder.ts#L22-L56) [packages/shadcn/src/commands/registry/add.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/commands/registry/add.ts) [packages/shadcn/src/utils/registries.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/utils/registries.ts)
- New CLI command: create a commander Command module under src/commands and addCommand it in index.ts; subcommand groups follow the commands/registry pattern (parent Command + .command children). — [packages/shadcn/src/index.ts#L33-47](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/index.ts#L33-L47) [packages/shadcn/src/commands/registry/index.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/commands/registry/index.ts)
- New codemods: add a module under src/migrations and register it in commands/migrate.ts (existing: migrate-radix, migrate-icons, migrate-base-color, migrate-rtl, migrate-cn). — [packages/shadcn/src/commands/migrate.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/commands/migrate.ts) [packages/shadcn/src/migrations/migrate-radix.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/migrations/migrate-radix.ts)
- New MCP tool: append to the tools[] literal in the ListToolsRequestSchema handler and add a case in handleCallTool (zod-parse args, return {content:[{type:'text',text}]}; RegistryError gets formatted with code/suggestion/context). — [packages/shadcn/src/mcp/index.ts#L55-187](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/mcp/index.ts#L55-L187) [packages/shadcn/src/mcp/index.ts#L545-598](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/mcp/index.ts#L545-L598)
- Presets: DEFAULT_PRESETS in src/preset + encode/decode preset codes (isPresetCode/decodePreset) resolve to site /init URLs; the site's parseDesignSystemConfig + buildRegistryBase define the server half of the contract. — [packages/shadcn/src/preset/presets.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/preset/presets.ts) [packages/shadcn/src/preset/preset.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/preset/preset.ts) [apps/v4/app/(app)/(create)/lib/parse-config.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/apps/v4/app/(app)/(create)/lib/parse-config.ts) [apps/v4/registry/config.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/apps/v4/registry/config.ts)
- Public registry directory: community registries are listed in apps/v4/registry/directory.json, validated by scripts/validate-registries.mts, and gated by the validate-registries workflow (reserved-namespace blocklist). — [apps/v4/registry/directory.json](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/apps/v4/registry/directory.json) [apps/v4/scripts/validate-registries.mts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/apps/v4/scripts/validate-registries.mts) [.github/workflows/validate-registries.yml](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/.github/workflows/validate-registries.yml)
- Icon libraries are pluggable via src/icons (exported as shadcn/icons) + transform-icons + the iconLibrary config field; styles/themes/fonts/base-colors are data registries under apps/v4/registry consumed by both site and build. — [packages/shadcn/src/icons/index.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/icons/index.ts) [packages/shadcn/src/utils/transformers/transform-icons.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/utils/transformers/transform-icons.ts) [apps/v4/registry/themes.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/apps/v4/registry/themes.ts) [apps/v4/registry/fonts.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/apps/v4/registry/fonts.ts)
- Agent-facing extension: skills/*/SKILL.md bundles (with rules/ and evals/) encode usage rules for AI tools — adding a skill is a docs-only change, separate from CLI code. — [skills/shadcn/SKILL.md](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/skills/shadcn/SKILL.md) [skills/migrate-radix-to-base/SKILL.md](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/skills/migrate-radix-to-base/SKILL.md)

## Contributor handoff

Most work happens in packages/shadcn (the CLI) and apps/v4 (site + registry authoring). Read the entrypoint, the two big command actions, the resolver/fetcher layer, and the updater pipeline before editing. Build the CLI before running e2e. Respect the invariants: CSS writes last, registry context cleared in finally, globalThis.fetch in proxy.ts, generated public/r is not hand-edited, and components.json is user-owned.
- Read-first files: packages/shadcn/src/index.ts (command table), commands/init.ts + commands/add.ts (the two complex actions), utils/add-components.ts (install pipeline), registry/resolver.ts + registry/fetcher.ts + registry/builder.ts (fetch/addressing), registry/schema.ts (all zod contracts), utils/updaters/update-files.ts (write+transform). — [packages/shadcn/src/index.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/index.ts) [packages/shadcn/src/commands/init.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/commands/init.ts) [packages/shadcn/src/commands/add.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/commands/add.ts) [packages/shadcn/src/utils/add-components.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/utils/add-components.ts) [packages/shadcn/src/registry/schema.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/registry/schema.ts)
- Dev loop: `pnpm install`; build CLI `pnpm --filter=shadcn build` (tsup); run CLI against local site `pnpm shadcn:dev` (REGISTRY_URL=http://localhost:4000/r, SHADCN_TEMPLATE_DIR=../../templates) after `pnpm v4:dev`; unit tests `pnpm shadcn:test` (vitest run in packages/shadcn). — [package.json](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/package.json) [packages/shadcn/package.json](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/package.json)
- E2e tests require the built dist and the v4 site: root `pnpm test` = `pnpm --filter=v4 registry:build` + start-server-and-test on http://localhost:4000 + `turbo run test`; packages/tests executes dist/index.js — editing src without rebuilding silently tests stale code. — [package.json](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/package.json) [packages/tests/src/utils/helpers.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/tests/src/utils/helpers.ts) [packages/shadcn/package.json](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/package.json)
- Conventions: zod schemas validate every external input (options schemas, registryItemSchema, rawConfigSchema); interactivity via `prompts`; output via logger/highlighter/spinner wrappers; errors are typed RegistryError subclasses with code/suggestion/context; deepmerge for config merges. — [packages/shadcn/src/registry/errors.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/registry/errors.ts) [packages/shadcn/src/commands/init.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/commands/init.ts) [packages/shadcn/src/registry/fetcher.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/registry/fetcher.ts)
- Import alias: packages/shadcn source imports use '@/src/...' resolved by tsconfig paths + vite-tsconfig-paths in vitest — keep new imports on the alias, not relative chains. — [vitest.config.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/vitest.config.ts) [packages/shadcn/vitest.config.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/vitest.config.ts) [packages/shadcn/src/commands/add.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/commands/add.ts)
- Trap: registry/proxy.ts must keep calling globalThis.fetch (not undici's) so msw interception works in tests; redirects are manual — don't replace with redirect:'follow' or private-registry headers will leak cross-origin. — [packages/shadcn/src/registry/proxy.ts#L84-153](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/registry/proxy.ts#L84-L153)
- Trap: every command action must end with clearRegistryContext() in finally (headers/env live in AsyncLocalStorage); new commands that fetch registry items need the same discipline. — [packages/shadcn/src/commands/add.ts#L325-327](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/commands/add.ts#L325-L327) [packages/shadcn/src/commands/init.ts#L598-600](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/commands/init.ts#L598-L600) [packages/shadcn/src/registry/context.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/registry/context.ts)
- Trap: write CSS last — updateCss is intentionally after updateFiles so file watchers rebuild once; preserve ordering when touching the updater pipeline. Also preserve the components.json FILE_BACKUP_SUFFIX backup/restore dance in init. — [packages/shadcn/src/utils/add-components.ts#L132-147](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/utils/add-components.ts#L132-L147) [packages/shadcn/src/commands/init.ts#L164-175](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/commands/init.ts#L164-L175)
- Do not hand-edit generated artifacts: apps/v4/public/r/**, registry/__index__.tsx, registry/bases/__index__.tsx, styles/<style>/ui/** are build-registry.mts outputs; edit authored sources under registry/bases, registry/styles/*.css, examples/, and registry/new-york-v4 instead. — [apps/v4/scripts/build-registry.mts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/apps/v4/scripts/build-registry.mts) [apps/v4/registry/new-york-v4/registry.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/apps/v4/registry/new-york-v4/registry.ts)
- Release flow: changesets (`pnpm release` = changeset version); publishing is `cd packages/shadcn && pnpm pub:beta|pub:rc|pub:next|pub:release`; release.yml auto-publishes prereleases for PRs labeled 'release: beta'/'release: rc'; commits use conventional-commit lint (.commitlintrc.json). — [package.json](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/package.json) [packages/shadcn/package.json](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/package.json) [.github/workflows/release.yml](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/.github/workflows/release.yml) [.commitlintrc.json](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/.commitlintrc.json)
- Env vars that matter: REGISTRY_URL (registry base), SHADCN_TEMPLATE_DIR (template lookup), SHADCN_GITHUB_URL (template repo override), GH_TOKEN/GITHUB_TOKEN (github: item auth), HTTPS_PROXY/HTTP_PROXY/ALL_PROXY (fetch proxying), plus .env* files loaded per-command for ${ENV} expansion. — [packages/shadcn/src/registry/constants.ts#L5-6](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/registry/constants.ts#L5-L6) [packages/shadcn/src/templates/create-template.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/templates/create-template.ts) [packages/shadcn/src/registry/github-cli.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/registry/github-cli.ts) [packages/shadcn/src/registry/proxy.ts#L4-11](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/registry/proxy.ts#L4-L11) [packages/shadcn/src/utils/env-loader.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/utils/env-loader.ts)
- Schema parity: registry/schema.ts is published as shadcn/schema and imported by apps/v4 (registryItemSchema in build-registry.mts and the /init route) — changing item shape requires updating both sides and the 871 committed public/r artifacts via a rebuild. — [packages/shadcn/src/registry/schema.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/packages/shadcn/src/registry/schema.ts) [apps/v4/scripts/build-registry.mts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/apps/v4/scripts/build-registry.mts) [apps/v4/app/(app)/(create)/init/route.ts](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/apps/v4/app/(app)/(create)/init/route.ts)
- templates/* are outside the pnpm workspace (pnpm-workspace only includes apps/*+packages/*); after editing a template, scripts/sync-templates.sh syncs them — CI templates.yml validates them. — [pnpm-workspace.yaml](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/pnpm-workspace.yaml) [scripts/sync-templates.sh](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/scripts/sync-templates.sh) [.github/workflows/templates.yml](https://github.com/shadcn-ui/ui/blob/98a1fe67b439324ddc857f47fbdce056600a4329/.github/workflows/templates.yml)

Source repository: https://github.com/shadcn-ui/ui
Full evidence corpus: https://github.com/Codevetter/codevetter/tree/main/benchmarks/repo-unpacks/ui.json

## Public product links

- [CodeVetter](https://codevetter.com/)
- [Download](https://codevetter.com/download)
- [Documentation](https://codevetter.com/docs/)
- [Source](https://github.com/Codevetter/codevetter)
