TL;DR Un hook
PermissionRequestcon"matcher": "ExitPlanMode"que devuelve{"behavior":"allow"}aprueba solo el "¿procedo con el plan?". Bash, edits y MCP siguen preguntando igual. La clave es el matcher estrecho: automatizas un permiso, no todos. Pensado para la sesión interactiva: en unclaude -psin host de permisos,ExitPlanModeni siquiera está disponible, así que no hay plan que aprobar.
Lanzas un plan grande. Te levantas a por un café, o te pones con otra cosa. Vuelves diez minutos después y Claude no ha tocado nada: lleva todo ese rato parado, esperando que apruebes el "sí, procede". Tiempo muerto, y encima por un permiso que ibas a dar igual.
La parte buena: ese permiso concreto se puede automatizar. Y solo ese.
Cómo funciona
Cuando Claude sale de plan mode llama a una tool, ExitPlanMode, que requiere permiso. El evento PermissionRequest se dispara justo cuando aparecería el diálogo de aprobación. Un hook puede responderlo por ti con behavior: allow. Acotado con "matcher": "ExitPlanMode", solo toca ese permiso, ninguno más.
Resultado:
Here's my plan:
1. ...
2. ...
✓ Allowed by PermissionRequest hook
Sin esperar tu clic.
Cómo montarlo
1. El hook en settings.json
En ~/.claude/settings.json (o el .claude/settings.json del proyecto):
{
"hooks": {
"PermissionRequest": [
{
"matcher": "ExitPlanMode",
"hooks": [
{
"type": "command",
"command": "echo '{\"hookSpecificOutput\":{\"hookEventName\":\"PermissionRequest\",\"decision\":{\"behavior\":\"allow\"}}}'"
}
]
}
]
}
}
El comando escribe la decisión en stdout. Nada más: el plan se aprueba solo.
2. El matcher estrecho es la seguridad
"matcher": "ExitPlanMode" hace que el hook responda solo a ese permiso. Un rm, una edición, una llamada MCP te siguen pidiendo permiso como siempre. Automatizas una cosa concreta, no bajas la guardia en el resto.
Cuando el nombre de la tool no basta para acotar, la entrada admite además un campo if con una regla de permisos, y con él filtras por lo que esa tool va a hacer: hooks condicionales.
3. Pensado para la sesión interactiva
En claude -p los hooks PermissionRequest sí se ejecutan, pero ExitPlanMode solo está disponible si la ejecución tiene un host de permisos (un callback canUseTool del Agent SDK o un --permission-prompt-tool). Sin host no hay plan que aprobar; con host, el hook corre junto a él y decide el primero que responda. Y si en -p se deniega un permiso, nada te avisa: en headless la ejecución acaba en verde igualmente. Al aprobar, Claude Code restaura el modo de permisos que tenías antes de entrar en plan.
Lo que NO hacer
Circula una variante que, además de aprobar el plan, salta a bypassPermissions para que nada vuelva a preguntar. Eso es lo contrario de la idea: abre la mano con todo. Si quieres seguir revisando bash y edits, evítala. El valor está, justamente, en el matcher estrecho.
Referencia
| Pieza | Valor |
|---|---|
| Evento | PermissionRequest (interactivo, o -p con host de permisos) |
| Matcher | ExitPlanMode (nombre pelado, sin specifier) |
| Salida | {"hookSpecificOutput":{...,"decision":{"behavior":"allow"}}} |
| Alcance | Solo el permiso de salir de plan mode |
Documentación oficial: Automate actions with hooks
Encaja con plan mode, de donde sale el permiso, y con el sistema de permisos de /permissions (deny/allow/ask), del que este hook es la capa programable. Y el plan que apruebas es un .md que puedes guardar en tu repo con una línea.
Requisitos
- Claude Code v2.1.x. El hook se dispara cuando Claude Code va a pedirte aprobar el plan: en la sesión interactiva, o en
-pcon un host de permisos. ExitPlanModerequiere permiso, y por eso se puede interceptar.
Este hook automatiza un solo permiso. Para cortar el resto sin abrir la mano, la guía de permisos ordena las cinco palancas por riesgo.