Skip to content
Agentmart
Submit a tool

ds-rules

Rules for building components in a shadcn-based design system with a Figma or Paper kit.

Skill by renzobianchi

IndexedMIT★ 2
Write a review

Chalk Labs

Need help deploying ds-rules?

Chalk Labs sets up agents like this inside real teams: connected to your tools, tested on your data, with a human in the loop where it matters.

Book a call

Install

Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.

npx agentmarket install skill/renzobianchi-ds-rules

Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.

Get the weekly diff

The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.

We use your email only for this newsletter. Privacy

About

Rules for building components in a shadcn-based design system with a Figma or Paper kit. Fires when editing a file under the namespace in ds.config.json, adding stories, editing a parity or legacy manifest, writing a Code Connect mapping, or answering PR review on that repo. Triggers: shadcn, parity, manifest, kit-first, data-slot, ds.config.json.

Use cases: design, data, writing, research

No reviews yet. Installed it? Reviews come from verified installers only. How reviews work

Permissions

What this skill can do and what it asks for, from its SKILL.md and code. Checked Nov 2, 2026.

Tools
No tools found
Secrets
None asked for
Install scripts
None found

Network hosts it talks to 1

  • codeload.github.com · found in install command

Files it touches

  • ~/.claude/skills/ds-rules

What's inside

Skill name
ds-rules
Description
Rules for building components in a shadcn-based design system with a Figma or Paper kit. Fires when editing a file under the namespace in ds.config.json, adding stories, editing a parity or legacy manifest, writing a Code Connect mapping, or answering PR review on that repo. Triggers: shadcn, parity, manifest, kit-first, data-slot, ds.config.json.
License
MIT
Instructions
144 lines in SKILL.md · view on GitHub

Files (1)

  • SKILL.md

SKILL.md (first lines)

<!-- Generated by scripts/sync-adapters.mjs from core/rules.md and core/traps.md. Edit those, then rerun. -->

Read `ds.config.json` at the repo root first; every branch below depends on it. If the repo has its own `skills/<system>/SKILL.md` (written in the foundations phase), its project rules add to these and never replace them. Apply everything below in full.

# Component rules

Rules for every component in the new namespace. Each carries the failure it prevents, so an uncovered case is decided by extending the reasoning. Project specifics (paths, primitive library, reviewers, tool flags) come from `ds.config.json`; read it first.

## Route by path

- File under `namespace` (default `src/next/`): these rules. Legacy conventions (CSS-in-JS macros, Radix, old token names) do not exist here.
- File under `legacyPath`: bug-fix only. Legacy is frozen from the moment the component rollout starts.

## Hard rules

1. **Build visuals with the live kit open, every time.** A written spec carries parts and decisions; shape is read only from the canvas. A component built from the spec alone with the design bridge disconnected came out structurally wrong (a bordered box where the kit was a muted tray holding an inset card) with every listed part present. If the bridge is down (`designTool: figma` → MCP status probe; `designTool: paper` → the Paper project open), stop and ask; the rewrite costs more than the wait.

2. **One kit variant axis = one union prop.** Mutually exclusive variants (`Type = Simple | CLI | Editor`) become `type: 'simple' | 'cli' | 'editor'`. Two booleans make a combination the design does not have representable, and a caller will ship it.

3. **Kit "Show X" boolean layers become composition.** A canvas cannot omit a layer; code omits the child. Incorrect: `<Block showHeader={false} />`. Correct: `<Block><Body /></Block>`.

4. **Raw Tailwind with `cn()`, theme tokens only.** Every color, radius and spacing resolves to a `theme.css` token: the kit binds `base/card`, code writes `bg-card`, and the shared name is what keeps dark mode and theming free. Hex lives in `theme.css` and nowhere else; a `var(--x, #fallback)` is a token that can silently stop being one, so tokens are written without fallbacks.

5. **Resolve every token in both modes before accepting it.** `background`/`card`, `accent`/`muted`, `secondary`/`muted` are equal in light and different in dark; the wrong pick is invisible until dark. A surface that reads as a card is `bg-card`.

6. **New Tailwind class ⇒ recompile the namespace CSS.** If the stylesheet compiles once at Storybook start, a class written afterward does not exist and the element renders unstyled, masquerading as a component bug. Verify: `grep -c '<class>' <generated css>`; zero means absent.

7. **State selectors belong to the primitive library in `ds.config.json`.** Under Base UI, Radix's `data-[state=open]` matches nothing; use `data-open`, `data-closed`, `data-pressed`, `data-starting-style`, `data-ending-style`. Before declaring a selector dead, check who renders the attribute: a consumer-spread `data-invalid={true}` is alive. Grep per component before the PR: `grep -rn "data-\[state=\|data-\[motion" <namespace>` returns zero.

8. **Requalify utilities the base layer guards.** With `[data-slot] { font-family: sans }` in `theme.css`, plain `font-mono` loses by source order. Incorrect: `<div data-slot="x" className="font-mono">`. Correct: `data-[slot=x]:font-mono`, on every slotted mono element.

