Skip to content

Tutoriel Claude Code Mods : créer, tester et installer votre premier mod, avec 15 exemples de la communauté

Mis à jour le

Les mods Claude Code (v2.1.287+) sont des plugins de fonctions TypeScript qui dessinent des panneaux, ajoutent des commandes slash instantanées et filtrent les appels d’outils. Créez et testez trois mods fonctionnels, parcourez 15 mods de la communauté et faites les vérifications de sécurité avant d’en installer un.

Un mod Claude Code est un plugin composé de fonctions JavaScript ou TypeScript qui s’exécutent à l’intérieur de Claude Code. Un mod peut dessiner un panneau ou une ligne au-dessus du prompt, ajouter une commande slash qui s’exécute instantanément, et bloquer ou réécrire un appel d’outil avant son exécution. Les mods sont arrivés dans Claude Code 2.1.287 le 1er octobre 2026, et ils sont activés par défaut.

Choisissez le point d’entrée le plus rapide :

Vous voulezFaites ceci
Obtenir un mod sans écrire de codeDécrivez-le dans une session, par exemple « crée un mod qui affiche la durée de chaque tour ». Claude l’écrit et vous demande une seule fois d’activer le rechargement à chaud
Installer le mod de quelqu’un d’autre/plugin install <name>@<marketplace> dans une session du terminal, ou claude plugin install <name>@<marketplace> dans votre shell
Charger un dossier pendant le développementclaude --plugin-dir ./my-mod
Essayer l’agent annexe intégré/plugin enable cc-plugin-you-should-know@builtin

Vérifiez d’abord votre version. claude --version doit afficher 2.1.287 ou une version ultérieure. L’application Desktop embarque sa propre copie de Claude Code, et les mods y fonctionnent à partir de 2.1.286. Tapez /status dans l’onglet Code pour savoir laquelle vous avez.

Ce que j’ai testé. Le 7 octobre 2026, j’ai créé trois mods sur Claude Code 2.1.293, dans l’onglet Code de l’application Desktop sous macOS : un garde-fou pour les commandes, un compteur de tours au-dessus du prompt et une commande /pyenv pour le travail en Python. Les trois passent claude plugin validate ainsi que 8 tests automatisés exécutés avec claude plugin test. J’ai aussi fait tourner le garde-fou en direct dans une session, avec le rechargement à chaud activé. Les sections sur la communauté s’appuient sur environ 50 articles japonais publiés sur Zenn, Qiita et note.com du 1er au 7 octobre, sur la documentation officielle des mods (opens in a new tab) et sur les données du scan du catalogue awesome-claude-code-mods (opens in a new tab) du 6 octobre.

Ce qu’est un mod, et quand utiliser autre chose

Avant les mods, vous étendiez Claude Code depuis l’extérieur, avec des settings hooks, des skills, un script de barre d’état (status line) ou un serveur MCP. La différence tient à l’endroit où le code s’exécute. Un settings hook est un script que Claude Code lance depuis l’extérieur. Les fonctions d’un mod s’exécutent dans le processus même de Claude Code : un mod peut donc dessiner dans l’interface, ce qu’aucune des autres options ne permet.

La page de présentation officielle les compare à peu près ainsi :

ModSettings hookSkillServeur MCP
Ce que c’estDes fonctions JS ou TS dans un pluginUne commande shell, un appel HTTP ou un prompt dans settings.jsonUn fichier SKILL.md d’instructionsUn processus externe qui fournit des outils à Claude
Peut dessiner dans l’interfaceOuiNonNonNon
Ce qu’il peut modifierAppels d’outils, prompts, commandes, tours, l’interfaceSi un appel a lieu, ses arguments et son résultat, du contexte supplémentaireCe que Claude sait et faitLes outils dont Claude dispose
À choisir quandVous voulez un panneau, un bandeau, une commande instantanée, ou réécrire un événementVous avez déjà un script qui bloque ou journaliseVous collez sans cesse les mêmes instructionsClaude doit accéder à un système externe

