Tu lances Claude Code, tu lui dis quoi faire, et tu attends. Cool.
Mais si tu pouvais lui dire comment faire ? Automatiser les tâches répétitives, valider chaque commande avant exécution, et déclencher des actions au bon moment ?
C'est exactement ce que permettent les scripts dans Claude Code. Et crois-moi, une fois que tu y goûtes, tu ne reviens plus en arrière.
C'est quoi un hook Claude Code ?
Un script Claude Code, c'est un fichier qui s'exécute automatiquement à un moment précis du workflow. Tu les places dans ton projet ou ta config globale, et Claude Code les déclenche tout seul.
Il y a deux grandes catégories :
- Les Hooks : des scripts déclenchés par des événements (avant une commande, après un outil, au démarrage...)
- Les scripts utilitaires : des fichiers que Claude Code peut appeler à la demande
On va voir les deux.
Les hooks Claude Code : le cœur de l'automatisation
Les hooks sont le mécanisme le plus puissant de Claude Code. Ils te permettent d'intercepter et de contrôler tout ce que fait l'agent.

Les principaux types de hooks
Claude Code propose 18 événements de hooks au total, mais voici les plus utilisés :
| Hook | Quand il se déclenche |
|---|---|
PreToolUse | Avant qu'un outil s'exécute (peut le bloquer) |
PostToolUse | Après qu'un outil s'exécute avec succès |
Notification | Quand Claude Code envoie une notification (permission, idle...) |
SessionStart | Au démarrage ou à la reprise d'une session |
UserPromptSubmit | Quand tu envoies un message |
Stop | Quand Claude termine de travailler |
Il existe aussi PostToolUseFailure, PermissionRequest, SubagentStart, SubagentStop, SessionEnd, PreCompact, ConfigChange, et d'autres pour des cas avancés.
Configuration dans settings.json
Tu configures tes hooks dans .claude/settings.json :
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "node ./scripts/validate-command.js"
}
]
}
]
}
}Le matcher filtre sur quel outil le hook s'active. Ici, uniquement sur les commandes Bash. Le matcher est une regex : Edit|Write matche les deux outils, mcp__.* matche tous les outils MCP.
Tu peux aussi utiliser la commande /hooks directement dans Claude Code pour ajouter, voir et supprimer tes hooks de façon interactive sans éditer le JSON à la main.
Comment activer le bypass permissions avec deny list
Avant de parler des hooks, parlons de la gestion des permissions. Par défaut, Claude Code te pose une question pour chaque action. C'est lent et pénible.
La solution : le mode bypass permissions avec une deny list dans ~/.claude/settings.json :
{
"permissions": {
"defaultMode": "bypassPermissions",
"deny": ["Bash(rm -rf *)", "Bash(sudo *)", "Bash(git push --force *)"]
}
}Avec ce setup :
- Claude Code ne te pose plus aucune question par défaut
- Mais les commandes dangereuses (
rm -rf,sudo,git push --force) sont automatiquement bloquées - Si tu tentes un
rm -rf, tu verras : "Error: permission denied"
C'est le meilleur des deux mondes : rapide ET sécurisé.
Combine ça avec une règle dans ton CLAUDE.md :
## Sécurité
- N'utilise jamais rm -rf, toujours utiliser `trash` pour supprimer des dossiersComme ça, même si la deny list ne catch pas tout, l'IA sait qu'elle doit utiliser trash au lieu de rm -rf.
Hook PreToolUse : bloquer les commandes dangereuses (rm -rf, drop database)
Le cas d'usage le plus classique. Tu veux empêcher Claude Code de lancer un rm -rf / ou un drop database.
Crée un fichier .claude/hooks/block-dangerous.js :
const input = await Bun.stdin.text();
const { tool_input } = JSON.parse(input);
const command = tool_input?.command || "";
const BLOCKED = [
/rm\s+.*-rf\s*\//i,
/drop\s+database/i,
/truncate\s+table/i,
/git\s+push.*--force\s+origin\s+main/i,
];
const isBlocked = BLOCKED.some((pattern) => pattern.test(command));
if (isBlocked) {
console.error(`BLOCKED: "${command}" is not allowed.`);
process.exit(2); // exit 2 = bloquer l'exécution
}
process.exit(0); // exit 0 = autoriserEt dans .claude/settings.json :
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "bun \"$CLAUDE_PROJECT_DIR\"/.claude/hooks/block-dangerous.js"
}
]
}
]
}
}Utilise $CLAUDE_PROJECT_DIR pour référencer tes scripts avec un chemin absolu, quel que soit le dossier courant.
Le code de sortie est la clé :
- Exit 0 : la commande passe
- Exit 2 : la commande est bloquée
Simple et efficace.
Hook PostToolUse : auto-format avec Prettier après chaque édition
Tu veux que ton code soit toujours formaté ? Ajoute un hook PostToolUse qui lance Prettier après chaque modification de fichier.
Les hooks reçoivent les données en JSON sur stdin (pas en variables d'environnement). Tu utilises jq pour extraire le chemin du fichier :
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.file_path' | xargs npx prettier --write 2>/dev/null || true"
}
]
}
]
}
}Chaque fois que Claude Code édite ou écrit un fichier, Prettier passe dessus automatiquement. Ton code est toujours clean.
Hook Notification : être alerté quand Claude Code attend ton input
Tu lances une tâche longue et tu veux être notifié quand Claude a besoin de toi ? Le hook Notification est fait pour ça. Il se déclenche quand Claude attend une permission, est idle, ou a besoin de ton attention :
{
"hooks": {
"Notification": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "osascript -e 'display notification \"Claude Code a besoin de toi\" with title \"Claude Code\"'"
}
]
}
]
}
}Sur Mac, ça t'envoie une notification native. Sur Linux, utilise notify-send 'Claude Code' 'Claude Code a besoin de toi' à la place.
Le matcher peut filtrer par type de notification : permission_prompt, idle_prompt, auth_success, elicitation_dialog. Laisse-le vide ou "*" pour capter toutes les notifications.
Tu peux aussi utiliser un hook Stop si tu veux être notifié spécifiquement quand Claude termine son travail (pas juste quand il attend) :
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "osascript -e 'display notification \"Claude Code a terminé !\" with title \"Claude Code\"'"
}
]
}
]
}
}Hook SessionStart : injecter du contexte au démarrage
Tu veux que Claude Code ait du contexte dès le démarrage ? Utilise SessionStart :
{
"hooks": {
"SessionStart": [
{
"hooks": [
{
"type": "command",
"command": "echo \"Branch: $(git branch --show-current), Last commit: $(git log --oneline -1)\""
}
]
}
]
}
}À chaque nouvelle session, Claude Code reçoit automatiquement le nom de la branche et le dernier commit. Le stdout d'un hook SessionStart est ajouté au contexte de Claude.
Tu peux aussi filtrer avec un matcher : startup (nouvelle session), resume (reprise), clear (après /clear), compact (après compaction du contexte). Par exemple, un matcher compact te permet de re-injecter du contexte important après que Claude a compacté la conversation.
Comment les hooks reçoivent les données
Les hooks reçoivent toutes les données en JSON sur stdin, pas via des variables d'environnement. Quand un hook PreToolUse se déclenche sur un Bash, tu reçois par exemple :
{
"session_id": "abc123",
"cwd": "/Users/toi/mon-projet",
"hook_event_name": "PreToolUse",
"permission_mode": "default",
"tool_name": "Bash",
"tool_input": {
"command": "npm test"
}
}Pour lire ces données dans un script bash, utilise jq :
#!/bin/bash
INPUT=$(cat)
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command')Il y a aussi quelques vraies variables d'environnement disponibles :
| Variable | Description |
|---|---|
CLAUDE_PROJECT_DIR | Le dossier racine du projet |
CLAUDE_ENV_FILE | Fichier pour persister des variables (uniquement dans SessionStart) |
CLAUDE_CODE_REMOTE | "true" en environnement web distant |
Utilise $CLAUDE_PROJECT_DIR pour référencer tes scripts avec des chemins absolus, peu importe le dossier courant.
Comment organiser tes scripts Claude Code
Voici la structure que je recommande (la convention officielle utilise .claude/hooks/) :
.claude/
├── settings.json # Config des hooks
├── hooks/
│ ├── block-dangerous.js # Validation de commandes
│ ├── auto-format.sh # Auto-formatage
│ └── notify.sh # Notifications
Quelques bonnes pratiques :
- Un script par responsabilité : ne mets pas tout dans un seul fichier
- Teste tes scripts manuellement avant de les brancher comme hooks
- Log les blocages pour comprendre ce qui se passe
- Commit tes scripts dans le repo pour que toute l'équipe en profite
Combiner les hooks avec CLAUDE.md
Les scripts sont encore plus puissants quand tu les combines avec ton CLAUDE.md. Le fichier CLAUDE.md dit à Claude Code quoi faire, les scripts contrôlent comment il le fait.
# CLAUDE.md
## Rules
- Never use rm -rf, use trash instead
- Always run tests after modifying code
- Format code with prettier before committingLe CLAUDE.md guide l'IA, les hooks l'empêchent de dévier.
Pour aller plus loin
Les scripts ne sont qu'une partie de l'écosystème Claude Code. Pour une vue complète :
- Formation Claude Code : le guide complet - Vue d'ensemble de toutes les features
- Claude Code Skills : crée tes propres workflows - Les skills et agents custom
- Claude Code Command : crée tes propres commandes - Les slash commands custom
- Claude Code MCP : connecte Claude à tes outils - Les serveurs MCP
- Claude Code Tips : 11 astuces pour coder 10x plus vite - Mes meilleurs tips
- Documentation officielle des hooks - La référence complète
Les scripts Claude Code c'est ce qui transforme un simple assistant en un vrai workflow automatisé. Commence par un hook simple, et tu verras vite à quel point c'est addictif.
Questions fréquentes sur les hooks Claude Code
Quelle est la différence entre exit 0 et exit 2 dans un hook ?
Exit 0 autorise l'exécution de l'outil. Exit 2 bloque l'exécution. Si ton script retourne exit 2, Claude Code ne lancera pas la commande et affichera le message que tu as écrit sur stderr (avec console.error en JS ou >&2 en bash). Tout autre code de sortie est une erreur non-bloquante : stderr est logué mais l'action continue.
Tu peux aussi retourner du JSON sur stdout (avec exit 0) pour un contrôle plus fin, par exemple permissionDecision: "deny" dans un PreToolUse. Voir la doc officielle des hooks pour tous les détails.
Les hooks fonctionnent-ils en mode bypass permissions ?
Oui. Les hooks s'exécutent toujours, même en bypass permissions. C'est justement pour ça qu'ils sont essentiels : ils agissent comme un filet de sécurité quand tu utilises --dangerously-skip-permissions.
Où mettre mes hooks : settings.json ou settings.local.json ?
Utilise settings.json pour les hooks que tu veux partager avec ton équipe (ils sont committés dans le repo). Utilise settings.local.json pour les hooks personnels (notifications, formatage local). Le fichier local n'est pas versionné.
Comment débugger un hook qui ne fonctionne pas ?
Teste ton script manuellement dans le terminal d'abord en lui passant du JSON sur stdin :
echo '{"tool_name":"Bash","tool_input":{"command":"ls"}}' | ./mon-hook.sh
echo $?Ensuite, vérifie que le matcher est correct (il doit correspondre au nom de l'outil : Bash, Edit, Write, etc. -- c'est case-sensitive). Lance Claude Code avec claude --debug pour voir les détails d'exécution des hooks, ou active le mode verbose avec Ctrl+O.

Agent Config Pro
Avec une ligne de commande, récupère ma configuration complète.
- Ma configuration (privé) pour Claude Code, Codex et Cursor
- Toutes mes commandes et skills
- Tous mes agents spécialisés
- Configuration des permissions
🔒 Safe et secure. Pas de spam. Unsubscribe en 1 click.
