El hook PermissionRequest de Claude Code se ejecuta justo cuando Claude Code va a mostrarte un prompt de permiso, y puede responderlo por ti. Para permitir, el hook sale con 0 e imprime {"hookSpecificOutput": {"hookEventName": "PermissionRequest", "decision": {"behavior": "allow"}}}; para denegar, usa "behavior": "deny" con un message para Claude. Filtra por nombre de herramienta, no puede saltarse tus reglas de denegación y el código de salida 2 no hace nada en este evento. Si el hook no imprime ninguna decisión, aparece el prompt normal.
01PermissionRequest frente a PreToolUse y Notification
Hay tres eventos de hook relacionados con los permisos, y cada uno cumple una función distinta:
PreToolUseAntes de cada llamada a una herramienta, necesite permiso o noSí: allow, deny, ask o deferPermissionRequestSolo cuando Claude Code está a punto de preguntarteSí: allow o denyNotification (permission_prompt)Cuando un prompt lleva unos seis segundos esperando mientras no estásNoUsa PermissionRequest cuando te interesen los propios prompts: responderlos, registrarlos o enviarlos a algún sitio. Se dispara al instante, sin el retraso de seis segundos. Usa PreToolUse para reglas que deban aplicarse a todas las llamadas, como "nunca ejecutes rm -rf", porque se ejecuta incluso cuando no aparecería ningún prompt. La guía del Notification hook explica cuándo se dispara ese evento.
02Qué recibe el hook
Además de los campos comunes, un hook PermissionRequest recibe el tool_name y el tool_input de la llamada que Claude quiere hacer, y un array opcional 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 los cambios de reglas que Claude Code sugeriría para esta solicitud. No es una copia exacta de las opciones del diálogo, porque cada diálogo genera sus propias opciones.
03El objeto decision
Devuelve un decision dentro de hookSpecificOutput:
behavior"allow" o "deny"updatedInputSolo con allow. Sustituye toda la entrada de la herramienta, así que incluye también los campos sin cambiosupdatedPermissionsSolo con allow. Cambios de permisos que aplicar, como añadir una regla o cambiar de modomessageSolo con deny. Le explica a Claude el motivointerruptSolo con deny. true además detiene a ClaudeDos reglas que conviene recordar:
- Las reglas deny y ask se siguen aplicando. Un hook que devuelve
"allow"no anula una regla deny que coincida en tu configuración, y la entrada modificada se vuelve a comprobar contra esas reglas. - El código de salida
2se ignora aquí. En la mayoría de eventos, salir con2bloquea, pero un hookPermissionRequestque sale con2sin un objetodecisiondeja el prompt tal cual. Para denegar, devuelve la decisión.
04Ejemplo: aprobar automáticamente un prompt
El propio ejemplo de Anthropic aprueba ExitPlanMode, el prompt que aparece cuando Claude termina un plan, para que no te pregunte cada vez:
{
"hooks": {
"PermissionRequest": [
{
"matcher": "ExitPlanMode",
"hooks": [
{
"type": "command",
"command": "echo '{\"hookSpecificOutput\": {\"hookEventName\": \"PermissionRequest\", \"decision\": {\"behavior\": \"allow\"}}}'"
}
]
}
]
}
}
Usa matchers específicos. Un matcher vacío o .* con un allow general aprobaría todos los prompts, incluidas escrituras de archivos y comandos de shell.
05Ejemplo: decidir según el comando
Este script (necesita jq) deniega cualquier cosa que toque git push con un motivo que Claude puede leer, y te deja el resto de prompts a ti sin imprimir nada:
#!/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" }]
}
]
}
}
Genera el JSON con jq en vez de concatenar strings, así las comillas del mensaje no lo rompen. Y asegúrate de que nada más se imprima en stdout. Si tu perfil de shell hace echo de alguna línea, Claude Code no leerá la decisión.
06Ejemplo: permitir y recordarlo durante la sesión
Para aprobar una solicitud y que Claude no vuelva a preguntar hasta que termine la sesión, añade una entrada updatedPermissions con destination: "session". Un hook puede devolver una de las permission_suggestions que recibió, cambiando solo el destino:
#!/bin/bash
input=$(cat)
jq -c '{hookSpecificOutput: {hookEventName: "PermissionRequest",
decision: {behavior: "allow",
updatedPermissions: [(.permission_suggestions // [])[]
| select(.type == "addRules")
| .destination = "session"]}}}' <<<"$input"
Tal como está, permite todas las solicitudes que ve, así que combínalo con un matcher específico. El destino también puede ser localSettings, projectSettings o userSettings, que guardan la regla en un archivo de configuración en lugar de mantenerla en memoria.
07A menudo, una regla de permisos es mejor opción
Si la respuesta nunca cambia, no necesitas un hook. Pon la regla en settings.json y Claude Code la aplica sin ejecutar nada:
{
"permissions": {
"allow": ["Bash(npm run *)"],
"deny": ["Bash(git push *)"]
}
}
Las reglas se evalúan primero deny, luego ask y luego allow. Un hook tiene sentido cuando la decisión depende de algo que una regla no puede ver, como la hora, la rama en la que estás o una persona respondiendo desde otro sitio. Los modos de permisos explicados cubre las demás opciones integradas.
08Cosas que suelen pillar a la gente
- Ejecuciones no interactivas. Con
claude -pno hay nadie a quien preguntar. Los hooksPermissionRequestse siguen ejecutando, y si ninguno devuelve una decisión, la llamada se deniega. - Timeouts. Un hook de comando puede ejecutarse hasta 600 segundos por defecto, y Claude espera. Configura
timeout(en segundos) si tu hook espera algo lento, como una persona. - Algunos prompts no lo activan. La petición de red de un comando en sandbox no ejecuta
PermissionRequest. Para eso usa el tipo de notificaciónpermission_prompt. - Seguridad. Un hook que devuelve
"allow"está aprobando acciones en tu nombre con los permisos de tu usuario. Revísalo como cualquier otro código que pueda ejecutar comandos.
09Dónde encaja Claude Code Notifier
El motivo más habitual para escribir un hook PermissionRequest es responder prompts cuando no estás frente al teclado. Una versión hecha por ti necesita que el hook envíe la solicitud a algún sitio, espere una respuesta y la devuelva antes del timeout. Se puede hacer, y hay quien lo monta con un bot de chat.
Claude Code Notifier lo hace por ti. Su herramienta de línea de comandos gratuita, ccn, funciona en Mac, Windows y Linux e instala sus hooks en ~/.claude/settings.json. Con la app de iPhone o Android vinculada, la solicitud de permiso llega al móvil y puedes permitir una vez, permitir durante la sesión o denegar; ccn devuelve esa decisión desde el hook PermissionRequest. Si has escrito algo en los últimos 30 segundos, no se espera nada y el terminal pregunta como siempre. Si no estás, el terminal espera al móvil hasta el límite que elijas (hold_ceiling_seconds, 600 por defecto) y deja de esperar en cuanto tocas el teclado. Es independiente y no está hecho por Anthropic. Consulta aprobar permisos desde el móvil para ver el flujo y ¿es segura la aprobación remota? para la parte de seguridad.
10Preguntas frecuentes
¿Cómo apruebo permisos automáticamente con un hook?
Añade un hook PermissionRequest con un matcher específico y haz que imprima una decisión JSON con "behavior": "allow" dentro de hookSpecificOutput, y luego salga con 0. Si el mismo comando siempre debe permitirse, una regla permissions.allow en settings.json es más sencilla y no necesita hook.
¿Por qué el código de salida 2 no deniega la solicitud?
PermissionRequest es uno de los eventos en los que la salida 2 no se respeta. Claude Code la ignora y muestra el prompt normal. En su lugar, devuelve "behavior": "deny" en el objeto de decisión.
¿Puede un hook PermissionRequest anular mis reglas deny?
No. Las reglas deny y ask se siguen evaluando, así que un "allow" de un hook no se salta una regla deny que coincida. Cualquier updatedInput que devuelvas también se comprueba contra esas reglas.
¿Qué diferencia hay entre PermissionRequest y PreToolUse?
PreToolUse se ejecuta antes de cada llamada a una herramienta y puede permitir, denegar, preguntar o aplazar. PermissionRequest solo se ejecuta cuando Claude Code va a mostrar un prompt, y puede permitirlo o denegarlo. Usa PreToolUse para políticas y PermissionRequest para responder prompts.
¿Qué pasa si mi hook no imprime nada?
No cambia nada. Claude Code muestra el prompt de permisos habitual en el terminal, como si el hook no existiera.