Un piège de vocabulaire à connaître. Dans les pages sur les mods, « hook » désigne une fonction de mod, et l’ancien type s’appelle « settings hook ». Les settings hooks fonctionnent toujours et ne sont pas dépréciés. Un même plugin peut contenir à la fois un mod, un skill et un serveur MCP.

Où les mods fonctionnent

Les hooks s’exécutent presque partout. L’interface d’un mod, elle, ne s’affiche que dans le terminal et dans l’application Desktop.

Où vous lancez Claude CodeHooks exécutésInterface du mod affichée
claude dans un terminal, y compris les terminaux d’éditeur et JetBrainsOuiOui
Application Desktop, onglet CodeOuiOui, sauf les éléments réservés au terminal
Application Desktop, session WSLNonNon
Panneau de chat de l’extension VS CodeOuiNon
claude -p et l’Agent SDKOuiNon
Sessions cloudOui, si le plugin arrive jusqu’à la sessionNon

Ce tableau vient de la page de présentation officielle. Concrètement, un mod garde-fou vous protège toujours dans VS Code et dans claude -p, alors qu’un compteur n’a nulle part où s’afficher.

Méfiez-vous des deux copies de Claude Code. Plusieurs auteurs japonais ont obtenu des erreurs validate déroutantes parce qu’un ancien CLI pour terminal, installé avec Homebrew (les versions 2.1.226 et 2.1.234 dans leurs comptes rendus), cohabitait avec la version 2.1.286 embarquée dans l’application Desktop. Vérifiez la version partout où vous utilisez Claude Code.

Comment un mod est organisé

Un petit mod tient en trois fichiers :

safe-shell/
├── .claude-plugin/
│   └── plugin.json      name, version, description
└── hooks/
    ├── hooks.json       { "modules": ["./register.ts"] }
    └── register.ts      your code

register.ts exporte une seule fonction, register(on). Chaque appel on(event, matcher, hook) ajoute un hook, et chaque hook reçoit les trois mêmes arguments.

  • $ est le moteur. Tout ce qui se trouve hors de votre propre code passe par lui : $.ui.toast, $.process.run, $.state, $.model.complete.
  • e est l’événement, par exemple la commande Bash que Claude s’apprête à exécuter.
  • next(e) transmet l’événement aux autres mods, puis à Claude Code. Si votre hook retourne sans l’appeler, il répond lui-même. Appelez next({ ...e, command }), et vous changez ce qui se passe.

Le module n’a accès ni à Node ni au DOM. C’est cette limite qui permet à Claude Code de lister tout ce qu’un mod appelle avant de l’exécuter. Essayez sur n’importe quel dossier de mod :

claude plugin validate ./safe-shell

Mod 1 : un garde-fou qui bloque les commandes destructrices

Si vous utilisez Claude en mode auto ou avec bypass permissions, rien ne l’arrête avant un git reset --hard. Ce mod refuse trois types de commandes shell et tient les fichiers .env à l’écart de la conversation.

import type { Register } from 'claude-code'
 
// Shell commands an agent should never run without a human typing them.
const BLOCKED: { pattern: RegExp; reason: string }[] = [
  {
    pattern: /\brm\s+-[a-zA-Z]*[rR][a-zA-Z]*\s+(\/|~|\$HOME)\/?\*?(\s|$)/,
    reason: 'recursive delete of / or the home folder',
  },
  {
    pattern: /\bgit\s+push\b.*(--force\b|--force-with-lease\b|\s-f\b).*\b(main|master)\b/,
    reason: 'force push to main or master',
  },
  {
    pattern: /\bgit\s+reset\s+--hard\b/,
    reason: 'git reset --hard throws away uncommitted work',
  },
]
 
