baoyu-design solves a specific problem: the claude.ai/design web app exposes tool names like questions_v2, fork_verifier_agent, and eval_js_user_view that don't exist in Claude Code. Without a substitution layer, the same skill prompt stalls or silently skips preview and verification. The fix is references/claude.md — a per-environment tool map the skill reads once at session start before touching any design work. The tradeoff is that three other gaps follow immediately: browser preview requires an HTTP server (not file://), React 18 breaks the MCP's click events in a specific way the README doesn't mention, and the design system pipeline adds two explicit compile/import steps before the token enforcement is active. Understanding all three is what decides whether to install this or just paste the repo URL to the agent for a one-off.
Late-Binding Tool Resolution: How One SKILL.md Works Across Three Agent Environments
The architecture here is late-binding dependency injection for skill tooling. SKILL.md contains the entry logic; system-prompt.md holds the fixed design methodology. What varies per environment — which tool to call when the methodology says 'ask the user a question,' 'preview this page,' 'take a screenshot,' 'run JS in-page' — is resolved at session start by reading a per-environment file from references/.
For Claude Code, that file is references/claude.md. It is a substitution table:
| Web tool (claude.ai) | Claude Code equivalent |
|---|---|
| questions_v2 | AskUserQuestion |
| fork_verifier_agent | SendUserFile + Claude Preview MCP + Agent subagent |
| show_to_user | SendUserFile + preview_screenshot + localhost URL |
| eval_js_user_view | Bash / preview_eval |
| copy_starter_component | Bash cp starter-components/<file> designs/<project>/ |
Cursor has references/cursor.md. Codex has references/codex.md. Unknown environments (Claude Desktop, generic agents) get the generic workflow in system-prompt.md with no MCP, no AskUserQuestion, no in-page JS evaluation — the agent starts the HTTP server manually and gives the user a localhost URL.
This pattern is the reusable architectural insight. Any skill author who needs to run one skill across multiple agent environments with different tool APIs can adopt the same structure: single SKILL.md entry point, per-environment tool maps in references/, loaded once at runtime. The skill stays unified; the execution layer is swappable.
Verification: after installing, ask for a design task and check that the agent cites references/claude.md in its reasoning. If it doesn't, it took the generic fallback path — mcp__Claude_Preview__preview_start will not be called, and the full preview and verification loop won't run.
HTTP-Only Previews and Why React 18 Breaks the MCP's Click Events
Every deliverable must be served over HTTP before preview or verification — this is a hard requirement, not hygiene. Multi-file prototypes load JSX components via <script type="text/babel" src="…jsx">. When opened from file://, the browser's CORS rules block those cross-origin local script reads; the components silently fail to load and the prototype renders empty or broken with no console error visible to the agent.
The agent configures a designs server in .claude/launch.json running python3 -m http.server 4311 --directory designs, starts it with mcp__Claude_Preview__preview_start {name: "designs"}, then reads mcp__Claude_Preview__preview_console_logs for JS errors and calls mcp__Claude_Preview__preview_screenshot to confirm layout.
Here is the non-obvious MCP-level problem: preview_click does not reach React 18 onClick handlers. This is not a bug in the prototype — it is a version-specific behavior of how React 18 changed event delegation. React 16 delegated synthetic events to document. React 18's createRoot delegates to the root container element instead. The Claude Preview MCP fires a synthetic click at the document level, below React's delegation mount point, so onClick never fires. references/claude.md documents the workaround:
const el = document.querySelector('#target');
const propKey = Object.keys(el).find(k => k.startsWith('__reactProps$'));
el[propKey].onClick({ stopPropagation(){}, preventDefault(){} });
This reads the React fiber's internal property key — __reactProps$ — which is not a public API. It works for the React@18.3.1 version pinned in ds-prompt.mjs, but any design system that bundles a different React version may expose a different internal key format. An agent that hasn't read references/claude.md will misdiagnose both the click failure and the second documented MCP issue — screenshot surface desync after location.reload() — as bugs in its own prototype and attempt to fix the components rather than using preview_resize to resync the MCP surface or substituting location.href = … for reload().
The Design System Pipeline: Two Phases, Two Enforcement Layers
The design system workflow is two explicit Node.js phases. Running them out of order or skipping either leaves the enforcement incomplete.
**Phase 1 — Compile.** node <skill>/agents/compile-design-system.mjs designs/<ds-name> reads every .jsx/.tsx with a sibling .d.ts, transpiles via vendored @babel/standalone (stripping ESM imports, rewriting relative sibling imports to pull from __ds_scope), and emits three files:
- _ds_bundle.js — an IIFE registering each component as window.<Namespace>.<Component>. The namespace is deterministic: PascalCase(projectName)_sha256(projectName).slice(0,6). On recompile, the existing namespace is read from _ds_manifest.json and reused — it never changes once established, which prevents window.* collisions when two design systems load on the same page.
- _ds_manifest.json — namespace, components, tokens, cards, starting points, fonts.
- _adherence.oxlintrc.json — an oxlint config built from .d.ts interfaces. Project-wide rules block raw hex literals (Literal[value=/#[0-9a-fA-F]{3,8}\b/]) and raw px literals. Per-component rules whitelist JSX props and their union-type string values, derived by parsing the first exported interface in each .d.ts file.
One hidden dependency: compile-design-system.mjs requires agents/vendor/babel.min.js. If it's absent (manual git clone, not npx skills), the compiler prints a hard exit with a curl command — curl -L https://unpkg.com/@babel/standalone@7.29.0/babel.min.js -o agents/vendor/babel.min.js — rather than a dependency-resolution error. This is the one setup step the skill's documentation buries.
**Phase 2 — Import.** node <skill>/agents/import-design-system.mjs <dsDir> <projectDir> [--primary] copies the CSS @import closure plus font/image assets into _ds/<slug>/, records the binding in _d_meta.json, and generates _ds/<slug>/_ds_prompt.md.
This is where the two layers diverge. _adherence.oxlintrc.json enforces the token constraint at the source level via static lint — it runs when the developer or CI runs oxlint. _ds_prompt.md enforces the same constraint at the agent-context level: it contains the complete sorted var(--*) token allowlist, the wiring block (pinned React@18.3.1 UMD tags with SRI hashes, <link> and <script> tags), per-component usage excerpts from each *.prompt.md, and a scope disclaimer preventing the agent from treating design system brand copy as facts about the project. When the agent reads _ds_prompt.md at session start, it has real token names rather than guessing.
Neither layer replaces the other. If oxlint isn't in CI, only the prompt is active. If the model ignores the prompt — the most likely failure mode on cheaper models — only the lint config catches raw values after the fact.
Three Failure Modes That Surface Before Verification Runs — and Who Should Skip This
**Babel vendor missing.** compile-design-system.mjs exits immediately if agents/vendor/babel.min.js is absent. The npx skills installer handles this; a manual git clone does not. The error output looks like a broken setup rather than a missing dependency: a stderr message and a curl command. Any team that clones the repo directly for use in a custom agent runner will hit this before any design work starts.
**Token drift — the silent failure.** _ds_prompt.md warns: 'Never guess a token name — an unresolved var() silently falls back to the browser default.' There is no console error, no visible crash. The design renders with browser-default values wherever a token is wrong. fork-verifier-agent.md catches this: it evaluates all defined --* custom properties from loaded stylesheets and diffs them against var(--*) references in the source, reporting any unresolved name. The timing problem: the main agent can mark the task complete before explicitly spawning the verifier as an Agent subagent. For design systems with more than a handful of tokens, run check-design-system.mjs after every compile and treat the verifier as a required step rather than an optional gate.
**Generated artifact mutation.** create-design-system.md is explicit: _ds_bundle.js, _ds_manifest.json, and _adherence.oxlintrc.json are generated artifacts — never hand-edit them. There is no background compiler; edits require explicitly re-running compile-design-system.mjs. An agent that edits the bundle to fix a rendering issue creates a stale namespace: ds-core.mjs reads the project README for window.<Name>_<hex6> references and flags any that don't match the current compiled namespace. The error surfaces on the *next* compile run, not immediately — making the root cause non-obvious.
**Skip this if:** you're building one-off wireframes or throwaway mockups — give Claude Code the repo URL and ask it to follow skills/baoyu-design/SKILL.md for a single session, or use claude.ai/design directly. Skip it if your team's design source of truth is Figma (the design system must be authored in CSS/JSX to feed the pipeline), if you need output formats other than self-contained HTML, or if Opus 4.8 is not available. The context budget — system-prompt.md + references/claude.md + relevant built-in skills + _ds_prompt.md for a bound system — is substantial, and weaker models skip the clarifying questions and design context gathering steps that define what this skill actually does.
baoyu-design is worth installing when you're committing to repo-tracked HTML mockups that need session-to-session design system consistency. Thereferences/claude.mdtool substitution layer and the two-layer token enforcement (_adherence.oxlintrc.jsonfor static lint,_ds_prompt.mdfor agent context) are both patterns worth studying regardless of whether you use the design output. For one-off work, the pipeline overhead is real — runnpx skills add JimLiu/baoyu-design --agent claude-codewhen you're ready to invest in the full compile/import flow, not before.
Practical takeaway
Run npx skills add JimLiu/baoyu-design --agent claude-code, ask for a design task, and verify the agent cited references/claude.md — if it didn't, it took the generic environment fallback and mcp__Claude_Preview__preview_start will not be called, leaving React onClick interactions silently broken during any verification step.