Notificações do Claude Code no celular com hooks

Receba um alerta no celular quando o Claude Code pedir permissão ou terminar uma tarefa. Config de hooks pronta para copiar, com Notification, Stop e webhook.

Atualizado

Sumário

O Claude Code para em duas situações que importam: ele está bloqueado esperando por você (um pedido de permissão, uma pergunta) ou terminou o trabalho. Se você não está olhando para o terminal, as duas parecem iguais — nada acontece, e a sessão fica parada até você voltar. A solução é um hook: algumas linhas no settings.json que enviam um webhook para o seu celular no instante em que qualquer uma das duas acontece.

Este guia traz a configuração para copiar, explica qual evento de hook usar em cada situação e cobre os detalhes que fazem tudo funcionar de forma confiável: ler a entrada do hook, aspas no shell e como não se afogar em notificações.

Qual hook para qual situação

O Claude Code executa hooks em eventos do ciclo de vida. Dois deles resolvem este problema (referência de hooks):

Você quer saber quando…Evento do hookMatcher / filtro
O Claude está esperando uma decisão de permissãoNotificationpermission_prompt
O Claude ficou ocioso esperando sua respostaNotificationidle_prompt
O Claude terminou de responderStopnão precisa

O matcher do hook Notification filtra pelo tipo de notificação, então você escolhe exatamente quais chegam ao celular. A entrada chega como JSON no stdin e inclui notification_type, message, cwd e session_id. Hooks Notification não podem bloquear nem alterar nada — são observadores, que é exatamente o que você quer aqui.

A entrada do Stop inclui last_assistant_message, o texto final que o Claude produziu. É uma linha de resumo de graça para a notificação.

O que você precisa

  • Echobell no celular (App Store / Google Play)
  • curl e jq na máquina que roda o Claude Code
  • Dois minutos

Passo 1 — Crie dois canais

Resista à tentação de mandar tudo para um canal só. No Echobell, crie:

  • Claude Blocked, tipo Time Sensitive ou Calling — para pedidos de permissão, em que o agente está parado e cada minuto é perda de processamento e de tempo real
  • Claude Done, tipo Normal — um push comum, que dá para ler quando der

Copie a URL do webhook de cada canal. Ela se parece com https://hook.echobell.one/t/<channel-token>. Trate-a como uma senha: quem a tiver pode fazer seu celular tocar.

Guarde as duas como variáveis de ambiente, para que nunca caiam num arquivo de configuração commitado:

export ECHOBELL_CLAUDE_BLOCKED_URL="https://hook.echobell.one/t/<blocked-token>"
export ECHOBELL_CLAUDE_DONE_URL="https://hook.echobell.one/t/<done-token>"

Coloque-as no perfil do seu shell para que o Claude Code as herde.

Passo 2 — Adicione os hooks

Adicione isto a ~/.claude/settings.json para valer em todos os projetos, ou a .claude/settings.local.json para um único repositório:

{
  "hooks": {
    "Notification": [
      {
        "matcher": "permission_prompt",
        "hooks": [
          {
            "type": "command",
            "command": "jq -c '{title: \"Claude precisa de permissão\", 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 terminou\", body: (.last_assistant_message // \"Concluído\" | .[0:200]), project: (.cwd | split(\"/\") | last)}' | curl -sS -m 10 -X POST -H 'Content-Type: application/json' -d @- \"$ECHOBELL_CLAUDE_DONE_URL\""
          }
        ]
      }
    ]
  }
}

O que cada parte faz:

  • jq -c '{...}' lê o JSON do hook no stdin e monta um payload pequeno, de modo que o Echobell receba exatamente os campos que você quer, e não o documento inteiro do hook.
  • .cwd | split("/") | last transforma /home/me/code/api em api, para a notificação dizer qual projeto está pedindo.
  • .[0:200] trunca a mensagem final. O worker do Echobell limita o corpo das notificações a 1500 bytes, e a tela de bloqueio mostra bem menos que isso.
  • -m 10 dá ao curl um timeout de 10 segundos, para que um problema de rede nunca deixe o Claude Code esperando pelo seu hook.

O Echobell renderiza as chaves que você envia pelos templates do canal, e um canal novo não tem nenhum template que as leia — defina-os nas configurações do canal: template de título {{title}}, template de corpo {{body}}. Adicione {{project}} a qualquer um deles se quiser ver o nome do projeto, por exemplo {{title}} ({{project}}).

Passo 3 — Teste sem esperar um pedido de verdade

Rode o mesmo pipeline à mão, com um payload de hook falso:

