Claude Code permissions instellen: de gids die ik miste
7m leestijd

Claude Code permissions instellen: de gids die ik miste

Hoe je Claude Code permissions instelt zonder gek te worden van de prompts: modes, allow- en deny-regels, hooks en de sandbox als één model, plus de settings.json die ik draai.

Het permissiesysteem van Claude Code bestaat uit vier lagen: de mode bepaalt hoe vaak hij om toestemming vraagt, allow- en deny-regels bepalen wat hij zonder vragen mag aanroepen, hooks dwingen af wat elke keer moet gelden, en de sandbox bepaalt wat het proces fysiek kan bereiken. Is je vraag waarom een Bash-commando geblokkeerd wordt, of hoe je voorkomt dat je voor de veertigste keer hetzelfde goedkeurt, dan wordt die op een van die vier lagen beantwoord. Uitzoeken welke van de vier, dat is het werk.

Anthropic heeft gemeten wat er gebeurt als Claude Code om toestemming vraagt: gebruikers keuren 93% van de prompts goed. Bij dat percentage is de prompt behang. Je leest hem niet meer, je vinger kent de sneltoets, en de ene prompt die ertoe doet, krijgt dezelfde reflex-ja als de veertig die er niet toe doen.

De populaire oplossing maakt het erger. --dangerously-skip-permissions is dezelfde beslissing, maar dan zonder de knop: je zei al overal ja op, nu geef je het gewoon toe. De incidenten laten zich raden: gewiste home-directories, verdwenen databases, een gestage stroom mensen die er door schade en schande achter komen dat een agent met jouw shell precies zo voorzichtig is als zijn slechtste sample.

De echte oplossing is snappen dat het permissiesysteem van Claude Code uit vier lagen bestaat, en dat elke laag een andere vraag beantwoordt. Zodra je dat ziet, kost de configuratie twintig minuten en zijn de prompts die overblijven de prompts die het lezen waard zijn.

De vier lagen ​

LaagDe vraag die hij beantwoordt
ModeHoe vaak vraagt hij om toestemming?
RegelsWat mag hij aanroepen?
HooksWat wordt er deterministisch afgedwongen?
SandboxWaar kan het proces fysiek bij?

Modes en regels sturen het gedrag van het model. Hooks en de sandbox dwingen af wat jij wilt. De meeste gidsen stoppen na de eerste twee lagen, en zo zitten mensen met een allowlist waarvan ze denken dat het een beveiligingsgrens is. Het is een slot op een deur die de agent keurig gebruikt.

Laag 1: de mode bepaalt hoe vaak hij vraagt ​

De mode is een schakelaar per sessie, in te stellen met Shift+Tab, --permission-mode, of defaultMode in je settings:

  • default: lezen mag altijd, al het andere geeft een prompt. Hier begin je. Recente versies noemen het Manual, met precies hetzelfde gedrag.
  • plan: alleen lezen en verkennen. De agent stelt voor, jij beslist.
  • acceptEdits: bestandswijzigingen gaan automatisch, shell-commando's blijven vragen. Mijn standaardmodus voor repo's met nette git-hygiëne, want git checkout . draait een edit terug en niets draait een shell-commando terug.
  • auto: een veiligheidsclassifier keurt alles goed wat hij onschuldig vindt. Anthropic rapporteert 0,4% vals-positief en 17% vals-negatief. Dat één op de zes riskante calls erdoorheen glipt, is nog altijd een betere deal dan de 93% reflex-ja, maar weet wat je koopt.
  • bypassPermissions: alles mag. Prima in een wegwerpcontainer, roekeloos op de machine met je SSH-keys.

Een mode die je als flag meegeeft, blijft niet per project hangen. Mensen draaien één keer --dangerously-skip-permissions, hervatten de sessie een dag later, en snappen niet waarom de prompts terug zijn. Wil je hem permanent, zet dan defaultMode in je settings.

Laag 2: regels bepalen wat hij mag aanroepen ​

Het permissions-blok in settings.json kent drie lijsten, en de volgorde ligt vast: eerst deny, dan ask, dan allow. De eerste match wint, en hoe specifiek een regel is doet er niet toe:

json
{
  "permissions": {
    "allow": ["Bash(aws s3 ls)"],
    "deny": ["Bash(aws *)"]
  }
}

