# @shadcn/lint: Design System Rules That Give Coding Agents Actionable Fix Guidance

> @shadcn/lint is an ESLint and Oxlint plugin for Tailwind v4 projects that lets teams encode design system constraints as lint rules. When a coding agent breaks a rule, the error message tells it what to use instead, drawing from the project's own components, variants, and theme.

**shadcn-ui/lint** — An agent-first linter for Tailwind design systems. Write design system rules that agents can verify.

- Repository: https://github.com/shadcn-ui/lint
- Stars: 2,942 · Forks: 55
- Language: TypeScript
- License: MIT
- Published: 2026-09-15 · Updated: 2026-09-15 · Language: en
- Canonical page: https://hysenlabs.com/projects/shadcn-ui-lint

## The Problem: Design Rules That Agents Cannot Act On

When a TypeScript type constraint rejects a prop value, the error tells the agent what is not allowed. It does not say what to use instead. For a Button that controls its own padding, a TypeScript error like `'padding' does not exist in type 'Pick<CSSProperties, "margin" | "width">'` identifies the violation but leaves the agent to infer the fix.

@shadcn/lint takes a different approach. Its error messages include the fix, drawn from the design system itself: the available sizes, the correct component to reach for, the file path where a new variant can be added. The README describes this design directly: errors tell agents what broke, what to use instead, and where to find it.

## The no-restyle Rule and the Contracts System

The primary rule is `shadcn/no-restyle`. It controls which Tailwind utility classes can be applied to which components. The `allow` option accepts category strings (`layout`, `spacing`, `typography`) and the `contracts` array applies per-component overrides using name patterns:

```js
"shadcn/no-restyle": ["error", {
  allow: ["layout"],
  contracts: [
    { pattern: "^Button$", allow: ["w-full", "mt-*", "mb-*"] },
  ],
}]
```

With this configuration, applying `p-4` or `hover:rounded-full` to a Button is an error. Applying `mt-4` or `md:w-full` is allowed. Each sub-component of a composite component can have its own contract. For a Card, `CardTitle` might allow typography changes but deny font-family overrides, while `CardContent` allows spacing but not typography changes:

```js
"shadcn/no-restyle": ["error", {
  allow: ["layout"],
  contracts: [
    { pattern: "^CardTitle$", allow: ["layout", "typography"], deny: ["font-*"] },
    { pattern: "^CardContent$", allow: ["layout", "spacing"] },
  ],
}]
```

A second rule, `shadcn/no-arbitrary-values`, prevents values like `p-[13px]` that fall outside the theme's spacing scale. The two rules combine: `no-restyle` can permit spacing changes on a component while `no-arbitrary-values` keeps those changes on the design system's defined values.

## Installing and Configuring @shadcn/lint

The README provides a quickstart prompt for coding agents: point the agent at the SETUP.md file in the repository and ask it to install the plugin. For manual setup, the standard ESLint plugin installation path applies, since @shadcn/lint distributes as an ESLint and Oxlint package.

The plugin works with Tailwind v4. It does not require shadcn/ui components; the README states explicitly that it works with any Tailwind v4 project. The supported frameworks are React, Svelte, and Vue. Node 20.19 or later is required, as specified in the workspace package.json.

Once installed, rules go into the ESLint or Oxlint configuration file. Custom messages can be attached to any rule using the `message` option:

```js
"shadcn/no-restyle": ["error", {
  allow: ["layout"],
  message: {
    spacing: "Use the size prop instead of padding.",
  },
}]
```

When the agent applies forbidden padding, it receives the custom message rather than a generic constraint description.

## Placeholders That Pull from the Design System

Custom error messages support placeholders that are resolved against the actual component configuration. The README shows `{{sizes}}` for spacing errors, which expands to the list of defined sizes for the component. This means an error message can say "use one of sm, md, lg" without the maintainer hardcoding those values into the message string.

