Les hooks Claude Code sont des commandes shell définies par l’utilisateur qui s’exécutent à différents moments du cycle de vie de Claude Code. Les hooks fournissent un contrôle déterministe sur le comportement de Claude Code, garantissant que certaines actions se produisent toujours plutôt que de compter sur le LLM pour choisir de les exécuter.

Pour la documentation de référence sur les hooks, voir Référence des hooks.

Exemples de cas d’usage pour les hooks incluent :

  • Notifications : Personnalisez la façon dont vous êtes notifié lorsque Claude Code attend votre saisie ou permission pour exécuter quelque chose.
  • Formatage automatique : Exécutez prettier sur les fichiers .ts, gofmt sur les fichiers .go, etc. après chaque modification de fichier.
  • Journalisation : Suivez et comptez toutes les commandes exécutées pour la conformité ou le débogage.
  • Retour d’information : Fournissez un retour automatisé lorsque Claude Code produit du code qui ne suit pas les conventions de votre base de code.
  • Permissions personnalisées : Bloquez les modifications aux fichiers de production ou aux répertoires sensibles.

En encodant ces règles comme hooks plutôt que comme instructions de prompt, vous transformez les suggestions en code au niveau de l’application qui s’exécute chaque fois qu’il est censé s’exécuter.

Vous devez considérer les implications de sécurité des hooks lorsque vous les ajoutez, car les hooks s’exécutent automatiquement pendant la boucle de l’agent avec les identifiants de votre environnement actuel. Par exemple, du code de hooks malveillant peut exfiltrer vos données. Examinez toujours votre implémentation de hooks avant de les enregistrer.

Pour les meilleures pratiques de sécurité complètes, voir Considérations de sécurité dans la documentation de référence des hooks.

Aperçu des événements de hooks

Claude Code fournit plusieurs événements de hooks qui s’exécutent à différents points du flux de travail :

  • PreToolUse : S’exécute avant les appels d’outils (peut les bloquer)
  • PostToolUse : S’exécute après la completion des appels d’outils
  • UserPromptSubmit : S’exécute lorsque l’utilisateur soumet un prompt, avant que Claude ne le traite
  • Notification : S’exécute lorsque Claude Code envoie des notifications
  • Stop : S’exécute lorsque Claude Code termine de répondre
  • SubagentStop : S’exécute lorsque les tâches de sous-agent se terminent
  • PreCompact : S’exécute avant que Claude Code ne soit sur le point d’exécuter une opération de compactage
  • SessionStart : S’exécute lorsque Claude Code démarre une nouvelle session ou reprend une session existante
  • SessionEnd : S’exécute lorsque la session Claude Code se termine

Chaque événement reçoit des données différentes et peut contrôler le comportement de Claude de différentes manières.

Démarrage rapide

Dans ce démarrage rapide, vous ajouterez un hook qui journalise les commandes shell que Claude Code exécute.

Prérequis

Installez jq pour le traitement JSON en ligne de commande.

Étape 1 : Ouvrir la configuration des hooks

Exécutez la commande slash /hooks et sélectionnez l’événement de hook PreToolUse.

Les hooks PreToolUse s’exécutent avant les appels d’outils et peuvent les bloquer tout en fournissant à Claude un retour sur ce qu’il faut faire différemment.

Étape 2 : Ajouter un matcher

Sélectionnez + Add new matcher… pour exécuter votre hook uniquement sur les appels d’outils Bash.

Tapez Bash pour le matcher.

Vous pouvez utiliser * pour correspondre à tous les outils.

Étape 3 : Ajouter le hook

Sélectionnez + Add new hook… et entrez cette commande :

jq -r '"\(.tool_input.command) - \(.tool_input.description // "No description")"' >> ~/.claude/bash-command-log.txt

Étape 4 : Sauvegarder votre configuration

Pour l’emplacement de stockage, sélectionnez User settings puisque vous journalisez dans votre répertoire personnel. Ce hook s’appliquera alors à tous les projets, pas seulement à votre projet actuel.

Puis appuyez sur Échap jusqu’à revenir au REPL. Votre hook est maintenant enregistré !

Étape 5 : Vérifier votre hook

Exécutez /hooks à nouveau ou vérifiez ~/.claude/settings.json pour voir votre configuration :

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '\"\\(.tool_input.command) - \\(.tool_input.description // \"No description\")\"' >> ~/.claude/bash-command-log.txt"
          }
        ]
      }
    ]
  }
}

Étape 6 : Tester votre hook

Demandez à Claude d’exécuter une commande simple comme ls et vérifiez votre fichier de log :

cat ~/.claude/bash-command-log.txt

Vous devriez voir des entrées comme :

ls - Lists files and directories

Plus d’exemples

Pour un exemple d’implémentation complète, voir l’exemple de validateur de commandes bash dans notre base de code publique.

