En bref
Les hooks Claude Code sont des commandes shell exécutées automatiquement à des points précis du cycle de vie d’une session. Contrairement aux instructions données dans un CLAUDE.md, les hooks sont déterministes : Claude ne peut pas choisir de les ignorer. Ils s’exécutent toujours, quelles que soient les instructions reçues par le modèle.
Cas d’usage principaux : logger toutes les commandes Bash exécutées par Claude, bloquer l’écriture sur des fichiers sensibles, envoyer une notification desktop quand Claude attend une saisie, ou ré-injecter du contexte dans la session après une compaction.
22 événements sont disponibles à ce jour. Deux ont été ajoutés récemment : InstructionsLoaded (v2.1.69) et StopFailure (v2.1.78).
Prérequis
- Claude Code installé — version v2.1.78 minimum recommandée (plusieurs bugs hooks corrigés entre v2.1.72 et v2.1.78)
- Accès au fichier
settings.json:~/.claude/settings.json(global) ou.claude/settings.jsondans votre projet - Aucune dépendance supplémentaire pour les hooks de type
command— jq recommandé pour parser le JSON stdin
Comment fonctionnent les hooks
Le mécanisme de base
Un hook reçoit un payload JSON sur stdin au moment où l’événement se déclenche. Il répond via son code de sortie et son stdout :
| Code de sortie | Effet |
|---|---|
0 | Succès — stdout parsé pour JSON de décision — exécution continue |
2 | Erreur bloquante — stderr transmis à Claude comme feedback — action bloquée |
| Autre | Erreur non-bloquante — stderr visible uniquement en mode verbose |
Quatre types de handlers sont disponibles : command (shell), http (POST vers une URL), prompt (appel LLM single-turn, Haiku par défaut), agent (sous-agent multi-turns). La majorité des cas d’usage se couvrent avec command.
Les 22 événements, par catégorie
Cycle de vie de la session
| Événement | Déclenchement | Bloquable |
|---|---|---|
SessionStart | Début ou reprise de session | Non |
InstructionsLoaded | Chargement d’un CLAUDE.md ou règle | Non |
SessionEnd | Fin de session | Non |
PreCompact | Avant compaction du contexte | Non |
PostCompact | Après compaction | Non |
ConfigChange | Modification d’un fichier de config pendant la session | Oui* |
*ConfigChange sur policy_settings ne peut pas être bloqué (sécurité entreprise).
Prompts et outils
| Événement | Déclenchement | Bloquable |
|---|---|---|
UserPromptSubmit | Soumission d’un prompt utilisateur | Oui |
PreToolUse | Avant exécution d’un outil | Oui |
PostToolUse | Après exécution réussie d’un outil | Non** |
PostToolUseFailure | Après échec d’un outil | Non |
PermissionRequest | Quand une dialog de permission apparaît | Oui |
**PostToolUse avec exit 2 montre l’erreur à Claude, mais ne peut pas annuler une action déjà exécutée.
Agents et coordination
| Événement | Déclenchement | Bloquable |
|---|---|---|
SubagentStart | Lancement d’un sous-agent | Non (async) |
SubagentStop | Fin d’un sous-agent | Oui |
Stop | Fin de réponse de Claude | Oui |
StopFailure | Fin de tour suite à une erreur API | Non |
TeammateIdle | Teammate (Agent Teams) passe en idle | Oui |
TaskCompleted | Tâche marquée complétée | Oui |
Notification | Notification envoyée par Claude Code | Non |
Worktrees et MCP
| Événement | Déclenchement | Bloquable |
|---|---|---|
WorktreeCreate | Création d’un worktree git | Oui |
WorktreeRemove | Suppression d’un worktree | Non |
Elicitation | Serveur MCP demande une saisie utilisateur | Oui |
ElicitationResult | Réponse à une elicitation MCP | Oui |
Configuration dans settings.json
Structure de base :
{
"hooks": {
"PostToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.command' >> ~/.claude/command-log.txt",
"timeout": 600
}
]
}
]
}
}
Le champ matcher est un pattern regex appliqué au champ filtré de l’événement (tool_name pour PreToolUse/PostToolUse, source pour SessionStart, etc.). Utilisez "" ou "*" pour intercepter tous les déclenchements.
Trois emplacements de fichier selon la portée souhaitée :
~/.claude/settings.json— s’applique à tous les projets, non partageable.claude/settings.json— projet uniquement, committable dans le dépôt.claude/settings.local.json— projet uniquement, gitignored
Exemples pratiques
Logging des commandes Bash exécutées par Claude :
{
"hooks": {
"PostToolUse": [
{
"matcher": "Bash",
"hooks": [{ "type": "command", "command": "jq -r '.tool_input.command' >> ~/.claude/command-log.txt" }]
}
]
}
}
Bloquer l’écriture sur des fichiers protégés :
#!/bin/bash
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
PROTECTED_PATTERNS=(".env" "package-lock.json" ".git/")
for pattern in "${PROTECTED_PATTERNS[@]}"; do
if [[ "$FILE_PATH" == *"$pattern"* ]]; then
echo "Bloqué : $FILE_PATH correspond au pattern '$pattern'" >&2
exit 2
fi
done
exit 0
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [{ "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/protect-files.sh" }]
}
]
}
}
Notification desktop quand Claude attend :
{
"hooks": {
"Notification": [
{
"matcher": "",
"hooks": [{ "type": "command", "command": "notify-send 'Claude Code' 'Attention requise'" }]
}
]
}
}
Ré-injecter du contexte après compaction (SessionStart avec matcher compact) :
{
"hooks": {
"SessionStart": [
{
"matcher": "compact",
"hooks": [{ "type": "command", "command": "echo 'Rappel : utiliser Bun, pas npm. Run bun test avant commit.'" }]
}
]
}
}
Anti-boucle infinie pour les hooks Stop : vérifier stop_hook_active avant d’agir. Si true, sortir immédiatement avec exit 0, sinon le hook se déclenche en boucle.
Pièges courants
Hooks vs MCP : deux mécanismes distincts
Les hooks et les serveurs MCP répondent à des besoins différents et ne sont pas interchangeables :
| MCP Servers | Hooks | |
|---|---|---|
| Objectif | Exposer de nouveaux outils à Claude | Automatiser des événements du cycle de vie |
| Invocation | Claude appelle l’outil quand il le juge utile | Automatique, déterministe |
| Usage typique | Intégration API externe, accès base de données | Validation sécurité, logging, notification |
| Configuration | mcp_servers dans settings | hooks dans settings |
Un hook ne peut pas créer un nouvel outil pour Claude. Un serveur MCP ne peut pas intercepter un PreToolUse.
Stdout : seulement deux événements injectent du contexte
C’est la confusion la plus fréquente. Seuls SessionStart et UserPromptSubmit transmettent le stdout du hook dans le contexte de Claude. Pour tous les autres événements, le stdout est parsé comme JSON de décision — il n’est pas lu par le modèle.
Nos tests montrent que le stdout de SessionStart est visible par Claude jusqu’à au moins 509 KB sans troncation, avec un ralentissement perceptible au démarrage à ce volume. La borne supérieure reste non vérifiée. Nos observations indiquent que Claude décrit ce contenu comme un “system-reminder”, mais le mécanisme d’injection exact (position par rapport aux CLAUDE.md, format de wrapping) n’est pas documenté officiellement.
Priorité des deny rules sur les hooks PermissionRequest
Un hook PermissionRequest avec "behavior": "allow" ne peut pas contourner les règles deny définies dans les managed policies. Les deny rules ont toujours la priorité. Ce comportement a été clarifié à partir de la v2.1.77 (une version antérieure permettait le contournement — bug corrigé).
Timeout SessionEnd : 1.5s par défaut
Le hook SessionEnd a un timeout de 1.5 secondes par défaut. Il est configurable via la variable d’environnement CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS (ajouté en v2.1.78). Nos tests montrent qu’écrire 50 lignes dans un fichier prend environ 3ms — largement dans le timeout. Les opérations réseau ou les scripts lourds doivent être lancés en mode async ou évités sur cet événement.
SessionEnd et /exit : attention au matcher
Le matcher other sur SessionEnd ne se déclenche pas lors d’un /exit dans le terminal. C’est le matcher prompt_input_exit qui couvre ce cas. Nos tests ont confirmé ce comportement.
Ce qu’il faut retenir
- Les hooks sont déterministes : Claude ne peut pas les ignorer, contrairement aux instructions d’un CLAUDE.md.
- 22 événements couvrent l’ensemble du cycle de vie : session, outils, agents, MCP, worktrees.
- Seuls
SessionStartetUserPromptSubmitinjectent le stdout du hook dans le contexte de Claude. claudeMdExcludeset les hooks sont deux mécanismes complémentaires pour contrôler le comportement de Claude Code.- La configuration dans
~/.claude/settings.jsons’applique globalement ;.claude/settings.jsonest projet-spécifique et committable.
Sources
- Documentation officielle hooks-guide — code.claude.com/docs/en/hooks-guide — accès direct 2026-03-19
- Documentation officielle hooks référence — code.claude.com/docs/en/hooks — accès direct 2026-03-19
- Changelog Claude Code — github.com/anthropics/claude-code/blob/main/CHANGELOG.md — consulté 2026-03-19