Passer au contenu principal
Pour un guide de démarrage rapide avec des exemples, consultez Démarrer 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 du projet local (non validés)
  • 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 : Modèle pour correspondre aux noms d’outils, sensible à la casse (applicable uniquement pour PreToolUse et PostToolUse)
    • Les chaînes simples correspondent exactement : Write correspond uniquement à l’outil Write
    • Supporte les expressions régulières : Edit|Write ou Notebook.*
    • Utilisez * pour correspondre à tous les outils. Vous pouvez également utiliser une chaîne vide ("") ou laisser matcher vide.
  • hooks : Tableau de hooks à exécuter lorsque le modèle correspond
    • type : Type d’exécution du hook - "command" pour les commandes bash ou "prompt" pour l’évaluation basée sur LLM
    • command : (Pour type: "command") La commande bash à exécuter (peut utiliser la variable d’environnement $CLAUDE_PROJECT_DIR)
    • prompt : (Pour type: "prompt") L’invite à envoyer au LLM pour évaluation
    • timeout : (Optionnel) Durée pendant laquelle un hook doit s’exécuter, en secondes, avant d’annuler ce hook 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 hooks spécifiques au projet

Vous pouvez utiliser la variable d’environnement CLAUDE_PROJECT_DIR (disponible uniquement lorsque Claude Code lance la commande hook) pour référencer les scripts stockés dans votre projet, en garantissant 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"
          }
        ]
      }
    ]
  }
}

Hooks de plugin

Les plugins peuvent fournir des hooks qui s’intègrent de manière transparente avec vos hooks utilisateur et projet. Les hooks de plugin sont automatiquement fusionnés avec votre configuration lorsque les plugins sont activés. Comment fonctionnent les hooks de plugin :
  • Les hooks de plugin sont définis dans le fichier hooks/hooks.json du plugin ou dans un fichier donné par un chemin personnalisé vers le champ hooks.
  • Lorsqu’un plugin est activé, ses hooks sont fusionnés avec les hooks utilisateur et projet
  • Plusieurs hooks de différentes sources peuvent répondre au même événement
  • Les hooks de plugin utilisent la variable d’environnement ${CLAUDE_PLUGIN_ROOT} pour référencer les fichiers du plugin
Exemple de configuration de hook de plugin :
{
  "description": "Formatage automatique du code",
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "${CLAUDE_PLUGIN_ROOT}/scripts/format.sh",
            "timeout": 30
          }
        ]
      }
    ]
  }
}
Les hooks de plugin utilisent le même format que les hooks réguliers avec un champ description optionnel pour expliquer l’objectif du hook.
Les hooks de plugin s’exécutent aux côtés de vos hooks personnalisés. Si plusieurs hooks correspondent à un événement, ils s’exécutent tous en parallèle.
Variables d’environnement pour les plugins :
  • ${CLAUDE_PLUGIN_ROOT} : Chemin absolu vers le répertoire du plugin
  • ${CLAUDE_PROJECT_DIR} : Répertoire racine du projet (identique à celui des hooks de projet)
  • Toutes les variables d’environnement standard sont disponibles
Consultez la référence des composants de plugin pour plus de détails sur la création de hooks de plugin.

Hooks basés sur des invites

En plus des hooks de commande bash (type: "command"), Claude Code supporte les hooks basés sur des invites (type: "prompt") qui utilisent un LLM pour évaluer s’il faut autoriser ou bloquer une action. Les hooks basés sur des invites sont actuellement uniquement supportés pour les hooks Stop et SubagentStop, où ils permettent des décisions intelligentes et conscientes du contexte.

Comment fonctionnent les hooks basés sur des invites

Au lieu d’exécuter une commande bash, les hooks basés sur des invites :
  1. Envoient l’entrée du hook et votre invite à un LLM rapide (Haiku)
  2. Le LLM répond avec du JSON structuré contenant une décision
  3. Claude Code traite la décision automatiquement

Configuration

{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "prompt",
            "prompt": "Évaluez si Claude doit s'arrêter : $ARGUMENTS. Vérifiez si toutes les tâches sont terminées."
          }
        ]
      }
    ]
  }
}
Champs :
  • type : Doit être "prompt"
  • prompt : Le texte d’invite à envoyer au LLM
    • Utilisez $ARGUMENTS comme espace réservé pour l’entrée JSON du hook
    • Si $ARGUMENTS n’est pas présent, l’entrée JSON est ajoutée à l’invite
  • timeout : (Optionnel) Délai d’expiration en secondes (par défaut : 30 secondes)

