The Testing Academy · AI for QA

Cursor Masterclass
for QA Engineers

The customization reference, not another tour of the chat box. Write rules the agent actually follows, package your playbooks as skills, delegate to subagents, enforce policy with hooks, pick a run mode that will not run rm on your repo, connect MCP servers, drive the CLI headless in CI, and put Bugbot and cloud agents on review duty.

Project rules Skills Subagents Hooks Run modes MCP Headless CLI Bugbot

Cursor's Agent is not a chat box with autocomplete bolted on: it is a loop that reads your repo, edits files, runs your test command and drives a browser, and it will keep calling tools until the task is done. This tab covers what that loop is made of, and the approval model that decides how much of it happens without you.

agent_

Cursor for QA

Rules, skills, subagents, hooks, MCP and the CLI

Cursor is not just a chat box bolted onto an editor. It is an agent you can ground with rules, teach with skills, delegate from with subagents, fence in with hooks and run modes, and run headless in CI. Almost everything on this page is a file you commit to the repo.

📜

Rules that stick

Scoped by glob, loaded at the top of context

🧩

Skills and subagents

Playbooks, plus delegation in its own context

🔒

Hooks as policy

Block a command before the agent runs it

Headless in CI

agent -p with a committed allowlist

How a grounded Cursor setup comes together

1. GROUND
Write the rules
.cursor/rules/*.mdc

Conventions the agent reads before it touches your suite.

2. GUARD
Pick a run mode
permissions.json

Auto-review, plus the actions in .cursor/ you always want to approve.

3. PACKAGE
Ship a skill
SKILL.md

Your triage playbook, version controlled and reusable.

4. DELEGATE
Add a subagent
readonly: true

Independent verification that cannot edit a thing.

5. ENFORCE
Wire a hook
.cursor/hooks.json

Deny destructive commands before they ever run.

6. AUTOMATE
Run it headless
agent -p

One shot in CI, then schedule the recurring work.

Describe the task → the right rule, skill or subagent loads → you review the diff

A grounded sessionIllustration

What the agent loads

AGENTS.mdrules
.cursor/rules/4
.cursor/skills/3
.cursor/agents/2
.cursor/hooks.json6
.cursor/mcp.json2

Run mode

auto-review

Chat mode

planno code yet

plan mode › rule match › skill match › review

Why does the login spec fail about once in every ten runs?
Cursor AgentPLAN
  • Loaded the Playwright conventions rule, scoped by glob to tests/**.
  • Matched the flaky-test-triage skill from your description, no slash needed.
  • Read the last ten runs and the trace. In plan mode no code is written until you click build.
  • Drafted a fix plan you can edit before clicking build.
  • One shell command was denied by a beforeShellExecution hook.

Loaded from

[1]Rule.cursor/rules/playwright.mdcglob
[2]Skill.cursor/skills/flaky-test-triage/SKILL.mdmatch
[3]Agent.cursor/agents/verifier.mdreadonly
[4]Hook.cursor/hooks.jsondeny
describe the task, or / for skills and subagents

What you commit

*.mdc

Project rules

SKILL.md

Team playbooks

hooks.json

Lifecycle gates

mcp.json

External tools

.cursor/BUGBOT.md

Review rules

cli.json

CI permissions

Key capabilities

  • Plan Mode drafts an editable plan before a line is written
  • Worktrees isolate a risky refactor from your main checkout
  • The Browser tool reads console output and network traffic
  • Agent Review checks local changes before anyone else sees them
  • Bugbot reviews the pull request against your .cursor/BUGBOT.md
  • Automations run the recurring triage while you sleep

Quickstart (local)

# 1. in your shell (macOS, Linux, WSL)
curl https://cursor.com/install -fsS | bash
agent

# 2. at the prompt
/create-rule          # write your first rule
/plan                # scope before editing

# 3. in CI (PowerShell: $env:CURSOR_API_KEY = "...")
# commit a .cursor/cli.json deny list first: --force is not read only
export CURSOR_API_KEY=...
agent -p --force --output-format json "triage the failing specs"

Why this matters for QA

Your conventions, your triage playbook and your safety limits stop living in one senior tester's head. They become files in the repo that agents read instead of guessing, on your machine and in the cloud.

4Rule types
21Hook events
4Skill locations
3Run modes
5Permission tokens

What the Agent actually is

The built-in toolbelt, read as a tester

These are first-party tools, present with no setup. Read the third column as the QA job each one does.

ToolWhat it doesWhere it lands in a QA loop
Search files and foldersSearch by name, read directory structures, find exact keywords or patterns inside filesFind the existing spec before writing a duplicate one
Read filesReads file content, and reads image files (.png, .jpg, .gif, .webp, .svg) into context for vision-capable modelsDrop a failure screenshot next to the spec and have both in context
Edit filesSuggests edits and applies them automaticallyThe step that writes the test, and the step you must review hardest
Run shell commandsExecutes terminal commands and monitors outputRuns the suite, the linter, the migration
BrowserNavigates, clicks, types, scrolls, screenshots, with full access to console logs and network trafficReproduce the bug, then verify the fix, with no external tooling to install
WebGenerates search queries and performs web searchesLook up a library behaviour without leaving the loop
Fetch RulesRetrieves specific rules based on type and descriptionHow an "Apply Intelligently" rule gets pulled in (see the Rules tab)
Image generationGenerates images from text or reference images, saved to the project's assets/ folder by default and shown inline in chatFixture and placeholder assets for visual test data
Ask questionsAsks clarifying questions mid-task; while waiting it keeps reading, editing and running commands, then folds your answer inAmbiguous acceptance criteria get challenged instead of guessed

Run Modes: the one setting that decides how much autonomy you gave away

Run Modes control how the agent runs tool calls and when Cursor interrupts you for approval. They govern shell commands, MCP tools, and Fetch calls. Pick one at Settings > Agents > Approvals & Execution. Cursor recommends Auto-review as "the safest useful setup for most people".

Auto-reviewallowlist, then sandbox, then a classifier reviews the restAllowlistonly your listed actions auto-run, no classifierRun Everythingevery tool call runs, no sandbox, no classifier
Three rungs of autonomy: you are choosing how much review sits between the agent and your machine
ModeWhat runs without askingSandboxClassifierUse it when
Auto-reviewAllowlisted calls run immediately. Other shell commands run in the sandbox when possible. Calls that do not use the sandbox go to the Auto-review classifier.Yes, for shell commandsYesYou want fewer prompts with a safety review before higher-risk calls run
AllowlistActions in your allowlist run without approval. With sandboxing enabled, supported shell commands can run in the sandbox.Optional, for shell commandsNoYou want deterministic behavior with a small set of trusted repeat actions
Run EverythingEvery tool call runs automatically.NoNoYou accept the risk and want zero prompts

The order of checks inside Auto-review, in the order Cursor applies them:

  1. Is it allowlisted? If yes, it runs immediately. No sandbox, no classifier, no prompt.
  2. Can the shell command run in the sandbox? A command can be sandboxed when it works under the sandbox's file and network limits. If it can, it runs there.
  3. Anything that cannot be sandboxed goes to the classifier. Commands needing full system access (writes outside the workspace, privileged operations) fall into this bucket.
  4. The classifier picks one of three outcomes. Allow the call, ask the agent to take a different approach, or ask you to approve. If the agent decides the blocked action makes sense anyway, Cursor shows you an approval prompt.
Verbatim, and worth quoting to your team lead: "Auto-review is not a security boundary." The classifier can make mistakes: it can allow a call you would have blocked, or block a call you would have allowed. Cursor describes Run Modes generally as "best-effort guardrails rather than a hard security boundary." Treat them as ergonomics with a safety net, not as a control you can point at in an audit.
Trap: two modes you will read about and cannot pick. Ask Every Time was deprecated and new users cannot choose it; reproduce it exactly by selecting Allowlist with an empty allowlist. Run in Sandbox no longer exists as its own mode; it was folded into Allowlist with sandboxing enabled. Auto-review shipped as the recommended default.

What needs approval by default, and what quietly does not

Cursor's stated premise is that "AI can behave unexpectedly due to prompt injection, hallucinations, and other issues", so sensitive actions require manual approval by default and the docs recommend keeping those defaults on. The line between free and gated is not where most testers assume it is.

Runs with no approvalreading files and searching codeediting workspace files, straight to diskany number of tool calls in one taskStops and asks youconfiguration filesterminal commands, by defaultevery MCP tool call, connection or notVS
The surprising half is on the left: workspace edits are free and hit disk immediately
ActionDefault behaviorWhat a tester should do about it
Read files, search codeNo approval requiredUse .cursorignore to block agent access to files it should never see
Edit workspace filesNo approval required, and changes save immediately to diskAlways work on a branch. Version control is your only undo that survives
Edit configuration files (for example workspace settings)Approval requiredThis is the one file class the agent cannot silently rewrite
Terminal commandsApproval required by default; your Run Mode relaxes itAllowlist your test and lint commands, nothing that publishes or deploys
MCP connectionsApproval requiredApprove the server once, deliberately
Each MCP tool callApproval required after the connection is approvedPre-approve individual tools with an MCP allowlist if the prompting is unbearable
Arbitrary network requestsNot possible with default settingsCursor's tools reach only GitHub, direct link retrieval, and web search providers
Auto-reload plus free workspace edits is the sharp edge. The docs warn that if you have auto-reload enabled, agent changes might execute before you can review them. For a test repo with a watcher running, that means a rewritten spec can run itself.

The three protections that can override your Run Mode

These sit on top of the mode and can force an approval even when the mode would otherwise auto-run.

ProtectionWhat it does
Browser ProtectionPrevents the agent from automatically running Browser tools
File-Deletion ProtectionPrevents the agent from automatically deleting files, including rm commands
External-File ProtectionPrevents the agent from automatically creating, modifying or deleting files outside the workspace

Plans and the two usage pools

Individual planOther Models usage includedCursor Models
Start (India only, billed in INR via UPI, credit card or debit card)None, the pool is not includedGenerous included usage
ProIncluded allowanceGenerous included usage
Pro PlusLarger allowanceGenerous included usage
UltraLargest allowanceGenerous included usage
On the numbers. Plan prices, included allowances and per-model rates move. Treat the table above as the shape of the pricing (two pools, four individual tiers, two business tiers), and read the current figures off Cursor's pricing and usage dashboard before you commit a team budget.

Everything above is Cursor's default behavior. The rest of this page is about overriding it: the next tab starts with Rules, the cheapest and most portable way to change what the agent does before it does it.

Rules are persistent instructions that get inserted into the model context before the agent reads your prompt. For a QA team they are the place you encode the things you would otherwise repeat in every message: locator conventions, what a real assertion looks like, and the rule that a failing test is a finding, not a file to edit.

The four rule types and where each one lives

TypeWhere it livesScope
Project Rules.cursor/rules in the repoVersion-controlled, scoped to that codebase. The default choice for a team
User RulesDefined in Customize -> Rules, not on the file systemGlobal to your Cursor environment. Used by Agent (Chat) only
Team RulesCursor dashboard, https://cursor.com/dashboard/team-contentOrg-wide, Team and Enterprise plans. Can be made mandatory
AGENTS.mdProject root, and any subdirectoryPlain markdown, no frontmatter, no metadata. The zero-ceremony option

How a rule reaches the model, and why short beats long

.mdc fileany filename, in.cursor/rulesFrontmatter readalwaysApply, globs,descriptionTrigger decidedalways, glob, judgement,or @mentionContext startin front of your prompt
The frontmatter is the whole selection mechanism, so a wrong field means the rule never fires

Project rules: .mdc files and the frontmatter that decides everything

.cursor/rules/
  react-patterns.mdc       # Recognized as a project rule
  api-guidelines.md        # Ignored (wrong extension)
  frontend/                # Organize rules in folders
    components.mdc
Trap: a plain .md file in .cursor/rules is silently ignored. No error, no warning in chat, no entry in Customize. It is ignored because it has no frontmatter for description, globs and alwaysApply. If your carefully written testing standards are having no effect, check the extension before you rewrite the prose.

The frontmatter interaction table. This is the single thing to get right on this tab.

alwaysApplydescriptionglobsBehavior
true(any)(any)Always included. Globs and description are ignored.
false(omitted)providedAuto-attached when a matching file is in context.
falseprovided(omitted)Agent reads the description and pulls the rule in when relevant.
false(omitted)(omitted)Included only when you @-mention the rule in chat.

The same four behaviors, named as the UI names them:

Rule Type (UI label)Trigger
Always ApplyApplied to every chat session
Apply IntelligentlyWhen Agent decides it is relevant based on description
Apply to Specific FilesWhen a file matches the specified pattern
Apply ManuallyWhen @-mentioned in chat, for example @my-rule
Rule not firing? The docs name the two causes. For Apply Intelligently, make sure a description actually exists, because that string is the only thing the agent has to judge relevance by. For Apply to Specific Files, make sure the glob really matches the files you are referencing.

Glob patterns for file-scoped rules

Separate multiple patterns with commas.

PatternMatches
*Any single file name segment
**Any number of directories (recursive)
*.tsAll .ts files in the root
**/*.tsAll .ts files in any directory
src/**All files anywhere under src/
src/**/*.tsxAll .tsx files anywhere under src/
docs/**/*.md, docs/**/*.mdx.md and .mdx files under docs/ (comma-separated)
tailwind.config.*tailwind.config with any extension

