# Lint locks

> Lint locks set which properties AI agents may change on each shadcn/ui component. The DS Manager agent obeys them, and so do Claude and Cursor in your project.

Canonical: https://www.shadcndesign.com/docs/ds-manager-lint

A lint lock says that agents may not change one kind of property on a component, such as Color on Card. The agent in DS Manager refuses a locked change and tells you why. The locks also publish with your registry as a policy for `@shadcn/lint`, so Claude Code, Cursor or any other agent that runs your linter gets them as lint errors.

<RichImage
  src="/docs/ds-manager/lint-lock.webp"
  alt="The Lint tab on the Button page, with Layout under Agents can change and Color, Type, Spacing, Shape, Effects and Motion under Agents can't change"
  width="899"
  height="621"
  quality="90"
/>

## What you can lock

Locks work per category. There are seven:

| Category | Covers |
| --- | --- |
| Layout | margin, width and position |
| Color | background, text and border |
| Type | size, weight and leading |
| Spacing | padding and gap |
| Shape | radius, border and ring |
| Effects | shadow, opacity and blur |
| Motion | transition and animation |

You can lock a category for every component, for one component, or for one part of a component (Card title, Dialog footer). A part follows its component until you change it.

## Turn locks on

Locks are off in a new system. Open any component page, switch to the **Lint** tab and click **Turn on** next to "Locks are off".

Turning locks on leaves Layout open and locks the other six categories on every component. From there you open what agents should be allowed to change.

## Lock or unlock a property

1. Open a component page, for example Card.
2. Open the **Lint** tab in the right rail, or press `4`.
3. Pick what to edit in the **Part** menu: the component itself or one of its parts. ⌘-clicking a part on the canvas, or picking it in Component Layers, selects it here too.
4. Click a category chip to move it between **Agents can change** and **Agents can't change**.

Each click is one undo step. Hover a chip to see an example change for that category drawn on the selected part. A part that differs from its component says so in the chip's tooltip ("Differs from Card").

To unlock, click the chip again in **Agents can't change**.

**Try a change** previews any edit against your locks without saving it. Pick a preset in **Change** (Wider, Red text, Bigger text, More padding, Round corners, Shadow) or type your own class under **Custom class**. The canvas outlines the part with the change applied and shows whether it is allowed. When it isn't, **Copy message** copies the sentence an agent would get.

## All locks on one page

**Brand → Lint** shows the whole policy. The header switches between two views.

**Locks** is a table with one row per component and one column per category. The first row, **Every component**, is the default the others inherit. Click a cell to lock or unlock it; its tooltip reads, for example, "Locked. Agents can't change Color on Card. Click to unlock." Inherited values are muted and exceptions are drawn solid with a dot, so they stand out. **Show parts** opens a component's parts, and the search field filters the table.

**Rules** sets how strict the linter is. **Strictness** offers three presets (Relaxed, Balanced, Strict). Below it, each of the six rules has **Off**, **Warn** and **Block**:

- **Restyling**: components keep their look. This is the rule your locks belong to.
- **Raw colors**: colors come from your tokens, not values like `red-500`.
- **Made-up sizes**: sizes come from your scale, not values like `p-[13px]`.
- **Inline styles**: styles go in classes, not a `style` attribute.
- **Typos**: every class must be one Tailwind or your system can make.
- **Dynamic classes**: class names are written out in full.

Block means agents must fix it. Warn means agents may ignore it. With Restyling at Off, no lock applies.

The **Actions** panel has three buttons. **Suggested contracts…** adds starting locks for components that have none yet and leaves the ones you changed alone. **Set up with the agent** opens the Agent tab, where the agent asks how pages may restyle your components and then writes the policy (this needs Pro). **Clear all…** turns every rule off and removes every lock; one undo brings it all back.

## What the agent does at a lock

With Restyling at Block, the agent checks every class it would add, swap or remove on a component. If a change hits a lock, the whole edit is refused and nothing is applied. The agent tells you which lock stopped it:

> Locked. Agents can't change Color on Card. Unlock it on the Lint tab first.

<RichImage
  src="/docs/ds-manager/lint-agent-reply.webp"
  alt="The Agent tab on the Button page after a request to make the default Button amber: the agent replies that Color is locked on Button and points to the Lint tab, and the buttons on the canvas keep their color"
  width="899"
  height="328"
  quality="90"
/>

If one request mixes locked and open changes, nothing lands, and the agent can send the open changes again on their own. Some styles are shared between components: Button's radius also sets Button Group's outer corners, for example. A rounder Button is refused when Shape is locked on Button Group, even if it is open on Button.

With Restyling at Warn, the edit goes through and the reply says so: "Locked. Agents get a warning if they change Color on Card."

Locks bind agents only. Your own edits in the Style tab are never blocked. ProBlocks and custom components are not covered by locks.

## Locks in your project

When the policy has at least one rule on, publishing adds it to your registry as `design-system.lint.json`. The [install command](/docs/ds-manager-publish) writes that file into the project root and adds `@shadcn/lint` as a dev dependency.

The registry can't write your linter config, so you add it once. Open **Get code** and go to the **Lint** tab:

1. Under **Install the linter**, pick ESLint or Oxlint and run the command, for example:

   ```bash
   pnpm add -D @shadcn/lint eslint @typescript-eslint/parser
   ```

2. Copy the config file the tab shows (`eslint.config.mjs` or `.oxlintrc.json`) into the project root. The ESLint version:

   ```js
   import policy from "./design-system.lint.json" with { type: "json" }
   import { plugin as shadcn } from "@shadcn/lint"
   import tsParser from "@typescript-eslint/parser"
   import { defineConfig } from "eslint/config"

   export default defineConfig([
     {
       files: ["**/*.{js,jsx,ts,tsx}"],
       languageOptions: { parser: tsParser, parserOptions: { ecmaFeatures: { jsx: true } } },
       plugins: { shadcn },
       settings: policy.settings ?? {},
       rules: policy.rules,
     },
     ...policy.overrides,
   ])
   ```

3. Add your lint command as the project's `lint` script.
4. Add this line to your project's `AGENTS.md`, so agents run it:

   ```text
   After making changes, run `npm run lint` and fix all errors.
   ```

From then on, an agent that passes a locked class to a component, like `bg-red-500` on a Card, gets a lint error and has to fix it. The components and blocks the registry installs in `components/ui` and `components/blocks` may style themselves; your own code gets every rule.

To change a lock later, edit it in DS Manager, publish again and rerun the install command. The policy file updates with the rest of the system.
