Update & diff
Updating is a reinstall: the update manifest refreshes every installed source and never touches the three skin-owned files.
Diff, then overwrite
# Preview upstream changes against your installed sourcesnpx shadcn@latest add https://control-ui.dev/r/update.json --diff# Refresh every installed source; skin files stay untouchednpx shadcn@latest add https://control-ui.dev/r/update.json --overwriteThe diff comes first, and the overwrite wants a clean tree: it rewrites source you own. Keep both as package
scripts against that same update manifest — control-ui:diff with --diff, control-ui:update with
--overwrite, chained onto node <install dir>/scripts/fix-css-imports.mjs — so no session has to remember the URL.
A diff listing per-file what the overwrite would change, and nothing outside the installed component directory —
skin.config.tsx, skin-theme.css, and skin.css never appear in it.
After the overwrite
../components/… prefix, so scripts/fix-css-imports.mjs runs chained onto it — a no-op in the canonical layout, the repair everywhere else.scripts/control-ui-doctor.mjs: the same read-only audit as after the first install. Verify before styling on top of it..claude/skills/control-ui/SKILL.md, the agent skill installed with the set — so hand-edits there do not survive.update pulls the whole set.npx shadcn@latest add …/r/skin-<id>.json --overwrite.all-<skin> with --overwrite also updates everything, but resets the three skin files to that pack.The contract
Updating is a reinstall. The update manifest refreshes every installed source and never touches the three
skin-owned files — a fully custom skin included.
That is the whole ownership rule made operational: installed source is owned but never edited, customization lives in the skin, and the update is safe precisely because those two never overlap.
A version of the skin contract can cross under you. Contract versions carries what each crossing costs.