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.
.cursorrulesshapes 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:
| Tool | Arguments | Returns |
|---|---|---|
check | all_files (bool), path (optional repo dir) | the same summary as check --json |
list_checks | — | the 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.