Hook de formatage de code

Formatez automatiquement les fichiers TypeScript après modification :

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|MultiEdit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '.tool_input.file_path' | { read file_path; if echo \"$file_path\" | grep -q '\\.ts$'; then npx prettier --write \"$file_path\"; fi; }"
          }
        ]
      }
    ]
  }
}

Hook de formatage Markdown

Corrigez automatiquement les balises de langage manquantes et les problèmes de formatage dans les fichiers markdown :

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|MultiEdit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/markdown_formatter.py"
          }
        ]
      }
    ]
  }
}

Créez .claude/hooks/markdown_formatter.py avec ce contenu :

#!/usr/bin/env python3
"""
Formateur Markdown pour la sortie Claude Code.
Corrige les balises de langage manquantes et les problèmes d'espacement tout en préservant le contenu du code.
"""
import json
import sys
import re
import os

def detect_language(code):
    """Détection de langage au mieux du code."""
    s = code.strip()
    
    # Détection JSON
    if re.search(r'^\s*[{\[]', s):
        try:
            json.loads(s)
            return 'json'
        except:
            pass
    
    # Détection Python
    if re.search(r'^\s*def\s+\w+\s*\(', s, re.M) or \
       re.search(r'^\s*(import|from)\s+\w+', s, re.M):
        return 'python'
    
    # Détection JavaScript  
    if re.search(r'\b(function\s+\w+\s*\(|const\s+\w+\s*=)', s) or \
       re.search(r'=>|console\.(log|error)', s):
        return 'javascript'
    
    # Détection Bash
    if re.search(r'^#!.*\b(bash|sh)\b', s, re.M) or \
       re.search(r'\b(if|then|fi|for|in|do|done)\b', s):
        return 'bash'
    
    # Détection SQL
    if re.search(r'\b(SELECT|INSERT|UPDATE|DELETE|CREATE)\s+', s, re.I):
        return 'sql'
        
    return 'text'

def format_markdown(content):
    """Formate le contenu markdown avec détection de langage."""
    # Corrige les clôtures de code non étiquetées
    def add_lang_to_fence(match):
        indent, info, body, closing = match.groups()
        if not info.strip():
            lang = detect_language(body)
            return f"{indent}```{lang}\n{body}{closing}\n"
        return match.group(0)
    
    fence_pattern = r'(?ms)^([ \t]{0,3})```([^\n]*)\n(.*?)(\n\1```)\s*$'
    content = re.sub(fence_pattern, add_lang_to_fence, content)
    
    # Corrige les lignes vides excessives (seulement en dehors des clôtures de code)
    content = re.sub(r'\n{3,}', '\n\n', content)
    
    return content.rstrip() + '\n'

# Exécution principale
try:
    input_data = json.load(sys.stdin)
    file_path = input_data.get('tool_input', {}).get('file_path', '')
    
    if not file_path.endswith(('.md', '.mdx')):
        sys.exit(0)  # Pas un fichier markdown
    
    if os.path.exists(file_path):
        with open(file_path, 'r', encoding='utf-8') as f:
            content = f.read()
        
        formatted = format_markdown(content)
        
        if formatted != content:
            with open(file_path, 'w', encoding='utf-8') as f:
                f.write(formatted)
            print(f"✓ Formatage markdown corrigé dans {file_path}")
    
except Exception as e:
    print(f"Erreur lors du formatage markdown : {e}", file=sys.stderr)
    sys.exit(1)

Rendez le script exécutable :

chmod +x .claude/hooks/markdown_formatter.py

Ce hook automatiquement :

  • Détecte les langages de programmation dans les blocs de code non étiquetés
  • Ajoute les balises de langage appropriées pour la coloration syntaxique
  • Corrige les lignes vides excessives tout en préservant le contenu du code
  • Ne traite que les fichiers markdown (.md, .mdx)

Hook de notification personnalisée

Obtenez des notifications de bureau lorsque Claude a besoin d’une saisie :

{
  "hooks": {
    "Notification": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "notify-send 'Claude Code' 'En attente de votre saisie'"
          }
        ]
      }
    ]
  }
}

Hook de protection de fichiers

Bloquez les modifications aux fichiers sensibles :

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|MultiEdit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "python3 -c \"import json, sys; data=json.load(sys.stdin); path=data.get('tool_input',{}).get('file_path',''); sys.exit(2 if any(p in path for p in ['.env', 'package-lock.json', '.git/']) else 0)\""
          }
        ]
      }
    ]
  }
}

En savoir plus

  • Pour la documentation de référence sur les hooks, voir Référence des hooks.
  • Pour les meilleures pratiques de sécurité complètes et les directives de sécurité, voir Considérations de sécurité dans la documentation de référence des hooks.
  • Pour les étapes de dépannage et les techniques de débogage, voir Débogage dans la documentation de référence des hooks.