AGENTS.md: rules with no frontmatter, nested by directory

project/
  AGENTS.md              # Global instructions
  frontend/
    AGENTS.md            # Frontend-specific instructions
    components/
      AGENTS.md          # Component-specific instructions
  backend/
    AGENTS.md            # Backend-specific instructions

Team Rules, enforcement, and precedence

Team Rulesdashboard, org-wide, can be enforced so users cannot disable themProject Rules.cursor/rules in the repo, committed and reviewed in pull requestsUser RulesCustomize, your machine only, Agent chat only
All applicable rules merge, and when guidance conflicts the earlier source wins
Cursor's own caveat on enforcement. Some teams use enforced rules for compliance workflows, but the docs are explicit that AI guidance should not be your only security control. A rule that says "never commit secrets" is a nudge, not a gate. If you need a gate, that is what hooks are for, covered later on this page.

Creating, referencing and importing rules

  1. Let the agent write the file. Type /create-rule in Agent and describe what you want. Agent writes the rule into .cursor/rules with the correct frontmatter, which removes the most common source of a rule that never fires.
  2. Or use the UI. Customize -> Rules -> Add Rule. The type dropdown sets description, globs and alwaysApply for you.
  3. Point at files rather than pasting them. Use @filename.ts inside the rule body, for example @migration-template.sql. Referencing beats copying: shorter rule, and it cannot go stale.
  4. Import a rule set from GitHub. Customize -> Rules -> Add Rule -> Remote Rule (Github), then paste a repo URL (public, or private that you can access). Cursor scans the repo for all .mdc files, then pulls and syncs them.
  5. Know where imports land. Imported rules go to .cursor/rules/imported/<repoName>, preserving relative paths. Review them like any other dependency before you rely on them.
  6. Keep them in review. Check rules into git so they go through PR review, and tag @cursor on a GitHub issue or PR to have Agent update a rule.

Stated limits, and the things rules do not touch

A starter QA rule set you would actually commit

Three files, one per trigger style. Together they cover roughly 80 percent of what a test-automation team keeps repeating in chat.

1. Playwright conventions, scoped to the test tree (.cursor/rules/playwright-conventions.mdc). Globs with no description, so it auto-attaches whenever a spec or page object is in context.

---
globs: tests/**/*.spec.ts, tests/**/*.page.ts
alwaysApply: false
---

- Prefer role and label based locators. Use a test id only when nothing semantic is stable
- Never use nth-child, XPath, or locators that depend on CSS class names
- Every spec opens with a test.describe named after the feature under test
- Page objects live in tests/pages and use named exports. Follow @login.page.ts
- Wait on the condition the test cares about. Never add a fixed timeout to stabilise a test

2. Test integrity, always on (.cursor/rules/test-integrity.mdc). Short on purpose: it rides along with every single request, so every line is paying rent.

---
alwaysApply: true
---

- Never delete, skip, or weaken an assertion to make a test pass
- A failing test is a finding. Report the failure and the suspected cause before changing any test file
- Do not change production code and its test in the same step without saying so explicitly
- Never commit credentials or real customer data into fixtures

3. API contract test conventions, description-driven (.cursor/rules/api-test-conventions.mdc). No globs, so Agent pulls it in when the description matches what you asked for.

---
description: Conventions for API contract tests, fixtures and response assertions
alwaysApply: false
---

- Assert status code and response schema as separate assertions so schema drift is not reported as a status failure
- Request fixtures live in tests/fixtures and are named after the endpoint they exercise
- Every negative-path test asserts on the error body, not only the status code
- Follow the fixture shape in @checkout.fixture.ts
Why file 2 is alwaysApply: true and the others are not. Test integrity is the rule you need most when the agent is not looking at a test file, for example when it decides the fastest way to green the suite is to edit the assertion. Scoping that rule to tests/** would remove it from exactly the moment it matters.

Rules are text in front of the prompt, which makes them cheap and blunt. When you need instructions that carry scripts, templates and reference files, and that load only when relevant, you want Skills: that is the next tab.

A rule tells Agent how to behave. A skill gives it a capability: a folder of instructions, scripts and reference material that loads only when it is relevant. For a QA team this is where repeatable work (triage a flake, write a test plan, run a review pass) stops living in someone's head and starts living in the repo.

What a skill actually is

Cursor startsscans every skill rootSkills registeredagent sees name anddescriptionContext matchesagent picks the relevantskillBody and files loadreferences and scripts ondemand
Discovery is automatic at startup, loading is deferred until the skill is actually needed

Where Cursor looks for skills

LocationScopeWhat that means for a team
.agents/skills/ProjectCommitted with the repo, applies to everyone who clones it
.cursor/skills/ProjectSame, and the directory /migrate-to-skills writes into
~/.agents/skills/User (global)Your machine only, available in every project, not shared
~/.cursor/skills/User (global)Same, good for personal habits you do not want to impose on the team
.agents/
└── skills/
    └── my-skill/
        └── SKILL.md

The SKILL.md frontmatter

FieldRequiredConstraints and behavior
nameYesLowercase letters, numbers and hyphens only, and it must match the parent folder name
descriptionYesWhat the skill does and when to use it. This is the text Agent reads to decide relevance
pathsNoGlob patterns scoping the skill to matching files. Accepts a comma-separated string or a list. When set, the skill is surfaced only while the agent works with matching files
disable-model-invocationNoWhen true, the skill is included only when you invoke /skill-name. Agent will not auto-apply it
metadataNoArbitrary key-value mapping for extra metadata
---
name: my-skill
description: Short description of what this skill does and when to use it.
---

# My Skill

Detailed instructions for the agent.

## When to Use

- Use this skill when...

## Instructions

- Step-by-step guidance for the agent
- Use the ask questions tool if you need to clarify requirements with the user

paths takes either a list or a comma-separated string:

---
name: react-component-patterns
description: Conventions for writing React components in this codebase.
paths:
  - "**/*.tsx"
  - "packages/ui/**/*.ts"
