Hooks ile Görev Tamamlama Bildirimi: Claude İşini Bitirince Sana Haber Versin

Stop Hook yapılandırarak Claude görevini bitirdiğinde masaüstü, Slack veya Telegram üzerinden otomatik bildirim alın


Claude Code bir görevi tamamlamak için genellikle birkaç dakika, hatta daha uzun süre harcıyor. Bir modülü refactor etmesini, test suite'i çalıştırmasını ya da bir yığın dosyayı işlemesini istiyorsun — sonra başka bir pencereye geçip kendi işine bakıyorsun. Sorun şu: ne zaman bitirdiğini bilmiyorsun.

Geri döndüğünde belki on dakika önce bitirmiştir, belki de bir onay penceresinde seni bekliyor olabilir.

Stop Hook ile Claude görevini tamamladığında (ya da müdahalene ihtiyaç duyduğunda) otomatik bildirim alabilirsin. Hangi pencerede, hangi cihazda olursan ol, bildirim doğrudan sana ulaşır.


Temel Mekanizma

Claude Code'da bir Stop olayı var — Claude her durduğunda tetiklenir; görev tamamlandığında, onay gerektiren bir hatayla karşılaşıldığında ya da kullanıcı girişi beklendiğinde.

{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "bash .claude/hooks/notify.sh"
          }
        ]
      }
    ]
  }
}

Hook, stdin üzerinden bir JSON alır. İçinde stop_reason (durma nedeni) ve stop_message (Claude'un son söylediği) bulunur. Bu bilgilere göre bildirim içeriğini özelleştirebilirsin.

stdin veri yapısı:

{
  "session_id": "xxx",
  "stop_reason": "end_turn",
  "stop_message": "重构完成,所有测试通过。"
}

Yöntem 1: Sistem Masaüstü Bildirimi (En Basit)

Linux'ta notify-send, macOS'ta osascript — harici bir servise gerek yok:

#!/bin/bash
input=$(cat)
reason=$(echo "$input" | jq -r '.stop_reason // "unknown"')
message=$(echo "$input" | jq -r '.stop_message // "Claude 已停止"' | head -c 200)

case "$(uname)" in
  Linux)
    notify-send "Claude Code" "$message" --urgency=normal
    ;;
  Darwin)
    osascript -e "display notification \"$message\" with title \"Claude Code\""
    ;;
esac

Avantajı: Sıfır yapılandırma, anında çalışır.
Dezavantajı: Sadece mevcut makinede alırsın — başka bir cihaza geçersen göremezsin.


Yöntem 2: Slack Webhook (Ekipler İçin Önerilir)

Slack Incoming Webhook ile bildirimi belirli bir kanala ya da özel mesaja gönder.

Ön Hazırlık:
1. Slack'in App yönetim sayfasından bir App oluştur
2. Incoming Webhooks'u etkinleştir ve Webhook URL'yi al
3. URL'yi SLACK_WEBHOOK_URL ortam değişkenine kaydet

#!/bin/bash
input=$(cat)
reason=$(echo "$input" | jq -r '.stop_reason // "unknown"')
message=$(echo "$input" | jq -r '.stop_message // "Claude 已停止"' | head -c 300)

webhook_url="${SLACK_WEBHOOK_URL}"
[[ -z "$webhook_url" ]] && exit 0

# 根据停止原因选 emoji
case "$reason" in
  end_turn)    emoji="✅" ;;
  user_input)  emoji="⏳" ;;
  *)           emoji="🔔" ;;
esac