// .env, .env.local, config/.env.production ... but not .env.example.
const isSecretEnvFile = (path: string) =>
  /(^|\/)\.env(\.[^/]+)?$/.test(path) && !/\.(example|sample|template)$/.test(path)
 
export const register: Register = on => {
  on('tool.call', { tool: 'Bash' }, ($, e, next) => {
    const hit = BLOCKED.find(rule => rule.pattern.test(e.command))
    if (hit === undefined) {
      return next(e)
    }
    $.ui.toast(`safe-shell blocked: ${hit.reason}`)
 
    return { deny: `safe-shell: blocked (${hit.reason}). Ask the user to run it themselves.` }
  }).catch(($, e, next) =>
    // Fail closed: if the guard itself breaks, refuse instead of letting the command through.
    next.called ? next(e) : { deny: 'safe-shell: the guard failed, so the command was not run.' },
  )
 
  for (const tool of ['Read', 'Edit', 'Write'] as const) {
    on('tool.call', { tool }, ($, e, next) =>
      isSecretEnvFile(e.file_path)
        ? { deny: `safe-shell: ${e.file_path} holds secrets and stays out of the conversation.` }
        : next(e),
    ).catch(($, e, next) =>
      next.called ? next(e) : { deny: 'safe-shell: the guard failed, so the file was not touched.' },
    )
  }
}

Deux détails comptent plus que les expressions régulières.

Le garde-fou décide avant d’appeler next. Dès que next s’exécute, la commande a déjà été lancée. Un deny renvoyé après coup n’annule rien.

Le .catch le fait échouer en mode fermé (fail closed). Un hook qui lève une exception, ou qui dépasse son budget de 10 secondes, est ignoré, et un garde-fou ignoré laisse passer la commande. Le gestionnaire next.called ? next(e) : deny refuse à la place. validate signale chaque hook capable de bloquer un appel (gating hook) et indique s’il a un .catch. C’est la première chose à vérifier sur le garde-fou de quelqu’un d’autre :

❯ ./register.ts hooks: tool.call{tool=Bash}, tool.call{tool=Read|Edit|Write}
❯ ./register.ts gating hook with .catch: tool.call{tool=Bash}
❯ ./register.ts gating hook with .catch: tool.call{tool=Read|Edit|Write}
❯ ./register.ts calls: $.ui.toast
✔ Validation passed

Le tester sans session

claude plugin test exécute les fichiers *.test.ts d’un mod contre le moteur, sans session, sans authentification et sans réseau. Le kit de test n’a rien sous votre mod : chaque test enregistre donc des hooks de substitution pour tout ce que le mod transmet :

import { expect, test } from 'claude-code/testing'
 
const ran = { stdout: 'ran', stderr: '', interrupted: false }
 
test('blocks rm -rf on the home folder', async ($, on) => {
  on('tool.call', { tool: 'Bash' }, () => ({ result: ran }))
  const answer = await $.tool.call({ tool: 'Bash', command: 'rm -rf ~' })
  expect(answer.deny).toContain('recursive delete')
})
 
test('lets ordinary commands through', async ($, on) => {
  on('tool.call', { tool: 'Bash' }, () => ({ result: ran }))
  const answer = await $.tool.call({ tool: 'Bash', command: 'rm -rf ./build && python -m pytest -q' })
  expect(answer.deny).toBeUndefined()
})

Le fichier complet contient quatre tests :

(pass) blocks rm -rf on the home folder [16.23ms]
(pass) blocks a force push to main [7.73ms]
(pass) lets ordinary commands through [7.22ms]
(pass) keeps .env out of Read but allows .env.example [9.40ms]

 4 pass
 0 fail

Mon premier lancement a échoué avec on("tool.call") after the test first called $. Enregistrez les substituts en haut de chaque test, avant le premier appel à $.

Ce qui s’est passé en session réelle

