Build
Guide · les réglages

Faire vérifier Claude par ton ordinateur, pas par ta vigilance.

Une règle écrite dans un fichier dépend de deux choses : qu'il la lise, puis qu'il choisisse de la suivre. Un hook ne dépend de rien. C'est ta machine qui refuse, avant que la commande parte.

Le format exact du fichier, trois hooks qui tournent en production, puis l'incident qui a coûté sept fiches membres avant que le troisième existe.
Tu débutes vraiment ? Commence iciL'app Claude ou Claude Code ? Ce n'est pas la même chose

Avant tout : la différence avec une règle

Une consigne dans CLAUDE.md est une demande. Elle est lue au démarrage, elle influence, elle se dilue à mesure que la conversation s'allonge. C'est très bien pour orienter un style.

Un hook est un programme que ta machine lance elle-même, à un moment précis, avant ou après une action. Il ne se dilue pas, il ne s'oublie pas, puis il peut refuser.

Une règle dans CLAUDE.mdUn hook
« Ne pousse jamais sur main sans me demander »La commande ne part pas
Dépend de l'attention du momentS'exécute toujours, à l'identique
Se règle en une phraseDemande dix lignes une fois
Le piège

Mettre en hook ce qui devrait être une règle. Un hook qui se déclenche sans arrêt devient un bruit qu'on apprend à ignorer, donc pire que rien. Réserve-les à ce qui coûte cher.

01

Où ça se règle, puis le squelette exact

Tout tient dans un fichier de réglages. Celui du projet ne vaut que pour ce dossier, celui du dessus vaut partout.

FichierPortée
.claude/settings.local.jsonce projet seulement, sans partir dans le dépôt
.claude/settings.jsonce projet, partagé avec ceux qui clonent
~/.claude/settings.jsontous tes projets
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "python "$CLAUDE_PROJECT_DIR/scripts/garde.py""
          }
        ]
      }
    ]
  }
}
Bon à savoir

matcher dit sur quel outil le hook se déclenche. Bash pour les commandes, Edit|Write pour les écritures de fichiers, la barre verticale sépare plusieurs outils. $CLAUDE_PROJECT_DIR pointe la racine du projet, donc le chemin marche sur n'importe quelle machine.

Le piège

Écrire un chemin absolu de ta machine. Le jour où tu changes d'ordinateur ou de dossier, le hook échoue en silence.

02

Le plus simple : un hook qui fait un geste à ta place

Commence par celui-là, il ne peut rien casser. À la fin de chaque session, il pousse ton travail sur ton dépôt. Tu n'y penses plus jamais.

{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "git push origin main > /dev/null 2>&1 || true"
          }
        ]
      }
    ]
  }
}
Où ça

Stop se déclenche quand Claude a fini de te répondre. Pas de matcher ici : il n'y a pas d'outil à filtrer.

Bon à savoir

Le || true à la fin est ce qui rend ce hook inoffensif. Sans lui, un dépôt sans connexion ou une branche protégée ferait remonter une erreur à chaque fin de réponse.

03

Le hook qui refuse : un programme qui rend 2

Un hook PreToolUse reçoit sur son entrée standard un JSON décrivant ce que Claude s'apprête à faire. S'il se termine par le code 2, l'action n'a pas lieu.

import json, sys

charge = json.load(sys.stdin)
commande = charge.get("tool_input", {}).get("command", "")

if "rm -rf" in commande:
    print("Refuse : suppression recursive.", file=sys.stderr)
    sys.exit(2)

sys.exit(0)
Code de sortieCe qui se passe
0l'action continue normalement
2l'action est bloquée, ton message part vers Claude
autreune erreur est signalée, l'action continue
Le piège

Écrire le message de refus sur la sortie normale au lieu de la sortie d'erreur. Sur stderr il remonte à Claude, qui comprend pourquoi et propose autre chose. Ailleurs il se perd.

04

Celui qui existe à cause d'un vrai dégât

Le 7 août, deux commandes de copie ont écrasé la base des membres d'un site en production par une version locale périmée. Sept fiches détruites, dont trois abonnés payants qui se sont retrouvés sans accès du jour au lendemain.

La consigne « le serveur est la source de vérité » existait déjà, écrite noir sur blanc dans le fichier de règles. Elle n'a pas suffi, parce qu'elle dépendait de l'attention au moment exact où la commande a été tapée.

import json, re, sys

VIVANT = ('members.json', 'trades.json', 'portfolios/')

charge = json.load(sys.stdin)
cmd = charge.get("tool_input", {}).get("command", "")

# une copie qui MONTE vers le serveur, pas qui en descend
monte = re.search(r"(scp|rsync)\s+[^:]+\s+\S+:", cmd)
if monte and any(f in cmd for f in VIVANT):
    print("Donnees vivantes : local vers serveur interdit.",
          file=sys.stderr)
    sys.exit(2)

sys.exit(0)
Bon à savoir

Le sens compte autant que le fichier. Descendre du serveur vers ta machine est une sauvegarde, donc c'est autorisé. Monter écrase du vivant par du périmé, donc c'est refusé. Un garde-fou qui bloque les deux sens finit par être désactivé.

Le piège

Se croire couvert par une consigne écrite. Une consigne protège tant que tu es attentif. Le jour où tu ne l'es pas est précisément celui où tu en avais besoin.

Premium

Le système qui empêche Claude de refaire la même erreur

  • Quoi faire quand le fichier de règles devient trop gros pour être lu
  • Le hook qui ressort la bonne leçon au moment du geste, pas au démarrage
  • 173 leçons réelles, tirées d'un an de production
Voir ce qu'il y a dedans →
05

Le piège qui te fera désactiver tes hooks

Deux jours après avoir écrit un hook qui ressort la bonne leçon quand on touche un fichier sensible, il s'est déclenché sur un brouillon posé dans un dossier temporaire, très loin du projet. Le fichier mentionnait un nom du projet, ça a suffi.

Un hook qui se trompe deux fois de suite est un hook qu'on désactive, puis qu'on oublie de réactiver. La règle qui évite ça tient en trois mots.

La règle

Le périmètre d'abord, la correspondance ensuite. Vérifie que le fichier appartient au projet AVANT de regarder ce qu'il contient. Dans l'autre sens, n'importe quel brouillon qui cite un nom du projet devient du code du projet.

import os

# 1. le perimetre
racine = os.environ.get("CLAUDE_PROJECT_DIR", "")
if not chemin.startswith(racine):
    sys.exit(0)

# 2. seulement maintenant, le contenu
Le piège

Tester son hook uniquement sur le cas qu'on veut attraper. Teste surtout sur trois cas qu'il ne doit PAS attraper : c'est là qu'un hook devient insupportable.

Si tu n'en gardes qu'une chose

Écris un hook quand l'erreur coûte cher, pas quand elle agace. Une consigne suffit pour orienter un style. Elle ne suffit pas pour protéger ce qui ne se répare pas. La différence entre les deux se mesure à ce que tu perds si personne ne fait attention ce jour-là.

Le guide suivantÉcrire ton premier skill, taillé pour ton travail

Un guide par semaine, tous ouverts.

Sans e-mail à donner. La formation complète ouvre bientôt à 39 € par mois ou 199 € l'année. Les inscrits ont l'accès en premier et gardent ce tarif.

Accès anticipé