إشعارات تلقائية عند انتهاء المهام باستخدام Hooks في Claude

إعداد Stop Hook لإرسال إشعارات تلقائية عبر سطح المكتب أو Slack أو Telegram عند انتهاء Claude من المهمة


تنفيذ المهام في Claude Code يستغرق أحيانًا عدة دقائق أو أكثر. تطلب منه إعادة هيكلة وحدة برمجية، أو تشغيل مجموعة اختبارات، أو معالجة دفعة من الملفات — ثم تنتقل إلى نافذة أخرى لتعمل على شيء آخر. المشكلة: لا تعرف متى انتهى.

تعود لتجد أنه ربما أنهى العمل منذ عشر دقائق، أو ربما توقف عند نافذة تأكيد ينتظر ردك.

باستخدام Hook من نوع Stop، يمكنك تلقي إشعار تلقائي عندما ينتهي Claude من المهمة أو يحتاج تدخلك. الإشعار يصلك أينما كنت — في أي نافذة أو على أي جهاز.


آلية العمل

يوفر Claude Code حدثًا يُسمى Stop — يُطلَق في كل مرة يتوقف فيها Claude، سواء أكمل المهمة، أو واجه خطأ يحتاج تأكيدًا، أو ينتظر إدخالًا من المستخدم.

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

يتلقى الـ Hook بيانات JSON عبر stdin تتضمن stop_reason (سبب التوقف) وstop_message (آخر رسالة من Claude). بناءً على هذه المعلومات، يمكنك تخصيص محتوى الإشعار.

هيكل بيانات stdin:

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

الطريقة الأولى: إشعارات سطح المكتب (الأبسط)

على Linux استخدم notify-send، وعلى macOS استخدم osascript، دون الحاجة لأي خدمة خارجية:

#!/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

المميزات: لا يحتاج أي إعداد، جاهز للاستخدام فورًا.
العيوب: الإشعار يظهر فقط على الجهاز الحالي، ولن تراه إذا انتقلت لجهاز آخر.


الطريقة الثانية: Slack Webhook (مُوصى به للفِرَق)

استخدم Slack Incoming Webhook لإرسال الإشعارات إلى قناة محددة أو كرسالة خاصة.

المتطلبات المسبقة:
1. أنشئ تطبيقًا في صفحة إدارة تطبيقات Slack
2. فعّل Incoming Webhooks واحصل على رابط الـ Webhook
3. خزّن الرابط في متغير البيئة 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

# 根据停止原因选 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 &

الرمز & في نهاية السطر مهم — يجعل curl يعمل في الخلفية دون أن يعطّل Claude.


الطريقة الثالثة: Telegram Bot

بوت Telegram خيار ممتاز للاستخدام الشخصي: مجاني وفوري، والإشعارات تصل مباشرة إلى هاتفك.

المتطلبات المسبقة:
1. أنشئ بوتًا عبر @BotFather واحصل على التوكن
2. احصل على Chat ID الخاص بك (أرسل رسالة للبوت ثم استدعِ API الـ getUpdates)
3. عيّن متغيرات البيئة TELEGRAM_BOT_TOKEN و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 &

الطريقة الرابعة: تنبيه صوتي (مفيد أيضًا عبر SSH)

إذا كنت على نفس الجهاز لكنك انتقلت لنافذة أخرى، صوت تنبيه قصير أكثر فعالية من الإشعار البصري:

#!/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

يمكنك دمجه مع الطرق الأخرى — تشغيل صوت محليًا + إرسال إشعار عن بُعد.


الإعداد الكامل: دمج طرق إشعار متعددة

في الاستخدام العملي، يُفضَّل جمع عدة طرق في سكريبت واحد:

.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"
          }
        ]
      }
    ]
  }
}

ملاحظات مهمة

جميع طلبات الشبكة يجب أن تعمل في الخلفية

أي أمر curl في سكريبت الإشعارات يجب أن ينتهي بـ & ليعمل في الخلفية. إذا كانت الشبكة بطيئة أو انتهت المهلة، سيتعطل Claude بالكامل. إضافة > /dev/null 2>&1 & هي الممارسة المعتادة.

التوقف لا يعني بالضرورة "إتمام ناجح"

قيمة stop_reason التي تساوي end_turn تعني عادةً أن المهمة اكتملت، لكنها قد تعني أيضًا أن Claude غير متأكد من الخطوة التالية. إذا أردت تلقي الإشعار فقط عند الانتهاء الفعلي، أضف فلترًا في السكريبت:

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

اقطع محتوى الإشعار

آخر رسالة من Claude قد تكون طويلة جدًا (تحتوي كتل برمجية أو مخرجات ضخمة). قبل إرسالها إلى Slack أو Telegram، استخدم head -c 300 لاقتطاعها وتجنب رسائل متضخمة.

متغيرات البيئة يُفضَّل وضعها في الإعدادات العامة

روابط Webhook وتوكنات البوت لا يجب أن تُحفَظ في مستودع المشروع. يُفضَّل وضعها في ~/.zshrc (أو ~/.bashrc)، أو إدارتها باستخدام direnv.


النتيجة

بعد هذا الإعداد، يتغير أسلوب عملك:

  1. تُسند مهمة لـ Claude
  2. تنتقل إلى نافذة أو جهاز آخر
  3. ينتهي Claude ← يصلك إشعار فورًا
  4. تعود لمراجعة النتائج وتتابع العمل

لا حاجة لمراقبة الطرفية، ولا للتبديل المتكرر بين النوافذ للاطمئنان على التقدم. Claude يعمل وأنت تعمل، وعندما ينتهي يُعلمك.