Integration
becwright + Claude Code: deterministic guardrails
CLAUDE.md is advisory; becwright is the enforcement layer. Block secrets and debug leftovers in Claude Code commits with a deterministic git hook.
Last updated
Claude Code ships code fast, and every team running it eventually sees the same
failure mode: the agent commits a stray debugger, a console.log dump, or a
hardcoded API key — even though CLAUDE.md says, in plain English, not to. That
isn’t a Claude bug; it’s the nature of instructions. becwright is a deterministic
pre-commit guardrails engine: instead of asking the agent to behave, it
verifies the actual code at commit time and blocks the commit (exit code 1)
when a blocking rule fails. Keep CLAUDE.md as the place where you describe how
code should be written; becwright is the enforcement layer that makes the
non-negotiable parts non-negotiable.
Why can’t CLAUDE.md alone enforce rules?
CLAUDE.md is context, not a contract. The agent reads it at the start of a
session and usually follows it — but “usually” carries a lot of weight in
that sentence:
- Rules compete for attention. Your “never commit secrets” line shares the context window with the task, the codebase, and the whole conversation. In a long session, especially after context compaction, it can simply lose.
- Compliance is probabilistic. The same instruction that held yesterday can be skipped today, because language models don’t execute rules — they weigh them against everything else in context.
- Claude Code hooks guard one session. Claude Code’s own hook system can run commands around tool use, and it’s genuinely useful — but it constrains that agent, in that session. It does nothing about a second agent, a teammate’s editor, or you at 1 a.m.
becwright takes the opposite approach: a native git pre-commit hook runs your rules against the staged files on every commit, whoever — or whatever — made it. The rule either passes or it doesn’t, no matter which model produced the change. If you want to stop Claude Code committing secrets, this is the mechanism that actually stops it rather than requests it. For how this relates to the classic framework in the space, 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 in one command:
becwright init
init detects whether the repo has Python or JS/TS files, writes a starter
.bec/rules.yaml with matching rules, and installs the git hook. The full
three-minute walkthrough is in the quickstart.
The Claude Code plugin
You don’t have to leave the chat to do any of the above. becwright has a first-class Claude Code plugin, installed from its marketplace:
/plugin marketplace add DataDave-Dev/becwright
/plugin install becwright@becwright
The plugin does not bundle becwright — it installs the published npm/PyPI package into your project. What it adds:
- A
becwrightskill. It teaches the agent what becwright is, how to install it (npm/pnpm, no Python needed, or pipx), how to scaffold rules, and how to read and fixcheckoutput. Claude invokes it automatically when you ask for “a guardrail”, “a pre-commit check”, or “a rule that can’t be ignored”. - A
/becwrightcommand — a direct entry point with four subcommands:
| Command | What it does |
|---|---|
/becwright init | Install becwright and scaffold .bec/rules.yaml + hook |
/becwright check | Run the rules and summarize PASS / WARN / BLOCK |
/becwright add <regex-or-url> | Add a forbid rule or import a BEC |
/becwright status | Report install + hook + rule count |
How does the agent react to a blocked commit?
This is where the design pays off. When Claude Code runs git commit and a
blocking rule fails, the hook exits 1 and git refuses the commit. The agent
then runs becwright check --json and gets structured results:
{
"blocked": true,
"results": [
{
"id": "no-ai-debug-leftovers",
"severity": "blocking",
"passed": false,
"intent": "No debugger statements or console.log calls may reach a commit.",
"why_it_matters": "A forgotten 'debugger' halts execution in production.",
"output": "src/api/client.ts:42\n > debugger;"
}
]
}
Every failing rule carries its intent (what the rule demands) and
why_it_matters (why it exists). The agent doesn’t just learn that it was
blocked — it reads why, fixes the code to satisfy the intent, and commits
again. The loop closes without a human in it, and without a debugger ever
landing in history. check --json needs no extra dependency and works from the
standalone binary; the schema is documented in MCP & JSON output.
Example: block AI debug leftovers
AI-generated code has a signature failure: debug scaffolding the agent used
while iterating and then forgot. 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 credentials there
is a built-in hardcoded_secrets check that catches AWS keys, private keys and
password = "..." assignments — and ready-made rules you can pull in with
becwright import <url> from the catalog, no writing required. If a pattern
appears legitimately, a becwright: ignore comment on that line suppresses it.
Next steps
- Get a guarded repo in about three minutes with the quickstart.
- See the other integration paths — MCP server and plain CLI — in AI agents.
- Already running pre-commit? They complement each other — the details are in becwright vs pre-commit.