Shade ShadCN install
DevelopmentShade ShadCN install is an Agent Skill for development published in the TryGhost/Ghost repository on GitHub: a SKILL.md instruction file an AI agent can load to do this task.
Guardrails for running `pnpm dlx shadcn@latest add` in Shade — never overwrite existing components, fresh branch first, swap raw colours for semantic tokens after integrating. Trigger when the user proposes a shadcn add, or when a fresh ShadCN-shaped file lands in apps/shade/src/components/ui.
How to use this skill
Bring this guide into your coding agent with a prompt tailored to the tool you use.
- Open your project in Codex.
- Copy and paste the prompt below.
- Review files and risks before approving any action.
Inspect the Agent Skill at https://github.com/TryGhost/Ghost/blob/HEAD/.agents/skills/shade-shadcn-install/SKILL.md and all supporting files. Report provenance, permissions, scripts, dependencies, and security risks. Propose an exact installation into .agents/skills/shade-shadcn-install, but wait for my approval before writing files or running scripts.
Copying this prompt does not install or run the skill. Review third-party files before use.
Shade — ShadCN install guardrails
Most new Shade components start from a ShadCN install. The CLI is destructive by default — follow these guardrails.
Command
pnpm dlx shadcn@latest add <component-name>
(Use pnpm, not npx / yarn / bunx. Ghost is pnpm.)
Before running
- Be on a fresh branch. The CLI's diff is mixed in with your branch's changes otherwise.
- Check if the component already exists in
apps/shade/src/components/ui/. If it does, do not run the CLI against the repo — generate into a scratch repo and manually port the parts you want. The CLI will offer to overwrite, and you'd lose Shade customisations.
During the prompts
- If asked to overwrite an existing file: choose No. Always.
- If asked about path aliases: keep
@/.
After the file lands — required cleanup
Raw ShadCN output is not Shade-quality yet. Do all of these:
- Swap raw colours for semantic tokens. ShadCN ships things like
bg-white,border-gray-200,text-zinc-500. Replace withbg-surface-elevated,border-border-default,text-muted-foreground, etc. See theshade-tokens-not-hexskill for the inventory. - Remove any
dark:colour variants. Semantic tokens flip automatically. Seeshade-no-dark-variants. - Use the
@/alias for internal imports (@/lib/utils,@/components/ui/...) — not relative paths. - Ensure all four required states work: default, hover, focus-visible, disabled. (
focus-visible:only — neverfocus:.) - Trim props that hint at a specific surface. If a prop name reads like product workflow (
isMembersPage,layoutMode), it doesn't belong on a generic Component — extract a Pattern instead. - For form controls, drive border/background/focus through the
inputSurfacerecipe instead of duplicating the chrome. Seeshade-input-surface-recipe. - Add a sibling
<name>.stories.tsxif one isn't already there. Copy useful examples fromhttps://ui.shadcn.com/docs/components/<name>into stories. Seeshade-new-component. - forwardRef + className merge via
cn()— both are required.
What ShadCN gets wrong that Shade fixes
| ShadCN default | Shade convention |
|---|---|
bg-background dark:bg-background | bg-background (token already flips) |
bg-white text-zinc-950 dark:bg-zinc-950 dark:text-zinc-50 | bg-surface-elevated text-foreground |
border border-input | border border-control-border (form controls) or border-border-default (other chrome) |
Direct focus-visible:ring-2 focus-visible:ring-ring chrome on every input | inputSurface('self') recipe |
Relative imports import {cn} from "../../lib/utils" | @/ alias: import {cn} from '@/lib/utils' |
When NOT to use the CLI
- The component already exists in Shade — port from a scratch repo instead.
- You're building a Pattern (something Ghost-shaped like
KpiCard,PageHeader). ShadCN doesn't ship Patterns — write it from primitives + components. - It's a Recipe (pure class-string function). ShadCN doesn't ship Recipes.
Source of truth
apps/shade/AGENTS.md, Storybook → Overview / Contributing.