Hooks Claude Code : le système nerveux que personne ne documente
Avant de lire votre code, Claude Code cherche un fichier CLAUDE.md. Avant d’exécuter vos procédures, il charge vos Skills. Mais entre le moment où il décide d’écrire un fichier et le moment où le fichier est effectivement écrit, il se passe quelque chose que la documentation officielle expédie en une demi-page : les hooks. Ce guide va beaucoup plus loin.
Ce que vous allez apprendre, et pourquoi la doc passe à côté
Si vous avez lu mes deux précédents articles, CLAUDE.md : le fichier que Claude Code lit avant votre code et SKILL.md : le guide ultime pour créer vos Skills Claude, vous connaissez déjà les deux premières couches de l’architecture Claude Code. CLAUDE.md est la mémoire déclarative : qui vous êtes, comment vous travaillez, ce que vous attendez. SKILL.md est la mémoire procédurale : les recettes, les templates, les méthodes que Claude charge à la demande.
Les hooks sont la troisième couche. La couche que personne ne documente sérieusement.
Si CLAUDE.md est la mémoire et SKILL.md les procédures, les hooks sont le système nerveux, les réflexes conditionnels qui s’exécutent sans intervention humaine. Dans ma stack IA quotidienne, Claude Code est l’outil central. Les hooks sont ce qui le rend véritablement autonome. Un fichier .env est sur le point d’être lu ? Le hook bloque avant que la donnée ne remonte. Un fichier TypeScript vient d’être modifié ? Le hook lance le type-checker et renvoie les erreurs à Claude dans la foulée. Un sous-agent termine une tâche déléguée ? Le hook valide le résultat avant de rendre la main à l’instance principale. Personne n’a cliqué sur rien. Personne n’a tapé de commande. Le réflexe s’est déclenché tout seul.
La documentation officielle d’Anthropic consacre environ 400 mots aux hooks. Le cours « Claude Code in Action » de l’Anthropic Academy y passe 7 leçons, mais reste en surface, des exemples basiques, des structures JSON incomplètes, et un aveu désarmant : « the stdin input to your commands will differ significantly based upon the hook type, you might not know the exact structure of the input ». On vous dit que ça existe. On ne vous dit pas comment ça marche vraiment.

