| 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. |
| name | shadcn-parity |
| metadata | {"skiller":{"source":".agents/rules/shadcn-parity.mdc"}} |
Shadcn Parity
Core Contract
When the user asks for shadcn parity, treat ../shadcn as the source of
truth for registry behavior and patterns.
Do not give them "inspired by shadcn". Do not invent a Plate-specific model
when upstream shadcn already has one.
The rule is simple:
- upstream schema first
- upstream resolver behavior first
- upstream file/layout patterns first
- upstream namespace semantics first
- Plate divergence only when the repo has a real constraint
Plate does not fork shadcn CLI. Do not talk about Plate as if it owns a
custom installer. Plate owns a registry and template sync layer around the
upstream shadcn contract.
If you diverge, say exactly why.
Ownership
Shadcn owns the contract:
- registry item schema
- namespace semantics for third-party registries like
@acme/button
- resolver behavior for plain items, namespaced items, URLs, and local files
- local-file add behavior
components.json registry semantics
Plate owns the content and delivery:
- registry source files under
apps/www/src/registry/*
- registry build logic in
apps/www/scripts/build-registry.mts
- generated registry output under
apps/www/public/r and apps/www/public/rd
- the
@plate namespace configured in template components.json
- template sync tooling in:
tooling/scripts/update-template.sh
tooling/scripts/prepare-local-template-registry.mjs
Important boundary:
- shadcn owns how registry items are resolved and installed
- Plate owns what the registry contains and how local template sync feeds it
Plate's registry build is custom. The goal is still upstream parity at the
item and resolver boundary.
Registry Rules
Registry items should stay as close as possible to upstream RegistryItem
shape.
When building or changing Plate registry items:
- check
../shadcn first
- copy upstream file/layout/helper patterns when they fit
- prefer upstream naming and dependency structure over Plate-specific novelty
- keep dynamic Plate-specific behavior in build or sync tooling, not in a fake
registry data model
Registry dependency rules:
- prefer bare names like
button, command, and popover when an upstream
shadcn registry item exists
- prefer upstream namespace syntax over raw URLs for non-default registries when
the namespace already covers the case
- prefer explicit
@plate/* for Plate self-dependencies in registry source
- public generated registry item JSON must rewrite Plate self-dependencies to
same-base item URLs such as
https://platejs.org/r/*.json, so direct URL
installs resolve transitive Plate items from the same registry base
- keep legacy localhost and absolute Plate item URLs as accepted input
compatibility for local-file sync adapters
- treat
@shadcn/* as compatibility input only; do not write it in Plate
registry source or generated output
- if upstream does not expose a small standalone item, use a small Plate
registry item instead of dragging in a huge upstream dependency just to steal
one internal file
- do not expand compatibility hacks into new conventions
Do not fork shadcn CLI to compensate for Plate registry problems. Fix the
registry data or the Plate sync tooling instead.
Template Rules
For template installs, shadcn CLI is still the installer. Plate supplies the
registry.
Template rules:
- keep
templates/*/components.json aligned with shadcn registry semantics
- treat
@plate in components.json as the install entrypoint for Plate
items
- prefer registry fixes over template-only patches when generated output is
wrong
- compare Plate output against
../shadcn before inventing a custom rule
For local template sync:
--local uses local-file mode, not localhost
- local sync works by preparing a JSON mirror from
apps/www/public/rd
- local sync exists to feed upstream shadcn local-file install flow, not to
replace it
If a change would make public installs cleaner but would break local-file sync,
call that out and fix both sides together.
Current Divergences
These are real Plate divergences today. Treat them as constraints, not as a
pattern to spread.
- Plate publishes a registry from
apps/www, not from upstream shadcn
infrastructure
- local template sync uses prepared JSON mirrors and local-file mode
- template install entrypoints use the
@plate registry in components.json
- old generated registry output may still contain absolute Plate self-URLs;
treat that as compatibility input only, not the source contract
Red Flags
Stop and reassess if you are about to do any of this:
- describe Plate as a fork of shadcn CLI
- invent a new Plate-only registry schema
- replace upstream namespace behavior with raw URL sprawl
- solve a registry issue by adding more installer logic when the data is wrong
- patch templates by hand without checking whether the registry source is the
real problem