---
---
name: python-style
description: Style rules for Python files.
paths: "**/*.py, scripts/**/*.py"
---
The rename trap. If you rename the folder and forget the name field (or use an underscore, a capital letter or a space), the skill is invalid. name must be lowercase letters, numbers and hyphens, and it must equal the folder that directly contains SKILL.md.

Nested folders and monorepo scoping

my-monorepo/
├── .cursor/skills/          # repo-wide skills
│   └── land-it/SKILL.md
└── apps/
    └── web/
        └── .cursor/skills/  # scoped to apps/web automatically
            └── deploy-web/SKILL.md
Use this instead of clever globs. In a monorepo with an API suite and a UI suite, put each team's skills under that team's directory. Location does the scoping, so nobody has to maintain a paths pattern that drifts from the folder structure.

Scripts, references and assets

DirectoryPurpose
scripts/Executable code that agents can run
references/Additional documentation loaded on demand
assets/Static resources such as templates, images or data files
name and descriptionwhat the agent sees for every installed skillSKILL.md bodyread once the skill is judged relevantreferences/pulled in only when the instructions point at themscripts/ and assets/run or used by relative path from the skill root
Progressive disclosure: each layer costs context only when the layer above pulls it in

Built-in Cursor skills

These ship with Cursor, are managed by Cursor, and appear alongside your own. Run any of them by typing / in Agent chat. Agent may also use some automatically when a request clearly matches. The pills mark the ones a tester reaches for.

SkillWhat it does
/create-skill QA pickCreates Agent Skills, including their structure and SKILL.md files
/create-rule QA pickCreates Cursor rules with the appropriate scope and instructions
/create-subagent QA pickCreates custom subagents with focused roles and delegation instructions
/create-hook QA pickCreates Cursor hooks and updates hooks.json for agent lifecycle events
/review QA pickSelects and runs the appropriate code-review agent
/review-bugbot QA pickReviews code for likely bugs and regressions with Bugbot
/review-security QA pickReviews code for security vulnerabilities with Security Review
/automate QA pickCreates Cursor Automations triggered by schedules, Slack messages, GitHub events and other sources
/babysit QA pickMonitors a pull request and addresses feedback, conflicts, failing checks and follow-up work
/loop QA pickRuns a prompt or skill repeatedly at a specified interval
/migrate-to-skills QA pickConverts eligible dynamic rules and slash commands into Agent Skills
/canvasCreates interactive React artifacts that render alongside the conversation
/cursor-blameInvestigates AI-authored changes and the prompts that produced them
/sdkHelps build applications and integrations with the Cursor SDK
/shellRuns the provided text as a literal shell command
/split-to-prsSplits large changes into smaller pull requests
/statuslineConfigures the Cursor CLI status line
/update-cli-configUpdates Cursor CLI settings in ~/.cursor/cli-config.json
/update-cursor-settingsFinds and updates the appropriate Cursor or VS Code setting

/cursor-blame deserves a second look even though it is not on the QA list: when a regression lands in agent-authored code, it investigates the change and the prompt that produced it.

Migrating existing rules with /migrate-to-skills

# --- in Agent chat, not a terminal ---
/migrate-to-skills
/create-skill a skill that triages a flaky Playwright spec
What this tells you about the split. The rules that survive migration are exactly the ones that are conditionally relevant. Anything that must always apply, or that is bound to a file pattern, stays a rule. That is the cleanest mental model for choosing between the two.

Plugins: shipping a whole QA setup as one install

ComponentWhat it contributes
RulesPersistent AI guidance and coding standards (.mdc files)
SkillsSpecialized agent capabilities for complex tasks
AgentsCustom agent configurations and prompts
CommandsAgent-executable command files
MCP ServersModel Context Protocol integrations
HooksAutomation scripts triggered by events
my-plugin/
├── .cursor-plugin/
│   └── plugin.json
├── rules/
│   └── coding-standards.mdc
├── skills/
│   └── code-reviewer/
│       └── SKILL.md
└── mcp.json
{
  "name": "my-plugin",
  "description": "Custom development tools",
  "author": { "name": "Your Name" }
}
  1. Create the local plugin folder. ~/.cursor/plugins/local/my-plugin, with .cursor-plugin/plugin.json at the plugin root.
  2. Symlink instead of copying. That way every edit is live and you are not testing a stale copy.
  3. Reload. Restart Cursor or run Developer: Reload Window, then verify the components actually loaded in Customize.
  4. Publish when it is stable. Submit for review at cursor.com/marketplace/publish. For a repo holding several plugins, add a marketplace manifest at .cursor-plugin/marketplace.json.
# --- shell, macOS and Linux ---
ln -s /path/to/my-plugin ~/.cursor/plugins/local/my-plugin

# --- PowerShell equivalent ---
# needs Developer Mode on, or an elevated shell. Otherwise copy the folder instead.
New-Item -ItemType SymbolicLink -Path "$env:USERPROFILE\.cursor\plugins\local\my-plugin" -Target "C:\path\to\my-plugin"
Installation modeBehaviorWhen a QA lead picks it
Default OffDevelopers find it and choose to installOptional helpers, experiments, team-specific tooling
Default OnInstalled by default, developers can opt outThe house test conventions, review skills, most people should have them
RequiredAlways installed, cannot be uninstalledSafety hooks and compliance gates that are not negotiable
Marketplace deletion warning. Removing a linked MCP plugin from the marketplace, or deleting the marketplace itself, can delete the Team MCP server, which removes it for local users and for Cloud Agents. Also note Auto Refresh updates plugins already in the marketplace, but adding a brand-new plugin from the repository is not automatic, you must re-import the repository URL.

A QA skill worth committing

Flaky-test triage is the ideal first skill: it is a procedure everyone already does badly, it needs a script, it needs a reference table, and it should only surface when someone is looking at specs.

.cursor/skills/
└── flaky-test-triage/
    ├── SKILL.md
    ├── scripts/
    │   └── rerun.sh
    └── references/
        └── flake-taxonomy.md
---
name: flaky-test-triage
description: Triage an intermittent test failure. Use when a spec fails on CI but passes locally, when a spec fails only in a parallel run, or when someone asks whether a failure is a real bug or a flake.
paths:
  - "tests/**/*.spec.ts"
  - "e2e/**/*.spec.ts"
---

# Flaky Test Triage

## When to Use

- A spec failed on CI and passes on a local rerun
- The same spec fails only when the suite runs in parallel
- Someone asks whether a failure is a product bug or a flake

## Instructions

1. Re-run the single spec in isolation ten times: scripts/rerun.sh <spec-path> 10
2. If it passes every time, treat it as environment or ordering related. Check shared fixtures and seeded test data first.
3. If it fails intermittently, classify it against references/flake-taxonomy.md (wait, race, data, selector, network).
4. Never delete or skip the test. Either propose the fix, or quarantine it and open a ticket with the run log attached.
5. Report back: spec path, failure class, the evidence, the proposed fix, and whether it should block the release.
Two flags to remember together. Set disable-model-invocation: true on any skill that has side effects (anything that pushes, files a ticket, or hits an environment) so it only ever runs when a human types /skill-name. Leave it off for advisory skills like triage.

Skills give Agent new capabilities inside the same context window. When the work is large enough that it would flood that window, or when you want an independent second opinion, you hand it to a subagent instead, and you enforce the rules of engagement with hooks.

Subagents give a task its own clean context window and hand back only the result. Hooks are the opposite direction of control: spawned processes that sit in the agent loop and decide what the agent is allowed to do. Together they are how a QA team turns policy into something the tool enforces rather than something the tool is asked politely to respect.

Where subagents live, and who wins

TypeLocationScope
Project.cursor/agents/Current project only
Project.claude/agents/Current project only (Claude compatibility)
Project.codex/agents/Current project only (Codex compatibility)
User~/.cursor/agents/All projects for the current user
User~/.claude/agents/All projects for the current user (Claude compatibility)
User~/.codex/agents/All projects for the current user (Codex compatibility)
A subagent knows nothing. Subagents start with a clean context and have no access to prior conversation history. Whatever the subagent needs (the ticket, the failing spec, the branch, the acceptance criteria) has to be in the delegating prompt. This is the single most common reason a delegated task comes back useless.

The frontmatter fields

FieldTypeDefaultDescription
namestringDerived from filenameDisplay name and identifier. Use lowercase letters and hyphens
descriptionstring(none)Short description shown in Task tool hints. Agent reads this to decide delegation
modelstringinheritinherit for the parent model, or a specific model ID
readonlybooleanfalseIf true, runs with restricted write permissions: no file edits and no state-changing shell commands
is_backgroundbooleanfalseIf true, runs in the background without blocking the parent
ModeBehaviorBest for
ForegroundBlocks until the subagent completes, returns the result immediatelySequential tasks where you need the output before the next step
Background (is_background: true)Returns immediately, the subagent works independentlyLong-running tasks or parallel workstreams

