Les hooks Claude Code sont des commandes shell définies par l’utilisateur qui s’exécutent à différents points du cycle de vie de Claude Code. Les hooks fournissent un contrôle déterministe du comportement de Claude Code, en 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, consultez Hooks reference.
Les cas d’usage des hooks incluent :
- Notifications : Personnalisez la façon dont vous êtes notifié lorsque Claude Code attend votre entrée 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 comptabilisez toutes les commandes exécutées pour la conformité ou le débogage.
- Retours d’information : Fournissez des retours automatisés lorsque Claude Code produit du code qui ne suit pas les conventions de votre base de code.
- Permissions personnalisées : Bloquez les modifications des fichiers de production ou des répertoires sensibles.
En codant ces règles comme des hooks plutôt que comme des instructions d’invite, 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, un 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, consultez Security Considerations dans la documentation de référence des hooks.
Aperçu des événements Hook
Claude Code fournit plusieurs événements hook 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 fin des appels d’outils
- UserPromptSubmit : S’exécute lorsque l’utilisateur soumet une invite, avant que Claude la traite
- Notification : S’exécute lorsque Claude Code envoie des notifications
- Stop : S’exécute lorsque Claude Code termine sa réponse
- SubagentStop : S’exécute lorsque les tâches du sous-agent se terminent
- PreCompact : S’exécute avant que Claude Code ne soit sur le point d’exécuter une opération compacte
- 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 enregistre 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 hook PreToolUse.
Les hooks PreToolUse s’exécutent avant les appels d’outils et peuvent les bloquer tout en fournissant à Claude des retours 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 : Enregistrer votre configuration
Pour l’emplacement de stockage, sélectionnez User settings puisque vous enregistrez dans votre répertoire personnel. Ce hook s’appliquera alors à tous les projets, pas seulement à votre projet actuel.
Appuyez ensuite sur Échap jusqu’à ce que vous reveniez 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 journal :
cat ~/.claude/bash-command-log.txt
Vous devriez voir des entrées comme :
ls - Lists files and directories
Plus d’exemples
Formatez automatiquement les fichiers TypeScript après les modifications :
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|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; }"
}
]
}
]
}
}
Corrigez automatiquement les balises de langue manquantes et les problèmes de formatage dans les fichiers markdown :
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|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
"""
Markdown formatter for Claude Code output.
Fixes missing language tags and spacing issues while preserving code content.
"""
import json
import sys
import re
import os
def detect_language(code):
"""Best-effort language detection from code content."""
s = code.strip()
# JSON detection
if re.search(r'^\s*[{\[]', s):
try:
json.loads(s)
return 'json'
except:
pass
# Python detection
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'
# JavaScript detection
if re.search(r'\b(function\s+\w+\s*\(|const\s+\w+\s*=)', s) or \
re.search(r'=>|console\.(log|error)', s):
return 'javascript'
# Bash detection
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'
# SQL detection
if re.search(r'\b(SELECT|INSERT|UPDATE|DELETE|CREATE)\s+', s, re.I):
return 'sql'
return 'text'
def format_markdown(content):
"""Format markdown content with language detection."""
# Fix unlabeled code fences
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)
# Fix excessive blank lines (only outside code fences)
content = re.sub(r'\n{3,}', '\n\n', content)
return content.rstrip() + '\n'
# Main execution
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) # Not a markdown file
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"✓ Fixed markdown formatting in {file_path}")
except Exception as e:
print(f"Error formatting markdown: {e}", file=sys.stderr)
sys.exit(1)
Rendez le script exécutable :
chmod +x .claude/hooks/markdown_formatter.py
Ce hook exécute automatiquement :
- Détecte les langages de programmation dans les blocs de code sans étiquette
- Ajoute les balises de langue appropriées pour la mise en évidence de la syntaxe
- Corrige les lignes vides excessives tout en préservant le contenu du code
- Traite uniquement les fichiers markdown (
.md, .mdx)
Hook de notification personnalisée
Recevez des notifications de bureau lorsque Claude a besoin d’une entrée :
{
"hooks": {
"Notification": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "notify-send 'Claude Code' 'Awaiting your input'"
}
]
}
]
}
}
Hook de protection de fichier
Bloquez les modifications des fichiers sensibles :
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|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, consultez Hooks reference.
- Pour les meilleures pratiques de sécurité complètes et les directives de sécurité, consultez Security Considerations dans la documentation de référence des hooks.
- Pour les étapes de dépannage et les techniques de débogage, consultez Debugging dans la documentation de référence des hooks.