Mon skill Claude Code ne partait jamais : le tuto plugin eval
Anthropic a livré le 11 septembre une commande qui mesure ce que votre plugin change vraiment au comportement du modèle.
J'écris des plugins Claude Code pour mon équipe depuis des mois, et je n'avais jamais eu de réponse honnête à la seule question qui compte : est-ce que ce truc change quelque chose au comportement du modèle, ou est-ce que je me suis fabriqué une décoration ? Anthropic a livré la réponse le 11 septembre avec claude plugin eval, dans la version 2.1.269 du CLI. Je l'ai branchée sur un plugin interne dès le lendemain. Verdict : une de mes skills tournait à vide depuis six semaines.
claude plugin eval : ce que la commande fait, et ce que validate ne faisait pas
Jusqu'ici, le seul contrôle disponible était claude plugin validate. Il lit votre plugin.json, vérifie le schéma, la syntaxe des hooks, l'emplacement des dossiers. Utile avant de soumettre au marketplace communautaire, inutile pour juger un comportement. Un plugin peut passer la validation à 100 % et ne jamais se déclencher.
claude plugin eval attaque le problème par l'autre bout. Un cas de test, c'est un prompt réaliste — tapé comme un collègue le taperait — plus un ou plusieurs graders, c'est-à-dire des vérifications pass/fail sur ce que Claude a produit : une regex sur la réponse, la présence d'un appel d'outil, un fichier créé, ou une rubrique jugée par un second modèle.
La vraie idée est ailleurs. Par défaut, chaque cas tourne deux fois de suite : un bras with où le plugin est chargé, un bras without où il ne l'est pas. La différence entre les deux, c'est ce que votre plugin apporte. Rien d'autre. Le guide officiel le formule sans détour : les évals servent à mesurer avec quelle fiabilité un plugin oriente Claude vers le bon résultat, et à attraper les régressions quand vous modifiez le plugin ou quand un nouveau modèle sort.
Installer et générer sa première suite d'évals en 15 minutes
Prérequis : Claude Code en 2.1.269 minimum (la fonctionnalité n'existe pas avant), un plugin qui fonctionne déjà en local, et des crédits API — j'y reviens, parce que ça compte.
Étape 1. Vérifiez la version, puis placez-vous à la racine du plugin :
claude --version
cd ~/dev/plugins/release-notesÉtape 2. Lancez l'assistant. Il vous interroge sur le plugin, propose des cas et des graders, les essaie une fois, puis écrit les fichiers dans evals/ :
Si vous préférez tout écrire à la main, claude plugin eval init --bare premier-cas pose juste le squelette. J'ai commencé par l'assistant, puis j'ai réécrit la moitié des prompts : ceux générés étaient trop propres, trop « documentation », et pas du tout la façon dont mes collègues formulent leurs demandes à 18 h un vendredi.
Le format d'un cas : prompt.md + graders/
Chaque cas est un dossier. Il contient soit un case.yaml, soit la paire plus simple : un prompt.md dont le corps est le prompt, et un dossier graders/ où chaque fichier Markdown déclare un type dans son frontmatter.
evals/
└── prepare-release/
├── prompt.md
└── graders/
├── skill-fired.md
└── changelog-format.mdLe prompt.md accepte des garde-fous d'exécution dans son frontmatter, max_turns et allowed_tools notamment :
---
max_turns: 8
allowed_tools: [Read, Bash, Write]
---
On sort la 2.4.0 demain. Prépare-moi les notes de version à partir des commits depuis le dernier tag.Notez la formulation : pas de /release-notes:generate, pas de nom de skill. C'est tout l'intérêt du test. Si vous appelez la skill explicitement dans le prompt, vous ne testez plus rien d'autre que votre capacité à taper une commande. Même logique que pour la rédaction d'un Claude Skill : la description compte plus que le contenu.
Les 6 graders de Claude Code : 4 gratuits, 2 qui consomment des tokens
Le catalogue se lit en deux blocs, et cette distinction pilote directement votre facture.
- regex — motif recherché dans la réponse. Gratuit, calculé sur le transcript.
- tool_used — tel outil a-t-il été appelé. Gratuit. C'est celui qui répond à « ma skill s'est-elle déclenchée ».
- tool_order — les outils ont-ils été appelés dans le bon ordre. Gratuit.
- file_exists — le fichier attendu a-t-il été écrit. Gratuit.
- llm — un second modèle note la réponse contre une rubrique que vous écrivez. Facturé.
- baseline — comparaison à une réponse de référence. Facturé.
Un détail qui m'a fait relire la doc trois fois : un grader marqué with-only, typiquement tool_used: Skill, est reporté comme indicateur mais exclu du score. Logique — le bras sans plugin n'a aucune skill à déclencher, il échouerait mécaniquement et fausserait le delta. Mais la première fois qu'on voit une ligne rouge qui ne compte pas dans le total, on cherche le bug pendant dix minutes.
Ma règle depuis : un grader de résultat (llm ou regex) plus un tool_used par cas. Le premier dit si le boulot est fait, le second dit qui l'a fait.
Lire le delta, pas le score
Voilà le passage où je me suis pris un mur. Mon plugin release-notes affichait un score WITH de 1,00 sur les trois premiers cas. Parfait, donc. Sauf que la colonne Δ indiquait +0,04. Traduction : Claude faisait le boulot aussi bien sans mon plugin. Six semaines de skill, quatre-vingts lignes de SKILL.md, pour une contribution mesurée à quatre centièmes.
Le tableau de sortie affiche cinq colonnes — WITH, W/OUT, Δ, RUNS, COST — et l'exemple de référence montre à quoi ressemble un plugin qui sert à quelque chose : WITH 1,00, WITHOUT 0,33, Δ +0,67.
Un delta proche de zéro alors que le plugin est bien chargé signifie que votre skill ne se déclenche pas sur une formulation naturelle. C'est un défaut de comportement qu'aucune validation de syntaxe ne peut attraper.
Dans mon cas, le grader tool_used confirmait le diagnostic : la skill ne partait jamais. Sa description commençait par « Generates structured release notes ». Personne n'écrit « generate structured release notes » dans un terminal. J'ai réécrit la description avec les formulations réelles de mon équipe — « prépare la release », « notes de version », « changelog depuis le tag » — et relancé. Δ passé à +0,58 sur le même jeu de cas. Une heure de travail, dont cinquante minutes à relire des transcripts.
Combien coûte une suite d'évals Claude Code
Chaque exécution est un vrai appel modèle, facturé sur votre compte ou votre plan. La doc chiffre un cas unique à environ 0,41 $ pour 74 secondes. Multipliez : par défaut, un cas tourne trois fois par bras, soit six exécutions.
Ma première suite complète — 12 cas, réglages par défaut, graders llm partout — a brûlé un peu plus de 5 $ et 22 minutes. Sur une équipe qui pousse dix PR par jour sur le dépôt de plugins, ça devient une ligne de budget, pas une broutille. Trois leviers, dans l'ordre d'efficacité :
- Dissocier les modèles :
--model claude-sonnet-5pour l'exécution,--judge-model claude-haiku-4-5pour le jugement. C'est la configuration recommandée dans l'exemple CI officiel. - Privilégier les graders gratuits : un
regexbien écrit remplace souvent unllmsur un format de sortie stable. Gardez le juge pour le fond, pas pour la forme. - Plafonner :
--max-cost-usd 20. Le run s'arrête net au plafond.
Le raisonnement rejoint celui que j'appliquais déjà en choisissant un modèle low-cost pour les tâches d'agent : on ne paie le modèle cher que là où il apporte un écart mesurable.
Brancher claude plugin eval dans GitHub Actions (et le piège du code retour)
L'invocation documentée pour la CI tient en une commande :
claude plugin eval . \
--trust-plugin \
--json results.json \
--threshold 0.8 \
--model claude-sonnet-5 \
--judge-model claude-haiku-4-5 \
--no-publish \
--max-cost-usd 20Détail des options qui comptent : --trust-plugin saute la confirmation de confiance en environnement non interactif, --no-publish empêche la remontée des résultats vers claude.ai, --threshold fixe le score de passage (1.0 par défaut, ce qui est brutal), --json écrit un rapport machine. Un report.html autonome atterrit aussi dans evals/results/<timestamp>/ avec le verdict et l'explication de chaque grader — c'est ce fichier que j'attache en artefact de build, pas les logs.
Maintenant le piège, et c'est celui qui m'a coûté ma soirée. Les codes de sortie documentés — 0 succès, 1 cas échoué, 2 run partiel quand le plafond de coût est atteint, 130 interruption — ne se comportent pas comme on l'attend partout, et plusieurs analyses du lancement rapportent des retours qui ne reflètent que les erreurs de manifeste. Résultat : ma gate CI était verte alors que deux cas échouaient. Depuis, je ne fais plus confiance qu'au JSON :
jq -e '.aggregates.casesPassed == (.cases | length)' results.jsonLe schéma expose schemaVersion: 1 et des agrégats exploitables, dont aggregates.meanDelta. C'est ce dernier que je gate en réalité : un plugin dont le delta moyen tombe sous 0,2 ne mérite pas d'être fusionné, même si tous ses cas « passent ». Si vos runs tournent sur votre propre infrastructure, la configuration décrite dans notre tuto sur Claude Code en runner self-hosted s'applique telle quelle.
claude plugin eval ou Promptfoo : lequel pour quoi
La question va se poser à tous ceux qui ont déjà un harnais de tests. Nous avions détaillé la mise en place d'évals de prompts avec Promptfoo il y a un mois : c'est l'outil pour tester des prompts et des sorties de modèle en général, multi-fournisseurs, indépendant de votre agent.
claude plugin eval ne joue pas dans cette catégorie. Il teste une chose précise que Promptfoo ne sait pas mesurer : le comportement d'un agent équipé de vos outils, avec un bras de contrôle sans plugin. Les deux cohabitent bien — Promptfoo sur la couche prompt applicatif, plugin eval sur la couche outillage de l'agent. Et le format de cas est distinct de l'evals/evals.json du plugin skill-creator, ne mélangez pas les deux.
Mon verdict après trois jours
C'est la première fois qu'Anthropic livre une mesure de l'utilité réelle de ce qu'on empile dans son agent, et elle est inconfortable — c'est précisément son intérêt. Sur mes quatre plugins internes, deux ont un delta supérieur à 0,5, un tourne à 0,2, le dernier est bon pour la poubelle. Sans cette commande, j'aurais continué à les maintenir tous les quatre.
Pour qui c'est indispensable : toute équipe qui distribue des plugins ou des skills à d'autres développeurs, et tous ceux qui ont vu un changement de modèle casser silencieusement un workflow d'agent. Le bras de contrôle vaut à lui seul le prix des tokens.
Pour qui c'est prématuré : si vous avez deux skills perso dans .claude/ et que vous êtes le seul utilisateur, --plugin-dir et un aller-retour manuel suffisent. Monter une suite, écrire des rubriques et payer six exécutions par cas pour valider un raccourci que vous tapez vous-même, c'est de la cérémonie.
Le vrai reproche que je fais à la commande aujourd'hui : la variabilité du grader llm. Sur des rubriques un peu subjectives, j'ai vu le même cas passer 2/3 puis 3/3 sans qu'une ligne de code bouge. Écrivez des rubriques binaires et vérifiables, ou restez sur des graders gratuits. Sinon vous allez gater votre CI sur du bruit.