AI Dev

Lesson 3

Rules: encode your standards once

Stop restating your conventions in every prompt — write them down where the agent picks them up automatically

By Lesson 2 you can write a precise prompt. The problem is that half of every precise prompt is the same each time:

...use TypeScript strict mode, no any. Named exports only. Data fetching goes through the useApi hook, never raw fetch. Never interpolate user input into SQL...

That is not context about this task. It is a description of how your codebase works, and repeating it is both tedious and unreliable — the day you forget it is the day you get raw fetch and a string-interpolated query.

Rules fix this by moving standing instructions out of the prompt and into files the agent picks up on its own.


What a rule is

A Cursor rule is a .mdc file — Markdown with a YAML frontmatter block — living in .cursor/rules/.

mdc
---
globs: src/**/*.tsx
alwaysApply: false
---
# React conventions
- Functional components with hooks; no class components.
- Data fetching goes through the `useApi` hook, never raw fetch.
- Co-locate component, test, and styles.

Two halves, and the frontmatter is the interesting one.

The body

Plain Markdown instructions. Short imperative bullets work best — this is guidance the model reads, not prose it admires.

The frontmatter

globs, alwaysApply, description — this is when the rule applies. It is the entire point.

Without the frontmatter you would be back to dumping every standard into every chat. With it, Cursor injects the right rule at the right time.


The four trigger types

TypeFrontmatterFires whenToken cost
AlwaysalwaysApply: trueEvery single requestPaid on every request — keep it short
Auto attachedglobs: [...]A file matching the glob is in contextOnly when the pattern matches
Agent requesteddescription: ...The agent reads the description and decidesOnly when the agent pulls it in
Manualnone of the aboveYou type @rule-nameOnly when you ask for it

Agent requested is the one worth understanding properly. Setting a description with no globs means the agent sees a one-line summary of the rule and chooses whether to load the full text. That makes the description the most important line in the file — it is the only part the agent reads before deciding.

How Cursor decides

Your requestprompt + files in contextCursor checks each rule’s triggerAlways — every requestAuto attached — a file matches its globsAgent requested — agent picks it by descriptionManual — you @mention itTriggered → injectedinto the context window, alongsideyour prompt and codeUntriggered → skippedcost no tokens at allModel generates codethat follows the rules

The right-hand branch is the payoff. A rule that does not fire is not merely inactive — it costs nothing. That is what makes it safe to have twenty rule files, and what makes one giant rules file a mistake: an always-on file pays its full token cost on every request, including the ones it has nothing to say about.


Worked examples

Three rules covering the three useful triggers.

Always-on — the project baseline. Keep this one tiny; you pay for it constantly.

mdc
---
alwaysApply: true
---
# Project base (keep this tiny)
- TypeScript strict mode; never use `any`.
- Named exports only, no default exports.
- All async code handles errors explicitly.

Auto attached — conventions for a file type. Fires only when a matching file is in context.

mdc
---
globs: src/**/*.tsx
alwaysApply: false
---
# React conventions
- Functional components with hooks; no class components.
- Data fetching goes through the `useApi` hook, never raw fetch. See @src/hooks/useApi.ts
- Co-locate component, test, and styles.

Agent requested — specialised guidance. No globs; the agent pulls it in when the description matches what it is doing.

mdc
---
description: Security standards for API routes, auth, and DB access
alwaysApply: false
---
# Security guardrails
- Never interpolate user input into SQL; parameterized queries only.
- Validate all request input with the shared Zod schemas.
- Never log secrets, tokens, or PII. Read secrets from env, never hardcode.
- Every mutating endpoint requires an authorization check.

Note the @src/hooks/useApi.ts reference in the second example. A rule can point at a canonical implementation, which is far more reliable than describing the pattern in words.


Writing rules that work

1

Small, focused files — not one big one

typescript-standards.mdc, react-conventions.mdc, security.mdc. Each can then have its own trigger, which is the entire mechanism. A single file can only have one.

2

Keep always-on rules short

Every token in an alwaysApply: true file is spent on every request, including trivial ones. Reserve it for genuinely non-negotiable, project-wide constraints.

3

Write imperatives, not explanations

“Parameterized queries only” beats a paragraph on why SQL injection is bad. The model does not need convincing; it needs the constraint stated.

4

Point at real code

A rule that says “follow the pattern in @src/hooks/useApi.ts” stays accurate as the code evolves. A rule that describes the pattern in prose goes stale silently.

5

