How .cursor/rules works, past the Cursor rules documentation

The file layout
Rules live in .cursor/rules/ at the repo root, one rule per file, with an .mdc extension. Each file is markdown with a small frontmatter block on top. You can also place a .cursor/rules directory inside a subdirectory, and those rules apply to work in that subtree, which is how monorepos keep frontend conventions away from backend tasks.
The old single .cursorrules file at the repo root is still read, but Cursor treats it as deprecated in favor of the directory form. Everything useful, especially scoping by file glob, only exists in the directory form. If you are still on the old file, moving is an afternoon. Devin Workshop is part of Harness Institute.
Four .cursor/rules attachment modes, and how to choose
This is the part the Cursor rules documentation states plainly and everyone still gets wrong. A rule reaches the model in one of four ways, controlled by frontmatter:
- Always Apply. Set
alwaysApply: trueand it is in context for every request. Use for a handful of facts that are true everywhere: how to run tests, what the package manager is. - Apply to Specific Files. Set
globsand the rule loads when a matching file is in play. This is the mode most rules should use. - Apply Intelligently. Give it a
descriptionand no globs, and the model pulls it in when the description matches the task. The description is the entire selection signal, so write it as a trigger condition, not a title. - Apply Manually. No description, no globs. It loads only when you reference the rule by name in a prompt. Good for rare procedures like a release checklist.
A rule file looks like this:
---
description: Conventions for React components
globs: ["src/components/**/*.tsx"]
alwaysApply: false
---
Components are function declarations, not arrow consts.
Data fetching happens in the route loader, never in a component.
The failure that costs teams the most
Marking everything as always-apply. It feels safe. It is the reason your rules stop working. Every always-on rule occupies context in every request, including the ones it has nothing to do with, and once the block is long enough the model starts treating all of it as background noise. Teams come to us with a 600-line always-on rule set and the complaint that Cursor ignores their conventions. It does. That is what happens.
The fix is mechanical. Keep the always-on file under roughly twenty lines. Everything else gets a glob.
Second failure: rules written as values rather than instructions. "We care about clean code" changes nothing. "Never add a new dependency without asking; suggest a standard library approach first" changes behaviour. If a rule cannot be violated by a specific line of code, it is not a rule.
Checking that a rule fired
Do not assume. In a chat, the rules that were pulled in are visible in the context shown with the request. Open a file the glob should match, ask a question, and confirm the rule appears. If it does not, your glob is wrong, and the usual cause is a leading slash or a missing ** segment.
Cursor can also draft a rule from a conversation. When you have just spent ten minutes correcting the agent about the same convention, ask it to generate a rule capturing what it learned, then edit the result down. The generated version is always too long and roughly right.
What to do next
Open your existing rules and count the always-apply ones. Convert every rule that only concerns a subset of the codebase to a glob, and cut the always-on file to the five facts a new hire needs. Then run a task you know used to go wrong and see whether it still does.
If you want help putting this into practice, talk to us.