Bugbot: learned rules and Autofix
Bugbot is Cursor’s pull request review agent: it checks pull requests for bugs, security issues, and code quality problems, follows rules from .cursor/BUGBOT.md files and rules learned from a team’s past reviews, and can hand findings to a Cloud Agent through Autofix. By default its check reports findings without failing, so it informs the merge gate rather than being one.
This page is for the developer who switches Bugbot on and the tech lead who keeps it useful. A month after rollout the pattern is familiar: Bugbot flags the same generated file on every pull request, half its comments are resolved as “won’t fix”, the review checklist sits in .cursor/rules/ where Bugbot never reads it, and Autofix has pushed to a branch halfway through human review. Each of those is a configuration decision, not a model problem.
What a tuned Bugbot setup gives you
Section titled “What a tuned Bugbot setup gives you”- A root and path-scoped
.cursor/BUGBOT.mdlayout that keeps findings on your team’s real risks. - A routine for learned rules: teach, read, and promote the ones you depend on into version control.
- An Autofix policy per repository, with the reason for each mode and the gates its commits still have to pass.
- A seeded-defect test and an analytics query that show whether Bugbot catches bugs, not just whether it comments.
- A clear place for Bugbot in layered pull request review, next to CI, code owners, and the evidence bundle.
Where does Bugbot sit in layered review?
Section titled “Where does Bugbot sit in layered review?”Bugbot reads the diff with judgement; it does not decide whether code merges. The check Bugbot publishes on GitHub is named Cursor Bugbot, and a run that finds issues ends with the conclusion neutral unless your organisation has turned on the option to fail on unresolved findings. Requiring the check in branch protection therefore guarantees that Bugbot ran, not that its findings were addressed.
| Layer | What it proves | Who or what owns it |
|---|---|---|
| Local pre-push review | The author’s diff has had one review pass before anyone else sees it | The author, with Agent Review or the /review-bugbot skill |
| Deterministic CI gates | Types, lint, tests, and the evidence bundle pass on the head commit | CI, from the base branch’s configuration |
| Bugbot | Logic errors, missing edge cases, and rule violations a linter cannot express | Bugbot, with rules your team maintains |
| Security review | Injection, secrets, authorisation, and dependency risks | Cursor’s Security Agents or your own scanner |
| Human sign-off | Intent, architecture, and high-risk paths | A named code owner reading the evidence and, for high risk, the code |
| Rollout | Behaviour in production | Canaries, flags, and monitors |
Three consequences follow. First, Bugbot’s findings feed the standard risk class; they approve nothing. Rollouts and PR Routing & Approval builds approval by rule on CI-computed risk labels instead. Second, if you run /review-bugbot in the editor before pushing, Bugbot records the patch ID of the reviewed diff and skips the pull request review when the same diff arrives, so the pull request carries no fresh Bugbot pass. Third, reviews are incremental by default: after the first review, each push is reviewed only for the changes since the previous one. A bug that needs an early and a late commit together can slip between passes, so turn Incremental Review off where you rely on Bugbot for high-risk paths.
Set up Bugbot on a repository
Section titled “Set up Bugbot on a repository”The rules go in before the first automatic review, so the team’s first impression is not a wall of noise.
-
Connect your source control. In the Cursor dashboard, connect GitHub (including GitHub Enterprise Server), GitLab (including self-hosted), Bitbucket (including Data Center), or Azure DevOps Services. On GitHub, Bugbot then comments as
cursor[bot], the account of Cursor’s GitHub app. -
Commit a root
.cursor/BUGBOT.mdbefore you enable reviews. Start from the file in the next section. A short file with a “do not flag” list does more for signal than a long checklist. -
Enable Bugbot on one repository. Open Bugbot under Automations in the Cursor dashboard and enable it for a single, active repository. On team plans, Bugbot then reviews pull requests from every contributor to that repository, whether or not they are on the Cursor team. An individual plan reviews only the pull requests you author.
-
Choose when it runs. Leave automatic reviews on for the pilot repository. Repository settings offer Incremental Review (on by default), Post PR Summary (in the description, as a comment, or off) and, on usage-based plans, an effort level: Low, Default, High, or Smart, where Smart takes a plain-language instruction such as “High for anything under
src/billing/”. Raise effort only where the seeded-defect test below shows misses; it costs more usage. The run-frequency switches sit at three levels:- Installation: team admins can set Run only once per pull request.
- Personal (team and enterprise members): Run only when mentioned, Run only once, and Enable reviews on draft PRs, for their own pull requests.
- Repository: the Admin API’s
manualTriggerOnly(step 7) makes Bugbot run only when triggered.
-
Prove the rules load. Open a small pull request and comment:
bugbot run verbose=trueBugbot posts a table of every rule included in that run, flags any rule that was truncated or omitted, and gives a request ID for support.
cursor review verbose=truedoes the same. If yourBUGBOT.mdis not in the table, fix that before going further. -
Require the check, then decide on failing. Add
Cursor Bugbotto the required checks in your branch protection ruleset so no pull request merges before Bugbot has run. If the option to fail on unresolved findings is available to your organisation, turn it on only after the seeded-defect test and two weeks of low noise; a failing check that the team learns to dismiss is worse than a neutral one. -
Roll out beyond the pilot from a script. Once the pilot passes the checks later on this page, a team admin can enable more repositories through Bugbot’s Admin API.
manualTriggerOnly: trueenables one in manual mode, a safe start for a repository with noBUGBOT.mdyet:Terminal window # Terminal. CURSOR_ADMIN_API_KEY is a team Admin API key read from your secret store.curl -sS -X POST https://api.cursor.com/bugbot/repo/update \-H "Authorization: Bearer $CURSOR_ADMIN_API_KEY" \-H "Content-Type: application/json" \-d '{"repoUrl": "https://github.com/acme/orders-api", "enabled": true, "manualTriggerOnly": true}'# List every repository with its Bugbot settings, to check the rollout.curl -sS https://api.cursor.com/bugbot/repos -H "Authorization: Bearer $CURSOR_ADMIN_API_KEY"
Write a BUGBOT.md that keeps the signal high
Section titled “Write a BUGBOT.md that keeps the signal high”Bugbot always includes the root .cursor/BUGBOT.md, then any further .cursor/BUGBOT.md files it finds while walking upward from each changed file. Put repository-wide rules at the root and stricter rules next to the code they govern:
orders-api/ .cursor/BUGBOT.md # always included src/billing/.cursor/BUGBOT.md # included when a billing file changes migrations/.cursor/BUGBOT.md # included when a migration changesBUGBOT.md is one of four rule sources. Bugbot merges them into one block in this order: team rules (written by team admins in Bugbot’s settings, applied to every enabled repository), then the project BUGBOT.md files, then learned rules, then manual rules. Put organisation-wide invariants such as “never log a token” in team rules, and mark the ones that matter most as required: over the size cap (below), Bugbot keeps required team rules first, but keep the total under the cap rather than rely on that.
Cursor’s project rules (the .mdc files in .cursor/rules/) do not apply to Bugbot runs. If one rule matters to both the agent and the review, write it in both places.
Write each rule as a condition Bugbot can check in a diff (“a handler that awaits without handling rejection”), not a value (“write robust code”). Ask Bugbot to cite the rule, as Sentry’s public BUGBOT.md for its JavaScript SDK does, so a reviewer can trace a noisy finding to its source. And keep the files short: each rule is truncated at 30,000 characters and the combined rules for one review are capped at 100,000, after which some rules are omitted. A root file for a TypeScript API service:
# Review rules for orders-api
Flag only issues you can tie to a line in this diff. When a finding comesfrom this file, say so in the comment and name the section.
## Always flag- A handler in src/routes/ that awaits a call without handling rejection.- Money stored or computed as a JavaScript number. Amounts are integer cents (bigint) or Decimal from src/lib/money.ts.- A new SQL string built with template literals instead of the query builder.- Logging of request bodies, tokens, email addresses or card data.- A feat change with no new or changed test; a fix with no test that fails without the fix.- A test whose assertion was loosened (toBeTruthy replacing toEqual, a removed expect, an added .skip) in the same PR as a code change.
## Do not flag- Formatting, import order or naming: dprint and oxlint own these.- Files under src/generated/ and any *.snap file.- Speculative refactors unrelated to the diff.And a scoped file for the billing path:
# Billing rules (src/billing/)
- Every state change to an invoice must be idempotent on the webhook event id. Flag any handler that writes before checking processed_events.- Currency conversion happens only in src/billing/fx.ts. Flag it anywhere else.- Treat any change to refund logic as high severity.Teach Bugbot rules from your review history
Section titled “Teach Bugbot rules from your review history”Learned rules live in Cursor’s dashboard, not in your repository. They come from your team’s GitHub pull request activity (the documentation names only GitHub), a one-off backfill of the repository’s history, and explicit @cursor remember comments. Each learned rule has a Name, the Rule content, and optional Scoped paths such as src/components/**.
-
Enable learning. In Bugbot’s repository rules, enable learning for your organisation and the pilot repository, and run the backfill from its history. Manual rules, which you write in the same screen, also apply only while learning is enabled for both the organisation and the repository.
-
Read what Bugbot learned before you trust it. Treat the list like a pull request: delete one-off decisions, scope rules that hold for one directory, and rewrite vague rules as checkable conditions.
-
Teach inline when a human writes the same comment twice. The second time a reviewer types the same correction, they reply on the pull request instead:
@cursor remember Background jobs in src/jobs/ must be idempotent: flag any job that inserts a row without an ON CONFLICT clause or a prior existence check. -
Review rule analytics monthly. Each rule shows Issues found, PRs reviewed, Accepted issues, and Acceptance rate. A rule with many findings and a low acceptance rate is noise; rewrite or delete it. Pick your own threshold and write it down, for example “below 30% acceptance after 20 findings”.
-
Promote the rules you depend on into
BUGBOT.md. Cursor enables and disables learned rules on its own as it sees more activity. That suits style drift and endangers invariants: a rule about idempotent billing webhooks must not switch off because nobody tripped it for a month. Move a rule that has earned its place into the rightBUGBOT.mdthrough a pull request, where it is versioned, reviewed, and owned.
How far should Autofix go?
Section titled “How far should Autofix go?”Autofix spawns a Cloud Agent to fix the bugs Bugbot found, pushes the fix, and comments on the pull request with the result. It uses your Default agent model (falling back to the team default), requires on-demand usage and storage to be enabled (not Legacy Privacy Mode), and bills as Cloud Agent usage. When it is on, GitHub may show a separate Cursor Bugbot Autofix check that only reports success or neutral, so it never blocks a merge on its own.
| Mode | What happens | Use it when |
|---|---|---|
| Off | Findings carry Fix in Cursor and Fix in Web links; a person starts the fix | Repositories with high-risk paths, or while you are still tuning rules |
| Create New Branch (Cursor’s recommended mode) | The fix lands on a new branch; the author decides whether to take it | The default for most repositories: the fix is visible and optional |
| Commit to Existing Branch | The fix is pushed to the pull request branch, with at most three attempts per pull request | Low-risk repositories with strong tests, where stale-approval dismissal is on |
Provider support differs. GitHub and Cursor’s Origin support both modes; GitLab and Bitbucket support only Commit to Existing Branch; Azure DevOps supports neither. An unsupported personal mode makes Bugbot skip Autofix for that pull request.
The team mode is a default, not a policy. Each developer can override it for their own pull requests (Use Installation Default, Off, or either branch mode), so a team default of Create New Branch does not stop one author from choosing Commit to Existing Branch. The controls that hold for everyone live in your source control: branch protection, required checks, and stale-approval dismissal.
Three limits shape the table:
- An Autofix commit is agent-written code. It passes CI, the evidence bundle check, and code-owner review like any commit. Never exempt it from branch protection, and keep stale-approval dismissal on.
- Autofix can clear a finding by changing the test. Put tests in
CODEOWNERSand keep the “loosened assertion” rule inBUGBOT.md. - Three attempts is a loop limit, not a quality bar. A finding that survives them goes to a person.
How do you know Bugbot is catching bugs?
Section titled “How do you know Bugbot is catching bugs?”Comment volume says nothing about quality. Two measurements do: a seeded-defect test and the share of findings the team acts on.
Run a seeded-defect test. Keep a branch with five planted defects that match your rules: an unhandled promise rejection in a route, money stored as a JavaScript number, a template-literal SQL query, a logged token, and a loosened test assertion. Open a draft pull request from it labelled do-not-merge, comment bugbot run verbose=true (drafts are skipped by automatic review unless enabled), and record which defects Bugbot found. Never merge it, and close it once you have recorded the results. Repeat after every BUGBOT.md or effort-level change. A defect it stops catching is a regression in your review layer, found before a real pull request needed it.
Measure what the team resolves. On Enterprise plans, the Bugbot analytics API returns one item per completed review with the findings count, the billed cost, and each finding’s severity and resolution status. The key needs the read:* scope; keep it in a secret store and read it from the environment:
# Terminal. CURSOR_ANALYTICS_API_KEY comes from your secret store, never the command line.curl -sS --get https://api.cursor.com/analytics/team/bugbot-reviews \ -u "$CURSOR_ANALYTICS_API_KEY:" \ --data-urlencode "startDate=$(date -d '30 days ago' +%F)" \ --data-urlencode "repo=github.com/acme/orders-api" \ --data-urlencode "pageSize=250" \ --data-urlencode "dryRun=false" \| jq -r ' ([.data[].cost_cents // 0] | add) as $cents | ([.data[] | (.bugs // [])[]] | group_by(.severity // "unknown")[] | [ (.[0].severity // "unknown"), length, (map(select(.resolution_status == "resolved")) | length) ] | @tsv), "total_usd\t\($cents / 100)"'On macOS, replace date -d '30 days ago' +%F with date -v-30d +%F. dryRun=false keeps trial runs, whose findings are never resolved, out of the share. The output is one line per severity with findings and findings resolved (a finding with no severity counts under unknown), then one total_usd line with the period’s spend in dollars. Follow pagination.hasNextPage if a month holds more than 250 reviews.
A falling resolved share at steady volume means noise: narrow the rules. A high resolved share with a missed seeded defect means the rules are too narrow: add the check. To trial Bugbot before announcing it, POST /bugbot/review with "dryRun": true (key scope admin:*) reviews a pull request without posting to it; findings appear only in analytics, and dry runs are billed like normal reviews.
Sign-off does not move to Bugbot. A code owner still approves high-risk paths, and the review layer’s owner (usually the tech lead) owns the rules, the seeded-defect branch, and the monthly numbers.
How does Bugbot compare with Claude Code and Codex review?
Section titled “How does Bugbot compare with Claude Code and Codex review?”The design on this page carries across tools; the mechanics differ:
| Cursor Bugbot | Claude Code | Codex | |
|---|---|---|---|
| Pull request review | Automatic on each update, or bugbot run / cursor review | Managed Code Review (research preview, Team and Enterprise) | @codex review and automatic reviews on GitHub (per OpenAI’s docs, checked 2026-08-28) |
| Local review | /review-bugbot skill | /code-review | /review; codex review from the shell (0.157.1) |
| Where rules live | .cursor/BUGBOT.md, learned, manual, and team rules | CLAUDE.md; managed Code Review also reads a root REVIEW.md (local /code-review does not) | AGENTS.md |
| Fixing findings | Autofix through a Cloud Agent | A separate session you start | A separate task you start |
For the full comparison on noise, configuration, and cost, including third-party bots, see AI code review bots compared. The Claude Code equivalent of this page is review automation with Claude Code. On Team and Enterprise plans Bugbot can also call MCP tools you add in its settings; add one only when a rule needs data outside the diff, such as acceptance criteria.
Copy-paste prompts for Bugbot rules and Autofix
Section titled “Copy-paste prompts for Bugbot rules and Autofix”Run these in Cursor’s agent from the repository root. The first needs the GitHub CLI (gh) authenticated for the repository.
What breaks when Bugbot reviews your pull requests?
Section titled “What breaks when Bugbot reviews your pull requests?”Bugbot ignores your review checklist. The checklist is in .cursor/rules/, which Bugbot does not read. Recovery: move the review rules into .cursor/BUGBOT.md and confirm with bugbot run verbose=true that the file appears in the rules table.
A rule you rely on stopped firing. It was a learned rule, and Cursor disabled it, or the combined rules passed the 100,000-character cap and it was omitted. Recovery: check the verbose table for omitted or truncated rules, shorten the files, and promote invariants from learned rules into BUGBOT.md.
The same false positive on every pull request. It matches generated code, snapshots, or a linter-owned pattern. Recovery: add it to “Do not flag” and run the noise prompt above after two weeks.
Required check, green merge, open findings. The Cursor Bugbot check concluded neutral, which branch protection treats as passing. Recovery: if the fail-on-unresolved option is available, turn it on for the repository; otherwise make resolved Bugbot threads part of your evidence bundle check or require conversation resolution in the branch protection ruleset.
A bug shipped that no single push contained. Incremental review looked at each push alone; the defect exists only when two combine. Recovery: turn Incremental Review off for repositories with high-risk paths, so each push gets a full-diff pass, and comment bugbot run on their open pull requests.
Autofix commits land in the middle of a human review. The repository, or the author’s personal setting, uses Commit to Existing Branch. Recovery: switch the team default to Create New Branch, ask the author to set Use Installation Default, and keep stale-approval dismissal on so any fix that still lands needs fresh approval.
Autofix never runs. On-demand usage is off, storage is disabled, the provider does not support the mode, or a personal setting overrides the installation. Recovery: check those four in that order.
No Bugbot review on a pull request you expected it on. The author ran /review-bugbot locally on the same diff, the repository runs only once or in manual mode, or the author’s own settings run Bugbot only when mentioned or skip drafts. Recovery: comment bugbot run, and put the trigger rules in the pull request template.
The bill grows faster than the value. Effort was raised everywhere, or dry runs are used at scale. Recovery: keep High effort for repositories where the seeded-defect test shows misses, and read the total_usd line monthly.