Skip to content
Component installs need the registry setup— the Base UI shadcn project, the @vegastack namespace and the Cloudflare Access service token.
VegaStack Design

Working with components

The copy-in ownership model end to end — add, verify, customize, and pull updates tracked by content.

Last updated

VegaStack components are copy-in: shadcn add writes real source files into your repo and you own them. Nothing updates behind your back; updates are pulled when you decide. This page is the full lifecycle.

The five item kinds

KindExampleBehavior
Component (registry:ui)@vegastack/buttoncopied to components/ui/, update-tracked by content
Hook (registry:hook)@vegastack/use-media-query, @vegastack/use-mobile, @vegastack/use-list-nav, @vegastack/use-platform, @vegastack/use-drag-reorder, @vegastack/use-file-drop, @vegastack/use-animation-replay, @vegastack/use-modal-inertplain .ts into components/ui/, same tracking
Icon item@vegastack/icon-arrow-rightone animated-icon mirror per item — 467 of them; bare names never collide with components
Block (registry:block)@vegastack/dashboard-01a multi-file starter composition (page + components + data) you own outright — deliberately NOT update-tracked
Lib (registry:lib)@vegastack/geo-data, @vegastack/drag-itemplain .ts into your lib/ alias — data and class-string recipes with no React in them, pulled in automatically as a dependency of the components that read them, and installed once however many of those you add

Adding

pnpm dlx shadcn@latest add @vegastack/dialog
  • Always the @vegastack/ prefix. A bare shadcn add dialog installs shadcn's own Radix-based dialog — a different component tree that will not match this system (and overwrites files if names collide).
  • registryDependencies come transitively: adding @vegastack/field also brings input; data-list brings table+checkbox+skeleton+empty; provider brings toast; the modal families bring the internal use-modal-inert focus-containment hook. You never chase dependencies manually or call that modal lifecycle hook yourself.
  • npm dependencies of each item (@base-ui/react, class-variance-authority, …) are installed by the CLI into your project automatically.

Every registry item carries a provenance header in its source:

// @vegastack dialog@0.1.0 sha256-Qm3…=

Heads-up: the current shadcn CLI strips leading comments during copy-in, so the header usually won't appear in your copied file — that's fine. Update tracking does not depend on it: check-updates identifies your copies by filename against the registry index and compares alias-normalized content. If a header is present (older CLIs, or files synced by other tooling), it's used as a fast-path version pin — keep it in that case.

The registry signs its item manifest (Sigstore, GitHub OIDC identity) and every item carries a whole-item SHA-256. The vegastack-design CLI (a bin inside @vegastack/design — already installed) closes the fetch-time/copy-time gap:

# 1. verify the item BEFORE copy-in, save the verified bytes
VEGASTACK_VERIFY_DIR="$(mktemp -d "${TMPDIR:-/tmp}/vegastack-verify.XXXXXX")"
VEGASTACK_ITEM="$VEGASTACK_VERIFY_DIR/dialog.json"
pnpm exec vegastack-design verify --save "$VEGASTACK_ITEM" dialog
VEGASTACK_EXPECTED_INTEGRITY="$(node -e \
  'process.stdout.write(JSON.parse(require("node:fs").readFileSync(process.argv[1], "utf8")).meta.integrity)' \
  "$VEGASTACK_ITEM")"

# 2. copy in
pnpm dlx shadcn@latest add @vegastack/dialog

# 3. prove the files on disk match the verified bytes (alias-rewrite aware)
pnpm exec vegastack-design verify --post-write --item "$VEGASTACK_ITEM" \
  --expected-integrity "$VEGASTACK_EXPECTED_INTEGRITY" --target-dir .

The save path must not already exist. The private directory prevents pre-creation or symlink redirection; retaining the digest before copy-in also detects replacement of the saved item.

--hash-only skips the Sigstore signature check for local development when cosign isn't installed; full mode verifies the signed manifest identity too.

Customizing

Edit the copied files freely — that's the point of the model. Two practices keep future updates painless:

  • Additive edits over rewrites. Add variants/classes/props; avoid reshuffling the file wholesale, so --diff output stays reviewable.
  • Compose in new files where possible — wrap Button in your own SubmitButton rather than forking button.tsx for one use case.

Customized files show as ≈ differs from registry — the content comparison can't tell your edits from an upstream change; add --diff is what disambiguates. CI note: --fail-on-update treats that status as failure too, so in-place customizations keep the drift gate red. If you customize, prefer wrapper files — or scope the gate: check-updates --fail-on-update --filter <uncustomized,...>.

Updating — pulled, never pushed

The authenticated internal runbook documents how registry pulls relate to npm bumps, including the two-speed propagation model and token-ordering trap for VegaStack-owned applications.

pnpm exec vegastack-design check-updates
  ⬆  button   0.1.0 → 0.2.0   update available
  ≈  card     → 0.2.0         differs from registry (update or local edits — review with --diff)
  ✓  field    0.2.0           up to date
  ?  legacy   0.1.0           not in registry (renamed/removed)

Status is by content, not version numbers: headered files compare their integrity hash; headerless files (the normal real-CLI case) compare alias-normalized bytes against the live item. Either way a component reads up to date when the registry's global version bumped but that component's content didn't change — you only re-pull what actually moved. The ≈ differs status means the bytes diverged — an upstream update or your local edits; add --diff shows which.

Per component, review then take:

pnpm dlx shadcn@latest add @vegastack/button --diff       # see exactly what changed
pnpm dlx shadcn@latest add @vegastack/button --overwrite  # take it

--overwrite replaces the file — if you customized it, git diff afterwards and re-apply your edits (they're in your git history; nothing is lost).

Useful flags: --dir (scan a non-default location), --filter <name>, --json (machine-readable — the right entry point for agents), --fail-on-update (exit non-zero when anything is stale — the CI drift gate), --registry / --cwd. Credentialed requests are pinned to VEGASTACK_TRUSTED_REGISTRY_ORIGIN (production by default) and reject redirects; checkout-local dotenv files cannot redefine that trust anchor.

For agents: the reliable loop is vegastack-design check-updates --json → for each item with status update or drift, shadcn add @vegastack/<name> --diff → present the diff → only after approval --overwrite. Never hand-edit a provenance header, and never "update" by pasting source from elsewhere — pull through the CLI so content and registry stay comparable.

Blocks are different — by design

dashboard-01 copies once and is then yours; check-updates will not track its page/data files. Rationale: a starter composition you've built a real page on top of must never be at risk of an upstream overwrite. Its underlying components (Card, Chart, Sidebar, …) remain individually tracked like any other.

On this page