TL;DR
- Un Mod Claude Code tient en trois fichiers :
.claude-plugin/plugin.json,hooks/hooks.jsoncontenant{"modules":["./index.ts"]}, et un module TypeScript qui exporteregister(on). Rien d'autre n'est nécessaire pour le charger. - Sur la build 2.1.272, la surface typée écrite par
/plugin-typesfait 11,783 lignes declaude-code.d.ts: 84 noms d'événements ou d'appels répartis sur 23 noms.fs.readFilea disparu, le nom estfs.readetfs.write. - Un hook
tool.callde 42 lignes a fait lire au modèleAPI_KEY=[REDACTED]au lieu de la vraie clé, avec l'outil Read comme avec l'outil Bash, à 27.9 ms par aller-retour sain et environ 0 token ajouté à la session. - Un hook qui dort au-delà du budget de 10 s ou qui lève une exception est ignoré, et la commande située dessous s'exécute. Le log le signale, mais l'effet est un contournement : un Mod de garde échoue en mode ouvert.
- Le chemin généré fonctionne : une phrase a produit un Mod de 190 lignes plus 53 lignes de tests en environ 4 minutes et $1.23, validé par
claude plugin validatesans avertissement etclaude plugin testavec 4 pass / 0 fail. - Un point n'a pas été reproduit : le Mod s'est chargé sous
claude -pmais est resté muet dans un REPL interactif piloté par pty, sur deux essais. Considérez le chargement en REPL comme non vérifié tant que vous ne l'avez pas testé sur un vrai terminal.
Ce que disent les mesures
Tout ce qui suit a été exécuté sur Claude Code 2.1.272 avec CLAUDE_CODE_ENABLE_FUNCTION_HOOKS activé, sur un Mod écrit à la main nommé redact-secrets et sur trois Mods jetables construits pour le casser. La fonctionnalité est suivie dans l'issue de proposition Function Hooks, qui reste ce qui ressemble le plus à une spec officielle s3.
L'outillage existe avant la doc. La build 2.1.272 embarque claude plugin validate, test, eval et details ; test fonctionne même si plugin --help ne le liste pas dans son bloc de commandes s3. Lancer /plugin-types dans une session a écrit 11,783 lignes dans .claude/types/claude-code.d.ts, plus un claude-code-mcp.d.ts de 3,438 lignes couvrant 150 outils MCP issus de 7 serveurs s3. En comptant les types générés, on obtient 84 noms d'événements ou d'appels répartis sur 23 noms, et le fichier renomme une chose dont vous avez peut-être lu parler dans les articles de septembre : fs.readFile n'existe plus, la surface est fs.read et fs.write s9. Les mêmes types disent qu'un hook tool.call renvoie { result, context? } ou { deny } ; text et ref viennent du core et ne font pas partie de la réponse propre au hook, donc on réécrit result, pas text s3.
claude plugin validate affiche une empreinte avant même que le Mod ne tourne : ./index.ts hooks: tool.call et ./index.ts calls: $.ui.toast, ou calls: nothing on $ quand le module ne touche aucune capacité de l'hôte s4. Cette ligne statique est la seule vérification qu'un annuaire comme awesome-claude-code-mods peut automatiser aujourd'hui, ce qui compte pour la suite.
La rédaction fonctionne en mode -p. Le hook de 42 lignes a intercepté tool.call, et le modèle a reçu API_KEY=[REDACTED] là où le fichier et la sortie du shell contenaient sk-test1234567890abcdef, avec l'outil Read comme avec l'outil Bash s3. Le log de debug a chronométré un aller-retour sain à 27.9 ms, saut vers le worker et next() compris s3. claude plugin details a chiffré le Mod à environ 0 token ajouté à chaque session : un Mod est du code dans le processus, pas du texte de prompt, ce qui est le principal argument de ses promoteurs face aux hooks shell et aux skills s7.
La garde échoue en mode ouvert. Un Mod slow-guard qui dort 15 s a été coupé au budget de 10 s avec hook failed: slow-guard: exceeded 10000ms budget (tool.call; skipped; what is below it ran in its place), et echo hi s'est exécuté quand même s3. Un Mod throw-guard qui lève une exception a été ignoré de la même façon, hook failed: throw-guard: boom (tool.call; skipped; what is below it ran in its place), avec 574.2 ms rapportées s3. Bruyant dans le log, contourné dans les faits. Tout Mod dont le rôle est de bloquer quelque chose doit se lire avec ça en tête : un bug dans la garde est un trou, pas un crash.
La génération coûte peu. À partir d'une seule phrase, le modèle a écrit un Mod fonctionnel de 190 lignes plus 53 lignes de tests en environ 4 minutes, 34 tours et $1.23 (19,053 tokens de sortie, 497,282 en lecture de cache, 8,357 de réflexion) s3. Ce Mod a passé claude plugin validate sans avertissement et claude plugin test avec 4 pass / 0 fail en 0.31 s, et a masqué les clés en direct s3. Sur le Mod écrit à la main, claude plugin test a tourné sans clé API et sans appel au modèle : 1 pass en 0.25 s s3. Un skill qui apprend aux agents à écrire des Mods existe déjà si vous voulez refaire l'expérience à partir d'un modèle s12.
Ce qui n'a pas été reproduit : $.ui.toast ne s'est jamais affiché parce que le Mod ne s'est pas chargé dans le REPL piloté par pty sur 2 essais ; en -p, l'équivalent n'est apparu que comme une ligne de debug. Le contraire de l'affirmation « REPL uniquement » qui circule sur X a été observé, et la cause racine n'a pas été isolée s8. Le heartbeat de 5 s du worker bloqué n'a pas été testé non plus ; seuls le budget d'attente de 10 s et le chemin d'exception ont été mesurés.
Mesures
| Cas | Ce que fait le Mod | Résultat | Durée |
|---|---|---|---|
| redact-secrets, outil Read | Réécrit result sur tool.call |
Le modèle voit API_KEY=[REDACTED] |
27.9 ms par saut |
| redact-secrets, outil Bash | Même hook, sortie du shell | Le modèle voit API_KEY=[REDACTED] |
27.9 ms par saut |
| slow-guard | Dort 15 s dans tool.call |
Ignoré, echo hi exécuté |
coupé à 10000 ms |
| throw-guard | Lève boom dans tool.call |
Ignoré, commande exécutée | 574.2 ms |
| Mod généré | 190 lignes + 53 lignes de tests à partir d'une phrase | validate : aucun avertissement ; test : 4 pass / 0 fail | ~4 min, 34 tours, $1.23 |
claude plugin test sur redact-secrets |
Sans clé API, sans appel au modèle | 1 pass | 0.25 s |
claude plugin details |
Coût du Mod par session | ~0 token ajouté | n/a |
Protocole : Claude Code 2.1.272, function hooks activés par variable d'environnement. Chaque Mod est un répertoire de plugin avec plugin.json, hooks/hooks.json et un seul index.ts. Les exécutions sont passées par claude -p avec le log de debug activé ; un fichier piégé et une commande shell contenaient tous deux sk-test1234567890abcdef. Les cas d'échec en mode ouvert ont été pilotés par un Mod qui dort 15 s et un Mod qui lève une exception, avec echo hi comme commande sous garde. Le REPL interactif a été piloté via un pty et n'a pas chargé le Mod sur deux essais.
À faire lundi
- Lancez
/plugin-typesdans une session et ouvrez.claude/types/claude-code.d.ts: cherchezfs.readettool.callavant de faire confiance à un extrait tiré d'un article de septembre. - Écrivez le squelette de Mod en trois fichiers (
plugin.json,hooks/hooks.jsonavec{"modules":["./index.ts"]},index.tsexportantregister(on)) et lancezclaude plugin validatedessus : lisez les lignes d'empreintehooks:etcalls:. - Portez votre hook shell le plus utilisé vers un handler
tool.callqui réécritresult, puis comparez le temps de saut dans le log de debug avec la version shell. - Ajoutez un fichier
claude plugin testà côté du Mod pour que la garde tourne sans clé API en CI. - Enveloppez chaque handler de garde dans un try/catch qui renvoie
{ deny }en cas d'échec : sur cette build, une exception ou un blocage de 10 s vous ignore et laisse passer la commande. - Testez le Mod sous
claude -pet dans votre vrai terminal interactif séparément, et notez lequel l'a chargé. - Avant d'installer un Mod tiers, lancez
claude plugin validatedessus et rejetez tout Mod dont la lignecalls:nomme des capacités de l'hôte sans rapport avec son rôle.
Aller plus loin
- Lisez l'issue de proposition de bout en bout, y compris le PDF d'architecture joint dans les commentaires : c'est le seul contrat écrit pour
register(on), les budgets et le saut vers le worker s3. - Comparez avec la conception des Mods de Command Code, qui exécute du TypeScript contre un
ModApidans le processus hôte : les deux systèmes partagent la forme et l'accès anticipé restreint s2. - L'aperçu de claudefa.st a été écrit quand la fonctionnalité n'était encore qu'une proposition : utile pour voir ce qui a changé entre le texte du 3 septembre et le binaire 2.1.272 s9.
- La note de Prathkum est l'énoncé court le plus clair de la raison pour laquelle les hooks en processus battent les hooks shell sur les tokens et la latence s7.
- cc-mod-waitwhat est un bon premier Mod à lire : de l'UI au-dessus du prompt, rien d'écrit dans la transcription s11.
- cc-arcade montre jusqu'où va
$.ui: des jeux affichés au-dessus du prompt depuis un Mod s5. - La référence des hooks décrit toujours le modèle shell ; gardez-la ouverte pour faire correspondre chaque ancien événement à son nouveau nom
noun.events1. - Les sceptiques sur X affirment que les plugins couvrent déjà ce besoin et que la surface cassera à chaque version ; le nom
fsrenommé est un argument pour eux s23.
Sources
- Function Hooks proposal (issue #91870), GitHub, anthropics/claude-code. Pourquoi le lire : le seul texte proche d'une spec pour les Mods, avec le PDF d'architecture et la trace des livraisons dans les commentaires.
- Hooks reference, Claude Code docs. Pourquoi le lire : le modèle de hooks shell dont vous partez, événement par événement.
- Command Code Mods documentation, Command Code. Pourquoi le lire : un précédent avec la même forme TypeScript en processus, utile pour repérer ce qu'Anthropic a copié ou évité.
- awesome-claude-code-mods, GitHub, karanb192. Pourquoi le lire : annuaire de Mods publics scanné automatiquement, avec l'empreinte de validate comme seule vérification.
- cc-arcade, GitHub, sezaakgun. Pourquoi le lire : la démo qui a rendu la fonctionnalité visible, et une visite de
$.ui. - Boris Cherny announcement tweet, X, Boris Cherny. Pourquoi le lire : l'annonce de lancement par un ingénieur d'Anthropic, faute d'article de blog.
- Prathkum: Function Hooks explained, X, Prathkum. Pourquoi le lire : la meilleure explication courte hooks contre Mods pour quelqu'un qui écrit déjà des hooks shell.
- shipnotesai reaction thread, X, shipnotesai. Pourquoi le lire : l'endroit où l'affirmation « REPL uniquement » a circulé, que notre essai contredit.
- Claude Code Function Hooks: Preview Behind a Flag, claudefa.st. Pourquoi le lire : explication avant sortie, utile pour comparer la proposition au binaire.
- cc-mod-waitwhat, GitHub, GGGODLIN. Pourquoi le lire : un petit Mod lisible qui écrit dans l'UI et pas dans la transcription.
- claude-mods-skill, GitHub, BeLazy167. Pourquoi le lire : un skill de génération de Mods, si vous voulez refaire l'expérience en une phrase.
- AxialisSoftware reaction, X, AxialisSoftware. Pourquoi le lire : le cas sceptique, en un seul tweet.
FAQ
Un Mod remplace-t-il mes hooks shell dès aujourd'hui ?
Pas encore pour tout ce qui doit bloquer. Sur 2.1.272, un hook qui lève une exception ou bloque au-delà de 10 s est ignoré et la commande s'exécute. Les hooks shell continuent de fonctionner : gardez-y ceux qui bloquent jusqu'à l'arrivée d'un catch déclaré ou d'une option d'échec fermé.
Pourquoi validate compte-t-il si le Mod tourne bien ?
Parce que ses lignes hooks: et calls: sont la seule vue statique de ce qu'un Mod touche sur $. Pour votre propre Mod, elle confirme l'empreinte ; pour un Mod tiers, c'est toute la revue dont vous disposez avant que le code ne tourne dans votre processus.
Combien un Mod coûte-t-il par session ?
claude plugin details a rapporté environ 0 token ajouté. Le Mod est du code qui tourne dans le moteur, pas du texte dans le prompt, ce qui est son principal avantage sur un skill ou une règle CLAUDE.md.
Pourquoi le Mod s'est-il chargé en -p mais pas dans le REPL ?
On ne sait pas. Deux essais pilotés par pty sont restés muets alors que claude -p chargeait et appliquait le hook. La cause probable est l'environnement pty plutôt que la fonctionnalité, donc testez sur votre propre terminal avant de vous fier à l'un ou l'autre sens.
AIDive