Claude Code Stop hook'u, ana Claude agent'ı her yanıtını bitirdiğinde bir komut çalıştırır; bu da onu "bitti" bildirimi göndermek, sonucu loglamak veya kontrol çalıştırmak için doğru yer yapar. Claude'u yarıda kestiğinizde çalışmaz; API hatasıyla biten bir turda ise bunun yerine StopFailure tetiklenir. Hook, Claude'un son mesajını last_assistant_message içinde alır ve Claude'un durmak yerine devam etmesi için bir reason ile birlikte decision: "block" döndürebilir.
01Stop ne zaman tetiklenir, ne zaman tetiklenmez
Stop yalnızca bütün bir görev tamamlandığında değil, her turun sonunda tetiklenir. Claude Code "görev" diye bir kavram bilmez; yalnızca Claude'un yanıt vermeyi bıraktığını ve sizi beklediğini bilir. Kısa bir soru da bir Stop üretir, iki saatlik bir refactor da.
Şu durumlarda tetiklenmez:
- Esc'e bastığınızda veya turu başka şekilde yarıda kestiğinizde;
- tur, rate limit, aşırı yük veya kimlik doğrulama hatası gibi bir API hatası nedeniyle bittiğinde. Claude Code bu durumlarda, eşleştirme yapabileceğiniz bir
erroralanıyla (rate_limit,overloaded,server_errorve diğerleri)StopFailuretetikler; - bir subagent bitirdiğinde. O,
SubagentStop'tur.
Stop matcher desteklemez; eklediğiniz her matcher yok sayılır ve hook her turda çalışır.
02En basit Stop hook
Claude her bitirdiğinde bir komut çalıştırmak için bunu ~/.claude/settings.json dosyasına ekleyin. Bu örnek macOS'ta bir ses çalar:
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "afplay /System/Library/Sounds/Glass.aiff"
}
]
}
]
}
}
Mac, Windows ve Linux için masaüstü bildirim komutları için Claude Code bitirdiğinde nasıl bildirim alınır rehberine bakın. Bu rehberin geri kalanı, hook'un girdi ve çıktısıyla neler yapabileceğinizi anlatıyor.
03Hook'un aldığı veriler
Ortak alanlara (session_id, transcript_path, cwd, permission_mode, hook_event_name) ek olarak bir Stop hook'u şunları alır:
last_assistant_messageClaude'un bu turdaki son yanıtının metnistop_hook_activeBir Stop hook engellediği için Claude zaten devam ediyorsa truebackground_tasksArka plan shell'leri veya subagent'lar gibi hâlâ çalışan görevlersession_cronsBu oturumdaki zamanlanmış uyanmalar (örneğin /loop kaynaklı)Transcript dosyasını okumak yerine last_assistant_message kullanın. Transcript asenkron yazılır ve hook çalıştığında son mesajı henüz içermiyor olabilir.
background_tasks ve session_crons, oturumun gerçekten bitip bitmediğini ya da arka plandaki bir işin onu yeniden uyandırmasına kadar yalnızca duraklatılmış olduğunu söyler. Bir bildirim script'i "bitti" demeden önce ikisinin de boş olduğunu kontrol edebilir.
04Claude'un son mesajını bildirime ekleyin
Bu script (macOS ve Linux, jq gerektirir) Claude'un yanıtının başını gösterir ve arka planda hâlâ çalışan bir iş varsa sessiz kalır:
#!/bin/bash
# ~/.claude/hooks/notify-done.sh
input=$(cat)
# Skip if background tasks are still in flight
busy=$(jq '(.background_tasks // []) | length' <<<"$input")
[ "$busy" -gt 0 ] && exit 0
msg=$(jq -r '(.last_assistant_message // "Claude has finished")
| gsub("\\s+"; " ") | .[0:140]' <<<"$input")
if command -v osascript >/dev/null 2>&1; then
osascript -e 'on run argv' \
-e 'display notification (item 1 of argv) with title "Claude has finished"' \
-e 'end run' "$msg"
elif command -v notify-send >/dev/null 2>&1; then
notify-send "Claude has finished" "$msg"
fi
exit 0
Kaydedin, chmod +x ~/.claude/hooks/notify-done.sh komutunu çalıştırın ve hook'u bu dosyaya yönlendirin:
{
"hooks": {
"Stop": [
{
"hooks": [{ "type": "command", "command": "~/.claude/hooks/notify-done.sh" }]
}
]
}
}
Script her zaman 0 ile çıkar. Bu önemlidir: Stop için 2 çıkış kodu "durma" anlamına gelir; yani yanlışlıkla 2 ile çıkan bir bildirim script'i Claude'un çalışmaya devam etmesine yol açar.
05Claude'un devam etmesini sağlamak
Stop, engelleme yapabilen event'lerden biridir. Durmayı engellemek, Claude'un verdiğiniz gerekçeyi bir sonraki talimat olarak kullanıp tura devam etmesi demektir. Bunu iki şekilde yapabilirsiniz:
2ile çıkın; Claude stderr çıktınızı gerekçe olarak alır; ya da0ile çıkın ve JSON yazdırın:
{
"decision": "block",
"reason": "The test suite is failing. Run npm test, fix the failures, then finish."
}
Hook bir hata bildirmek yerine yönlendirme yapıyorsa hookSpecificOutput.additionalContext de konuşmayı sürdürür, ancak transcript bunu hook hatası olarak değil Stop hook geri bildirimi olarak etiketler:
{
"hookSpecificOutput": {
"hookEventName": "Stop",
"additionalContext": "Please run the test suite before finishing"
}
}
Sonsuz döngüden kaçınmak
Her zaman engelleyen bir Stop hook, Claude'un hiç durmasına izin vermez. Sizi iki şey korur:
- Claude bir Stop hook yüzünden zaten devam ediyorsa
stop_hook_activetrueolur. Bunu kontrol edip erkenden çıkın. - Stop hook'ları arada hiçbir tool çağrısı olmadan art arda sekiz kez engellediğinde Claude Code turu yine de sonlandırır. Bu sınırı
CLAUDE_CODE_STOP_HOOK_BLOCK_CAPortam değişkeniyle yükseltebilirsiniz.
İşte Claude'a başarısız testleri bir kez düzelttiren, ardından durmasına izin veren bir hook:
#!/bin/bash
# ~/.claude/hooks/tests-must-pass.sh
input=$(cat)
[ "$(jq -r '.stop_hook_active' <<<"$input")" = "true" ] && exit 0
if ! npm test --silent >/dev/null 2>&1; then
jq -nc '{decision: "block", reason: "npm test is failing. Fix the failures, then finish."}'
fi
exit 0
Hook'lar oturumun çalışma dizininde çalışır, yani npm test projenizde çalışır. Kontrolleri hızlı tutun: varsayılan olarak bir command hook 600 saniyeye kadar çalışabilir ve Claude onu bekler.
Script yazmadan Claude'un bir hedefe doğru çalışmaya devam etmesini istiyorsanız, Claude Code'un yerleşik /goal komutu sizin için oturuma özel bir Stop hook kurar.
06Hatalar için de bildirim
API hataları Stop'u atladığından, "bitti" bildirimi Claude'un rate limit yüzünden vazgeçtiğini size söylemez. Bundan haberdar olmak istiyorsanız aynı script'i StopFailure altına da ekleyin. Çıktısı ve exit code'u yok sayılır, bu yüzden yalnızca bildirim gönderebilir veya log tutabilir. StopFailure için last_assistant_message, "API Error: Rate limit reached" gibi hata metnini içerir.
07Claude Code Notifier'ın yeri
Bir push servisini çağıran Stop hook, siz uzaktayken Claude'un işini bitirdiğini öğrenmenin gayet iyi bir yoludur. Bunu kendiniz kurmak istiyorsanız ntfy rehberi iyi bir başlangıçtır.
Claude Code Notifier da aynı Stop hook'unu kullanır, tek bir farkla: geri yanıt gönderebilir. Ücretsiz komut satırı aracı ccn, Mac, Windows ve Linux üzerinde çalışır ve tek başına masaüstü bildirimi gösterir. iPhone veya Android uygulamasını eşleştirdiğinizde, bir tur biter bitmez "Claude işini bitirdi" push bildirimi alırsınız ve sonraki talimatı telefondan yazabilirsiniz. ccn bunu Stop hook'undan Claude'un sonraki talimatı olarak döndürür; böylece siz klavyenin başında olmadan oturum devam eder. Son 30 saniye içinde yazı yazdıysanız telefon beklenmez. Bağımsız bir araçtır ve Anthropic tarafından geliştirilmemiştir. Bu iş akışı için uzun görevlerde bilgisayardan uzaklaşma rehberine, kurulum için ccn sayfasına bakın.
08SSS
Stop hook, Claude tüm görevi bitirdiğinde mi yoksa her yanıttan sonra mı çalışır?
Her yanıttan sonra. Stop, isteğin boyutu ne olursa olsun ana agent yanıtını her bitirdiğinde tetiklenir. Planlanmış başka iş olup olmadığını bilmeniz gerekiyorsa input'taki background_tasks ve session_crons alanlarını kontrol edin.
Stop hook'um neden tetiklenmedi?
Turu yarıda kesmiş olabilirsiniz, bu durumda Stop atlanır; ya da tur bir API hatasıyla bitmiştir ve onun yerine StopFailure tetiklenir. Bunlar değilse /hooks çıktısında hook'unuzun listelendiğini ve script'in çalıştırılabilir olduğunu kontrol edin. Gerisi için sorun giderme kontrol listesine bakın.
Stop hook'um çalıştıktan sonra Claude neden çalışmaya devam ediyor?
Hook'unuz durmayı engelliyor: ya 2 koduyla çıkıyor ya da decision: "block" yazdırıyor. Yalnızca bildirim gönderen bir hook'un her zaman 0 ile çıktığından ve engelleyen her hook'un önce stop_hook_active değerini kontrol ettiğinden emin olun.
Hook içinde Claude'un son yanıtını nasıl alırım?
stdin'den gelen JSON'daki last_assistant_message alanını okuyun, örneğin jq -r '.last_assistant_message' ile. transcript_path'e güvenmeyin: Stop tetiklendiğinde dosya son mesajı henüz içermiyor olabilir.
Stop ile SubagentStop arasındaki fark nedir?
Stop ana agent içindir. SubagentStop bir subagent bittiğinde tetiklenir, agent türüne göre eşleşir ve aynı engelleme alanlarını destekler. "Claude işini bitirdi" bildiriminin yeri Stop'tur.