TIPS 31 · JEV

Jev, l'IA qui décide, point

Comment donner à Claude Code un contrôle avant qu'une commande destructrice ne parte : une liste de commandes interdites, un hook gardien et le prompt pour que Claude le mette en place.

Ce que c'est et pourquoi ça compte

La vidéo parlait de Jev : une IA qui n'écrit pas de texte, mais répond avec un type précis, c'est-à-dire un choix, un score ou un vrai/faux, avec les probabilités et son degré de confiance. Ce qu'on fait de la réponse, c'est votre code qui le décide. Pour l'instant, il y a une liste d'attente. Ici, une seule idée m'intéresse : un contrôle qui se place entre l'IA et la commande, avant que la commande ne parte. Votre Claude Code peut l'avoir dès aujourd'hui, sans attendre sur aucune liste.

Le problème est simple. Claude Code lance des commandes dans le terminal de votre ordinateur. Presque toujours, elles sont inoffensives : installer un paquet, lancer les tests, lire un fichier. Mais certaines ne s'annulent pas. rm -rf supprime un dossier avec tout son contenu, sans passer par la corbeille. git push --force écrase l'historique du projet en ligne. git reset --hard jette les modifications que vous n'avez pas encore enregistrées dans un commit. Un drop table supprime une table de la base de données.

Pas besoin que Claude se trompe exprès. Il suffit d'une instruction mal comprise, d'un mauvais chemin, d'une longue session où il s'est embrouillé. Et si vous validez les confirmations à la va-vite, ou si vous les avez réduites pour aller plus vite, le moment où vous pouviez dire non passe sans que vous le remarquiez.

Il y a aussi une chose à savoir. Le rewind de Claude Code (Échap deux fois, ou /rewind) annule les modifications faites avec ses outils de fichiers, mais pas celles faites par des commandes dans le terminal. Si un rm supprime un fichier, le rewind ne vous le rendra pas.

Le frein doit donc être posé avant. Deux façons : une liste de commandes interdites, la plus simple, et un petit script qui lit chaque commande avant qu'elle ne parte, la plus maligne. Ensuite, il y a le prompt pour que Claude s'en charge.

1. La liste des commandes interdites

Claude Code lit les réglages du projet dans le fichier .claude/settings.json, dans le dossier du projet. Si vous voulez les mêmes règles dans tous vos projets, utilisez ~/.claude/settings.json dans votre dossier utilisateur. Écrivez-y ceci :

Le fichier
{
  "permissions": {
    "deny": [
      "Bash(rm -rf *)",
      "Bash(git push --force *)",
      "Bash(git reset --hard *)"
    ]
  }
}

Un « deny » l'emporte toujours sur n'importe quelle permission accordée. Claude Code regarde d'abord les règles deny, puis celles qui demandent une confirmation, puis celles qui autorisent. Donc même si un jour vous avez répondu « oui, ne plus demander » à une commande, le deny reste plus fort. Et il s'applique dans tous les modes de permission, même en bypassPermissions.

La limite : la règle bloque la commande écrite de cette façon, pas ses variantes. Bash(rm -rf *) arrête rm -rf build/, mais pas la même commande dans bash -c, ou écrite /bin/rm -rf build/. rm -fr, avec les lettres inversées, passe aussi. C'est un filet, pas un mur.

2. Le gardien : un hook qui contrôle chaque commande

Un hook est un script que Claude Code lance tout seul à un moment précis. Celui qu'il nous faut s'appelle PreToolUse : il s'exécute avant chaque appel à un outil, et avec le filtre « Bash » il ne regarde que les commandes du terminal. Il reçoit la commande en JSON. Si le script se termine avec le code 2, la commande ne part pas et Claude lit la raison que vous avez écrite. S'il se termine avec 0, la commande continue avec les permissions normales.

L'avantage par rapport à la liste : le script cherche les mots dangereux dans tout le texte de la commande. Il attrape donc aussi un rm -rf caché dans bash -c.

Créez le fichier .claude/hooks/gardien.sh dans le projet et collez-y ceci :

Le fichier
#!/bin/bash
command -v jq >/dev/null || { echo "jq est requis" >&2; exit 2; }
CMD=$(jq -r '.tool_input.command')
if echo "$CMD" | grep -Eiq 'rm -rf|git push --force|git reset --hard|drop table'; then
  echo "Bloqué : commande destructive. Demande-moi d'abord la permission." >&2
  exit 2
fi
exit 0

Rendez-le exécutable avec chmod +x .claude/hooks/gardien.sh. Le script utilise jq pour lire le JSON : si vous ne l'avez pas, sur Mac vous l'installez avec brew install jq. S'il manque, la première ligne du script bloque toutes les commandes au lieu de les laisser passer.

Ensuite, ajoutez dans .claude/settings.json, à côté de « permissions », cette partie :

Le fichier
"hooks": {
  "PreToolUse": [
    {
      "matcher": "Bash",
      "hooks": [{ "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/gardien.sh" }]
    }
  ]
}

$CLAUDE_PROJECT_DIR désigne le dossier du projet, et les guillemets autour gardent le chemin d'un seul tenant même s'il contient des espaces. Mises ensemble, les deux parties donnent un fichier comme celui-ci :

Le fichier
{
  "permissions": {
    "deny": [
      "Bash(rm -rf *)",
      "Bash(git push --force *)",
      "Bash(git reset --hard *)"
    ]
  },
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [{ "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/gardien.sh" }]
      }
    ]
  }
}