Avec le rechargement à chaud activé, j’ai demandé à Claude d’exécuter echo "the words git reset --hard inside an echo". Le garde-fou a refusé la commande avec « blocked (git reset --hard throws away uncommitted work) », et une notification toast s’est affichée. Or cette commande était inoffensive. La recherche de motifs ne distingue pas une commande d’un texte qui la mentionne, et elle rate aussi une commande cachée dans une variable, un script ou un alias. Les auteurs japonais qui ont publié des garde-fous similaires, comme rafi-guard, delete-guard et board-guard, signalent ces deux problèmes.

Considérez un mod garde-fou comme un second filet de sécurité. Tout ce qui ne doit jamais arriver a aussi sa place dans une règle de permission deny. Attention aussi au sens inverse. La documentation officielle indique que, sur une machine personnelle sans paramètres gérés (managed settings), un mod peut approuver un appel qu’une règle deny refuse. Les mods ne tournent pas dans une sandbox. Ils s’exécutent avec vos permissions.

Mod 2 : un compteur au-dessus du prompt

Le bandeau au-dessus du prompt et le panneau latéral sont les endroits où les mods dessinent le plus. Dans le scan du catalogue du 6 octobre, 41 % des mods dessinent dans le bandeau et 40 % ouvrent un panneau. Celui-ci affiche la durée du dernier tour, ses appels d’outils et ses tokens, avec un bouton Hide.

Les valeurs que lit un affichage vont dans $.state, et chacune est déclarée dans un petit fichier de types :

// types/index.d.ts, named in plugin.json as "types": "./types/index.d.ts"
export type TurnStats = {
  seconds: number
  tools: number
  inputTokens: number
  outputTokens: number
  model: string | null
}
 
declare module 'claude-code' {
  interface PluginState {
    'turn-meter': { last: TurnStats | null; isHidden: boolean }
  }
}

Les hooks comptent les appels d’outils, lisent durationMs et usage dans turn.complete, puis dessinent le bandeau :

import { atom, read, update } from 'claude-code'
import type { Register } from 'claude-code'
 
import type { TurnStats } from '../types'
 
const last = atom({ plugin: 'turn-meter', key: 'last' } as const, null)
const isHidden = atom({ plugin: 'turn-meter', key: 'isHidden' } as const, false)
 
const formatTokens = (n: number) => (n >= 1000 ? `${(n / 1000).toFixed(1)}k` : String(n))
 
export const register: Register = on => {
  let tools = 0
 
  on('prompt.submit', ($, e, next) => {
    tools = 0
    return next(e)
  })
 
  on('tool.call', ($, e, next) => {
    // Count the main conversation's calls; subagents carry an agentId.
    if (e.agentId === undefined) tools += 1
    return next(e)
  })
 
  on('turn.complete', async ($, e, next) => {
    if (e.agentId !== undefined) return next(e)
    const usage = e.usage
    const stats: TurnStats = {
      seconds: Math.round(e.durationMs / 1000),
      tools,
      inputTokens: usage
        ? usage.input_tokens + usage.cache_read_input_tokens + usage.cache_creation_input_tokens
        : 0,
      outputTokens: usage?.output_tokens ?? 0,
      model: usage?.model ?? null,
    }
    await update($, last, () => stats)
    if (stats.seconds > 120) $.ui.toast(`That turn took ${stats.seconds}s`)
    return next(e)
  })
 
  on('ui.render', { component: 'AbovePrompt' }, async ($, e, next) => {
    const stats = await read($, last)
    if (e.props.hasSurvey || stats === null || (await read($, isHidden))) return next(e)
 
    const { Box, Button, Text } = $.ui.resolve(e)
    const model = stats.model === null ? '' : ` · ${stats.model}`
    // The band is shared by every mod: keep what the mods beneath drew, then add a row.
    const below = await next(e)
 
    return (
      <Box flexDirection="column">
        {below}
        <Box>
          <Text dimColor>
            {`Last turn: ${stats.seconds}s · ${stats.tools} tool calls · ${formatTokens(stats.inputTokens)} in / ${formatTokens(stats.outputTokens)} out${model} `}
          </Text>
          <Button key="hide" label="Hide" onPress={() => update($, isHidden, () => true)} />
        </Box>
      </Box>
    )
  })
}