Cet article comble le vide. Vous y trouverez :
- La taxonomie complète des huit types de hooks (pas deux, huit) avec le déclencheur, le payload, les capacités et les limites de chacun.
- La cartographie des payloads stdin que personne n’a publiée, avec les structures JSON annotées pour chaque type.
- Cinq hooks de production annotés ligne par ligne, du simple garde-fou
.envau pattern multi-agent « Claude supervise Claude ». - Le piège de la récursivité infinie quand un hook déclenche le SDK qui re-déclenche le hook, et trois stratégies pour l’éviter.
- La stratégie de flotte pour déployer des hooks de gouvernance à l’échelle d’une entreprise.
- L’intégration GitHub Actions et le contraste fondamental entre permissions interactives et permissions déclaratives.
Bienvenue dans le dernier volet de la trilogie.
Ce que les hooks sont vraiment : anatomie du cycle de vie d’un tool call
Pour comprendre les hooks, il faut d’abord comprendre ce qui se passe quand vous demandez quelque chose à Claude Code. Pas dans les grandes lignes : dans le détail mécanique.
Le flux normal est linéaire : vous tapez un prompt, Claude Code l’envoie au modèle Claude avec les définitions d’outils disponibles, le modèle décide d’utiliser un outil (lire un fichier, écrire du code, exécuter une commande), Claude Code exécute cet outil, récupère le résultat, le renvoie au modèle, et le modèle formule sa réponse. Ce cycle peut se répéter plusieurs fois dans une même réponse (Claude lit un fichier, en modifie un autre, lance un test, lit le résultat, corrige) avant de vous rendre la main.
Les hooks s’insèrent dans ce flux. Ils ne le remplacent pas, ils l’interceptent, exactement comme les middleware interceptent les requêtes HTTP dans Express ou Laravel. Si vous avez déjà écrit un app.use() dans Express qui vérifie un token d’authentification avant de laisser la requête atteindre le contrôleur, vous comprenez déjà les hooks. C’est un pipeline d’interception, avec une asymétrie fondamentale : le middleware before peut court-circuiter la requête et renvoyer une erreur 403, le middleware after ne peut qu’observer la réponse et éventuellement la modifier. Transposez : PreToolUse peut court-circuiter le tool call, PostToolUse ne peut que réagir au résultat.
Voici le cycle de vie complet, avec les huit points d’interception :
Le point critique est la zone rouge entre le PreToolUse et l’écriture effective. C’est le dernier rempart. Avant cette zone, tout est réversible : un exit code 2 dans votre hook PreToolUse suffit à tout annuler, et le fichier n’est jamais touché. Après cette zone, c’est trop tard : le PostToolUse peut lancer un formatter, signaler une erreur, logger l’opération, mais il ne peut pas rembobiner. Le fichier est déjà modifié.
C’est cette asymétrie qui structure toute la logique de sécurité des hooks. Retenez-la : pour protéger, c’est toujours PreToolUse. Pour réagir, c’est PostToolUse.
La taxonomie complète : huit hooks, pas deux
La documentation officielle et la plupart des tutoriels ne parlent que de PreToolUse et PostToolUse. C’est comme expliquer HTTP en ne mentionnant que GET et POST. Il existe en réalité huit types de hooks, chacun avec son déclencheur, son payload, et ses capacités propres.
1. PreToolUse : Le gardien
- Quand : avant l’exécution de tout outil (Read, Write, Edit, Grep, Bash…).
- Peut bloquer : oui (exit code 2).
- Payload clé :
tool_name,tool_input. - Cas d’usage : protéger des fichiers sensibles, valider des paramètres, interdire certaines commandes Bash.
C’est le hook le plus utilisé et le plus puissant. Quand votre script retourne exit code 2, tout message envoyé sur stderr est transmis à Claude comme explication du blocage. Claude comprend alors pourquoi l’opération a été refusée et adapte son comportement.
2. PostToolUse : Le contrôleur qualité
- Quand : après l’exécution réussie d’un outil.
- Peut bloquer : non (l’outil s’est déjà exécuté).
- Payload clé :
tool_name,tool_input,tool_response. - Cas d’usage : lancer un formatter, exécuter des tests, vérifier les types, fournir du feedback à Claude.
Le PostToolUse est votre boucle de rétroaction automatique. Claude écrit du code, votre hook lance le linter, les erreurs remontent, Claude corrige, sans que vous ayez touché le clavier.
3. Notification : La sentinelle passive
- Quand : quand Claude Code envoie une notification, ou après 60 secondes d’inactivité (quand Claude a besoin d’une permission).
- Peut bloquer : non.
- Payload clé : informations de session.
- Cas d’usage : alerting externe (webhook Slack, notification système), monitoring de sessions longues.
C’est le hook le moins documenté et pourtant le plus utile pour l’observabilité. Quand Claude tourne depuis dix minutes sur une tâche complexe et finit par s’arrêter en attente de permission, c’est Notification qui vous permet de le savoir sans surveiller le terminal. Imaginez un webhook Slack qui vous envoie « Claude Code attend votre permission sur le projet X depuis 60 secondes ». Vous répondez depuis votre téléphone. L’interruption de workflow tombe à zéro.
Pour les équipes qui utilisent Claude Code en mode semi-autonome sur des tâches longues (refactoring, migration de code, génération de documentation), Notification est la clé d’une supervision asynchrone efficace.
4. Stop : Le témoin de fin de réponse
- Quand : quand Claude Code a fini de répondre.
- Peut bloquer : non.
- Payload clé :
stop_hook_active(booléen). - Cas d’usage : logging de session, déclenchement de post-traitements, métriques.
Le payload est minimal : c’est un signal, pas un transporteur de données. Utilisez-le comme déclencheur pour des opérations légères : écrire une ligne dans un fichier de log, incrémenter un compteur, envoyer un ping.
5. SubagentStop : Le superviseur de sous-agents
- Quand : quand un sous-agent (affiché comme « Task » dans l’interface) termine son exécution.
- Peut bloquer : non.
- Payload clé : informations du sous-agent.
- Cas d’usage : valider le résultat d’un sous-agent, agréger les résultats de tâches parallèles.
La différence avec Stop est subtile mais importante : Stop se déclenche quand l’instance principale finit de répondre, SubagentStop quand une tâche déléguée se termine. Si vous orchestrez des workflows complexes avec des sous-agents, c’est ce hook qui vous donne la visibilité sur chaque étape.
6. PreCompact : Le gardien de la mémoire
- Quand : avant une opération de compaction, qu’elle soit manuelle ou automatique.
- Peut bloquer : non.
- Payload clé : informations de session.
- Cas d’usage : sauvegarder le contexte avant compaction, injecter un résumé, alerter.
La compaction, c’est le moment où Claude Code résume la conversation pour libérer de la fenêtre de contexte. Des informations sont perdues. Si vous avez travaillé pendant deux heures avec Claude sur une architecture complexe, la compaction va condenser ces échanges en quelques paragraphes. Les nuances, les décisions intermédiaires, les raisons pour lesquelles vous avez rejeté telle approche, tout ça risque de disparaître.
PreCompact vous permet d’intervenir juste avant. Vous pouvez extraire les décisions clés du transcript (disponible via transcript_path dans le payload), les sauvegarder dans un fichier de notes, ou les injecter dans le CLAUDE.md du projet pour qu’elles survivent à la compaction. C’est une assurance mémoire.
Si vous avez lu mon article sur CLAUDE.md, vous savez que la fenêtre de contexte est une ressource rare. PreCompact est le hook qui vous donne un dernier mot avant que cette ressource ne soit compressée.
7. UserPromptSubmit : Le filtre d’entrée
- Quand : quand l’utilisateur soumet un prompt, avant que Claude ne le traite.
- Peut bloquer : non.
- Payload clé : le prompt utilisateur.
- Cas d’usage : transformer, enrichir ou filtrer les prompts, ajouter du contexte automatiquement.
C’est le hook le plus sous-estimé. Imaginez : chaque fois que vous tapez un prompt, un script enrichit automatiquement votre message avec le contexte du ticket Jira en cours, le nom de la branche Git, ou l’état du dernier build CI. Le prompt que Claude reçoit est plus riche que celui que vous avez tapé.
Concrètement, vous tapez « corrige le bug de validation ». Votre hook UserPromptSubmit détecte que vous êtes sur la branche fix/issue-342, récupère le titre du ticket correspondant dans Jira via l’API, et transmet à Claude un prompt enrichi : « Contexte : branche fix/issue-342, ticket JIRA-342 « Le formulaire de contact rejette les emails avec un + dans l’adresse ». Corrige le bug de validation. » Claude travaille avec un contexte complet sans que vous ayez eu à le fournir manuellement.
C’est aussi le hook idéal pour normaliser les prompts dans un contexte d’entreprise : ajouter automatiquement un rappel de conventions de code, un préfixe de langue (« Réponds toujours en français »), ou un contexte de sprint en cours.
8. SessionStart / SessionEnd : Les bornes de session
- Quand : au démarrage ou à la reprise d’une session / à la fin d’une session.
- Peut bloquer : non.
- Payload clé : informations de session.
- Cas d’usage : setup/teardown d’environnement, démarrage de serveurs, logging de durée, facturation.
Pour les freelances qui facturent au temps passé avec Claude Code : un hook SessionStart qui écrit l’heure de début dans un CSV, et un SessionEnd qui calcule la durée. Facturation automatique.
Tableau synthétique
| Type | Déclencheur | Peut bloquer | Payload distinctif | Cas d’usage principal |
|---|---|---|---|---|
| PreToolUse | Avant un outil | ✅ (exit 2) | tool_name, tool_input | Sécurité, validation |
| PostToolUse | Après un outil | ❌ | + tool_response | Qualité, feedback |
| Notification | Notification / idle 60s | ❌ | Session info | Alerting, monitoring |
| Stop | Fin de réponse | ❌ | stop_hook_active | Logging, métriques |
| SubagentStop | Fin de sous-agent | ❌ | Sous-agent info | Orchestration |
| PreCompact | Avant compaction | ❌ | Session info | Sauvegarde de contexte |
| UserPromptSubmit | Soumission de prompt | ❌ | Prompt utilisateur | Enrichissement |
| SessionStart/End | Début/fin de session | ❌ | Session info | Setup/teardown |
Le payload stdin : la structure que personne ne documente
Le cours Anthropic Academy l’admet sans détour : la structure des données envoyées à vos hooks varie selon le type, et vous ne saurez pas forcément à quoi vous attendre. C’est un problème. Résolvons-le.
Le socle commun

