Le cours complet sur Claude, du premier message à l'automatisation : Projects, mémoire, connecteurs, skills, Cowork, puis Claude Code avec CLAUDE.md, agents, MCP, hooks, plugins et mods.
settings.json est le fichier de configuration de Claude Code. Il contrôle les permissions, le modèle, les variables d'environnement et les hooks : des commandes shell qui s'exécutent automatiquement à des moments précis de la session. La différence avec CLAUDE.md est simple : une instruction dans CLAUDE.md, Claude peut l'oublier ; un hook s'exécute à tous les coups.
~/.claude/settings.json ← personnel, tous les projets
.claude/settings.json ← projet, commité dans le dépôt
.claude/settings.local.json ← projet, personnel, ignoré par GitQuand deux fichiers se contredisent, le plus local gagne : settings.local.json l'emporte sur le fichier projet, qui l'emporte sur le fichier personnel. En entreprise, un fichier de règles gérées par l'administrateur passe au-dessus de tout.
Structure de base :
{
"model": "sonnet",
"permissions": {
"allow": [],
"deny": []
},
"env": {},
"hooks": {}
}Pas envie d'éditer du JSON ? /config ouvre les réglages courants dans une interface, et /permissions gère les règles d'autorisation. Le skill intégré /update-config modifie le fichier à partir d'une phrase : « autorise npm test sans confirmation ».
Les règles d'autorisation décident de ce que Claude fait sans demander, quel que soit le mode actif vu au module 6.
{
"permissions": {
"allow": [
"Bash(git status)",
"Bash(git diff *)",
"Bash(git log *)",
"Bash(npm run *)",
"Bash(npm test *)",
"mcp__github"
],
"deny": [
"Bash(git push --force *)",
"Bash(rm -rf *)",
"Read(./.env)",
"Read(./.env.*)"
]
}
}| Règle | Couvre |
|---|---|
Bash(npm run *) | Toute commande qui commence par npm run |
Read(./.env) | La lecture de ce fichier précis |
Edit(src/**) | Les modifications sous src/ |
mcp__github | Tous les outils du serveur MCP github |
mcp__github__create_issue | Un seul outil de ce serveur |
deny passe avant allow, et avant tous les modes, même bypassPermissions. Bloquer la lecture des fichiers .env est la première règle que j'ajoute sur un projet.
Une limite à garder en tête : une règle sur Bash se contourne. Interdire Bash(curl *) n'empêche pas un wget ou un script Python. Pour une vraie barrière, il faut un hook qui inspecte la commande, ou un conteneur.
{
"env": {
"NODE_ENV": "development",
"LOG_LEVEL": "debug"
}
}Ces variables sont injectées dans chaque session et chaque commande lancée par Claude. Les secrets vont dans settings.local.json, jamais dans le fichier commité.
Un hook associe un événement à une commande. Claude Code exécute la commande quand l'événement survient, et lui envoie sur l'entrée standard un objet JSON qui décrit la situation.
| Événement | Quand | Usage typique |
|---|---|---|
SessionStart | Au démarrage ou à la reprise d'une session | Injecter du contexte (branche, tickets) |
UserPromptSubmit | Quand vous envoyez un message | Ajouter du contexte, filtrer une demande |
PreToolUse | Avant l'exécution d'un outil | Bloquer une commande dangereuse |
PostToolUse | Après l'exécution d'un outil | Formater, linter, lancer les tests |
Notification | Quand Claude attend votre attention | Notification système |
Stop | Quand Claude a fini de répondre | Vérifier que le travail est terminé |
SubagentStop | Quand un sous-agent a fini | Contrôler son résultat |
PreCompact | Avant un compactage du contexte | Sauvegarder la conversation |
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/format.sh"
}
]
}
]
}
}matcher filtre sur le nom de l'outil, avec une expression régulière : Edit|Write réagit aux deux. $CLAUDE_PROJECT_DIR pointe vers la racine du projet, ce qui évite les chemins relatifs fragiles.
Pour un PreToolUse sur Bash, l'entrée standard ressemble à ceci :
{
"session_id": "abc123",
"cwd": "/home/william/mon-projet",
"hook_event_name": "PreToolUse",
"tool_name": "Bash",
"tool_input": {
"command": "git commit -m \"fix: typo\""
}
}Pour Edit ou Write, tool_input.file_path contient le fichier visé. Un PostToolUse reçoit en plus tool_response. On extrait les champs avec jq.
Le code de sortie décide de la suite :
| Code | Effet |
|---|---|
0 | Tout va bien. Pour UserPromptSubmit et SessionStart, la sortie standard est ajoutée au contexte de Claude |
2 | Blocage. L'action est annulée et le message écrit sur la sortie d'erreur est transmis à Claude, qui s'adapte |
| Autre | Erreur non bloquante, affichée à l'utilisateur, l'action continue |
Le piège classique : un hook de sécurité qui sort en 1. Il affiche une erreur, et l'action passe quand même. Pour bloquer, c'est 2.
#!/usr/bin/env bash
file=$(jq -r '.tool_input.file_path // empty')
[ -z "$file" ] && exit 0
case "$file" in
*.ts|*.tsx|*.js|*.jsx|*.css|*.json|*.md) npx prettier --write "$file" >/dev/null 2>&1 ;;
esac
exit 0Branché sur PostToolUse avec le matcher Edit|Write, il formate chaque fichier juste après que Claude l'a écrit. Plus jamais de diff pollué par des espaces.
#!/usr/bin/env bash
cmd=$(jq -r '.tool_input.command // empty')
if echo "$cmd" | grep -q 'git commit' && [ "$(git branch --show-current)" = "main" ]; then
echo "Commit direct sur main interdit : crée une branche d'abord." >&2
exit 2
fi
exit 0{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{ "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/no-commit-main.sh" }
]
}
]
}
}Claude reçoit le message, crée une branche et recommence. Pas besoin de le lui rappeler dans CLAUDE.md.
{
"hooks": {
"UserPromptSubmit": [
{
"hooks": [
{
"type": "command",
"command": "echo \"Branche : $(git branch --show-current 2>/dev/null). Fichiers non commités : $(git status --short 2>/dev/null | wc -l | tr -d ' ').\""
}
]
}
]
}
}La sortie s'ajoute au message : Claude connaît la branche et l'état du dépôt sans que vous le précisiez. Gardez ce genre de hook très court, il est relu à chaque message.
{
"hooks": {
"Notification": [
{
"hooks": [
{
"type": "command",
"command": "notify-send 'Claude Code' 'Claude attend ta réponse' 2>/dev/null || true"
}
]
}
]
}
}Sur macOS, remplacez la commande par osascript -e 'display notification "Claude attend" with title "Claude Code"'.
Un hook s'exécute avec vos droits, sans confirmation. Lisez ceux d'un dépôt cloné ou d'un plugin avant de les laisser tourner, comme n'importe quel script. /hooks liste tous les hooks actifs et leur origine.
Pour aller plus loin, le guide complet des hooks Claude Code couvre tous les événements et les sorties JSON avancées, et l'article sur les cas d'usage des hooks en propose une dizaine prêts à copier.
{
"permissions": {
"allow": [
"Bash(git status)",
"Bash(git diff *)",
"Bash(git log *)",
"Bash(git branch *)",
"Bash(ls *)"
],
"deny": [
"Bash(git push --force *)",
"Bash(rm -rf *)",
"Bash(* --no-verify *)",
"Read(./.env)",
"Read(./.env.*)"
]
},
"hooks": {
"Notification": [
{
"hooks": [
{ "type": "command", "command": "notify-send 'Claude Code' 'Claude attend ta réponse' 2>/dev/null || true" }
]
}
]
}
}{
"permissions": {
"allow": [
"Bash(npm run dev)",
"Bash(npm run build)",
"Bash(npm test *)"
]
},
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{ "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/format.sh" }
]
}
]
}
}Le fichier personnel pose les garde-fous qui valent partout. Le fichier projet ajoute ce qui dépend du dépôt, et toute l'équipe en profite.
Skills, agents, serveurs MCP, hooks : vous avez maintenant de quoi construire une configuration sur mesure. Le module suivant montre comment l'emballer dans un plugin pour la partager en une commande.