Back to blog
Engineering18 min read

Cursor Rules Not Working? Why Cursor Ignores Your Rules File

A diagnostic ladder for cursor rules not working, cheapest check first: wrong extension, wrong rule type, a glob that misses, a legacy path, a file that never syncs, and the case where it loads fine.

NH
Nafiul Hasan
Founder, Prompt Architects

TL;DR: Cursor rules not working is two different problems wearing the same costume. Either the rule never reached the model, or it reached the model and lost. The first is a configuration bug with a cheap fix. The second is a prompt-strength problem, and no amount of file-shuffling touches it. Work down in cost order.

At 2am, the useful question is not why Cursor ignores your rules file. It is whether your rule reached the model at all. Those are different failures with different fixes, and most of the advice you will find online silently assumes the second while you are actually suffering the first.

So this is a ladder, cheapest rung first, each one grounded in what Cursor publishes: the rules reference at cursor.com/docs/rules and the customization help page at cursor.com/help/customization/rules, both read on 28 August 2026. They do not cover the same ground. The reference opens by saying Cursor "supports four types of rules" and never mentions .cursorrules; the help page documents three more things Cursor reads. If you have read only one, your map is incomplete.

Where Cursor documents nothing, this post says so rather than inventing a mechanism. Four such gaps are collected near the end.

Which rung are you on?

Start with the symptom you can actually observe, not the cause you suspect.

#What you seeLikely causeCheapest check
1Rules never seem to apply, anywhereYou are not in Agent (Chat)Which pane are you typing into?
2One specific file does nothingWrong extensionfind .cursor/rules -type f ! -name '*.mdc'
3Rule applies sometimes, unpredictablyRule type is not what you assumedPrint every rule's frontmatter
4Applies in one folder, not anotherThe glob does not matchExpand the glob in a shell
5Worked last year, stoppedRule is in a legacy locationls -la .cursorrules
6Works on your laptop, not the desktopUser-scoped file that does not syncls -la ~/.cursor/rules
7Rule applies but gets overruledAnother rule, or your own requestList every file Cursor reads
8Rule is clearly loaded and still lostRules are context, not enforcementRewrite the rule

Rungs 1 to 6 are configuration. Rung 7 is arbitration. Rung 8 is the honest one, and it is where most people who have already checked their frontmatter actually live.

Rung 1: Are you even using the surface rules apply to?

Rules reach Agent (Chat). They do not reach the other panes.

Cursor's help page is unambiguous: "Rules only apply to Agent (Chat)." The same sentence excludes Tab completion, Inline Edit and Bugbot PR reviews. The reference asks in its own FAQ, "Do rules impact Cursor Tab or other AI features?", answers no, and separately states that "User Rules are not applied to Inline Edit".

This is the most common way to conclude your rules are broken when they are fine. You write a naming-convention rule, test it with Cmd+K on a function, watch it get ignored, and go rewrite the file. The file was never in play.

The behavioural test costs nothing. Put a distinctive token in an always-applied rule and ask for it back in Agent:

---
alwaysApply: true
---

- If the user's message contains the exact word RULECHECK, begin your reply
  with the line: rules loaded, canary v1

Ask RULECHECK in Agent (Chat). If the canary comes back, your pipeline works and every rung below is about which rule, not whether rules. If it does not, keep descending. If it returns in Agent but not in Inline Edit, that is documented behaviour, not a bug.

Rung 2: Is the file actually a .mdc file?

This is the cheapest real fix and it catches an embarrassing number of cases.

Project rules live in .cursor/rules, and Cursor's reference states plainly that project rules must use the .mdc extension. A plain markdown file in that directory "is ignored by the rules system because it has no frontmatter to specify" the three fields it needs. Cursor's own directory listing labels api-guidelines.md as ignored, wrong extension.

There is no warning. The file sits there looking like a rule, git tracks it, code review approves it, and it does nothing.

# Everything Cursor treats as a project rule:
find .cursor/rules -type f -name '*.mdc' | sort

# Everything in that directory that is NOT a project rule:
find .cursor/rules -type f ! -name '*.mdc' | sort

Anything printed by the second command is inert. Usual culprits: an editor that autocompleted .md, a README.md explaining the folder, and a rule copied from a blog post with the wrong suffix.

If you want plain markdown with no frontmatter, Cursor documents the supported path: AGENTS.md in the project root, picked up automatically and also supported in subdirectories. Different mechanism, different behaviour, not a rename.

