Konfigurasi Stop Hook agar Claude otomatis mengirim notifikasi via desktop, Slack, atau Telegram saat selesai bekerja
Claude Code sering butuh waktu beberapa menit atau bahkan lebih lama untuk menyelesaikan tugas. Kamu minta dia refactor sebuah modul, menjalankan test suite, atau memproses sekumpulan file — lalu pindah ke jendela lain untuk mengerjakan hal lain. Masalahnya: kamu tidak tahu kapan dia selesai.
Begitu kamu cek lagi, mungkin sudah selesai sepuluh menit yang lalu, atau malah sedang menunggu konfirmasi darimu.
Dengan Stop Hook, kamu bisa dapat notifikasi otomatis setiap kali Claude selesai mengerjakan tugas (atau butuh intervensimu). Entah kamu ada di jendela mana atau perangkat mana, notifikasi langsung sampai.
Claude Code punya event Stop — terpicu setiap kali Claude berhenti, entah karena tugas selesai, ada error yang perlu konfirmasi, atau menunggu input dari pengguna.
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "bash .claude/hooks/notify.sh"
}
]
}
]
}
}
Hook menerima JSON melalui stdin yang berisi stop_reason (alasan berhenti) dan stop_message (pesan terakhir Claude). Berdasarkan informasi ini, kamu bisa menyesuaikan isi notifikasi.
Struktur data stdin:
{
"session_id": "xxx",
"stop_reason": "end_turn",
"stop_message": "重构完成,所有测试通过。"
}
Linux pakai notify-send, macOS pakai osascript, tanpa layanan eksternal apa pun:
#!/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
Kelebihan: Tanpa konfigurasi, langsung jalan.
Kekurangan: Hanya bisa diterima di mesin yang sama — kalau pindah perangkat, tidak akan terlihat.
Gunakan Slack Incoming Webhook untuk mengirim notifikasi ke channel atau DM tertentu.
Persiapan:
1. Buat App di halaman manajemen App Slack
2. Aktifkan Incoming Webhooks dan dapatkan Webhook URL
3. Simpan URL tersebut di environment variable SLACK_WEBHOOK_URL
#!/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
# Pilih emoji berdasarkan alasan berhenti
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 &
Tanda & di akhir itu penting — agar curl berjalan di background dan tidak memblokir Claude.
Telegram Bot cocok untuk penggunaan pribadi — gratis, instan, dan notifikasinya langsung masuk ke HP.
Persiapan:
1. Buat Bot melalui @BotFather dan dapatkan Token
2. Dapatkan Chat ID-mu (kirim pesan ke Bot, lalu panggil API getUpdates)
3. Set environment variable TELEGRAM_BOT_TOKEN dan TELEGRAM_CHAT_ID
#!/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 &
Kalau kamu masih di mesin yang sama tapi pindah jendela, suara notifikasi bisa lebih efektif dari popup:
#!/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
Bisa dikombinasikan dengan opsi lain — putar suara di lokal + kirim notifikasi ke perangkat lain.
Untuk penggunaan sehari-hari, disarankan menggabungkan beberapa cara dalam satu script:
.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)
# Pilih emoji berdasarkan alasan
case "$reason" in
end_turn) emoji="✅"; title="任务完成" ;;
user_input) emoji="⏳"; title="等待输入" ;;
*) emoji="🔔"; title="Claude 已停止" ;;
esac
# 1. Notifikasi desktop (lokal)
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. Notifikasi suara
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 (jika Webhook sudah dikonfigurasi)
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 (jika Bot sudah dikonfigurasi)
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"
}
]
}
]
}
}
Semua request jaringan harus dijalankan di background
Setiap curl di script notifikasi wajib ditambahkan & agar berjalan di background. Kalau jaringan lambat atau timeout, bisa memblokir seluruh sesi Claude. Menambahkan > /dev/null 2>&1 & adalah praktik standar.
Stop bukan berarti "berhasil selesai"
stop_reason bernilai end_turn biasanya berarti tugas selesai, tapi bisa juga Claude sedang tidak yakin apa langkah selanjutnya. Kalau kamu hanya ingin dapat notifikasi saat benar-benar selesai, tambahkan filter di script:
[[ "$reason" != "end_turn" ]] && exit 0
Potong isi notifikasi
Pesan terakhir Claude bisa sangat panjang (berisi blok kode, output panjang). Sebelum dikirim ke Slack atau Telegram, potong dengan head -c 300 agar notifikasi tidak meledak.
Simpan environment variable di konfigurasi global
Webhook URL dan Bot Token jangan disimpan di repository proyek. Lebih baik taruh di ~/.zshrc (atau ~/.bashrc), atau kelola dengan direnv.
Setelah dikonfigurasi, cara kerjamu berubah:
Tidak perlu lagi memelototi terminal, tidak perlu bolak-balik cek progress. Claude bekerja, kamu juga bekerja — selesai, dia kasih tahu.