<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: ofir saban</title>
    <description>The latest articles on DEV Community by ofir saban (@ofir_saban_a14cc4bc21c433).</description>
    <link>https://dev.to/ofir_saban_a14cc4bc21c433</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2179709%2Fe9b44878-4a25-40f6-b84b-0f9fecd62812.png</url>
      <title>DEV Community: ofir saban</title>
      <link>https://dev.to/ofir_saban_a14cc4bc21c433</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ofir_saban_a14cc4bc21c433"/>
    <language>en</language>
    <item>
      <title>How to write Cursor rules that the agent actually follows (with .mdc examples)</title>
      <dc:creator>ofir saban</dc:creator>
      <pubDate>Mon, 09 Nov 2026 12:27:17 +0000</pubDate>
      <link>https://dev.to/ofir_saban_a14cc4bc21c433/how-to-write-cursor-rules-that-the-agent-actually-follows-with-mdc-examples-2j1o</link>
      <guid>https://dev.to/ofir_saban_a14cc4bc21c433/how-to-write-cursor-rules-that-the-agent-actually-follows-with-mdc-examples-2j1o</guid>
      <description>&lt;p&gt;If you use Cursor every day, you've typed this more than once:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"No, we use the App Router." "Don't use &lt;code&gt;any&lt;/code&gt;." "Put the test next to the file." "Validate with zod."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The agent isn't bad. It just doesn't know your project. &lt;strong&gt;Project rules&lt;/strong&gt; are how you tell it once instead of every prompt. Here's the structure I've settled on after a lot of trial and error.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Cursor rules work (current format)
&lt;/h2&gt;

&lt;p&gt;Rules live in &lt;code&gt;.cursor/rules/&lt;/code&gt; as &lt;code&gt;.mdc&lt;/code&gt; files: Markdown with a small frontmatter block.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Next.js&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;App&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Router&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;conventions"&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;app/**/*,**/*.tsx"&lt;/span&gt;
&lt;span class="na"&gt;alwaysApply&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="gh"&gt;# Next.js (App Router)&lt;/span&gt;
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three fields decide &lt;strong&gt;when&lt;/strong&gt; a rule is loaded:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Setup&lt;/th&gt;
&lt;th&gt;When it loads&lt;/th&gt;
&lt;th&gt;Use for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;alwaysApply: true&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Every request&lt;/td&gt;
&lt;td&gt;Small project core, code style&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;globs&lt;/code&gt; set&lt;/td&gt;
&lt;td&gt;When matching files are in context&lt;/td&gt;
&lt;td&gt;Framework / language rules&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;description&lt;/code&gt; only&lt;/td&gt;
&lt;td&gt;When the agent decides it's relevant&lt;/td&gt;
&lt;td&gt;Niche topics (migrations, i18n)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;none&lt;/td&gt;
&lt;td&gt;Only when you @-mention it&lt;/td&gt;
&lt;td&gt;Rare procedures&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;(The old single &lt;code&gt;.cursorrules&lt;/code&gt; file still works but is legacy. Split it up.)&lt;/p&gt;

&lt;h2&gt;
  
  
  A 5-file structure that works
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.cursor/
  rules/
    00-project-core.mdc   # always: what this is + definition of done
    01-workflow.mdc       # always: git, small diffs, summarize changes
    02-security.mdc       # globs: server code
    05-code-style.mdc     # always: typing, tests, tone
    10-nextjs.mdc         # globs: app/**, *.tsx
  skills/
    code-review/SKILL.md
    write-tests/SKILL.md
PROMPTS.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Rule of thumb:&lt;/strong&gt; always-on rules stay short (under ~40 lines each). Everything framework-specific is glob-scoped so it doesn't eat context when you're editing a SQL migration.&lt;/p&gt;

&lt;h3&gt;
  
  
  00-project-core.mdc
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Project&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;context&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;and&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;definition&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;of&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;done"&lt;/span&gt;
&lt;span class="na"&gt;alwaysApply&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="gh"&gt;# Project&lt;/span&gt;
Acme Invoices: B2B invoicing SaaS. Next.js 15 App Router, Postgres (Drizzle), Tailwind.
Team of 3. Optimise for readable code over clever code.

