Skip to content

Integration

becwright + Cursor: deterministic guardrails

.cursorrules asks; becwright verifies. Wire deterministic pre-commit guardrails into Cursor via the MCP server or the plain CLI and block bad commits.

Last updated

Cursor’s agent reads .cursorrules (and its newer project rules) the same way Claude Code reads CLAUDE.md: as advice. It usually complies — and sometimes it doesn’t, which is exactly when a debugger, a console.log dump, or a live API key lands in your history. becwright is a deterministic pre-commit guardrails engine: it verifies the actual code at commit time and blocks the commit (exit code 1) when a blocking rule fails. .cursorrules stays the place where you describe style and intent; becwright is the layer that turns .cursorrules enforcement from a hope into a guarantee, and it gives Cursor a real pre-commit gate that no prompt can talk its way past.

Why can’t .cursorrules enforce anything?

Because rules files are input, not verification. Three structural problems:

  • Compliance is probabilistic. The model weighs your “no hardcoded secrets” line against the task, the code and the conversation. In a long session, the rule can simply lose — and you won’t know until review, or production.
  • Nothing checks the output. .cursorrules shapes what the agent tries to write. No part of that pipeline inspects what actually got written before it becomes a commit.
  • The rule only covers Cursor. A teammate on another editor, a second agent, or a quick manual edit is outside its reach entirely.

becwright inverts this: a native git pre-commit hook runs your rules over the staged files on every commit, regardless of who or what made the change. The result is pass/fail, deterministic, the same on every run. (It complements rather than replaces the classic pre-commit framework — see becwright vs pre-commit.)

Install

The npm packages ship a self-contained binary, so no Python is required:

npm install --save-dev becwright   # or: pnpm add -D becwright
pipx install becwright             # fallback for platforms outside the npm binaries

Then scaffold rules and the hook:

becwright init

init detects whether the repo has Python or JS/TS files, writes a starter .bec/rules.yaml, and installs the git hook. From that moment every commit — from Cursor, the terminal, anywhere — runs the checks. The full walkthrough is in the quickstart.

Drive becwright from Cursor over MCP

Cursor speaks MCP, and becwright ships an MCP server — no dedicated plugin needed. Point Cursor’s MCP configuration (.cursor/mcp.json at the project root, or your global MCP settings) at the command:

{
  "mcpServers": {
    "becwright": {
      "command": "becwright",
      "args": ["mcp"]
    }
  }
}

This exposes two structured tools to the agent:

ToolArgumentsReturns
checkall_files (bool), path (optional repo dir)the same summary as check --json
list_checksthe built-in checks as {name, description}

One honest caveat: the MCP server ships only with the Python package — install it with pipx install "becwright[mcp]". The npm binary covers the CLI and the hook, which is all most setups need; details in MCP & JSON output.

No MCP? Use the shell. becwright is a plain CLI, so Cursor’s agent can drive it with ordinary commands and get machine-readable output either way:

npx becwright check --all    # run every rule over the repo
npx becwright check --json   # machine-readable results to parse

What happens when Cursor hits a blocked commit?

The agent finishes a task, runs git commit, and a blocking rule fails: the hook exits 1 and git refuses the commit. The agent then calls the check tool (or runs becwright check --json) and reads structured results:

{
  "blocked": true,
  "results": [
    {
      "id": "no-hardcoded-secrets",
      "severity": "blocking",
      "passed": false,
      "intent": "No credentials, API keys or passwords in source code.",
      "why_it_matters": "A secret committed to git history stays leaked even after you delete it.",
      "output": "src/config.ts:3\n      > const STRIPE_KEY = \"sk_live_51H8...\""
    }
  ]
}

Each failing rule carries its intent and why_it_matters, so the agent sees not just that the commit was refused but why the rule exists — enough context to fix the code properly (move the key to the environment) instead of gaming the check. Then it commits again and passes. The loop closes without a human, and without the secret ever entering history.

Example: block AI debug leftovers

The most common mess in AI-generated code is debug scaffolding the agent forgot to remove. One BEC in .bec/rules.yaml closes it:

rules:
  - id: no-ai-debug-leftovers
    intent: >
      No debugger statements or console.log calls may reach a commit.
    why_it_matters: >
      Agents add debug output while iterating and routinely forget to remove
      it; a forgotten 'debugger' halts execution in production.
    paths:
      - "src/**/*.js"
      - "src/**/*.ts"
    check: "becwright run forbid --pattern '\\bdebugger\\b|console\\.log\\('"
    severity: blocking

The built-in forbid check takes any regex (plus --ignore-case and --message), so most guardrails need zero custom code. For secrets there is a built-in hardcoded_secrets check (AWS keys, private keys, password = "..."), and ready-made rules you can import from the catalog with becwright import <url>. Legitimate occurrences can be exempted line-by-line with a becwright: ignore comment.

Next steps

  • Set up a guarded repo in about three minutes with the quickstart.
  • Compare all agent integration paths — Claude Code plugin, MCP, plain CLI — in AI agents.
  • Running pre-commit already? Read how they fit together in becwright vs pre-commit.