# Essential Cursor configuration for agent work

URL: https://developertoolkit.ai/en/cursor-ide/quick-start/essential-configuration/
Description: Set Cursor up so the agent runs your checks unattended: a verify command, a run mode, project rules, a stop hook that re-runs the gate, and .cursorignore.

Essential Cursor configuration is the set of repository and account settings that let Cursor's agent run a project's checks without asking each time, while keeping destructive commands and secrets behind approval. It has five parts: one verify command, a run mode, project rules, a stop hook that re-runs the gate, and `.cursorignore` plus Privacy Mode.

You open a real repository in Cursor, ask the agent to fix a failing test, and it stops to ask before `npm test`, then again before `tsc`, then again before `eslint`. After the tenth approval you either give up or tell it to run everything, which is how an agent ends up running `git push` or reading `.env`. Neither is a configuration. Both leave you reading every line of the diff to find out whether the change works.

This page is for the **developer** setting up Cursor on a working repository in the first hour, and the **tech lead** who commits the result so the whole team gets the same setup. It assumes Cursor is installed ([installation and platform setup](/en/cursor-ide/quick-start/installation-setup/)).

**What this page checked**

On 2026-10-12 Cursor's docs and help confirm the run modes, the Auto-review classifier, the `.mdc` rule format and frontmatter keys, and Cursor's support for AGENTS.md and CLAUDE.md. On 2026-09-26 cursor.com could not be fetched, so the rest of the settings behaviour (hooks, `.cursorignore`, protected config files) was checked against the agent runtime shipped in Cursor's own `@cursor/sdk` 1.0.32 package on npm (the current release on 2026-09-26; `@cursor/sdk` on npm and `cursor-sdk` on PyPI are both at 1.0.37 as of 2026-10-07), and the feature names against Cursor's docs as fetched on 2026-08-28. That other behaviour was not re-checked on 2026-10-12. Menu labels change between releases, so this page names settings by what they do, not by their exact position in the UI.

## What a working Cursor configuration gives you

- A single `npm run verify` command that proves a change, which the agent, your stop hook and CI all run.
- A run mode that lets the agent run that command unattended while `git push`, `rm -rf` and anything with `sudo` still stop for you.
- A committed project rule that tells the agent your stack, commands and boundaries.
- A `stop` hook that re-runs the gate when the agent says it is finished and sends it back to work if the gate fails.
- A five-minute smoke test that proves the configuration works before you trust it with a real task.

## What order should you configure Cursor in?

Configure from the inside out. The verify command comes first, because every later layer points at it. Account-level privacy comes before you open proprietary code, because data that already left cannot be recalled.

| Layer | Lives in | Committed to git? | Owner |
| --- | --- | --- | --- |
| Verify command | `package.json` (or `Makefile`, `pyproject.toml`) | Yes | Developer |
| Run mode and allowlist | Cursor Settings > Agents > Approvals & Execution | No: per user; a team admin can add a team-wide terminal allowlist | Developer, then tech lead |
| Project rules | `.cursor/rules/*.mdc` | Yes | Tech lead |
| Stop hook | `.cursor/hooks.json` and `.cursor/hooks/` | Yes | Tech lead |
| Secret exclusions | `.cursorignore` | Yes | Tech lead with security |
| Privacy Mode | Your Cursor account or team admin dashboard | No | Account owner or admin |
| Editor settings | `.vscode/settings.json` | Yes | Tech lead |

## Give the agent one command that proves the work

An agent that has to guess how to test your project guesses differently every session: `npx jest` today, `npm test -- --watch` tomorrow, which hangs. A single script removes the guess and gives the allowlist, the hook and CI the same thing to call.

```json
{
  "scripts": {
    "typecheck": "tsc --noEmit",
    "lint": "eslint .",
    "test": "vitest run",
    "verify": "npm run typecheck && npm run lint && npm run test"
  }
}
```

The script has to exit non-zero on any failure and must never start a watcher. If your project already has a CI workflow, `verify` runs the same steps CI runs, so a green local gate predicts a green pipeline.

**Copy-paste prompt: build the verify command**

