codarch lint
codarch lint no trae un linter ni escribe configuración: lee el lint que el proyecto ya tiene y escribe un artefacto con lo que dijo. Si el repo no tiene lint, no se lo inventa: recomienda el mínimo y no escribe artefacto. El lint no entra en el snapshot —depende de las herramientas instaladas y de su configuración—, así que tiene su propio fichero, su propio checksum y su propio ciclo de vida. Quien lo mide en el uso normal es codarch analyze, en la misma pasada que las demás lentes; este comando es para medirlo suelto, sin mapa.
Qué detecta
Sección titulada «Qué detecta»| Sistema | Configuración que busca | Qué se lee |
|---|---|---|
| ESLint | eslint.config.*, .eslintrc*, eslintConfig en package.json | eslint --format json y sus reglas activas con --print-config. |
| oxlint | oxlint.json, .oxlintrc.json, .oxlintrc | oxlint --format json y las reglas de su JSON. |
| Biome | biome.json, biome.jsonc | biome lint --reporter=json; sus reglas activas no se enumeran todavía. |
| Ruff | ruff.toml, .ruff.toml, [tool.ruff] en pyproject.toml | ruff check --output-format=json, con el ruff del PATH. |
| Checkstyle | checkstyle.xml, config/checkstyle/checkstyle.xml, el plugin en build.gradle | checkstyle -c <config> -f xml ., con el checkstyle del PATH. El plugin de Gradle no dice qué XML usa: ahí no se mide. |
| go vet | go.mod | go vet ./..., con el go vet del PATH. |
| .NET | *.csproj, *.sln | `dotnet format <solución |
Un sistema entra si tiene su configuración o si su herramienta está instalada. Si hay configuración y no hay binario, el comando lo dice: no se completa con npx, porque descargar una versión que el repo no eligió sería inventar la medida. Si hay binario y no hay archivo de configuración, también se dice con esas palabras, y sus reglas por defecto no se enumeran. Las herramientas corren con el binario del proyecto (node_modules/…) —Ruff y Checkstyle, que no viven ahí, con los que el proyecto tenga en el PATH— y su propia configuración.
Biome no da línea ni columna en su JSON —su span son desplazamientos de bytes—, así que sus mensajes entran sin posición en vez de calcularla a mano. Ruff no da severidad: todos sus hallazgos cuentan como error, que es como los trata al salir con código distinto de cero.
ESLint y oxlint dan el mismo mensaje normalizado: regla, severidad, línea, columna y texto. Las rutas absolutas se hacen relativas a la raíz y las que caen fuera del repo se descartan. Si dos herramientas dicen exactamente lo mismo del mismo sitio, se cuenta una vez.
Reglas activas
Sección titulada «Reglas activas»- ESLint se resuelve con
eslint --print-config <fichero>, que lee la configuración real —flat config, plugins y overrides— en vez de interpretar el fichero a mano. - oxlint se lee de su JSON; sin archivo de configuración corre sus reglas por defecto, y la nota del sistema lo dice: no hay configuración y sus reglas no se enumeran.
- Biome lee de su config las reglas que escribe, con su grupo y su nivel (
style/useConst). Las derecommendeddependen de la versión de Biome y no se enumeran: la nota del sistema lo dice. - Ruff enumera sus reglas, no sus selectores: lee
selectyextend-select(menosignoreyextend-ignore), pide el catálogo a su propia versión conruff rule --all --output-format=jsony expande por prefijo con la especificidad de Ruff: gana el selector más concreto y, si empatan, el ignorado. Sinselect, corren las de por defecto y no se enumeran; sin catálogo, se listan los selectores y se dice. El catálogo se guarda en.codarch/lint-cache.jsoncon la versión de Ruff que lo dio: solo se vuelve a pedir cuando actualizas Ruff. No es parte del artefacto ni del checksum, y no se crea.codarch/para escribirlo. - Checkstyle lee los
<module name="…">de su XML, sin contenedores (Checker,TreeWalker) ni filtros de supresión. Su config no da severidad a cada módulo: la trae cada hallazgo. - go vet y los analizadores de .NET no enumeran sus reglas: van con la versión de Go o con el SDK y
AnalysisLevel. Los hallazgos dego vetentran comogo vet—su texto no firma el analizador—; los de .NET llevan su código (CA1822,CS0168). Una lista plausible sería peor que un hueco.
El override opcional
Sección titulada «El override opcional»El bloque lint: de .codarch.yml es para los comandos que la detección no cubre. Si está, manda y se ejecuta tal cual:
lint: - name: eslint command: node node_modules/eslint/bin/eslint.js . --format json format: eslint-json - name: oxlint command: node node_modules/oxlint/bin/oxlint --format json . format: oxlint-json list: node node_modules/oxlint/bin/oxlint --debug=files .Cada entrada lleva name, command y format (eslint-json, oxlint-json, biome-json, ruff-json, checkstyle-xml, govet-text o dotnet-text). list es opcional: un comando que imprime una ruta por línea, el universo que la herramienta mira, limpios incluidos; sin él no se supone universo. Un bloque mal formado es un error en vez de una adivinanza.
codarch lint [ruta] [opciones]Opciones
Sección titulada «Opciones»| Opción | Qué hace |
|---|---|
-o, --out <dir> | Carpeta del artefacto. Por defecto <ruta>/.codarch. |
--config <file> | YAML con el override. Por defecto .codarch.yml si existe. |
--no-config | Ignora el override del YAML; usa el lint del proyecto. |
--no-detect | No detecta el lint del proyecto. |
--fail-on <modo> | never, errors o warnings. Por defecto never. |
-h, --help | Ayuda. |
-v, --version | Versión. |
Escribe lint.repmod.json en la carpeta de salida. Si crea .codarch/ en la raíz, añade .codarch/ al .gitignore; si la carpeta ya existía, no lo toca. Un .codarch/lint.json o lint.cc.json de una versión anterior no se lee: la hoja dirá «sin medir» hasta que se vuelva a analizar.
{ "schemaVersion": "1.3", "domain": "code", "meta": { "checksum": "…", "tools": ["eslint"], "systems": [ { "name": "eslint", "config": "eslint.config.js", "rules": [{ "id": "no-console", "severity": "warn" }] } ] }, "files": { "src/a.ts": { "errors": 0, "warnings": 1, "messages": [ { "rule": "no-console", "severity": "warn", "line": 1, "column": 1, "message": "Unexpected console" } ] } }, "coverage": { "tools": { "eslint": { "outcome": "enumerated", "measuredPaths": ["src/a.ts"], "eligiblePaths": null } } }, "summary": { "files": 1, "errors": 0, "warnings": 1, "messages": 1, "measured": 1 }}meta.systems dice qué lint tiene el proyecto —con su configuración y sus reglas activas— y meta.tools cuáles midieron de verdad. Un artefacto 1.0–1.2 se sigue leyendo: la cobertura queda en unknown con legacy-global, y no se inventa measured.
summary.measured es cuántos ficheros derivó la cobertura, limpios incluidos, que no aparecen en files. Es una cifra global de la pasada. Solo se escribe si se puede derivar: un cero que no sale de una enumeración válida no se pone. ESLint declara el universo con lo que devolvió —también los limpios— y oxlint con --debug=files, así que el código puede quedar complete (ADR 0110); Checkstyle y las demás siguen en unknown si no listan los limpios. meta.tree es el checksum del snapshot que se midió; lo rellena quien analiza —codarch analyze y, en el live, serve—. Este comando suelto no analiza el repo, así que por sí solo no escribe tree: la app no puede comparar y no lo finge.
summary.files, summary.errors, summary.warnings, summary.messages y los errors y warnings de cada fichero se regeneran al leer desde los mensajes. summary.files son los ficheros con algún hallazgo. Un info cuenta como mensaje y como fichero, y no como error ni aviso. Las rutas se canonizan al leer —NFC por segmento, con /, sin ./ ni barras repetidas— y no se pasan a minúsculas. Si dos claves distintas caen en la misma ruta, no se funden en silencio: la lectura lo deja en diagnostics. El esquema es 1.3. Los nombres siguen siendo lint.repmod.json y lint-rest.repmod.json.
Ficheros por ruta relativa, mensajes ordenados por línea y columna, y un checksum que no cambia si la salida de las herramientas no cambia. Cero hallazgos no es «limpio»: hace falta cobertura complete, árbol al día y algo que medir. Cuando se cumple, la ficha dice «Limpio y al día»; si no, enseña las cuentas y el motivo. Que no haya artefacto significa que nadie midió.
El resumen cuenta la raíz, la fuente, el artefacto, lo que hizo cada herramienta y cada sistema con su configuración. Los ficheros con hallazgos son los que tienen algún mensaje, y se enseñan de los medidos —3 ficheros con hallazgos de 494 medidos—: eso es lo que distingue un repo limpio de uno sin medir. El recuento de reglas y hallazgos es el mismo que leen la app y el MCP, y --fail-on decide con esa misma cuenta, no con el resumen que declare el fichero.

Fallo blando
Sección titulada «Fallo blando»Las herramientas se lanzan en paralelo y el comando espera a todas. Una que no está o que revienta se avisa y las demás siguen: el artefacto se escribe con lo que sí se midió, y solo con esas herramientas.
Un linter con hallazgos sale con código distinto de cero, y eso no es un fallo si dejó su JSON. Por eso el comando no bloquea por defecto: --fail-on errors es lo que se usa en CI, y --fail-on warnings cuenta errores y avisos.
Si el proyecto no tiene lint
Sección titulada «Si el proyecto no tiene lint»No escribe configuración ni lanza un linter que el repo no tiene: el comando sale con 1 y recomienda el mínimo por lenguaje.
| Lenguaje | Mínimo recomendable |
|---|---|
| TypeScript y JavaScript | ESLint + typescript-eslint en recommended. |
| Python | Ruff con select = ["E", "F"]. |
| Go | go vet ./... y staticcheck en CI. |
| Java | Checkstyle con google_checks.xml. |
| C# | Analizadores de .NET con AnalysisLevel=latest-recommended. |
Ejemplos
Sección titulada «Ejemplos»codarch lint .codarch lint . --fail-on errorscodarch lint . --no-detect --config .codarch.ymlCódigos de salida
Sección titulada «Códigos de salida»| Código | Significado |
|---|---|
0 | Artefacto escrito. No dice que el código esté limpio: eso lo dicen sus cuentas. |
1 | Configuración inválida, ninguna herramienta midió (incluido «el proyecto no tiene lint»), no se pudo escribir el artefacto, o --fail-on encontró lo que buscaba. |