Schéma de réponse

Le LLM doit répondre avec du JSON contenant :
{
  "decision": "approve" | "block",
  "reason": "Explication de la décision",
  "continue": false,  // Optionnel : arrête Claude entièrement
  "stopReason": "Message affiché à l'utilisateur",  // Optionnel : message d'arrêt personnalisé
  "systemMessage": "Avertissement ou contexte"  // Optionnel : affiché à l'utilisateur
}
Champs de réponse :
  • decision : "approve" autorise l’action, "block" l’empêche
  • reason : Explication affichée à Claude lorsque la décision est "block"
  • continue : (Optionnel) Si false, arrête complètement l’exécution de Claude
  • stopReason : (Optionnel) Message affiché lorsque continue est false
  • systemMessage : (Optionnel) Message supplémentaire affiché à l’utilisateur

Événements de hook supportés

Les hooks basés sur des invites fonctionnent avec n’importe quel événement de hook, mais sont plus utiles pour :
  • Stop : Décider intelligemment si Claude doit continuer à travailler
  • SubagentStop : Évaluer si un sous-agent a terminé sa tâche
  • UserPromptSubmit : Valider les invites utilisateur avec l’aide du LLM
  • PreToolUse : Prendre des décisions de permission conscientes du contexte

Exemple : Hook Stop intelligent

{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "prompt",
            "prompt": "Vous évaluez si Claude doit arrêter de travailler. Contexte : $ARGUMENTS\n\nAnalysez la conversation et déterminez si :\n1. Toutes les tâches demandées par l'utilisateur sont terminées\n2. Des erreurs doivent être corrigées\n3. Un travail de suivi est nécessaire\n\nRépondez avec du JSON : {\"decision\": \"approve\" ou \"block\", \"reason\": \"votre explication\"}",
            "timeout": 30
          }
        ]
      }
    ]
  }
}

Exemple : SubagentStop avec logique personnalisée

{
  "hooks": {
    "SubagentStop": [
      {
        "hooks": [
          {
            "type": "prompt",
            "prompt": "Évaluez si ce sous-agent doit s'arrêter. Entrée : $ARGUMENTS\n\nVérifiez si :\n- Le sous-agent a terminé sa tâche assignée\n- Des erreurs se sont produites qui doivent être corrigées\n- Une collecte de contexte supplémentaire est nécessaire\n\nRetournez : {\"decision\": \"approve\" ou \"block\", \"reason\": \"explication\"}"
          }
        ]
      }
    ]
  }
}

Comparaison avec les hooks de commande bash

FonctionnalitéHooks de commande BashHooks basés sur des invites
ExécutionExécute un script bashInterroge le LLM
Logique de décisionVous implémentez dans le codeLe LLM évalue le contexte
Complexité de configurationNécessite un fichier de scriptConfigurez simplement l’invite
Conscience du contexteLimitée à la logique du scriptCompréhension du langage naturel
PerformanceRapide (exécution locale)Plus lent (appel API)
Cas d’utilisationRègles déterministesDécisions conscientes du contexte

Meilleures pratiques

  • Soyez spécifique dans les invites : Énoncez clairement ce que vous voulez que le LLM évalue
  • Incluez les critères de décision : Énumérez les facteurs que le LLM doit considérer
  • Testez vos invites : Vérifiez que le LLM prend les bonnes décisions pour vos cas d’utilisation
  • Définissez des délais d’expiration appropriés : La valeur par défaut est 30 secondes, ajustez si nécessaire
  • Utilisez pour les décisions complexes : Les hooks bash sont meilleurs pour les règles simples et déterministes
Consultez la référence des composants de plugin pour plus de détails sur la création de hooks de plugin.

É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 courants :
  • Task - Tâches de sous-agent (consultez la documentation des sous-agents)
  • Bash - Commandes shell
  • Glob - Correspondance de modèle de fichier
  • Grep - Recherche de contenu
  • Read - Lecture de fichier
  • Edit - Édition de fichier
  • Write - Écriture de fichier
  • 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 d’invite a été inactive pendant au moins 60 secondes. « Claude attend votre entrée »

UserPromptSubmit