```text
Read package.json, any Makefile, and every workflow under .github/workflows/.
List each check that CI runs (type check, lint, unit tests, format check) and
the exact command it uses.

Then add a single "verify" script to package.json that runs those same checks
in order, fails on the first error, and never starts a watch mode. Do not
change any existing script. Run `npm run verify` once and report: the exit code,
how long it took, and every check that failed with its first error line.
Do not fix failures yet.
```

A red `verify` on an untouched checkout is useful information: it is the baseline. Fix it, or record it in the project rule, before you ask the agent for anything else. Otherwise the agent inherits failures it did not cause and "fixes" them in ways you did not ask for.

## Choose a run mode that lets the agent run the gate

Cursor groups terminal control under **run modes** ([Cursor's run modes page](https://cursor.com/docs/agent/security/run-modes)). The runtime supports three mechanisms that combine:

- **An allowlist**: commands that always run without asking.
- **A sandbox** for shell commands, which limits what a command can write and reach on the network.
- **Auto-review**, which sends tool calls that are neither allowlisted nor sandboxable to a classifier that decides whether they run or come to you.

Cursor's docs name three run modes (checked 2026-10-12), set under **Settings > Agents > Approvals & Execution**:

- **Auto-review** is the recommended default since Cursor 3.6 and, in Cursor's words, "the safest useful setup for most people". Allowlisted calls run immediately, other shell commands run in the sandbox when possible, and calls that do not use the sandbox go to the Auto-review classifier.
- **Allowlist**: "Actions in your allowlist run without approval."
- **Run Everything**: "Every tool call runs automatically." In the CLI, `/run-everything [on|off|status]` switches it, and `/auto-run` is an alias.

The classifier is itself a model. Cursor's docs say "Today it uses Gemini 3.5 Flash Lite, with Claude 4.5 Haiku as the fallback", and that blocking Claude 4.5 Haiku "can disable Auto-review". They also say "Auto-review is not a security boundary" and "The classifier can make mistakes", so keep irreversible commands off the allowlist whichever mode you use. Cursor 3.24 added "Auto-review stops risky deletes for your approval", and CLI v2026.10.08 made Auto-review stricter on risky deletes.

Tutorials still use older names. YOLO mode and Auto-Run are old names, and "run modes" is the current term. Cursor 3.5 deprecated Ask Every Time (use Allowlist with an empty allowlist for the same behaviour) and folded Run in Sandbox into Allowlist with sandboxing enabled.

Run modes apply to local agents only: Cursor's docs say "Cloud Agents run inside their own dedicated machine, so the agent never asks you to approve an action". The same docs page lists `~/.cursor/permissions.json` and `<project>/.cursor/permissions.json` (merged) as config files, and `sandbox.json` for the sandbox; the steps below use the Settings screen.

On a team plan, an admin can set a team-wide terminal allowlist that overrides yours, so check what your admin already set before you change anything.

1. Open **Cursor Settings** and go to **Agents > Approvals & Execution**, where the run modes live.

2. Keep a mode that sends anything not allowlisted to review (Auto-review) or to the sandbox (Allowlist with sandboxing enabled), not Run Everything.

3. Add the commands the agent needs to verify its own work to the allowlist. A starter set for a TypeScript project:

   ```text
   npm run verify, npm test, npm run lint, npm run typecheck, npx vitest run,
   tsc, eslint, prettier --check, git status, git diff, git log
   ```

   For Python, add `pytest`, `ruff check`, `mypy`. For Rust, `cargo test`, `cargo clippy`.

4. Leave everything irreversible off the list: `git push`, `git commit`, `git reset --hard`, `rm -rf`, `sudo`, `npm publish`, `docker rm`, `curl`, `ssh`, and any `deploy` or database migration script.

**Do not run every command without review on your laptop**

Cursor also offers a mode, Run Everything, that runs every command without asking. Use it only inside a disposable, network-restricted environment, never on a machine that holds credentials, SSH keys or a production kubeconfig. An allowlist plus review for everything else gets the same speed for the commands that matter. The trade-offs across all three agents are in [permissions and sandboxing](/en/workflows/harness/permissions-and-sandboxing/).

**Copy-paste prompt: propose an allowlist from the repository**

```text
List every command an agent would need to verify a change in this repository:
the scripts in package.json, the tools CI calls, and the git read commands.

Sort them into two tables:
1. Safe to run unattended: read-only, or writes only inside the working tree
   and is undone by `git restore .`.
2. Must ask first: pushes, publishes, deletes outside the working tree,
   touches the network, a database or a cloud account, or needs sudo.

For every row say why. Do not run any command in table 2. Print table 1 as a
single comma-separated line I can paste into Cursor's allowlist.
```

## Tell the agent your conventions with a project rule

Project rules are the instructions the agent loads with every request. The runtime reads rules from `.cursor/rules/**/*.mdc`, and a rule whose frontmatter sets `alwaysApply: true` loads in every session. One always-apply rule is enough to start; scoped rules by file pattern, and the full format, are in [project rules in Cursor](/en/cursor-ide/quick-start/project-rules/). Cursor's docs also say it supports `AGENTS.md` in the project root and in subdirectories, and that it reads `CLAUDE.md` files the same way (checked 2026-10-12).

**Copy-paste starter rule: .cursor/rules/project.mdc**

```text
---
description: Stack, commands and boundaries for this repository
alwaysApply: true
---

Stack: Next.js App Router, TypeScript strict, Tailwind CSS, Drizzle ORM on
PostgreSQL, Vitest. Package manager: npm (never pnpm or yarn).

Before you say a task is done, run `npm run verify` and paste the last lines
of its output. A task is not done while verify fails.

Never edit or delete an existing test to make it pass. If a test looks wrong,
stop and explain why instead.

Use named exports. Validate all external input with zod. Handle errors from
every async call; never swallow them.

Ask before adding a dependency, changing a migration, or touching anything
under .github/ or .cursor/.
```

A rule shapes what the agent writes. It does not stop a command, so never rely on a rule where the run mode, a hook or `.cursorignore` should hold the line. Cursor's help calls a root `.cursorrules` file "legacy and will be deprecated" (checked 2026-10-12), and the SDK 1.0.32 runtime still loads it as an always-apply rule next to your new ones. Move its content into `.cursor/rules/` and delete it, or the agent reads two sets of instructions that drift apart.

## Make Cursor re-run the gate before it says "done"

The rule asks the agent to run `verify`. A hook makes it happen. Cursor's hooks are processes that "communicate over stdio using JSON" and "can observe, block, or modify behavior" ([Cursor hooks docs](https://cursor.com/docs/hooks), checked 2026-08-28). The `stop` hook runs when the agent finishes a turn. In the SDK 1.0.32 runtime it receives the turn's `status` and a `loop_count`, and if it prints a `followup_message`, the agent receives that message and keeps working.

```json
{
  "version": 1,
  "hooks": {
    "stop": [{ "command": "node .cursor/hooks/verify-on-stop.mjs", "loop_limit": 3, "timeout": 900 }]
  }
}
```

```js
// .cursor/hooks/verify-on-stop.mjs: send the agent back if the gate fails
import { readFileSync } from 'node:fs';
import { spawnSync } from 'node:child_process';

const input = JSON.parse(readFileSync(0, 'utf8'));
const done = () => { process.stdout.write('{}'); process.exit(0); };

// Only check turns the agent finished on its own, not ones you stopped.
if (input.status !== 'completed') done();

const run = spawnSync('npm run verify', { shell: true, encoding: 'utf8' });
if (run.status === 0) done();

const tail = `${run.stdout}\n${run.stderr}`.trim().split('\n').slice(-40).join('\n');
process.stdout.write(JSON.stringify({
  followup_message:
    'npm run verify failed after your last change. Fix the cause. Do not edit, ' +
    'skip or delete tests to make it pass. Output:\n' + tail,
}));
```

`loop_limit` caps how many times the hook can send the agent back in one task. Three is enough to fix a missed import; a fourth failure usually means the approach is wrong, and you want to see it. Without `loop_limit` the runtime stops after 5 loops (SDK 1.0.32). Hooks time out after 60 seconds unless you set `timeout` (seconds; SDK 1.0.32), and a timed-out hook lets the agent stop, so set it above your slowest `verify` run.

Commit both files. The runtime treats JSON files under `.cursor/` as protected configuration, so an agent edit to `hooks.json` or `mcp.json` asks for your approval instead of happening silently. That protection covers JSON only: the hook script `verify-on-stop.mjs` and the `verify` script in `package.json` are not protected files, and the agent can edit them without a prompt. An agent that shortens `verify` or neuters the hook turns the gate green without the work being right, so the diff check under [when Cursor configuration breaks](#when-cursor-configuration-breaks) covers them too. The companion guard that blocks secret reads and network commands with `beforeShellExecution` and `beforeReadFile` hooks is in [privacy and security in Cursor](/en/cursor-ide/team/privacy-security/).

## Keep secrets and private code out of the agent's reach

Two settings decide what leaves your machine, and they live in different places.

- **`.cursorignore`**, committed at the repository root in `.gitignore` syntax. The agent's file tools refuse to read matching paths. Start with `.env`, `.env.*`, `*.pem`, `*.key`, `secrets/` and any database dump.
- **Privacy Mode**, an account-level setting on Cursor's side. A repository cannot set it. On a team plan, confirm the tier in the admin dashboard; on a personal account, check it in your own settings before you open proprietary code.

What each tier guarantees depends on your plan and contract, so confirm it on Cursor's current privacy pages rather than from a blog post. The full setup, including a CI test that proves the guard still blocks, is in [privacy and security in Cursor](/en/cursor-ide/team/privacy-security/).

## Editor settings that keep agent changes reviewable

Cursor is built on VS Code, so workspace settings in `.vscode/settings.json` apply and can be committed for the team.

```json
{
  "files.autoSave": "afterDelay",
  "editor.formatOnSave": true,
  "search.exclude": {
    "**/node_modules": true,
    "**/dist": true,
    "**/.next": true,
    "**/coverage": true
  }
}
```

Auto-save keeps the files on disk in step with what you see, so the agent's commands never run against a stale buffer. Format on save covers the files you edit. It does not guarantee that files the agent writes are formatted, so keep `prettier --check` (or your formatter's check mode) inside `verify` and let the gate catch it.

For a monorepo, open the packages you work on rather than the root, or group them in a multi-root workspace file:

```json
{
  "folders": [
    { "path": "apps/web", "name": "Web (Next.js)" },
    { "path": "services/api", "name": "API (Express)" },
    { "path": "packages/shared", "name": "Shared types" }
  ]
}
```

Save it as `myproject.code-workspace` and open it with **File > Open Workspace from File**. The agent can then edit across all three folders in one conversation. Strategies for larger trees are in [large codebase strategies](/en/cursor-ide/build/large-codebase-strategies/) and [multi-repository workflows](/en/cursor-ide/build/multi-repo-workflows/).

## How do you prove the configuration works?

Do not trust a configuration you have not seen hold. Commit a clean baseline first (`git status` shows nothing), then give the agent a small task that exercises every layer.

**Copy-paste prompt: smoke-test the Cursor configuration**

```text
This is a configuration test. Do the following in order and report each result.

1. Add a function `slugify(title: string): string` to src/lib/slugify.ts that
   lowercases, trims, replaces runs of non-alphanumerics with "-", and strips
   leading and trailing "-". Add three Vitest cases in src/lib/slugify.test.ts,
   including an empty string.
2. Run `npm run verify` and paste the last 10 lines of output.
3. Try to run `git push --dry-run`. Report whether you were asked for approval.
4. Try to read .env with your file tool and then with the terminal. Report
   exactly what happened each time.
5. List every command you ran and whether it needed my approval.
```

The configuration passes when all of these are true, and none of them requires reading the new code:

| Check | Where you see it | Pass |
| --- | --- | --- |
| `verify` ran without an approval prompt | The agent's command list | Yes, no prompt |
| The gate result is real | Run `npm run verify` yourself | Exit code 0 |
| `git push` stopped | The approval prompt (or the guard hook's deny message, if you added the guard from [privacy and security in Cursor](/en/cursor-ide/team/privacy-security/)) | Asked or blocked |
| `.env` was not read | The agent's report | Refused by `.cursorignore` (file tool) or stopped for approval (shell); a shell read that ran without a prompt is a fail |
| Only the expected files changed | `git diff --stat` | Two files |
| Gate files unchanged | `git diff --stat -- package.json .cursor/` | No lines |
| The stop hook works | Break a test by hand, ask the agent to "finish up" | It is sent back with the failure |

Then open a pull request with `.cursor/`, `.cursorignore`, `.vscode/settings.json` and the `verify` script. The tech lead reviews that configuration PR once, and CI runs the same `npm run verify` on every later PR. From then on, a change is judged by its gate result and a short diff summary, not by reading every line; the method behind that is in [reading evidence instead of code](/en/ladder/evidence-not-diffs/).

## When Cursor configuration breaks

**The agent still asks before every test run.** The command it runs does not match the allowlist entry: `npx vitest` is not `npm test`. Add a line to the project rule ("run tests only with `npm run verify`") and allowlist that exact string.

**The agent ran something destructive.** Stop the agent. Run `git status` and `git diff --stat` to see the damage, then `git restore .` (tracked files) and `git clean -n` followed by `git clean -f` (untracked files, after you check the list). Remove the command from the allowlist, or block it in the `beforeShellExecution` guard from [privacy and security in Cursor](/en/cursor-ide/team/privacy-security/). This is why the clean baseline comes before the first task. For in-editor rollback, see [checkpoints and branching](/en/cursor-ide/build/checkpoints-branching/).

**The stop hook never fires, or loops.** Check that `.cursor/hooks.json` is valid JSON and that the command path works from the project root. If the agent keeps coming back with the same failure, the `loop_limit` is doing its job: read the failure yourself, because the plan is wrong, not the code.

**The stop hook passes but `verify` is red.** The hook timed out, and a timed-out hook lets the agent stop. Raise `timeout` in `.cursor/hooks.json` above the time your slowest `npm run verify` takes.

**The agent weakens a test or the gate to get green.** Run `git diff --stat -- '*.test.*' '*.spec.*' package.json .cursor/ .cursorignore` after every task. Any change to an existing test that you did not ask for is a rejection, whatever the gate says. The same goes for the hook script (`.mjs`) and `package.json`: they are not protected files, so any change to them that you did not request is a rejection. The rule line "Never edit or delete an existing test" reduces this; the diff check catches the rest.

**The agent ignores the project rule.** Confirm the file is under `.cursor/rules/`, ends in `.mdc`, and has `alwaysApply: true` in valid frontmatter. Delete any leftover root `.cursorrules` that contradicts it, and check that no `AGENTS.md` or `CLAUDE.md` does either, because Cursor reads both. More diagnosis is in [project rules in Cursor](/en/cursor-ide/quick-start/project-rules/).

**Teammates get different behaviour.** Everything in git is shared; the run mode and Privacy Mode are not. Ask your admin to set a team-wide terminal allowlist, and add `.cursor/` and `.cursorignore` to `CODEOWNERS` so a change to the configuration gets a reviewer.

## Where to go next after configuring Cursor

- [Model selection](/en/cursor-ide/quick-start/model-selection/) — Which model to run in Cursor, and when to switch.
- [Project rules in Cursor](/en/cursor-ide/quick-start/project-rules/) — Scoped rules, rule types and how to check they load.
- [MCP setup](/en/cursor-ide/quick-start/mcp-setup/) — Connect the agent to your issue tracker, database and browser.
- [Your first feature](/en/cursor-ide/quick-start/first-feature/) — Put the configuration to work on a real change.

Using more than one agent? The same layers for the other tools are in [Claude Code configuration](/en/claude-code/quick-start/configuration/) and [Codex configuration](/en/codex/quick-start/configuration/). Model prices and defaults live on the [models hub](/en/ecosystem/models/).
