- Bloquer les opérations dangereuses avant leur exécution, comme les commandes shell destructrices ou l’accès non autorisé aux fichiers
- Enregistrer et auditer chaque appel d’outil pour la conformité, le débogage ou l’analyse
- Transformer les entrées et les sorties pour nettoyer les données, injecter des identifiants ou rediriger les chemins de fichiers
- Exiger une approbation humaine pour les actions sensibles comme les écritures de base de données ou les appels API
- Suivre le cycle de vie de la session pour gérer l’état, nettoyer les ressources ou envoyer des notifications
Fonctionnement des hooks
Un événement se déclenche
Quelque chose se produit lors de l’exécution de l’agent et le SDK déclenche un événement : un outil est sur le point d’être appelé (
PreToolUse), un outil a renvoyé un résultat (PostToolUse), un sous-agent a démarré ou s’est arrêté, l’agent est inactif ou l’exécution s’est terminée. Consultez la liste complète des événements.Le SDK collecte les hooks enregistrés
Le SDK vérifie les hooks enregistrés pour ce type d’événement. Cela inclut les hooks de rappel que vous transmettez dans
options.hooks et les hooks de commande shell à partir des fichiers de paramètres lorsque l’entrée settingSources ou setting_sources correspondante est activée, ce qui est le cas pour les options query() par défaut.Les matchers filtrent les hooks qui s'exécutent
Si un hook a un motif
matcher (comme "Write|Edit"), le SDK le teste par rapport à la cible de l’événement (par exemple, le nom de l’outil). Les hooks sans matcher s’exécutent pour chaque événement de ce type.Les fonctions de rappel s'exécutent
Chaque fonction de rappel du hook correspondant reçoit des informations sur ce qui se passe : le nom de l’outil, ses arguments, l’ID de session et d’autres détails spécifiques à l’événement.
Votre rappel retourne une décision
Après avoir effectué toute opération (enregistrement, appels API, validation), votre rappel retourne un objet de sortie qui indique à l’agent quoi faire : autoriser l’opération, la bloquer, modifier l’entrée ou injecter du contexte dans la conversation.
PreToolUse (étape 1) avec un matcher "Write|Edit" (étape 3) afin que le rappel ne se déclenche que pour les outils d’écriture de fichiers. Lorsqu’il est déclenché, le rappel reçoit l’entrée de l’outil (étape 4), vérifie si le chemin du fichier cible un fichier .env et retourne permissionDecision: "deny" pour bloquer l’opération (étape 5) :
Hooks disponibles
Le SDK fournit des hooks pour différentes étapes de l’exécution de l’agent. Certains hooks sont disponibles dans les deux SDK, tandis que d’autres sont réservés à TypeScript.| Événement Hook | SDK Python | SDK TypeScript | Ce qui le déclenche | Cas d’usage exemple |
|---|---|---|---|---|
PreToolUse | Oui | Oui | Demande d’appel d’outil (peut bloquer ou modifier) | Bloquer les commandes shell dangereuses |
PostToolUse | Oui | Oui | Résultat de l’exécution de l’outil | Enregistrer tous les changements de fichiers dans la piste d’audit |
PostToolUseFailure | Oui | Oui | Échec de l’exécution de l’outil | Gérer ou enregistrer les erreurs d’outil |
PostToolBatch | Non | Oui | Un lot complet d’appels d’outil se résout, une fois par lot avant l’appel du modèle suivant | Injecter des conventions une fois pour tout le lot |
UserPromptSubmit | Oui | Oui | Soumission d’invite utilisateur | Injecter du contexte supplémentaire dans les invites |
MessageDisplay | Non | Oui | Un message d’assistant avec du texte se termine, une fois par message avec le texte complet du message | Masquer ou reformater le texte affiché sans modifier la transcription |
Stop | Oui | Oui | Arrêt de l’exécution de l’agent | Enregistrer l’état de la session avant la sortie |
SubagentStart | Oui | Oui | Initialisation du sous-agent | Suivre le lancement des tâches parallèles |
SubagentStop | Oui | Oui | Achèvement du sous-agent | Agréger les résultats des tâches parallèles |
PreCompact | Oui | Oui | Demande de compaction de conversation | Archiver la transcription complète avant le résumé |
PermissionRequest | Oui | Oui | La boîte de dialogue de permission s’afficherait | Gestion des permissions personnalisée |
SessionStart | Non | Oui | Initialisation de la session | Initialiser la journalisation et la télémétrie |
SessionEnd | Non | Oui | Arrêt de la session | Nettoyer les ressources temporaires |
Notification | Oui | Oui | Messages d’état de l’agent | Envoyer les mises à jour d’état de l’agent à Slack ou PagerDuty |
Setup | Non | Oui | Configuration/maintenance de la session | Exécuter les tâches d’initialisation |
TeammateIdle | Non | Oui | Le coéquipier devient inactif | Réassigner le travail ou notifier |
TaskCompleted | Non | Oui | La tâche de fond se termine | Agréger les résultats des tâches parallèles |
ConfigChange | Non | Oui | Le fichier de configuration change | Recharger les paramètres dynamiquement |
WorktreeCreate | Non | Oui | Git worktree créé | Suivre les espaces de travail isolés |
WorktreeRemove | Non | Oui | Git worktree supprimé | Nettoyer les ressources de l’espace de travail |
Configurer les hooks
Pour configurer un hook, transmettez-le dans le champhooks de vos options d’agent (ClaudeAgentOptions en Python, l’objet options en TypeScript) :
hooks est un dictionnaire (Python) ou un objet (TypeScript) où :
- Les clés sont les noms d’événements hook (par exemple,
'PreToolUse','PostToolUse','Stop') - Les valeurs sont des tableaux de matchers, chacun contenant un motif de filtre optionnel et vos fonctions de rappel
Matchers
Utilisez les matchers pour filtrer quand vos rappels se déclenchent. Le champmatcher correspond à une valeur différente selon le type d’événement hook. Par exemple, les hooks basés sur les outils correspondent au nom de l’outil, tandis que les hooks Notification correspondent au type de notification. Consultez la référence des hooks Claude Code pour la liste complète des valeurs de matcher pour chaque type d’événement.
Les matchers du SDK suivent les mêmes règles que les matchers dans les fichiers de paramètres : un matcher contenant uniquement des lettres, des chiffres, _ et | est comparé comme une chaîne exacte, avec | séparant les alternatives, donc Write|Edit correspond exactement à ces deux outils. Un matcher de *, une chaîne vide, ou l’omission du matcher entièrement correspond à chaque occurrence de l’événement ; un matcher contenant tout autre caractère est évalué comme une expression régulière, donc ^mcp__ correspond à chaque outil MCP. Un matcher comme mcp__memory contient uniquement des lettres et des traits de soulignement, donc il est comparé comme une chaîne exacte et ne correspond à aucun outil ; utilisez mcp__memory__.* pour correspondre à chaque outil de ce serveur.
| Option | Type | Par défaut | Description |
|---|---|---|---|
matcher | string | undefined | Motif mis en correspondance avec le champ de filtre de l’événement, en suivant les règles de comparaison ci-dessus. Pour les hooks d’outils, c’est le nom de l’outil. Les outils intégrés incluent Bash, Read, Write, Edit, Glob, Grep, WebFetch, Agent et d’autres (consultez Types d’entrée d’outil pour la liste complète). Les outils MCP utilisent le motif mcp__<server>__<action>. |
hooks | HookCallback[] | - | Requis. Tableau de fonctions de rappel à exécuter lorsque le motif correspond |
timeout | number | 60 | Délai d’expiration en secondes |
matcher pour cibler des outils spécifiques chaque fois que possible. Un matcher avec 'Bash' s’exécute uniquement pour les commandes Bash, tandis que l’omission du motif exécute vos rappels pour chaque occurrence de l’événement. Notez que pour les hooks basés sur les outils, les matchers ne filtrent que par nom d’outil, pas par chemins de fichiers ou d’autres arguments. Pour filtrer par chemin de fichier, vérifiez tool_input.file_path à l’intérieur de votre rappel.
Fonctions de rappel
Entrées
Chaque rappel hook reçoit trois arguments :- Données d’entrée : un objet typé contenant les détails de l’événement. Chaque type de hook a sa propre forme d’entrée (par exemple,
PreToolUseHookInputincluttool_nameettool_input, tandis queNotificationHookInputinclutmessage). Consultez les définitions de type complètes dans les références du SDK TypeScript et Python.- Toutes les entrées de hook partagent
session_id,cwdethook_event_name. agent_idetagent_typesont remplis lorsque le hook se déclenche à l’intérieur d’un sous-agent. En TypeScript, ceux-ci se trouvent sur l’entrée de hook de base et sont disponibles pour tous les types de hook. En Python, ils se trouvent uniquement surPreToolUse,PostToolUseetPostToolUseFailure.
- Toutes les entrées de hook partagent
- ID d’utilisation d’outil (
str | None/string | undefined) : met en corrélation les événementsPreToolUseetPostToolUsepour le même appel d’outil. - Contexte : en TypeScript, contient une propriété
signal(AbortSignal) pour l’annulation. En Python, cet argument est réservé pour une utilisation future.
Sorties
Votre rappel retourne un objet avec deux catégories de champs :- Champs de niveau supérieur fonctionnent de la même manière sur chaque événement :
systemMessageaffiche un message à l’utilisateur, etcontinue(continue_en Python) détermine si l’agent continue à s’exécuter après ce hook. hookSpecificOutputcontrôle l’opération actuelle. Les champs à l’intérieur dépendent du type d’événement hook. Pour les hooksPreToolUse, c’est là que vous définissezpermissionDecision("allow","deny","ask"ou"defer"),permissionDecisionReasonetupdatedInput. Retourner"defer"termine la requête pour que vous puissiez la reprendre plus tard. Pour les hooksPostToolUse, vous pouvez définiradditionalContextpour ajouter des informations au résultat de l’outil. Pour remplacer la sortie de l’outil avant que Claude ne la voie, définissezupdatedToolOutput, qui fonctionne pour n’importe quel outil dans les deux SDK. Le champ plus ancienupdatedMCPToolOutputremplace uniquement la sortie de l’outil MCP et est déprécié.
{} pour autoriser l’opération sans modifications. Les hooks de rappel du SDK utilisent le même format de sortie JSON que les hooks de commande shell Claude Code, qui documente chaque champ et option spécifique à l’événement. Pour les définitions de type du SDK, consultez les références du SDK TypeScript et Python.
Lorsque plusieurs hooks ou règles de permission s’appliquent, deny a priorité sur defer, qui a priorité sur ask, qui a priorité sur allow. Si un hook retourne
deny, l’opération est bloquée indépendamment des autres hooks.Sortie asynchrone
Par défaut, l’agent attend que votre hook retourne avant de continuer. Si votre hook effectue un effet secondaire (enregistrement, envoi d’un webhook) et n’a pas besoin d’influencer le comportement de l’agent, vous pouvez retourner une sortie asynchrone à la place. Cela indique à l’agent de continuer immédiatement sans attendre la fin du hook :| Champ | Type | Description |
|---|---|---|
async | true | Signale le mode asynchrone. L’agent continue sans attendre. En Python, utilisez async_ pour éviter le mot-clé réservé. |
asyncTimeout | number | Délai d’expiration optionnel en millisecondes pour l’opération de fond |
Les sorties asynchrones ne peuvent pas bloquer, modifier ou injecter du contexte dans l’opération puisque l’agent a déjà avancé. Utilisez-les uniquement pour les effets secondaires comme la journalisation, les métriques ou les notifications.
Exemples
Modifier l’entrée de l’outil
Cet exemple intercepte les appels d’outil Write et réécrit l’argumentfile_path pour ajouter /sandbox, redirigeant toutes les écritures de fichiers vers un répertoire en sandbox. Le rappel retourne updatedInput avec le chemin modifié et permissionDecision: 'allow' pour approuver automatiquement l’opération réécrite :
Lors de l’utilisation de
updatedInput, vous devez également inclure permissionDecision: 'allow' pour approuver automatiquement l’entrée modifiée ou permissionDecision: 'ask' pour la montrer à l’utilisateur. Avec 'defer', updatedInput est ignoré. Retournez toujours un nouvel objet plutôt que de muter le tool_input original.Ajouter du contexte et bloquer un outil
Cet exemple bloque les écritures dans le répertoire/etc et explique pourquoi au modèle et à l’utilisateur :
permissionDecision: 'deny'arrête l’appel d’outil.permissionDecisionReasonindique au modèle pourquoi, afin qu’il évite de réessayer.systemMessagemontre à l’utilisateur ce qui s’est passé.
Approuver automatiquement des outils spécifiques
Par défaut, l’agent peut demander une permission avant d’utiliser certains outils. Cet exemple approuve automatiquement les outils de système de fichiers en lecture seule (Read, Glob, Grep) en retournantpermissionDecision: 'allow', les laissant s’exécuter sans confirmation de l’utilisateur tout en laissant tous les autres outils soumis aux vérifications de permission normales :
Enregistrer plusieurs hooks
Quand un événement se déclenche, tous les hooks correspondants s’exécutent en parallèle. Pour les décisions de permission, le résultat le plus restrictif gagne : un seuldeny bloque l’appel d’outil indépendamment de ce que les autres hooks retournent. Parce que l’ordre d’exécution est non-déterministe, écrivez chaque hook pour agir indépendamment plutôt que de compter sur l’exécution préalable d’un autre hook.
L’exemple ci-dessous enregistre trois vérifications indépendantes pour chaque appel d’outil :
Filtrer avec des matchers multi-outils
Utilisez des matchers multi-outils pour partager un rappel entre outils connexes. Cet exemple enregistre trois matchers avec des portées différentes :- Une liste exacte séparée par des barres (
Write|Edit|Delete) déclenchefile_security_hookuniquement pour les outils de modification de fichiers. - Une regex (
^mcp__) déclenchemcp_audit_hookpour tout outil MCP dont le nom commence parmcp__. - Un matcher omis déclenche
global_loggerpour chaque appel d’outil indépendamment du nom.
Suivre l’activité des sous-agents
Utilisez les hooksSubagentStop pour surveiller quand les sous-agents terminent leur travail. Consultez le type d’entrée complet dans les références du SDK TypeScript et Python. Cet exemple enregistre un résumé chaque fois qu’un sous-agent se termine :
Effectuer des requêtes HTTP à partir des hooks
Les hooks peuvent effectuer des opérations asynchrones comme les requêtes HTTP. Capturez les erreurs à l’intérieur de votre hook au lieu de les laisser se propager, car une exception non gérée peut interrompre l’agent. Cet exemple envoie un webhook après chaque exécution d’outil, enregistrant quel outil a été exécuté et quand. Le hook capture les erreurs afin qu’un webhook échoué n’interrompe pas l’agent :Transférer les notifications à Slack
Utilisez les hooksNotification pour recevoir les notifications système de l’agent et les transférer vers des services externes. Les notifications se déclenchent pour des types d’événements tels que :
permission_promptquand Claude a besoin d’une permissionidle_promptquand Claude attend une entréeauth_successquand l’authentification se termineelicitation_dialog,elicitation_complete, etelicitation_responsepour les flux d’élicitation d’entrée utilisateur
message avec une description lisible par l’homme et optionnellement un title.
Cet exemple transfère chaque notification à un canal Slack. Il nécessite une URL de webhook entrant Slack, que vous créez en ajoutant une application à votre espace de travail Slack et en activant les webhooks entrants :
Corriger les problèmes courants
Hook ne se déclenche pas
- Vérifiez que le nom de l’événement hook est correct et sensible à la casse (
PreToolUse, paspreToolUse) - Vérifiez que votre motif matcher correspond exactement au nom de l’outil
- Assurez-vous que le hook se trouve sous le type d’événement correct dans
options.hooks - Pour les hooks non basés sur les outils comme
StopetSubagentStop, les matchers correspondent à des champs différents (consultez motifs matcher) - Les hooks peuvent ne pas se déclencher lorsque l’agent atteint la limite
max_turnscar la session se termine avant que les hooks puissent s’exécuter
Matcher ne filtre pas comme prévu
Les matchers ne correspondent qu’aux noms d’outils, pas aux chemins de fichiers ou à d’autres arguments. Pour filtrer par chemin de fichier, vérifieztool_input.file_path à l’intérieur de votre hook :
Délai d’expiration du hook
- Augmentez la valeur
timeoutdans la configurationHookMatcher - Utilisez le
AbortSignaldu troisième argument de rappel pour gérer l’annulation correctement en TypeScript
Outil bloqué de manière inattendue
- Vérifiez tous les hooks
PreToolUsepour les retourspermissionDecision: 'deny' - Ajoutez la journalisation à vos hooks pour voir quel
permissionDecisionReasonils retournent - Vérifiez que les motifs matcher ne sont pas trop larges (un matcher vide correspond à tous les outils)
Entrée modifiée non appliquée
-
Assurez-vous que
updatedInputse trouve à l’intérieur dehookSpecificOutput, pas au niveau supérieur : -
Retournez
permissionDecision: 'allow'pour approuver automatiquement l’entrée modifiée, ou'ask'pour la montrer à l’utilisateur pour approbation -
Incluez
hookEventNamedanshookSpecificOutputpour identifier le type de hook pour lequel la sortie est destinée
Hooks de session non disponibles en Python
SessionStart et SessionEnd peuvent être enregistrés en tant que hooks de rappel du SDK en TypeScript, mais ne sont pas disponibles dans le SDK Python (HookEvent les omet). En Python, ils ne sont disponibles que comme hooks de commande shell définis dans les fichiers de paramètres (par exemple, .claude/settings.json). Pour charger les hooks de commande shell à partir de votre application SDK, incluez la source de paramètre appropriée avec setting_sources ou settingSources :
client.receive_response() comme déclencheur.
Les invites de permission des sous-agents se multiplient
Lors du lancement de plusieurs sous-agents, chacun peut demander des permissions séparément. Les sous-agents n’héritent pas automatiquement des permissions de l’agent parent. Pour éviter les invites répétées, utilisez les hooksPreToolUse pour approuver automatiquement des outils spécifiques, ou configurez des règles de permission qui s’appliquent aux sessions de sous-agent.
Boucles de hook récursives avec des sous-agents
Un hookUserPromptSubmit qui lance des sous-agents peut créer des boucles infinies si ces sous-agents déclenchent le même hook. Pour éviter cela :
- Vérifiez un indicateur de sous-agent dans l’entrée du hook avant de lancer
- Utilisez une variable partagée ou un état de session pour suivre si vous êtes déjà à l’intérieur d’un sous-agent
- Limitez les hooks pour qu’ils s’exécutent uniquement pour la session d’agent de niveau supérieur
systemMessage n’apparaît pas dans la sortie
Le champsystemMessage affiche un message à l’utilisateur, pas au modèle. Par défaut, le SDK ne fait pas apparaître la sortie du hook dans le flux de messages, donc le message peut ne pas apparaître à moins que vous définissiez includeHookEvents (include_hook_events en Python). Pour transmettre du contexte au modèle à la place, retournez additionalContext.
Si vous avez besoin de faire apparaître les décisions de hook à votre application de manière fiable, enregistrez-les séparément ou utilisez un canal de sortie dédié.
Ressources connexes
- Référence des hooks Claude Code : schémas JSON d’entrée/sortie complets, documentation des événements et motifs matcher
- Guide des hooks Claude Code : exemples de hooks de commande shell et procédures pas à pas
- Référence du SDK TypeScript : types de hook, définitions d’entrée/sortie et options de configuration
- Référence du SDK Python : types de hook, définitions d’entrée/sortie et options de configuration
- Permissions : contrôlez ce que votre agent peut faire
- Outils personnalisés : créez des outils pour étendre les capacités de l’agent