Cursor lee archivos de reglas desde .cursor/rules y los inyecta en el contexto del modelo, de modo que las convenciones de tu proyecto sobreviven entre chats. Esa parte es fácil. Lo difícil es escribir una regla que el modelo realmente siga. La mayoría de las reglas que circulan falla de una de tres formas: se ignoran en silencio (formato de archivo incorrecto), se cargan en el momento equivocado (tipo de activación incorrecto) o están escritas en un estilo que degrada de forma medible a los modelos actuales. Esta guía cubre las tres: la anatomía del .mdc, los cuatro tipos de regla y lo que la investigación dice que debe ir dentro de una regla.
Qué es una Cursor Rule y cuándo la necesitas
Una Cursor Rule es un archivo markdown con frontmatter YAML, guardado con la extensión .mdc dentro de .cursor/rules/ en la raíz de tu proyecto. Cuando una regla se activa, Cursor antepone su cuerpo al contexto del modelo para esa petición. Las reglas viven en el repo, así que todo el equipo las comparte, y los directorios .cursor/rules anidados en subcarpetas permiten que un monorepo delimite reglas por paquete.
Escribe una regla cuando te descubras corrigiendo a la IA por lo mismo dos veces: sigue sugiriendo componentes de clase, sigue importando desde la ruta equivocada, sigue escribiendo SQL crudo donde tu código usa un query builder. Las reglas son para hechos que el modelo no puede descubrir por sí mismo y convenciones que difieren de los valores por defecto del framework.
No escribas una regla para cosas que el modelo ya sabe (cómo funciona npm install) ni para cosas que un linter aplica mejor (formato, orden de imports). Cada regla gasta tokens de contexto; gástalos en señal específica del proyecto.
Dos notas de mantenimiento. El archivo único legado .cursorrules en la raíz del repo todavía funciona pero está deprecado; migra su contenido a .cursor/rules/. Y el fallo más común de todos: un archivo .md plano dentro de .cursor/rules se ignora en silencio. Sin aviso, sin error. La extensión debe ser .mdc y el archivo necesita frontmatter.
La anatomía de un archivo .mdc
Tres campos de frontmatter y luego un cuerpo en markdown. Esta es una regla completa y funcional:
---
description: React component conventions for the design system
globs:
- "src/components/**/*.tsx"
alwaysApply: false
---
# Component conventions
- Use function components with named exports. Default exports break
our barrel-file codegen.
- Style with Tailwind utilities only. Do not add CSS Modules; the
build pipeline strips them.
- Every component accepts a className prop and merges it via cn()
from src/lib/utils.
- Data fetching lives in hooks under src/hooks, never inside
components, because components are rendered in Storybook without
a network layer.
After edits, run: npm run lint:components (it enforces the export rule).
Qué hace cada campo:
description: una oración que dice qué cubre la regla. En las reglas Agent Requested (más abajo) este es el texto que el modelo lee para decidir si la regla es relevante, así que escríbelo como la descripción de una herramienta: "Use when writing or editing React components."globs: patrones de archivos que disparan la regla. Cuando un archivo coincidente está en el contexto actual, la regla se adjunta automáticamente.alwaysApply:truecarga la regla en cada petición, sin importar los otros dos campos.
El cuerpo es markdown plano. Que sean instrucciones, no documentación: viñetas imperativas cortas, rutas de archivo concretas, comandos ejecutables y una razón adjunta a cada prohibición.
Los cuatro tipos de regla y cómo elegir el alcance
La combinación del frontmatter determina cuándo se carga la regla:
| Tipo | Frontmatter | Cuándo se carga |
|---|---|---|
| Always | alwaysApply: true | En cada petición. globs y description se ignoran. |
| Auto Attached | globs definido, alwaysApply: false | Cuando un archivo que coincide con el glob está en el contexto |
| Agent Requested | description definida, sin globs | El modelo decide, a partir de la descripción |
| Manual | ninguno de los anteriores | Solo cuando la invocas con @nombre-de-regla |
Auto Attached es el caballo de batalla. Tus convenciones de React se cargan cuando hay un .tsx en juego, tus convenciones de API se cargan en los route handlers, tus convenciones de tests se cargan en *.test.ts, y ninguna cobra impuestos a las peticiones que no tienen que ver. Reserva Always para un puñado de fundamentos de todo el proyecto (declaración del stack, restricciones de seguridad no negociables), porque una regla Always factura tokens en cada interacción.
Una trampa que vale la pena señalar explícitamente: con alwaysApply: true, Cursor ignora tus globs. Si defines ambos, la regla se carga en todas partes y el alcance que creías tener no existe. Si querías delimitar por ruta, pon alwaysApply: false y conserva los globs. (Esta combinación exacta es una de las verificaciones de nuestro linter.)
Prefiere varias reglas estrechas sobre una amplia. Una regla por asunto, cada una delimitada a los archivos donde importa, mantiene cada inyección de contexto pequeña y relevante.
Qué incluir y qué dejar fuera
Aquí es donde la mayoría de las reglas pierde valor en silencio. Repasamos la investigación detrás de ~30 anti-patrones de archivos de contexto en nuestro artículo sobre el linter de archivos de contexto; esta es la versión corta aplicada a las Cursor Rules.
Incluye:
- Hechos no descubribles. Escollos, motivos y decisiones que el modelo no puede inferir del código: "fijamos Zod en v3 porque v4 rompe nuestro generador de OpenAPI".
- Desviaciones de los valores por defecto. El modelo asume las convenciones del framework; documenta solo donde difieres.
- Comandos. "Ejecuta npx vitest run antes de afirmar que un arreglo funciona" cambia el comportamiento. Los agentes siguen reglas ancladas a un comando y se saltan las referencias de estilo en prosa.
- Prohibiciones con razones. "Nunca uses CSS Modules, porque el build los elimina" generaliza; un "NEVER use CSS Modules" a secas no, y los modelos lo descuentan cada vez más.
Deja fuera:
- Prosa de guía de estilo sin comando. "Sigue la guía de estilo de Airbnb" se ignora. Da el comando de lint o borra la línea; nunca mandes a un LLM a hacer el trabajo de un linter.
- Volcados de árboles de directorios. El benchmark de AGENTS.md de ETH Zurich halló que los agentes ignoran las estructuras de carpetas pegadas mientras pagan aproximadamente 14-22% más tokens de razonamiento por ellas. El agente explora el árbol por sí mismo.
- Lenguaje impositivo. "CRITICAL: You MUST..." se escribió para corregir la sub-activación en modelos de la era 2024. Los modelos actuales se sobre-activan con él; Anthropic ahora recomienda un simple "Use X when...", y Cursor documentó una regresión en producción con GPT-5 causada por una instrucción "be THOROUGH".
- Inflación de énfasis. Si ocho viñetas son IMPORTANT en MAYÚSCULAS, ninguna lo es. El énfasis funciona por contraste.
- Lenguaje con evasivas. "Intenta", "si es posible", "idealmente" le dicen al modelo que la regla es opcional, y obedece. Enuncia las reglas firmes con claridad.
- Todo lo que pase de 500 líneas. Las propias docs de Cursor recomiendan mantener las reglas por debajo de 500 líneas. Pasado eso, divide en reglas enfocadas y delimitadas.
Un ejemplo trabajado: Next.js App Router más Supabase
Esta es una regla Auto Attached realista para route handlers de API en un código con Next.js y Supabase:
---
description: Conventions for App Router API route handlers
globs:
- "app/api/**/route.ts"
alwaysApply: false
---
# API route conventions
- Validate the request body with a Zod schema from src/schemas
before any I/O. Return 400 with the flattened error, never a
raw Zod error object (it leaks internal paths).
- Create the Supabase client with createServerClient from
src/lib/supabase/server. Do not import the browser client here;
it has no access to auth cookies.
- Mutating handlers call validateOrigin(req) first. Webhooks are
the only exception; they verify provider signatures instead.
- Return NextResponse.json with an explicit status. Bare
Response objects bypass our logging middleware.
Verify with: npx vitest run __tests__/api
Fíjate en lo que la hace funcionar: cada línea es específica del proyecto, cada prohibición lleva su razón, el alcance es exactamente los archivos donde aplican las convenciones, y termina con un comando de verificación ejecutable. Quince líneas de cuerpo, y ninguna es algo que el modelo habría adivinado.
Errores comunes
- Guardar como
.md. Se ignora en silencio. Usa.mdccon frontmatter. alwaysApply: truecon globs. Los globs se ignoran; la regla se carga en todas partes.- Una mega regla Always. Cada petición paga por toda ella; la mayor parte es irrelevante para cualquier tarea concreta.
- Una descripción vaga en una regla Agent Requested. "Guía general del proyecto" no le da al modelo nada contra qué comparar, así que la regla nunca se activa. Describe el disparador: "Use when writing database migrations."
- Duplicar tu linter. ESLint y Prettier ya aplican el formato de forma determinista y gratis.
- Secretos en las reglas. Las reglas se commitean y se comparten. Los archivos de reglas fueron además el vector del ataque "Rules File Backdoor" de 2025, donde Unicode invisible coló instrucciones más allá de la revisión de código, así que trata las reglas de terceros que pegues como entrada no confiable y escanéalas.
- Dejar que las reglas caduquen. Una regla que contradice el código actual es peor que ninguna regla; el modelo quema tokens tratando de reconciliarlas.
Cómo validar una regla
Dos verificaciones, una estática y una empírica.
Estática: revisa tu regla con el linter en el navegador, u offline con la CLI:
npx promptarch lint .cursor/rules/api-conventions.mdc
El linter verifica que el frontmatter exista y esté bien formado, marca la trampa de alwaysApply más globs, aplica el presupuesto de 500 líneas, escanea Unicode oculto y secretos filtrados, y puntúa la redacción contra la investigación de anti-patrones de arriba. Es gratis, no necesita cuenta y corre totalmente offline.
Empírica: abre Cursor, pide una tarea que la regla debería gobernar y revisa el panel de contexto para confirmar que la regla se adjuntó. Luego mira la salida. Si el modelo ignoró una instrucción, el arreglo suele ser especificidad: agrega la razón, agrega el comando o estrecha la regla para que la instrucción no quede enterrada.
Genera una gratis
Si prefieres partir de un borrador funcional en vez de un archivo en blanco, el generador gratuito de Cursor Rules de PromptArch te hace las preguntas estructuradas (stack, tipo de activación, globs, convenciones, restricciones) y genera un .mdc completo con el frontmatter ya elegido correctamente. Tu primera generación es gratis y sin registro en la página de prueba. Y si ya tienes reglas en tu repo, pégalas en el linter y mira qué puntaje sacan.