Dans le test, sur les surfaces terminal et Desktop, le bandeau affiche :

Last turn: 42s · 0 tool calls · 18.2k in / 800 out · claude-opus-5-5 [ Hide ]

Trois choses que j’ai apprises en le construisant :

  • Gardez les valeurs affichées dans $.state, pas dans des variables du module. Un rechargement à chaud relance register et réinitialise vos variables, alors que $.state survit. /clear repart de zéro : si une valeur doit y survivre, écrivez-la dans $.store sur session.end.
  • Le bandeau est partagé. Appelez next(e) et placez son résultat dans votre Box, sinon vous masquez la ligne de tous les autres mods. Un auteur sur note.com a perdu l’un de ses bandeaux, masqué par un autre mod, avant de comprendre ce point.
  • Les éléments Text ne conservent pas de key. Dans les tests, retrouvez-les par leur contenu : ui.find({ type: 'Text', text: /Last turn/ }).

Mod 3 : /pyenv, quand Claude lance le mauvais Python

J’ai cherché des mods pour la data science et j’ai trouvé un manque. Sur les 2 690 mods du scan du 6 octobre, aucun ne mentionne Jupyter, pandas, DataFrames, Polars, venv ou conda dans son nom ou sa description.

Le problème derrière ce mod est courant en analyse de données. L’outil Bash de Claude exécute le premier python3 trouvé dans votre PATH, et ce n’est souvent pas l’environnement de votre projet. Voici ce que la sonde a affiché sur ma machine :

python: /Users/<you>/.local/bin/python3 (3.14.2)
env: none (system or tool-managed Python)
pandas: 3.0.1
numpy: 2.4.2
polars: not installed
matplotlib: 3.11.0
pygwalker: not installed

Aucun environnement virtuel n’était actif : un pip install lancé par Claude serait donc allé dans un interpréteur global.

La commande /pyenv lance cette sonde et répond en deux parties. text est la ligne que vous voyez. context est une note que seul le modèle lit : les appels Bash suivants de Claude savent ainsi quel interpréteur est utilisé, sans nouveau prompt de votre part.

import type { Register } from 'claude-code'
 
// Reads package versions from metadata instead of importing them, so it stays fast.
const PROBE = `
import os, sys
from importlib.metadata import PackageNotFoundError, version
env = os.environ.get("VIRTUAL_ENV") or os.environ.get("CONDA_PREFIX") or "none (system or tool-managed Python)"
print(f"python: {sys.executable} ({sys.version.split()[0]})")
print(f"env: {env}")
for name in ("pandas", "numpy", "polars", "matplotlib", "pygwalker"):
    try:
        print(f"{name}: {version(name)}")
    except PackageNotFoundError:
        print(f"{name}: not installed")
`
 
export const register: Register = on => {
  on('session.start', async ($, e, next) => {
    await $.command.register({
      name: 'pyenv',
      description: "Show which Python, environment and data packages this session's shell uses",
    })
    return next(e)
  })
 
  on('command.run', { command: 'pyenv' }, async $ => {
    try {
      const probe = await $.process.run(['python3', '-c', PROBE], { timeoutMs: 15_000 })
      if (probe.exitCode !== 0) {
        return { text: `pyenv: python3 exited with ${probe.exitCode}: ${probe.stderr.trim().slice(0, 300)}` }
      }
      const report = probe.stdout.trim()
      // `text` is the row you see; `context` is a note only the model reads.
      return {
        text: report,
        context: [`Python environment of this session's shell, from /pyenv:\n${report}`],
      }
    } catch (error) {
      return { text: `pyenv: could not run python3 (${String(error).slice(0, 200)})` }
    }
  })
}

