description: Autogoal-backed planning, status, review, dashboard, apply, and tracking for upstream shadcn docs syncs into Plate docs. Use when the user asks for sync-shadcn, sync-shadcn status, sync-shadcn review, sync-shadcn dashboard, sync-shadcn apply, a scoped sync-shadcn <feature> lane, to sync shadcn docs, audit newer shadcn docs changes, compare ../shadcn/apps/v4 with apps/www, update the shadcn sync baseline, or decide what to adopt, fork, defer, or exclude from upstream shadcn.
name: sync-shadcn
metadata:
skiller:
source: .agents/rules/sync-shadcn.mdc
Sync Shadcn
Handle $ARGUMENTS.
Goal: compare the tracked upstream shadcn docs baseline with the current
../shadcn/apps/v4 target, inventory every added/modified/deleted upstream
change, map each change to Plate's docs app, classify the merge decision, write
a reviewable plan under docs/sync/shadcn, directly merge any qualifying tiny
overlap fixes, then stop for user review of the remaining slices. A later
explicit user acceptance starts implementation mode for a named plan and slice.
If $ARGUMENTS starts with a command name, dispatch to that command before the default planning/implementation flow. If $ARGUMENTS names a feature, product surface, or slice, run a scoped planning lane for that scope. The default full-range planning lane applies only when no command or scope is mentioned.
This skill exists because Plate's docs app is a forked product surface, not a generic shadcn mirror. Upstream owns the Fumadocs/shadcn docs architecture. Plate owns Plate docs content, editor demos, registry content, API MDX, CN docs, MCP, Plate Plus hooks, GA, and a small set of intentional forks.
Autogoal Dependency
This skill depends on
$autogoal. Load
autogoal before mutable sync state, upstream pull/fetch, run artifact writes,
status JSON edits, or implementation delegation.
sync-shadcn is a derived autogoal workflow and a two-phase lane:
- Planning mode is the default. It writes the range plan, updates
lastPlannedCommit, directly applies qualifying micro-overlap merges, asks the user to review the remaining plan, and stops. - Implementation mode starts only after the user explicitly accepts a plan and slice in a later instruction, except for the micro-overlap direct merge exception below.
- Default flow mode: one-shot execution for planning mode and one-shot execution for accepted implementation mode. They are separate activations.
- Use collaborative planning only when the user is explicitly deciding policy before a range plan is written.
- Primary template:
docs/plans/templates/sync-shadcn.md. - Default packs: none. Add
docsif docs/content pages are edited during an accepted implementation,browserif visible docs UI is edited, andagent-nativeif.agents/**,.claude/**,.codex/**, skills, commands, prompts, or user-action tooling are edited. - Required evidence types:
command,source-audit,artifact, andN/Arows. Addbrowserevidence when a planning scope or accepted implementation touches visible docs UI. - Visual sync scopes must capture comparable screenshots of the upstream shadcn page and the Plate page before making or closing a visual parity call. Save only screenshots and notes, not broad upstream patch files.
autogoalowns goal lifecycle, blocked/completion semantics, active-goal conflict handling, plan instantiation, output-budget discipline, andcheck-complete.mjs.sync-shadcnowns shadcn range policy, commit accounting, upstream inventory classification, Plate fork/exclusion decisions, status JSON semantics, and merge-slice handoff.
Micro-Overlap Direct Merge Exception
The default review boundary is still real. Do not use it as an excuse to miss obvious tiny upstream fixes on components Plate already mirrors.
During planning, directly merge a change when all of these are true:
- The upstream row maps to a retained Plate component, primitive, hook, or utility with a clear local owner path, not to upstream product content.
- The parent surface is already
synced, an accepted partial sync, or an obvious overlapping primitive such asButton,Badge,Input,Command,Tooltip,PageHeader, or the copied docs-shell components. - The diff is tiny: one local file, one behavior/class/token/prop/import fix, no new files, no deleted files, no new dependency, no route, no data model, no generated output, and no package or lockfile edit.
- The local Plate file still has the old value or an equivalent local variant that should receive the same fix.
- The change does not touch settled exclusions: v0, create, charts, colors,
Rhea/theme/customizer/style-registry product surfaces, upstream docs prose,
external registry directory content, or generated
public/r/**output. - No product judgment is needed. If the change changes layout, UX, copy, route shape, docs concepts, registry semantics, or multi-file architecture, it is not a micro-merge.
Examples of direct merges:
- Replace one stale utility class on Plate's copied
Buttonbecause upstream fixed the same class on every style variant. - Apply one bugfix conditional to a copied
CommandorCopyButtonprimitive when Plate has the same bug and no Plate product requirement changes. - Remove one dead prop/import from a synced component when upstream removed it and Plate has no local dependency on it.
Examples that still require review:
- Package bumps, lockfile changes, registry schema/route changes, docs concept additions, new components, deleted components, multi-file UI chunks, visual layout rewrites, sidebar/search behavior changes, generated registry output, and anything touching a deferred or rejected product surface.
When a micro-overlap merge is found:
- Record it in the run plan under
## Micro Auto-Mergeswith upstream path, Plate path, focused diff summary, why it qualifies, and verification. - Patch the Plate owner file directly in the same activation.
- Run the smallest meaningful verification: focused eslint/typecheck/source audit; add browser proof when the changed component is browser-visible and a stable route exists.
- Add a
partialSyncsentry if the full baseline does not advance. KeeplastSyncedCommitunchanged unless the whole range is complete. - Continue to stop for review on every non-micro slice.
Commands
Supported commands:
status: summarize current shadcn sync state, partial syncs, deferred decisions, and recommended next step without writing sync artifacts.dashboard: regenerate the structured feature-delta dashboard underdocs/sync/shadcnfor visual review of synced, deferred, rejected, forked, and pending shadcn sync decisions.apply: apply a copied dashboard review payload todocs/sync/shadcn/deltas.json, answer question-only rows without mutation, implement rows targetingsynced, then regenerate the dashboard when rows changed.review: re-audit the current tracked shadcn range against../shadcnand the current Plate checkout before trusting an existing plan.
Feature-scoped planning:
- Any non-command $ARGUMENTS value is a user-named scope. Treat the full argument string as the scope label instead of hardcoding allowed feature names.
- Scope labels can describe UI surfaces, routes, product areas, registry groups, content families, or implementation slices.
- If the scope is too vague to map to upstream and Plate files, ask one focused question before writing artifacts.
Command parsing:
- The first $ARGUMENTS token is the command when it matches a supported command.
- The full $ARGUMENTS string is the scope when the first token is not a supported command.
- If no command or scope is present, use the default full-range planning/implementation flow.
- Reserved commands are
status,dashboard,apply, andreview; do not treat them as scope labels. - Scopes are planning lanes, not broad implementation permission. A scoped
plan still stops for user review before non-micro
apps/wwwwork.
Scoped Planning
Use sync-shadcn <scope> when the user wants to sync only one named surface
before reviewing broader docs sync work.
Purpose:
- compare the tracked upstream range, but inventory and classify only changes that affect the named scope
- write a reviewable scope-specific plan under
docs/sync/shadcn - avoid the default full-range lane unless the user invokes
sync-shadcnwithout a command or scope
Scope discovery:
- Translate the user-named scope into likely upstream files under
../shadcn/apps/v4and likely Plate files underapps/www. - Search names, route paths, component names, config keys, registry names, and docs paths that match the scope.
- Include all matching hunks that directly affect the scope.
- Exclude adjacent changes that only share a file but belong to another surface; classify those as out-of-scope.
Scoped planning rules:
- Save artifacts in a scope-named run directory or plan name, for example
docs/sync/shadcn/runs/<date>-<base>-to-<target>-<scope-slug>/. - Use upstream diffs/logs for the same baseline and target as the default lane, but filter inventory rows to scope-matching files and patch hunks.
- Also record an out-of-scope count for upstream rows in the range so it is
clear the scoped plan cannot advance
lastSyncedCommitalone. - If the scope is visual or route-owned, capture upstream and Plate screenshots
for the matching route(s) at the same viewport before finalizing the plan.
Use
docs/sync/shadcn/runs/<range>/screenshots/for committed evidence, and include screenshot paths plus the visible deltas in the plan. - Do not update
lastSyncedCommitfrom a scoped plan. Scoped sync can add apartialSyncsentry after accepted implementation, but the baseline advances only when the full range is accounted for. - The plan's recommended slices must stay inside the named scope. If a file also
contains unrelated changes, classify the scope hunk as
smart-mergeand the unrelated hunks as out-of-scope for this lane. - Final planning output must say that the default full sync lane remains pending for the out-of-scope rows.
status
Use sync-shadcn status when the user wants a quick checkpoint before choosing
the next sync step.
Purpose:
- show the current baseline, latest planned target, current upstream target, and whether the tracked plan looks fresh enough for decision-making
- list accepted partial syncs already landed
- list deferred decisions so the user can choose what to do next
- list reviewable Plate-vs-shadcn differences that are still intentionally undecided or deferred, especially visual parity gaps from scoped sync plans
- recommend the next command or decision
Status mode may:
- read
docs/sync/shadcn/status.json - read
lastPlan, the linkedinventory.md, and the latest run directory when present - resolve
../shadcnrefs and fetchorigin main --tagswhen the user asks for current upstream freshness; if fetch fails, report freshness as unverified - count upstream commits and file-status rows for
lastPlannedCommit..origin/main - summarize
partialSyncs[*].slices,partialSyncs[*].deferred, and planQuestions - when the user supplies words after
status, treat the remaining argument as a status scope filter, for examplestatus our /editors vs shadcn /blocks; prefer the matchingpartialSyncs[*].plan,lastPlan, or run directory before falling back to global status - summarize remaining reviewable differences from the matched plan's
Recommended Merge Slices,Visual Evidence,Implementation Result, andpartialSyncs[*].deferred
Status mode must not:
- patch
apps/www - write
docs/sync/shadcn/runs/** - write review artifacts
- change
lastSyncedCommit,lastPlannedCommit,lastPlan, orpartialSyncs - delegate implementation to
task - treat listed deferred items as accepted decisions
- list settled exclusions or preserved Plate forks as if they still need
action; those belong in
reviewevidence or the plan, not routine status output
Status must distinguish three things:
Landed: accepted partial sync slices already applied.Reviewable differences: Plate still differs from upstream and the difference is not settled policy. These are the items the user can re-decide. Include the upstream behavior, current Plate behavior, likely owner files, and the smallest next command or decision.Settled differences: explicit exclusions and preserved Plate forks. Do not list these by default unless the user asks to re-open them.
Deferred item sources, in order:
docs/sync/shadcn/status.jsonpartialSyncs[*].deferred- the selected plan's
Questionssection - recommended merge slices marked
defer,needs-question, or not yet implemented - visual evidence rows where the plan says a Plate-vs-upstream difference still needs work
- implementation-result notes that explicitly leave a follow-up slice open
- status update notes that say
lastSyncedCommitcannot advance
For visual scoped status, do not stop at "fresh" when visible deltas remain. Report them as reviewable differences even when the scoped implementation was verified. Example:
Reviewable differences:
- BlockViewer toolbar: upstream `/blocks` has compact device controls,
refresh, separated command pill, and v0 action; Plate `/editors` still keeps
its current toolbar density and excludes v0. Decision: sync toolbar spacing
only, keep Plate install/source behavior and no v0; or leave as Plate fork.
Collapse upstream product/theme/style noise into its owning deferred decision. For example, Rhea/style/theme/generated style registry rows are part of the upstream create/theming product surface; do not list them as separate status items unless the user explicitly asks to review that product surface.
Status checks:
node -e '
const fs = require("fs");
const status = JSON.parse(fs.readFileSync("docs/sync/shadcn/status.json", "utf8"));
console.log(JSON.stringify({
lastSyncedCommit: status.lastSyncedCommit,
lastPlannedCommit: status.lastPlannedCommit,
lastPlan: status.lastPlan,
partialSyncs: status.partialSyncs ?? []
}, null, 2));
'
git -C ../shadcn fetch origin main --tags
TARGET=$(git -C ../shadcn rev-parse origin/main)
PLANNED=$(node -e 'console.log(JSON.parse(require("fs").readFileSync("docs/sync/shadcn/status.json", "utf8")).lastPlannedCommit || "")')
git -C ../shadcn log --oneline --decorate "$PLANNED..$TARGET" -- apps/v4
git -C ../shadcn diff --name-status --find-renames "$PLANNED..$TARGET" -- apps/v4
Status output shape:
Status: <fresh | upstream-ahead | no-plan | blocked-ref | unverified>
Baseline: <lastSynced-short>
Planned: <lastPlanned-short>
Current upstream: <target-short>
Plan: <path or none>
Partial syncs:
- <date/range>: <landed slices>
Reviewable differences:
- <surface>: upstream <behavior>; Plate <behavior>; decision needed <adopt |
smart-merge | keep fork>; files <paths>
Deferred decisions:
- <item>
Next: <run review | rerun planning | decide deferred item | implement accepted slice | advance baseline>
Keep status concise, but do not hide reviewable differences behind a generic
"deferred" label. If the user wants full evidence, tell them to run
sync-shadcn review.
apply
Use sync-shadcn apply when the user pastes a dashboard review payload.
Purpose:
- apply rows listed directly under
$sync-shadcn applyor under an optionalRowsheading - answer rows listed under
Questionsin chat without mutatingdeltas.json - keep the copied dashboard prompt short by storing the mutation contract in this command
Apply mode may:
- read and update
docs/sync/shadcn/deltas.json - patch
apps/www,content/docs, and related source files when a listed row targetssyncedorfork - delegate a coherent implementation slice to
taskwhen asyncedorforkrow needs more than a tiny local edit - remove screenshot refs for rows applied to
syncedorrejected - delete unreferenced local screenshot files under
docs/sync/shadcn/runs/** - run
pnpm sync-shadcn dashboardafter any JSON mutation
Apply mode must not:
- write
docs/sync/shadcn/runs/**except deleting unreferenced screenshots - change
lastSyncedCommit,lastPlannedCommit,lastPlan, orpartialSyncs - infer decisions for rows not listed in the pasted payload
- mutate
deltas.jsonfor question-only rows - mark a row
syncedorforkbefore implementation is present and verified - ask for review when the row has clear files, suggestion, and acceptance criteria; ask one focused question only when the target behavior is unclear
Payload shape:
$sync-shadcn apply
- command-menu/command-footer-shortcuts (Command Menu / Footer shortcuts and copy payloads): defer -> pending note: Add copy only for components and editor kits.
Questions:
- registry/registry-review (Registry / Full registry review): Which registry rows should include copy shortcuts?
Apply rules:
- A direct bullet row under
$sync-shadcn apply, or under an optionalRowsheading, is the only mutation unit. - Set each listed item state to the requested target state.
- Target states
pending,defer, andrejectedare metadata decisions. - Target state
syncedis implementation mode: inspect the row files and suggestion, implement the requested change, run focused verification, then updatedeltas.jsontosynced. - Target state
forkis also implementation mode when the row's note, suggestion, or files imply work in Plate. Inspect the row files and suggestion, implement or verify the intentional Plate-owned fork, run focused verification, then updatedeltas.jsontofork. - A
forkupdate may be metadata-only only when the Plate fork already exists, the row note does not ask for code/content work, and the source evidence is checked before updatingdeltas.json. - Use notes to update
decision,suggestion, or summary text when appropriate. - If a note is only a question, keep it under
Questions, answer it in chat, and do not mutate JSON. - When applying
syncedorrejected, remove that row'sscreenshotsobject and delete unreferenced local screenshot files. - Keep screenshots for
forkrows. - If any row is applied, run
pnpm sync-shadcn dashboard.
dashboard
Use sync-shadcn dashboard when the user wants a visual decision board for
the shadcn sync delta instead of prose status output.
Purpose:
- render feature-owned sync deltas grouped by product surface, such as header, home, editors, releases, command menu, registry, create, preview routes, and sidebar
- show review states that can be re-decided later:
pending,defer,fork,rejected, andsynced - keep settled exclusions visible in the dashboard without polluting routine
statusoutput - make user review possible through a local static HTML artifact
- include browser-only state controls, note textareas, and a copy button that
builds a concise
$sync-shadcn applypayload - include quick row actions in two rows:
Ask,Defer, thenSync,Reject,Fork;pendingis a state/filter, not a row action - keep note textareas locked until the user chooses an explicit row intent:
Ask, a quick apply action, or a changed state value - render review actions as selected controls;
Synccopies an$sync-shadcn applyrow targetingsynced, which means implementation mode for that row - render
Forkas an implementation-capable action too: copied payloads targetingforkmean "make or verify the Plate-owned fork", not "metadata only" - use
suggestionas the durable item field for Plate-owned recommendation text, rendered asSuggestionin the dashboard with an explicitApplyaction that copies that suggestion intoNote - treat
Askas question-only: it keeps the current row state, writes the row underQuestions, and must not mutatedeltas.json - treat question-only notes as questions to answer in chat, not as decisions to
apply to
deltas.json; only rows underRowsin a$sync-shadcn applypayload should mutate structured state - open on the actionable filter by default:
pendinganddefer; keepsynced,rejected, andforkavailable behind explicit filters - split state filters into an Action row and a Done row so active review work is visually separate from settled policy/history
- render Suggestion and shadcn screenshot columns for non-
syncedreview rows when row screenshot paths exist, with click-to-zoom and close behavior in the static HTML page - remove screenshot refs for
syncedandrejectedrows during dashboard generation, and delete unreferenced local screenshot files; keep screenshot evidence forforkrows because forked differences stay useful - render one card per delta item instead of a wide table, with Suggestion vs shadcn text in two responsive columns and empty screenshot areas hidden
- do not use an item-level
nextfield indeltas.json; status and workflow guidance should come from item state, decision, suggestion, and group summary
Dashboard mode may:
- read
docs/sync/shadcn/status.json - read and update
docs/sync/shadcn/deltas.json - write
docs/sync/shadcn/dashboard.json - write
docs/sync/shadcn/dashboard.html
Dashboard mode must not:
- patch
apps/www - write
docs/sync/shadcn/runs/** - change
lastSyncedCommit,lastPlannedCommit,lastPlan, orpartialSyncs - delegate implementation to
task - treat a dashboard item as user acceptance to implement
State meanings:
synced: the slice was accepted, implemented, and verified.defer: the item is acknowledged but intentionally postponed.pending: the item has no final decision yet, including rows waiting on a user decision.fork: Plate intentionally keeps a different implementation, and that implementation is present or has been verified before the row is marked fork.rejected: upstream behavior is explicitly excluded.
Dashboard source:
docs/sync/shadcn/deltas.jsonis the editable structured decision source.docs/sync/shadcn/dashboard.jsonanddocs/sync/shadcn/dashboard.htmlare generated views.- When adding a landed implementation slice, update
status.jsonfirst, then add or update the matchingdeltas.jsonfeature row, then regenerate the dashboard. - When rejecting, deferring, or forking a feature, record the upstream behavior,
suggestion, owner files, and state rationale in
deltas.json. - For non-
syncedvisual rows, add screenshot paths underscreenshots.suggestionandscreenshots.shadcnwhen available. Leave source-only rows blank. - The HTML review controls are intentionally not persistent. The user can mark many rows, copy the generated prompt, and send it back; Codex applies the JSON edits and regenerates the dashboard.
Dashboard command:
pnpm sync-shadcn dashboard
This regenerates dashboard.html and opens it in the local browser. Use
--no-open or SYNC_SHADCN_NO_OPEN=1 when running in a non-GUI check.
Dashboard output shape:
Dashboard: docs/sync/shadcn/dashboard.html
Data: docs/sync/shadcn/dashboard.json
Opened: file:///.../docs/sync/shadcn/dashboard.html
| Feature | State | Items |
| --- | --- | ---: |
| Registry | defer | 2 |
review
Use sync-shadcn review when the user asks whether the latest sync plan is
still fresh, whether a previously written plan can still be implemented, or
whether current apps/www drift changed the merge posture.
Purpose:
- prove whether
docs/sync/shadcn/status.json, the latest plan artifacts, the current../shadcn/apps/v4target, and the current Plate docs checkout still describe the same sync problem - find new upstream commits since
lastPlannedCommit - find stale inventory artifacts for the
lastSyncedCommit..targetrange - re-run local Plate owner/source evidence for actionable rows before implementation
Inputs:
- optional plan path or run directory; default to
lastPlanfromdocs/sync/shadcn/status.json - optional target ref; default to
origin/mainin../shadcn - baseline from
lastSyncedCommit - planned target from
lastPlannedCommit
Review mode may:
- fetch
../shadcnand resolve exact refs - read
docs/sync/shadcn/status.json, the selected plan,inventory.md, andupstream-name-status.tsv - recompute upstream name-status/numstat/log data into a temporary review file
under the same run directory or under
docs/sync/shadcn/reviews/ - compare recomputed inventories with the stored run artifacts
- re-run scoped
rg/file-existence checks for Plate owner paths, explicit exclusions, preserved forks, partial sync entries, and recommended slices - write a dated
review.mdartifact with the verdict and evidence
Review mode must not:
- patch
apps/www - change
lastSyncedCommit,lastPlannedCommit,lastPlan, orpartialSyncs - delegate implementation to
task - create a new implementation plan or advance the baseline
- treat a fresh review as user acceptance to implement
Review checks:
git -C ../shadcn fetch origin main --tags
node -e '
const fs = require("fs");
const status = JSON.parse(fs.readFileSync("docs/sync/shadcn/status.json", "utf8"));
console.log(JSON.stringify({
lastSyncedCommit: status.lastSyncedCommit,
lastPlannedCommit: status.lastPlannedCommit,
lastPlan: status.lastPlan,
partialSyncs: status.partialSyncs?.length ?? 0
}, null, 2));
'
BASE=$(node -e 'console.log(JSON.parse(require("fs").readFileSync("docs/sync/shadcn/status.json", "utf8")).lastSyncedCommit || "")')
PLANNED=$(node -e 'console.log(JSON.parse(require("fs").readFileSync("docs/sync/shadcn/status.json", "utf8")).lastPlannedCommit || "")')
TARGET=$(git -C ../shadcn rev-parse origin/main)
git -C ../shadcn merge-base --is-ancestor "$BASE" "$TARGET"
git -C ../shadcn log --oneline --decorate "$PLANNED..$TARGET" -- apps/v4
git -C ../shadcn diff --name-status --find-renames "$BASE..$TARGET" -- apps/v4
Staleness verdicts:
fresh: current upstream target equalslastPlannedCommit, recomputed upstream inventory matches the selected run artifact, required Plate owner paths/source evidence still exist, and no partial-sync/status contradiction is found.stale-upstream:origin/mainhas newerapps/v4commits thanlastPlannedCommitor the recomputed upstream inventory differs from the selected run artifact.stale-local: Plate owner paths or local search evidence used by the plan no longer match the current checkout.stale-status:status.jsoncontradicts the selected plan, for example the selected plan target differs fromlastPlannedCommitwithout an explicit override, orpartialSyncsclaim work that the local checkout no longer shows.blocked-ref: the baseline, planned target, selected target, or ancestry cannot be proven.
The review artifact must include:
- selected plan/run directory
- base, planned target, and current target SHAs
- upstream commit count and file-status count for
PLANNED..TARGET - inventory comparison result for
BASE..TARGET - local Plate owner/source evidence summary
- explicit exclusions and preserved forks checked
- status semantics checked
- verdict and the next action
Review output shape:
Review: <fresh | stale-upstream | stale-local | stale-status | blocked-ref>
Range: <base-short>..<target-short>
Plan: <path>
Report: <path>
| Check | Result | Evidence |
| --- | --- | --- |
| upstream target | ... | ... |
| inventory | ... | ... |
| Plate owners | ... | ... |
| status semantics | ... | ... |
Next: <use the existing plan | rerun planning | fix local drift | resolve refs>
Before substantive work:
node .agents/skills/autogoal/scripts/create-goal-scratchpad.mjs \
--template sync-shadcn \
--title "sync shadcn <short range or target>"
Fill the generated plan immediately. It must name the objective, flow mode, completion threshold, verification surface, constraints, boundaries, output budget strategy, blocked condition, and planned run directory. Do not replace it with a smaller ad hoc plan.
Completion requires the named sync evidence plus:
node .agents/skills/autogoal/scripts/check-complete.mjs <docs/plans/path>
Never mark the active goal complete just because a range plan was written if the goal also required implementation, baseline advancement, or user acceptance.
User Review Boundary
This mirrors the important part of slate-plan: plan first, stop, then execute
only after explicit acceptance.
Planning mode may:
- fetch/pull
../shadcn - create the active goal plan
- write
docs/sync/shadcn/runs/<range>/artifacts - update
lastPlannedCommitandlastPlan - directly apply qualifying micro-overlap merges and record them as partial syncs
- ask one review/decision question
Planning mode must not:
- patch
apps/wwwexcept for qualifying micro-overlap direct merges - delegate to
task - advance
lastSyncedCommit - treat "recommended first slice" as accepted
- combine plan creation and non-micro implementation in the same activation
The final planning response must say:
Review the plan. I directly merged these micro-overlap fixes: <list or none>.
To implement the remaining slices, invoke `sync-shadcn` again with the accepted
plan path and slice.
Implementation mode requires a later user message that names or clearly accepts
the plan/slice. Then create or continue an implementation-shaped goal for that
accepted slice and proceed through task.
Hard Rules
- Use evidence, not vibes. Read upstream commits, file status, focused diffs, local Plate files, prior decisions, screenshots for visual surfaces, and relevant solution notes.
- Track exact commits. Never say "latest shadcn" without recording the target SHA.
- Treat
docs/sync/shadcn/status.jsonas the durable baseline. Do not advancelastSyncedCommituntil every upstream change in the planned range is accounted for as adopted, smart-merged, intentionally forked, or explicitly excluded. - Planning is the default output. Do not patch
apps/wwwunless the row qualifies as a micro-overlap direct merge or the user accepts a merge slice in a later instruction after reviewing a written plan. - Do not edit generated registry output, templates output, or generated skill mirrors by hand.
- Do not run
build:registry; local registry generation is CI-owned in this repo. - Do not delegate to
taskin the same activation that creates or materially updates a sync plan. Direct micro-overlap merges stay in-thread and tiny; all bigger work waits for review. - Keep the active
sync-shadcngoal plan current after every meaningful decision, artifact write, classification pass, status JSON edit, accepted implementation slice, verification run, or blocker. - Prefer deleting old Plate fork residue over preserving compatibility layers when upstream already owns the better model.
- Prefer upstream docs infrastructure unless Plate has a real product or registry reason to diverge.
- Keep output comprehensive. If a diff is too large for the chat, save complete
TSV inventories under
docs/sync/shadcn/runs/<range>/and summarize the artifact paths in the response. - Do not persist
.patchfiles in the repo. Inspect focused diffs on demand with cappedgit diffcommands, summarize the relevant hunks ininventory.mdorplan.md, and leave broad upstream patches out of committed sync artifacts.
Start Gates
These gates must be resolved in the active sync-shadcn goal plan before broad
exploration:
autogoalloaded and active goal checked or created.docs/sync/shadcn/status.jsonread.docs/sync/shadcn/decisions.mdread.- Prior migration plans and solution notes checked when relevant.
- Output budget strategy recorded before running upstream diff/log commands.
../shadcnclone state known and fetched/pulled intentionally.- Base and target refs resolved to exact SHAs.
- Base ancestry proven, or the ref problem recorded before stopping.
- Planning-only versus implementation mode decided.
- User-review boundary recorded: planning mode stops, implementation mode requires later explicit acceptance.
Completion Gates
These gates belong in docs/plans/templates/sync-shadcn.md and must be closed
in the instantiated goal plan:
- Upstream range artifacts exist and are non-empty, or a target-only bootstrap exception is recorded.
inventory.mdaccounts for every row inupstream-name-status.tsv.- Decision counts cover every upstream row.
- Source-backed Plate mapping exists for every actionable adoption, fork, exclusion, or question group.
docs/sync/shadcn/status.jsonparses and itslastPlannedCommit/lastSyncedCommitsemantics match the work actually completed.- Planning-only runs prove no
apps/wwwimplementation patch was made, or record and verify every qualifying micro-overlap direct merge. - Accepted implementation runs include focused verification for the touched Plate surface.
- Browser proof exists when browser-visible docs UI changed, or when a planning scope is visual and needs Plate-vs-shadcn parity evidence.
- Visual sync scopes include screenshots of both upstream shadcn and Plate pages at matching viewport(s), plus written deltas such as background, spacing, disabled/gray controls, nav/header items, and first-viewport framing.
lastSyncedCommitadvances only after full-row accounting, verification, and user acceptance.- Planning-mode final handoff lists any direct micro-overlap merges, asks the
user to review the remaining plan, and invokes
sync-shadcnagain with the accepted plan path and slice for bigger work. check-complete.mjspasses for the active goal plan.
Durable Policy
Read these before making decisions:
docs/sync/shadcn/status.jsondocs/sync/shadcn/decisions.mddocs/plans/2026-05-23-shadcn-docs-restart-comparison.mddocs/plans/2026-05-24-shadcn-base-migration-progress.md.agents/rules/shadcn-parity.mdcdocs/solutions/best-practices/2026-05-23-shadcn-docs-restart-comparison.mddocs/solutions/developer-experience/2026-05-27-shadcn-docs-sidebar-parity-needs-source-and-dom-metrics.mddocs/solutions/developer-experience/2026-05-24-plate-init-routes-should-return-shadcn-registry-base-items.mddocs/solutions/developer-experience/2026-05-24-shadcn-v4-registry-schema-needs-source-only-validation.mddocs/solutions/developer-experience/2026-05-24-shadcn-registry-install-commands-should-use-configured-namespaces.mddocs/solutions/developer-experience/2026-05-24-fumadocs-page-tree-search-needs-locale-safe-metadata.md
Default durable decisions:
- Discard upstream v0 surfaces.
- Discard upstream
/create,/charts,/colors, and public directory-style product pages unless the user explicitly asks for a Plate version. - Discard Plate theme/customizer/project/lift-mode residue.
- Keep Plate docs content under
content/docs/**. - Keep committed Fumadocs metadata as the docs navigation authority.
- Keep Plate API MDX vocabulary and generated API docs support.
- Keep Plate registry content and docs-registry generation, aligned to shadcn v4 schema/resolver semantics.
- Keep Plate editor demos,
/view/[name], and registry preview/source display. - Keep lazy code-view source loading through
/api/registry-source/[name]for bandwidth, but do not treat it as a public registry API. - Keep CN docs, MCP docs/dialog, Plate Plus/Pro hooks, GA, Plate home page, and the Slate-to-HTML special page.
- Keep Plate's sidebar accordion/filter UX only as an intentional fork rebuilt on Fumadocs/upstream sidebar primitives.
1. Establish Upstream Clone And Refs
Do this only after the autogoal start gates are satisfied and the active
sync-shadcn plan records the output budget strategy.
Use ../shadcn as the upstream clone. Create it only if missing:
test -d ../shadcn/.git || gh repo clone shadcn-ui/ui ../shadcn
git -C ../shadcn fetch origin main --tags
test -d ../shadcn/apps/v4
Read the tracked baseline:
node -e '
const fs = require("fs");
const status = JSON.parse(fs.readFileSync("docs/sync/shadcn/status.json", "utf8"));
console.log(JSON.stringify(status, null, 2));
'
Resolve refs:
BASE=$(node -e 'console.log(JSON.parse(require("fs").readFileSync("docs/sync/shadcn/status.json", "utf8")).lastSyncedCommit || "")')
TARGET=$(git -C ../shadcn rev-parse origin/main)
git -C ../shadcn log -1 --format='%H%n%ci%n%s' "$TARGET"
If $ARGUMENTS names a base or target ref, prove it exists and use it:
git -C ../shadcn rev-parse <base-or-target-ref>
If BASE is empty, run a bootstrap audit:
- compare the whole
../shadcn/apps/v4source against Plate - write a plan
- ask the user before setting
lastSyncedCommit - do not silently set the baseline
If BASE is present, prove ancestry when possible:
git -C ../shadcn merge-base --is-ancestor "$BASE" "$TARGET"
git -C ../shadcn log --oneline --decorate "$BASE..$TARGET" -- apps/v4
If BASE is not an ancestor of TARGET, stop and explain the ref problem
before planning. Do not produce a misleading change list.
2. Create A Run Artifact Directory
Use a range-keyed directory so the full evidence survives beyond chat context:
RUN_DIR="docs/sync/shadcn/runs/$(date +%Y-%m-%d)-${BASE:0:7}-to-${TARGET:0:7}"
mkdir -p "$RUN_DIR"
Save complete inventories:
git -C ../shadcn diff --name-status --find-renames "$BASE..$TARGET" -- apps/v4 \
> "$RUN_DIR/upstream-name-status.tsv"
git -C ../shadcn diff --numstat "$BASE..$TARGET" -- apps/v4 \
> "$RUN_DIR/upstream-numstat.tsv"
git -C ../shadcn log --oneline --decorate "$BASE..$TARGET" -- apps/v4 \
> "$RUN_DIR/upstream-commits.txt"
For bootstrap audits without a base ref, use target-only in the directory
name and save a full current upstream file list instead:
git -C ../shadcn ls-files apps/v4 > "$RUN_DIR/upstream-files.txt"
Do not stream huge diffs into chat and do not write .patch files. Inspect
focused diffs on demand with capped commands, then summarize only the relevant
hunks in inventory.md or plan.md:
git -C ../shadcn diff --stat "$BASE..$TARGET" -- apps/v4/app apps/v4/components apps/v4/lib
git -C ../shadcn diff "$BASE..$TARGET" -- apps/v4/app/(app)/(root)/page.tsx | sed -n '1,220p'
If the focused diff is still too large, narrow by path/function/search term and record the command plus summary instead of saving the diff body.
3. Classify Upstream Changes
Every upstream changed file must be assigned to one subsystem:
docs-engine: Fumadocs source, page tree, MDX compilation, raw markdownrouting: Next routes, rewrites, metadata, layout groupsshell-nav-sidebar: header, footer, sidebar, mobile nav, command/search UImdx-code: MDX components, code blocks, copy-page, source viewer, RSS/OGregistry-contract: shadcn schema, resolver semantics, namespace behavior, init/base item, local-file installregistry-build: registry scripts, generated source indexes, validationpreview-view: block/component preview routes and iframe/source displayproduct-page: create, charts, colors, blocks gallery, directory, examples pages that are shadcn product surfacestheme-style: global CSS, theme providers, tokens, active theme, customizerdeps-config: package, lock, tsconfig, eslint, Next configtests: upstream app tests and fixturesassets: public assets, manifest, images, fontsother: only with an explanation
For each file, record:
- upstream status: added, modified, deleted, renamed
- upstream path
- subsystem
- nearest Plate owner path, or
none - local search evidence
- default decision
- confidence
Useful local mapping heuristics:
| Upstream path | Plate path to inspect |
|---|---|
apps/v4/app/** |
apps/www/src/app/** |
apps/v4/components/** |
apps/www/src/components/** |
apps/v4/lib/** |
apps/www/src/lib/** |
apps/v4/hooks/** |
apps/www/src/hooks/** |
apps/v4/content/docs/** |
content/docs/** |
apps/v4/registry/** |
apps/www/src/registry/** |
apps/v4/scripts/** |
apps/www/scripts/** |
apps/v4/styles/** |
apps/www/src/app/globals.css, apps/www/src/styles/** |
apps/v4/package.json |
apps/www/package.json |
apps/v4/next.config.mjs |
apps/www/next.config.ts |
Search Plate by component/function names from upstream diffs:
rg -n "<ComponentOrFunctionName>|<route-segment>|<registry-key>" apps/www content/docs docs/sync/shadcn
Also search deleted/discarded vocabulary when upstream or Plate removes a surface:
rg -n "v0|OpenInV0|create|charts|colors|themes|customizer|useProject|liftMode|docsConfig|Contentlayer|/api/registry/\\[name\\]" apps/www content/docs docs
Classify each row with one decision:
adopt-upstream: upstream owns the better generic docs infrastructure and Plate has no durable reason to diverge.smart-merge: apply the upstream architecture or fix, but retain a named Plate product requirement.plate-fork: keep Plate's implementation intentionally; upstream change is useful as context but not directly adopted.exclude-upstream: do not bring this upstream product surface to Plate.delete-plate-residue: upstream direction confirms local fork code should be removed.no-op: upstream changed content or product surface irrelevant to Plate.needs-question: user decision required before planning implementation.
4. Produce The Sync Plan
Write a Markdown plan:
PLAN="docs/sync/shadcn/runs/$(date +%Y-%m-%d)-${BASE:0:7}-to-${TARGET:0:7}/plan.md"
The plan must include these sections:
# Sync Shadcn <base-short>..<target-short>
## Range
- Upstream repo: `shadcn-ui/ui`
- Upstream app: `../shadcn/apps/v4`
- Base: `<sha> <date> <subject>`
- Target: `<sha> <date> <subject>`
- Plate app: `apps/www`
- Status source: `docs/sync/shadcn/status.json`
## Summary
Short factual summary of the changed subsystems and the recommended merge
posture.
## Complete Upstream Inventory
| Status | Upstream file | Subsystem | Plate owner | Decision | Evidence |
| --- | --- | --- | --- | --- | --- |
| M | `apps/v4/...` | `shell-nav-sidebar` | `apps/www/src/...` | `smart-merge` | focused diff summary + rg evidence |
This table must include every row from `upstream-name-status.tsv`.
## Added Files
All upstream added files with decision.
## Modified Files
All upstream modified files with decision.
## Deleted Files
All upstream deleted files with decision.
## Recommended Merge Slices
| Order | Slice | Class | Files | Why | Verification |
| --- | --- | --- | --- | --- | --- |
## Micro Auto-Merges
List qualifying tiny overlapping-component fixes applied during this activation,
or `None`.
| Upstream file | Plate file | Change | Why direct | Verification |
| --- | --- | --- | --- | --- |
## Explicit Exclusions
List upstream changes not to import, especially v0/create/charts/colors/theme
surfaces, with the local Plate policy evidence.
## Plate Forks To Preserve
List intentional forks, including sidebar accordion/filter UX,
`/api/registry-source/[name]`, API MDX, CN docs, MCP, Plus hooks, GA, Plate home,
editor demos, workspace aliases, and package integration tests when touched.
## Visual Evidence
For visual scopes or browser-visible slices, include upstream and Plate
screenshot paths, viewport, route, and the visible deltas that still need work.
Do not rely on source diffs alone for visual parity.
## Smart Merge Details
For every `smart-merge` row, state what comes from upstream and what remains
Plate-owned.
## Questions
Only include real user decisions. Do not ask about settled policy.
## Status Update Rule
State whether this plan can advance `lastSyncedCommit` after implementation. If
not, identify the remaining groups.
If the inventory is very large, the plan still needs every row. Put the full row
table in inventory.md in the same run directory and link it from plan.md.
5. Stop For User Review
Default stop point:
Range: <base-short>..<target-short>
Plan: <path>
| Decision | Count | Notes |
| --- | ---: | --- |
| adopt-upstream | ... | ... |
| smart-merge | ... | ... |
| plate-fork | ... | ... |
| exclude-upstream | ... | ... |
| delete-plate-residue | ... | ... |
| needs-question | ... | ... |
Micro auto-merges:
- <list, or none>
Recommended first slice: <slice>
Question: Review the plan. Should any decision change before implementation?
To implement it, invoke `sync-shadcn` again with the accepted plan path and
slice.
Ask one pointed question when there are needs-question rows. Do not ask about
settled exclusions.
Then stop. Do not delegate implementation to task from the same planning
activation, even if the recommended slice looks obvious.
6. Delegate Accepted Implementation Through task
Only after a later user message accepts a plan/slice, load $task with this prompt:
Implement this shadcn docs sync slice.
Upstream: shadcn-ui/ui `../shadcn/apps/v4`
Range: <base-sha>..<target-sha>
Plan: <docs/sync/shadcn/runs/.../plan.md>
Slice: <one-sentence selected slice>
Class: <adopt-upstream | smart-merge | plate-fork cleanup | delete-plate-residue>
Evidence:
- Upstream commits: <short commit list or artifact path>
- Upstream files: <file rows from the plan>
- Upstream diff evidence: <focused command summaries, file rows, or hunk notes>
- Plate evidence: <local files and solution notes>
- Explicit exclusions: <v0/create/charts/colors/themes/etc. if relevant>
Implementation:
- <specific files or surfaces to inspect first>
- <what should come from upstream>
- <what must stay Plate-owned>
- <what must be deleted instead of carried forward>
Acceptance:
- <focused typecheck/test/source audit>
- `pnpm install` only if package, lock, or agent generated output needs it
- `pnpm lint:fix`
- browser proof only if the slice changes browser-visible docs UI
- for visual slices, screenshot both upstream shadcn and Plate pages at the
same viewport before calling the slice done
- do not run `build:registry`
- update `docs/sync/shadcn/status.json` only if the whole target range is fully
accounted for; otherwise record a partial sync note and keep
`lastSyncedCommit` unchanged
Do not preserve obsolete Plate fork residue if the upstream change removes the
need for it. Hard cut the residue.
Then follow task until the implementation is verified or a real blocker is
proven. This is implementation mode, not the planning run that wrote the plan.
7. Status Updates
docs/sync/shadcn/status.json has three meanings:
lastSyncedCommit: every upstream change through this commit has been adopted, smart-merged, intentionally forked, or explicitly excluded.lastPlannedCommit: latest target commit with a written sync plan.partialSyncs: accepted slices that landed before the whole range was fully accounted for.
Plan generation may update lastPlannedCommit and lastPlan.
Only update lastSyncedCommit when:
- the plan covers every row in the upstream range
- all selected implementation slices for that range are complete
- all excluded/forked rows are recorded in the plan
- verification for touched surfaces passed
- the user accepted the final accounting
When advancing the baseline, include:
{
"lastSyncedCommit": "<target-sha>",
"lastSyncedAt": "YYYY-MM-DD",
"lastSyncPlan": "docs/sync/shadcn/runs/.../plan.md",
"lastVerification": ["<commands or proof>"]
}
Do not delete older run artifacts. They are the audit trail.
Output
For planning-only runs, end with:
Range: <base-short>..<target-short>
Plan: <path>
| Decision | Count | Notes |
| --- | ---: | --- |
| adopt-upstream | ... | ... |
| smart-merge | ... | ... |
| plate-fork | ... | ... |
| exclude-upstream | ... | ... |
| delete-plate-residue | ... | ... |
| needs-question | ... | ... |
Micro auto-merges:
- <list, or none>
Recommended first slice: <slice>
Question: Review the plan. Should any decision change before implementation?
To implement it, invoke `sync-shadcn` again with the accepted plan path and
slice.
For implementation runs, use task's final handoff format and include whether
docs/sync/shadcn/status.json was advanced or left unchanged.