S’exécute lorsque l’utilisateur soumet une invite, avant que Claude la traite. Cela vous permet d’ajouter du contexte supplémentaire basé sur l’invite/conversation, de valider les invites ou de bloquer certains types d’invites.

Stop

S’exécute lorsque l’agent Claude Code principal a terminé sa réponse. Ne s’exécute pas si l’arrêt s’est produit en raison d’une interruption utilisateur.

SubagentStop

S’exécute lorsqu’un sous-agent Claude Code (appel d’outil Task) a terminé sa réponse.

PreCompact

S’exécute avant que Claude Code ne soit sur le point d’exécuter une opération de compactage. Matchers :
  • manual - Invoqué depuis /compact
  • auto - Invoqué depuis le compactage automatique (en raison de la fenêtre de contexte complète)

SessionStart

S’exécute lorsque Claude Code démarre une nouvelle session ou reprend une session existante (ce qui démarre actuellement une nouvelle session sous le capot). Utile pour charger le contexte de développement comme les problèmes existants ou les modifications récentes de votre base de code, installer les dépendances ou configurer les variables d’environnement. Matchers :
  • startup - Invoqué au démarrage
  • resume - Invoqué depuis --resume, --continue ou /resume
  • clear - Invoqué depuis /clear
  • compact - Invoqué depuis le compactage automatique ou manuel.

Persistance des variables d’environnement

Les hooks SessionStart ont accès à la variable d’environnement CLAUDE_ENV_FILE, qui fournit un chemin de fichier où vous pouvez persister les variables d’environnement pour les commandes bash ultérieures. Exemple : Définition de variables d’environnement individuelles
#!/bin/bash

if [ -n "$CLAUDE_ENV_FILE" ]; then
  echo 'export NODE_ENV=production' >> "$CLAUDE_ENV_FILE"
  echo 'export API_KEY=your-api-key' >> "$CLAUDE_ENV_FILE"
  echo 'export PATH="$PATH:./node_modules/.bin"' >> "$CLAUDE_ENV_FILE"
fi

exit 0
Exemple : Persistance de tous les changements d’environnement du hook Lorsque votre configuration modifie l’environnement (par exemple, nvm use), capturez et persistez tous les changements en comparant l’environnement :
#!/bin/bash

ENV_BEFORE=$(export -p | sort)

# Exécutez vos commandes de configuration qui modifient l'environnement
source ~/.nvm/nvm.sh
nvm use 20

if [ -n "$CLAUDE_ENV_FILE" ]; then
  ENV_AFTER=$(export -p | sort)
  comm -13 <(echo "$ENV_BEFORE") <(echo "$ENV_AFTER") >> "$CLAUDE_ENV_FILE"
fi

exit 0
Toutes les variables écrites dans ce fichier seront disponibles dans toutes les commandes bash ultérieures que Claude Code exécute pendant la session.
CLAUDE_ENV_FILE n’est disponible que pour les hooks SessionStart. Les autres types de hooks n’ont pas accès à cette variable.

SessionEnd

S’exécute lorsqu’une session Claude Code se termine. Utile pour les tâches de nettoyage, la journalisation des statistiques de session ou l’enregistrement de l’état de la session. Le champ reason dans l’entrée du hook sera l’un des suivants :
  • clear - Session effacée avec la commande /clear
  • logout - L’utilisateur s’est déconnecté
  • prompt_input_exit - L’utilisateur a quitté pendant que l’entrée d’invite était visible
  • other - Autres raisons de sortie

Entrée du hook

Les hooks reçoivent des données JSON via stdin contenant les informations de session et les données spécifiques à l’événement :
{
  // Champs courants
  session_id: string
  transcript_path: string  // Chemin vers le JSON de conversation
  cwd: string              // Le répertoire courant lorsque le hook est invoqué
  permission_mode: string  // Mode de permission actuel : "default", "plan", "acceptEdits" ou "bypassPermissions"

  // 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/...",
  "permission_mode": "default",
  "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/...",
  "permission_mode": "default",
  "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/...",
  "permission_mode": "default",
  "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/...",
  "permission_mode": "default",
  "hook_event_name": "UserPromptSubmit",
  "prompt": "Write a function to calculate the factorial of a number"
}

Entrée Stop et SubagentStop

