IAMaîtriser l'IA générative Plan du corpus
Accueil/Exemples prets a l'emploi/settings.json et hooks : configuration commentee

settings.json et hooks : configuration commentee

Les reglages qui t'evitent de valider dix fois la meme chose, et le garde-fou qui t'evite la catastrophe.

Temps de lecture : 12 min | Niveau : Intermediaire

Ce que tu sauras faire apres

  • Savoir dans quel fichier de reglages mettre quoi, et lequel gagne en cas de conflit
  • Reduire les demandes de permission sans tout autoriser aveuglement
  • Installer un hook qui bloque une commande dangereuse avant son execution
  • Formater automatiquement ton code apres chaque modification

Partie 1 - Les fichiers de reglages

Ou ils se trouvent, et qui gagne

Du plus prioritaire au moins prioritaire :

RangFichierQui le decide
1Reglages geres par l'organisationTon entreprise
2claude --settingsToi, pour cette session
3.claude/settings.local.jsonToi, pour ce projet, non partage
4.claude/settings.jsonToute l'equipe du projet
5~/.claude/settings.jsonToi, pour tous tes projets

Une cle definie au rang 3 ecrase la meme cle au rang 5. Retiens la regle : plus on est proche du projet, plus on est prioritaire.

.claude/settings.local.json doit etre dans ton .gitignore. C'est la qu'on met ce qui est propre a ta machine. .claude/settings.json, lui, se versionne : c'est la configuration partagee de l'equipe.

Un settings.json utilisateur commente

Fichier : ~/.claude/settings.json (celui qui s'applique a tous tes projets)

{
  "model": "opus",

  "permissions": {
    "defaultMode": "default",

    "allow": [
      "Read",
      "Grep",
      "Glob",
      "Bash(git status *)",
      "Bash(git diff *)",
      "Bash(git log *)",
      "Bash(ls *)",
      "Bash(python -m pytest *)",
      "Bash(ruff check *)",
      "Bash(ruff format *)",
      "Bash(dbt compile *)",
      "Bash(dbt parse *)",
      "Bash(dbt test *)"
    ],

    "ask": [
      "Bash(git push *)",
      "Bash(pip install *)",
      "Bash(npm install *)"
    ],

    "deny": [
      "Bash(rm -rf *)",
      "Bash(dbt run --target prod *)",
      "Bash(dbt build --target prod *)",
      "Read(./.env)",
      "Read(./.env.*)",
      "Read(./**/credentials*.json)",
      "Read(./**/*.pem)"
    ]
  }
}

Ce que fait chaque bloc :

  • allow : execute sans rien te demander. Mets-y uniquement des commandes de lecture ou d'analyse, jamais une commande qui ecrit en production.
  • ask : demande confirmation a chaque fois, meme si tu es en mode permissif.
  • deny : refuse purement et simplement. C'est le filet de securite. deny gagne toujours sur allow.
  • Les regles de type Read(./.env) empechent Claude de lire tes secrets. Mets-les des maintenant.

Le caractere * fait office de joker : Bash(git diff *) autorise toutes les variantes de git diff, mais pas git push.

La bonne methode pour construire ton allow

Ne remplis pas cette liste a l'avance. Travaille une semaine normalement, note les commandes que tu autorises dix fois par jour, et ajoute celles-la uniquement.

Raccourci utile : quand Claude Code te demande une permission, la reponse du type « oui, et ne plus me demander » ecrit la regle toute seule dans .claude/settings.local.json.


Partie 2 - Les hooks

Le principe

Un hook est une commande de ta machine que Claude Code declenche automatiquement a un moment precis. Contrairement a une instruction du CLAUDE.md, un hook n'est pas une suggestion : c'est du code qui s'execute, toujours.

Les evenements les plus utiles :

EvenementQuand il se declencheUsage typique
PreToolUseAvant l'execution d'un outilBloquer une commande dangereuse
PostToolUseApres la reussite d'un outilFormater, linter, lancer les tests
UserPromptSubmitAvant le traitement de ton messageInjecter du contexte, bloquer un envoi
SessionStartAu demarrage d'une sessionRappeler l'etat du projet
StopQuand Claude a fini de repondreNotification sonore ou visuelle

Structure generale dans settings.json :

{
  "hooks": {
    "NomDeLEvenement": [
      {
        "matcher": "FiltreSurLOutil",
        "hooks": [
          { "type": "command", "command": "...", "timeout": 10 }
        ]
      }
    ]
  }
}

Le matcher filtre sur le nom de l'outil : "Bash", "Edit|Write", "mcp__memory__.*", ou "*" pour tout.

Le garde-fou anti-catastrophe

Le script. Fichier : .claude/hooks/garde-fou.py

#!/usr/bin/env python3
"""Bloque les commandes destructrices avant leur execution.

Claude Code envoie sur l'entree standard un JSON decrivant l'appel d'outil.
Code de sortie 2 = l'action est bloquee, et le message d'erreur remonte a Claude.
"""
import json
import re
import sys

INTERDITS = [
    (r"\brm\s+(-[a-z]*r[a-z]*f|-[a-z]*f[a-z]*r)\b", "suppression recursive forcee"),
    (r"--target[= ]\s*prod", "execution sur l'environnement de production"),
    (r"\bDROP\s+(TABLE|DATABASE|SCHEMA)\b", "suppression d'objet de base de donnees"),
    (r"\bTRUNCATE\s+TABLE\b", "vidage de table"),
    (r"\bgit\s+push\s+.*--force\b", "push force"),
    (r"\bgit\s+reset\s+--hard\b", "reinitialisation destructive"),
]

try:
    donnees = json.load(sys.stdin)
except json.JSONDecodeError:
    sys.exit(0)  # entree illisible : on ne bloque pas

commande = donnees.get("tool_input", {}).get("command", "")

for motif, raison in INTERDITS:
    if re.search(motif, commande, re.IGNORECASE):
        print(
            "Bloque par le garde-fou du projet : %s.\n"
            "Si c'est volontaire, execute cette commande toi-meme dans ton terminal." % raison,
            file=sys.stderr,
        )
        sys.exit(2)

sys.exit(0)

Le branchement. Dans .claude/settings.json :

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "python",
            "args": ["${CLAUDE_PROJECT_DIR}/.claude/hooks/garde-fou.py"],
            "timeout": 10,
            "statusMessage": "Verification de la commande..."
          }
        ]
      }
    ]
  }
}