echo '{"message":"O Claude precisa da sua permissão para usar o Bash","cwd":"/home/me/code/api","notification_type":"permission_prompt"}' \
  | jq -c '{title: "Claude precisa de permissão", body: .message, project: (.cwd | split("/") | last)}' \
  | curl -sS -m 10 -X POST -H 'Content-Type: application/json' -d @- "$ECHOBELL_CLAUDE_BLOCKED_URL"

Se o celular acender, o lado do Echobell está funcionando e qualquer problema restante está em como o Claude Code lê a configuração. No Claude Code, rode /hooks para confirmar que os hooks foram carregados; mudanças nas configurações feitas com uma sessão em andamento podem precisar do menu de hooks ou de um reinício para valer.

Passo 4 — Faça o canal de bloqueio tocar

Uma notificação push perde para o Não Perturbe. Um canal Calling se comporta como uma ligação recebida e atravessa o modo Foco do iOS, o que importa mais quando você começa uma tarefa longa e sai para o resto da noite. Se você só quer ser interrompido por alguns pedidos, filtre com uma condição de canal do Echobell sobre as variáveis que você envia, por exemplo project == "api", em vez de editar o hook. Para a lista completa de variáveis, veja a referência de condições.

Como evitar o excesso de notificações

Uma sessão movimentada pode disparar muitos eventos Stop — toda resposta termina com um. Três formas de preservar o sinal:

  • Não envie o Stop para um canal que toca. Concluir não é urgente; mantenha no Normal.
  • Use idle_prompt em vez de Stop se você só quer saber quando o Claude parou e está esperando por você, e não depois de cada resposta.
  • Restrinja por projeto com uma condição, para que um repositório de testes não notifique você de jeito nenhum.

Rodando o Claude Code remotamente ou em CI

A mesma abordagem funciona em ambientes na nuvem ou remotos, porque o hook é só uma requisição HTTPS de saída. Nada precisa estar acessível pela internet. Defina as duas variáveis de ambiente nos secrets do ambiente em vez do perfil do shell, e a notificação chega ao seu celular onde quer que a sessão rode.

Solução de problemas

Nada chega, e o teste manual também falha. Verifique se a variável da URL está definida no shell que inicia o Claude Code: echo "$ECHOBELL_CLAUDE_BLOCKED_URL". Uma variável vazia faz o curl falhar em silêncio.

O teste manual funciona, mas o hook não dispara. Confirme o matcher: permission_prompt e idle_prompt são distintos, e um matcher que não corresponde simplesmente nunca executa. Rode /hooks e confira se o JSON é válido — uma vírgula sobrando desativa os hooks do arquivo de configuração inteiro.

O corpo da notificação está em branco. O filtro do jq referenciou um campo que não existe para aquele evento. message existe na entrada de Notification; last_assistant_message existe na entrada de Stop. Use // para fornecer um valor padrão, como na configuração acima.

Dispara com frequência demais. Veja a seção acima — troque Stop por idle_prompt ou adicione uma condição.

Perguntas frequentes

Como receber uma notificação quando o Claude Code precisa de permissão?

Adicione um hook Notification com o matcher permission_prompt que envie um webhook para um canal. O Echobell transforma essa requisição em um push ou em um alerta em formato de ligação no seu celular.

Como saber quando o Claude Code termina uma tarefa?

Adicione um hook Stop. Ele roda quando o Claude termina de responder, e a entrada inclui last_assistant_message, que você pode usar como corpo da notificação.

A notificação consegue furar o Não Perturbe?

Sim, se o canal receptor for um canal Calling. Ele se comporta como uma ligação recebida, que o modo Foco do iOS deixa passar. Um push normal de qualquer app não passa.

Isso funciona no Claude Code na web ou em sessões remotas?

Sim. O hook só faz uma requisição HTTPS de saída, então funciona em qualquer lugar em que a sessão alcance a internet. Informe as URLs dos canais pelos secrets do ambiente.

É seguro colocar a URL do webhook no settings.json?

Prefira uma variável de ambiente, como mostrado acima, para que o token não seja commitado num repositório. Se ele vazar, crie um canal novo e aposente o antigo.

Conclusão

Dois canais, dois hooks e um pipeline jq | curl: um canal Calling ou Time Sensitive para permission_prompt e um canal Normal para Stop. Depois disso, você pode iniciar uma tarefa longa de um agente, sair da sala e ser chamado de volta só quando o agente realmente precisar de você.

Baixe o Echobell para iPhone ou instale pelo Google Play e rode o teste manual acima antes de confiar nele numa tarefa longa.

Leia também