Douze jours entre « si vous le voulez » et Tetris
Les Claude Code Mods sont des modules TypeScript qui tournent à l'intérieur du moteur de Claude Code et interceptent ses événements sous forme de fonctions. Boris Cherny, qui dirige Claude Code chez Anthropic, les a annoncés en cinq mots : « Claude mods are landing now. » Le post a récolté 2 400 likes, et quelqu'un avait déjà construit Tetris dans le terminal. Tetris, Doom, et un animal de compagnie qui grandit pendant que Claude fait tourner vos tests, tout ça affiché au-dessus du prompt, pour zéro token.
L'annonce ne renvoie vers aucune page de doc. Elle renvoie vers une issue GitHub ouverte 12 jours plus tôt par un ingénieur d'Anthropic, avec une condition écrite noir sur blanc. Alice Poteat y écrivait que la réaction de la communauté déciderait probablement si la fonctionnalité sortirait ou non. 177 commentaires plus tard, les gens avaient malmené le binaire caché derrière un flag, mesuré ses timeouts, et construit des jeux dessus.
| Mesure | Valeur |
|---|---|
| Likes sur l'annonce | 2 400 |
| Commentaires sur l'issue GitHub | 177 |
| Surface typée dans le build de la semaine | 10 700 lignes |
| Événements sur des noms (build du fil de l'issue) | 84 sur 19 |
| Mods sur GitHub en 48 heures | 31 |
La page de doc renvoie une 404 au moment où cet article est écrit. Cet article couvre les quatre façons d'étendre Claude Code, un Mod utile construit puis cassé volontairement, et ce qui reste instable avant d'en livrer un.
Un Mod, c'est une fonction au milieu
L'arborescence source le définit en une phrase : un Mod est un plugin Claude Code dont le comportement vit dans un module de hooks. Une entrée d'enregistrement accroche les événements du moteur sous forme de fonctions. Sur le disque, c'est un dossier de plugin, un manifeste de hooks qui nomme exactement un module, et le module lui-même.
Chaque hook est une fonction de trois choses : $, la porte par laquelle passe tout effet de bord ; l'événement ; et la continuation, le reste de la chaîne en dessous de vous. Les hooks s'emboîtent comme du middleware. Celui enregistré en premier possède l'événement, et rien plus bas dans la chaîne ne peut l'inhiber. Cet ordre se configure, il ne s'installe pas. Dans les mots d'Alice Poteat, l'ordre est fixé par la configuration, pas par le moment où vous les avez installés.
Il n'y a pas d'accès ambiant. Tout ce que fait un Mod passe par $, si bien qu'un admin peut auditer, autoriser, refuser ou logger n'importe quel événement. Un commentateur l'a résumé ainsi : ce qu'a fait un plugin, ce sont exactement les appels qu'il a passés. Un seul hook sur * voit tous les événements, donc un journal d'audit tient en une fonction. Un Mod peut dessiner, parce que l'interface est React. Il tourne dans le même process, sur Bun, à 50 microsecondes au 99e centile. Une variable d'environnement suffit à l'activer. Ce qui vit réellement sur $ est encore en cours de conception avec des partenaires en accès anticipé.
Quatre façons d'étendre Claude Code, et laquelle pour quoi
Un shell hook est un script que le moteur appelle à un moment fixe. Il reçoit du JSON sur l'entrée standard et répond par un code de sortie. La réponse a un plafond : 8 000 caractères de contexte renvoyés, et 2 000 pour certains hooks. Dans les mots de Pratham, sous Windows ils cassent souvent de façon bizarre.
Un plugin est une boîte. Un seul manifeste regroupe des skills, des agents, des hooks et des serveurs MCP. Il s'installe depuis une marketplace ou se charge directement depuis un dossier sur disque, et une commande valide la boîte avant que quoi que ce soit ne tourne.
Un skill, c'est de la prose que le modèle lit quand il en a besoin. Le corps ne se charge que si un prompt correspondant arrive. C'est encore la façon la moins coûteuse de changer un comportement.
Un Mod, c'est la même boîte avec un fichier de plus : un manifeste de hooks qui nomme un module, et ce module est du TypeScript, typé, dans le même process, sur chaque événement du moteur. C'est toute la différence.
| Mécanisme | Ce que c'est | Exécution | Plafond |
|---|---|---|---|
| Shell hook | Script appelé à un moment fixe | Sous-processus, code de sortie | 8 000 caractères renvoyés (2 000 pour certains hooks) |
| Plugin | Regroupement de skills, agents, hooks, serveurs MCP | Installé ou chargé depuis le disque | Validé avant de tourner |
| Skill | Prose chargée sur un prompt correspondant | Dans le contexte du modèle | Changement le moins coûteux |
| Mod | Plugin plus un module de hooks TypeScript | Dans le process, sur chaque événement | Typé, accès anticipé |
Les types viennent d'une seule slash command, qui écrit la liste complète de ce que propose $ directement dans votre projet. Les anciens shell hooks sont enveloppés, pas mis à la retraite. Sur un build antérieur, Spencer Morley a vu le wrapper échouer à se charger tout en restant déclaré. La règle de base : pour changer ce que Claude sait, écrivez un skill ; pour lancer un script à un moment donné, un shell hook ; pour livrer un ensemble, un plugin ; pour se loger dans le moteur, un Mod. Le shell hook fonctionne encore partout où le flag est désactivé.
Les trois Mods d'Anthropic, lus depuis le code source
Trois Mods sont livrés dans le binaire et leur source est sur GitHub : un réglage de sécurité par défaut, un panneau de diff, et de la télémétrie.
Le réglage de sécurité par défaut se place tout en dehors. Sur une machine aux réglages administrés, ou dans une organisation Team ou Enterprise, rien de ce qu'installe une personne ne passe au-dessus. Il intercepte 12 événements, et chaque hook fait l'un de trois choix : continuer au-delà du palier utilisateur, refuser un appelant de ce palier par son nom, ou laisser passer. Il échoue fermé, et le commentaire de doc le dit en deux mots. C'est la partie qui a intéressé le fil de discussion : un admin retire une capacité à $, et rien d'enregistré plus bas ne peut l'invoquer. Dans les mots d'un commentateur, c'est catégoriquement différent de demander à un plugin de ne pas faire quelque chose.
Diff est un panneau à côté de la transcription, qui montre les changements non commités de la session, fichier par fichier, rafraîchi à chaque édition de Claude. Il s'enregistre au démarrage de la session et s'étend sur 27 fichiers d'aide, pas un gadget.
Telemetry ajoute un nom à $ depuis l'intérieur de la création du moteur. Il attend ce qui est en dessous et renvoie cela plus lui-même. Il ne tourne que dans les builds internes.
Le README dit d'en lancer un depuis la source et d'en tester un depuis la source. L'aide du build du jour liste validate, eval, et details. Il n'y a pas de test dans la liste, même si l'aide de test répond encore. Le palier intégré refuse aussi votre propre copie : livrez un plugin portant l'un de ces noms, et le binaire charge le sien.
Quarante-deux lignes : un Mod qui cache les secrets au modèle
La slash command qui écrit les types produit, sur ce build, 11 700 lignes : 84 événements répartis sur 23 noms. Le hook d'appel d'outil répond par un résultat ou un refus, jamais le texte. Cette partie est fixée par le cœur du moteur.
Le Mod tient en trois fichiers : le manifeste de plugin, le manifeste de hooks avec sa seule ligne, et le module. Le module fait 42 lignes. Il attend ce qui est en dessous, nettoie le résultat, et le renvoie. Quatre motifs couvrent deux formats de clés de fournisseurs, un token GitHub, et tout ce qui est assigné à une variable appelée key, secret ou token.
Validate lit la source avant qu'elle ne tourne. Il nomme l'événement que le module intercepte et la seule chose qu'il appelle sur $. Le seul avertissement porte sur un auteur manquant. Chargé depuis le disque avec le flag activé, le fichier de test contient deux clés, toutes deux fausses par construction, et le modèle lit « redacted ». Dans ses propres mots, les valeurs sont revenues caviardées, donc il ne peut pas voir ce qu'elles contiennent.
| Mesure | Valeur |
|---|---|
| Longueur du module | 42 lignes |
| Latence du saut, worker inclus | 28 ms |
| Tokens ajoutés à la session | 0 |
Le moteur journalise le saut comme résolu par un module de hooks. L'inventaire ne montre aucun skill, aucun agent, rien de toujours actif. Une limite subsiste : caché au modèle n'est pas caché à l'écran. La transcription montre toujours ce que l'outil a imprimé. C'est un autre Mod, comme l'a noté Max de Ship Notes en une ligne.
Le casser : un garde-fou lent est un garde-fou contourné
Même Mod, une ligne ajoutée : une pause de 15 secondes avant l'appel à ce qui est en dessous. Dix secondes plus tard, le moteur y renonce, rapporte que le hook a dépassé son budget et a été sauté, et ce qui est en dessous tourne à sa place. La commande s'exécute quand même et imprime « hi ».
Remplacez la pause par un throw : 574 millisecondes, même verdict, sauté, et la commande s'exécute.
| Cas | Temps | Verdict |
|---|---|---|
| Hook sain | 28 ms | Résolu |
| Throw | 574 ms | Sauté, la commande s'est exécutée |
| Blocage | plus de 10 s | Sauté, la commande s'est exécutée |
Les deux échecs se terminent par le même mot : sauté. Le fil de discussion avait mesuré cette asymétrie une semaine plus tôt. Une capacité absente au chargement échoue fermée. Un hook qui dépasse son budget échoue ouvert : bruyant mais contourné, dans les mots de Spencer Morley. Un blocage sans raison envoie simplement le modèle vers un autre outil. Pratham l'a vu choisir un autre outil et écrire le fichier quand même.
La réponse sur la table est un catch. Alice Poteat propose un catch sur le retour du hook, qui se déclenche si vous prenez trop de temps ou si vous levez une exception. Une écriture réécrite a quand même besoin d'une note pour le modèle : il voit ce qu'il a demandé d'écrire, pour des raisons de cache, donc vous ajoutez une ligne de contexte. Le budget, c'est aussi l'isolation. Le worker des hooks tourne à part, et quand il plante, le moteur le relance et coupe les hooks pour la session. Le correctif n'est pas un budget plus long mais un catch déclaré.
Quarante-huit heures de Mods, et ce qu'achète une seule phrase
Deux jours plus tard : Tetris au-dessus du prompt et sept autres jeux, jouables pendant que Claude travaille, pour zéro token. Doom, l'original de 1993, tourne dans son propre process ; le Mod l'atteint via HTTP local et redessine 10 fois par seconde. Il y a un pacemaker de respiration dans le spinner, et un modèle narratif à 260 000 paramètres qui tourne dans le worker des hooks, avec zéro token d'API.
Le registre a scanné 31 Mods avec validate. 14 peuvent lancer des processus hôtes. 13 voient chaque appel d'outil.
La démo n°8 du fil communautaire promettait qu'une seule phrase écrit un plugin qui cache les secrets avant que le modèle ne les lise. Nous en avons demandé une.
| Mesure | Valeur |
|---|---|
| Temps | 4 min |
| Tours | 34 |
| Coût | 1,23 $ |
| Lignes (plus un fichier de test) | 190, contre nos 42 |
| Tests | 4 réussis en un tiers de seconde |
Il étiquette ce qu'il cache par type, valide proprement, et n'a besoin ni de clé d'API ni d'appel au modèle. Une réponse l'a formulé ainsi : les allowlists sont le produit, Tetris est la démo.
Verdict : en construire un maintenant, en livrer un plus tard
Les propres chiffres du registre sont l'avertissement. 14 des 31 Mods peuvent lancer des processus hôtes, et le seul contrôle est une empreinte statique. L'aide d'eval le dit elle-même : une suite qui passe n'est pas un contrôle de sécurité.
| Signal | Valeur |
|---|---|
| Événements le 8 | 20 |
| Événements le 15 | 84 |
| Versions CLI en une quinzaine de jours | 14 |
| Points Hacker News | 2 |
| Réponses à la question de compatibilité | 0 |
Le budget de 10 secondes vit dans le runtime, pas dans les types, comme l'a noté Marat. Il n'y a aucune ligne de changelog, aucune page de doc, aucun post de lancement. Un rival affirme qu'Anthropic a copié : Ahmad Awais pointe vers les mods de Command Code, et c'est lui qui écrit leur exemple de mod, donc à prendre avec cette réserve. Le post « accès anticipé, les API peuvent changer » a récolté 357 likes.
Construisez-en un maintenant si vous écrivez déjà des hooks et voulez de l'audit, de la rédaction ou un panneau. Attendez si vous livrez à une équipe avant que le contrat ne soit écrit. C'est cette même ouverture qui a permis que le budget qui échoue ouvert, l'incompatibilité de type sur l'appel MCP et l'échec du wrapper soient trouvés par des utilisateurs en quelques jours.
AIDive