
Après la série débutant, vos sessions sont cadrées mais chaque projet redemande les mêmes autorisations. Ce guide pose une configuration durable via settings.json : vous verrouillez les permissions sensibles, pré-autorisez les commandes répétitives et partagez un socle commun avec votre équipe. Tout est appliqué sur lab-claude et vérifié avec /status.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Les quatre fichiers de configuration et les cinq niveaux de priorité
- Comment Claude Code décide : type d'outil, ordre
denypuisaskpuisallow - Les six modes de permission, de
planàbypassPermissions - Poser chaque niveau concrètement, du fichier projet aux réglages administrés
- Écrire une règle juste du premier coup : outil, portée, liste, forme du motif
- Vérifier la configuration active avec
/permissionset/status
Prérequis
Section intitulée « Prérequis »Claude Code CLIinstallé et fonctionnel- Projet fil rouge prêt :
~/Projets/lab-claude - Conventions posées dans
CLAUDE.md(voir configurer CLAUDE.md) - À l'aise avec les modes d'exécution (voir mode plan, diff et validations)
Les quatre fichiers de configuration
Section intitulée « Les quatre fichiers de configuration »Claude Code lit la configuration depuis quatre emplacements, du plus spécifique au plus général :
| Scope | Fichier | Usage | Suivi git |
|---|---|---|---|
| Managed | managed-settings.json (système) | Politique d'entreprise imposée | N/A |
| Local | .claude/settings.local.json | Préférences personnelles du projet | Ignoré |
| Project | .claude/settings.json | Règles partagées de l'équipe | Suivi |
| User | ~/.claude/settings.json | Préférences globales utilisateur | N/A |
La documentation officielle donne cinq niveaux de priorité, parce que les arguments de ligne de commande s'intercalent entre le niveau administré et le fichier local :
- Managed, le plus fort : « can't be overridden by anything »
- Arguments de ligne de commande, le temps d'une session
- Local, qui l'emporte sur le projet et l'utilisateur
- Project
- User, qui s'applique quand rien d'autre ne définit le réglage
Les permissions font exception à cette hiérarchie. Elles ne s'écrasent pas, elles fusionnent : « Permission rules behave differently because they merge across scopes rather than override ». Une règle du fichier utilisateur coexiste donc avec celles du projet au lieu d'être remplacée. C'est ce qui explique qu'un fichier de permissions ne fasse que grossir avec le temps, sujet traité dans sécuriser son settings.json.
Comment Claude Code décide d'exécuter une commande
Section intitulée « Comment Claude Code décide d'exécuter une commande »Avant d'écrire la moindre règle, il faut comprendre ce qui se passe quand Claude veut lancer quelque chose. Beaucoup de configurations ratées viennent d'une mauvaise représentation de ce cycle, pas d'une erreur de syntaxe.
Première étape, le type d'outil. Tous ne sont pas soumis au même régime, et c'est la source de confusion la plus fréquente.
| Type d'outil | Exemple | Approbation demandée |
|---|---|---|
| Lecture seule | lire un fichier, Grep | Non, dans les répertoires de travail |
| Commande shell | Bash | Oui, sauf un jeu de commandes en lecture seule |
| Modification de fichier | Edit, Write | Oui |
Deuxième étape, l'évaluation des règles. Elle suit un ordre strict, et la documentation insiste sur un point contre-intuitif : « Rules are evaluated in order: deny, then ask, then allow. The first match in that order determines the outcome, and rule specificity doesn't change the order ».
Autrement dit, un deny large l'emporte toujours sur un allow précis. Une
règle Bash(aws *) en deny bloque Bash(aws s3 ls) même si cette dernière
figure explicitement en allow. Une liste deny ne peut donc pas porter
d'exceptions : il n'existe aucun moyen de dire « tout aws sauf aws s3 ls ».
Le même principe vaut entre ask et allow : une règle ask qui correspond
déclenche la question, même si un allow plus spécifique correspond aussi.
Troisième étape, le mode de permission, qui décide de ce qui se passe quand aucune règle ne correspond.
Les modes de permission
Section intitulée « Les modes de permission »Le defaultMode est le réglage qui change le plus le quotidien, et le guide
serait incomplet en le réduisant à une ligne de tableau. Six valeurs existent.
| Mode | Comportement |
|---|---|
default | Demande à chaque action non couverte par une règle. Affiché Manual dans l'interface depuis la version 2.1.200 |
acceptEdits | Accepte automatiquement les modifications de fichiers, continue de demander pour le reste |
plan | Claude lit et explore avec des commandes en lecture seule, sans modifier vos sources |
auto | Approuve automatiquement, avec des contrôles de sécurité en arrière-plan qui vérifient la cohérence avec votre demande |
dontAsk | Refuse automatiquement tout ce qui n'est pas pré-approuvé, au lieu de demander |
bypassPermissions | Passe outre les demandes, sauf les règles ask explicites |
Les deux derniers sont des extrêmes symétriques et méritent une lecture
attentive. dontAsk durcit : ce qui n'est pas prévu est refusé, sans
interruption. bypassPermissions ouvre, et la documentation l'assortit d'un
avertissement net.
La structure de base d'un settings.json
Section intitulée « La structure de base d'un settings.json »Commencez toujours avec $schema pour activer l'autocomplétion et la validation dans votre éditeur.
{ "$schema": "https://json.schemastore.org/claude-code-settings.json", "permissions": { "allow": [], "deny": [], "ask": [] }, "env": {}, "includeCoAuthoredBy": false, "cleanupPeriodDays": 30}Les clés les plus utiles au quotidien :
| Clé | Effet |
|---|---|
permissions.allow | Commandes pré-autorisées, pas de prompt |
permissions.deny | Commandes toujours refusées, non contournables |
permissions.ask | Commandes qui demandent confirmation à chaque fois |
env | Variables d'environnement injectées dans chaque session |
includeCoAuthoredBy | Active ou coupe l'attribution Co-Authored-By: Claude |
cleanupPeriodDays | Rétention des transcriptions de conversation |
defaultMode | Mode de permission par défaut (default, acceptEdits, plan) |
Mettre en place chaque niveau, concrètement
Section intitulée « Mettre en place chaque niveau, concrètement »Les quatre fichiers n'ont ni le même emplacement, ni le même mode de création, ni le même sort vis-à-vis de git. Voici comment poser chacun, dans l'ordre où on en a besoin.
-
Le niveau projet, partagé par l'équipe. C'est celui qu'on crée en premier, parce qu'il porte les règles qui valent pour tout le monde.
Fenêtre de terminal mkdir -p .claudecat > .claude/settings.json <<'EOF'{"$schema": "https://json.schemastore.org/claude-code-settings.json","permissions": {"allow": ["Bash(npm run lint:*)", "Bash(npm test:*)"],"ask": ["Bash(git push:*)"],"deny": ["Read(./.env)", "Bash(rm -rf:*)"]}}EOFgit add .claude/settings.jsonCe fichier se commite. Il est le contrat du dépôt, au même titre qu'un
.editorconfig. -
Le niveau local, personnel au dépôt. Il sert à ce qui dépend de votre machine et n'a rien à faire dans le dépôt partagé.
Fenêtre de terminal cat > .claude/settings.local.json <<'EOF'{"permissions": {"allow": ["Bash(podman:*)"]}}EOFCréé par Claude Code, ce fichier est automatiquement ajouté au
.gitignore. Créé à la main, comme ci-dessus, il ne l'est pas : vérifiez-le, sinon vos règles personnelles partiront sur le dépôt.Fenêtre de terminal git check-ignore -v .claude/settings.local.json -
Le niveau utilisateur, valable pour tous vos projets. C'est la place des règles qui n'ont aucun rapport avec un dépôt particulier.
Fenêtre de terminal mkdir -p ~/.claudecat > ~/.claude/settings.json <<'EOF'{"permissions": {"deny": ["Read(~/.ssh/**)","Read(~/.aws/credentials)","Read(~/.claude/.credentials.json)"]}}EOFUn
denysur vos secrets est le meilleur usage de ce niveau : il vous suit partout, quel que soit le projet ouvert. -
Le niveau administré, imposé par l'organisation. Il se déploie par l'outillage de gestion de parc, à un emplacement système qui dépend de l'OS.
Système Chemin Linux et WSL /etc/claude-code/managed-settings.jsonmacOS /Library/Application Support/ClaudeCode/managed-settings.jsonWindows C:\Program Files\ClaudeCode\managed-settings.jsonCe niveau ne se contourne pas. Il porte aussi les verrous de politique, comme
disableBypassPermissionsModequi interdit le mode le plus permissif.
Créer une règle : la méthode
Section intitulée « Créer une règle : la méthode »Une règle mal placée ou mal formée ne produit aucune erreur, elle est simplement sans effet. Quatre questions permettent de la poser juste du premier coup.
Quel outil ? Le nom qui précède la parenthèse doit être celui de l'outil
réellement utilisé : Bash pour une commande shell, Read pour une lecture,
Edit et Write pour une modification, WebFetch pour une requête réseau.
Écrire Bash(...) pour protéger un fichier ne protège rien.
Quelle portée ? Une commande stable et utile à toute l'équipe va dans le fichier de projet. Une commande liée à votre poste va dans le fichier local. Une protection de vos secrets va dans le fichier utilisateur.
Quelle liste ? deny pour ce qui ne doit jamais passer, ask pour ce qui
doit rester sous votre œil, allow pour ce qui est répétitif et sans risque.
Rappel du cycle : deny gagne toujours, quelle que soit la précision de la
règle allow en face.
Quelle forme de motif ? C'est là que se jouent la plupart des échecs.
| Intention | Motif correct | Erreur fréquente |
|---|---|---|
| Une commande exacte | Bash(git status) | |
| Un préfixe et ses arguments | Bash(npm run:*) | Bash(npm run *) |
| Un fichier précis | Read(./.env) | |
| Un dossier et son contenu | Read(./secrets/**) | Read(./secrets) |
| Un domaine réseau | WebFetch(domain:github.com) | WebFetch(github.com) |
Une fois la règle écrite, vérifiez qu'elle est bien active plutôt que de le
supposer. La commande /permissions liste toutes les règles et le fichier
d'où chacune provient, ce qui tranche immédiatement entre une règle absente et
une règle présente mais mal formée.
/permissionsSyntaxe des règles de permissions
Section intitulée « Syntaxe des règles de permissions »Les règles utilisent une syntaxe simple Outil(motif) :
Bash(uv run ruff check:*) -> préfixe "uv run ruff check" + n'importe quels argumentsBash(git status) -> commande exacte, sans argumentRead(./.env) -> lecture d'un fichier précisRead(./secrets/**) -> lecture récursive d'un dossierEdit(src/**) -> édition d'un chemin via motifWebFetch(domain:github.com) -> accès réseau restreint à un domaineRègles importantes :
- La forme canonique pour « préfixe + arguments libres » est
Bash(prefix:*)avec deux-points (Bash(uv run:*)autorise toutes les sous-commandesuv run) - Les motifs
denyont priorité surallowau sein d'un même scope denyau niveau Managed ne peut jamais être contourné
Le nom d'outil seul ouvre tout
Section intitulée « Le nom d'outil seul ouvre tout »C'est le piège le plus coûteux, et il ne se voit pas. Une règle réduite au
nom de l'outil, sans parenthèses, autorise cet outil en entier. La
documentation l'énonce comme une recette : « To run all Bash commands without
prompts except for a few you want blocked, add "Bash" to your allow list ».
{ "permissions": { "allow": ["Bash"] }}Cette seule ligne rend inutiles toutes les autres règles Bash(...) du
fichier, aussi précises soient-elles. Sur une configuration réelle auditée, 349
des 386 règles étaient dans ce cas : elles ne protégeaient plus rien depuis le
jour où un Bash nu avait été ajouté.
Le même effet vaut pour Read, Edit, Write, Glob, Grep, et pour un
serveur MCP entier comme mcp__github, qui couvre tous ses outils.
Deux subtilités de correspondance
Section intitulée « Deux subtilités de correspondance »La forme :* n'est reconnue qu'en fin de motif. Dans Bash(git:* push), le
deux-points est traité comme un caractère littéral et la règle ne
correspondra à aucune commande git.
Claude Code retire par ailleurs un jeu fixe de wrappers avant de comparer :
timeout, time, nice, nohup, stdbuf, les commandes internes command et
builtin, et le noglob de zsh. Une règle Bash(npm test:*) couvre donc aussi
timeout 30 npm test, et un deny ne se contourne pas en préfixant la commande.
Sur les liens symboliques, le traitement est volontairement asymétrique :
une règle allow ne s'applique que si le lien et sa cible correspondent tous
les deux, alors qu'une règle deny s'applique dès que l'un des deux
correspond.
Application sur lab-claude
Section intitulée « Application sur lab-claude »-
Placez-vous dans le projet
Fenêtre de terminal cd ~/Projets/lab-claude -
Créez
.claude/settings.jsonpartagé{"$schema": "https://json.schemastore.org/claude-code-settings.json","permissions": {"allow": ["Bash(uv run ruff check:*)","Bash(uv run ruff format:*)","Bash(uv run pytest:*)","Bash(uv add:*)","Bash(uv sync:*)","Bash(git status)","Bash(git diff:*)","Bash(git log:*)"],"deny": ["Bash(rm -rf:*)","Bash(curl:*)","Bash(wget:*)","Read(./.env)","Read(./.env.*)","Read(./secrets/**)"],"ask": ["Bash(git push:*)","Bash(git commit:*)"]},"env": {"PYTHONDONTWRITEBYTECODE": "1"},"includeCoAuthoredBy": false,"cleanupPeriodDays": 30} -
Validez la syntaxe JSON
Fenêtre de terminal python3 -c "import json; json.load(open('.claude/settings.json'))" && echo "JSON valide" -
Démarrez une session et vérifiez
Fenêtre de terminal claudePuis dans la session :
/status -
Confirmez que
.claude/settings.local.jsonest bien ignoréFenêtre de terminal git check-ignore .claude/settings.local.json
settings.json vs settings.local.json
Section intitulée « settings.json vs settings.local.json »Deux fichiers, deux usages distincts :
| Fichier | Contenu recommandé |
|---|---|
.claude/settings.json | Règles stables, pertinentes pour toute l'équipe (allow de uv run, deny des secrets) |
.claude/settings.local.json | Préférences personnelles temporaires (modèle préféré, allow spécifique à votre machine) |
Règle simple : si un autre développeur rejoue votre configuration sans souci, c'est du settings.json. Si ça dépend de votre machine ou de votre compte, c'est du settings.local.json.
Vérifier la configuration active
Section intitulée « Vérifier la configuration active »La commande /status affiche d'où vient chaque valeur (Managed, Local, Project, User). C'est le réflexe à avoir quand une permission semble bloquée ou accordée sans raison apparente.
Dans une session Claude :
/statusVous y trouvez :
- Les scopes chargés et leur chemin sur disque
- Les règles
allow,deny,askrésultantes après fusion - Le mode de permission actif
Exemple commenté pour lab-claude
Section intitulée « Exemple commenté pour lab-claude »Pourquoi ces règles dans le settings.json partagé :
Bash(uv run ruff check:*)etBash(uv run pytest:*): validations répétées à chaque cycle, aucune raison de prompterBash(git status),Bash(git diff:*),Bash(git log:*): lecture seule, sans risqueBash(git push:*)etBash(git commit:*)dansask: action visible côté équipe, confirmation souhaitableRead(./.env)etRead(./secrets/**)endeny: protection systématique des secretsBash(rm -rf:*),Bash(curl:*),Bash(wget:*)endeny: opérations destructives ou exfiltration réseauincludeCoAuthoredBy: false: l'attribution par défaut peut gêner dans certains workflows de revue
Erreurs fréquentes
Section intitulée « Erreurs fréquentes »Ces symptômes se ressemblent tous, mais ils relèvent de trois familles
distinctes. Soit la règle est au mauvais endroit, et /status le dit. Soit
sa syntaxe ne correspond pas à ce que vous croyez, en général l'oubli du
deux-points. Soit une règle plus large la rend sans effet, cas du nom
d'outil seul vu plus haut. La colonne du milieu identifie laquelle des trois.
| Symptôme | Cause probable | Correction |
|---|---|---|
Claude redemande une autorisation pourtant dans allow | Motif trop restrictif ou syntaxe incorrecte | Utiliser la forme Bash(prefix:*) avec deux-points, pas Bash(prefix *) |
deny non respecté | Règle placée dans le mauvais scope | Vérifier avec /status d'où vient la règle |
| Éditeur ne complète pas le JSON | $schema absent ou incorrect | Ajouter la ligne $schema en tête du fichier |
settings.local.json apparaît dans git status | Projet créé avant le fichier | Ajouter .claude/settings.local.json au .gitignore manuellement |
| Permissions perso poussées sur le dépôt | Règle mise dans settings.json au lieu de .local.json | Déplacer la règle vers le fichier local |
Checklist de fin de guide
Section intitulée « Checklist de fin de guide »Une configuration se vérifie sur le résultat effectif, pas sur ce que le fichier semble dire. Les deux derniers points de cette liste sont ceux qu'on oublie le plus souvent, et ce sont précisément ceux qui font qu'une règle ne s'applique pas.
- J'ai identifié les quatre fichiers de configuration et leur ordre de priorité
- J'ai créé
.claude/settings.jsonavec$schemaen tête - J'ai au moins une entrée dans
allow,denyetask - J'ai validé la syntaxe JSON du fichier
- J'ai vérifié la configuration active avec
/status - Je sais où mettre une règle perso (
settings.local.json) vs équipe (settings.json) -
.claude/settings.local.jsonest bien ignoré par git - Aucune règle nue (
Bash,Read,Edit) ne rend mes règles détaillées inutiles - Mes préfixes utilisent bien
Bash(commande:*), avec le deux-points en fin de motif
À retenir
Section intitulée « À retenir »- Le
settings.jsontransforme les garde-fous en contrat durable du projet denyprotège,allowaccélère,askgarde la main sur les actions visibles- Les permissions fusionnent entre portées au lieu de s'écraser, contrairement aux autres réglages
- Un nom d'outil seul ouvre tout l'outil et annule les règles détaillées qui le concernent
- La forme
:*n'est reconnue qu'en fin de motif, et les wrappers commetimeoutsont retirés avant comparaison settings.jsonse partage,settings.local.jsonreste local/statusest le seul juge de ce qui est vraiment actif
Pour aller plus loin
Section intitulée « Pour aller plus loin »- Hooks pour automatiser lint et tests : L'étape suivante des permissions : déclencher vos propres commandes sur les événements de session.
- Skills : routines réutilisables : Les procédures répétitives rangées dans une routine, avec leurs outils pré-autorisés.
- Brancher un serveur MCP : Les outils MCP s'autorisent dans le même fichier, avec une syntaxe de permission qui leur est propre.