Tous les hooks reçoivent leur payload via stdin au format JSON. Trois champs sont toujours présents :
{
"session_id": "2d6a1e4d-6f3a-4b2c-9e1d-8a7b6c5d4e3f",
"transcript_path": "/Users/paul/.claude/sessions/2d6a1e4d.transcript",
"hook_event_name": "PreToolUse"
}
Langage du code : JSON / JSON avec commentaires (json)
Le session_id identifie la session en cours. Le transcript_path pointe vers le fichier de transcription complet. Le hook_event_name vous dit quel type de hook s’est déclenché, indispensable si vous utilisez un seul script pour plusieurs types.
Les champs spécifiques par type
PreToolUse ajoute l’intention de Claude :
{
"session_id": "...",
"transcript_path": "...",
"hook_event_name": "PreToolUse",
"tool_name": "Read",
"tool_input": {
"file_path": "/code/project/.env"
}
}
Langage du code : JSON / JSON avec commentaires (json)
PostToolUse ajoute le résultat de l’outil :
{
"session_id": "...",
"transcript_path": "...",
"hook_event_name": "PostToolUse",
"tool_name": "TodoWrite",
"tool_input": {
"todos": [{ "content": "write a readme", "status": "pending" }]
},
"tool_response": {
"oldTodos": [],
"newTodos": [{ "content": "write a readme", "status": "pending" }]
}
}
Langage du code : JSON / JSON avec commentaires (json)
Stop est minimal :
{
"session_id": "af9f50b6-f042-4773-b3e2-c3a4814765ce",
"transcript_path": "...",
"hook_event_name": "Stop",
"stop_hook_active": false
}
Langage du code : JSON / JSON avec commentaires (json)
L’asymétrie critique : PreToolUse vs PostToolUse
Le payload de PreToolUse est léger : il contient l’intention : quel outil, quels paramètres. Quelques centaines d’octets tout au plus.
Le payload de PostToolUse est potentiellement massif : tool_response contient le résultat complet de l’outil. Un Read sur un fichier de 5 000 lignes, un Grep avec des centaines de résultats, un Bash(ls -R) sur un gros projet, tout ça atterrit intégralement dans le stdin de votre hook.
Les conséquences pratiques sont immédiates :
Ne loggez jamais tool_response systématiquement. Un hook de débogage avec jq . >> debug.log sur un matcher "*" peut générer des dizaines de mégaoctets en quelques minutes de session. Logger tool_name + tool_input suffit dans 95 % des cas.
Parsez avec des limites. Si votre hook analyse tool_response, tronquez au-delà d’un seuil raisonnable (10 000 caractères par exemple). Les hooks sont synchrones : ils bloquent le flux tant qu’ils s’exécutent. Un script qui parse 2 Mo de JSON à chaque écriture de fichier, c’est une session Claude Code qui rame.
L’astuce du logger intelligent
Pour le débogage, créez un hook catch-all qui exclut tool_response du dump :
// hooks/debug-logger.js
async function main() {
const chunks = [];
for await (const chunk of process.stdin) {
chunks.push(chunk);
}
const toolArgs = JSON.parse(Buffer.concat(chunks).toString());
// Exclure tool_response pour éviter la saturation
const { tool_response, ...light } = toolArgs;
const fs = require('fs');
fs.appendFileSync(
'hook-debug.log',
JSON.stringify(light, null, 2) + '\n---\n'
);
}
main().catch(() => process.exit(0));
Langage du code : JavaScript (javascript)
Activez-le temporairement avec un matcher "*", inspectez vos payloads, puis retirez-le. Ne le laissez jamais en production.
Configuration : les trois fichiers, la hiérarchie, et la stratégie de flotte
Les trois niveaux
Les hooks se déclarent dans des fichiers JSON, à trois niveaux de portée :
- Global,
~/.claude/settings.json: s’applique à tous vos projets, sur toute la machine. C’est l’endroit pour les garde-fous universels, par exemple, bloquer l’accès aux clés SSH quel que soit le projet. - Projet (partagé),
.claude/settings.json: commité dans le repo, partagé avec l’équipe. C’est l’endroit pour les conventions de projet, le linter à exécuter après chaque édition, les répertoires protégés spécifiques au projet. - Projet (local),
.claude/settings.local.json: non commité, dans le.gitignore. C’est l’endroit pour vos préférences personnelles, un logger de débogage, un hook de notification vers votre Slack personnel, des chemins spécifiques à votre machine.
Point crucial : les hooks des trois niveaux se cumulent. Ils ne s’écrasent pas. Un hook déclaré au niveau global ET un hook déclaré au niveau projet s’exécutent tous les deux quand le même outil est appelé. C’est une décision d’architecture délibérée qui a des conséquences majeures, nous y reviendrons dans la section « flotte d’agents ».

