Lo hook PermissionRequest di Claude Code viene eseguito nel momento in cui Claude Code sta per mostrarti un prompt di permesso, e può rispondere al posto tuo. Per consentire, lo hook esce con 0 e stampa {"hookSpecificOutput": {"hookEventName": "PermissionRequest", "decision": {"behavior": "allow"}}}; per negare, usa "behavior": "deny" con un message per Claude. Fa match sul nome del tool, non può scavalcare le tue regole di deny e l'exit code 2 non ha effetto su questo evento. Se lo hook non stampa alcuna decisione, compare il prompt normale.
01PermissionRequest a confronto con PreToolUse e Notification
Tre eventi hook hanno a che fare con i permessi, e fanno cose diverse:
PreToolUsePrima di ogni chiamata a un tool, che serva il permesso o noSì: allow, deny, ask o deferPermissionRequestSolo quando Claude Code sta per chiederti qualcosaSì: allow o denyNotification (permission_prompt)Dopo che un prompt è rimasto in attesa per circa sei secondi mentre sei viaNoUsa PermissionRequest quando ti interessano i prompt in sé: rispondere, registrarli nei log o inviarli da qualche parte. Scatta subito, senza il ritardo di sei secondi. Usa PreToolUse per regole che devono valere per ogni chiamata, come "non eseguire mai rm -rf", perché viene eseguito anche quando non comparirebbe alcun prompt. La guida al Notification hook spiega le tempistiche di quell'evento.
02Cosa riceve il hook
Oltre ai campi comuni, uno hook PermissionRequest riceve tool_name e tool_input della chiamata che Claude vuole fare, più un array opzionale permission_suggestions:
{
"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 contiene le modifiche alle regole che Claude Code suggerirebbe per questa richiesta. Non è una copia esatta delle opzioni nella finestra di dialogo, perché ogni dialogo costruisce le proprie opzioni.
03L'oggetto decision
Restituisci una decision dentro hookSpecificOutput:
behavior"allow" o "deny"updatedInputSolo allow. Sostituisce l'intero input del tool, quindi includi anche i campi invariatiupdatedPermissionsSolo allow. Modifiche ai permessi da applicare, come aggiungere una regola o cambiare modalitàmessageSolo deny. Spiega a Claude il motivointerruptSolo deny. true ferma anche ClaudeDue regole da tenere a mente:
- Le regole deny e ask valgono comunque. Un hook che restituisce
"allow"non scavalca una regola deny corrispondente nelle tue impostazioni, e l'input modificato viene ricontrollato rispetto a quelle regole. - Qui l'exit code
2viene ignorato. Nella maggior parte degli eventi l'exit2blocca, ma un hookPermissionRequestche esce con2senza un oggettodecisionlascia il prompt com'era. Per negare, restituisci la decisione.
04Esempio: approvare automaticamente un prompt
L'esempio di Anthropic approva ExitPlanMode, il prompt che compare quando Claude ha finito un piano, così non ti viene chiesto ogni volta:
{
"hooks": {
"PermissionRequest": [
{
"matcher": "ExitPlanMode",
"hooks": [
{
"type": "command",
"command": "echo '{\"hookSpecificOutput\": {\"hookEventName\": \"PermissionRequest\", \"decision\": {\"behavior\": \"allow\"}}}'"
}
]
}
]
}
}
Tieni i matcher stretti. Un matcher vuoto o .* con un allow generico approverebbe ogni prompt, comprese scritture di file e comandi shell.
05Esempio: decidere guardando il comando
Questo script (richiede jq) nega tutto ciò che tocca git push con un motivo leggibile da Claude, e lascia a te tutti gli altri prompt non stampando nulla:
#!/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" }]
}
]
}
}
Costruisci il JSON con jq invece di concatenare stringhe, così le virgolette nel messaggio non possono romperlo. E assicurati che nient'altro venga stampato su stdout: se il profilo della tua shell stampa una riga, Claude Code non leggerà la decisione.
06Esempio: consentire e ricordare per la sessione
Per approvare una richiesta ed evitare che Claude la richieda fino alla fine della sessione, aggiungi una voce updatedPermissions con destination: "session". Un hook può rimandare indietro uno dei permission_suggestions ricevuti, cambiando solo la destinazione:
#!/bin/bash
input=$(cat)
jq -c '{hookSpecificOutput: {hookEventName: "PermissionRequest",
decision: {behavior: "allow",
updatedPermissions: [(.permission_suggestions // [])[]
| select(.type == "addRules")
| .destination = "session"]}}}' <<<"$input"
Così com'è, consente ogni richiesta che vede, quindi abbinalo a un matcher stretto. La destinazione può anche essere localSettings, projectSettings o userSettings, che scrivono la regola in un file di impostazioni invece di tenerla in memoria.
07Spesso una regola di permesso è lo strumento migliore
Se la risposta non cambia mai, non ti serve un hook. Metti la regola in settings.json e Claude Code la applica senza eseguire nulla:
{
"permissions": {
"allow": ["Bash(npm run *)"],
"deny": ["Bash(git push *)"]
}
}
Le regole vengono valutate prima deny, poi ask, poi allow. Un hook ha senso quando la decisione dipende da qualcosa che una regola non vede, come l'ora del giorno, il branch su cui sei o una persona che risponde da altrove. Le modalità di permesso spiegate illustra le altre opzioni integrate.
08Errori comuni
- Esecuzioni non interattive. Con
claude -pnon c'è nessuno a cui chiedere. Gli hookPermissionRequestvengono comunque eseguiti e, se nessuno restituisce una decisione, la chiamata viene negata. - Timeout. Un command hook può girare fino a 600 secondi di default, e Claude aspetta. Imposta
timeout(in secondi) se il tuo hook aspetta qualcosa di lento, come una persona. - Alcuni prompt non lo attivano. La richiesta di rete di un comando in sandbox non esegue
PermissionRequest. Per quella usa il tipo di notificapermission_prompt. - Sicurezza. Un hook che restituisce
"allow"approva azioni a tuo nome con i permessi del tuo utente. Revisionalo come qualsiasi altro codice in grado di eseguire comandi.
09Dove si inserisce Claude Code Notifier
Il motivo più comune per scrivere un hook PermissionRequest è rispondere ai prompt quando non sei alla tastiera. Una versione fai-da-te richiede che l'hook invii la richiesta da qualche parte, aspetti una risposta e la restituisca prima del timeout. Si può fare, e c'è chi lo realizza con un chat bot.
Claude Code Notifier lo fa per te. Il suo tool da riga di comando gratuito, ccn, funziona su Mac, Windows e Linux e installa i suoi hook in ~/.claude/settings.json. Con l'app iPhone o Android associata, la richiesta di permesso arriva sul telefono e puoi consentire una volta, consentire per la sessione o negare; ccn restituisce quella decisione dall'hook PermissionRequest. Se hai digitato negli ultimi 30 secondi, non c'è attesa e il terminale chiede come al solito. Se sei via, il terminale aspetta il telefono fino a un limite che scegli tu (hold_ceiling_seconds, default 600), e smette di aspettare appena tocchi la tastiera. È indipendente e non è realizzato da Anthropic. Vedi approvare i permessi dal telefono per il flusso di lavoro e l'approvazione remota è sicura? per l'aspetto della sicurezza.
10FAQ
Come approvo automaticamente i permessi con un hook?
Aggiungi un hook PermissionRequest con un matcher stretto, fagli stampare una decisione JSON con "behavior": "allow" dentro hookSpecificOutput, poi esci con 0. Se lo stesso comando va sempre consentito, una regola permissions.allow in settings.json è più semplice e non richiede un hook.
Perché l'exit code 2 non nega la richiesta?
PermissionRequest è uno degli eventi in cui l'exit 2 non viene rispettato. Claude Code lo ignora e mostra il prompt normale. Restituisci invece "behavior": "deny" nell'oggetto decision.
Un hook PermissionRequest può scavalcare le mie regole deny?
No. Le regole deny e ask vengono comunque valutate, quindi un "allow" da un hook non supera una regola deny corrispondente. Anche qualsiasi updatedInput restituito viene controllato rispetto a quelle regole.
Qual è la differenza tra PermissionRequest e PreToolUse?
PreToolUse viene eseguito prima di ogni chiamata a un tool e può consentire, negare, chiedere o rimandare. PermissionRequest viene eseguito solo quando Claude Code sta per mostrare un prompt, e può consentirlo o negarlo. Usa PreToolUse per le policy, PermissionRequest per rispondere ai prompt.
Cosa succede se il mio hook non stampa nulla?
Non cambia nulla. Claude Code mostra il solito prompt di permesso nel terminale, come se l'hook non ci fosse.