Pour un guide de démarrage rapide avec des exemples, voir Commencer avec les hooks Claude Code.

Configuration

Les hooks Claude Code sont configurés dans vos fichiers de paramètres :

  • ~/.claude/settings.json - Paramètres utilisateur
  • .claude/settings.json - Paramètres du projet
  • .claude/settings.local.json - Paramètres locaux du projet (non committé)
  • Paramètres de politique gérés par l’entreprise

Structure

Les hooks sont organisés par matchers, où chaque matcher peut avoir plusieurs hooks :

{
  "hooks": {
    "EventName": [
      {
        "matcher": "ToolPattern",
        "hooks": [
          {
            "type": "command",
            "command": "your-command-here"
          }
        ]
      }
    ]
  }
}
  • matcher : Motif pour faire correspondre les noms d’outils, sensible à la casse (applicable uniquement pour PreToolUse et PostToolUse)
    • Les chaînes simples correspondent exactement : Write correspond uniquement à l’outil Write
    • Prend en charge les regex : Edit|Write ou Notebook.*
    • Utilisez * pour faire correspondre tous les outils. Vous pouvez également utiliser une chaîne vide ("") ou laisser matcher vide.
  • hooks : Tableau de commandes à exécuter lorsque le motif correspond
    • type : Actuellement, seul "command" est pris en charge
    • command : La commande bash à exécuter (peut utiliser la variable d’environnement $CLAUDE_PROJECT_DIR)
    • timeout : (Optionnel) Durée pendant laquelle une commande doit s’exécuter, en secondes, avant d’annuler cette commande spécifique.

Pour les événements comme UserPromptSubmit, Notification, Stop, et SubagentStop qui n’utilisent pas de matchers, vous pouvez omettre le champ matcher :

{
  "hooks": {
    "UserPromptSubmit": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "/path/to/prompt-validator.py"
          }
        ]
      }
    ]
  }
}

Scripts de Hook Spécifiques au Projet

Vous pouvez utiliser la variable d’environnement CLAUDE_PROJECT_DIR (disponible uniquement lorsque Claude Code génère la commande hook) pour référencer des scripts stockés dans votre projet, en s’assurant qu’ils fonctionnent quel que soit le répertoire courant de Claude :

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/check-style.sh"
          }
        ]
      }
    ]
  }
}

Événements de Hook

PreToolUse

S’exécute après que Claude crée les paramètres d’outil et avant de traiter l’appel d’outil.

Matchers communs :

  • Task - Tâches d’agent
  • Bash - Commandes shell
  • Glob - Correspondance de motifs de fichiers
  • Grep - Recherche de contenu
  • Read - Lecture de fichiers
  • Edit, MultiEdit - Édition de fichiers
  • Write - Écriture de fichiers
  • WebFetch, WebSearch - Opérations web

PostToolUse

S’exécute immédiatement après qu’un outil se termine avec succès.

Reconnaît les mêmes valeurs de matcher que PreToolUse.

Notification

S’exécute lorsque Claude Code envoie des notifications. Les notifications sont envoyées lorsque :

  1. Claude a besoin de votre permission pour utiliser un outil. Exemple : “Claude a besoin de votre permission pour utiliser Bash”
  2. L’entrée de prompt est inactive depuis au moins 60 secondes. “Claude attend votre entrée”

UserPromptSubmit

S’exécute lorsque l’utilisateur soumet un prompt, avant que Claude ne le traite. Cela vous permet d’ajouter du contexte supplémentaire basé sur le prompt/conversation, de valider les prompts, ou de bloquer certains types de prompts.

Stop

S’exécute lorsque l’agent principal Claude Code a fini de répondre. Ne s’exécute pas si l’arrêt s’est produit à cause d’une interruption utilisateur.

SubagentStop

S’exécute lorsqu’un sous-agent Claude Code (appel d’outil Task) a fini de répondre.

PreCompact

S’exécute avant que Claude Code soit sur le point d’exécuter une opération de compactage.

Matchers :

  • manual - Invoqué depuis /compact
  • auto - Invoqué depuis le compactage automatique (à cause d’une fenêtre de contexte pleine)

Entrée de Hook

Les hooks reçoivent des données JSON via stdin contenant des informations de session et des données spécifiques à l’événement :