This keeps error messages accurate as the design system evolves. If a new size is added to the component, the placeholder reflects it without a manual message update.

## How It Performs with Coding Agents

The README reports results from more than 150 task runs with coding agents. For each model tested, the number of design system violations after lint feedback was zero. Before feedback, violations ranged from 42 to 117 per run depending on the model. The README presents results per model for one run each: Sonnet 5, Haiku 4.5, and Opus 5 each completed all 8 of 8 tasks; GPT 5.6 Terra completed 8/8; GPT 5.6 Sol completed 6/8.

The README also reports that in the Claude control runs, fixing violations with lint feedback cost 10% to 48% less than using design rules alone. The methodology is documented in `docs/evals.md` in the repository.

## Where @shadcn/lint Does Not Apply

@shadcn/lint requires Tailwind v4. Projects on Tailwind v3 or earlier are not supported. The plugin does not enforce Tailwind class ordering; that is a separate concern addressed by other tools like Prettier's Tailwind plugin.

The plugin operates at the linting stage, which means it catches violations when the agent runs lint, not at the type-checking stage. An agent that does not run lint after generating code will not see the errors. The README's quickstart is explicitly designed to ensure the agent sets up lint and learns to run it as part of its workflow.

Rules are configured without changing component code, which is an advantage for teams using third-party component libraries. However, the guidance in error messages is drawn from the local design system configuration, so a project that has not defined sizes and variants will see less informative error messages.

## Comparison with TypeScript-Only Enforcement

TypeScript type constraints are the other common way to control component usage. The README uses a Button example to show the difference. TypeScript can enforce which CSS properties a `style` prop accepts by limiting its type with `Pick<React.CSSProperties, "margin" | "width">`. This approach requires changing the component API.

@shadcn/lint does not change component APIs. The same component ships to every project unchanged. Each project adds its own lint configuration to define what is allowed. This makes it possible to apply different rules in different projects using the same component library, without forking the component. It also allows rules to be applied to third-party packages without modifying them.

The two approaches are not mutually exclusive: TypeScript catches type errors at the call site, while @shadcn/lint catches design system violations at lint time and provides the guidance needed to fix them.

## Release History and License

Version 0.2.0 was released on 2026-09-22. The previous version, 0.1.5, was released the day before, and 0.1.4 the day before that, indicating rapid iteration at the time of writing. The repository uses changesets for release management, with a release script that runs typecheck, tests, and a corpus check before publishing.

The license is MIT, located in the root LICENSE file. The package manager is pnpm at version 10.28.2.

## Conclusion

@shadcn/lint fits teams who use coding agents to write UI and who have invested in defining a Tailwind-based design system. The benefit is direct: the README reports that almost every agent task reached zero violations in one correction round after lint feedback, and that fixing violations cost 10% to 48% less than using design rules alone. Teams without a coding agent workflow will still benefit from consistent enforcement, but the error message design is optimized for agent consumption. The plugin requires Tailwind v4 and supports React, Svelte, and Vue. Version 0.2.0 was released on 2026-09-22.

## FAQ

### Does @shadcn/lint require shadcn/ui components?

No. The README states explicitly that @shadcn/lint works with any Tailwind v4 project and that shadcn/ui is not required. The plugin can be applied to components from any source, including third-party packages.

### Does @shadcn/lint work with Oxlint as well as ESLint?

Yes. The README lists both ESLint and Oxlint as supported linting engines.

### Can @shadcn/lint rules be shared across multiple projects?

Yes. The README describes sharing a configuration across projects as a supported use case. Each project can then add its own rules on top of the shared configuration.

## Sources

- [Issues](https://github.com/shadcn-ui/lint/issues)
- [License: MIT](https://github.com/shadcn-ui/lint/blob/main/LICENSE)
- [README](https://github.com/shadcn-ui/lint/blob/main/README.md)
- [shadcn-ui/lint on GitHub](https://github.com/shadcn-ui/lint)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/shadcn-ui-lint