&lt;span class="gh"&gt;# Definition of done&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Types pass, lint passes, tests for new logic.
&lt;span class="p"&gt;-&lt;/span&gt; Loading and error states for every new route.
&lt;span class="p"&gt;-&lt;/span&gt; End with a 3-bullet summary: what changed, what to verify, any risk.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  10-nextjs.mdc
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Next.js&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;App&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Router&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;conventions"&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;app/**/*,**/*.tsx"&lt;/span&gt;
&lt;span class="na"&gt;alwaysApply&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="gh"&gt;# Next.js (App Router)&lt;/span&gt;
&lt;span class="gu"&gt;## Server vs client&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Components are Server Components by default. Add "use client" only for state, effects or events.
&lt;span class="p"&gt;-&lt;/span&gt; Never import DB clients or secrets into client code.
&lt;span class="gu"&gt;## Data&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Fetch in Server Components, not in useEffect.
&lt;span class="p"&gt;-&lt;/span&gt; Mutations → Server Actions, validated with zod, then revalidatePath().
&lt;span class="p"&gt;-&lt;/span&gt; Be explicit about caching on every fetch.
&lt;span class="gu"&gt;## Env&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Only NEXT_PUBLIC_ vars reach the browser.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  02-security.mdc
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Security&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;rules&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;for&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;server&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;code"&lt;/span&gt;
&lt;span class="na"&gt;globs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;app/**/actions.ts,app/api/**,lib/server/**"&lt;/span&gt;
&lt;span class="na"&gt;alwaysApply&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Every mutation checks auth AND ownership of the resource.
&lt;span class="p"&gt;-&lt;/span&gt; Validate all input at the boundary (zod). Never trust client IDs.
&lt;span class="p"&gt;-&lt;/span&gt; No secrets in logs, errors or client bundles.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Rules vs skills
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Rules&lt;/strong&gt; say how code should look. &lt;strong&gt;Skills&lt;/strong&gt; are step-by-step procedures the agent follows when you ask for a task, like "review this diff" or "write tests for this module". Keeping procedures out of rules keeps your always-on context small.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# skills/write-tests/SKILL.md&lt;/span&gt;
&lt;span class="p"&gt;1.&lt;/span&gt; Read the module and list its public behaviours.
&lt;span class="p"&gt;2.&lt;/span&gt; Write one test per behaviour + edge cases (empty, invalid, unauthorized).
&lt;span class="p"&gt;3.&lt;/span&gt; Colocate as &lt;span class="err"&gt;*&lt;/span&gt;.test.ts, use Vitest, no snapshot tests for logic.
&lt;span class="p"&gt;4.&lt;/span&gt; Run tests; fix failures in the code only if the test reveals a real bug.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Add a prompt library
&lt;/h2&gt;

&lt;p&gt;The same tasks come up every week. Save the prompts that work:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Debug:&lt;/strong&gt; "Find the root cause (not just the symptom), explain it in 2–3 sentences, apply the fix and add a regression test."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Plan:&lt;/strong&gt; "Before writing code, list the files you'll touch and why. Wait for my OK."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PR:&lt;/strong&gt; "Write a PR description: why, what changed, how to test, risks."&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Common mistakes
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;One giant always-on file.&lt;/strong&gt; It costs context and the agent skims it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vague rules&lt;/strong&gt; ("write clean code"). Be concrete: "no default exports", "tests next to the file".&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No globs.&lt;/strong&gt; Your Python rules load while you edit CSS.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Contradictions&lt;/strong&gt; between rules. The agent picks one at random.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Never updating them.&lt;/strong&gt; When you correct the agent twice, add a rule.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The shortcut
&lt;/h2&gt;

&lt;p&gt;Writing all of this for every project takes a while, so I built &lt;strong&gt;&lt;a href="https://viberules.netlify.app/" rel="noopener noreferrer"&gt;VibeRules&lt;/a&gt;&lt;/strong&gt;. You describe your project (stack, team size, testing, styling), preview every file, and download a ready &lt;code&gt;.cursor/&lt;/code&gt; folder with 6–8 rules, 3 skills and a prompt library. It supports Next.js, React + Vite, Node, FastAPI and full-stack TypeScript, and runs entirely in your browser with no signup. It's free during early access.&lt;/p&gt;

&lt;p&gt;Even if you write your own rules, I hope this structure saves you some trial and error.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's the one rule you always add to a new project?&lt;/strong&gt; Drop it in the comments. I'm collecting the best ones.&lt;/p&gt;

</description>
      <category>cursor</category>
      <category>ai</category>
      <category>productivity</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