A review subagent a QA team can commit as .cursor/agents/test-reviewer.md:

---
name: test-reviewer
description: Reviews test code for assertions that cannot fail, sleeps used as synchronization, and selectors bound to markup. Use proactively after any change under tests/ or e2e/.
model: inherit
readonly: true
---

You review test code. You never edit files and you never run the suite.

When invoked:
1. Read every changed spec file named in the prompt.
2. Flag assertions that cannot fail, fixed sleeps used instead of waits, selectors bound to markup rather than roles or test ids, and shared mutable fixtures.
3. For each finding give file, line, why it is unsafe, and the smallest fix.
4. End with a single verdict: safe to merge, or needs changes.

How delegation actually happens

# --- in Agent chat, not a terminal ---
/verifier confirm the auth flow is complete
/security-auditor review the payment module
/test-reviewer review the specs I changed on this branch

Parallelism, resuming and the nesting limit

The honest cost trade-off

BenefitTrade-off
Context isolationStartup overhead, each subagent gathers its own context from scratch
Parallel executionHigher token usage, multiple contexts running at once
Specialized focusLatency, often slower than the main agent for simple tasks
Reach for a subagentcontext isolation for long researchworkstreams running in parallelexpertise across many stepsindependent verification of workReach for a skilla single-purpose taska quick repeatable actionit completes in one shotno separate context window neededVS
If it fits in one shot, a skill is cheaper and faster

Subagents versus skills, as a decision

Use subagents whenUse skills when
You need context isolation for long research tasksThe task is single-purpose (generate changelog, format)
You are running multiple workstreams in parallelYou want a quick, repeatable action
The task requires specialized expertise across many stepsThe task completes in one shot
You want an independent verification of workYou do not need a separate context window

The docs are explicit about the failure mode: if you are creating a subagent for a simple single-purpose task like generating a changelog or formatting imports, make it a skill instead.

Anti-patterns

Hooks: processes that talk JSON to the agent loop

beforeSubmitPromptstop the prompt before itis sentpreToolUseallow or deny each actionpostToolUseobserve, format, auditstopreturns followup_messagesubmitted as the next user message
The stop hook closes the loop, which is why follow-ups are capped at 5 per script

Config locations and priority

SourceLocationWorking directory for relative paths
Enterprise (MDM, system-wide)macOS /Library/Application Support/Cursor/hooks.json, Linux and WSL /etc/cursor/hooks.json, Windows C:\ProgramData\Cursor\hooks.jsonThe enterprise config directory
Team (Enterprise only)Web dashboard at cursor.com/dashboard/team-content, section hooks, synced to all membersThe managed hooks directory
Project<project-root>/.cursor/hooks.jsonThe project root
User~/.cursor/hooks.json~/.cursor/
The working-directory trap, and the first thing to check when a hook never runs. Project hooks run from the project root, so the path must be .cursor/hooks/script.sh. Writing ./hooks/script.sh resolves to <project>/hooks/script.sh, which does not exist, and the hook silently does nothing. User hooks are the opposite: they run from ~/.cursor/, so ./hooks/script.sh or hooks/script.sh is correct there. Copying a snippet from one level to the other without fixing the path is the most likely cause of a hook that appears to be ignored.
  1. Write the script under .cursor/hooks/. Keep it beside the config it belongs to.
  2. Make it executable. chmod +x .cursor/hooks/format.sh on macOS and Linux. A non-executable script is a hook failure, and by default a hook failure lets the action through. On Windows there is no chmod: write the hook as a script your shell can run and point command at it.
  3. Register it in .cursor/hooks.json with the project-root relative path. Save, and Cursor reloads.
  4. Watch the Hooks output channel while you trigger it. Confirm it fired before you trust it as a control.
  5. Commit both files. Everyone on a trusted workspace gets the policy, and so do Cloud Agents.
{
  "version": 1,
  "hooks": {
    "afterFileEdit": [{ "command": ".cursor/hooks/format.sh" }]
  }
}

Command hooks and prompt hooks

Exit codeResult
0Hook succeeded, Cursor uses the JSON output
2Block the action, equivalent to returning permission: "deny" (matches Claude Code behavior for compatibility)
anything elseHook failed and the action proceeds. Fail-open by default
Per-script optionTypeDefaultDescription
commandstringrequiredScript path or command. Shell string, absolute path, or relative path
type"command" or "prompt""command"Hook execution type
timeoutnumberplatform defaultExecution timeout in seconds
loop_limitnumber or null5 for Cursor hooks, null for hooks loaded from Claude CodePer-script loop limit for stop and subagentStop hooks. null means no limit
failClosedbooleanfalseWhen true, hook failures (crash, timeout, invalid JSON) block the action instead of allowing it through
matcherpattern(none)Filter criteria for when the hook runs. Every documented example passes a string regex pattern
Hooks fail open. Read that again. If your guard script crashes, times out, or prints invalid JSON, the action it was supposed to block goes through. Any hook you are relying on as a control needs "failClosed": true, which makes a failure block instead. This is explicitly recommended for security-critical beforeMCPExecution hooks, and it applies just as much to a beforeShellExecution guard or a beforeReadFile secrets filter. A guard you have never seen fail is a guard you have never tested.

The events a QA team actually wires up

The full catalog splits into agent hooks (Cmd+K and Agent Chat): sessionStart, sessionEnd, preToolUse, postToolUse, postToolUseFailure, subagentStart, subagentStop, beforeShellExecution, afterShellExecution, beforeMCPExecution, afterMCPExecution, beforeReadFile, afterFileEdit, beforeSubmitPrompt, preCompact, stop, afterAgentResponse, afterAgentThought; tab hooks (inline completions): beforeTabFileRead, afterTabFileEdit; and app lifecycle hooks: workspaceOpen. These are the ones worth your time first.

EventFiresWhat a QA team uses it for
beforeShellExecutionBefore a terminal command runs. Input has command, cwd, sandboxBlock destructive commands and writes against shared environments. Can return allow, deny or ask
beforeReadFileBefore Agent reads a file. Input has file_path, content, attachmentsKeep credentials, prod dumps and customer fixtures out of the model. Returns allow or deny
afterFileEditAfter Agent edits a file. Input has file_path and the edits arrayRun the formatter or linter, and account for how much agent-written code landed
preToolUseBefore any tool execution, for all tool typesBroad policy in one place, narrowed with a matcher. Can also return updated_input
postToolUseAfter a successful tool call. Input adds tool_output and durationAudit trails, and injecting additional_context after a result
subagentStartBefore a subagent spawns. Input has subagent_type, task, subagent_modelAllow or deny delegation, for example blocking cloud or write-capable subagents on a release branch
subagentStopWhen a subagent completes, errors or aborts. Input has status, summary, modified_files, agent_transcript_pathRecord what a reviewer touched, and push a followup_message when it completed
beforeSubmitPromptRight after send, before the backend request. Input has prompt and attachmentsStop a prompt that carries a secret or a customer record. Output continue decides submission
stopWhen the agent loop ends. Input has status and loop_countThe test-run gate. A non-empty followup_message is submitted as the next user message
sessionStartWhen a new composer conversation is createdInject additional_context (the current branch, the environment) and set env variables available to every later hook in the session

Matchers, and what each hook matches against

HookThe matcher is tested against
preToolUse, postToolUse, postToolUseFailureTool type. Values include Shell, Read, Write, Grep, Delete, Task, and MCP tools as MCP:<tool_name>
beforeShellExecution, afterShellExecutionThe full shell command string
beforeReadFileTool type (TabRead, Read, and so on)
afterFileEditTool type (TabWrite, Write, and so on)
subagentStart, subagentStopSubagent type (generalPurpose, explore, shell, and so on)
beforeSubmitPromptThe value UserPromptSubmit
stopThe value Stop
afterAgentResponseThe value AgentResponse
afterAgentThoughtThe value AgentThought

Every documented example passes a string pattern, so write it that way:

{
  "hooks": {
    "beforeShellExecution": [
      {
        "command": "./scripts/approve-network.sh",
        "timeout": 30,
        "matcher": "curl|wget|nc"
      }
    ]
  }
}

What hook output cannot do

LimitDetail
permission: "ask" on preToolUseAccepted by the schema but not enforced. Only allow and deny take effect
permission: "ask" on subagentStartNot supported and treated as deny. Returning it silently blocks delegation
postToolUseFailure, afterTabFileEdit, afterAgentThoughtNo output fields are currently supported. Observation only
preCompactObservational only. It cannot block or modify compaction. It can show a user_message
sessionEndFire and forget. The response is logged but not used
sessionStartFire and forget. The loop does not wait for it, and session creation is not blocked even when continue is false
stop and subagentStop follow-upsCapped at 5 automatic follow-ups per script by default via loop_limit. Set it to null to remove the cap. A subagentStop follow-up is consumed only when status is "completed"

Hooks in cloud agents

Two hooks worth committing

One. Block a destructive command. The matcher narrows it to the commands you care about, and failClosed means a broken guard blocks instead of waving things through.

