Project rules in Cursor
PLCursor project rules are .mdc files in a repository’s .cursor/rules/ folder that give Cursor’s Agent standing instructions. Frontmatter sets when each rule loads: always, for matching files, on Agent’s judgment, or on an @-mention. Rules steer Agent; tests and CI still decide whether its output ships.
This page is for a developer setting up Cursor on a real repository. The pattern is familiar: for the third time this week you type “validate the body with Zod first” and “run the tests before you say done”, and Agent still writes a route that skips the tenant filter. Project rules put those corrections in the repository once, so every Agent session starts from them and every teammate gets the same ones.
What your first project rules give you
Section titled “What your first project rules give you”- Three working rule files: a short always-on core rule, a rule scoped to one area of the code, and a manual procedure you load on demand.
- A decision table for which load mode each instruction needs, so the context is not filled with rules that do not apply.
- A canary check that proves which rules Agent actually loaded, in under a minute and without guessing.
- A probe task with a command that decides whether a rule changed Agent’s output, so you verify behaviour instead of reading the diff.
- Copy-paste prompts that draft the core rule from your repository and test every rule you write.
How does Cursor decide when a project rule loads?
Section titled “How does Cursor decide when a project rule loads?”Three frontmatter fields decide it: alwaysApply, description, and globs. The type dropdown in Cursor’s rule editor sets them for you; in a text editor you write them yourself.
| Type in the dropdown | alwaysApply | description | globs | When the rule loads | Use it for |
|---|---|---|---|---|---|
| Always Apply | true | ignored | ignored | Every Agent session | Commands that prove work is done, hard boundaries |
| Apply to Specific Files | false | — | set | A file matching the pattern is in context | Conventions for one area: API routes, migrations, UI |
| Apply Intelligently | false | set | — | Agent reads the description and decides | A procedure tied to a kind of task |
| Apply Manually | false | — | — | You @-mention the rule in chat | Rare, risky procedures: backfills, releases |
Five details trip up most first rule sets:
- Only
.mdccounts. Cursor’s rules documentation says “Project rules live in.cursor/rulesas.mdcfiles” and “A plain.mdfile in.cursor/rulesis ignored by the rules system” (checked 2026-10-12). - Multiple globs are comma-separated, as in
src/**/*.ts, src/**/*.tsx. A bare*.tsmatches files in the repository root only. - Rules reach Agent only. Cursor’s help says “Rules only apply to Agent (Chat). They do not apply to Tab completion, Inline Edit, or Bugbot PR reviews” (checked 2026-10-12). Bugbot takes its own guidance from
.cursor/BUGBOT.md, a file described second-hand and not re-checked on 2026-10-12; see Bugbot. - Subfolders work.
.cursor/rules/frontend/components.mdcis a project rule too, which helps once you have more than a handful. - Other instruction files count too. Cursor’s rules documentation says “Cursor supports AGENTS.md in the project root and subdirectories”, and nested files “are combined with parent directories, with more specific instructions taking precedence”. Cursor “reads
CLAUDE.mdfiles the same way it readsAGENTS.md”, and “CLAUDE.mdfiles are always applied to every conversation, regardless of anyalwaysApplyfrontmatter setting” (checked 2026-10-12).
Write your first three project rules
Section titled “Write your first three project rules”Start from the corrections you repeat, not from a style guide. Agent already knows common conventions; a rule earns its place only when it changes what Agent would otherwise do.
-
Create the folder and move any old rules file. In a terminal at the repository root:
Terminal window mkdir -p .cursor/rulesls .cursorrules 2>/dev/null && echo "move its content into .cursor/rules/core.mdc"If the repository still has a single-file
.cursorrules, move its content into the core rule below and delete the file, so all rules live in one place that the team reviews. Cursor’s help calls the.cursorrulesfile in the project root “legacy and will be deprecated” and recommends migrating it to a project rule set to Always Apply (checked 2026-10-12). -
Write a short core rule. Save it as
.cursor/rules/core.mdc. It carries only what every task needs: the stack in one line, the commands that define “done”, and the boundaries Agent must not cross. Keep it under about 40 lines, because every session pays for it.---description: Stack, done criteria, and hard boundaries for every taskalwaysApply: true---Stack: TypeScript (strict), Next.js App Router, Drizzle on PostgreSQL, Vitest, pnpm.Done means all of these pass, and you paste the last lines of each:- pnpm lint- pnpm typecheck- pnpm testBoundaries:- Never add a dependency without naming it and the reason in your summary.- Never edit a merged migration in src/db/migrations/; add a new one.- Never weaken, skip, or delete an existing test to make a check pass.- Log with the logger in @src/lib/logger.ts, never console.log.The
@src/lib/logger.tsreference points Agent at the real file instead of copying code into the rule, so the rule does not go stale when the file changes. An@reference loads that file whenever the rule loads, so in an Always Apply rule keep references to small files. -
Scope an area rule to its files. Save it as
.cursor/rules/api-routes.mdc. It loads only when a matching file is in context, so it costs nothing while Agent works on the UI.---globs: src/app/api/**/*.tsalwaysApply: false---API route conventions:- Validate the request body with a Zod schema from @src/lib/validators/index.ts before any other work.- Every database query filters by organizationId. A route without it is a security bug.- Throw AppError from @src/lib/errors.ts; never return raw database errors or stack traces.Canonical route: @src/app/api/users/route.ts -
Keep a risky procedure manual. Save it as
.cursor/rules/data-backfill.mdc. With nodescriptionand noglobs, it loads only when someone types@data-backfillin chat.---alwaysApply: false---Data backfill procedure:- Write the backfill as a plain Node script (.mjs) in scripts/backfills/ with a --dry-run flag that prints row counts.- Batch writes in chunks of 1,000 and make the script safe to re-run.- Stop after the dry run and show its output. A human runs the real backfill. -
Commit the rules. Rules in
.cursor/rules/are version-controlled, so review a rule change like a code change. When the team grows, add.cursor/rules/toCODEOWNERSso one named person signs off on rule edits.
Adapt the paths and commands to your stack; the structure is what matters. You can also type /create-rule in Agent and describe the rule; it writes the file with frontmatter into .cursor/rules/. Review what it writes before you commit it, because a generated rule tends to restate conventions Agent already follows.
How do you prove a project rule loaded and changed the output?
Section titled “How do you prove a project rule loaded and changed the output?”A rule is an untested instruction until something checks it. Two quick checks cover a first rule set: a canary that proves which rules loaded, and a probe task whose result a command decides.
Check loading with a canary
Section titled “Check loading with a canary”Cursor puts applied rule contents into the model context, so Agent can quote from a rule it has. Asking “which rules do you see?” invites a plausible guess; asking for a random token it cannot guess does not.
- Add a temporary last line to each rule with a unique token, for example
Canary: core-7f3aincore.mdc,Canary: api-19c2inapi-routes.mdc, andCanary: backfill-d04eindata-backfill.mdc. - Close any editor tabs under
src/app/api/, open a new Agent chat with no files attached, and paste the prompt below. Onlycore-7f3ashould come back. - In another new chat, attach
src/app/api/users/route.tsand ask again. Nowapi-19c2should appear too. - In a third chat, type
@data-backfilland ask again.backfill-d04eshould appear. - For an Apply Intelligently rule, give it a canary too, open a new chat, type a request that matches its description (for example “Add a new API endpoint end to end”), and paste the prompt again. Its token should appear; if it does not, Agent skipped the rule for that request.
- Remove the canary lines and commit.
If a token is missing, the rule did not load; the failure modes below tell you why. For a second opinion, Customize → Rules lists every rule Cursor found and its status.
Check behaviour with a probe task
Section titled “Check behaviour with a probe task”Loading is not obeying. Give Agent a small task that the rule should shape, then let a command decide instead of reading the diff.
| Probe task in a new chat | Rule it exercises | Command that decides |
|---|---|---|
| “Add GET /api/invoices/[id] that returns one invoice” | api-routes.mdc | pnpm test src/app/api/invoices passes, including a test where a user requests another organization’s invoice and gets 404; rg -c organizationId src/app/api/invoices is only a quick pre-check |
| “Log the retry count in the payment service” | core.mdc | git add -N src/lib/services && git diff -U0 -- src/lib/services | rg '^\+.*console\.log' returns nothing, so Agent added no console.log, not even in a new file (git add -N makes untracked files visible to git diff) |
| “@data-backfill fill invoices.currency from orders” | data-backfill.mdc | node scripts/backfills/<name>.mjs --dry-run exits 0 and prints row counts, and git status --porcelain --untracked-files=all lists only ?? scripts/backfills/<name>.mjs, with no path under src/db/migrations/ |
Run the probes again whenever you change a rule. A probe that fails means the rule is unclear, did not load, or conflicts with another rule or with the code.
What still checks the code after the rules work?
Section titled “What still checks the code after the rules work?”Rules steer Agent; they enforce nothing. Cursor’s own guidance says AI guidance should not be your only security control. The core rule asks Agent to run the done commands, but the same commands in CI are what block a bad merge. A boundary that must never be crossed belongs in a CI gate or a fitness function. The rule is only the hint that keeps Agent away from it. Whoever merges the pull request signs off on the green gates, not on having read every line.
Should an instruction be a rule, a skill or a linter check?
Section titled “Should an instruction be a rule, a skill or a linter check?”Most weak rule sets come from putting a sound instruction in the wrong place.
| The instruction is… | Put it in | Why |
|---|---|---|
| Needed on almost every task | Always Apply rule | Short, and paid for in every session |
| True in one area of the code | Apply to Specific Files rule | Loads only where it matters |
| A long multi-step procedure with scripts | An Agent Skill | Skills load their resources on demand and work across agents that support the standard |
Mechanically checkable: naming, imports, any | Linter or type rule | Runs on every commit, not only when Agent remembers |
| Something Agent does correctly already | Nowhere | It costs context and changes nothing |
Cursor’s documentation says that Cursor loads project skills from .agents/skills/ and .cursor/skills/ (user level: ~/.agents/skills/ and ~/.cursor/skills/) and, “for compatibility”, from .claude/skills/ and .codex/skills/ (and ~/.claude/skills/ and ~/.codex/skills/). Nested project skill folders are scoped to their subtree. Built-in skills include /create-rule, /create-skill and /migrate-to-skills (checked 2026-10-12). On 2026-09-26 the docs described /migrate-to-skills as converting eligible dynamic rules and slash commands into skills. How to install and share skills is covered in the skills overview.
When Cursor project rules do not work
Section titled “When Cursor project rules do not work”A rule never loads. The file ends in .md, not .mdc, or the frontmatter is malformed (a missing closing ---, a tab in the YAML). Recovery: rename it to .mdc, fix the frontmatter, and repeat the canary check.
A file-scoped rule never fires. The glob is *.ts, which matches the repository root only, or it points at a folder that moved. Recovery: use **/*.ts or a directory prefix such as src/app/api/**/*.ts. For a rough check, list the files it matches with shopt -s globstar; ls src/app/api/**/*.ts in bash. Then confirm with the canary check, because bash globbing only approximates Cursor’s matcher.
An Apply Intelligently rule is skipped for the task it was written for. Its description names a topic (“API stuff”) instead of a task. Recovery: rewrite the description as the request a developer would type, such as “Adding a new API endpoint end to end”, or scope the rule with globs instead.
Agent follows a rule that contradicts the code. The rule describes last quarter’s pattern. Recovery: replace pasted code with @ references to the canonical file, and delete the stale lines.
Context fills up before the task starts. The always-on rule grew one line at a time. Recovery: move area-specific lines into glob rules and procedures into skills, and move @ references out of the always-on rule; context management in Cursor shows how to see what the session carries.
The team expects rules in Tab, Inline Edit or Bugbot. Rules apply to Agent only (Cursor help, checked 2026-10-12). Recovery: put pull request review guidance in Bugbot’s own guidance file (see Bugbot) and enforce style with the linter.
A Team Rule beats your project rule. On Teams and Enterprise plans, Team Rules take precedence over project rules, which take precedence over User Rules: Cursor’s rules help page says “When rules conflict, precedence is: Team Rules > Project Rules > User Rules” (read 2026-10-13). Since Cursor 3.21 (2026-09-17, Cursor’s release notes), a team rule with file patterns applies only to matching files. Recovery: ask the admin to keep Team Rules to policy, and keep code conventions in the repository.
Where to go next with project rules
Section titled “Where to go next with project rules”- Essential configuration: the prerequisite, if Cursor is not set up yet.
- PRD workflow: the next step, turning a requirement into a plan that these rules shape.
- Custom rules and templates: growing these files into a tested library with a CI check and Team Rules.
- Shared agent rules and one rules source for every agent: when the same repository also runs Claude Code or Codex.
- The same idea in the sibling tools: Claude Code’s memory system (
CLAUDE.md) andAGENTS.mdin Codex. - Design: where conventions and boundaries are decided in the lifecycle before they become rules.
Did this guide help you?
One tap, no sign-in.
What will you do with it?
How did it read?
What got in the way? Pick any that apply
Your role?
Thanks. I read every answer. Michał Jaskólski
Did this guide help?
One tap each. Close whenever you like.
no sign-in