La commande /hooks dans Claude Code offre une interface interactive pour créer vos hooks sans éditer le JSON à la main. C’est pratique pour débuter, mais pour des configurations avancées, l’édition directe reste incontournable.
Structure JSON d’une configuration complète
{
"hooks": {
"PreToolUse": [
{
"matcher": "Read|Grep",
"hooks": [
{
"type": "command",
"command": "node /home/paul/projects/monapp/hooks/env-guard.js"
}
]
}
],
"PostToolUse": [
{
"matcher": "Write|Edit|MultiEdit",
"hooks": [
{
"type": "command",
"command": "node /home/paul/projects/monapp/hooks/format-check.js"
}
]
}
]
}
}
Langage du code : JSON / JSON avec commentaires (json)
Le matcher utilise une syntaxe regex où le pipe | sert d’opérateur OR. Quelques patterns courants : "Read" (un seul outil), "Read|Grep" (lecture et recherche), "Write|Edit|MultiEdit" (toutes les écritures), "*" (catch-all, tous les outils).
Le piège des chemins absolus
La documentation recommande d’utiliser des chemins absolus dans les commandes, et elle a raison. Les chemins relatifs exposent vos hooks au path traversal et au binary planting : un fichier malveillant dans le répertoire courant pourrait se substituer à votre script.
Mais les chemins absolus créent un autre problème : votre .claude/settings.json, commité dans le repo, contient /home/paul/projects/monapp/hooks/env-guard.js. Votre collègue clone le repo sur /Users/sophie/dev/monapp/. Le chemin ne correspond plus. Le hook ne se déclenche pas. Aucune erreur visible.
Le cours Anthropic Academy propose une solution élégante : un fichier settings.example.json avec un placeholder $PWD, et un script d’initialisation qui effectue le remplacement :
// scripts/init-claude.js
const fs = require('fs');
const path = require('path');
const projectRoot = process.cwd();
const template = fs.readFileSync('.claude/settings.example.json', 'utf8');
const resolved = template.replaceAll('$PWD', projectRoot);
fs.writeFileSync('.claude/settings.local.json', resolved);
Langage du code : JavaScript (javascript)
Ajoutez node scripts/init-claude.js à votre npm run setup et chaque développeur obtient des chemins absolus corrects au premier clone. C’est le pattern .env.example / .env appliqué aux hooks Claude Code.
La dimension « flotte d’agents » : les hooks comme outil de gouvernance
Prenons du recul. Vous êtes CTO. Quarante développeurs utilisent Claude Code au quotidien. Comment garantir que :
- aucun agent ne touche aux fichiers
.env,credentials.*, ou aux clés API ; - chaque modification passe par le linter maison ;
- les accès aux répertoires sensibles (
/infra/,/deploy/) sont loggés.
La réponse est dans la hiérarchie des fichiers de configuration.
Niveau projet : commitez un .claude/settings.json dans chaque repo avec les hooks de compliance. Chaque développeur qui clone le projet hérite automatiquement des garde-fous. C’est du policy-as-code appliqué aux agents IA.
Niveau global : poussez un ~/.claude/settings.json via votre outil de gestion de configuration : Ansible, Chef, Puppet, ou un MDM pour macOS. Ce hook global s’applique à tous les projets, sur tous les postes. Et puisque les hooks se cumulent sans s’écraser, un développeur ne peut pas contourner le hook global en ajoutant une exception dans son settings.local.json.
C’est l’équivalent des pre-commit hooks Git poussés via .pre-commit-config.yaml, mais appliqué à l’agent IA lui-même plutôt qu’au développeur humain. L’agent devient auditable, encadré, gouverné, sans sacrifier sa productivité. Le développeur garde toute sa liberté de prompt, tout son accès aux outils, mais dans un cadre défini par l’organisation.
C’est probablement la réponse la plus concrète à la question que se pose chaque DSI : « comment déployer Claude Code à l’échelle sans perdre le contrôle ? ». Et la réponse tient en trois niveaux de fichiers JSON et quelques scripts Node.js de 20 lignes.
Un dernier point pour les architectes : pensez à documenter vos hooks de gouvernance dans le CLAUDE.md global. Claude Code lit CLAUDE.md avant chaque session. Si vous y mentionnez « Ce projet utilise des hooks PreToolUse qui bloquent l’accès aux fichiers sensibles. Ne tente pas de contourner cette protection. », Claude intègre cette information dans son comportement. Les hooks bloquent mécaniquement. CLAUDE.md aligne l’intention. Les deux se renforcent mutuellement.
Cinq hooks de production : du formatter au multi-agent
La théorie est posée. Passons au code.
Hook 1 : Protection des fichiers sensibles (PreToolUse)
Le classique. Empêcher Claude de lire vos fichiers .env, vos clés privées, vos credentials.
// hooks/env-guard.js
// PreToolUse - Matcher: "Read|Grep"
async function main() {
const chunks = [];
for await (const chunk of process.stdin) {
chunks.push(chunk);
}
const toolArgs = JSON.parse(Buffer.concat(chunks).toString());
// Extraire le chemin visé (Read utilise file_path, Grep utilise path)
const targetPath = toolArgs.tool_input?.file_path
|| toolArgs.tool_input?.path
|| "";
// Liste des patterns interdits
const forbidden = ['.env', '.pem', '.key', 'credentials', '/secrets/'];
const match = forbidden.find(p => targetPath.includes(p));
if (match) {
// stderr est transmis à Claude comme explication
console.error(`⛔ Accès bloqué : le fichier "${targetPath}" contient le pattern interdit "${match}".`);
process.exit(2); // Exit 2 = bloquer l'opération
}
// Exit 0 = laisser passer
process.exit(0);
}
main().catch(() => process.exit(0));
Langage du code : JavaScript (javascript)
La configuration correspondante dans .claude/settings.local.json :
{
"hooks": {
"PreToolUse": [
{
"matcher": "Read|Grep",
"hooks": [{
"type": "command",
"command": "node /chemin/absolu/hooks/env-guard.js"
}]
}
]
}
}
Langage du code : JSON / JSON avec commentaires (json)
Quand Claude tente de lire .env, il reçoit le message d’erreur et comprend que l’opération a été refusée par un hook. Il adapte son comportement et ne réessaie pas.
Hook 2 : Auto-formatter après édition (PostToolUse)
Chaque fois que Claude modifie un fichier, Prettier le reformate automatiquement.
// hooks/auto-format.js
// PostToolUse - Matcher: "Write|Edit|MultiEdit"
const { execSync } = require('child_process');
async function main() {
const chunks = [];
for await (const chunk of process.stdin) {
chunks.push(chunk);
}
const toolArgs = JSON.parse(Buffer.concat(chunks).toString());
// Extraire le chemin du fichier modifié
const filePath = toolArgs.tool_input?.file_path
|| toolArgs.tool_input?.path
|| "";
if (!filePath) {
process.exit(0);
}
// Ne formater que les fichiers supportés
const supported = ['.js', '.ts', '.jsx', '.tsx', '.css', '.json', '.md'];
const ext = filePath.substring(filePath.lastIndexOf('.'));
if (!supported.includes(ext)) {
process.exit(0);
}
try {
execSync(`npx prettier --write "${filePath}"`, {
timeout: 10000, // 10 secondes max, les hooks sont synchrones
stdio: 'pipe'
});
} catch (err) {
// En cas d'échec, on ne bloque pas, on signale
console.error(`⚠️ Prettier a échoué sur ${filePath}: ${err.message}`);
}
process.exit(0);
}
main().catch(() => process.exit(0));
Langage du code : JavaScript (javascript)
Adaptable à n’importe quel outil : ESLint avec --fix, PHP-CS-Fixer, Black pour Python, gofmt pour Go. Le pattern est toujours le même : extraire le chemin, vérifier l’extension, lancer le formatter avec un timeout.
Hook 3 : Type-checker continu (PostToolUse)
C’est le hook qui transforme Claude Code en développeur discipliné. Après chaque modification de fichier TypeScript, le compilateur vérifie les types et renvoie les erreurs à Claude.
// hooks/type-check.js
// PostToolUse - Matcher: "Write|Edit|MultiEdit"
const { execSync } = require('child_process');
async function main() {
const chunks = [];
for await (const chunk of process.stdin) {
chunks.push(chunk);
}
const toolArgs = JSON.parse(Buffer.concat(chunks).toString());
const filePath = toolArgs.tool_input?.file_path || "";
// Ne vérifier que les fichiers TypeScript
if (!filePath.endsWith('.ts') && !filePath.endsWith('.tsx')) {
process.exit(0);
}
try {
execSync('npx tsc --noEmit', {
timeout: 30000,
stdio: 'pipe'
});
} catch (err) {
// tsc retourne un code non-zéro quand il y a des erreurs
// stdout contient les erreurs de type
const errors = err.stdout?.toString() || err.message;
// Feedback renvoyé à Claude via stdout
console.log(`TypeScript a détecté des erreurs après modification de ${filePath}:\n${errors}\nCorrigez ces erreurs dans les fichiers concernés.`);
}
process.exit(0);
}
main().catch(() => process.exit(0));
Langage du code : JavaScript (javascript)
Le cours Anthropic Academy identifie le problème exact que ce hook résout : quand Claude modifie la signature d’une fonction dans schema.ts, il oublie souvent de mettre à jour les appels dans main.ts. Le type-checker attrape l’erreur immédiatement et Claude corrige dans la foulée, sans que vous ayez levé le petit doigt.
Pour PHP, remplacez tsc --noEmit par php vendor/bin/phpstan analyse. Pour Python typé, mypy .. Le principe est universel.
Hook 4 : Détection de code dupliqué via multi-agent (PostToolUse + SDK)
C’est le pattern le plus avancé du cours. Un hook qui lance une seconde instance de Claude Code pour faire de la code review automatique. Si vous avez lu Société de pensées : quand les modèles d’IA débattent entre eux, vous connaissez le concept de multi-agent en théorie. Ici, on passe à la pratique.
Le scénario : vous avez un répertoire ./queries/ avec des dizaines de fonctions SQL. Vous demandez à Claude de « créer une intégration Slack qui alerte sur les commandes en attente depuis plus de 3 jours ». Claude, concentré sur la tâche Slack, écrit une nouvelle requête SQL au lieu de réutiliser la fonction getPendingOrders() qui existe déjà.
Le hook intercepte chaque modification dans ./queries/, lance une instance Claude Code en lecture seule via le SDK, lui demande de vérifier les duplications, et renvoie le verdict à l’instance principale.
// hooks/duplicate-check.js
// PostToolUse - Matcher: "Write|Edit|MultiEdit"
import { query } from "@anthropic-ai/claude-code";
async function main() {
const chunks = [];
for await (const chunk of process.stdin) {
chunks.push(chunk);
}
const toolArgs = JSON.parse(Buffer.concat(chunks).toString());
const filePath = toolArgs.tool_input?.file_path || "";
// Ne surveiller que le répertoire queries
if (!filePath.includes('/queries/')) {
process.exit(0);
}
// Variable sentinelle anti-récursivité
if (process.env.CLAUDE_HOOK_CONTEXT === 'review') {
process.exit(0);
}
// Lancer une seconde instance en lecture seule
process.env.CLAUDE_HOOK_CONTEXT = 'review';
const prompt = `Examine le fichier ${filePath} qui vient d'être modifié.
Compare-le avec les autres fichiers dans ./queries/.
Y a-t-il des fonctions dupliquées ou très similaires ?
Si oui, indique quelle fonction existante devrait être réutilisée.
Réponds uniquement par le résultat de ton analyse.`;
let result = '';
for await (const message of query({ prompt })) {
if (message.type === 'text') {
result += message.text;
}
}
if (result.toLowerCase().includes('dupliq') || result.toLowerCase().includes('similaire')) {
console.log(`⚠️ Duplication potentielle détectée dans ${filePath}:\n${result}`);
}
process.exit(0);
}
main().catch(() => process.exit(0));
Langage du code : JavaScript (javascript)
Point de vigilance : la portée de process.env. Dans ce code, process.env.CLAUDE_HOOK_CONTEXT = 'review' fonctionne parce que la fonction query() du SDK Node.js hérite automatiquement de l’environnement du processus parent : les variables définies avant l’appel sont transmises à l’instance SDK. Mais si vous portez ce pattern en Python ou en Bash (en lançant Claude Code via claude --print dans un sous-processus), la variable d’environnement doit être explicitement exportée avant l’appel : export CLAUDE_HOOK_CONTEXT=review en Bash, ou passée via le paramètre env de subprocess.run() en Python. Sans ça, le sous-processus ne voit pas la sentinelle, et votre protection anti-récursivité est silencieusement inopérante.
Les trade-offs sont réels : chaque vérification consomme des tokens API et ajoute de la latence. Une revue par le SDK peut prendre 10 à 30 secondes et coûter quelques centimes. Sur un projet où Claude modifie le répertoire queries/ dix fois dans une session, ça représente quelques minutes de latence cumulée et quelques dizaines de centimes. Réservez ce hook aux répertoires critiques, ceux où la duplication a un coût métier réel (fonctions SQL, règles métier, configurations d’infrastructure).
Pour les répertoires moins critiques, le type-checker (hook #3) offre un ratio coût/bénéfice bien meilleur : il est local, instantané, et gratuit.
Hook 5 : Logger de session pour facturation (SessionStart + SessionEnd)
// hooks/session-logger.js
// SessionStart ET SessionEnd - Matcher: "*"
const fs = require('fs');
const path = require('path');
async function main() {
const chunks = [];
for await (const chunk of process.stdin) {
chunks.push(chunk);
}
const toolArgs = JSON.parse(Buffer.concat(chunks).toString());
const logFile = path.join(process.env.HOME, '.claude/session-log.csv');
const now = new Date().toISOString();
if (toolArgs.hook_event_name === 'SessionStart') {
fs.appendFileSync(logFile, `${toolArgs.session_id},start,${now}\n`);
}
if (toolArgs.hook_event_name === 'Stop' || toolArgs.hook_event_name === 'SessionEnd') {
fs.appendFileSync(logFile, `${toolArgs.session_id},end,${now}\n`);
}
process.exit(0);
}
main().catch(() => process.exit(0));
Langage du code : JavaScript (javascript)
Un CSV avec session_id, événement, timestamp. Un script de post-traitement calcule les durées par session, agrège par jour ou par projet. Pour les freelances qui facturent au temps passé, c’est la base d’une facturation automatique et vérifiable : plus besoin de Toggl ou de minuteurs manuels, Claude Code se documente lui-même.
Pour les équipes, ce même mécanisme permet de mesurer l’adoption : combien de sessions par jour, quelle durée moyenne, quels projets consomment le plus de temps Claude Code. Des métriques concrètes, sans effort de saisie.
Le SDK TypeScript : quand un hook ne suffit plus
Le hook #4 ci-dessus utilise le SDK @anthropic-ai/claude-code. C’est la passerelle entre les hooks (réactifs) et l’automatisation programmatique (proactive).
L’essentiel en 60 secondes
Le SDK exécute le même Claude Code que votre terminal, mais depuis du code. Même modèle, mêmes outils, même accès au système de fichiers. La différence : pas d’interface interactive. Tout passe par des appels programmatiques.
Note : le package
@anthropic-ai/claude-codea été récemment renommé@anthropic-ai/claude-agent-sdk. Les imports changent, mais l’API reste identique. Le guide de migration est trivial : un search-and-replace sur les imports suffit.
import { query } from "@anthropic-ai/claude-code";
const prompt = "Analyse les fichiers dans ./src/queries pour trouver des duplications";
for await (const message of query({ prompt })) {
console.log(JSON.stringify(message, null, 2));
}
Langage du code : JavaScript (javascript)
La fonction query() retourne un itérateur asynchrone qui stream les messages de la conversation en temps réel. Chaque message est un objet typé : texte, appel d’outil, résultat d’outil. Le dernier message contient la réponse finale de Claude. Pour la plupart des cas d’usage dans les hooks, vous ne vous intéressez qu’à ce dernier message : le verdict de la review, l’analyse de duplication, le résultat du check.
Par défaut, le SDK fonctionne en lecture seule : Read, Grep, Glob, LS. Pas de Write, pas de Edit, pas de Bash. C’est un choix de conception délibéré, et un choix de sécurité excellent, surtout quand le SDK est déclenché par un hook (nous verrons pourquoi dans la section suivante).
Pour débloquer des outils supplémentaires, ajoutez allowedTools :
for await (const message of query({
prompt,
options: {
allowedTools: ["Edit", "Write"]
}
})) {
// ...
}
Langage du code : JavaScript (javascript)
Un point souvent négligé : le SDK hérite automatiquement des settings du répertoire courant. Votre instance SDK respecte les mêmes CLAUDE.md, Skills, hooks, et permissions que votre instance terminal. Cela signifie que si vous avez un hook PreToolUse qui bloque l’accès à .env, l’instance SDK déclenchée par un autre hook respectera aussi ce blocage. L’architecture est cohérente de bout en bout.
Les SDK Python et CLI existent aussi, mais le TypeScript reste le plus mature et le mieux documenté par Anthropic.
Le piège de la récursivité : la boucle infinie hooks ↔ SDK
Voici le scénario catastrophe que personne ne documente.
Vous avez un PostToolUse hook qui surveille les écritures dans ./queries/. Quand il détecte une modification, il lance une instance Claude Code via le SDK pour review. Cette seconde instance décide de corriger le fichier, ce qui déclenche le même PostToolUse hook, qui relance le SDK, qui re-modifie, qui re-déclenche…
Boucle infinie. Facturation API en roue libre. Et personne dans la documentation officielle ne vous prévient.
Trois stratégies de protection :
Stratégie 1 : Le mode read-only du SDK (recommandée). Par défaut, le SDK ne peut ni écrire ni éditer. Si votre instance de review ne fait que lire et analyser, elle ne déclenche aucun hook PostToolUse sur Write/Edit. C’est la solution la plus propre. Ne débloquez allowedTools: ["Edit"] que si vous savez exactement ce que vous faites.
Stratégie 2 : La variable d’environnement sentinelle. Définissez une variable avant de lancer l’instance SDK, et vérifiez-la au début de chaque hook :
// Au début de CHAQUE hook
if (process.env.CLAUDE_HOOK_CONTEXT === 'review') {
process.exit(0); // Instance de review → ne pas re-déclencher
}
// Avant de lancer le SDK
process.env.CLAUDE_HOOK_CONTEXT = 'review';
Langage du code : JavaScript (javascript)
C’est le même pattern que les développeurs backend utilisent pour éviter les boucles infinies dans les webhooks ou les triggers de base de données. Simple, efficace, mais fragile si quelqu’un oublie de positionner la variable.
Stratégie 3 : Le fichier verrou (lock file). Créez un .claude-hook-running au démarrage du hook, vérifiez son existence avant de s’exécuter, supprimez-le à la fin. Pattern classique de mutual exclusion, mais attention aux crashes qui laissent le verrou en place.
Recommandation : combinez le mode read-only (stratégie 1) avec la sentinelle (stratégie 2). La ceinture et les bretelles. Le hook #4 dans la section précédente applique exactement cette double protection.
GitHub Actions : les hooks dans le cloud
Jusqu’ici, tout se passe en local. Mais Claude Code peut aussi tourner dans GitHub Actions, et les règles du jeu changent fondamentalement.
Mise en place
La commande /install-github-app dans Claude Code lance un assistant qui vous guide pas à pas : installer l’application Claude Code sur votre compte GitHub, configurer votre clé API Anthropic comme secret du repository, et générer un pull request contenant deux fichiers de workflow GitHub Actions prêts à l’emploi. Une fois cette PR mergée, les workflows sont actifs.
C’est remarquablement simple à déployer, et c’est précisément pour ça qu’il faut comprendre ce qu’on déploie avant de merger.
Les deux workflows par défaut
Le bot de mention : mentionnez @claude dans n’importe quelle issue ou pull request. Claude analyse la demande, crée un plan d’action, exécute la tâche avec accès au codebase complet, et répond directement dans le fil de discussion GitHub. Vous pouvez lui demander de corriger un bug décrit dans une issue, d’implémenter une fonctionnalité, ou de faire une analyse de code. Claude crée sa propre branche, fait ses modifications, et soumet une PR, le tout depuis un commentaire GitHub.
La review automatique : à chaque pull request, Claude analyse les changements, évalue l’impact des modifications, identifie les problèmes potentiels, et poste un rapport détaillé directement sur la PR. C’est de la code review assistée par IA, intégrée nativement dans votre flux Git. Pas besoin d’attendre qu’un collègue soit disponible pour un premier passage : Claude fait le filtre initial en quelques minutes.
Personnalisation des workflows
Les workflows YAML acceptent trois paramètres de personnalisation essentiels :
custom_instructions pour injecter le contexte projet :
custom_instructions: |
Le projet est configuré avec toutes les dépendances installées.
Le serveur tourne déjà sur localhost:3000.
Les logs sont dans logs.txt.
Utilise sqlite3 pour les requêtes DB si nécessaire.
Langage du code : YAML (yaml)
mcp_config pour ajouter des serveurs MCP :
mcp_config: |
{
"mcpServers": {
"playwright": {
"command": "npx",
"args": ["@playwright/mcp@latest", "--allowed-origins", "localhost:3000"]
}
}
}
Langage du code : JavaScript (javascript)
allowed_tools pour la liste explicite des outils autorisés :
allowed_tools: "Bash(npm:*),Bash(sqlite3:*),Read,Grep,Glob,Write,Edit"
Langage du code : JavaScript (javascript)
Le contraste qui change tout : en local, quelqu’un dit « Yes », en CI, personne
En développement local, Claude Code fonctionne en mode interactif. Il demande la permission, vous dites « Yes », et le réflexe s’installe. On finit par approuver machinalement. C’est humain.
En GitHub Actions, il n’y a personne pour dire « Yes ». Chaque outil doit être pré-autorisé explicitement dans la configuration YAML, ou il sera refusé silencieusement. La liste allowed_tools est votre unique contrat de confiance avec l’agent.
Le pattern restrictif recommandé :
Pour la code review automatique (PR) : n’autorisez que les outils de lecture : Read, Grep, Glob, LS. Claude analyse, commente, mais ne touche à rien. La modification reste une décision humaine.
Pour le mention bot (issues) : étendez avec Write et Edit, mais listez explicitement chaque outil MCP (mcp__playwright__browser_snapshot, mcp__playwright__browser_click…). Pas de wildcard.
Jamais de Bash(*) en CI. Toujours préfixez : Bash(npm:*), Bash(sqlite3:*), Bash(python:*). Un Bash(*) en CI, c’est un shell root donné à un agent autonome dans un environnement sans supervision humaine. Relisez cette phrase. Lentement. Pensez aux secrets de votre repository, aux tokens d’accès, aux variables d’environnement de production qui transitent dans GitHub Actions. Un agent avec un Bash(*) non restreint pourrait (théoriquement) exfiltrer ces données dans un commit ou les afficher dans un log.
La complémentarité entre hooks locaux et permissions GitHub Actions est naturelle et puissante : les hooks locaux (PreToolUse) protègent le développeur pendant le développement quotidien. Les permissions GitHub Actions (allowed_tools) protègent le repository quand l’agent tourne sans supervision. Deux lignes de défense, deux contextes, un même objectif : garder le contrôle sur ce que l’agent peut faire.
Sécurité : ce que les hooks ne doivent jamais faire
Les hooks sont du code qui s’exécute automatiquement dans votre environnement de développement. Ils ont accès au système de fichiers, aux variables d’environnement, au réseau. Leur surface d’attaque mérite qu’on s’y attarde sérieusement.
Chemins absolus, toujours. La documentation insiste, et à raison. Un chemin relatif dans votre commande (node ./hooks/guard.js) résout depuis le répertoire de travail courant. Si un fichier malveillant nommé guard.js atterrit dans ce répertoire (via un clone, un téléchargement, un copier-coller malheureux), c’est lui qui s’exécute à la place de votre script. Le path traversal et le binary planting ne sont pas des menaces théoriques. Dans un contexte où Claude Code manipule des fichiers et exécute des commandes, un hook compromis est une porte ouverte sur votre machine.
Quotez systématiquement vos variables shell. "$VAR", jamais $VAR. Un chemin de fichier contenant des espaces ou des caractères spéciaux peut transformer une commande inoffensive en injection de commande. C’est du Security 101, mais dans le contexte des hooks (où le tool_input provient des décisions du modèle IA), c’est d’autant plus critique. Claude construit les chemins de fichiers à partir de son analyse du codebase. Un prompt malicieux pourrait l’amener à construire un chemin contenant des caractères d’échappement.
Bloquez le path traversal. Vérifiez la présence de .. dans les chemins extraits de tool_input. Vérifiez aussi que le chemin résolu (via path.resolve()) reste dans l’arborescence du projet. Claude est généralement bien intentionné, mais un prompt injection sophistiqué pourrait le pousser à construire un chemin qui sort du répertoire autorisé.
Ne loggez jamais de secrets. Un hook qui écrit tool_input brut dans un fichier de log expose potentiellement les arguments de commandes Bash contenant des tokens, des mots de passe, ou des clés API. Filtrez avant de logger. Mieux : ne loggez que tool_name et un hash du chemin, jamais le contenu.
Fichiers à exclure systématiquement dans vos hooks de protection : .env, .env.*, .env.local, .git/, *.key, *.pem, *.p12, *.pfx, credentials.*, *secret*, id_rsa, id_ed25519, *.keystore, token.json, service-account.json. Chaque projet a ses propres fichiers sensibles, adaptez cette liste, mais partez de cette base.
PreToolUse pour la sécurité, toujours. C’est le point le plus important de toute cette section. Si vous ne retenez qu’une phrase de cet article, que ce soit celle-ci. PostToolUse arrive après l’exécution de l’outil. Si Claude a lu votre .env, le contenu est déjà dans la fenêtre de contexte du modèle, votre hook PostToolUse ne peut pas l’en retirer. Si Claude a exécuté rm -rf, les fichiers sont déjà supprimés. La protection se joue avant, jamais après. PostToolUse est un outil de qualité. PreToolUse est un outil de sécurité. Ne les confondez pas.
Dépannage : les erreurs que vous allez rencontrer
Le hook ne se déclenche pas. Vérifiez trois choses dans l’ordre : le matcher correspond-il au nom exact de l’outil (c’est sensible à la casse : Read, pas read, pas READ) ? Le hook est-il dans le bon fichier de settings (global vs projet vs local) ? Avez-vous redémarré Claude Code après modification ? Les hooks sont chargés au démarrage de session, pas à chaud. Si vous modifiez un fichier de settings pendant une session active, les changements ne seront pris en compte qu’à la prochaine session. C’est le piège le plus fréquent.
Le hook se déclenche mais ne bloque pas. Vérifiez que votre script retourne bien exit code 2. Un process.exit(1) ne bloque pas, seul le code 2 est interprété comme un blocage explicite par Claude Code. Un process.exit(1) est traité comme une erreur du hook lui-même, pas comme une décision de blocage. Et vérifiez que c’est bien un hook PreToolUse : les PostToolUse, Stop, Notification, et tous les autres ne peuvent pas bloquer, quel que soit le code de sortie.
Erreur de parsing JSON. Le stdin peut être vide ou malformé si le hook se déclenche sur un événement inattendu. Wrappez toujours votre parsing dans un try/catch, et retournez exit code 0 en cas d’erreur, un hook qui crashe ne doit jamais bloquer Claude Code :
main().catch((err) => {
console.error(`Hook error: ${err.message}`);
process.exit(0); // Ne pas bloquer en cas de crash
});
Langage du code : JavaScript (javascript)
Cette ligne est la plus importante de tous vos scripts de hooks. Sans elle, un JSON malformé ou un champ manquant fait crasher votre hook avec exit code 1, ce qui perturbe le flux sans raison.
Le hook ralentit tout. Les hooks sont synchrones et bloquent le flux d’exécution. Un tsc --noEmit sur un gros projet TypeScript prend 15 secondes ? Chaque écriture de fichier prendra 15 secondes de plus. Multipliez par les dizaines d’écritures d’une session productive, et vous comprenez le problème. Solutions : ajoutez un timeout strict (execSync avec l’option timeout: 10000), ciblez vos matchers (ne vérifiez les types que sur les fichiers .ts, pas sur tout), ou déplacez les vérifications lourdes dans un hook Stop qui s’exécute une seule fois en fin de réponse plutôt qu’à chaque outil.
Permissions Node.js. Sur macOS et Linux, vérifiez que votre script est exécutable : chmod +x hooks/mon-hook.js. Sinon, utilisez explicitement node /chemin/absolu/hooks/mon-hook.js dans la commande plutôt que d’appeler le script directement. Sur certains environnements, le shebang #!/usr/bin/env node en première ligne du script est aussi nécessaire.
Le hook fonctionne en local mais pas en CI. En GitHub Actions, les hooks déclarés dans .claude/settings.local.json ne sont pas disponibles (ce fichier n’est pas commité). Seuls les hooks dans .claude/settings.json (niveau projet) sont actifs. Vérifiez aussi que les dépendances de vos scripts (Node.js, npm packages) sont installées dans l’environnement CI.
Le hook s’exécute mais vous ne voyez rien. C’est le piège le plus déroutant pour les débutants. Quand un hook retourne exit code 0 (succès), Claude Code n’affiche pas son stdout dans le terminal. Votre console.log("Hook exécuté !") est avalé silencieusement. Seul le stderr des hooks qui bloquent (exit 2) est visible, il est transmis à Claude comme explication. Si vous voulez observer le comportement d’un hook sans bloquer le flux, votre seule option est d’écrire dans un fichier de log externe, exactement comme le debug-logger.js présenté plus haut. Un fs.appendFileSync('hook.log', ...) et un tail -f hook.log dans un second terminal : c’est la méthode fiable pour déboguer un hook qui « ne fait rien ».
Checklist de validation
Avant le déploiement
- [ ] Le type de hook est le bon (PreToolUse pour bloquer, PostToolUse pour réagir)
- [ ] Le matcher cible les bons outils (vérifier la casse :
Write, paswrite) - [ ] Le chemin de la commande est absolu
- [ ] Le script parse le stdin de manière défensive (try/catch)
- [ ] Le script gère le cas où
tool_inputest absent ou incomplet - [ ] Un timeout est défini pour les commandes externes (
execSyncavectimeout)
Pendant le développement
- [ ] Le hook logger temporaire (
jq . > debug.log) a été installé pour vérifier les payloads - [ ] Les exit codes sont corrects : 0 pour laisser passer, 2 pour bloquer (PreToolUse uniquement)
- [ ] Les messages d’erreur (stderr) sont clairs, Claude les lit et adapte son comportement
- [ ] La variable sentinelle
CLAUDE_HOOK_CONTEXTest en place si le hook utilise le SDK
Après le déploiement
- [ ] Le hook a été testé avec des cas limites (fichiers avec espaces, chemins profonds, gros payloads)
- [ ] Les performances ont été vérifiées (le hook n’ajoute pas plus de 2-3 secondes par outil)
- [ ] Le hook est documenté dans le CLAUDE.md du projet (pour que Claude sache qu’il existe)
- [ ] Le hook logger temporaire a été retiré
- [ ] Les logs de production excluent
tool_response
Le mot de la fin
CLAUDE.md donne la mémoire. SKILL.md donne les procédures. Les hooks donnent les réflexes.
Ensemble, ces trois couches transforment Claude Code d’un assistant conversationnel en un agent de développement semi-autonome. Un agent qui sait qui vous êtes (CLAUDE.md), qui sait comment travailler (Skills), et qui réagit en temps réel à ses propres actions (hooks). Le tout sans interface graphique, sans configuration cloud, sans vendor lock-in, trois fichiers Markdown et JSON dans votre repo, et c’est tout. La dépossession des développeurs n’est pas une fatalité : c’est une question d’architecture.
Les hooks sont aussi le point d’entrée vers l’orchestration multi-agent. Quand un hook déclenche le SDK, qui lance un sous-agent en lecture seule pour vérifier le travail de l’agent principal, on ne parle plus d’assistance. On parle de supervision automatisée. Et quand cette architecture est déployée via GitHub Actions sur chaque pull request, avec des permissions minimales et des garde-fous explicites, on parle de gouvernance IA à l’échelle.
Ce qui me frappe, en ayant disséqué cette architecture pour écrire ces trois articles, c’est à quel point les primitives sont simples. Un fichier Markdown. Un dossier avec un script. Un JSON de configuration avec un matcher regex. Pas de framework propriétaire, pas de SDK obscur, pas d’API avec 47 endpoints. Des fichiers texte, du JSON, et du code qui lit stdin et retourne un exit code. C’est Unix dans l’âme.
Et c’est peut-être pour ça que si peu de gens en exploitent le potentiel. On attend un dashboard, un wizard, une interface de configuration. On ne s’attend pas à ce que la réponse soit un script de 20 lignes en Node.js qui parse du JSON et retourne process.exit(2).
La documentation officielle y consacre une demi-page. Vous venez de lire le reste !
Ressources
- Documentation officielle Anthropic, Hooks : Le point de départ, nécessaire mais insuffisant
- Cours « Claude Code in Action », Anthropic Academy : 7 leçons sur les hooks, le SDK, et GitHub Actions
@anthropic-ai/claude-agent-sdksur npm : Le package pour l’utilisation programmatique (ex@anthropic-ai/claude-code)anthropics/claude-code-actionsur GitHub : L’action GitHub Actions officielle- CLAUDE.md : le fichier que Claude Code lit avant votre code : Premier volet de la trilogie
- SKILL.md : le guide ultime pour créer vos Skills Claude : Deuxième volet de la trilogie
