Skip to content

Commit d16ea6d

Browse files
committed
Add shadcn parity skill
1 parent 3aefab1 commit d16ea6d

File tree

3 files changed

+198
-0
lines changed

3 files changed

+198
-0
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
name: shadcn-parity
3+
description: Clone shadcn implementation patterns with source-by-source parity. Use when the user says "shadcn parity", asks to mirror shadcn, copy shadcn UX/architecture/tests, or wants more than inspiration.
4+
---
5+
6+
@.claude/skills/shadcn-parity/shadcn-parity.mdc
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
# Shadcn Parity
2+
3+
## Core Contract
4+
5+
When the user asks for shadcn parity, treat `../shadcn` as the source of
6+
truth for registry behavior and patterns.
7+
8+
Do not give them "inspired by shadcn". Do not invent a Plate-specific model
9+
when upstream shadcn already has one.
10+
11+
The rule is simple:
12+
13+
- upstream schema first
14+
- upstream resolver behavior first
15+
- upstream file/layout patterns first
16+
- upstream namespace semantics first
17+
- Plate divergence only when the repo has a real constraint
18+
19+
Plate does **not** fork shadcn CLI. Do not talk about Plate as if it owns a
20+
custom installer. Plate owns a registry and template sync layer around the
21+
upstream shadcn contract.
22+
23+
If you diverge, say exactly why.
24+
25+
## Ownership
26+
27+
Shadcn owns the contract:
28+
29+
- registry item schema
30+
- namespace semantics like `@shadcn/button` and other registry prefixes
31+
- resolver behavior for plain items, namespaced items, URLs, and local files
32+
- local-file add behavior
33+
- `components.json` registry semantics
34+
35+
Plate owns the content and delivery:
36+
37+
- registry source files under `apps/www/src/registry/*`
38+
- registry build logic in `apps/www/scripts/build-registry.mts`
39+
- generated registry output under `apps/www/public/r` and `apps/www/public/rd`
40+
- the `@plate` namespace configured in template `components.json`
41+
- template sync tooling in:
42+
- `tooling/scripts/update-template.sh`
43+
- `tooling/scripts/prepare-local-template-registry.mjs`
44+
45+
Important boundary:
46+
47+
- shadcn owns how registry items are resolved and installed
48+
- Plate owns what the registry contains and how local template sync feeds it
49+
50+
Plate's registry build is custom. The goal is still upstream parity at the
51+
item and resolver boundary.
52+
53+
## Registry Rules
54+
55+
Registry items should stay as close as possible to upstream `RegistryItem`
56+
shape.
57+
58+
When building or changing Plate registry items:
59+
60+
- check `../shadcn` first
61+
- copy upstream file/layout/helper patterns when they fit
62+
- prefer upstream naming and dependency structure over Plate-specific novelty
63+
- keep dynamic Plate-specific behavior in build or sync tooling, not in a fake
64+
registry data model
65+
66+
Registry dependency rules:
67+
68+
- prefer `@shadcn/*` when an upstream shadcn item exists
69+
- prefer upstream namespace syntax over raw URLs when the namespace already
70+
covers the case
71+
- if upstream does not expose a small standalone item, use a small Plate
72+
registry item instead of dragging in a huge upstream dependency just to steal
73+
one internal file
74+
- do not expand compatibility hacks into new conventions
75+
76+
Do not fork shadcn CLI to compensate for Plate registry problems. Fix the
77+
registry data or the Plate sync tooling instead.
78+
79+
## Template Rules
80+
81+
For template installs, shadcn CLI is still the installer. Plate supplies the
82+
registry.
83+
84+
Template rules:
85+
86+
- keep `templates/*/components.json` aligned with shadcn registry semantics
87+
- treat `@plate` in `components.json` as the install entrypoint for Plate
88+
items
89+
- prefer registry fixes over template-only patches when generated output is
90+
wrong
91+
- compare Plate output against `../shadcn` before inventing a custom rule
92+
93+
For local template sync:
94+
95+
- `--local` uses local-file mode, not localhost
96+
- local sync works by preparing a JSON mirror from `apps/www/public/rd`
97+
- local sync exists to feed upstream shadcn local-file install flow, not to
98+
replace it
99+
100+
If a change would make public installs cleaner but would break local-file sync,
101+
call that out and fix both sides together.
102+
103+
## Current Divergences
104+
105+
These are real Plate divergences today. Treat them as constraints, not as a
106+
pattern to spread.
107+
108+
- Plate publishes a registry from `apps/www`, not from upstream shadcn
109+
infrastructure
110+
- local template sync uses prepared JSON mirrors and local-file mode
111+
- template install entrypoints use the `@plate` registry in `components.json`
112+
- some built registry output may still emit absolute Plate self-URLs for
113+
compatibility; treat that as behavior to minimize, not a new model to copy
114+
115+
## Red Flags
116+
117+
Stop and reassess if you are about to do any of this:
118+
119+
- describe Plate as a fork of shadcn CLI
120+
- invent a new Plate-only registry schema
121+
- replace upstream namespace behavior with raw URL sprawl
122+
- solve a registry issue by adding more installer logic when the data is wrong
123+
- patch templates by hand without checking whether the registry source is the
124+
real problem

.github/workflows/registry.yml

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
name: Registry
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
paths:
8+
- '.github/actions/**'
9+
- '.github/workflows/registry.yml'
10+
- 'apps/www/package.json'
11+
- 'apps/www/scripts/**'
12+
- 'apps/www/src/app/globals.css'
13+
- 'apps/www/src/registry/**'
14+
15+
permissions:
16+
contents: write
17+
pull-requests: write
18+
19+
jobs:
20+
update-registry:
21+
name: Update Registry
22+
runs-on: ubuntu-latest
23+
if: ${{ github.repository == 'udecode/plate' && github.ref == 'refs/heads/main' && !contains(github.event.head_commit.message, '[skip release]') }}
24+
25+
concurrency:
26+
group: ${{ github.workflow }}-${{ github.ref }}
27+
cancel-in-progress: true
28+
29+
steps:
30+
- name: 📥 Checkout Repo
31+
uses: actions/checkout@v4
32+
with:
33+
fetch-depth: 0
34+
token: ${{ secrets.API_TOKEN_GITHUB || secrets.GITHUB_TOKEN }}
35+
36+
- name: ♻️ Setup Node.js
37+
uses: actions/setup-node@v4
38+
with:
39+
node-version: 22
40+
41+
- name: 📦 Monorepo install
42+
uses: ./.github/actions/pnpm-install
43+
with:
44+
link-workspace-packages: 'true'
45+
46+
- name: 🔧 Configure git
47+
run: |
48+
git config user.name "github-actions[bot]"
49+
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
50+
51+
- name: 🏗 Build Registry
52+
run: pnpm --filter www build:registry && pnpm --filter www build:tw
53+
54+
- name: ◻️ Create Pull Request
55+
uses: peter-evans/create-pull-request@v7
56+
with:
57+
token: ${{ secrets.API_TOKEN_GITHUB || secrets.GITHUB_TOKEN }}
58+
title: 'Update Registry'
59+
body: |
60+
Update Registry.
61+
commit-message: 'chore: update registry [skip release]'
62+
committer: GitHub <noreply@github.com>
63+
branch: registry
64+
delete-branch: true
65+
add-paths: |
66+
apps/www/public/r
67+
apps/www/public/tailwind.css
68+
apps/www/src/__registry__/index.tsx

0 commit comments

Comments
 (0)