Comparison
becwright vs pre-commit
pre-commit manages a huge hook ecosystem but needs Python; becwright ships intent-bound checks in one binary. Honest comparison, plus how to run both.
Last updated
becwright and pre-commit meet at the same place — the git pre-commit hook — but they are different kinds of tools. pre-commit is a framework that installs and manages hooks written by other people: linters, formatters and scanners from a huge community ecosystem, orchestrated through .pre-commit-config.yaml. becwright is a constraint engine that ships its own deterministic checks and binds every rule to the intent behind it. The honest verdict: they complement each other, and plenty of repos should run both.
TL;DR — pre-commit gives you a massive ecosystem of third-party hooks, but it ships no checks of its own and needs a Python interpreter to run. becwright ships working checks out of the box (hardcoded secrets, tokens in logs, debug leftovers, a generic
forbidregex), needs no Python thanks to a self-contained npm binary, and binds every rule to its why. Keep pre-commit for linters and formatters; add becwright for the constraints that must never be broken.
What is pre-commit?
pre-commit is a multi-language framework for managing git hooks. You list hook repositories and hook ids in .pre-commit-config.yaml; the framework clones them, builds isolated environments for each (Python, Node, Ruby, Go and more), pins versions, and runs the hooks against changed files on every commit. pre-commit autoupdate bumps hook versions, and pre-commit.ci runs the same config in CI.
Its ecosystem is the largest of any hook tool by a wide margin: community hooks exist for almost every mainstream linter, formatter and scanner — black, ruff, eslint and prettier mirrors, shellcheck, terraform fmt, and hundreds more. If your goal is “run the tools we already use, at commit time, with pinned versions”, pre-commit is the standard answer and becwright does not try to compete with that.
What does becwright do that pre-commit doesn’t?
Four things, and they define when it earns a place next to pre-commit:
- Checks included. pre-commit ships zero checks — every behavior comes from an external hook repo you choose, vet and pin. becwright works the minute you run
becwright init: built-in checks catch hardcoded secrets, tokens in log calls,eval()/exec(), forgotten breakpoints, and anything you can express as a regex with the genericforbidcheck. - Every rule is bound to its intent. In
.pre-commit-config.yaml, a hook is a repo URL and an id; the reason it exists lives in a wiki or in someone’s head. A becwright rule carriesintentandwhy_it_mattersin.bec/rules.yamland prints them when the rule fails — which is exactly what an AI agent (or a new teammate) needs to fix the violation instead of deleting the rule. See Writing checks for the full rule format. - No Python required. The pre-commit framework itself is a Python application. becwright’s npm and pnpm packages ship a self-contained binary for linux-x64, linux-arm64, darwin-x64, darwin-arm64 and win32-x64 (pipx remains available for everything else).
- Machine-readable and portable.
becwright check --jsonreturns structured pass/fail with each rule’s intent, an MCP server exposescheckandlist_checksto any MCP-capable agent, andbecwright export/importmoves a rule between repos as a single self-contained.bec.yamlbundle.
becwright vs pre-commit: side by side
| Aspect | pre-commit | becwright |
|---|---|---|
| What it is | Hook manager / framework | Constraint engine with its own checks |
| Runtime needed | Python interpreter | None — self-contained binary via npm/pnpm (pipx optional) |
| Ships built-in checks? | No — hooks come from external repos | Yes — secrets, tokens in logs, eval, debug leftovers, generic forbid |
| Rule ↔ intent binding | No — config lists repos and hook ids | Yes — intent and why_it_matters on every rule |
| Portable rule bundles | Hook repos, pinned per project | Single-file .bec.yaml via export / import |
| Output for AI agents | Plain text | check --json + MCP server + Claude Code plugin |
| Ecosystem size | Massive — hundreds of community hooks | Small, growing becs/ catalog |
| Bypass story | git commit --no-verify skips it | git commit --no-verify skips it too |
Two honest notes on that table. First, the ecosystem row is decisive when your need is “run black, ruff and eslint on commit” — that is pre-commit’s home turf. Second, neither tool survives --no-verify: both are local hooks, so both pair naturally with a CI re-run (becwright check --all works well there).
When is pre-commit alone enough?
- Everything you want to enforce is formatting and linting already covered by existing community hooks.
- Your team has Python everywhere and a mature, pinned
.pre-commit-config.yamlnobody fights. - Your rules don’t need to carry context — no AI agents regenerating code, no “why does this rule exist?” archaeology.
It is also fair to say that secret scanning can live inside pre-commit — gitleaks and detect-secrets both publish pre-commit hooks. What that setup does not give you is checks that work with zero configuration, rules bound to the decision that created them, or a JSON/MCP surface an agent can consume.
Running becwright alongside pre-commit
If pre-commit already owns your hooks, don’t fight it — register becwright as a local hook so both run on every commit:
repos:
- repo: local
hooks:
- id: becwright
name: becwright check
entry: becwright check
language: system
pass_filenames: false
language: system uses the becwright already installed in your project (npm dev dependency or pipx). pass_filenames: false matters: becwright asks git for the staged files itself, so pre-commit should not append its own file list. When a blocking rule fails, becwright check exits with code 1 and pre-commit rejects the commit like any other failing hook.
If you are not a pre-commit shop, you don’t need the framework at all: becwright install (or becwright init, which also scaffolds rules) installs a native git hook directly.
How do you block secrets in commits without Python?
This is the question that most cleanly separates the two tools. With pre-commit, the answer starts with “install Python, then the framework, then choose a secrets hook”. With becwright it is three commands:
npm install --save-dev becwright # self-contained binary, no Python
npx becwright init # scaffolds .bec/rules.yaml + installs the hook
npx becwright check --all # see the current state of the whole repo
From then on the built-in hardcoded_secrets check blocks AWS keys, private keys and password = "..." literals on every commit. For deeper secret detection — entropy analysis and full-history scans — see becwright vs gitleaks.
Which one should you pick?
Usually both. pre-commit orchestrates the tools you already trust; becwright is the layer of deterministic, intent-bound constraints on top — the rules an AI agent cannot talk its way past, because they run against the real code and return pass/fail. If your project is JavaScript-first and you use husky instead of pre-commit, the same logic applies — see becwright vs husky. To try it in three commands, start with the quickstart; to let your agent drive it, see the Claude Code integration.
FAQ
Is becwright a replacement for pre-commit?
No. pre-commit is a framework that installs and runs hooks from a large community ecosystem; becwright is a constraint engine that ships its own deterministic checks and binds each rule to the intent behind it. Teams that already rely on pre-commit for linters and formatters can add becwright as a local hook and keep both tools running on every commit.
Can becwright run as a hook inside pre-commit?
Yes. Declare a repo: local hook whose entry is becwright check, with language: system and pass_filenames: false. becwright asks git for the staged files itself, runs every rule in .bec/rules.yaml, and returns exit code 1 when a blocking rule fails, which makes pre-commit reject the commit exactly like any other failing hook.
How do I block secrets in commits without installing Python?
Install becwright from npm or pnpm: the package ships a self-contained binary for linux-x64, linux-arm64, darwin-x64, darwin-arm64 and win32-x64, so no Python interpreter is required. Run becwright init to scaffold .bec/rules.yaml and install the git hook; the built-in hardcoded_secrets check then blocks AWS keys, private keys and password literals on every commit.