Skip to main content
< All Topics
Print

Chapter 29: Cursor Rules

Chapter 29: Cursor Rules

Last Updated: 2026-03

## 29.1 What Rules Are

Cursor rules are persistent instructions that the Cursor AI follows automatically during coding sessions. Unlike skills (which are invoked on demand), rules are applied continuously — either always, when a matching file pattern is active, or when manually triggered.

Rules live in .cursor/rules/ as .mdc (Markdown with Cursor frontmatter) files.

29.2 Rule Types

Type How Applied Use For
Always Applied to every message in every session Workspace-wide conventions (code style, import style)
Auto (glob) Applied when the referenced file types are active Language-specific rules (PHP rules for .php files)
Manual Applied only when explicitly referenced Optional patterns a user invokes selectively

29.3 Rule File Format


---
description: Short description of what this rule does
globs:
  - "**/*.php"         # Apply to all PHP files (omit for always-apply)
alwaysApply: false     # true = always; false = auto or manual
---

Rule content goes here.

Keep rules concise and specific.
Each rule should express a single coding convention or constraint.

Always-apply rule example


---
description: Keep imports at the top of files, no inline imports
alwaysApply: true
---

Always place imports at the top of the file, never inline within functions or classes.
This applies to PHP `require_once`, JavaScript/TypeScript `import`, Python `import`, and Rust `use`.

Auto-apply rule (TypeScript only)


---
description: Use exhaustive switch handling for TypeScript unions and enums
globs:
  - "**/*.ts"
  - "**/*.tsx"
alwaysApply: false
---

When switching on a TypeScript union type or enum, always handle every case.
Use a default case with a type assertion to enforce exhaustiveness at compile time:

function handleStatus(status: 'active' | 'inactive' | 'pending'): string {
  switch (status) {
    case 'active': return 'Active';
    case 'inactive': return 'Inactive';
    case 'pending': return 'Pending';
    default: {
      const _exhaustive: never = status;
      throw new Error(`Unhandled status: ${_exhaustive}`);
    }
  }
}

29.4 ITI Workspace Rules

Current rules configured for the ITI workspace:

Rule File Type Effect
no-inline-imports.mdc Always Keep imports at top of file
typescript-exhaustive-switch.mdc Auto (.ts, .tsx) Exhaustive switch for TypeScript unions

29.5 Creating a New Rule

Use the create-rule skill:

“Apply the create-rule skill to create a rule that [describes the desired behavior].”

Or manually:

  1. Create a new .mdc file in .cursor/rules/.
  2. Add the YAML frontmatter with description, optional globs, and alwaysApply.
  3. Write the rule content. Keep it concise — one rule, one concept.
  4. Test by opening a relevant file and asking the AI to perform the action the rule governs.

Rule writing guidelines

  • Be specific — vague rules are ignored or misapplied. “Write good code” is useless. “Use prepared statements for all database queries” is actionable.
  • One concept per rule — don’t combine multiple conventions in one rule.
  • Include an example — a concrete before/after example removes ambiguity.
  • Keep it short — rules should be readable in under 30 seconds.

29.6 Rules vs Skills: When to Use Which

Situation Use
A convention that applies to every file and session Rule (always-apply)
A language-specific pattern (e.g., “use async/await in TypeScript”) Rule (auto, glob to that extension)
A complex procedure with multiple steps Skill
Something invoked occasionally, not constantly Skill
A guardrail you never want the AI to violate Rule (always-apply)

Previous: Chapter 28 — Cursor Skills | Next: Chapter 30 — MCP Integrations

Table of Contents