Conceptos
Arquitectura
Cómo el motor matchea archivos, corre checks y decide si un commit puede proceder.
Última actualización
becwright es un motor chico que corre checks sobre tus archivos y decide si un commit puede proceder. Es agnóstico al lenguaje: nunca parsea tu código — filtra archivos por su ruta y corre un comando.
La versión en una frase: por cada regla, becwright elige los archivos a los que aplica y corre un programita (el “check”); si ese programa reporta un problema, una regla blocking frena el commit. Todo lo de abajo es esa misma idea en detalle — los componentes, el flujo exacto y el contrato que un check debe seguir.
El resto de esta página es para los curiosos y para quien escriba sus propios checks.
Componentes
| Módulo | Responsabilidad |
|---|---|
cli.py | CLI con argparse: init / list / check / check-msg / install / uninstall / export / import / add / search |
rules.py | El modelo Rule (incl. severity, target) y la carga de .bec/rules.yaml |
engine.py | Matching de rutas por glob, corre los checks (archivos o mensaje del commit), decide pasa/no-pasa |
git.py | Raíz del repo, archivos en staging, los hooks pre-commit y commit-msg nativos |
checks/ | Checks incluidos (un módulo cada uno) |
bundle.py | Export/import de BECs (el .bec.yaml portable) |
El motor se distribuye como paquete instalado; el repo vigilado solo aporta su
propio .bec/rules.yaml. Ese desacople es lo que permite instalar becwright una
vez y usarlo en muchos repos.
¿Cómo decide becwright pasa/no-pasa?
- Un commit dispara el hook pre-commit, que corre
becwright check. - becwright carga las reglas de
.bec/rules.yaml. - Le pide a git los archivos en staging.
- Por cada regla con
target: files, filtra los archivos por los globs depathsy corre el comandocheckde la regla, pasándole los archivos que matchean por stdin. - El código de salida del check decide el resultado:
0pasa; no-cero falla. - Si alguna regla blocking falló, el commit se rechaza (exit 1). Los hallazgos
warningyadvisoryse imprimen pero nunca frenan (advisoryva etiquetado como best-effort, para checks no-deterministas como un revisor LLM).
git commit
└─▸ hook pre-commit → becwright check
├─ carga .bec/rules.yaml en Rules
├─ obtiene los archivos en staging de git
└─ por cada regla:
├─ matchea archivos contra rule.paths
├─ corre rule.check (archivos por stdin)
└─ código de salida 0 .... PASS
código no-cero
├─ blocking ......... BLOCK (commit rechazado, exit 1)
├─ warning .......... WARN (commit permitido)
└─ advisory ......... ADVISORY (best-effort, commit permitido)
Un hook commit-msg aparte corre becwright check-msg, que aplica las reglas con
target: commit-msg al mensaje del commit del mismo modo (el mensaje se le pasa al
check por stdin en vez de las rutas de archivos).
El contrato del check
El motor corre rule.check como comando de shell con cwd en la raíz del repo,
y le pasa las rutas relevantes (una por línea) por stdin — stdin es
simplemente la entrada estándar del programa, el canal por el que un comando lee.
Un check:
- lee la lista de archivos por stdin,
- imprime las violaciones por stdout (se muestran bajo “Found in:”),
- sale 0 si todo está bien, no-cero si encontró una violación.
Como el contrato es solo “archivos por stdin, código de salida”, un check se puede escribir en cualquier lenguaje. Ver Escribir checks.
¿Por qué becwright es determinista?
A diferencia de una nota en CLAUDE.md que le pide a un agente que se porte
bien, el check de una BEC corre sobre el código real en cada commit y devuelve
pasa/no-pasa sin importar quién o qué produjo el cambio. La regla lleva su
intención y su por qué (la parte bound), el check la vuelve
ejecutable, y un bundle la vuelve portable — ver
Portabilidad.