{
  // Champs communs
  session_id: string
  transcript_path: string  // Chemin vers le JSON de conversation
  cwd: string              // Le répertoire de travail courant lorsque le hook est invoqué

  // Champs spécifiques à l'événement
  hook_event_name: string
  ...
}

Entrée PreToolUse

Le schéma exact pour tool_input dépend de l’outil.

{
  "session_id": "abc123",
  "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "cwd": "/Users/...",
  "hook_event_name": "PreToolUse",
  "tool_name": "Write",
  "tool_input": {
    "file_path": "/path/to/file.txt",
    "content": "file content"
  }
}

Entrée PostToolUse

Le schéma exact pour tool_input et tool_response dépend de l’outil.

{
  "session_id": "abc123",
  "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "cwd": "/Users/...",
  "hook_event_name": "PostToolUse",
  "tool_name": "Write",
  "tool_input": {
    "file_path": "/path/to/file.txt",
    "content": "file content"
  },
  "tool_response": {
    "filePath": "/path/to/file.txt",
    "success": true
  }
}

Entrée Notification

{
  "session_id": "abc123",
  "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "cwd": "/Users/...",
  "hook_event_name": "Notification",
  "message": "Task completed successfully"
}

Entrée UserPromptSubmit

{
  "session_id": "abc123",
  "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "cwd": "/Users/...",
  "hook_event_name": "UserPromptSubmit",
  "prompt": "Write a function to calculate the factorial of a number"
}

Entrée Stop et SubagentStop

stop_hook_active est vrai lorsque Claude Code continue déjà suite à un hook d’arrêt. Vérifiez cette valeur ou traitez le transcript pour empêcher Claude Code de s’exécuter indéfiniment.

{
  "session_id": "abc123",
  "transcript_path": "~/.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "hook_event_name": "Stop",
  "stop_hook_active": true
}

Entrée PreCompact

Pour manual, custom_instructions provient de ce que l’utilisateur passe dans /compact. Pour auto, custom_instructions est vide.

{
  "session_id": "abc123",
  "transcript_path": "~/.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "hook_event_name": "PreCompact",
  "trigger": "manual",
  "custom_instructions": ""
}

Sortie de Hook

Il y a deux façons pour les hooks de retourner une sortie vers Claude Code. La sortie communique s’il faut bloquer et tout retour qui devrait être montré à Claude et à l’utilisateur.

Simple : Code de Sortie

Les hooks communiquent le statut via les codes de sortie, stdout, et stderr :

  • Code de sortie 0 : Succès. stdout est montré à l’utilisateur en mode transcript (CTRL-R), sauf pour UserPromptSubmit, où stdout est ajouté au contexte.
  • Code de sortie 2 : Erreur bloquante. stderr est renvoyé à Claude pour traitement automatique. Voir le comportement par événement de hook ci-dessous.
  • Autres codes de sortie : Erreur non bloquante. stderr est montré à l’utilisateur et l’exécution continue.

Rappel : Claude Code ne voit pas stdout si le code de sortie est 0, sauf pour le hook UserPromptSubmit où stdout est injecté comme contexte.

Comportement du Code de Sortie 2

Événement de HookComportement
PreToolUseBloque l’appel d’outil, montre stderr à Claude
PostToolUseMontre stderr à Claude (l’outil a déjà été exécuté)
NotificationN/A, montre stderr à l’utilisateur uniquement
UserPromptSubmitBloque le traitement du prompt, efface le prompt, montre stderr à l’utilisateur uniquement
StopBloque l’arrêt, montre stderr à Claude
SubagentStopBloque l’arrêt, montre stderr au sous-agent Claude
PreCompactN/A, montre stderr à l’utilisateur uniquement

Avancé : Sortie JSON

Les hooks peuvent retourner du JSON structuré dans stdout pour un contrôle plus sophistiqué :

Champs JSON Communs

Tous les types de hooks peuvent inclure ces champs optionnels :

{
  "continue": true, // Si Claude doit continuer après l'exécution du hook (par défaut : true)
  "stopReason": "string" // Message montré quand continue est false
  "suppressOutput": true, // Masquer stdout du mode transcript (par défaut : false)
}

Si continue est false, Claude arrête le traitement après l’exécution des hooks.

  • Pour PreToolUse, c’est différent de "permissionDecision": "deny", qui bloque seulement un appel d’outil spécifique et fournit un retour automatique à Claude.
  • Pour PostToolUse, c’est différent de "decision": "block", qui fournit un retour automatisé à Claude.
  • Pour UserPromptSubmit, cela empêche le prompt d’être traité.
  • Pour Stop et SubagentStop, cela prend la priorité sur toute sortie "decision": "block".
  • Dans tous les cas, "continue" = false prend la priorité sur toute sortie "decision": "block".