Die allow-regel is dode code. De deny matcht eerst, dus elk aws-commando wordt geblokkeerd, ook het commando dat je net had toegestaan. Deny wint van ask, ask wint van allow, altijd.

De syntax heeft een paar valkuilen, en die wil je kennen:

  • De spatie in de wildcard telt. Bash(ls *) matcht ls -la en dwingt een woordgrens af. Bash(ls*) matcht ook lsof. Eén teken verschil, een compleet andere blast radius.
  • Samengestelde commando's matchen per onderdeel. Bash(git *) keurt git add . && rm -rf /tmp/x niet goed. Elk subcommando achter &&, ; of een pipe heeft zijn eigen matchende regel nodig. Daarom blijft je allowlist prompts geven: het model rijgt dolgraag commando's aan elkaar.
  • Padankers luisteren nauw. In Read- en Edit-regels is //etc/passwd een absoluut pad, ankert /src/** aan het project van het settings-bestand, en is ./ de werkmap. Eén slash vooraan betekent iets anders dan je shell-reflex zegt.
  • Een deny op Read geldt alleen voor de Read-tool. "deny": ["Read(.env)"] houdt tegen dat de agent het bestand rechtstreeks opent. Het doet niets tegen een script dat de agent draait en dat zelf .env uitleest. Regels begrenzen tool calls, nooit de code die door zo'n call wordt uitgevoerd.

Dat laatste punt is precies de reden dat de volgende twee lagen bestaan.

Laag 3: hooks zijn de deterministische laag ​

Een PreToolUse-hook is een shell-commando dat elke tool call ziet vóór hij draait en hem onvoorwaardelijk kan tegenhouden, zonder dat er een model aan te pas komt. Exitcode 2 blokkeert de call. Met een JSON-antwoord dwing je allow, ask of deny af:

bash
#!/bin/bash
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')

if [[ "$FILE_PATH" == *".env"* ]]; then
  echo "Blocked: secrets stay out of context" >&2
  exit 2
fi
exit 0

Regels zijn patronen die het permissiesysteem naast de commandostring legt. Een hook is jouw code: die krijgt de volledige tool-input in handen en past elke logica toe die jij wilt. Waar de allowlist-regex je in de steek laat (en met de valkuil van samengestelde commando's hierboven gebeurt dat gegarandeerd een keer), gaat de hook gewoon af. Ik schreef eerder een volledige gids over Claude Code-hooks voor de hele levenscyclus. Voor permissions is PreToolUse de hook die telt. Twijfel je of een regel, een hook of iets anders bij je situatie past, dan is er ook een keuzegids voor skills, subagents, hooks en slash commands.

Laag 4: de sandbox is de muur ​

Alles hierboven draait in het proces van Claude Code en onderhandelt met het model. De sandbox zit op OS-niveau: bestandssysteem- en netwerkisolatie om de shell-commando's zelf heen. Anthropics eigen beeld klopt hier gewoon: permissions zijn het slot op de deur, de sandbox is de muur.

json
{
  "sandbox": {
    "enabled": true,
    "network": { "allowedDomains": ["registry.npmjs.org", "api.github.com"] },
    "filesystem": { "denyRead": ["~/.ssh", "~/.aws"] }
  }
}

Met de sandbox aan strandt een script dat ~/.ssh probeert te lezen op OS-niveau, wat het model ook van plan was, wat de regels ook zeiden. Het standaardgedrag is een prettige ruil: gesandboxte commando's draaien zonder prompt, en alles wat de sandbox uit wil, valt terug op de gewone permission-flow. Minder prompts en een hardere grens tegelijk. De muur verdient meer dan één paragraaf, dus ik schreef een volledige gids over Claude Code sandboxen: wat de ingebouwde sandbox afdekt, en wanneer je opschaalt naar een container of VM.

De settings.json die ik draai ​

Op projectniveau, ingecheckt in de repo, per project bijgesteld. Goed om te weten voor je hem commit: in een team gelden de deny-regels voor iedereen vanaf de eerste clone, terwijl de allow-regels wachten tot elke ontwikkelaar een trust-dialoog accepteert. Dat verschil pluis ik uit in wat een repo in een team wel en niet afdwingt. Met toelichting:

json
{
  "permissions": {
    "defaultMode": "acceptEdits",
    "allow": [
      "Bash(npm run test:*)",
      "Bash(npm run build)",
      "Bash(npx vitest run:*)",
      "Bash(git status)",
      "Bash(git diff:*)",
      "Bash(git log:*)"
    ],
    "ask": ["Bash(git push:*)"],
    "deny": [
      "Read(.env)",
      "Read(.env.*)",
      "Read(~/.ssh/**)",
      "Bash(curl:*)",
      "Bash(wget:*)"
    ]
  },
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [{ "type": "command", "command": "./.claude/hooks/protect-files.sh" }]
      }
    ]
  }
}

