Les hooks de Claude Code sont des commandes (ou des appels HTTP, des prompts et quelques autres types de handlers) que Claude Code exécute automatiquement à des moments précis d'une session : avant l'exécution d'un outil, quand une permission est requise ou quand Claude a fini de répondre, par exemple. Tu les définis sous une clé hooks dans un fichier de paramètres comme ~/.claude/settings.json. Chaque hook reçoit sur stdin un JSON décrivant l'événement et peut répondre via son code de sortie ou un objet JSON sur stdout, ce qui lui permet de journaliser, d'envoyer une notification, de bloquer une action ou de répondre à ta place.
01Comment un hook est structuré
Une configuration de hook comporte trois niveaux :
- L'événement de hook, comme
PreToolUseouStop. - Un groupe de matchers, qui filtre quand il se déclenche, par exemple « uniquement pour l'outil Bash ».
- Un ou plusieurs handlers de hook, c'est-à-dire ce qui s'exécute réellement.
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "/path/to/lint-check.sh"
}
]
}
]
}
}
Ceci lance un script de lint après que Claude a écrit ou modifié un fichier. Pour ajouter un second événement, ajoute une clé voisine dans le même objet hooks.
02Où se trouvent les hooks
~/.claude/settings.jsonTous tes projetsNon, uniquement ta machine.claude/settings.jsonUn projetOui, peut être commité.claude/settings.local.jsonUn projetNonhooks/hooks.json d'un pluginTant que le plugin est activéOuiLes hooks de différents fichiers s'additionnent au lieu de se remplacer. Tape /hooks dans Claude Code pour voir tous les hooks actifs et leur provenance.
En session interactive, Claude Code retient les hooks, même les tiens, tant que tu n'as pas accepté la boîte de dialogue de confiance du workspace pour le dossier.
03Types de handlers
La plupart des hooks sont de type "type": "command", qui exécute une commande shell. Il en existe quatre autres :
http: envoie le JSON de l'événement en POST à une URL et lit le corps de la réponse.mcp_tool: appelle un outil sur un serveur MCP que tu as configuré.prompt: pose une question en un seul tour à un modèle Claude et lit une décision en JSON.agent: lance un sous-agent qui peut lire des fichiers avant de décider (expérimental).
Les hooks de type command s'exécutent avec toutes tes permissions utilisateur, via sh -c sur macOS et Linux, et via Git Bash (ou PowerShell) sur Windows. Ajoute "async": true pour en lancer un en arrière-plan ; il ne peut alors plus prendre de décisions.
04Matchers
Le matcher détermine quelles occurrences d'un événement déclenchent le hook. Ce sur quoi il porte dépend de l'événement : le nom de l'outil pour les événements d'outil, le type de notification pour Notification, la façon dont la session a démarré pour SessionStart, etc.
"*",""ou l'absence de matcher correspondent à tout.- Les lettres, chiffres,
_,-, espaces,|et,sont traités comme des noms exacts.Edit|Writecorrespond à l'un ou l'autre outil. - Tout le reste est interprété comme une expression régulière JavaScript :
mcp__memory__.*correspond donc à tous les outils d'un même serveur MCP.
Les matchers sont sensibles à la casse. Certains événements, dont Stop et UserPromptSubmit, ignorent les matchers. Pour les événements d'outil, un champ if contenant une règle de permission comme "Bash(git *)" restreint encore davantage un handler donné.
05Entrée : ce que reçoit ton hook
Chaque hook reçoit sur stdin un JSON avec quelques champs communs, dont session_id, transcript_path, cwd et hook_event_name, ainsi que des champs propres à l'événement. Un hook PreToolUse pour un appel Bash reçoit par exemple aussi tool_name et tool_input.command. Lis-le avec jq ou n'importe quel parseur JSON :
#!/bin/bash
input=$(cat)
cmd=$(jq -r '.tool_input.command // empty' <<<"$input")
echo "Claude wants to run: $cmd" >> ~/claude-commands.log
exit 0
06Sortie : codes de sortie et JSON
Un hook peut répondre de deux façons.
Codes de sortie. 0 signifie succès. 2 est une erreur bloquante : sur les événements qui peuvent bloquer, l'action s'arrête et ton stderr sert de motif. Tout autre code, y compris le classique 1, est une erreur non bloquante : l'action continue et tu vois un avertissement d'erreur du hook. Si ton hook doit faire respecter une règle, sors avec 2, pas 1.
JSON sur stdout. Pour un contrôle plus fin, sors avec 0 et affiche un unique objet JSON. Certains champs fonctionnent partout, comme continue: false pour arrêter complètement Claude. D'autres dépendent de l'événement : Stop utilise decision: "block" avec un reason, tandis que PreToolUse et PermissionRequest placent leur décision dans hookSpecificOutput. N'affiche rien d'autre sur stdout : une ligne parasite venant de ton profil shell empêche Claude Code de lire le JSON.
07Tous les événements de hook
SessionStartUne session démarre ou reprendNon (ajoute du contexte)SetupLancé avec --init-only, ou --init / --maintenance avec -pNonInstructionsLoadedUn fichier CLAUDE.md ou .claude/rules/*.md est chargéNonUserPromptSubmitTu envoies un prompt, avant que Claude le voieOuiUserPromptExpansionUne commande saisie se développe en promptOuiPreToolUseAvant chaque appel d'outilOuiPermissionRequestUn appel d'outil nécessite une décision de permissionAutorise ou refuse via JSONPermissionDeniedLe mode auto refuse un appel d'outilNonPostToolUseAprès un appel d'outil réussiNon (l'outil a déjà tourné)PostToolUseFailureAprès l'échec d'un appel d'outilNonPostToolBatchAprès un lot d'appels d'outils parallèles, avant le prochain appel au modèleOuiNotificationClaude Code envoie une notificationNonMessageDisplayPendant l'affichage du texte de réponse de ClaudeNon (peut modifier ce qui s'affiche)SubagentStart / SubagentStopUn subagent démarre ou se termineSubagentStop uniquementTaskCreated / TaskCompletedUne tâche est créée ou marquée comme terminéeOuiStopClaude a fini de répondreOui (relance Claude)StopFailureLe tour se termine sur une erreur d'APINonTeammateIdleUn coéquipier d'une agent team est sur le point de passer inactifOuiConfigChangeUn fichier de settings change pendant une sessionOuiCwdChangedLe répertoire de travail changeNonDirectoryAddedUn répertoire est ajouté avec /add-dirNonFileChangedUn fichier surveillé change sur le disqueNonWorktreeCreate / WorktreeRemoveUn worktree est créé ou suppriméOuiPreCompact / PostCompactAvant et après la compaction du contextePreCompact uniquementPreModelSwitch / PostModelSwitchAvant et après le changement de modèlePreModelSwitch uniquementElicitation / ElicitationResultUn serveur MCP te demande une saisie, puis après ta réponseOuiSessionEndUne session se termineNonAnthropic ajoute des événements de temps en temps, donc consulte la référence des hooks pour la liste à jour et les champs d'entrée de chaque événement.
08Quels événements comptent pour les notifications
Quatre événements couvrent presque tout ce dont on veut être prévenu :
Stoppour « Claude a terminé ». Voir le guide du Stop hook.Notificationpour « Claude t'attend », avec des types commepermission_promptetidle_prompt. Voir le guide du Notification hook.PermissionRequestpour être prévenu, ou répondre, dès qu'une permission est nécessaire. Voir le guide PermissionRequest.PreToolUsesur l'outilAskUserQuestion, pour voir ou répondre aux questions à choix multiples de Claude. Voir répondre aux questions depuis ton téléphone.
Pour une config desktop prête à coller, commence par comment recevoir une notification quand Claude Code a terminé.
09Où se situe Claude Code Notifier
Claude Code Notifier repose entièrement sur ces hooks. Son outil en ligne de commande gratuit, ccn, tourne sur Mac, Windows et Linux. L'installation ajoute sept entrées de hook dans ~/.claude/settings.json, chacune lançant ccn hook, et crée une sauvegarde unique du fichier. ccn s'exécute quelques millisecondes par événement puis se ferme : rien ne reste actif.
Seul, il affiche des notifications desktop. Avec l'app iPhone ou Android associée, les mêmes hooks renvoient tes réponses : autoriser ou refuser une permission, répondre à une question, ou envoyer l'instruction suivante quand Claude s'arrête. C'est un outil indépendant, non développé par Anthropic. Si tu as juste besoin d'un log ou d'une étape de lint, quelques lignes à toi suffisent. Plus de détails sur la page ccn.
10FAQ
Comment tester un hook sans attendre Claude ?
Envoie un JSON d'exemple au script via un pipe et vérifie le code de sortie : echo '{"tool_name":"Bash","tool_input":{"command":"ls"}}' | ./my-hook.sh; echo $?. Ensuite, lance /hooks dans Claude Code pour vérifier qu'il est enregistré sous le bon événement.
Pourquoi mon hook ne se lance pas ?
Les causes habituelles : un JSON invalide dans settings.json (virgules finales, commentaires), un matcher qui ne correspond pas exactement (ils sont sensibles à la casse), un script non exécutable, ou un dossier que tu n'as pas encore approuvé. Lance Claude Code avec claude --debug et lis le log de debug pour voir ce qui s'est exécuté. La liste complète est dans la checklist de dépannage.
Comment désactiver tous les hooks temporairement ?
Mets "disableAllHooks": true dans un fichier de settings. Pour les ignorer le temps d'une seule session, lance Claude Code avec --settings '{"disableAllHooks": true}'. Il n'existe pas d'interrupteur pour un seul hook : il faut supprimer son entrée. Aucune de ces options ne désactive les hooks définis par ton organisation dans les managed settings.
Quel est le timeout par défaut d'un hook ?
Dix minutes (600 secondes) pour les hooks de type command, HTTP et outil MCP, 30 secondes pour les hooks prompt et 60 pour les hooks agent. Quelques événements ont des valeurs par défaut plus courtes, et tu peux définir timeout en secondes sur n'importe quel handler.