stop_hook_active est true lorsque Claude Code continue déjà en raison d’un hook stop. Vérifiez cette valeur ou traitez la transcription pour empêcher Claude Code de s’exécuter indéfiniment.
{
  "session_id": "abc123",
  "transcript_path": "~/.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "permission_mode": "default",
  "hook_event_name": "Stop",
  "stop_hook_active": true
}

Entrée PreCompact

Pour manual, custom_instructions provient de ce que l’utilisateur transmet à /compact. Pour auto, custom_instructions est vide.
{
  "session_id": "abc123",
  "transcript_path": "~/.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "permission_mode": "default",
  "hook_event_name": "PreCompact",
  "trigger": "manual",
  "custom_instructions": ""
}

Entrée SessionStart

{
  "session_id": "abc123",
  "transcript_path": "~/.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "permission_mode": "default",
  "hook_event_name": "SessionStart",
  "source": "startup"
}

Entrée SessionEnd

{
  "session_id": "abc123",
  "transcript_path": "~/.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "cwd": "/Users/...",
  "permission_mode": "default",
  "hook_event_name": "SessionEnd",
  "reason": "exit"
}

Sortie du hook

Il y a deux façons pour les hooks de retourner la sortie à Claude Code. La sortie communique s’il faut bloquer et tout retour d’information qui doit être affiché à 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 affiché à l’utilisateur en mode transcription (CTRL-R), sauf pour UserPromptSubmit et SessionStart, où stdout est ajouté au contexte.
  • Code de sortie 2 : Erreur de blocage. stderr est renvoyé à Claude pour être traité automatiquement. Consultez le comportement par événement de hook ci-dessous.
  • Autres codes de sortie : Erreur non bloquante. stderr est affiché à 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, affiche stderr à Claude
PostToolUseAffiche stderr à Claude (l’outil a déjà été exécuté)
NotificationN/A, affiche stderr à l’utilisateur uniquement
UserPromptSubmitBloque le traitement de l’invite, efface l’invite, affiche stderr à l’utilisateur uniquement
StopBloque l’arrêt, affiche stderr à Claude
SubagentStopBloque l’arrêt, affiche stderr au sous-agent Claude
PreCompactN/A, affiche stderr à l’utilisateur uniquement
SessionStartN/A, affiche stderr à l’utilisateur uniquement
SessionEndN/A, affiche stderr à l’utilisateur uniquement

Avancé : Sortie JSON

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

Champs JSON courants

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 affiché lorsque continue est false

  "suppressOutput": true, // Masquer stdout du mode transcription (par défaut : false)
  "systemMessage": "string" // Message d'avertissement optionnel affiché à l'utilisateur
}
Si continue est false, Claude arrête le traitement après l’exécution des hooks.
  • Pour PreToolUse, ceci est différent de "permissionDecision": "deny", qui bloque uniquement un appel d’outil spécifique et fournit un retour d’information automatique à Claude.
  • Pour PostToolUse, ceci est différent de "decision": "block", qui fournit un retour d’information automatisé à Claude.
  • Pour UserPromptSubmit, ceci empêche l’invite d’être traitée.
  • Pour Stop et SubagentStop, ceci a la priorité sur tout résultat "decision": "block".
  • Dans tous les cas, "continue" = false a la priorité sur tout résultat "decision": "block".
stopReason accompagne continue avec une raison affichée à l’utilisateur, non affiché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 affiché à l’utilisateur mais pas à Claude.
  • "deny" empêche l’appel d’outil de s’exécuter. permissionDecisionReason est affiché à Claude.
  • "ask" demande à l’utilisateur de confirmer l’appel d’outil dans l’interface utilisateur. permissionDecisionReason est affiché à l’utilisateur mais pas à Claude.
De plus, les hooks peuvent modifier les entrées d’outil avant l’exécution en utilisant updatedInput :
  • updatedInput vous permet de modifier les paramètres d’entrée de l’outil avant l’exécution de l’outil. C’est un objet Record<string, unknown> contenant les champs que vous souhaitez modifier ou ajouter.
  • Ceci est très utile avec "permissionDecision": "allow" pour modifier et approuver les appels d’outil.
{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "allow"
    "permissionDecisionReason": "Ma raison ici",
    "updatedInput": {
      "field_to_modify": "new value"
    }
  }
}
Les champs decision et reason sont dépréciés pour les hooks PreToolUse. Utilisez hookSpecificOutput.permissionDecision et hookSpecificOutput.permissionDecisionReason à la place. Les champs dépréciés "approve" et "block" correspondent à "allow" et "deny" respectivement.