La liste dans le script, c'est vous qui la complétez : ajoutez les commandes qui font des dégâts dans votre projet, par exemple celle qui vide la base de données ou le script qui publie l'app.

3. Si vous n'avez pas envie de le faire à la main

Vous pouvez demander à Claude de tout faire : le script, le fichier de réglages et le test. Écrivez-lui :

Le prompt
Configure dans .claude/settings.json un hook PreToolUse qui bloque les commandes destructrices avant qu'elles ne partent (rm -rf, git push --force, git reset --hard, drop table) et ajoute les mêmes règles dans la liste deny des permissions. Ensuite, crée un dossier de test vide et vérifie que rm -rf sur ce dossier est bien bloqué.

Quand il a fini, lisez vous-même le fichier .claude/settings.json et le script. Ce ne sont que quelques lignes. Si quelque chose vous échappe, demandez-lui de l'expliquer :

Le prompt
Montre-moi le contenu de .claude/settings.json et du script du hook, et explique-moi ligne par ligne ce qu'il bloque et ce qu'il laisse passer.

4. Le test

Une règle que vous n'avez pas testée est une règle dont vous espérez qu'elle marche. Tapez /hooks dans Claude Code : la liste des hooks configurés s'ouvre, et le vôtre doit apparaître sous PreToolUse. D'habitude, Claude Code prend en compte tout de suite les modifications du fichier de réglages. Si votre hook n'apparaît pas, fermez et rouvrez Claude Code.

Attention à un détail : avec le deny actif, un rm -rf écrit normalement est déjà arrêté par la liste. Pour voir si le gardien fonctionne tout seul, demandez à Claude la même commande dans bash -c : la liste ne la voit pas, le gardien si.

Le prompt
Crée un dossier vide appelé test-gardien et essaie de le supprimer avec bash -c 'rm -rf test-gardien'. Ensuite, dis-moi ce qui t'a arrêté : la liste deny ou le hook.

Si la commande passe, le gardien ne fait pas son travail : en général, le script n'est pas exécutable ou le chemin dans settings.json est faux, et dans ces cas Claude Code ne reçoit pas le code 2 et laisse la commande continuer. Si au contraire tout est bloqué, même un simple ls, et que la raison est « jq est requis », c'est que jq manque.

5. Le filet en dessous : git

Le gardien réduit le risque, il ne le supprime pas. Une commande a beaucoup de variantes et vous ne les prévoirez pas toutes. C'est pour ça que le vrai filet en dessous, c'est git : faites un commit avant de confier à Claude un long travail, et gardez aussi une copie du projet en ligne, par exemple sur GitHub. Si quelque chose tourne mal, vous revenez au dernier commit.

Et le mode bypassPermissions, celui qui saute les demandes de confirmation, la documentation de Claude Code ne le conseille que dans des environnements isolés, comme un conteneur ou une machine virtuelle. Pas sur l'ordinateur où vous avez tout.

Les erreurs les plus courantes

  • Écraser le settings.json qui existait déjà : ajoutez les nouvelles parties à ce qui s'y trouve et vérifiez les virgules, car une seule virgule manquante suffit à casser le fichier.
  • Croire que le deny couvre toutes les variantes : il bloque la commande écrite de cette façon, alors associez-lui le gardien qui lit tout le texte de la commande.
  • Oublier chmod +x : le script ne se lance pas et le gardien ne bloque rien sans vous le dire, alors faites toujours le test sur un dossier vide.
  • Compter sur le rewind pour les fichiers supprimés : le rewind n'annule pas les commandes du terminal, alors faites un commit avant les longs travaux.

Check-list

  • Règles deny dans .claude/settings.json
  • Script gardien créé et rendu exécutable
  • jq installé
  • Hook visible dans /hooks sous PreToolUse
  • Test sur un dossier vide : commande bloquée
  • Commit fait avant les longs travaux

Questions fréquentes

Claude Code ne demande-t-il pas déjà la permission avant les commandes ?

En mode Manual, oui : il demande avant chaque commande qui n'est pas en lecture seule. Mais si vous répondez « oui, ne plus demander », ou si vous travaillez dans un mode qui demande moins, cette confirmation disparaît. Le deny et le gardien, eux, restent actifs dans ce cas aussi.

Qu'est-ce qui est mieux, la liste deny ou le hook ?

Les deux. Le deny, ce sont trois lignes, et il n'a besoin de rien d'autre. Le hook lit tout le texte de la commande et attrape les variantes les plus courantes. L'un couvre les trous de l'autre.

Le gardien peut-il aussi bloquer des commandes inoffensives ?

Oui : si une commande contient ces mots, par exemple une recherche de texte avec « rm -rf » dedans, elle est arrêtée. Ce n'est pas grave : Claude lit la raison et vous demande comment continuer. Si ça arrive souvent, rendez la liste plus précise.

Est-ce que ça vaut pour tous mes projets ?

Dans .claude/settings.json, ça vaut pour ce projet, et si le fichier est dans git, ça vaut aussi pour ceux qui y travaillent avec vous. Dans ~/.claude/settings.json, ça vaut pour tous vos projets : dans ce cas, mettez le script dans ~/.claude/hooks et écrivez ce chemin dans la commande du hook.

← Tous les guides