This skill should be used when creating or editing Cursor rules files (.mdc format) in the .cursor/rules directory...
Guide for creating and editing Cursor rules files (.mdc format) that provide context-aware instructions to the AI in Cursor IDE.
Cursor rules are instructions that guide AI behavior in Cursor IDE. Rules use the MDC format (.mdc) with YAML frontmatter and markdown content, stored in .cursor/rules/ directories.
Key capabilities:
Context: All Cursor rules guidance in this skill applies to .mdc files only, not .cursorrules (deprecated) or AGENTS.md files.
Use this skill when:
Cursor rules use MDC format combining YAML frontmatter with markdown content.
---
description: Brief explanation of rule's purpose
globs: ["**/*.ts", "**/*.tsx"]
alwaysApply: false
---
# Rule Content
Markdown instructions for the AI...
description (string, required for Agent Requested rules)
description: TypeScript coding standards including type safety and error handling patterns
globs (array of strings, optional)
globs: ["**/*.ts", "**/*.tsx"] # TypeScript files
globs: ["src/api/**/*"] # API directory
globs: ["**/*.test.ts"] # Test files
alwaysApply (boolean, default: false)
true: Rule always included in model contextfalse: Rule applied based on type and conditionsalwaysApply: true # For critical standards that always apply
alwaysApply: false # For context-specific guidance
Cursor provides four rule types controlling when rules are applied. Choose the type based on how broadly the rule should apply.
When to use: Critical standards that apply to all AI interactions in the project.
Configuration:
---
description: Core coding standards
alwaysApply: true
---
Characteristics:
Example use cases:
When to use: Context-specific guidance that applies when working with certain file types or directories.
Configuration:
---
description: React component patterns
globs: ["**/*.tsx", "src/components/**/*"]
alwaysApply: false
---
Characteristics:
Example use cases:
.tsx files)src/api/**/*)*.test.ts files)When to use: Guidance that AI should evaluate for relevance based on the task.
Configuration:
---
description: Database migration patterns for PostgreSQL schema changes
alwaysApply: false
---
# Note: No globs - AI decides based on description
Characteristics:
description fieldExample use cases:
When to use: On-demand guidance invoked explicitly in chat.
Configuration:
---
description: Debugging workflow for production issues
alwaysApply: false
---
# Note: No globs - invoked with @ruleName
Characteristics:
@ruleName in chatExample use cases:
Usage:
@debug-production help me investigate the API timeout issue
Apply AI instruction writing best practices to create clear, actionable Cursor rules.
Keep rules under 500 lines
Be specific and actionable
Use progressive disclosure
Include concrete examples
@filename.ts syntax to reference existing project filesImperative/infinitive form (verb-first), not second person:
✓ Good: "Validate input before API requests"
✗ Bad: "You should validate input before you make API requests"
Consistent terminology:
✓ Good: Always use "component" for React components
✗ Bad: Mix "component", "element", "widget" interchangeably
Objective, instructional language:
✓ Good: "Return explicit error types rather than throwing exceptions"
✗ Bad: "Hey, try to return errors instead of throwing them if possible"
XML tags help structure complex rules for clearer parsing. Use them for:
Multiple examples requiring distinction:
<example type="valid">
const result = await fetchData();
if (!result) {
return { error: "Not found" };
}
return result;
</example>
<example type="invalid">
// Don't assume success
return (await fetchData()).data;
</example>
Separating context from instructions:
<context>
This project uses Zod for runtime validation with React Query for data fetching.
</context>
<instructions>
When creating API clients:
1. Define Zod schema for response
2. Create React Query hook using the schema
3. Export both for component consumption
</instructions>
Defining templates:
<template>
export const use[EntityName] = () => {
return useQuery({
queryKey: ['[entity]'],
queryFn: async () => {
const response = await fetch('/api/[endpoint]');
return [Schema].parse(await response.json());
}
});
};
</template>
Skip XML tags when markdown structure is sufficient for simple content.
Use @filename syntax to reference existing project files as examples:
## Component Patterns
Follow the patterns in @src/components/Button.tsx for all interactive components:
- Props interface with TypeScript
- Forwarded refs for accessibility
- Consistent event handler naming
This grounds the AI in actual project code rather than abstract descriptions.
Purpose: Critical standards applying to all code.
---
description: TypeScript and code quality standards
alwaysApply: true
---
# Code Standards
## Type Safety
- All functions must have explicit return types
- No `any` types without justification comment
- Use discriminated unions for complex state
## Error Handling
- Return Result<T, E> types for operations that can fail
- Never silently catch and ignore errors
- Log errors with context before re-throwing
## Testing
- All exported functions must have unit tests
- Integration tests for all API endpoints
- Minimum 80% code coverage
Purpose: File-type or directory-specific conventions.
---
description: React component patterns and conventions
globs: ["**/*.tsx", "src/components/**/*"]
alwaysApply: false
---
# React Component Standards
## Component Structure
<template>
interface [ComponentName]Props {
// Props definition
}
export const [ComponentName] = forwardRef<
HTMLElement,
[ComponentName]Props
>((props, ref) => {
// Implementation
});
[ComponentName].displayName = '[ComponentName]';
</template>
## Examples
<example type="valid">
// Interactive component with forwarded ref
interface ButtonProps {
onClick: () => void;
children: React.ReactNode;
}
export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
({ onClick, children }, ref) => (
<button ref={ref} onClick={onClick}>
{children}
</button>
)
);
Button.displayName = 'Button';
</example>
<example type="invalid">
// Missing ref forwarding and display name
export const Button = ({ onClick, children }) => (
<button onClick={onClick}>{children}</button>
);
</example>
Purpose: Step-by-step procedures invoked on-demand.
---
description: Pre-deployment verification checklist
alwaysApply: false
---
# Deployment Checklist
Invoke with: @deploy-checklist
## Pre-Deployment Verification
### 1. Code Quality
- [ ] All tests passing (`npm run test`)
- [ ] No TypeScript errors (`npm run type-check`)
- [ ] Linter passing (`npm run lint`)
- [ ] No console.log or debugger statements
**Validation:** Check CI pipeline status
### 2. Security Review
- [ ] No hardcoded secrets or API keys
- [ ] Environment variables properly configured
- [ ] Dependencies updated (no critical vulnerabilities)
**Validation:** Run `npm audit` and review results
### 3. Database Migrations
- [ ] Migrations tested locally
- [ ] Rollback plan documented
- [ ] Backup completed
**Validation:** Verify migration scripts in `db/migrations/`
### 4. Deployment
Follow standard deployment process:
1. Deploy to staging
2. Run smoke tests
3. Get approval from lead
4. Deploy to production
5. Monitor for 15 minutes
Purpose: Domain-specific patterns AI loads when relevant.
---
description: Performance optimization patterns for React applications
alwaysApply: false
---
# React Performance Optimization
## When to Optimize
Optimize when:
- Components re-render unnecessarily (use React DevTools Profiler)
- User interactions feel laggy (>100ms response)
- Large lists without virtualization
## Optimization Techniques
### Memoization
<instructions>
Use `useMemo` for expensive computations:
- Complex filtering/sorting operations
- Derived state calculations
- Object/array creation in render
</instructions>
<example type="valid">
const filteredItems = useMemo(
() => items.filter(item => item.category === selectedCategory),
[items, selectedCategory]
);
</example>
<example type="invalid">
// Recreates array on every render
const filteredItems = items.filter(item =>
item.category === selectedCategory
);
</example>
### Component Memoization
<instructions>
Use `React.memo` for expensive presentational components:
- Complex rendering logic
- Large component trees
- Components receiving stable props
</instructions>
Refer to @src/components/DataTable.tsx for production example.
❌ Vague, high-level guidance
✗ Bad: "Write clean, maintainable code following best practices"
✓ Good: "Extract functions exceeding 50 lines into smaller units with single responsibilities"
❌ Overly broad Always rules
✗ Bad: 500-line rule with alwaysApply: true covering all coding standards
✓ Good: Focused 100-line rule for critical standards + separate Auto Attached rules for context-specific patterns
❌ Missing concrete examples
✗ Bad: "Use proper error handling"
✓ Good: Show specific error handling pattern with code example
❌ Inconsistent terminology
✗ Bad: Mix "API endpoint", "route", "path", "URL" for same concept
✓ Good: Choose "API endpoint" and use consistently
❌ Conversational language
✗ Bad: "Hey, when you're working with APIs, make sure you handle errors properly, okay?"
✓ Good: "Handle API errors by returning Result<T, Error> types"
❌ Temporal references
✗ Bad: "Use the new authentication system" or "Recently refactored to async/await"
✓ Good: "Use OAuth 2.0 authentication" (evergreen, specific)
❌ No glob patterns for context-specific rules
✗ Bad: React-specific rule without globs (always loads unnecessarily)
✓ Good: React rule with globs: ["**/*.tsx"] (loads only when relevant)
Before finalizing a Cursor rule:
Format & Structure:
.mdc format with YAML frontmatter.cursor/rules/ directoryRule Type Configuration:
alwaysApply: true only for critical project-wide standardsglobs configured for Auto Attached rulesdescription clear and specific for Agent Requested rulesContent Quality:
@filename syntaxSpecificity:
Token Efficiency:
Comprehensive example showing best practices:
---
description: API client patterns using Zod schemas and React Query hooks
globs: ["src/api/**/*", "**/*-client.ts"]
alwaysApply: false
---
# API Client Patterns
## Overview
This project separates API clients (Zod schemas + React Query hooks) from UI components.
**Pattern:** Schema definition → Client function → React Query hook → Component consumption
## Client Structure
<template>
// 1. Define Zod schema
const [Entity]Schema = z.object({
id: z.string(),
// ... fields
});
type [Entity] = z.infer<typeof [Entity]Schema>;
// 2. Create client function
async function fetch[Entity](id: string): Promise<[Entity]> {
const response = await fetch(`/api/[entity]/${id}`);
return [Entity]Schema.parse(await response.json());
}
// 3. Create React Query hook
export function use[Entity](id: string) {
return useQuery({
queryKey: ['[entity]', id],
queryFn: () => fetch[Entity](id),
});
}
</template>
## Error Handling
<instructions>
All client functions must handle errors consistently:
1. Parse responses with Zod (throws on invalid data)
2. Catch network errors and re-throw with context
3. React Query handles loading/error states
</instructions>
<example type="valid">
async function fetchUser(id: string): Promise<User> {
try {
const response = await fetch(`/api/users/${id}`);
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const data = await response.json();
return UserSchema.parse(data);
} catch (error) {
console.error('Failed to fetch user:', { id, error });
throw error;
}
}
</example>
<example type="invalid">
// Missing error context and response validation
async function fetchUser(id: string): Promise<User> {
const response = await fetch(`/api/users/${id}`);
return UserSchema.parse(await response.json());
}
</example>
## Reference Implementation
See @src/api/user-client.ts for production example implementing this pattern.
## Validation
Before completing API client:
- [ ] Zod schema covers all response fields
- [ ] Client function includes error handling
- [ ] React Query hook properly configured
- [ ] Types exported for component consumption
Remember: Effective Cursor rules are specific, actionable, and scoped appropriately. When in doubt, create focused rules with Auto Attached globs rather than broad Always rules.