stopReason accompagne continue avec une raison montrée à l’utilisateur, pas montrée à Claude.

Contrôle de Décision PreToolUse

Les hooks PreToolUse peuvent contrôler si un appel d’outil procède.

  • "allow" contourne le système de permission. permissionDecisionReason est montré à l’utilisateur mais pas à Claude. (La valeur dépréciée "approve" + reason a le même comportement.)
  • "deny" empêche l’appel d’outil de s’exécuter. permissionDecisionReason est montré à Claude. (La valeur "block" + reason a le même comportement.)
  • "ask" demande à l’utilisateur de confirmer l’appel d’outil dans l’UI. permissionDecisionReason est montré à l’utilisateur mais pas à Claude.
{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "allow" | "deny" | "ask",
    "permissionDecisionReason": "My reason here (shown to user)"
  },
  "decision": "approve" | "block" | undefined, // Déprécié pour PreToolUse mais toujours pris en charge
  "reason": "Explanation for decision" // Déprécié pour PreToolUse mais toujours pris en charge
}

Contrôle de Décision PostToolUse

Les hooks PostToolUse peuvent contrôler si un appel d’outil procède.

  • "block" invite automatiquement Claude avec reason.
  • undefined ne fait rien. reason est ignoré.
{
  "decision": "block" | undefined,
  "reason": "Explanation for decision"
}

Contrôle de Décision UserPromptSubmit

Les hooks UserPromptSubmit peuvent contrôler si un prompt utilisateur est traité.

  • "block" empêche le prompt d’être traité. Le prompt soumis est effacé du contexte. "reason" est montré à l’utilisateur mais pas ajouté au contexte.
  • undefined permet au prompt de procéder normalement. "reason" est ignoré.
  • "hookSpecificOutput.additionalContext" ajoute la chaîne au contexte si pas bloqué.
{
  "decision": "block" | undefined,
  "reason": "Explanation for decision",
  "hookSpecificOutput": {
    "hookEventName": "UserPromptSubmit",
    "additionalContext": "My additional context here"
  }
}

Contrôle de Décision Stop/SubagentStop

Les hooks Stop et SubagentStop peuvent contrôler si Claude doit continuer.

  • "block" empêche Claude de s’arrêter. Vous devez remplir reason pour que Claude sache comment procéder.
  • undefined permet à Claude de s’arrêter. reason est ignoré.
{
  "decision": "block" | undefined,
  "reason": "Must be provided when Claude is blocked from stopping"
}

Exemple de Code de Sortie : Validation de Commande Bash

#!/usr/bin/env python3
import json
import re
import sys

# Définir les règles de validation comme une liste de tuples (motif regex, message)
VALIDATION_RULES = [
    (
        r"\bgrep\b(?!.*\|)",
        "Use 'rg' (ripgrep) instead of 'grep' for better performance and features",
    ),
    (
        r"\bfind\s+\S+\s+-name\b",
        "Use 'rg --files | rg pattern' or 'rg --files -g pattern' instead of 'find -name' for better performance",
    ),
]


def validate_command(command: str) -> list[str]:
    issues = []
    for pattern, message in VALIDATION_RULES:
        if re.search(pattern, command):
            issues.append(message)
    return issues


try:
    input_data = json.load(sys.stdin)
except json.JSONDecodeError as e:
    print(f"Error: Invalid JSON input: {e}", file=sys.stderr)
    sys.exit(1)

tool_name = input_data.get("tool_name", "")
tool_input = input_data.get("tool_input", {})
command = tool_input.get("command", "")

if tool_name != "Bash" or not command:
    sys.exit(1)

# Valider la commande
issues = validate_command(command)

if issues:
    for message in issues:
        print(f"• {message}", file=sys.stderr)
    # Le code de sortie 2 bloque l'appel d'outil et montre stderr à Claude
    sys.exit(2)

Exemple de Sortie JSON : UserPromptSubmit pour Ajouter du Contexte et de la Validation

Pour les hooks UserPromptSubmit, vous pouvez injecter du contexte en utilisant l’une ou l’autre méthode :

  • Code de sortie 0 avec stdout : Claude voit le contexte (cas spécial pour UserPromptSubmit)
  • Sortie JSON : Fournit plus de contrôle sur le comportement