{
  "version": 1,
  "hooks": {
    "beforeShellExecution": [
      {
        "command": ".cursor/hooks/block-destructive.sh",
        "matcher": "rm -rf|drop table|truncate|db:reset",
        "timeout": 10,
        "failClosed": true
      }
    ]
  }
}
#!/bin/bash
json_input=$(cat)
echo "$json_input" >> /tmp/agent-audit.log
echo '{"continue": true, "permission": "deny", "user_message": "Destructive command blocked by the QA hook.", "agent_message": "That command was blocked. Use the seeded test database and the fixture reset task instead."}'
exit 0

Two. Keep the agent away from secrets. beforeReadFile receives the absolute file_path and the full content, and its output decides whether the model ever sees the file.

{
  "version": 1,
  "hooks": {
    "beforeReadFile": [
      { "command": ".cursor/hooks/guard-secrets.sh", "failClosed": true }
    ]
  }
}
{ "permission": "deny", "user_message": "Blocked: this path is on the secrets list and is never sent to the model." }

The same idea as a release gate, using stop. When the loop ends without the suite having run, hand the agent its next instruction:

{
  "version": 1,
  "hooks": {
    "stop": [
      { "command": ".cursor/hooks/test-gate.sh", "loop_limit": 2 }
    ]
  }
}
{ "followup_message": "The test suite was not run for this change. Run it now and report pass or fail before you finish." }
Set loop_limit deliberately on any stop hook. The default of 5 means a badly written gate can push five automatic follow-ups before it gives up, and each one is a full turn you are paying for. Two is usually enough for a gate. Reserve null for loops you are actively watching.

Subagents isolate context and hooks enforce policy. What decides how much rope the agent has in the first place is the mode it is running in, and what it can reach outside your repo is the MCP servers you connect. Both are next.

Plan Mode decides what gets built, Agent Review checks what got built, and checkpoints undo it when the agent gets it wrong. This tab covers those three, plus the context ring you should read before blaming the model, the browser tool that turns the agent into a manual tester, worktrees for running several agents on one repo, and MCP for wiring in the tools your team already runs.

Plan Mode: decide before you build

  1. Agent asks clarifying questions. It pins down requirements instead of guessing them.
  2. It researches your codebase. Gathering the relevant context itself, so you do not have to hand-feed files.
  3. It creates a comprehensive implementation plan. The plan, not the diff, is the artifact at this stage.
  4. You review and edit the plan. Through chat or through the markdown file.
  5. You click to build. Only now does Agent start changing files.
Clarifyagent asksquestionsResearchagent reads thecodebasePlan filesaved to home bydefaultEdit the planin chat or markdownBuildthe first codechange
The plan is the reviewable artifact, and the diff comes last
SituationMode to use
Complex feature with multiple valid approachesPlan Mode
Task touching many files or systemsPlan Mode
Unclear requirements that need exploration to understand scopePlan Mode
Architectural decision you want to review firstPlan Mode
A quick changeAgent mode, skip planning
Something you have done many times alreadyAgent mode, skip planning
Recovery pattern worth stealing. When Agent builds the wrong thing, do not patch it with follow-up prompts. Revert the changes, refine the plan to be more specific, and run it again. The docs are explicit that this is often faster than fixing an in-progress agent and produces cleaner results. For larger changes, spend the extra time on a precise, well-scoped plan: the hard part is deciding what change to make, then you delegate the implementation.

Agent Review: a second pass on local changes

How to start itWhat you get
Automatic, enabled in settingsReviews run on their own with no action from you
Slash command /agent-review in the agent window inputAn on-demand review of the current work
Source Control tabCompares all local changes against your main branch, catching issues across the full change set rather than only the latest edit
DepthSpeedCostBest for
QuickFastLowSmall diffs, formatting changes, a fast sanity check
DeepSlowHighComplex logic, security-sensitive code, large refactors

Checkpoints: the undo button that is not Git

Trap. Checkpoints are stored locally and are separate from Git. Use them only for undoing Agent changes. Use Git for permanent version control. A checkpoint will not survive as history, will not travel to a teammate, and is not a substitute for a branch.

Context: read the ring before blaming the model

Ring categoryWhat fills it
System promptCursor's own instructions for the agent
ToolsDefinitions of every available tool
RulesProject and user rules (tab 2)
SkillsSkill descriptions injected into system context (tab 3)
MCPInstructions and catalog from connected servers
SubagentsDocumentation for the subagent types the agent can launch (tab 4)
Summarized conversationOlder turns that have already been compressed
ConversationThe live turns you are working in

The Browser tool: your agent as a manual tester

CapabilityDetail
NavigateVisit URLs, follow links, go back and forward in history, refresh pages
ClickClick, double-click, right-click and hover on any visible element
TypeEnter text into inputs, fill and submit forms, search boxes, text areas
ScrollReveal additional content, find elements, explore long documents
ScreenshotCapture page state to understand layout and verify visual elements
Console outputRead console messages, JavaScript errors, debugging output, network warnings
Network trafficMonitor HTTP requests and responses, track API calls, analyze payloads, check status codes. Available in the Agent panel only
Browser approval modeBehavior
Manual approvalReview and approve each browser action individually (recommended, and the default is that browser tools require approval)
Allow-listed actionsActions matching your allow list run automatically, everything else needs approval
Auto-runAll browser actions execute immediately without approval, use with caution

Allow list and block list live at Cursor Settings > Agents > Auto-Run. The browser itself runs as a secure web view controlled by an MCP server running as an extension, with a random authentication token generated before each session and a unique random ID per tab.

# in-chat prompts, typed into the Agent input (not shell)

@browser Check color contrast ratios, verify semantic HTML and ARIA labels, test keyboard navigation, and identify missing alt text

@browser Fill out forms with test data, click through workflows, test responsive designs, validate error messages, and monitor console for JavaScript errors
Two warnings, both verbatim in the docs. "The allow/block list system provides best-effort protection. AI behavior can be unpredictable due to prompt injection and other issues. Review auto-approved actions regularly." And: "Never use auto-run mode with untrusted code or unfamiliar websites. Agent could execute malicious scripts or submit sensitive data without your knowledge." A browser session that is still logged in as your test admin account is exactly the session you do not want on auto-run against a third-party page.

Worktrees: several agents, one repo, no collisions

Key in .cursor/worktrees.jsonApplies to
setup-worktree-unixmacOS and Linux. Takes precedence over setup-worktree on Unix
setup-worktree-windowsWindows. Takes precedence over setup-worktree on Windows
setup-worktreeGeneric fallback for all operating systems
{
  "setup-worktree": [
    "npm ci",
    "cp $ROOT_WORKTREE_PATH/.env .env"
  ]
}
{
  "setup-worktree-unix": "setup-worktree-unix.sh",
  "setup-worktree-windows": "setup-worktree-windows.ps1",
  "setup-worktree": [
    "echo 'Using generic fallback. For better support, define OS-specific scripts.'"
  ]
}
# in-chat slash commands, typed into the Agent input (not shell)

/worktree fix the failing auth tests and update the login copy
/apply-worktree
/delete-worktree
/best-of-n sonnet,gpt,composer fix the flaky logout test
# shell
git worktree list
Cleanup gotcha. Cursor deletes older worktrees on an interval to limit disk usage, keeping the newest up to a machine-wide maximum across every workspace on the device. The default cap is 25 per machine, and all workspaces contribute to the same limit. Both settings are machine-scoped. Cursor re-discovers the worktree root on every cleanup pass, so worktrees created outside the manager, including ones you made with git worktree add, are eligible for deletion. Do not leave a long-lived manual checkout there.
{
  "cursor.worktreeCleanupIntervalHours": 6,
  "cursor.worktreeMaxCount": 25
}

MCP: connecting the tools your team already runs

TransportExecutionDeploymentUsersInputAuth
stdioLocalCursor managesSingle userShell commandManual
SSELocal or remoteDeploy as serverMultiple usersURL to an SSE endpointOAuth
Streamable HTTPLocal or remoteDeploy as serverMultiple usersURL to an HTTP endpointOAuth
ScopePath
Project.cursor/mcp.json, project-specific tools, commit it for the team
Global~/.cursor/mcp.json, tools available everywhere

A QA-shaped local server: run it over stdio so the credential never leaves your machine, and pull the token from the environment rather than hardcoding it.

{
  "mcpServers": {
    "server-name": {
      "command": "npx",
      "args": ["-y", "mcp-server"],
      "env": {
        "API_KEY": "${env:QA_TRACKER_TOKEN}"
      }
    }
  }
}

A remote server, HTTP or SSE, uses url and headers instead of command and args:

{
  "mcpServers": {
    "server-name": {
      "url": "https://api.example.com/mcp",
      "headers": {
        "Authorization": "Bearer ${env:MY_SERVICE_TOKEN}"
      }
    }
  }
}
STDIO fieldRequiredDescription
typeListed as requiredServer connection type, "stdio". The docs list it as required, yet none of their own mcp.json examples include it
commandYesCommand that starts the server. Must be on your system path or contain its full path
argsNoArray of arguments passed to the command
envNoEnvironment variables for the server
envFileNoPath to an environment file, for example ".env" or "${workspaceFolder}/.env"
envFile is STDIO only. Remote HTTP and SSE servers do not support it. For those, use config interpolation with environment variables set in your shell profile or system environment. Interpolation resolves in command, args, env, url, headers and auth values only, using ${env:NAME}, ${userHome}, ${workspaceFolder}, ${workspaceFolderBasename}, ${pathSeparator} and ${/}. Put a variable anywhere else in the file and it stays a literal string.