Comment le tester : demande a Claude de lancer git reset --hard HEAD~1. La commande doit etre refusee avec ton message.

Le formatage automatique apres modification

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "ruff",
            "args": ["format", "."],
            "timeout": 60,
            "async": true
          }
        ]
      }
    ]
  }
}

async: true laisse le formatage tourner en arriere-plan sans bloquer la suite du travail.

Comment un hook bloque une action

Code de sortieEffet
0Tout va bien. Si le hook a produit du JSON, ce JSON decide
2Blocage. L'action n'a pas lieu, le message d'erreur remonte a Claude
autreNon bloquant, l'action continue

Deuxieme methode, plus fine : renvoyer du JSON sur la sortie standard.

{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "deny",
    "permissionDecisionReason": "Operation interdite sur l'environnement de production"
  }
}

Trois regles de prudence

  1. Un hook s'execute avec tes droits, sans confirmation. Relis toujours un hook trouve sur internet avant de l'installer.
  2. Mets un timeout court. Un hook lent ralentit chacune de tes actions.
  3. Commence par un hook qui ne fait qu'observer (afficher un message) avant d'en ecrire un qui bloque. Un hook trop zele est vite insupportable.

Template a remplir

{
  "permissions": {
    "allow": [
      "[COMMANDES_DE_LECTURE_QUE_TU_AUTORISES_SOUVENT]"
    ],
    "deny": [
      "Read(./.env)",
      "[COMMANDES_QUI_NE_DOIVENT_JAMAIS_PARTIR]"
    ]
  },
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "python",
            "args": ["${CLAUDE_PROJECT_DIR}/.claude/hooks/garde-fou.py"],
            "timeout": 10
          }
        ]
      }
    ]
  }
}

A retenir

  • Le reglage le plus proche du projet gagne ; deny gagne toujours sur allow.
  • Interdis la lecture des fichiers de secrets des aujourd'hui, en une ligne.
  • N'autorise automatiquement que des commandes de lecture.
  • Un hook n'est pas une consigne, c'est du code qui s'execute : relis-le avant de l'installer.
  • Code de sortie 2 = action bloquee.

Sources

Corpus personnel de formation · genere le 26/09/2026 · source : 04-hooks-et-settings.md