#!/usr/bin/env python3
import json
import sys
import re
import datetime

# Charger l'entrée depuis stdin
try:
    input_data = json.load(sys.stdin)
except json.JSONDecodeError as e:
    print(f"Error: Invalid JSON input: {e}", file=sys.stderr)
    sys.exit(1)

prompt = input_data.get("prompt", "")

# Vérifier les motifs sensibles
sensitive_patterns = [
    (r"(?i)\b(password|secret|key|token)\s*[:=]", "Prompt contains potential secrets"),
]

for pattern, message in sensitive_patterns:
    if re.search(pattern, prompt):
        # Utiliser la sortie JSON pour bloquer avec une raison spécifique
        output = {
            "decision": "block",
            "reason": f"Security policy violation: {message}. Please rephrase your request without sensitive information."
        }
        print(json.dumps(output))
        sys.exit(0)

# Ajouter l'heure actuelle au contexte
context = f"Current time: {datetime.datetime.now()}"
print(context)

"""
Ce qui suit est également équivalent :
print(json.dumps({
  "hookSpecificOutput": {
    "hookEventName": "UserPromptSubmit",
    "additionalContext": context,
  },
}))
"""

# Permettre au prompt de procéder avec le contexte supplémentaire
sys.exit(0)

Exemple de Sortie JSON : PreToolUse avec Approbation

#!/usr/bin/env python3
import json
import sys

# Charger l'entrée depuis stdin
try:
    input_data = json.load(sys.stdin)
except json.JSONDecodeError as e:
    print(f"Error: Invalid JSON input: {e}", file=sys.stderr)
    sys.exit(1)

tool_name = input_data.get("tool_name", "")
tool_input = input_data.get("tool_input", {})

# Exemple : Auto-approuver les lectures de fichiers pour les fichiers de documentation
if tool_name == "Read":
    file_path = tool_input.get("file_path", "")
    if file_path.endswith((".md", ".mdx", ".txt", ".json")):
        # Utiliser la sortie JSON pour auto-approuver l'appel d'outil
        output = {
            "decision": "approve",
            "reason": "Documentation file auto-approved",
            "suppressOutput": True  # Ne pas montrer en mode transcript
        }
        print(json.dumps(output))
        sys.exit(0)

# Pour les autres cas, laisser le flux de permission normal procéder
sys.exit(0)

Travailler avec les Outils MCP

Les hooks Claude Code fonctionnent parfaitement avec les outils Model Context Protocol (MCP). Lorsque les serveurs MCP fournissent des outils, ils apparaissent avec un motif de nommage spécial que vous pouvez faire correspondre dans vos hooks.

Nommage des Outils MCP

Les outils MCP suivent le motif mcp__<server>__<tool>, par exemple :

  • mcp__memory__create_entities - Outil de création d’entités du serveur Memory
  • mcp__filesystem__read_file - Outil de lecture de fichier du serveur Filesystem
  • mcp__github__search_repositories - Outil de recherche du serveur GitHub

Configuration des Hooks pour les Outils MCP

Vous pouvez cibler des outils MCP spécifiques ou des serveurs MCP entiers :

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "mcp__memory__.*",
        "hooks": [
          {
            "type": "command",
            "command": "echo 'Memory operation initiated' >> ~/mcp-operations.log"
          }
        ]
      },
      {
        "matcher": "mcp__.*__write.*",
        "hooks": [
          {
            "type": "command",
            "command": "/home/user/scripts/validate-mcp-write.py"
          }
        ]
      }
    ]
  }
}

Exemples

Pour des exemples pratiques incluant le formatage de code, les notifications, et la protection de fichiers, voir Plus d’Exemples dans le guide de démarrage.

Considérations de Sécurité

Avertissement

UTILISEZ À VOS PROPRES RISQUES : Les hooks Claude Code exécutent des commandes shell arbitraires sur votre système automatiquement. En utilisant les hooks, vous reconnaissez que :

  • Vous êtes seul responsable des commandes que vous configurez
  • Les hooks peuvent modifier, supprimer, ou accéder à tous les fichiers auxquels votre compte utilisateur peut accéder
  • Les hooks malveillants ou mal écrits peuvent causer une perte de données ou des dommages système
  • Anthropic ne fournit aucune garantie et n’assume aucune responsabilité pour les dommages résultant de l’utilisation des hooks
  • Vous devriez tester minutieusement les hooks dans un environnement sûr avant l’utilisation en production