La commande slash d’un mod exécute votre fonction immédiatement, sans tour du modèle, même pendant que Claude travaille. $.process.run prend une liste d’arguments, sans shell, et s’interrompt au bout de 30 secondes sauf si vous définissez timeoutMs.

$.process.run voit-il le même PATH que l’outil Bash de Claude ? Un auteur de la communauté a constaté que le node de nvm manquait dans les processus d’un mod. J’ai donc vérifié avec un mod sonde temporaire. Dans ma session Desktop, un simple $.process.run obtenait exactement le PATH de l’outil Bash et le même python3. Passer par un shell de connexion, zsh -lc, donnait la mauvaise réponse : la sonde tombait sur le Python 3.10.9 de python.org, car un shell de connexion non interactif ignore ~/.zshrc, où se trouvent la plupart des ajouts au PATH. Gardez l’appel simple. Si un résultat vous semble faux sur votre machine, comparez-le avec !which python3 tapé dans le prompt de Claude Code.

Les tests ont révélé un autre piège. Les appels sur $, comme $.process.run et $.command.register, ont eux aussi besoin de substituts, et un substitut d’appel $ répond { value: ... }. Si vous renvoyez le résultat brut, le kit le refuse.

Si l’essentiel de vos analyses se fait dans des notebooks plutôt que dans des scripts, cette approche a ses limites : Claude Code modifie les fichiers .ipynb comme du JSON et ne voit jamais le kernel en cours d’exécution. RunCell (opens in a new tab) est un agent pour notebooks qui exécute les cellules et lit directement leurs sorties : il convient mieux à ce type de travail.

Laisser Claude écrire le mod

Vous n’êtes pas obligé d’écrire tout cela à la main. Il suffit de demander dans une session, par exemple « crée un mod qui affiche ma consommation sur 5 heures au-dessus du prompt ». Claude charge le skill intégré plugin-authoring et écrit les fichiers dans ~/.claude/dev-mods/<session-id>/. Le premier fichier déclenche une seule question, « Enable hot reloading for this session? ». Une fois que vous acceptez, chaque modification se recharge à la fin du tour de Claude. C’est ainsi que les trois mods ci-dessus ont été construits et chargés.

Ce qu’ajoutent la documentation et la communauté :

  • Copiez le dossier dans un emplacement permanent. Des auteurs sur Qiita et Zenn signalent que les dossiers dev-mods sont nettoyés avec les anciennes sessions au bout d’environ 30 jours.
  • Développez avec claude --plugin-dir ./my-mod. Un mod installé exécute une copie en cache : modifier son dossier ne change rien tant que vous ne mettez pas le plugin à jour.
  • L’application Desktop n’accepte aucun flag. Définissez CLAUDE_CODE_PLUGIN_DIRS dans le bloc env de ~/.claude/settings.json. Les paramètres du projet sont ignorés pour ce réglage.
  • Lancez /plugin. Une ligne grisée comme 1 mod active · safe-shell confirme que le mod est chargé.
  • Démarrez avec claude --debug pendant le développement. Le journal de débogage nomme chaque hook ignoré et chaque affichage refusé par le moteur.

15 mods de la communauté à étudier

Le catalogue awesome-claude-code-mods (opens in a new tab), qui compte 316 étoiles, a analysé 2 690 mods publics dans 1 265 dépôts le 6 octobre, cinq jours après le lancement. Les données de ce scan montrent ce que les gens construisent :

  • 68 % ajoutent une commande slash
  • 53 % interceptent des appels d’outils
  • 41 % dessinent au-dessus du prompt, 40 % ouvrent un panneau
  • 40 % lancent des processus, 12 % appellent un modèle, 11 % utilisent le réseau

Ces 15 mods montrent l’étendue des possibilités. Les étoiles sont celles du 7 octobre 2026.