payload=$(jq -n \
  --arg text "$emoji *Claude Code* | \`$reason\`
$message" \
  '{text: $text}')

curl -s -X POST "$webhook_url" \
  -H 'Content-Type: application/json' \
  -d "$payload" > /dev/null 2>&1 &

Sondaki & çok önemli — curl'ü arka planda çalıştırır, Claude'u bloke etmez.


Yöntem 3: Telegram Bot

Telegram Bot bireysel kullanım için ideal — ücretsiz, anlık ve bildirimler doğrudan telefonuna gelir.

Ön Hazırlık:
1. @BotFather üzerinden Bot oluştur ve Token'ı al
2. Chat ID'ni öğren (Bot'a bir mesaj gönder, sonra getUpdates API'sini çağır)
3. TELEGRAM_BOT_TOKEN ve TELEGRAM_CHAT_ID ortam değişkenlerini ayarla

#!/bin/bash
input=$(cat)
reason=$(echo "$input" | jq -r '.stop_reason // "unknown"')
message=$(echo "$input" | jq -r '.stop_message // "Claude 已停止"' | head -c 300)

token="${TELEGRAM_BOT_TOKEN}"
chat_id="${TELEGRAM_CHAT_ID}"
[[ -z "$token" || -z "$chat_id" ]] && exit 0

text="🤖 *Claude Code*
状态:\`$reason\`
$message"

curl -s "https://api.telegram.org/bot${token}/sendMessage" \
  -d chat_id="$chat_id" \
  -d text="$text" \
  -d parse_mode="Markdown" > /dev/null 2>&1 &

Yöntem 4: Sesli Uyarı (SSH Senaryolarında da İşe Yarar)

Aynı makinedeysen ama başka bir pencereye geçtiysen, bir uyarı sesi popup'tan çok daha etkili olabilir:

#!/bin/bash
input=$(cat)
reason=$(echo "$input" | jq -r '.stop_reason // "unknown"')

case "$(uname)" in
  Linux)
    paplay /usr/share/sounds/freedesktop/stereo/complete.oga 2>/dev/null &
    ;;
  Darwin)
    afplay /System/Library/Sounds/Glass.aiff &
    ;;
esac

Diğer yöntemlerle birleştirilebilir — yerelde ses çal + uzak cihaza bildirim gönder.


Tam Yapılandırma: Birden Fazla Bildirim Yöntemini Birleştir

Günlük kullanımda birden fazla yöntemi tek bir script'te birleştirmek en mantıklısı:

.claude/hooks/notify.sh:

#!/bin/bash
input=$(cat)
reason=$(echo "$input" | jq -r '.stop_reason // "unknown"')
message=$(echo "$input" | jq -r '.stop_message // "Claude 已停止"' | head -c 300)

# 根据原因选 emoji
case "$reason" in
  end_turn)    emoji="✅"; title="任务完成" ;;
  user_input)  emoji="⏳"; title="等待输入" ;;
  *)           emoji="🔔"; title="Claude 已停止" ;;
esac

# 1. 桌面通知(本地)
case "$(uname)" in
  Linux)  notify-send "Claude Code: $title" "$message" --urgency=normal ;;
  Darwin) osascript -e "display notification \"$message\" with title \"Claude Code: $title\"" ;;
esac

# 2. 声音提示
case "$(uname)" in
  Linux)  paplay /usr/share/sounds/freedesktop/stereo/complete.oga 2>/dev/null & ;;
  Darwin) afplay /System/Library/Sounds/Glass.aiff & ;;
esac

# 3. Slack(如果配了 Webhook)
if [[ -n "$SLACK_WEBHOOK_URL" ]]; then
  payload=$(jq -n --arg text "$emoji *$title*
$message" '{text: $text}')
  curl -s -X POST "$SLACK_WEBHOOK_URL" \
    -H 'Content-Type: application/json' \
    -d "$payload" > /dev/null 2>&1 &
fi

# 4. Telegram(如果配了 Bot)
if [[ -n "$TELEGRAM_BOT_TOKEN" && -n "$TELEGRAM_CHAT_ID" ]]; then
  curl -s "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \
    -d chat_id="$TELEGRAM_CHAT_ID" \
    -d text="$emoji *$title*
$message" \
    -d parse_mode="Markdown" > /dev/null 2>&1 &
fi

.claude/settings.json:

{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "bash .claude/hooks/notify.sh"
          }
        ]
      }
    ]
  }
}

Dikkat Edilmesi Gerekenler

Tüm ağ istekleri arka planda çalıştırılmalı

Bildirim script'indeki curl komutlarına mutlaka & ekleyerek arka planda çalıştır. Ağ yavaşsa veya zaman aşımı olursa Claude'un tüm oturumunu bloke eder. > /dev/null 2>&1 & eklemek standart pratiktir.

Stop, "başarıyla tamamlandı" demek değildir

stop_reason değeri end_turn genellikle görevin bittiği anlamına gelir, ama Claude'un bir sonraki adımda ne yapacağından emin olmaması da olabilir. Sadece gerçekten tamamlandığında bildirim almak istiyorsan, script'e filtre ekle:

[[ "$reason" != "end_turn" ]] && exit 0

Bildirim içeriğini kırp

Claude'un son mesajı çok uzun olabilir (kod blokları, uzun çıktılar). Slack veya Telegram'a göndermeden önce head -c 300 ile kırp, mesajın patlamasını önle.

Ortam değişkenlerini global yapılandırmada tut

Webhook URL ve Bot Token proje reposuna yazılmamalı. ~/.zshrc (veya ~/.bashrc) dosyasına koy ya da direnv ile yönet.


Sonuç

Yapılandırdıktan sonra çalışma şeklin değişir:

  1. Claude'a bir görev ver
  2. Başka bir pencereye/cihaza geç
  3. Claude bitirince → bildirim gelir
  4. Geri dön, sonuca bak, bir sonraki adıma geç

Terminale gözünü dikip beklemeye gerek yok, sürekli pencere değiştirip ilerlemeyi kontrol etmeye gerek yok. Claude çalışır, sen çalışırsın — bitince sana haber verir.