Contrôle de décision PostToolUse

Les hooks PostToolUse peuvent fournir un retour d’information à Claude après l’exécution de l’outil.
  • "block" invite automatiquement Claude avec reason.
  • undefined ne fait rien. reason est ignoré.
  • "hookSpecificOutput.additionalContext" ajoute du contexte pour que Claude le considère.
{
  "decision": "block" | undefined,
  "reason": "Explication de la décision",
  "hookSpecificOutput": {
    "hookEventName": "PostToolUse",
    "additionalContext": "Informations supplémentaires pour Claude"
  }
}

Contrôle de décision UserPromptSubmit

Les hooks UserPromptSubmit peuvent contrôler si une invite utilisateur est traitée.
  • "block" empêche l’invite d’être traitée. L’invite soumise est effacée du contexte. "reason" est affiché à l’utilisateur mais pas ajouté au contexte.
  • undefined permet à l’invite de procéder normalement. "reason" est ignoré.
  • "hookSpecificOutput.additionalContext" ajoute la chaîne au contexte si elle n’est pas bloquée.
{
  "decision": "block" | undefined,
  "reason": "Explication de la décision",
  "hookSpecificOutput": {
    "hookEventName": "UserPromptSubmit",
    "additionalContext": "Mon contexte supplémentaire ici"
  }
}

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": "Doit être fourni lorsque Claude est empêché de s'arrêter"
}

Contrôle de décision SessionStart

Les hooks SessionStart vous permettent de charger du contexte au début d’une session.
  • "hookSpecificOutput.additionalContext" ajoute la chaîne au contexte.
  • Les valeurs additionalContext de plusieurs hooks sont concaténées.
{
  "hookSpecificOutput": {
    "hookEventName": "SessionStart",
    "additionalContext": "Mon contexte supplémentaire ici"
  }
}

Contrôle de décision SessionEnd

Les hooks SessionEnd s’exécutent lorsqu’une session se termine. Ils ne peuvent pas bloquer la terminaison de la session mais peuvent effectuer des tâches de nettoyage.

Exemple de code de sortie : Validation de commande Bash

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

# Définissez les règles de validation comme une liste de tuples (modèle regex, message)
VALIDATION_RULES = [
    (
        r"\bgrep\b(?!.*\|)",
        "Utilisez 'rg' (ripgrep) au lieu de 'grep' pour de meilleures performances et fonctionnalités",
    ),
    (
        r"\bfind\s+\S+\s+-name\b",
        "Utilisez 'rg --files | rg pattern' ou 'rg --files -g pattern' au lieu de 'find -name' pour de meilleures performances",
    ),
]


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"Erreur : Entrée JSON invalide : {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)

# Validez 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 affiche stderr à Claude
    sys.exit(2)

Exemple de sortie JSON : UserPromptSubmit pour ajouter du contexte et une 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

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

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

# Vérifiez les modèles sensibles
sensitive_patterns = [
    (r"(?i)\b(password|secret|key|token)\s*[:=]", "L'invite contient des secrets potentiels"),
]

for pattern, message in sensitive_patterns:
    if re.search(pattern, prompt):
        # Utilisez la sortie JSON pour bloquer avec une raison spécifique
        output = {
            "decision": "block",
            "reason": f"Violation de la politique de sécurité : {message}. Veuillez reformuler votre demande sans informations sensibles."
        }
        print(json.dumps(output))
        sys.exit(0)

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

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

# Permettez à l'invite 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

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

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

# Exemple : Approbation automatique des 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")):
        # Utilisez la sortie JSON pour approuver automatiquement l'appel d'outil
        output = {
            "decision": "approve",
            "reason": "Fichier de documentation approuvé automatiquement",
            "suppressOutput": True  # Ne pas afficher en mode transcription
        }
        print(json.dumps(output))
        sys.exit(0)

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

Travail avec les outils MCP

Les hooks Claude Code fonctionnent de manière transparente avec les outils du protocole de contexte de modèle (MCP). Lorsque les serveurs MCP fournissent des outils, ils apparaissent avec un modèle de nommage spécial que vous pouvez correspondre dans vos hooks.

Nommage des outils MCP

Les outils MCP suivent le modèle 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 du code, les notifications et la protection des fichiers, consultez 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 au système
  • Anthropic ne fournit aucune garantie et n’assume aucune responsabilité pour les dommages résultant de l’utilisation des hooks
  • Vous devez tester minutieusement les hooks dans un environnement sûr avant l’utilisation en production