Rung 3: Is the rule's type what you assumed it was?

Cursor has four rule types and three are conditional. A rule that attaches only by glob looks completely ignored on any file the glob does not match, and it looks that way silently.

The type is not a separate setting. It falls out of three frontmatter fields, and Cursor publishes the interaction directly:

alwaysApplydescriptionglobsBehaviour
true"Always included. Globs and description are ignored."
falseprovided"Auto-attached when a matching file is in context."
falseprovidedomitted"Agent reads the description and pulls the rule in when relevant."
falseomittedomittedIncluded only when you @-mention the rule in chat

Read the third row carefully. A rule with a description and no globs is not applied on a schedule or on every message. The Agent decides, and if the description is vague it has nothing to decide on, so the rule stays out. Cursor's troubleshooting note says as much: for Apply Intelligently, "make sure you've added a description so Agent knows when it's relevant."

Print every rule's actual frontmatter before you theorise about any of it:

for f in $(find .cursor/rules -name '*.mdc' | sort); do
  echo "── $f"
  awk 'NR==1 && /^---/ {inside=1; next} inside && /^---/ {exit} inside' "$f"
  echo
done

Read the output against the table. In most repositories at least one rule turns out manual-only: no alwaysApply, no description, no globs. It has done nothing since the day it was written unless somebody @-mentions it.

Rung 4: Does the glob actually match your file?

Globs are where the it-works-under-src-but-not-under-app class of bug comes from, and the failure is nearly always a missing **.

Cursor publishes a pattern table. The first two rows are where most of the damage happens:

PatternMatches
*.tsAll .ts files in the root
**/*.tsAll .ts files in any directory
src/**All files anywhere under src/
src/**/*.tsxAll .tsx files anywhere under src/
docs/**/*.md, docs/**/*.mdxTwo patterns, comma-separated

If you wrote globs: *.tsx and your components live in src/components/, the rule matches nothing. It is not broken; it is scoped to the repository root, which has no .tsx files in it.

Expand the pattern before you argue with it:

# bash 4+. Paste the exact string from your globs field.
shopt -s globstar nullglob
matches=( src/components/**/*.tsx )
printf '%s\n' "${matches[@]}" | head -20
echo "total matched: ${#matches[@]}"

If that prints total matched: 0, you have found your bug in ten seconds. One caveat: this is bash's glob engine, not Cursor's. Cursor publishes example patterns but never names its matching implementation, so treat the expansion as a close approximation, not a guarantee. Expand comma-separated patterns one at a time.

There is a subtler trap in that same table row. A glob rule is "Auto-attached when a matching file is in context." Existing in the repository is not the same as being in context, and neither page defines what puts a file there. So a rule can be correctly written, correctly globbed, and still absent because the file was never pulled in. @-mention the file explicitly and see whether the behaviour changes.

Rung 5: Is the rule sitting in a legacy location?

If your setup predates the .cursor/rules directory, you may still have a .cursorrules file in the project root.

Cursor's help page says that file "is legacy and will be deprecated" and gives four migration steps: create a new rule via the command palette, copy the content across, set the type to Always Apply because that matches the old behaviour, and delete the root file.

ls -la .cursorrules 2>/dev/null && echo "LEGACY FILE PRESENT"
find . -maxdepth 3 -name '.cursorrules' -not -path './node_modules/*'

This rung is easy to miss because a legacy root file and a modern rules directory coexist happily. The repository looks correctly configured: a .cursor/rules folder full of sensible .mdc files, plus a two-year-old .cursorrules nobody has opened, quietly carrying instructions that contradict the new ones.

Rung 6: Is the rule user-scoped and not syncing?

The classic shape: a colleague cannot reproduce your setup, or your desktop behaves differently from your laptop, on identical checkouts.

Cursor documents four storage locations with different sync behaviours:

Where the rule livesSyncs?Documented behaviour
.cursor/rules/ in the projectVia gitVersion-controlled with the repository
Customize → Rules (account)Yes"They apply across all your projects and sync when you sign in on another machine."
~/.cursor/rules (files)No"stay on the machine and do not sync"
Team dashboardYesStored on Cursor's servers, sync automatically to members

The third row is the one that produces works-on-my-machine. A rule file at ~/.cursor/rules (or %USERPROFILE%\.cursor\rules on Windows) is invisible to everyone else and invisible to your other computer, by design.

ls -la ~/.cursor/rules 2>/dev/null || echo "no machine-local user rule files"

