De Claude Code PermissionRequest hook draait op het moment dat Claude Code je een permissieprompt wil tonen, en kan die prompt voor je beantwoorden. Om toe te staan sluit de hook af met 0 en print hij {"hookSpecificOutput": {"hookEventName": "PermissionRequest", "decision": {"behavior": "allow"}}}; om te weigeren gebruikt hij "behavior": "deny" met een message voor Claude. Hij matcht op toolnaam, kan je deny-regels niet overrulen, en exitcode 2 doet bij dit event niets. Print de hook geen beslissing, dan verschijnt de normale prompt.
01PermissionRequest vergeleken met PreToolUse en Notification
Drie hook-events hebben met permissies te maken, en ze doen elk iets anders:
PreToolUseVóór elke toolaanroep, of er nu permissie nodig is of nietJa: allow, deny, ask of deferPermissionRequestAlleen als Claude Code het je gaat vragenJa: allow of denyNotification (permission_prompt)Nadat een prompt ongeveer zes seconden heeft gewacht terwijl je weg bentNeeGebruik PermissionRequest als het je om de prompts zelf gaat: beantwoorden, loggen of ergens naartoe sturen. Hij vuurt meteen, zonder vertraging van zes seconden. Gebruik PreToolUse voor regels die voor elke aanroep moeten gelden, zoals 'draai nooit rm -rf', omdat die ook draait als er geen prompt zou komen. De guide over de Notification hook legt de timing van dat event uit.
02Wat de hook ontvangt
Naast de gewone velden krijgt een PermissionRequest hook de tool_name en tool_input van de aanroep die Claude wil doen, plus een optionele permission_suggestions-array:
{
"session_id": "abc123",
"cwd": "/Users/...",
"permission_mode": "default",
"hook_event_name": "PermissionRequest",
"tool_name": "Bash",
"tool_input": {
"command": "rm -rf node_modules",
"description": "Remove node_modules directory"
},
"permission_suggestions": [
{
"type": "addRules",
"rules": [{ "toolName": "Bash", "ruleContent": "rm -rf node_modules" }],
"behavior": "allow",
"destination": "localSettings"
}
]
}
permission_suggestions bevat de regelwijzigingen die Claude Code voor dit verzoek zou voorstellen. Het is geen exacte kopie van de opties in de dialoog, omdat elke dialoog zijn eigen opties opbouwt.
03Het decision-object
Geef een decision terug binnen hookSpecificOutput:
behavior"allow" of "deny"updatedInputAlleen bij allow. Vervangt de volledige input van de tool, dus neem ook ongewijzigde velden opupdatedPermissionsAlleen bij allow. Toe te passen permissiewijzigingen, zoals een regel toevoegen of de modus wijzigenmessageAlleen bij deny. Vertelt Claude waarominterruptAlleen bij deny. true stopt ook ClaudeTwee regels om te onthouden:
- Deny- en ask-regels blijven gelden. Een hook die
"allow"teruggeeft, overschrijft geen overeenkomende deny-regel in je settings, en aangepaste input wordt opnieuw tegen die regels gecontroleerd. - Exitcode
2wordt hier genegeerd. Bij de meeste events blokkeert exit2, maar eenPermissionRequest-hook die met2afsluit zonderdecision-object, laat de prompt gewoon staan. Wil je weigeren, geef dan de decision terug.
04Voorbeeld: één prompt automatisch goedkeuren
Het voorbeeld van Anthropic zelf keurt ExitPlanMode goed, de prompt die verschijnt als Claude klaar is met een plan, zodat je het niet elke keer gevraagd wordt:
{
"hooks": {
"PermissionRequest": [
{
"matcher": "ExitPlanMode",
"hooks": [
{
"type": "command",
"command": "echo '{\"hookSpecificOutput\": {\"hookEventName\": \"PermissionRequest\", \"decision\": {\"behavior\": \"allow\"}}}'"
}
]
}
]
}
}
Houd matchers smal. Een lege matcher of .* met een algemene allow keurt elke prompt goed, inclusief file writes en shellcommando's.
05Voorbeeld: beslissen op basis van het commando
Dit script (vereist jq) weigert alles wat git push raakt, met een reden die Claude kan lezen, en laat elke andere prompt aan jou over door niets te printen:
#!/bin/bash
# ~/.claude/hooks/permission-check.sh
input=$(cat)
cmd=$(jq -r '.tool_input.command // empty' <<<"$input")
case "$cmd" in
*"git push"*)
jq -nc '{hookSpecificOutput: {hookEventName: "PermissionRequest",
decision: {behavior: "deny",
message: "Pushing is not allowed from this session. Commit and stop."}}}'
;;
esac
exit 0
{
"hooks": {
"PermissionRequest": [
{
"matcher": "Bash",
"hooks": [{ "type": "command", "command": "~/.claude/hooks/permission-check.sh" }]
}
]
}
}
Bouw de JSON op met jq in plaats van strings aan elkaar te plakken, zodat quotes in het bericht hem niet kapotmaken. Zorg er ook voor dat er verder niets naar stdout gaat. Als je shellprofiel een regel echoot, leest Claude Code de decision niet.
06Voorbeeld: toestaan en onthouden voor de sessie
Wil je een request goedkeuren en zorgen dat Claude het tot het einde van de sessie niet meer vraagt, voeg dan een updatedPermissions-entry toe met destination: "session". Een hook kan een van de ontvangen permission_suggestions terugsturen en alleen de destination aanpassen:
#!/bin/bash
input=$(cat)
jq -c '{hookSpecificOutput: {hookEventName: "PermissionRequest",
decision: {behavior: "allow",
updatedPermissions: [(.permission_suggestions // [])[]
| select(.type == "addRules")
| .destination = "session"]}}}' <<<"$input"
Zoals het er nu staat, staat dit elk request toe dat het ziet, dus combineer het met een smalle matcher. De destination kan ook localSettings, projectSettings of userSettings zijn; dan wordt de regel naar een settingsbestand geschreven in plaats van in het geheugen bewaard.
07Vaak is een permission-regel het betere gereedschap
Als het antwoord nooit verandert, heb je geen hook nodig. Zet de regel in settings.json en Claude Code past hem toe zonder iets uit te voeren:
{
"permissions": {
"allow": ["Bash(npm run *)"],
"deny": ["Bash(git push *)"]
}
}
Regels worden geëvalueerd in de volgorde deny, ask, allow. Een hook heeft pas zin als de beslissing afhangt van iets wat een regel niet kan zien, zoals het tijdstip, de branch waarop je zit of iemand die van elders antwoordt. Permission modes uitgelegd behandelt de andere ingebouwde opties.
08Valkuilen
- Niet-interactieve runs. Met
claude -pis er niemand om een prompt aan te tonen.PermissionRequest-hooks draaien nog steeds, en als geen ervan een decision teruggeeft, wordt de call geweigerd. - Timeouts. Een command-hook mag standaard tot 600 seconden draaien, en Claude wacht zolang. Stel
timeout(in seconden) in als je hook op iets traags wacht, zoals een mens. - Sommige prompts triggeren hem niet. Een netwerkrequest van een gesandboxt commando start
PermissionRequestniet. Gebruik daarvoor het notificatietypepermission_prompt. - Beveiliging. Een hook die
"allow"teruggeeft, keurt acties goed uit jouw naam en met de rechten van jouw gebruiker. Review hem zoals alle andere code die commando's kan uitvoeren.
09Waar Claude Code Notifier in past
De meest voorkomende reden om een PermissionRequest-hook te schrijven is prompts beantwoorden als je niet achter je toetsenbord zit. Voor een zelfgebouwde versie moet de hook het request ergens naartoe sturen, op een antwoord wachten en dat vóór de timeout teruggeven. Dat is te doen, en sommigen bouwen het met een chatbot.
Claude Code Notifier regelt dit voor je. De gratis command line tool, ccn, draait op Mac, Windows en Linux en installeert zijn hooks in ~/.claude/settings.json. Met de gekoppelde iPhone- of Android-app komt een permission request binnen op je telefoon en kun je eenmalig toestaan, voor de sessie toestaan of weigeren; ccn geeft die beslissing terug vanuit de PermissionRequest-hook. Heb je in de laatste 30 seconden getypt, dan wacht er niets en vraagt de terminal het zoals gewoonlijk. Ben je weg, dan wacht de terminal op je telefoon tot een limiet die je zelf kiest (hold_ceiling_seconds, standaard 600), en stopt met wachten zodra je het toetsenbord aanraakt. Het is onafhankelijk en niet gemaakt door Anthropic. Zie permissions goedkeuren vanaf je telefoon voor de workflow en is goedkeuren op afstand veilig? voor de beveiligingskant.
10FAQ
Hoe keur ik permissions automatisch goed met een hook?
Voeg een PermissionRequest-hook toe met een smalle matcher, laat hem een JSON-decision printen met "behavior": "allow" binnen hookSpecificOutput en sluit af met 0. Moet hetzelfde commando altijd toegestaan worden, dan is een permissions.allow-regel in settings.json eenvoudiger en heb je geen hook nodig.
Waarom weigert exitcode 2 het request niet?
PermissionRequest is een van de events waarbij exit 2 niet wordt gerespecteerd. Claude Code negeert het en toont de normale prompt. Geef in plaats daarvan "behavior": "deny" terug in het decision-object.
Kan een PermissionRequest-hook mijn deny-regels overschrijven?
Nee. Deny- en ask-regels worden nog steeds geëvalueerd, dus een "allow" van een hook komt niet langs een overeenkomende deny-regel. Elke updatedInput die je teruggeeft, wordt ook tegen die regels gecontroleerd.
Wat is het verschil tussen PermissionRequest en PreToolUse?
PreToolUse draait vóór elke tool call en kan allow, deny, ask of defer teruggeven. PermissionRequest draait alleen als Claude Code op het punt staat een prompt te tonen, en kan die toestaan of weigeren. Gebruik PreToolUse voor beleid en PermissionRequest om prompts te beantwoorden.
Wat gebeurt er als mijn hook niets print?
Er verandert niets. Claude Code toont de gewone permission prompt in de terminal, alsof de hook er niet is.