9. **`React.forwardRef` on every part a consumer could compose or pass a ref to** while the library ships to React 18. The ref drops silently: the component renders, the downstream behavior (tooltip opening, popup anchoring) disappears. The test is not "does it use the primitive library inside" but "could a consumer wrap it in a trigger". Tag every shim "remove on the React 19 upgrade".

10. **Motion: `motion-safe:` on the animation itself**, transform and opacity only, `ease-out` for user-initiated enters, paired elements share duration and easing. `motion-reduce:animate-none` loses by source order to a `data-*` variant animation. Measure the cycle (close, reopen), never the resting state.

11. **Icon-only controls get `aria-label` before the props spread.** Upstream registries do not name icon buttons; the accessibility gate fails per story. Scroll containers get `tabIndex={0}`, `role="region"`, a label. Repeated landmarks get distinct labels. A Select's visible value is not its name.

12. **Truncation in fixed-height rows:** `truncate` on the cell as the safety net plus `<span className="truncate">` around the value. `truncate` on a flex container does not ellipsize bare text, and the anonymous item never yields width. If a story needs a hand-added class to look right, the component is missing it.

13. **Header actions:** constant meaning → icon-only with tooltip (copy, download); meaning that inverts with state → visible label (`Show all` ↔ `Show less`), because touch has no hover. A leading glyph flips with the label or contradicts it.

14. **Page shell is a grid row, never a viewport subtraction.** Incorrect: `h-[calc(100vh-81px)]`. Correct: `grid h-dvh grid-rows-[auto_1fr]` with `<main className="overflow-y-auto">`.

15. **Code-highlighting themes are chosen by measured contrast against your backgrounds**, scoped to the component (`[data-slot=code-block-pre]`, `data-language`), never by taste and never with a global `language-*` class a legacy stylesheet also matches.

16. **Manifest edits go to the component's own file** (`manifests.parity/<key>.json`), by targeted string replacement. Generated docs (`PARITY.md`, `LEGACY-MAP.md`, `MIGRATION.md`) are regenerated with `node scripts/ds-manifest.mjs docs`; a hand edit is overwritten by the next run and fails `check` until then.

17. **Read the usage doc before composing with a namespace component; write it before declaring parity.** `manifests.usage/<key>.md` is the caller's contract (when, which variant, what to compose, the owner's warnings); the manifest is the builder's. A screen built from prop names alone picks the variant that compiles, not the one the product means. When the usage doc and the code disagree, fix the doc in the same PR; a stale contract is the one agents follow with confidence.

18. **Docs ship inside the package, where the consumer's agent reads them.** Usage docs, `MIGRATION.md` and the manifests go to `manifests.ship`, indexed by `llms.txt` at the package root; `package.json` `files` covers both and a script runs `ds-manifest.mjs ship` on `prepack`. The consumer is migrated by agents in its own repo, so a package that ships `dist/` alone hands them compiled JS and a recipe nobody wrote down. `check` fails on a missing `files` entry or a missing script; `npm pack --dry-run` is the proof.

19. **`parity` is a verified mirror, stamped against a kit version.** Every kit axis value has its code value or an axis `note` saying why not; every other deliberate difference is in `asymmetries` with its reason; `verified` carries the level, the date and the kit version id, written by `ds-manifest.mjs verify` after the audit. `audit code` proves the code half; `check --kit-version` shows which entries the kit has since moved past. A manifest that says `parity` on the strength of the build day is how forty components ship and a QA pass afterwards finds two kinds of drift at once.

## Build procedure (kit-first)

1. Read `manifests.parity/<key>.json` (the `note` carries the decisions) and the tracker issue if `tracker != none`.
2. Audit the live set. Figma: analyze the component set, walk the tree resolving tokens (fills, strokes, radii, padding, text styles), and read `textTruncation` and `maxLines` on every TEXT node by name (the tree walk omits them). Paper: open the component, read every property and the applied tokens, export one image per variant. Record measurements in the PR description draft; do not eyeball.
3. Core component: `npx shadcn add <name>` then adapt, keeping the file diffable. Composite: compose from namespace parts. Zero raw `<button>`/`<select>`.
4. Verify computed styles in the running Storybook, light and dark: fonts, colors, row heights, scroll behavior, every state via its story (never a scripted `click()`).
5. Update the component's manifest file to `parity` only after step 4 matches per axis; write the usage doc (`phases/component.md`, step 5); run the generator; run the guards.

**Done when:** every recorded measurement matches in both modes in the browser.

## Confidence gate

Score each decision. High confidence: decide silently, record in the manifest `note`. Low confidence: bring the design owner a tradeoff in design language ("the primitive's Menu gives keyboard navigation free but has no nested submenus; a custom part covers them and puts a11y on us. Which?"), never a technical question ("should I use the primitive's Menu?"). Bringing every decision equals bringing none.

## Budgets

- Visual match: 5 iterations max. An iteration that moves no recorded measurement ends the loop; report the delta.
- Same failure twice: stop. The model of the problem is wrong.
- a11y P1: 3 attempts, then leave it red and say so. A finding downgraded to green a check is worse than a red check.
- A fix that breaks a passing measurement is reverted, never layered on.