One more line catches people migrating machines: "User rules and team rules are not included in profile exports." A profile export is not a complete transfer. Account user rules return when you sign in; machine-local files do not travel at all.

Team rules have their own version of this. A team rule created with the enable checkbox unticked is "saved as a draft and does not apply until you enable it later", and rules that are not marked enforced "are enabled by default but members can disable them in" Customize. So a rule can sit in the dashboard looking live to an admin and be switched off for the one person filing the bug report.

Rung 7: Is something else contradicting it?

By this rung the rule is loading. It is losing an argument.

First, find everything Cursor might be reading here. It is usually more than you remember:

find . -maxdepth 3 \
  \( -name 'AGENTS.md' -o -name 'CLAUDE.md' -o -name '.cursorrules' \) \
  -not -path './node_modules/*' -not -path './.git/*'

find .cursor/rules -name '*.mdc' 2>/dev/null | sort

Two of those deserve special attention.

CLAUDE.md is read by Cursor the same way AGENTS.md is, and the help page states such files "are always applied to every conversation, regardless of any" alwaysApply setting. That is a rule you cannot scope: a CLAUDE.md kept for Claude Code is in every Cursor conversation too, unconditionally. If you maintain one, our CLAUDE.md templates for Claude Code matter more now that the file does double duty.

Nested AGENTS.md files are the other one. Cursor supports them in subdirectories, and instructions "are combined with parent directories, with more specific instructions taking precedence." So a stale frontend/AGENTS.md can quietly override the root file for everything under frontend/.

For the rules themselves, Cursor publishes the arbitration order:

  • Precedence is Team Rules, then Project Rules, then User Rules.
  • "All applicable rules are merged; earlier sources take precedence when guidance conflicts."
  • Filenames do not enter into it: "Cursor identifies rules by their full file path, not their name alone." Two rules with the same filename in different folders both apply. "There are no conflicts or overrides based on filename."

That surprises anyone who assumed a more specific .mdc shadows a general one of the same name. It does not. Both load, and if they disagree you have handed the model two instructions and asked it to pick.

The other contradiction is your own message. If the rule says never use default exports and your request says convert this file to a default export, the request usually wins, and it should. A rule is standing context; your message is the task.

Rung 8: The rule is loading, and it is being ignored anyway

This is the honest core, and no amount of file reorganisation touches it.

Cursor rules are context, not enforcement. The reference page states the mechanism: "When applied, rule contents are included at the start of the model context." That is all of it. The rule becomes text near the front of the context window, roughly where a system prompt sits, and a probabilistic model decides what to do with it. Neither page promises compliance, and neither could.

Even the enforcement language is about distribution, not obedience. Team and Enterprise admins can mark a rule as enforced so members cannot disable it, and Cursor still appends the caveat: "AI guidance should not be your only security control."

So if your canary from Rung 1 comes back and your rule still loses, you do not have a configuration bug. You have a weak instruction competing against a long conversation, a large diff, and a user request pulling the other way. The fixes are prompt fixes.

Make the instruction specific and checkable. Vague rules lose to specific requests every time, and Cursor's own guidance is to avoid vague guidance and write rules like clear internal docs. Compare:

---
alwaysApply: true
---

# Engineering principles

We care deeply about code quality. Always write clean, maintainable,
well-tested code. Follow best practices. Be mindful of performance.
Prefer simplicity and think about the reader.

Nothing in that is falsifiable, so nothing in it constrains anything. Now the same intent, written as instructions a reviewer could check:

---
globs: src/**/*.ts, src/**/*.tsx
alwaysApply: false
---

- Every exported function has an explicit return type. No inferred returns
  across a module boundary.
- Never use `any`. If a type is genuinely unknown, use `unknown` and narrow it.
- Files under `src/services/` export one named function. No default exports.
- Do not add a dependency. If one is needed, stop and say which and why.
- Do not edit anything under `src/generated/`.

Make it shorter. Cursor's guidance is to "Keep rules under 500 lines" and to split large rules into composable ones. Note what that is: a documented best practice, not an enforced ceiling, and Cursor publishes no token budget for rules. The practical effect is real, though. A three-page style guide dilutes every line in it. Cursor's list of what to avoid opens with "Copying entire style guides" and recommends you "Reference files instead of copying their contents".