Encode security standards as rules, not just review checks

A rule steers the model while it generates. A review catches the problem afterwards. Both are worth having, but the first is cheaper.


AGENTS.md — the broad brief

.mdc rules answer “when editing this kind of file, do X.” Some things are not file-specific at all: how the repository is laid out, how to build and test it, what never to touch. That is what AGENTS.md is for — a single “README for agents” that is generally relevant regardless of what is being edited.

Put in it:

  • How the repo is laid out — the map, and which directory owns what
  • How to build, test and run — the exact commands
  • Non-negotiables — “don't touch X”, “prefer Y”
  • Where the docs live
AGENTS.md.cursor/rules/*.mdc
ShapeOne broad document, or a fewMany small rules
ScopingWhole-projectBy glob, or always, or on request
Best for“How this repo works”“When editing TS, do X”
PortabilityHigh — a common convention across toolsCursor-native

They are complements, not alternatives. AGENTS.md carries the project brief; .mdc files carry the conditional detail.


Planning documents are not agent policy

A third artefact often gets confused with the first two: your own plan — a roadmap, a status page, a list of decisions and priorities. Perhaps a plan.html you open in a browser.

That is for you, not for the agent. It tracks what is being done. Rules describe how to behave while coding. Mixing them produces a rules file full of stale task lists and a plan nobody reads.

What it isWhere it goesWho reads it
Task plan, roadmap, status, decisionsplan.htmlYou — or the agent, when you @ it deliberately
Stable, project-wide agent instructionsAGENTS.mdThe agent, generally
File-type and domain conventions.cursor/rules/*.mdcThe agent, conditionally

You do not need AGENTS.md to replace your planning document. Keep planning in whatever format you find readable; use rules only when you want the agent to inherit conventions without you pasting them each time.


User Rules — personal and global

Cursor also has User Rules, set in settings rather than in the repository. They apply to every project you open and travel with your account, not your team.

Belongs in User Rules

  • How you like explanations pitched
  • Preferred response length and tone
  • “Show me the diff before applying”
  • Personal editor and workflow habits

Belongs in the repo instead

  • Architectural constraints
  • Security standards
  • Framework and library conventions
  • Anything a teammate also needs

The test is simple: would a new teammate need this to work correctly? If yes, it belongs in the repository where they will actually get it. Personal preferences in a team repo are noise; team standards in your personal settings are invisible to everyone else.


The whole landscape

Cursor is not the only tool reading instruction files, and the same repository often carries several. Each has a distinct scope and a distinct token-cost profile.

File patternToolScope & triggerPrimary functionToken cost
~/.claude/settings.jsonClaude CodeGlobal userPersonal formatting preferences and base hooksMinimal static footprint
CLAUDE.md (root)Claude CodeRepository rootStack setup, build commands, core constraintsKeep well under ~60 lines
CLAUDE.md (subdirectory)Claude CodeDirectory pathPath-specific domain logic and API schemasLoaded on entering that path
.mdc — alwaysApply: trueCursorGlobal projectNon-negotiable architectural mandatesPermanent — paid every request
.mdc — globs: [...]CursorPattern matchLanguage or framework-specific rulesOnly when a matching file is open
.mdc — alwaysApply: falseCursorSemantic matchSpecialised edge-case workflows or refactorsRetrieved when the agent judges it relevant

The column that matters is the last one. Instruction files are not free, and the discipline is the same across every tool: make the expensive ones small and the specific ones conditional.


Common mistakes

MistakeWhat goes wrong
One large always-on rules fileEvery request pays for guidance it does not need, and nothing can be scoped
Vague descriptions on agent-requested rulesThe agent has nothing to match against, so the rule loads inconsistently
Describing a pattern in prose instead of linking the fileThe description drifts out of date and nobody notices
Task lists inside rule filesStale work items get injected as if they were standards
Team standards in personal User RulesYour code follows them, your teammates’ does not, and reviews get inconsistent
Rules nobody revisitsThe codebase moves on and the agent keeps enforcing last year’s conventions

Recap

Lesson 4 turns to the other side of the contract: what to hunt for in a diff before it reaches main.

Check your understanding

1 / 10
the .mdc rule file: YAML frontmatter plus markdown body

What does the YAML frontmatter in an .mdc file control?

Test your understanding

Prof is ready

Prof will ask you questions about Encoding engineering standards as Cursor rules — not explain it. You'll be surprised what you don't know until you have to say it.

Finished this lesson?

Read through the lesson first (0/20s).