Examinez toujours et comprenez 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. Validez et nettoyez les entrées - Ne faites jamais confiance aux données d’entrée aveuglément
  2. Citez toujours les variables shell - Utilisez "$VAR" et non $VAR
  3. Bloquez la traversée de répertoires - Vérifiez la présence de .. dans les chemins de fichiers
  4. Utilisez des chemins absolus - Spécifiez les chemins complets pour les scripts (utilisez “$CLAUDE_PROJECT_DIR” pour le chemin du projet)
  5. Ignorez les fichiers sensibles - Évitez .env, .git/, les clés, etc.

Sécurité de la 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 en externe
  4. Nécessite un examen dans le menu /hooks pour que les modifications s’appliquent
Cela empêche les modifications malveillantes de hooks d’affecter votre session actuelle.

Détails d’exécution du hook

  • Délai d’expiration : Limite d’exécution de 60 secondes par défaut, configurable par commande.
    • Un délai d’expiration pour une commande individuelle n’affecte pas les autres commandes.
  • Parallélisation : Tous les hooks correspondants s’exécutent en parallèle
  • Déduplication : Les commandes de hook identiques multiples sont automatiquement dédupliquées
  • 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 (où Claude Code a été démarré)
    • La variable d’environnement CLAUDE_CODE_REMOTE indique si le hook s’exécute dans un environnement distant (web) ("true") ou un environnement CLI local (non défini ou vide). Utilisez ceci pour exécuter une logique différente en fonction du contexte d’exécution.
  • Entrée : JSON via stdin
  • Sortie :
    • PreToolUse/PostToolUse/Stop/SubagentStop : Progression affichée en transcription (Ctrl-R)
    • Notification/SessionEnd : Enregistré au débogage uniquement (--debug)
    • UserPromptSubmit/SessionStart : stdout ajouté comme contexte pour Claude

Débogage

Dépannage de base

Si vos hooks ne fonctionnent pas :
  1. Vérifiez la configuration - Exécutez /hooks pour voir si votre hook est enregistré
  2. Vérifiez la syntaxe - Assurez-vous que votre JSON de paramètres est valide
  3. Testez les commandes - Exécutez d’abord les commandes de hook manuellement
  4. Vérifiez les permissions - Assurez-vous que les scripts sont exécutables
  5. Consultez les journaux - Utilisez claude --debug pour voir les détails d’exécution du hook
Problèmes courants :
  • Guillemets non échappés - Utilisez \" dans les chaînes JSON
  • Matcher incorrect - Vérifiez que les noms d’outils correspondent exactement (sensible à la casse)
  • Commande non trouvée - Utilisez les chemins complets pour les scripts

Débogage avancé

Pour les problèmes de hook complexes :
  1. Inspectez l’exécution du hook - Utilisez claude --debug pour voir l’exécution détaillée du hook
  2. Validez les schémas JSON - Testez l’entrée/sortie du hook avec des outils externes
  3. Vérifiez les variables d’environnement - Vérifiez que l’environnement de Claude Code est correct
  4. Testez les cas limites - Essayez les hooks avec des chemins de fichiers ou des entrées inhabituels
  5. Surveillez les ressources système - Vérifiez l’épuisement des ressources pendant l’exécution du hook
  6. Utilisez la journalisation structurée - Implémentez la journalisation dans vos scripts de hook

Exemple de sortie de débogage

Utilisez claude --debug pour voir les détails d’exécution du hook :
[DEBUG] Exécution des hooks pour PostToolUse:Write
[DEBUG] Obtention des commandes de hook correspondantes pour PostToolUse avec la requête : Write
[DEBUG] 1 matcher de hook trouvé dans les paramètres
[DEBUG] 1 hooks correspondants trouvés pour la requête "Write"
[DEBUG] 1 commandes de hook trouvées à exécuter
[DEBUG] Exécution de la commande de hook : <Your command> avec délai d'expiration 60000ms
[DEBUG] Commande de hook terminée avec le statut 0 : <Your stdout>
Les messages de progression apparaissent en mode transcription (Ctrl-R) affichant :
  • Quel hook s’exécute
  • Commande en cours d’exécution
  • Statut de succès/échec
  • Messages de sortie ou d’erreur