MCP approval and the security you should keep on

Team MCP allowlistadmins approve which servers and tools may run at allConnection approvalyou approve the server onceTool call approvalevery call still prompts unless allowlistedRun Mode routingthe Auto-review classifier handles what is left
Four gates, and approving the connection only clears the second one

That covers everything the desktop app gives you. The same rules, skills, MCP servers and worktrees also run from a terminal, which is where QA automation actually lives, so tab 6 takes the agent into CI.

The Cursor CLI is the same agent without the editor, and it is the piece a tester can put in a pipeline. This tab is the reference: install, modes, every flag you will use, subcommands, slash commands, headless output for CI, the permission tokens that stop it doing something stupid, and where the config actually lives.

Install: the binary is agent

# shell - macOS, Linux, WSL
curl https://cursor.com/install -fsS | bash
# shell - Windows PowerShell
irm 'https://cursor.com/install?win32=true' | iex
# shell - first run
agent
agent "refactor the auth module to use JWT tokens"
agent -p "find and fix performance issues"

The three modes

ModeWhat it doesHow to enter
AgentFull access to all tools for complex coding tasksDefault, no --mode value needed
PlanDesign your approach before coding, agent asks clarifying questionsShift+Tab, /plan, --plan, --mode=plan
AskRead-only exploration without making changes/ask, --mode=ask
Interactive: agentShift+Tab rotates Agent, Plan, Askapprove each shell command, y or nCtrl+R reviews the diffprefix & to hand off to the cloudHeadless: agent -p--output-format text, json, stream-jsonCURSOR_API_KEY, not a login prompt--trust skips the workspace prompt--force is the documented way to writeVS
The same agent with two very different safety defaults

Flag reference

Global options work with any command.

FlagValueWhat it does
-p, --printnonePrint responses to console, for scripts or non-interactive use. Has access to all tools, including write and shell
--output-formattext, json, stream-jsonOutput format, only works with --print. Default text
--stream-partial-outputnoneStream partial output as individual text deltas. Only works with --print plus stream-json
--resume [chatId]optional chat idResume a chat session
--continuenoneContinue the previous session, alias for --resume=-1
--model <model>modelModel to use
--mode <mode>plan, askSet agent mode. Agent is the default when no mode is specified
--plannoneStart in plan mode, shorthand for --mode=plan
--list-modelsnoneList all available models
-f, --forcenoneForce allow commands unless explicitly denied
--yolononeAlias for --force
--sandbox <mode>enabled, disabledSet sandbox mode
--approve-mcpsnoneAutomatically approve all MCP servers
--trustnoneTrust the workspace without prompting. Headless mode only
--workspace <path>pathWorkspace directory to use
-w, --worktree [name]optional nameRun in a new Git worktree under ~/.cursor/worktrees/<reponame>/<name>. A name is generated if you omit it
--worktree-base <branch>branch or refBranch or ref to base the new worktree on. Default is current HEAD
--skip-worktree-setupnoneSkip running worktree setup scripts from .cursor/worktrees.json
--api-key <key>keyAPI key for authentication. CURSOR_API_KEY does the same job
-H, --header <header>Name: ValueAdd a custom header to agent requests. Can be used multiple times
--plugin-dir <path>pathLoad a local plugin directory. Can be specified multiple times
-v, --versionnoneOutput the version number
-h, --helpnoneDisplay help for command
Three flag traps in one place. --output-format only works with --print. --stream-partial-output only works with --print plus stream-json. --trust is headless mode only. If a CI job is silently producing plain text when you asked for JSON, check that -p is actually there.

Subcommands

CommandWhat it doesUsage
loginAuthenticate with Cursoragent login
statusView authentication status. whoami is an alias, both take --format text|jsonagent status
modelsList available models for this accountagent models
mcpManage MCP serversagent mcp
workerStart a private cloud worker that runs agents in your environmentagent worker start
lsOpen previous chats and resume oneagent ls
resumeResume the latest chat sessionagent resume
create-chatCreate a new empty chat and return its IDagent create-chat
generate-ruleGenerate a new Cursor rule with interactive prompts. rule is an aliasagent generate-rule
install-shell-integrationInstall shell integration to ~/.zshrcagent install-shell-integration
updateUpdate Cursor Agent to the latest versionagent update

Slash commands, grouped for scanning

These are typed inside an interactive session, never in your shell.

GroupCommands
Mode and model/model [filter] (press Tab to edit), /plan [prompt], /ask, /debug [prompt], /max-mode
Execution and safety/run-everything [on|off|status] (alias /auto-run), /sandbox, /shell [command] (aliases /sh, /run)
Session control/clear (aliases /new, /new-chat, /newchat), /resume, /fork, /rename <name>, /rewind
Context/summarize (alias /compress), /copy, /copy-request-id, /copy-conversation-id
Tools and plugins/mcp [list|list-tools] [identifier], /plugin [subcommand], /bedrock [subcommand]
Display/vim, /line-numbers, /show-thinking, /status-indicators
Config and terminal/config, /setup-terminal
Housekeeping/logs, /update, /about, /help [command], /feedback <message>, /open (alias /cursor), /logout, /quit, /exit
Terminal quirks worth knowing. Shift+Enter inserts a newline instead of submitting, and works in iTerm2, Ghostty, Kitty, Warp and Zed. Under tmux, use Ctrl+J. Ctrl+J and Option+Enter are the universal alternatives that work in all terminals. Ctrl+D exits and requires a double press. ArrowUp cycles through previous messages. When a command needs sudo, Cursor shows a masked prompt and the password flows straight to sudo over a secure IPC channel, so the model never sees it.

Headless mode: putting the agent in a pipeline

Test job failsJUnit XML in reports/export CURSOR_API_KEYa CI secret, never therepoagent -p, JSON outa deny list keeps srcuntouchedParse .resultpost the triage, gate thestep
One pipeline step: safety is a committed deny list, not a flag you left off
# commit this FIRST, at .cursor/cli.json. Without it, --force means write and shell.
{
  "permissions": {
    "allow": ["Read(reports/**)", "Read(tests/**)", "Write(reports/**)"],
    "deny": ["Write(src/**)", "Write(tests/**)", "Shell(rm)", "Shell(git)", "WebFetch(*)"]
  }
}
#!/bin/bash
# shell - triage-failures.sh, run this after the test job fails
# Safe only because the deny list above is committed. The prompt is not the guard.

echo "Triaging failing tests..."

agent -p --force --output-format text "Read every JUnit XML file under reports/ and the spec files each failure names. For each failing test, classify it as product bug, test bug or environment issue, quote the assertion that failed, and write the table to reports/triage.md. Do not modify any test or source file."

if [ $? -eq 0 ]; then
  echo "Triage written to reports/triage.md"
else
  echo "Triage failed"
  exit 1
fi
# shell - other documented invocations
agent -p "What does this codebase do?"
agent -p --force "Refactor this code to use modern ES6+ syntax"
agent -p --output-format json "Analyze this image and provide a detailed description: $IMAGE_PATH" | jq -r '.result'
agent -p --force --output-format stream-json --stream-partial-output "Summarize the failing specs in reports/"
Read this before you add --force --trust to a pipeline. Print mode has access to all tools, including write and shell. --trust removes the workspace prompt and --approve-mcps automatically approves all MCP servers. That combination on a runner that checks out untrusted pull request branches is how a prompt injection becomes a shell command. Pair every one of those flags with a committed deny list.

Reading stream-json

Permissions: the part you commit

Permissions are set as permission tokens in ~/.cursor/cli-config.json (global) or <project>/.cursor/cli.json (project-specific).

TypeFormatNotes
Shell commandsShell(commandBase)commandBase is the first token in the command line. Supports glob patterns and an optional command:args syntax, for example Shell(curl:*)
File readsRead(pathOrGlob)Read access to files and directories, supports glob patterns
File writesWrite(pathOrGlob)Write access to files and directories, supports glob patterns
Web fetchWebFetch(domainOrPattern)Which domains the agent may fetch with the web fetch tool
MCP toolsMcp(server:tool)server comes from mcp.json, tool is the tool name, * is a wildcard

A permissions block a tester can commit: the agent may run the suite and read the code, but it can only write into reports/, and it can never touch secrets or delete anything.

{
  "permissions": {
    "allow": [
      "Shell(ls)",
      "Shell(git)",
      "Shell(npm)",
      "Read(src/**/*.ts)",
      "Read(tests/**)",
      "Read(reports/**)",
      "Write(reports/**)",
      "WebFetch(docs.github.com)",
      "Mcp(*:search)"
    ],
    "deny": [
      "Shell(rm)",
      "Read(.env*)",
      "Write(**/*.key)",
      "Write(**/.env*)",
      "Write(src/**)"
    ]
  }
}

Configuration, and the one limitation to remember

TypePlatformPath
GlobalmacOS and Linux~/.cursor/cli-config.json
GlobalWindows$env:USERPROFILE\.cursor\cli-config.json
ProjectAll<project>/.cursor/cli.json
Only permissions can be configured at the project level. Every other CLI setting must be set globally. So the deny list travels with the repo, but the approval mode, the sandbox setting and the model do not: they are per machine, and per runner. Note also that the project file is cli.json while the global one is cli-config.json. They are not the same filename.

Worktrees from the CLI, and the cloud handoff