Move the constraint into the request. The strongest position for an instruction is the message you just sent, not a file loaded twenty turns ago. If a constraint must hold for this task, restate it in the task. That is not a workaround; it is how prompt engineering works, and it is the same failure mode as AI ignoring your format instructions, ignoring a word count, or ignoring a negative prompt. Different tool, identical mechanism: a soft instruction losing to a stronger signal.

Move anything non-negotiable out of the model. If a constraint must hold every time, a rule is the wrong home. ESLint, Prettier, a type checker, a pre-commit hook and CI are enforcement. A rule is a suggestion delivered politely and early. Use rules for the judgement calls tooling cannot express and tooling for the rest.

What Cursor does not document

Four gaps, stated as gaps. If a forum answer fills one of these confidently, it is filling it from somewhere other than Cursor's documentation.

  1. Whether an existing .cursorrules file is still read today. The help page commits only to future deprecation. The reference page does not mention the file.
  2. The case where alwaysApply: false is combined with both a description and globs. Cursor's interaction table has four rows and none of them covers both fields being present at once.
  3. Nested .cursor/rules directories in project subfolders. Both pages describe folders inside one .cursor/rules directory. Nesting the rules directory itself is documented only for AGENTS.md, which explicitly supports subdirectories.
  4. What puts a file "in context" for the purposes of auto-attaching a glob rule, and which glob implementation the matcher uses.

For the syntax itself, and for rule files you can copy rather than diagnose, our Cursor rules and prompt templates guide covers the frontmatter fields and ships seven ready-made rule files. This post deliberately stops at diagnosis.

Where Prompt Architects fits, and where it does not

Straight answer first: we do not generate .mdc rule files, and there is no Prompt Architects extension for Cursor. If you came here for a tool that authors your rules directory, that is not us.

What we do run is an MCP server Cursor connects to. Our /integrations/mcp page documents the setup as Settings → MCP → Add new MCP server, with OAuth on first use or a personal access token from your dashboard. It exposes improve, refine, shorten and enhance, also as slash commands like /mcp__pa__improve.

That is relevant to exactly one rung: Rung 8. When a rule loads correctly and still loses, the fix is a better-written instruction, and shorten and refine target the two things that make rules lose: length and vagueness. It does nothing for Rungs 1 through 7, which are file-system problems and want a find command, not a prompt tool.

Free Chrome Extension

Stop rewriting prompts. Start shipping.

Works with ChatGPT, Claude, Gemini, Grok, Midjourney, Ideogram, Veo3 & Kling. 5.0★ on the Chrome Web Store.

Create An Account

The one-screen checklist

Paste this into a scratch file and work down it. Stop at the first thing that is wrong.

# 1. Surface — are you in Agent (Chat)? Rules do not reach Tab or Inline Edit.

# 2. Extension — anything printed here is ignored by the rules system
find .cursor/rules -type f ! -name '*.mdc' 2>/dev/null

# 3. Rule type — read each frontmatter block against Cursor's interaction table
for f in $(find .cursor/rules -name '*.mdc' 2>/dev/null | sort); do
  echo "── $f"
  awk 'NR==1 && /^---/ {i=1; next} i && /^---/ {exit} i' "$f"
done

# 4. Globs — expand each pattern; zero matches means zero rule
shopt -s globstar nullglob
m=( src/**/*.tsx ); echo "matched: ${#m[@]}"

# 5. Legacy — a root .cursorrules that nobody has opened in a year
ls -la .cursorrules 2>/dev/null

# 6. Sync — machine-local user rule files never leave this machine
ls -la ~/.cursor/rules 2>/dev/null

# 7. Contradiction — everything else Cursor reads in this repo
find . -maxdepth 3 \( -name 'AGENTS.md' -o -name 'CLAUDE.md' \) \
  -not -path './node_modules/*' -not -path './.git/*'

# 8. If all seven are clean, the rule is loading. Rewrite it shorter and
#    more specific, or move the constraint into the request.

Seven of those eight are cheap and mechanical. The eighth is the real work, and it is worth reaching honestly rather than by exhausting every configuration theory first. A rule that loads and is not obeyed is telling you something true about how it is written.

Everything attributed to Cursor here was read on 28 August 2026 at cursor.com/docs/rules and cursor.com/help/customization/rules. Both pages change; re-check before quoting them in a code review.

Frequently asked questions

Free Chrome Extension

Stop rewriting prompts. Start shipping.

Works with ChatGPT, Claude, Gemini, Grok, Midjourney, Ideogram, Veo3 & Kling. 5.0★ on the Chrome Web Store.

Create An Account