| name | Cursor Skill (.mdc) Authoring |
| description | Author effective Cursor rules in .cursor/rules/*.mdc - YAML frontmatter (description, globs, alwaysApply), the four rule types, scoped QA rules, subagents, and structure that actually steers the model. |
| version | 1.0.0 |
| author | thetestingacademy |
| license | MIT |
| tags | ["cursor","mdc","cursor-rules","ai-rules","rules-for-ai","prompt-engineering","qa-automation","subagents","agent-config"] |
| testingTypes | ["unit","integration","e2e"] |
| frameworks | ["playwright","vitest","pytest","jest"] |
| languages | ["typescript","python","javascript"] |
| domains | ["web","api","ai"] |
| agents | ["claude-code","cursor","github-copilot","windsurf","codex","aider","continue","cline","zed","bolt","gemini-cli","amp"] |
Cursor Skill (.mdc) Authoring Skill
You are an expert at writing Cursor rules - the .mdc files in .cursor/rules/ that steer Cursor's AI. When the user asks you to create or improve a Cursor rule (especially for testing/QA conventions), you write a correctly typed .mdc with valid YAML frontmatter, scope it precisely with globs, keep it short and imperative, and reference example files instead of pasting walls of code. You never write one giant catch-all rule; you write small, composable, well-scoped rules.
Core Principles
.mdc lives in .cursor/rules/, not the legacy root file. Modern Cursor uses .cursor/rules/*.mdc. Nested rules in subfolders (packages/api/.cursor/rules/) scope to that part of the tree.
- The frontmatter fields decide when the rule fires.
description, globs, and alwaysApply together select one of four rule types. Get these wrong and the rule never activates - or always does.
- Four rule types, one chosen by frontmatter. Always, Auto-Attached, Agent-Requested, and Manual. Pick deliberately; do not default everything to
alwaysApply: true.
description is the trigger for Agent-Requested rules. When alwaysApply is false and globs is empty, the model reads description to decide relevance. Write it as a clear "use this when..." sentence.
- Scope with
globs, not prose. A rule that only matters for tests should be glob-scoped to **/*.test.ts, not a paragraph saying "only apply to tests."
- Keep rules short and imperative. Under ~500 lines, ideally far less. Bullet directives beat essays. The rule competes for the model's attention with the actual task.
- Reference files with
@, do not paste them. @tests/example.spec.ts pulls in a canonical example on demand instead of bloating every prompt.
- One concern per rule file. A "Playwright conventions" rule and a "PR description format" rule are two files. Composable rules are easier to scope and maintain.
The Four Rule Types
| Type | alwaysApply | globs | description | When it fires |
|---|
| Always | true | - | - | Injected into every prompt in the project |
| Auto-Attached | false | set | optional | When a file matching globs is in context |
| Agent-Requested | false | empty | required | When the model judges it relevant from the description |
| Manual | false | empty | empty | Only when invoked explicitly with @ruleName |
File Layout
project/
.cursor/
rules/
000-core.mdc # Always: project-wide non-negotiables
testing-playwright.mdc # Auto-Attached: globs **/*.spec.ts
testing-pytest.mdc # Auto-Attached: globs tests/**/*.py
pr-format.mdc # Agent-Requested: description-triggered
legacy-migration.mdc # Manual: invoked with @legacy-migration
packages/
api/
.cursor/rules/
api-contracts.mdc # nested: scoped to the api package
Anatomy of an .mdc File
---
description: TypeScript end-to-end test conventions using Playwright.
globs: ["**/*.spec.ts", "tests/**/*.ts"]
alwaysApply: false
---
# Playwright E2E Conventions
When writing or editing Playwright tests in this project:
- Use `getByRole`, `getByLabel`, `getByText` locators. Do NOT use raw XPath.
- Never use `page.waitForTimeout`. Rely on auto-wait and web-first assertions.
- Assert with `await expect(locator).toBeVisible()` - never fetch a value
manually and compare it.
- One `test()` verifies one behavior. Use `test.step()` to label phases.
- Page Objects live in `tests/pages/*.page.ts` with `Locator` fields built
in the constructor.
See the canonical example: @tests/pages/login.page.ts
The frontmatter here makes it Auto-Attached: it activates whenever a .spec.ts file is open or referenced, without the model having to decide.
Rule Type 1: Always (project core)
Use sparingly - it costs context on every single prompt. Reserve it for genuinely universal rules.
---
alwaysApply: true
---
# Project Core Rules
- Package manager is pnpm. Never suggest `npm install` or `yarn`.
- TypeScript strict mode is on. No `any` without an inline justification comment.
- Tests are required for every new function in `src/`. No PR merges without them.
- Follow Prettier: single quotes, semicolons, 100-char width.
Rule Type 2: Auto-Attached (the workhorse for QA)
This is the right type for most testing conventions: it fires exactly when a matching test file is in play.
---
description: Python test conventions with pytest.
globs: ["tests/**/*.py", "**/test_*.py"]
alwaysApply: false
---
# Pytest Conventions
- Use fixtures from `conftest.py`; never write unittest setUp/tearDown.
- Default fixtures to function scope; widen only for expensive read-only resources.
- Parametrize cases with `@pytest.mark.parametrize` and always pass `ids=`.
- Mock at the point of use with the `mocker` fixture: patch where the name is
looked up, not where it is defined.
- Name tests `test_<unit>_<condition>_<expected>`.
- All markers must be declared in pyproject.toml (suite runs with --strict-markers).
Reference fixture setup: @tests/conftest.py
Rule Type 3: Agent-Requested (description-triggered)
No globs - the model reads description and decides. Write the description as an explicit trigger.
---
description: >
Use when writing a pull request title or description. Enforces the
Conventional Commits style and the required QA checklist.
alwaysApply: false
---
# PR Description Format
When asked to draft a PR:
- Title: `type(scope): summary` (feat, fix, test, refactor, chore).
- Body must include a "## Testing" section listing how the change was verified.
- Include a checklist: [ ] unit tests, [ ] e2e if UI changed, [ ] no skipped tests.
- Link the issue with `Closes #<n>`.
Rule Type 4: Manual (invoked on demand)
Empty description and globs. Fires only when the user types @rule-name. Good for heavy, occasional workflows.
---
description:
globs:
alwaysApply: false
---
# Legacy Selenium -> Playwright Migration
(Invoke with @legacy-migration when porting an old test.)
- Map By.id/By.cssSelector to getByLabel/getByRole.
- Delete every WebDriverWait; replace with web-first `expect` assertions.
- Convert the Java Page Object to a TS class with lazy Locator fields.
- Keep both suites green; migrate one page at a time.
Subagents: Delegating QA Work
Cursor can spawn subagents for focused, parallel work. Define them so a parent agent can hand off bounded tasks (e.g., "write the tests" while the main thread keeps building). Keep each subagent single-purpose with an explicit success criterion.
---
description: Use to spin up a focused test-writing subagent for a single module.
alwaysApply: false
---
# Test-Author Subagent
When delegating test creation, instruct the subagent to:
1. Read ONLY the target module and its existing tests.
2. Write tests following @.cursor/rules/testing-pytest.mdc (or the matching
framework rule for the file type).
3. Cover: happy path, each error branch, and boundary inputs.
4. Run the suite and report pass/fail counts. Do NOT edit source code.
5. Success criterion: new tests pass and branch coverage for the module is >= 85%.
Keep the subagent's scope to one module so its context stays small and focused.
Writing Effective QA Rules
A rule that steers the model well is concrete, scoped, and shows an example.
---
description: API contract test conventions.
globs: ["**/*.contract.test.ts"]
alwaysApply: false
---
# API Contract Tests
- Validate responses against the Zod schema in `@src/schemas`, not ad-hoc asserts.
- Test the status code AND the body shape for every endpoint.
- Include at least one 4xx case (bad input) per endpoint.
- Use the shared `apiClient` fixture; never construct fetch calls inline.
Good:
\`\`\`ts
const res = await apiClient.post('/orders', { amount: -1 });
expect(res.status).toBe(422);
expect(() => OrderSchema.parse(res.body)).toThrow();
\`\`\`
Bad: asserting only `expect(res.status).toBe(200)` with no body validation.
Best Practices
- Choose the rule type on purpose. Default to Auto-Attached for anything file-specific (most QA rules). Reserve Always for true universals; it taxes every prompt.
- Make
description an explicit "use when..." sentence for Agent-Requested rules. The model triggers on it - vague descriptions never fire.
- Scope with
globs, not prose. globs: ["**/*.spec.ts"] is enforceable; "apply only to test files" written in the body is a hope.
- Keep each rule under ~500 lines and single-concern. Short, imperative bullets win attention; one topic per file keeps scoping clean.
- Reference canonical files with
@path. Pull in one good example on demand instead of pasting code into every prompt.
- Number Always rules (
000-core.mdc) to control ordering. Predictable load order avoids surprising overrides.
- Use nested
.cursor/rules/ for monorepos. A package-local rule scopes naturally to that package's tree.
- Give subagents a bounded scope and an explicit success criterion. "Write tests for this one module, do not touch source, target 85% coverage" keeps delegation reliable.
Anti-Patterns to Avoid
alwaysApply: true on everything. It floods every prompt with irrelevant rules and dilutes the ones that matter. Scope instead.
- Agent-Requested rule with a vague or empty
description. With no globs and no clear description, the model has nothing to trigger on - the rule is dead.
- One giant
rules.mdc covering testing, style, git, and architecture. Unscopable and unmaintainable. Split into focused files.
- Pasting whole example files into the rule body. It balloons context. Use
@file references.
- Writing scope as prose instead of globs. "Only for tests" in the body still loads the rule everywhere; the model may apply it to non-test files.
- Essays and rationale dumps. Rules are directives, not documentation. State what to do, not three paragraphs of why.
- Subagents with open-ended scope. "Improve the tests" with no boundary lets a subagent wander into source files and rack up context. Bound it.
When to Trigger This Skill
Trigger when the user asks to:
- Create or edit a Cursor rule,
.mdc file, or .cursor/rules/ config
- Set up "rules for AI" / coding conventions for Cursor
- Choose between Always / Auto-Attached / Agent-Requested / Manual rule types
- Write QA or testing conventions that Cursor should follow
- Configure Cursor subagents for delegated test work
- Fix a Cursor rule that never activates or always activates
This skill is specific to Cursor's .mdc rule format. For authoring portable SKILL.md skills (this directory's format) or Claude Code skills, use the relevant skill-authoring guidance instead.