ModCe qu’il faitÉtoilesÀ lire pour
terminal-browser (opens in a new tab)Un navigateur web à côté de la conversation, pour les sites, les aperçus HTML locaux et les pull requests3 695Le panneau le plus ambitieux à ce jour
claude-image-view (opens in a new tab)Des miniatures des images collées au-dessus du prompt, au lieu de [Image #1]160L’affichage d’images dans le terminal
hamzafer/claude-code-mods (opens in a new tab)Un ensemble : barre de contexte, garde-fou de rayon d’impact, aperçu Markdown, tableau de bord des sous-agents138Plusieurs types de mods dans un seul dépôt
claude-auto-handoff (opens in a new tab)Transmet une longue session à une nouvelle session avec un résumé structuré60La gestion du contexte
prismantis (opens in a new tab)Des réponses thématisées : tableaux, code, graphiques en art ASCII, texte de droite à gauche49Le restylage des messages de Claude lui-même
cc-arcade (opens in a new tab)Neuf jeux au-dessus du prompt, mis en pause quand Claude a terminé41L’animation avec une horloge de frames
jev-permission-gate (opens in a new tab)Un modèle de décision Jev juge les appels d’outils en mode auto28Une section confidentialité soignée : il envoie vos trois derniers messages, jusqu’à 1 500 caractères chacun, à l’API de TypeSafe
prompt-rail (opens in a new tab)Un rail de vos anciens prompts : survolez pour lire, cliquez pour y revenir22La pièce maîtresse de la revue japonaise de mods la plus appréciée sur Zenn
claude-paste-view (opens in a new tab)Un aperçu des images collées et des longs textes collés18Un code court et lisible
claude-gfm-render (opens in a new tab)Alertes GitHub, listes de tâches et Mermaid dans les réponses, en art ASCII ou en SVG14Un affichage différent selon la surface
claude_qamods (opens in a new tab)qa-guide explique les questions et les options de Claude dans un panneau latéral10L’amélioration d’une boîte de dialogue intégrée
CC-Usage-Band (opens in a new tab)Limites sur 5 heures et sur 7 jours, contexte et taux de succès du cache au-dessus du prompt10Le type de mod le plus courant : un compteur
harness-scope (opens in a new tab)Des profils par dépôt qui masquent les skills, agents et règles globaux1L’auteur a mesuré une liste de skills passée de 98 entrées à 49
touch-map (opens in a new tab)Montre quels fichiers Claude a listés, lus, modifiés ou créés0Son auteur a constaté que Claude avait touché 125 fichiers sur 304 pendant une exploration avant refactoring
claude-mods-router (opens in a new tab)Oriente chaque prompt vers un niveau d’effort avec $.model.classify0Son article sur Qiita (26 likes) note que changer de modèle casse le cache de prompt

Anthropic publie aussi trois exemples dans claude-code-playground (opens in a new tab) : token-weather, blast-radius et replay-theater. Le code source des mods intégrés, dont /diff, se trouve dans le dépôt claude-code (opens in a new tab).

Les bonnes pratiques adoptées par la communauté

Pendant la première semaine, les auteurs japonais ont publié à eux seuls environ 50 articles avec des mods fonctionnels, des mesures et des retours d’échec. Voici les habitudes qui revenaient le plus souvent.

  1. Lisez un mod avant de l’installer. Clonez-le, lancez claude plugin validate et lisez les lignes hooks: et calls:. Lisez le code source partout où apparaissent $.process, $.http, $.fs.write, $.env.get ou $.model. Relancez la validation après chaque mise à jour. Une validation réussie signifie que le moteur peut charger le code, pas que ce code est sûr.
  2. Les garde-fous décident avant next et échouent en mode fermé. Les mods qui se contentent d’observer doivent échouer en mode ouvert avec .catch(($, e, next) => next(e)), pour qu’un bug dans un compteur ne bloque jamais votre travail.
  3. Attendez à l’intérieur des appels $. Un hook dispose de 10 secondes de temps propre. Un $.process.run ou un $.ui.ask en cours ne compte pas dans ce budget, mais vos propres promesses, si.
  4. Ne stockez jamais $ et ne le déstructurez pas. Passez-le uniquement à des fonctions déclarées au niveau supérieur du fichier. Plusieurs auteurs avaient des mods qui échouaient au chargement sans aucun message, jusqu’à ce qu’ils corrigent ce point.
  5. Attention au cache de prompt. Changer de modèle en cours de session, ou modifier le prompt système entre deux requêtes, invalide le cache.
  6. Adaptez le code selon e.surface. Svg ne s’affiche que dans l’application Desktop. Raster et Image ne s’affichent que dans le terminal.
  7. Figez une version pour un usage en équipe. L’API est en accès anticipé et change d’une version à l’autre. Cinq des six versions publiées après le lancement, de 2.1.288 à 2.1.293, ont modifié ou corrigé le comportement des mods.

Le masquage des secrets est le contre-exemple à retenir. Un auteur sur note.com a créé un mod qui remplaçait les clés API dans la sortie des outils avant que Claude ne les voie. Claude a tout de même affiché les valeurs brutes en déboguant une modification ratée avec od -c, et un Write sur le fichier entier a enregistré les valeurs de remplacement à la place des vraies clés. Seule une règle de permission deny sur le fichier a tenu. Un mod qui change ce qu’affiche l’écran ne cache rien au modèle.

Problèmes courants

SymptômeCause probableSolution
/plugin ne liste pas le modDossier non approuvé, --safe-mode, --bare ou disableAllHooksApprouvez le dossier et redémarrez sans le flag
hooks modules are turned off in this processAnthropic a désactivé à distance les mods installésRien à changer en local. Mettez à jour, car 2.1.289 et 2.1.290 ont corrigé deux cas où les mods restaient désactivés
validate échoue avec « expected record, received undefined »Un ancien CLI placé plus tôt dans votre PATHLancez claude --version et mettez à jour
Un hook est ignoré sans erreur visibleIl a levé une exception, par exemple en appelant $.plugin.name(), qui est une propriétéLancez claude --debug et lisez la ligne qui signale le hook ignoré
Un panneau ne s’ouvre jamaisUn panneau qui s’ouvre sans que vous le demandiez attend 144 colonnes, ne se place à côté de la conversation qu’en disposition plein écran, et /diff peut le recouvrirÉlargissez la fenêtre, essayez la disposition plein écran, fermez /diff
Ça fonctionne dans le terminal mais pas dans DesktopDesktop embarque sa propre version, et certains éléments sont réservés au terminalVérifiez /status dans l’onglet Code et adaptez le code selon e.surface
Aucune interface de mod dans VS Code ou claude -pCes surfaces n’affichent rienRabattez-vous sur une ligne dans la conversation ou sur le texte d’une commande
Un test échoue avec « nothing beneath the plugins answers »Le kit de test n’a pas de moteurAjoutez des hooks de substitution, et répondez aux appels $ avec { value }

Partager votre mod

Placez un marketplace.json à côté de plugin.json, dans .claude-plugin/ :

{
  "name": "my-mods",
  "owner": { "name": "you" },
  "plugins": [{ "name": "safe-shell", "source": "./" }]
}

Poussez le dossier sur GitHub. N’importe qui peut ensuite l’installer depuis une session du terminal :

/plugin install safe-shell --marketplace you/safe-shell

Dans l’application Desktop, passez par + puis Plugins puis Add plugin, dans les sessions locales et SSH. Si vous ajoutez le topic claude-code-mod au dépôt, le catalogue de la communauté le repère en général dans les quelques heures qui suivent votre prochain push.

FAQ

Guides liés