# shell
agent --worktree "upgrade the test runner and fix any broken snapshots"
agent --workspace ~/src/my-app --worktree auth-fix "fix the flaky auth test and open a PR"
# in-session message - prefix with & to hand off to a Cloud Agent
& refactor the auth module and add comprehensive tests

Which is the natural handoff: once the agent runs unattended, review has to become someone else's job. Tab 7 puts Bugbot, cloud agents and automations on review duty.

Everything up to here ran on your machine, at your pace, with you watching. This tab is the other half of the job: review that happens without you, agents that run in someone else's VM, and QA chores that fire on a schedule. Bugbot guards the pull request, cloud agents do the long jobs, automations put the recurring work on a timer.

Bugbot: what it reviews and how you turn it on

Agent writes iton a local branch/review-bugbotbranch vs base,before you pushPR openeda patch-id matchskips a repeatBugbot reviewsBUGBOT.md rulesapplyFindings orAutofixneutral unless setto fail
The same reviewer runs twice, and the second run is skipped when the diff has not changed

Every way to trigger a review

TriggerWhereEffect
AutomaticNothing to typeRuns on every PR update once the repository is enabled
cursor reviewPR commentManually trigger a Bugbot review on any PR
bugbot runPR commentSame as above, alternate phrasing
cursor review verbose=truePR commentTrigger with verbose mode for detailed logs and a request ID
bugbot run verbose=truePR commentSame, alternate phrasing. This is step one of the documented troubleshooting order
@cursor remember [fact]PR commentTeach Bugbot a rule inline. It saves the fact as a learned rule and applies it to future reviews
/review-bugbotAgent sessionRun Bugbot from your agent before you push the code
/reviewAgent sessionSelects and runs the appropriate code review agent
Also worth knowing. Personal settings let you restrict Bugbot to run only when mentioned, and to run only once per PR, skipping subsequent commits. Team admins can enable Bugbot per repository, configure allow and deny lists for reviewers, and set run-only-once per installation. Team members can still override for their own PRs, including enabling reviews on draft PRs.

BUGBOT.md: the rules file both reviewers read

A QA-shaped rules file. Every clause below maps to a documented capability: blocking versus non-blocking, title and body, assignment, labels, autofix suggestions, auto-resolve.

# .cursor/BUGBOT.md

## Weakened assertions are blocking

If a diff replaces an exact assertion with a weaker one (a truthiness check in place of a
value check, a removed expect, an assertion moved inside a try block), raise a blocking Bug.
Title it "Assertion weakened" and quote the old and the new assertion in the body.
Assign it to the pull request author and apply the label "test-quality".

## Backend changes need tests

If any file under src/api/ or src/services/ changes and no file under tests/ changes in the
same pull request, raise a non-blocking Bug titled "Backend change with no test".
Suggest an autofix snippet containing a skeleton test for the changed function.

## No skipped or focused tests reach the base branch

Flag any added test.skip, test.only, it.only or xit as a blocking Bug.
Auto-resolve the finding once the line no longer appears in the diff.

## Hard waits are a smell, not a fix

Flag any added fixed-duration sleep or timeout inside tests/ as a non-blocking Bug.
Explain in the body which condition should be waited on instead. Apply the label "flaky-risk".

## No TODO or FIXME in shared test helpers

Raise a non-blocking Bug on any added TODO or FIXME comment under tests/helpers/.
Apply the label "cleanup" and assign it to the pull request author.

Running Bugbot before anyone sees the branch

Autofix and its ceiling

The check conclusion every QA lead gets wrong

Bugbot publishes a GitHub check named Cursor Bugbot and a Bitbucket build status with key cursor-bugbot. What that check reports is not what most people assume.

ConclusionWhen it is emitted
successNo issues found, and no unresolved Bugbot comments from earlier runs
neutralIssues found, or the run was cancelled by a newer commit, or an internal error. This is the default conclusion when Bugbot reports findings.
failureIssues found and the check is configured to fail on unresolved issues
skippedNever. Bugbot does not emit this conclusion
Trap. Adding Cursor Bugbot to branch protection makes Bugbot run before merge. It does not make findings block the merge, because findings default to neutral and a neutral check is not a failing check. If you want unresolved findings to stop a merge, you have to enable fail-on-unresolved-issues behavior where it is available for your organization. A quality gate that always goes green is worse than no gate, because your team stops reading it. When Autofix is on, GitHub may also show a separate Cursor Bugbot Autofix check, which only ever reports success or neutral.

Cloud agents: the long jobs you should not babysit

Start it fromHow
Cursor Webcursor.com/agents on any device. On Android, open it in Chrome and tap Install App for a PWA
Cursor DesktopSelect Cloud in the dropdown under the agent input
Cursor for iOSStart and manage agents from the iOS app
SlackUse the @cursor command
GitHub or BitbucketComment @cursor on a GitHub PR or issue, or on a Bitbucket PR
LinearUse the @cursor command
APIKick off an agent programmatically
Cursor CLIPrepend & to any message to hand the conversation off mid-flow, then pick it up on web or mobile
# in an interactive CLI session, hand the rest of the job to the cloud
& run the full regression suite against staging and attach screenshots for every failure
The limits, plainly. Cloud agent runs require a paid plan and read-write privileges on the repository plus any dependent repos or submodules. Hooks are partly different: cloud agents run command-based project hooks from .cursor/hooks.json (plus team and enterprise hooks on Enterprise plans), but user-level hooks from ~/.cursor/hooks.json never load because the VM cannot see your home directory, and hooks do not run during early read-only exploratory turns. Sharing an agent URL is view-only, and viewers must connect their own source control account and have verified access to the repository. Secrets are workspace and team scoped, added at cursor.com/dashboard/cloud-agents. Snapshots save the base environment. .env.local files are saved only if you include them at snapshot creation, so the Secrets tab is the recommended route for environment variables.

Automations: scheduled and event-driven QA work

  1. Choose a trigger. Every hour, or when a pull request is opened, or when an incident is raised.
  2. Write the prompt. Be specific about what to check, change, or produce. Reference the tools you enabled by name. Include decision rules for the different cases.
  3. Choose the tools. Send to Slack, Comment on Pull Request, MCP tools, and the rest of the list below.
  4. Decide the repository shape. One repository, a multi-repo environment, or no repository at all.
  5. Set the quality bar and save. State when the agent should open a PR, when it should only comment, and when it should do nothing. Then save and activate.
Timescheduled: a preset recurrence or a cron expressionCodesource control: PR opened, pushed, merged, comment added, CI completedConversationSlack messages and reactions, Linear issues and cyclesAlarms and glueSentry issues, PagerDuty incidents, your own webhook endpoint
The trigger catalogue is four different clocks, and QA work hangs off all of them
SourceTriggers
ScheduledRecurring schedule from preset options or a cron expression. A scheduled run may start late but never earlier than the indicated time
Source control coreSupported by every connected provider (GitHub, GitLab, and Bitbucket Cloud only, not Bitbucket Server or Data Center): Draft opened, Pull request opened, Pull request pushed, Pull request merged, Push to branch, Comment added
GitHub extrasPull request label changed, Issue label changed, CI completed, Issue comment, PR review comment, PR review submitted, Review thread updated, Workflow run completed
GitLab extrasPull request label changed, Pull request approved
Bitbucket extrasPull request approved
SlackNew message in channel, Emoji reaction, Channel created
WebhookA private HTTP endpoint you POST to. For internal systems, CI pipelines, and monitoring tools
LinearIssue created, Status changed, End of cycle
SentryIssue created, Issue updated, Any issue event
PagerDutyIncident triggered, Incident acknowledged, Incident resolved, Any incident event

Automation tools and settings

Five gotchas that will cost you an afternoon. (1) Pull request triggers do not run on fork PRs, and fail with a "Fork pull requests not supported" error, because the branch only exists on the fork. The one exception is Pull request merged, which starts from the merge commit. Push the branch to the repo itself if you need the trigger. (2) Slack triggers see only public channels, and without a message filter the New message trigger fires only on top-level messages, not threaded replies. (3) A No repository automation cannot edit code or open pull requests, so a "fix it" prompt on one will quietly produce nothing. (4) Promoting an automation to Team Owned switches it from your auth to the team's shared service account, so you must regenerate its webhook API key after the change and reconfigure any MCP or integration that relied on your personal OAuth credentials. (5) Automations always use the model's maximum supported context window with no toggle, which is convenient and also the reason a chatty automation costs more than the same prompt run locally.

Three automations worth building

  1. Nightly flaky-test triage. Scheduled trigger, single repository, tools: Read Slack channels off, Send to Slack on, Memories on. Prompt it to re-run the specs that failed in the last CI window, separate genuine failures from non-deterministic ones, and post one Slack summary grouping tests by suspected cause. Memories give it a running record of which tests keep reappearing, which is the fact your team actually wants.
  2. Test coverage check on every PR opened. Trigger: Pull request opened, plus Pull request pushed if you want it on every commit. Tools: Comment on pull request, no PR creation. Prompt it to list every behavior changed in the diff and say which of them has a test, then comment only when something is untested. Set the quality bar explicitly, otherwise it will comment on every PR and your team will mute it. This is the complement to your BUGBOT.md rules: Bugbot judges the code, this one judges the coverage.
  3. Incident to reproduction case. Trigger: PagerDuty Incident triggered or Sentry Issue created, single repository, tools: computer use and pull request creation. Prompt it to read the incident payload, reproduce the failure against the environment in .cursor/environment.json, capture a screenshot or recording, and open a PR containing a failing regression test plus the artifact. You arrive in the morning to a red test that proves the bug instead of a paragraph describing it.

