An intentionally minimal TanStack Start + Vite+ starter template for publishing a shadcn-compatible registry without writing the documentation site and registry plumbing from scratch.
The scaffold contains a typed registry authoring layer, authored docs, live preview pages, syntax-highlighted source snippets, schema validation, package-manager install commands, and TanStack Start server routes. See a demo here.
Note
_cn is pronounced "underscore-cn".
Ensure you have Vite+ installed first; this will ensure all other requirements are taken care of for you.
# Install Vite+
curl -fsSL https://vite.plus | bash
# Setup and start local server
vp install
vp devOpen the localhost URL from Vite+ and browse the starter docs, component, block, and utility pages.
This repository includes an installable Agent Skill for authoring _cn registry items. Install it into your harness from the upstream template using the Skills CLI:
npx skills add jakejarvis/_cn --skill shadcn-registryAfter installing the skill, ask your agent for registry authoring work directly:
- "add a button component to the registry"
- "adapt this modal from my app to make it reusable via this shadcn registry"
- "add a reusable hook to the registry"
- "turn this dashboard section into a registry block"
Above is a one-click button to fork the template and deploy it to Vercel as a platform-agnostic Nitro server.
You can just as easily use any other platform (Cloudflare Workers, Netlify, etc.) by following the TanStack Start docs to make a few adjustments to your vite.config.ts file (agents are usually pretty good at this too).
vp check
vp buildRegistry tests live under src/lib/registry/*.test.ts and src/components/docs/*.test.ts.
Edit registry/config.ts.
export const registryConfig = {
name: "_cn",
registryName: "_cn",
namespace: "@_cn",
description: "Installable components for your project.",
homepage: "https://underscore-cn.vercel.app",
repositoryUrl: "https://github.com/jakejarvis/_cn",
} as const;Set homepage before deploying. Install commands and local registry dependency URLs are built from this value.
Registry endpoint paths stay in src/lib/site-config.ts with the URL helpers so template plumbing can evolve separately from the registry-specific values most projects edit.
The public registry index is available at both the root and /r paths, while installable item JSON lives under /r:
/registry.jsonserves the registry index./r/registry.jsonserves the same registry index./r/<name>.jsonserves an item JSON file./llms.txtand/llms-full.txtare generated from the same Markdown docs and registry item pages used by the site.
Docs pages, registry section pages, and registry item pages also support Markdown content negotiation (inspired by Fumadocs). AI clients that request text/markdown, text/x-markdown, or text/plain in the Accept header receive the Markdown version of the current page directly, while normal browser requests still receive HTML.
Install command URLs and local registry dependency URLs are generated from the registry path config in src/lib/site-config.ts.
Create public documentation pages under registry/docs/.
registry/docs/
index.mdx
installation.mdx
registry.mdx
Docs render under /docs: registry/docs/index.mdx becomes /docs, and registry/docs/installation.mdx becomes /docs/installation. Keep docs files directly under registry/docs for now; nested docs pages are not supported yet.
Docs files support optional YAML frontmatter:
---
title: Installation
description: Install and run this registry.
order: 1
group: Getting Started
---
# Installation
Use Markdown or MDX with the built-in docs components.Use registry/docs/* for documentation only. Installable registry item source must stay under registry/items/**.
Create a folder under registry/items/<section>/<item-name>/.
registry/items/components/example-card/
_registry.mdx
example-card.tsx
Keep item source under registry/items. The Vite import.meta.glob paths are intentionally static.
Write metadata, usage docs, and the preview together in _registry.mdx.
---
name: example-card
type: registry:ui
title: Example Card
description: A compact card component.
registryDependencies:
- card
localRegistryDependencies:
- other-local-item
---
import { ExampleCard } from "./example-card";
Use the component anywhere you need a compact content summary.
```tsx
import { ExampleCard } from "@/components/ui/example-card";
export function Example() {
return <ExampleCard />;
}
```
export function Preview() {
return <ExampleCard />;
}For a one-file component, the catalog infers the published file path from the item root and name. List files explicitly in frontmatter for hooks, libs, blocks, pages, target paths, or any item with multiple published files. Do not publish _registry.mdx or other authoring-only files.
The MDX body renders as the optional Usage section on the docs page. Fenced code blocks are syntax highlighted and keep the docs site's copy button. The Preview export is compiled as a client-only virtual module, so hooks and event handlers are fine there, but server-only logic should stay out of previews. Use localRegistryDependencies for dependencies on other local registry items; they are converted into canonical registry URLs in the public JSON.
The template ships three plain examples:
example-card: aregistry:uiitem with shadcn dependencies.use-copy-to-clipboard: aregistry:hookitem that publishes a non-component file.stats-panel: a multi-fileregistry:blockitem that uses a local registry dependency.registry/docs: starter public docs for installation, theming, CLI, registry authoring, and changelog notes.
Replace them with your own registry items before publishing.
The docs site renders non-empty Components, Blocks, and Utilities sections. Utility items cover registry:hook and registry:lib entries so non-component registry items remain discoverable before installation.
- Choose a registry name, namespace, domain, and repository URL.
- Update or replace the starter docs under
registry/docs. - Replace the starter registry items.
- Verify
/registry.json,/r/registry.json, and at least one/r/<name>.jsonitem URL. - Verify
/llms.txt,/llms-full.txt, and Markdown negotiation withAccept: text/markdownon a docs or item page. - Update
package.jsonmetadata,README.mddetails,LICENSEowner, etc. - Run
vp checkandvp build. - Deploy and test install commands with npm, pnpm, yarn, and bun.
- Optionally submit your registry to shadcn's official directory.
The registry JSON uses shadcn schemas directly from shadcn/schema.
Public item files include file contents in each item JSON response, and local registry dependencies should use localRegistryDependencies in _registry.mdx frontmatter so generated URLs follow the homepage in registry/config.ts.
The docs site uses the local shadcn UI configuration in components.json; that styling is for this app shell and does not define the identity of published registry items.