Para enviar notificações do Claude Code para o Telegram, Slack ou Discord, crie um bot ou um incoming webhook no app e depois adicione um hook do Claude Code que envia uma mensagem curta para ele com curl. Um hook Notification cobre "o Claude precisa da sua permissão" e "o Claude está esperando", e um hook Stop cobre "o Claude terminou". O Telegram precisa de um token de bot e do seu chat ID; o Slack e o Discord precisam só de uma URL de webhook. O mesmo script funciona no Mac e no Linux, e uma versão curta em PowerShell cobre o Windows.
01Antes de começar: a mensagem e o segredo
Todo hook recebe JSON pela entrada padrão. Os campos úteis são hook_event_name, cwd (a pasta do projeto), message nos eventos Notification e last_assistant_message nos eventos Stop. Os exemplos abaixo transformam isso em uma linha como Claude needs you in my-app: Claude needs your permission to use Bash.
Tokens de bot e URLs de webhook são senhas: quem tiver uma pode postar como o seu bot. A documentação do Slack diz claramente para não compartilhar URLs de webhook nem fazer commit delas no controle de versão. Guarde-as em um arquivo separado que só você pode ler:
mkdir -p ~/.claude
touch ~/.claude/chat-notify.env
chmod 600 ~/.claude/chat-notify.env
02Telegram: um bot que manda mensagens para você
- No Telegram, abra um chat com o @BotFather, envie
/newbote siga as instruções. Ele responde com um token como123456789:AA.... - Abra um chat com o seu novo bot e mande qualquer mensagem, para que ele tenha permissão de responder.
- Descubra o seu chat ID. Acesse esta URL com o seu token e procure
"chat":{"id":na resposta:
curl "https://api.telegram.org/bot<TOKEN>/getUpdates"
- Coloque os dois valores em
~/.claude/chat-notify.env:
SERVICE=telegram
TELEGRAM_TOKEN=123456789:AA...
TELEGRAM_CHAT_ID=987654321
O método sendMessage do Telegram recebe chat_id e text (de 1 a 4.096 caracteres). Ele também aceita disable_notification=true, que entrega a mensagem sem som. O script usa isso nas mensagens de "terminou" e mantém o som nos pedidos de permissão.
03Slack: um incoming webhook
- Crie um app do Slack em api.slack.com/apps (ou abra um existente).
- Em Incoming Webhooks, ative Activate Incoming Webhooks.
- Clique em Add New Webhook to Workspace, escolha um canal e selecione Authorize.
- Copie a URL que começa com
https://hooks.slack.com/services/.
SERVICE=slack
SLACK_WEBHOOK_URL=https://hooks.slack.com/services/T000/B000/XXXX
Cada webhook posta em um único canal, escolhido na criação, e não dá para mudar o nome nem o ícone por mensagem. Um canal privado pequeno só seu funciona melhor, para que o alerta não se perca num canal movimentado.
04Discord: um webhook de canal
- No seu servidor, abra Server Settings, depois Integrations e depois Webhooks.
- Crie um webhook, escolha o canal e copie a URL.
SERVICE=discord
DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/1234/abcd
O endpoint execute-webhook do Discord recebe um corpo JSON com content (até 2.000 caracteres) e um username opcional para substituir o nome do webhook.
05O script do hook (Mac e Linux)
Salve isto como ~/.claude/chat-notify.sh e rode chmod +x ~/.claude/chat-notify.sh. Ele precisa de curl e jq (brew install jq ou apt install jq).
#!/bin/sh
. "$HOME/.claude/chat-notify.env"
input=$(cat)
event=$(printf '%s' "$input" | jq -r '.hook_event_name')
project=$(basename "$(printf '%s' "$input" | jq -r '.cwd')")
if [ "$event" = "Stop" ]; then
detail=$(printf '%s' "$input" | jq -r '(.last_assistant_message // "") | .[0:300]')
text="Claude finished in $project. $detail"
quiet=true
else
detail=$(printf '%s' "$input" | jq -r '.message // "Needs your attention"')
text="Claude needs you in $project: $detail"
quiet=false
fi
case "$SERVICE" in
telegram)
curl -s "https://api.telegram.org/bot$TELEGRAM_TOKEN/sendMessage" \
--data-urlencode "chat_id=$TELEGRAM_CHAT_ID" \
--data-urlencode "text=$text" \
--data-urlencode "disable_notification=$quiet" > /dev/null ;;
slack)
jq -n --arg t "$text" '{text: $t}' | curl -s -X POST \
-H 'Content-Type: application/json' --data @- "$SLACK_WEBHOOK_URL" > /dev/null ;;
discord)
jq -n --arg t "$text" '{content: $t, username: "Claude Code"}' | curl -s -X POST \
-H 'Content-Type: application/json' --data @- "$DISCORD_WEBHOOK_URL" > /dev/null ;;
esac
exit 0
Montar o JSON com jq -n --arg faz diferença: as respostas do Claude têm aspas, barras invertidas e quebras de linha, e colá-las à mão numa string JSON quebra a requisição.
Teste antes de conectar:
echo '{"hook_event_name":"Notification","cwd":"/tmp/demo","message":"Test"}' | ~/.claude/chat-notify.sh
06Adicione os hooks
Em ~/.claude/settings.json, dentro do objeto hooks existente, se houver:
{
"hooks": {
"Notification": [
{
"matcher": "permission_prompt|idle_prompt",
"hooks": [{ "type": "command", "command": "~/.claude/chat-notify.sh" }]
}
],
"Stop": [
{
"hooks": [{ "type": "command", "command": "~/.claude/chat-notify.sh", "async": true }]
}
]
}
}
Inicie uma nova sessão do Claude Code para carregar os hooks. idle_prompt e Stop se sobrepõem: Stop dispara assim que o Claude termina, e idle_prompt cerca de um minuto depois, se você não tiver digitado nada. Mantenha os dois ou tire um; o guia do ntfy explica os prós e contras.
07Windows (PowerShell)
Salve como %USERPROFILE%\.claude\chat-notify.ps1. Esta versão posta no Discord; para o Slack, troque o corpo por @{ text = $text } e mude a URL.
$url = 'https://discord.com/api/webhooks/1234/abcd'
$in = [Console]::In.ReadToEnd() | ConvertFrom-Json
$project = Split-Path $in.cwd -Leaf
if ($in.hook_event_name -eq 'Stop') { $text = "Claude finished in $project." }
else { $text = "Claude needs you in ${project}: $($in.message)" }
$json = @{ content = $text; username = 'Claude Code' } | ConvertTo-Json
Invoke-RestMethod -Method Post -Uri $url -ContentType 'application/json; charset=utf-8' `
-Body ([Text.Encoding]::UTF8.GetBytes($json)) | Out-Null
Entrada do hook:
{
"type": "command",
"shell": "powershell",
"command": "powershell -NoProfile -ExecutionPolicy Bypass -File \"$HOME\\.claude\\chat-notify.ps1\""
}
Dentro do WSL, use o script de Mac e Linux.
08O que saber sobre usar apps de chat como notificador
- O que você envia sai do seu computador. A mensagem de "terminou" inclui o começo da resposta do Claude. Num canal compartilhado do Slack ou do Discord, todo mundo nele pode ler. Remova
$detailse o seu código for privado. - Apps de chat agrupam e silenciam. Um workspace movimentado ou um servidor silenciado pode esconder o alerta. Um app de push dedicado como o ntfy (veja o guia do ntfy) tem menos chance de se perder.
- Hooks não sabem se você está na mesa. O
Stopposta toda vez.idle_promptepermission_promptsão o mais próximo de um filtro de "ausente" nativo.
09Onde o Claude Code Notifier se encaixa
Um webhook é uma boa forma de manter um log do que o Claude fez e, para uma equipe, pode ser a ferramenta certa. Para quem quer agir sobre o alerta, ele fica no meio do caminho: você lê que o Claude precisa de permissão e precisa voltar ao terminal para concedê-la. Um bot do Telegram até poderia receber respostas, mas você teria que escrever o hook que espera por elas e devolve uma decisão.
O Claude Code Notifier faz essa parte. Com um celular pareado, você permite uma vez, permite para a sessão ou nega um pedido de permissão, responde às perguntas de múltipla escolha do Claude e envia uma nova instrução quando o Claude termina, tudo pelo celular. Se você digitou nos últimos 30 segundos, o terminal pergunta normalmente e nada fica esperando no celular. É independente, não é feito pela Anthropic, e o ccn roda no Mac, Windows e Linux. Veja como ele se compara, a página do ccn e os preços.
10Perguntas frequentes
O Claude Code consegue postar no Slack sem um script?
O Claude Code tem hooks http que fazem POST do JSON do hook para uma URL, mas os webhooks do Slack e do Discord esperam um formato de corpo próprio (text ou content), então um hook http direto para eles falha. É preciso um pequeno script ou um relay no meio.
Como descubro meu chat ID do Telegram?
Mande uma mensagem para o seu bot e abra https://api.telegram.org/bot<TOKEN>/getUpdates. O número depois de "chat":{"id": é o chat ID. Para um grupo, adicione o bot ao grupo e mande uma mensagem lá primeiro.
Dá para responder ao Claude Code pelo Slack ou pelo Discord?
Não com um incoming webhook, que só publica mensagens. Para responder, você precisa de um hook que espere sua resposta e devolva uma decisão, e é exatamente para isso que existem as ferramentas de aprovação remota.
O hook deixa o Claude Code mais lento?
A entrada Stop usa "async": true, então o envio acontece em segundo plano. Os hooks de Notification já rodam em paralelo ao Claude sem bloqueá-lo.