Toujours réviser et comprendre toutes les commandes de hook avant de les ajouter à votre configuration.

Meilleures Pratiques de Sécurité

Voici quelques pratiques clés pour écrire des hooks plus sécurisés :

  1. Valider et assainir les entrées - Ne jamais faire confiance aveuglément aux données d’entrée
  2. Toujours citer les variables shell - Utiliser "$VAR" pas $VAR
  3. Bloquer la traversée de chemin - Vérifier .. dans les chemins de fichiers
  4. Utiliser des chemins absolus - Spécifier des chemins complets pour les scripts (utiliser $CLAUDE_PROJECT_DIR pour le chemin du projet)
  5. Ignorer les fichiers sensibles - Éviter .env, .git/, clés, etc.

Sécurité de Configuration

Les modifications directes des hooks dans les fichiers de paramètres ne prennent pas effet immédiatement. Claude Code :

  1. Capture un instantané des hooks au démarrage
  2. Utilise cet instantané tout au long de la session
  3. Avertit si les hooks sont modifiés extérieurement
  4. Nécessite une révision dans le menu /hooks pour que les changements s’appliquent

Cela empêche les modifications malveillantes de hooks d’affecter votre session actuelle.

Détails d’Exécution des Hooks

  • Timeout : Limite d’exécution de 60 secondes par défaut, configurable par commande.
    • Un timeout pour une commande individuelle n’affecte pas les autres commandes.
  • Parallélisation : Tous les hooks correspondants s’exécutent en parallèle
  • Environnement : S’exécute dans le répertoire courant avec l’environnement de Claude Code
    • La variable d’environnement CLAUDE_PROJECT_DIR est disponible et contient le chemin absolu vers le répertoire racine du projet
  • Entrée : JSON via stdin
  • Sortie :
    • PreToolUse/PostToolUse/Stop : Progrès montré dans le transcript (Ctrl-R)
    • Notification : Enregistré en debug uniquement (--debug)

Débogage

Dépannage de Base

Si vos hooks ne fonctionnent pas :

  1. Vérifier la configuration - Exécuter /hooks pour voir si votre hook est enregistré
  2. Vérifier la syntaxe - S’assurer que vos paramètres JSON sont valides
  3. Tester les commandes - Exécuter les commandes de hook manuellement d’abord
  4. Vérifier les permissions - S’assurer que les scripts sont exécutables
  5. Réviser les logs - Utiliser claude --debug pour voir les détails d’exécution des hooks

Problèmes communs :

  • Guillemets non échappés - Utiliser \" dans les chaînes JSON
  • Mauvais matcher - Vérifier que les noms d’outils correspondent exactement (sensible à la casse)
  • Commande non trouvée - Utiliser des chemins complets pour les scripts

Débogage Avancé

Pour les problèmes de hooks complexes :

  1. Inspecter l’exécution des hooks - Utiliser claude --debug pour voir l’exécution détaillée des hooks
  2. Valider les schémas JSON - Tester l’entrée/sortie des hooks avec des outils externes
  3. Vérifier les variables d’environnement - Vérifier que l’environnement de Claude Code est correct
  4. Tester les cas limites - Essayer les hooks avec des chemins de fichiers ou entrées inhabituels
  5. Surveiller les ressources système - Vérifier l’épuisement des ressources pendant l’exécution des hooks
  6. Utiliser la journalisation structurée - Implémenter la journalisation dans vos scripts de hooks

Exemple de Sortie de Debug

Utiliser claude --debug pour voir les détails d’exécution des hooks :

[DEBUG] Executing hooks for PostToolUse:Write
[DEBUG] Getting matching hook commands for PostToolUse with query: Write
[DEBUG] Found 1 hook matchers in settings
[DEBUG] Matched 1 hooks for query "Write"
[DEBUG] Found 1 hook commands to execute
[DEBUG] Executing hook command: <Your command> with timeout 60000ms
[DEBUG] Hook command completed with status 0: <Your stdout>

Les messages de progrès apparaissent en mode transcript (Ctrl-R) montrant :

  • Quel hook s’exécute
  • Commande en cours d’exécution
  • Statut de succès/échec
  • Messages de sortie ou d’erreur