Bugbot guards the PR, cloud agents do the heavy runs, and automations handle the recurring work. None of that matters until it is one continuous habit.

Next: chain all of it into one workflow →

A login test in your Playwright suite has failed twice and passed on retry both times, so nobody filed it. Here is that test going from noticed to merged fix, using one artifact from every tab on this page, in the order you would actually touch them.

The pass, step by step

  1. Ground the repo before you ask for anything. An AGENTS.md at the root stating the framework, the runner command, the fixture conventions, and the assertion style, plus one scoped .cursor/rules/flaky-triage.mdc with globs: tests/**/*.spec.ts saying how this team handles waits and retries. Without this the agent invents your conventions from the first file it opens. See rules for the frontmatter that decides when each file loads.
  2. Set the guardrails before the first prompt, not after the first accident. Pick Auto-review as your Run Mode, add autoRun.block_instructions to .cursor/permissions.json in plain English ("Every command that drops or truncates a database table should go through approval first", "Every command that pushes or force-pushes should go through approval first"), and add a beforeShellExecution hook in .cursor/hooks.json for the destructive shapes you never want to argue about. Set failClosed: true on that hook, because hooks fail open by default and a crashed guard that lets the command through is not a guard. The run modes and hooks tabs have the exact shapes.
  3. Scope it in Plan Mode instead of burning edit turns. Shift+Tab to Plan Mode and describe the symptom, not the fix: "the login spec passes on retry, find out why". The agent asks clarifying questions, researches the codebase, and produces a plan you can edit before a single line changes. Click Save to workspace so the plan is a reviewable artifact rather than a file in your home directory. If the build later goes sideways, revert and sharpen the plan; do not patch a wrong build with follow-up prompts.
  4. Isolate it in a worktree. /worktree reproduce the flaky login test gives the agent its own checkout with its own dependencies, so a half-finished experiment never blocks your main branch. Commit .cursor/worktrees.json with the setup commands (install, copy the env file from $ROOT_WORKTREE_PATH, run migrations) so every new worktree is usable on arrival. Do not symlink dependencies in; use a fast package manager instead.
  5. Reproduce it with the Browser tool. @browser plus the login URL, with instructions to run the flow ten times, watch the console and the network panel, and screenshot the state at the moment of failure. This is where flaky login tests usually confess: a race between a token refresh call and the first assertion, visible in network traffic and invisible in the test log.
  6. Package the repeatable part as a skill. The reasoning you just did (how to distinguish a genuine failure from a timing failure in this codebase) belongs in .cursor/skills/flaky-test-triage/SKILL.md with paths scoped to your spec files, so the next person does not redo it. Remember the folder name must match the name in the frontmatter. See skills.
  7. Delegate the verification to a subagent that cannot edit anything. A .cursor/agents/verifier.md with readonly: true runs in its own context window, cannot make file edits or run state-changing shell commands, and confirms the fix holds without any chance of quietly "helping" by adjusting the test. Give it everything it needs in the prompt: subagents start with a clean context and see none of your conversation.
  8. Review locally before anyone else sees it. /agent-review in the agent window, or the Source Control tab to compare all local changes against your main branch rather than only the latest edit. Pick Deep depth for logic changes, Quick for a formatting pass. Agent Review reads your BUGBOT.md files, so it enforces the same rules the PR gate will.
  9. Gate the PR with Bugbot. Run /review-bugbot before you push; the patch-id sync means the identical diff will not be reviewed twice on the PR. Your .cursor/BUGBOT.md is what catches the fix that "fixes" the flake by weakening the assertion. Configure fail-on-unresolved-issues if you want findings to actually stop a merge, because findings default to a neutral check.
  10. Run it headless in CI. The same agent, non-interactive, with a permissions block committed in .cursor/cli.json so the pipeline's allowances live in the repo and not in one engineer's head. Only permissions can be configured at the project level; every other CLI setting is global. See the CLI in CI.
  11. Schedule the recurring part. The one-off triage is done. The habit is an automation: a scheduled cloud agent that re-runs last night's failures, tells genuine failures from timing failures using the skill you wrote in step 6, and posts one grouped summary to Slack. That is the difference between fixing a flaky test and having fewer flaky tests.
# shell (macOS, Linux, WSL): the headless verification step in your pipeline
# PowerShell: $env:CURSOR_API_KEY = "your_api_key_here"
# --force allows anything the committed .cursor/cli.json deny list does not block.
# Commit that deny list before this line, not after the first incident.
export CURSOR_API_KEY=your_api_key_here
agent -p --force --output-format text "Run the login spec ten times, and write every failure with its console and network context to flaky-report.txt"
# in-session slash commands, in the order this workflow uses them
/worktree reproduce the flaky login test and capture a trace
/verifier confirm the login spec passes ten consecutive runs without a retry
/agent-review
/review-bugbot
Ground and gateAGENTS.md, rules,permissions, hooksPlan and isolatePlan Mode, then aworktreeReproduceBrowser tool,console and networkPackage andverifya skill, then areadonly subagentReview andscheduleAgent Review,Bugbot, CI,
Guardrails come first and scheduling comes last, and every box between produces a committed file

What to commit

This is the whole page as a directory listing. If you copy one thing from here, copy this table.

PathWhat it doesWho it serves
AGENTS.mdPlain markdown instructions, no frontmatter. Works at the root and in subdirectories, where nested files combine with their parents and the more specific one winsEvery agent that touches the repo, and every new joiner who reads it as onboarding
.cursor/rules/*.mdcScoped rules with description, globs, and alwaysApply frontmatter deciding when each one loads. A .md file here is silently ignoredThe reviewer who is tired of leaving the same comment
.cursor/skills/<name>/SKILL.mdA packaged procedure with optional scripts/, references/, and assets/. The folder name must match the name fieldThe next tester who inherits the flow and should not rediscover it
.cursor/agents/*.mdSubagent definitions with description, model, readonly, and is_background. The description is what decides whether delegation happens at allAnyone who wants verification done by something that cannot edit the code
.cursor/hooks.jsonLifecycle gates over the agent loop. Project hooks run from the project root, so paths look like .cursor/hooks/guard.shThe QA lead who needs policy that does not depend on anyone remembering it
.cursor/mcp.jsonMCP servers for this project, in stdio, SSE, or Streamable HTTP form, with interpolation for secretsTesters who need the tracker, the observability tool, or the test-data service in-session
.cursor/permissions.jsonautoRun.allow_instructions and autoRun.block_instructions, written in plain English. Merges with your personal file. A team dashboard configuration overrides bothEveryone sharing the repo, especially on the day someone runs an agent against production config
.cursor/sandbox.jsonWhat a sandboxed terminal command may reach: network domains, extra readable and writable paths. A different job from permissions.json, and neither is required to get startedTeams with an internal package registry or an air-gapped dependency mirror
.cursor/worktrees.jsonsetup-worktree plus the OS-specific variants, as command arrays or script paths, with $ROOT_WORKTREE_PATH for copying files acrossAnyone running more than one agent on the same repo at once
.cursor/environment.jsonThe cloud agent environment: agent-led setup, a saved snapshot, or a DockerfileCloud agents, automations, and the incident-to-repro pipeline
.cursor/cli.jsonProject-level CLI permission tokens such as Shell(npx), Write(tests/**), Read(.env*) under deny. Permissions are the only thing configurable per projectCI, and the reviewer of the pipeline that runs the agent
.cursor/BUGBOT.mdRepository review rules. The root file always applies, and nested files apply when files under them change. Read by both Bugbot on the PR and Agent Review locallyEvery reviewer, human or otherwise, on every pull request
.cursorignoreBlocks agent access to specific files, and hides them inside the sandbox tooAnyone whose repo contains fixtures, dumps, or config the model has no business reading
Runthe suite, theautomation, the PR gateNoticea repeated mistake or arepeated flakeEncodeone rule, one BUGBOT.mdclause, or one skillPrunedelete what nobodyacceptsnext week, with less noise
The setup is not a project, it is a weekly loop, and pruning is half of it

The first week, in order

The honest limits, and what stays yours

Read the safety story on this page as risk reduction, not as a control. Run Modes are described in the docs as best-effort guardrails rather than a hard security boundary, and Auto-review is called out by name as not a security boundary: its classifier can allow a call you would have blocked, and it can block a call you would have allowed. Both directions are real failure modes, and the second one is the one that tempts people into Run Everything. Hooks fail open unless you set failClosed: true. The browser origin allowlist does not stop link clicks, redirects, or JavaScript navigation. Team Rules can be marked as enforced and used in compliance workflows, and the docs still say plainly that AI guidance should not be your only security control. A model asked to behave is not an access control, and a check that reports neutral is not a merge gate.

What all of this buys you is leverage: the agent grounds itself in your conventions, isolates its experiments, reproduces the failure, gates its own diff, and repeats the boring part on a schedule. What it does not buy you is the last decision. Bugbot finds a weakened assertion; whether the fix is acceptable is a judgement about your product, your users, and your risk. The tester still owns the acceptance decision, and nothing on this page should be built in a way that quietly takes it away.