Índice
- Qué hook para cada situación
- Qué necesitas
- Paso 1 — Crea dos canales
- Paso 2 — Añade los hooks
- Paso 3 — Pruébalo sin esperar a una petición real
- Paso 4 — Haz que el canal de bloqueo suene
- Evitar la sobrecarga de notificaciones
- Claude Code en remoto o en CI
- Solución de problemas
- Preguntas frecuentes
- ¿Cómo recibo una notificación cuando Claude Code necesita permiso?
- ¿Cómo sé cuándo Claude Code termina una tarea?
- ¿Puede la notificación atravesar el modo No molestar?
- ¿Funciona en Claude Code en la web o en sesiones remotas?
- ¿Es seguro poner la URL del webhook en settings.json?
- Resumen
- Relacionado
Claude Code se detiene en dos situaciones que importan: está bloqueado esperándote (una petición de permiso, una pregunta) o ha terminado. Si no estás mirando el terminal, ambas se ven igual: no pasa nada y la sesión se queda parada hasta que vuelves. La solución es un hook: unas pocas líneas en settings.json que envían un webhook a tu teléfono en cuanto ocurre cualquiera de las dos.
Esta guía te da la configuración para copiar, explica qué evento de hook usar en cada situación y cubre los detalles que hacen que funcione de forma fiable: leer la entrada del hook, las comillas en el shell y cómo no ahogarte en notificaciones.
Qué hook para cada situación
Claude Code ejecuta hooks en eventos de su ciclo de vida. Dos de ellos cubren este problema (referencia de hooks):
| Quieres saber cuándo… | Evento de hook | Matcher / filtro |
|---|---|---|
| Claude espera una decisión de permiso | Notification | permission_prompt |
| Claude lleva tiempo inactivo esperando tu respuesta | Notification | idle_prompt |
| Claude terminó de responder | Stop | no hace falta |
El matcher del hook Notification filtra por el tipo de notificación, así que puedes elegir exactamente cuáles llegan a tu teléfono. La entrada llega como JSON por stdin e incluye notification_type, message, cwd y session_id. Los hooks Notification no pueden bloquear ni cambiar nada: son observadores, que es justo lo que quieres aquí.
La entrada de Stop incluye last_assistant_message, el último texto que produjo Claude. Es una línea de resumen gratis para la notificación.
Qué necesitas
- Echobell en tu teléfono (App Store / Google Play)
curlyjqen la máquina donde corre Claude Code- Dos minutos
Paso 1 — Crea dos canales
Resiste la tentación de mandarlo todo a un solo canal. En Echobell, crea:
- Claude Bloqueado, tipo Time Sensitive o Llamada — para las peticiones de permiso, donde el agente está parado y cada minuto es cómputo y tiempo de reloj desperdiciados
- Claude Terminó, tipo Normal — una notificación push corriente, para leer cuando quieras
Copia la URL de webhook de cada canal. Se parece a https://hook.echobell.one/t/<channel-token>. Trátala como una contraseña: cualquiera que la tenga puede hacer sonar tu teléfono.
Guarda ambas como variables de entorno para que nunca acaben en un archivo de configuración versionado:
export ECHOBELL_CLAUDE_BLOCKED_URL="https://hook.echobell.one/t/<blocked-token>"
export ECHOBELL_CLAUDE_DONE_URL="https://hook.echobell.one/t/<done-token>"
Ponlas en el perfil de tu shell para que Claude Code las herede.
Paso 2 — Añade los hooks
Añade esto a ~/.claude/settings.json para que valga en todos los proyectos, o a .claude/settings.local.json para un solo repositorio:
{
"hooks": {
"Notification": [
{
"matcher": "permission_prompt",
"hooks": [
{
"type": "command",
"command": "jq -c '{title: \"Claude necesita permiso\", body: .message, project: (.cwd | split(\"/\") | last)}' | curl -sS -m 10 -X POST -H 'Content-Type: application/json' -d @- \"$ECHOBELL_CLAUDE_BLOCKED_URL\""
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "jq -c '{title: \"Claude terminó\", body: (.last_assistant_message // \"Listo\" | .[0:200]), project: (.cwd | split(\"/\") | last)}' | curl -sS -m 10 -X POST -H 'Content-Type: application/json' -d @- \"$ECHOBELL_CLAUDE_DONE_URL\""
}
]
}
]
}
}
Qué hace cada pieza:
jq -c '{...}'lee el JSON del hook desde stdin y construye una carga útil pequeña, de modo que Echobell recibe exactamente los campos que quieres y no todo el documento del hook..cwd | split("/") | lastconvierte/home/me/code/apienapi, así la notificación dice qué proyecto está pidiendo algo..[0:200]recorta el mensaje final. El worker de Echobell limita el cuerpo de las notificaciones a 1500 bytes, y la pantalla de bloqueo muestra mucho menos de todos modos.-m 10da acurlun timeout de 10 segundos para que un problema de red nunca deje a Claude Code esperando a tu hook.
Echobell muestra las claves que envías a través de las plantillas del canal, y un canal nuevo no tiene ninguna plantilla que las lea: configúralas en los ajustes del canal, plantilla de título {{title}} y plantilla de cuerpo {{body}}. Añade {{project}} a cualquiera de las dos si quieres ver el nombre del proyecto, por ejemplo {{title}} ({{project}}).
Paso 3 — Pruébalo sin esperar a una petición real
Ejecuta a mano la misma tubería con una carga de hook falsa:
echo '{"message":"Claude necesita tu permiso para usar Bash","cwd":"/home/me/code/api","notification_type":"permission_prompt"}' \
| jq -c '{title: "Claude necesita permiso", body: .message, project: (.cwd | split("/") | last)}' \
| curl -sS -m 10 -X POST -H 'Content-Type: application/json' -d @- "$ECHOBELL_CLAUDE_BLOCKED_URL"
Si tu teléfono se ilumina, la parte de Echobell funciona y cualquier problema restante está en cómo Claude Code lee la configuración. En Claude Code, ejecuta /hooks para confirmar que los hooks se cargaron; los cambios de configuración hechos con una sesión en marcha pueden necesitar el menú de hooks o un reinicio para aplicarse.
Paso 4 — Haz que el canal de bloqueo suene
Una notificación push pierde contra No molestar. Un canal de Llamada se comporta como una llamada entrante y atraviesa el modo Concentración de iOS, lo que importa sobre todo cuando lanzas una tarea larga y te vas por la tarde. Si solo quieres que te interrumpan por algunas peticiones, filtra con una condición de canal de Echobell sobre las variables que envías, por ejemplo project == "api", en lugar de editar el hook. Para la lista completa de variables consulta la referencia de condiciones.
Evitar la sobrecarga de notificaciones
Una sesión activa puede disparar muchos eventos Stop: cada respuesta termina con uno. Tres formas de quedarte con la señal:
- No envíes
Stopa un canal que suena. Terminar no es urgente; déjalo en Normal. - Usa
idle_prompten lugar deStopsi solo quieres saber cuándo Claude se ha detenido y te espera, y no después de cada respuesta. - Acota por proyecto con una condición, para que un repositorio de pruebas no te notifique en absoluto.
Claude Code en remoto o en CI
El mismo enfoque funciona en entornos en la nube o remotos, porque el hook es solo una petición HTTPS saliente. Nada tiene que ser accesible desde internet. Define las dos variables de entorno en los secretos del entorno en lugar de en el perfil del shell, y la notificación llegará a tu teléfono dondequiera que corra la sesión.
Solución de problemas
No llega nada y la prueba manual también falla. Comprueba que la variable con la URL está definida en el shell que lanza Claude Code: echo "$ECHOBELL_CLAUDE_BLOCKED_URL". Una variable vacía hace que curl falle en silencio.
La prueba manual funciona pero el hook no se dispara. Confirma el matcher: permission_prompt e idle_prompt son distintos, y un matcher que no coincide simplemente nunca se ejecuta. Ejecuta /hooks y comprueba que el JSON es válido: una coma final desactiva los hooks de todo el archivo de configuración.
El cuerpo de la notificación está en blanco. El filtro de jq hizo referencia a un campo que no existe para ese evento. message existe en la entrada de Notification; last_assistant_message existe en la de Stop. Usa // para dar un valor por defecto, como en la configuración de arriba.
Se dispara demasiado. Mira la sección anterior: pasa de Stop a idle_prompt o añade una condición.
Preguntas frecuentes
¿Cómo recibo una notificación cuando Claude Code necesita permiso?
Añade un hook Notification con el matcher permission_prompt que envíe un webhook a un canal. Echobell convierte esa petición en un push o una alerta tipo llamada en tu teléfono.
¿Cómo sé cuándo Claude Code termina una tarea?
Añade un hook Stop. Se ejecuta cuando Claude termina de responder y su entrada incluye last_assistant_message, que puedes usar como cuerpo de la notificación.
¿Puede la notificación atravesar el modo No molestar?
Sí, si el canal receptor es de tipo Llamada. Se comporta como una llamada entrante, que el modo Concentración de iOS deja pasar. Un push normal de cualquier app no lo consigue.
¿Funciona en Claude Code en la web o en sesiones remotas?
Sí. El hook solo hace una petición HTTPS saliente, así que funciona en cualquier sitio donde la sesión pueda llegar a internet. Proporciona las URL de los canales mediante los secretos del entorno.
¿Es seguro poner la URL del webhook en settings.json?
Es mejor usar una variable de entorno, como se muestra arriba, para que el token no se suba a un repositorio. Si se filtra, crea un canal nuevo y retira el anterior.
Resumen
Dos canales, dos hooks y una tubería jq | curl: un canal de Llamada o Time Sensitive para permission_prompt y un canal Normal para Stop. Después puedes lanzar una tarea larga de un agente, salir de la habitación y volver solo cuando el agente de verdad te necesite.
Descarga Echobell para iPhone o consíguelo en Google Play y ejecuta la prueba manual de arriba antes de confiarle una tarea larga.