Cursor is fast enough that you can generate a whole page before you notice it used the wrong grey. I have done this. Twice in one afternoon.
The fix is not prompting harder. It is making the design system part of the context Cursor always has.
How Cursor rules work
Cursor reads rule files from .cursor/rules/ in your project. Each file uses the .mdc extension and starts with a small front matter block that tells Cursor when to apply it.
The important field is alwaysApply. Set it to true and the rule goes into context on every request, not just when the model decides it is relevant. For a design contract, that is exactly what you want.
The setup
Put DESIGN.md in your project root. Then create .cursor/rules/design-system.mdc:
---
description: Visual contract for all UI work
alwaysApply: true
---
All UI in this project follows DESIGN.md in the repository root.
@DESIGN.md
Before writing or editing any component:
- Use only the colors, type scale, spacing, and radius tokens from DESIGN.md.
- Match the component rules exactly, including states and density.
- Do not add a shadow, gradient, or font that DESIGN.md does not define.
- If a token is missing, say so instead of guessing a value.The @DESIGN.md reference pulls the file in, so you maintain one source of truth rather than two copies that slowly disagree.
Scope it if your repo is big
Here is where it gets interesting. On a large monorepo, you may not want the design contract loaded during backend work.
Swap alwaysApply for a glob and the rule only attaches when you touch UI files:
---
description: Visual contract for all UI work
globs: ["**/*.tsx", "**/*.jsx", "**/*.css"]
---This keeps your context budget for the code that actually needs it. On smaller projects, alwaysApply: true is simpler and I would not bother.
Verify it worked
Open a new chat and ask a question with a checkable answer:
List the exact hex values for primary, background, and border in this project.Cursor should return the real tokens. If it returns generic Tailwind values, the rule is not loading. Check that the file sits in .cursor/rules/, ends in .mdc, and has valid front matter between the --- markers.
Common mistakes
- Using `.cursorrules`. The single-file legacy format still works in many versions, but the directory format is the current one and it supports scoping.
- Forgetting to commit `.cursor/`. If it is in
.gitignore, your teammates get none of this and you will not understand why their output looks different. - Pasting the whole design system into the rule. Reference the file instead. When DESIGN.md changes, the rule stays correct.
What this means for you
Cursor is at its best when it can move fast without you reviewing every color. A rule file that always applies gets you there, because the constraint travels with the repo instead of living in your head.
Pick a system from the library, save it as DESIGN.md, add the rule file, and the next component you generate will already match.