De logica: een edit terugdraaien kost niets, dus acceptEdits. De test- en buildloop mag vrijuit draaien, want een prompt op elke npm run test is precies waarmee je die 93%-reflex kweekt. git push vraagt altijd, want dat is het moment waarop werk de machine verlaat. Secrets worden op de regellaag geweigerd en door de hook nog eens tegengehouden, en curl/wget staan op deny omdat de agent daarvoor WebFetch met een domein-allowlist heeft. Dat twee lagen hetzelfde zeggen is precies de bedoeling: de regel stuurt wat het model probeert, de hook vangt wat erdoorheen glipt.

Hetzelfde principe trek je door naar je data. De agent databasetoegang geven met SELECT-only credentials en field redaction is exact deze stack, één laag dieper. Hoe dat eruitziet staat uitgewerkt in Claude veilig toegang geven tot je SQL-database.

Twintig minuten configureren, en het aantal prompts zakt van veertig per sessie naar een handvol. Lees die. Dat zijn de prompts die je aandacht verdienen.

(17 van 38)
1Mijn Claude Code-setup: status line, plugins en terminal2Superpowers: hoe je Claude Code leert eerst te denken3Claude Code-hooks: deterministische controle over AI-workflows4Het CLAUDE.md-bestand: geef je AI permanent geheugen5Stop met vriendelijk vragen aan je agent6Wat er nieuw is in Claude Code: notities van het Londen-event7Het beste cijfer in Opus 4.8 is geen benchmark8Verouderd geheugen is erger dan geen geheugen9De agent is gewoon een loop10Bouw een MCP-server, en vraag je dan af of die moet bestaan11Skill, subagent, hook of slash command? Kies de juiste12Inloggen op MCP-servers vanuit je shell13Claude veilig toegang geven tot je SQL-database14De dag dat 'default' ineens 'Manual' heette15Claude Code-skills: zo schrijf je er een die werkt16Een goede Claude Code-subagent schrijven17Claude Code permissions instellen: de gids die ik miste18Claude Code sandboxen: toestemming is geen muur19Prompt injection voorkomen: verdediging voor wie agents bouwt20Het beste Claude-model voor code: welk model voor welke taak21Legacy code refactoren met AI: begin met characterization tests22Je MCP-server beveiligen: authenticatie, scopes en rate limits23Opus 5 is er, en je effort-instellingen kloppen niet meer24Incident response voor AI-agents: wat je doet als je coding agent de fout in gaat25Claude Code /doctor: wat hij controleert en wat er nieuw is26Context beheren in Claude Code: wanneer /clear en wanneer /compact27Git worktrees uitgelegd: parallel werken met AI-agents zonder botsingen28Claude Code plan mode: beslissen voordat de agent schrijft29Debuggen met een coding agent: geef hem het zoekwerk, de hypothese houd je zelf30Claude Code checkpoints en /rewind: wijzigingen van je agent terugdraaien31Claude Code cross-session messaging: sessies die elkaar berichten sturen32Audit logging voor AI-agents: wat Claude Code vastlegt en wanneer je iemand wakker belt33Claude Code-config delen met je team: wat de repo wel en niet afdwingt34Je Claude Code-sessie heeft geen klok35Claude Code in een grote codebase: de agent afbakenen tot wat ertoe doet36Een Claude Code-sessie terughalen die de resume-picker niet laat zien37Waar Claude Code zijn tijd aan kwijt is: een maand eigen sessies gemeten38Claude Code bijsturen tijdens het werk: Esc, de wachtrij en /btw