Skip to Content

Chapitre 14.3 — Snippets de hooks

⏱️ TL;DR — Les recettes de settings.json (niveau projet, .claude/settings.json) pour automatiser la qualité et poser des garde-fous. Voir Partie 7 pour le pourquoi. Vérifie la syntaxe courante (noms d’événements, matcher) dans la doc ou via update-config — la structure est stable, les détails peuvent bouger.

Chaîne complète (format + lint + tests + garde-fous) (→ 7.4)

{ "hooks": { "PostToolUse": [ { "matcher": "Edit|Write", "hooks": [ { "type": "command", "command": "npx prettier --write ." }, { "type": "command", "command": "npx eslint --fix ." } ] } ], "Stop": [ { "hooks": [ { "type": "command", "command": "npm run typecheck" }, { "type": "command", "command": "npm test" } ] } ], "PreToolUse": [ { "matcher": "Edit|Write", "hooks": [{ "type": "command", "command": "node .claude/hooks/protect-paths.mjs" }] }, { "matcher": "Bash", "hooks": [{ "type": "command", "command": "node .claude/hooks/git-guard.mjs" }] } ] }, "permissions": { "allow": ["Bash(npm test)", "Bash(npm run lint)", "Bash(npm run typecheck)", "Bash(git status)", "Bash(git diff)"], "deny": ["Bash(git push --force*)", "Bash(rm -rf*)"] } }

Garde-fou « fichiers protégés » (→ 7.3)

Esquisse de .claude/hooks/protect-paths.mjs (à adapter au format d’entrée exact, cf. doc) :

// Refuse l'édition de fichiers protégés, avec un message explicatif. import { readFileSync } from 'node:fs' const PROTECTED = [/^prisma\/migrations\//, /(^|\/)\.env/, /\.generated\./, /lock(file)?$/i] // Lire l'événement (chemin visé) depuis l'entrée standard — cf. doc pour le format. const input = JSON.parse(readFileSync(0, 'utf8')) const path = input?.tool_input?.file_path ?? '' if (PROTECTED.some((re) => re.test(path))) { console.error( `Édition refusée : ${path} est protégé. ` + `Migrations : génère-en une nouvelle. .env : utilise .env.example / variables d'env.` ) process.exit(2) // code d'échec = bloque l'action (cf. doc pour la convention exacte) }

Garde-fou « git » (main / force push) (→ 7.3)

Esquisse de .claude/hooks/git-guard.mjs :

import { readFileSync } from 'node:fs' import { execSync } from 'node:child_process' const input = JSON.parse(readFileSync(0, 'utf8')) const cmd = input?.tool_input?.command ?? '' const branch = execSync('git rev-parse --abbrev-ref HEAD').toString().trim() const onMain = branch === 'main' || branch === 'master' if (/--force|-f\b/.test(cmd) && /git\s+push/.test(cmd)) { console.error('push --force refusé. Travaille sur une branche, sans réécrire l’historique.') process.exit(2) } if (onMain && /git\s+(commit|push)/.test(cmd)) { console.error(`commit/push sur ${branch} refusé. Crée une branche de travail.`) process.exit(2) }

⚠️ Rappel — Un garde-fou doit expliquer en bloquant (message clair + quoi faire à la place), sinon l’agent réessaie en boucle (7.3). Le format exact des données reçues par un hook et la convention de code de sortie sont à vérifier dans la doc.

CI alignée (GitHub Actions) (→ 11.5)

.github/workflows/ci.yml — mêmes vérifications que les hooks :

name: CI on: [push, pull_request] jobs: check: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: { node-version: 20, cache: npm } - run: npm ci - run: npm run lint - run: npm run typecheck - run: npm test - run: npm run build

Recette suivante : Skills & commandes types.