## Pre-flight (before "ready for review")

- [ ] Kit audit against the live set; computed styles verified, light and dark
- [ ] CSS recompiled after the last new class; greps > 0
- [ ] Type check and lint clean on touched files
- [ ] a11y gate items (rule 11); inputs in stories carry `aria-label` in meta `args` (a placeholder is not a label)
- [ ] Stories demonstrate behavior for real (an overflow story overflows; every state has a story)
- [ ] Dead-selector grep zero; console free of ref warnings across stories
- [ ] `codeConnect: true` → `<key>.figma.tsx` written and `npx figma connect parse --dir <namespace>` passes
- [ ] Manifest file updated; axes mirrored or noted, `asymmetries` complete; `verify` stamped and `audit code` ok; usage doc filled, Owner notes answered; legacy `recipe`s written; generator run; guards green
- [ ] Every commit passes commitlint locally; subject starts with `commitSubjectPrefix`
- [ ] Self-review pass on the diff (see `phases/component.md`, step 7)
- [ ] Design-owner preview in Storybook, handed off with the hand-off list

## Hand-off list (what no gate reaches)

Deliver with the preview, every time: screen-reader announcement; hover with a real pointer; whether motion feels right; 2x pixel check on custom indicators; detached frames in the kit (customization or drift?); anything the kit visuals do not disambiguate (single vs multi select).

## Closing: classify every finding

- Tier 1, the agent needed a rule: into this file if it generalizes, into the manifest `note` if not.
- Tier 2, a tooling gap: into the tracker as an issue. This is the tier teams lose.
- Tier 3, resists automation: onto the hand-off list, never into a rule.

# Trap catalog

Each fails silently and masquerades as a component bug or a design decision. Check the method before blaming the component.

| Trap | Symptom | Rule |
|---|---|---|
| Namespace CSS compiled once, not watched | new class renders unstyled | recompile after every new class; grep the generated file |
| Bare `git stash` in a shared worktree | someone else's stash pops onto your tree | `git stash push -u -m <tag>`, apply by SHA, or a WIP commit |
| Tokens equal in light, different in dark | surface vanishes only in dark | resolve both modes; nothing automated renders dark unless you make it |
| Cached kit screenshots of new nodes | render contradicts data | screenshot the parent frame; vary the scale; data wins until a third method decides |
| Synthesizing a state with a scripted click | measurements from a transient DOM | use the story that has the state; if none, add it and say so |
| Tree walk omits text truncation | free-wrapping text documented as intentional | read `textTruncation` and `maxLines` per TEXT node |
| Radix selectors under Base UI | animation or state style never applies | selector table; grep per component; confirm attributes in the DOM |
| `motion-reduce` vs `data-*` animation | animation runs under reduced motion | `motion-safe:` on the animation; measure the cycle |
| `[data-slot]` font guard | `font-mono` renders sans | requalify: `data-[slot=x]:font-mono` |
| React 18 ref drop | popups anchored wrong or never open | `forwardRef` on every composable part; console probe; reason about call sites |
| Unlayered legacy preflight | buttons transparent | compile utilities unlayered |
| Placeholder passes the axe label rule | inputs unnamed in the app | `aria-label` in story args; Field in app usage |
| Upstream icon buttons unnamed | `button-name` violations | default `aria-label` before the props spread; record the deviation |
| Hand-copied counts in docs | doc says 20 of 20, manifests say 23 | generate docs; guard equality |
| Shared manifest file across PRs | every merge conflicts the other approved PRs | one manifest file per component; no shared edits |

From renzobianchi/skills, MIT.

More from renzobianchi/skills

Signals

Stars
2
Forks
2
Open issues
0
Last commit (this folder)
Sep 10, 2026 (1 month ago)

From GitHub (fetched Oct 24, 2026).

Details

License
MIT
First seen
Oct 24, 2026
Last checked
Oct 24, 2026

More from renzobianchi

Done for you

Rather not set it up yourself?

Chalk Labs scopes, builds and runs agents for your team: the task audit, the eval harness, the integrations and the weekly ops report. Fixed scope, priced before we start.

See how we build AI agents →Read the case studies

Chalk Labs is a two-founder AI and growth studio. We build AI agents, CRMs and MVPs for Web3 and AI companies, and have shipped 50+ product and token launches.

launches shipped
50+
launches shipped
media placements
500+
media placements
founders on every account
2
founders on every account

Press we've placed: Forbes · CoinDesk · Decrypt · Cointelegraph · The Block

Rahil Jain, Co-founder, Chalk Labs. Ex-Goldman Sachs engineer. You talk to the person who builds it.

Get ds-rules running in your business

Tell us what you want to automate. A founder replies within one working day with a plan, not a pitch deck.

Goes to the Chalk Labs founders, not the newsletter. Privacy

Need help deploying ds-rules?

CallGet help
Cite this page

ds-rules skill. Agent Mart. https://agentmart.dev/skills/renzobianchi-ds-rules (last updated 2026-10-24)