Bir Claude Code Oturumunda 30 Hook Olayı Tetiklenir. Sadece 3'ü Cevap Verebilir.

Claude Code hook olaylarının eksiksiz listesi, her birinin ne zaman tetiklendiği, hangi 15'inin engelleyebildiği ve çoğu hook çıktısını sessizce yutan stdout kuralı. Binlerce ajan oturumunda hook'ları üretimde çalıştırarak oluşturulmuş bir saha referansı.

İnsanlar Claude Code'a hook bağlarken iki arıza tekrar tekrar ortaya çıkıyor ve bu ikisi birbirine hiç benzemiyor.

Birincisi: bir hook ekliyorsunuz, hiçbir şey olmuyor. Hata yok, uyarı yok, günlük satırı yok. Hook basitçe hiç çalışmıyor.

İkincisi: hook belli ki çalışıyor, yan etkilerini diskte görebiliyorsunuz, ama ajan için yazdırdığı mesaj asla ulaşmıyor. Ajan, hook hiçbir şey söylememiş gibi davranıyor.

İkisi de aynı yerden geliyor. Hook sistemi, çoğu yazının ele aldığı bir avuç olaydan daha geniş ve daha az tekdüze, ve ajanla kimin konuşabileceğini belirleyen kurallar tahmin edeceğiniz kurallar değil. Bu, keşke elimizde olsaydı dediğimiz referans. AgentsRoom'u bu hook'ların üzerine inşa ediyoruz ve aşağıdaki her şey ya resmî referanstan alıntı ya da üretimde ölçülmüş.

30 olay var, altı değil

Çoğu rehber PreToolUse, PostToolUse, UserPromptSubmit, Stop, Notification ve SubagentStop olaylarını ele alıyor. Bu altısı gerçek ve faydalı işin çoğunu taşıyorlar. Aynı zamanda var olanların yalnızca beşte biriler.

Tam liste, gözlemledikleri şeye göre gruplanmış hâliyle:

GrupOlaylar
OturumSessionStart, SessionEnd, Setup
PromptUserPromptSubmit, UserPromptExpansion
AraçlarPreToolUse, PostToolUse, PostToolUseFailure, PostToolBatch
İzinlerPermissionRequest, PermissionDenied
TurStop, StopFailure
Alt ajanlar ve görevlerSubagentStart, SubagentStop, TaskCreated, TaskCompleted, TeammateIdle
BağlamPreCompact, PostCompact, InstructionsLoaded
OrtamFileChanged, CwdChanged, ConfigChange
Worktree'lerWorktreeCreate, WorktreeRemove
ArayüzNotification, MessageDisplay
MCP elicitationElicitation, ElicitationResult

Bir ajan oturumu sırasında tetiklenme sıralarına göre 30 Claude Code hook olayını gösteren zaman çizelgesi şeması: SessionStart'tan başlayıp UserPromptSubmit, PreToolUse, PostToolUse, Stop ve SessionEnd'e uzanan akış ve hangi olayların ajanı engelleyebildiği.

Tek bir oturumda olayların tetiklenme sırası. Araç bloğu her araç çağrısında bir kez, prompt bloğunun tamamı ise her turda bir kez tekrarlanır.

Bunlardan birkaçı sistemi düşünme biçiminizi değiştirir. PostToolUseFailure var, yani "araç çalıştı mı" dalı bir olaydır, bir payload'dan çıkarsadığınız bir şey değil. PostToolBatch, paralel araç çağrılarından oluşan bir grup tamamlandıktan sonra bir kez tetiklenir; linter'ı her düzenlemede bir kez değil de tek seferde çalıştırmanın doğru yeri burasıdır. InstructionsLoaded, CLAUDE.md okunduğunda tetiklenir ve ajanın gerçekten sizin sandığınız kuralları yüklediğini kontrol etmek için bir hook noktası verir.

Çoğu hook çıktısını yutan stdout kuralı

Bu sayfadaki en faydalı tek şey bu.

Çıkış kodu 0'da Claude Code, stdout'u JSON çıktı alanları için ayrıştırır. Ama o stdout'un ajana gösterilip gösterilmeyeceği olaya bağlıdır ve istisnalar kısa bir listedir. Referanstan:

Çoğu olayda stdout hata ayıklama günlüğüne yazılır ama dökümde gösterilmez. İstisnalar UserPromptSubmit, UserPromptExpansion ve SessionStart'tır; bu olaylarda stdout, Claude'un görebileceği ve üzerine hareket edebileceği bağlam olarak eklenir.

Otuz olaydan üçü. Bir PostToolUse hook'undan echo "warning: this migration is destructive" yapıp ajanın bunu okumasını beklerseniz, asla okumayacak. Metniniz hata ayıklama günlüğüne gitti.

Başka herhangi bir olaydan ajanın önüne metin koymanın tam olarak iki yolu var:

  1. 2 ile çıkın ve stderr'e yazın. Çıkış kodu 2'de Claude Code, stdout'u ve içindeki her türlü JSON'u yok sayar, stderr'i bir hata mesajı olarak ajana geri besler.
  2. 0 ile çıkın ve bir JSON nesnesi yazdırın: içinde hookSpecificOutput.additionalContext taşısın.

İlkindeki asimetriye dikkat edin. Çıkış 0, stdout'un önemli olduğu ve stderr'in olmadığı anlamına gelir. Çıkış 2, stderr'in önemli olduğu ve stdout'un tamamen atıldığı anlamına gelir. Bunu ters anlamak, bir hook'un tamamen doğru görünüp yine de dilsiz kalmasının sebebidir.

Başka herhangi bir çıkış kodu, engellemeyen bir hatadır. Döküm, stderr'in ilk satırıyla birlikte bir <hook name> hook error uyarısı gösterir, yürütme devam eder ve stderr'in tamamı hata ayıklama günlüğüne düşer.

Claude Code hook çıkış kodları şeması: çıkış 0, stdout'taki JSON'u ajana yalnızca üç olayda gönderir, çıkış 2 eylemi engeller ve stderr'i ajana gönderir, başka herhangi bir çıkış kodu ise hata ayıklama günlüğüne yazılan ve engellemeyen bir hatadır.

Çıkış koduna göre hangi kanalın ajana ulaştığı. Kesik çizgili yol, herkesin var sandığı ama var olmayan yoldur.

Tam olarak yarısı engelleyebilir

On beş olay, çıkış 2'de eylemi durdurur. On beşi bunu yok sayıp devam eder.

Engelleyebilir: PreToolUse, PermissionRequest, UserPromptSubmit, UserPromptExpansion, Stop, SubagentStop, TeammateIdle, TaskCreated, TaskCompleted, ConfigChange, PostToolBatch, PreCompact, Elicitation, ElicitationResult, WorktreeCreate.

Engelleyemez: PostToolUse, PostToolUseFailure, PermissionDenied, StopFailure, Notification, SubagentStart, SessionStart, Setup, SessionEnd, CwdChanged, FileChanged, PostCompact, WorktreeRemove, InstructionsLoaded, MessageDisplay.

Pratik sonuç: bir koruma bariyerinin yeri PreToolUse'dur, asla PostToolUse değil. PostToolUse, araç başarılı olduktan sonra tetiklenir. Orada 2 ile çıkmak yazma işlemini geri almaz, hasar diskte dururken sadece bir hata yazdırır. Bir rm -rf komutunu durdurmak istiyorsanız, bunu yapabileceğiniz tam olarak tek bir yer var.

PostToolUse engellemezken PostToolBatch'in engelleyebilmesi ikinci bir bakışı hak ediyor. Bu, grup seviyesindeki bir kontrolün paralel düzenlemeler diske indikten sonra bile turu durdurabileceği anlamına gelir; sistemin sunduğu, yazma sonrası vetoya en yakın şey budur.

Matcher'lar tam eşleşmedir, ta ki birdenbire olmayana kadar

matcher alanı, kendi karakterlerine göre değerlendirme stratejisini değiştirir ve hangi yolu seçtiğini size hiçbir şey söylemez.

MatcherŞu şekilde değerlendirilir
"*", "", ya da hiç yokher şeyle eşleşir
Yalnızca harfler, rakamlar, _, -, boşluklar, ,, |tam dize, ya da | veya , ile bölünen tam dizeler listesi
Başka herhangi bir şeysabitlenmemiş JavaScript düzenli ifadesi

Tuzak, sabitlenmemiş olmasında. Referans, düzenli ifadenin RegExp.prototype.test ile test edildiğini açıkça söylüyor; bu da değerin herhangi bir yerindeki eşleşmede başarılı olur. Yani Edit.*, hem Edit hem de NotebookEdit ile eşleşir. Tek bir aracı kastettiyseniz ^Edit$ yazın.

Yanlış şeyin hatasını ayıklamadan önce bilinmesi gereken, sürüme bağlı iki davranış:

  • Virgül ayırıcılar ve boşluk toleransı Claude Code v2.1.191 veya daha yenisini gerektirir.
  • Tireler, tam eşleşme karakter kümesine v2.1.195'te katıldı. Ondan önce code-reviewer gibi bir matcher sabitlenmemiş bir regex olarak ele alınıyordu, dolayısıyla senior-code-reviewer için de tetikleniyordu.

AgentsRoom'da kendi dosya atıfı hook'umuzu Write|Edit|MultiEdit|NotebookEdit ile sınırlıyoruz; bu, tam dize yolunda kalır ve yalnızca o dört araçla eşleşir, başka hiçbir şeyle değil. Kurduğumuz yaşam döngüsü hook'larının ise hiç matcher'ı yok, çünkü onlar bizi her zaman ilgilendiriyor.

Altı yer hook tanımlayabilir ve hepsi birleşir

İlk refleks bir öncelik sırası aramaktır. Böyle bir sıra yok ve asıl ilginç kısım da bu.

KonumKapsam
~/.claude/settings.jsontüm projeleriniz, makinenize özel
.claude/settings.jsontek proje, commit edilebilir
.claude/settings.local.jsontek proje, Claude Code tarafından gitignore'a alınır
Managed policy settingskuruluş genelinde, yönetici kontrolünde
Eklenti hooks/hooks.jsoneklenti etkin olduğu sürece
Skill ya da ajan frontmatter'ıbileşen aktif olduğu sürece

Referanstan:

Hook girdileri birbirinin yerine geçmek yerine ayar seviyeleri arasında birleşir: kullanıcı, proje ve yerel ayarlar, yönetilen hook'ları kaldırmadan kendi hook'larını ekler ve disableAllHooks ayarı, yönetilen ayarların dışından yönetilen hook'ları devre dışı bırakamaz.

Yani bir proje hook'u asla genel bir hook'un yerine geçmez, onun üstüne eklenir. Altı kaynak, hepsi toplamalı. Kullanıcı ayarlarınızda ve bir de projede tanımlanmış bir PostToolUse biçimlendiricisi her düzenlemede iki kez çalışır ve tek belirti, işlerin yavaş hissettirmesidir.

Hook tanımlayabilen altı Claude Code ayar konumunu gösteren şema: hepsi birbirinin yerine geçmek yerine toplamalı biçimde tek bir hook kümesinde birleşiyor.

Altı kaynak, tek bir birleşik küme. Burada hiçbir şey hiçbir şeyin yerine geçmez.

Bu aynı zamanda, bir aracın birinin projesine hook kurması için neden .claude/settings.local.json dosyasının doğru yer olduğunu açıklıyor. Proje kapsamındadır, Claude Code onu gitignore'a alır ve hiçbir CLI bayrağı olmadan yüklenir. AgentsRoom girdilerini oraya yazar; böylece kullanıcının commit ettiği .claude/settings.json dosyasına hiç dokunulmaz ve iş arkadaşları asla makineye özgü bir yol devralmaz.

Hook'ları üretimde çalıştırmak bize ne öğretti

AgentsRoom, ajan durumunu deterministik biçimde izlemek ve düzenlenen dosyaları doğru ajana atfetmek için açtığı her projeye hook kurar. Bazı şeyler ancak o ölçekte ortaya çıkıyor.

Bilinmeyen olay adları sessizce yok sayılır. Bu belgelerde yok ve biz buna güveniyoruz. Yükleyicimize yeni bir yaşam döngüsü olayı eklediğimizde, eski bir CLI kullanan kullanıcılar, ikili dosyalarının hiç duymadığı bir olay adını içeren bir settings.local.json alıyor. Hiçbir şey kırılmıyor, hiçbir uyarı çıkmıyor, girdi atlanıyor. Yükleyiciyi bir CLI sürümünden önce yayınlamayı güvenli kılan şey bu. Aynı zamanda, kaçınılmaz olarak, bir yazım hatasının hata yerine tam bir sessizlik üretmesinin sebebi de bu.

Bir alt ajanın içinde olduğunuzu agent_id sayesinde anlarsınız. Bu alan yalnızca hook bir alt ajan çağrısının içinde tetiklendiğinde bulunur. Bu, kulağa geldiğinden daha önemli: Stop, yalnızca ana ajan bittiğinde değil, bir alt ajan turunu bitirdiğinde de tetiklenir. Naif bir "Stop'ta oturumu tamamlandı olarak işaretle" kuralı, herhangi bir alt ajan ilk kez döndüğünde oturumun tamamını bitmiş sayar. Tur olaylarından agent_id taşıyanları tam olarak bu yüzden atlıyoruz.

Mevcut tur için transcript_path dosyasını okumayın. Referans, dökümün asenkron olarak yazıldığı ve bellekteki konuşmanın gerisinde kalabileceği konusunda uyarıyor; yani hook'unuz tetiklendiğinde en son mesajlar henüz orada olmayabilir. Stop ve SubagentStop, dosyayla yarışmak zorunda kalmayasınız diye last_assistant_message alanını alır.

Hook'lar tek güvenilir durum sinyalidir. Hook'lardan önce, bir ajanın düşündüğünü mü, beklediğini mi yoksa bitirdiğini mi anlamak için PTY'yi kazıyorduk. CLI, terminalin alternatif ekran tamponu üzerinden çizmeye başladığı anda bu bozuluyor; /tui fullscreen tam olarak bunu yapıyor. Hook'lar her çizim motorunda aynı şekilde tetikleniyor. Bir ajanı dışarıdan gözlemleyen bir şey inşa ediyorsanız, üzerine inşa edilecek katman budur ve ekran kazıma en iyi ihtimalle yedek çözüm olarak kalır.

async: true hiçbir şeye mal olmaz. Bir hook komutu async: true bildirebilir ve ajan onu beklemez. Bizim hook'umuz yerel bir uç noktaya 2 saniyelik bir üst sınırla POST atıp geri döner; alıcı uygulama kapalıyken bile ajanın tur gecikmesi etkilenmez. Hook'unuz yalnızca gözlemliyor ve hiçbir karar vermiyorsa, onu async yapın ve bedelini ödemeyi bırakın.

Bir hook'un terminale çöp yazmasına asla izin vermeyin. Betiğimiz, en üst seviye dahil olmak üzere her istisnayı yutar. Bir hook'tan gelen yakalanmamış bir traceback sadece sessizce başarısız olmaz, kullanıcının terminal oturumuna, işinin tam ortasına bir Python yığın izi yazdırır.

Zaman aşımları

Varsayılanlar cömert, cömert olmayan üç istisna dışında:

Hook türüVarsayılan zaman aşımı
command, http, mcp_tool600 s
prompt30 s
agent60 s
UserPromptSubmit (command, http, mcp_tool)30 s
MessageDisplay (command, http, mcp_tool)10 s
SessionEndtüm hook'lar arasında paylaşılan 1,5 s, daha uzun bir hook başına timeout değerine uyacak şekilde 60 s'ye kadar yükseltilir

İnsanları şaşırtan, SessionEnd bütçesidir. Bu, hook başına bir tahsis değil, paylaşılan bir bütçedir; yani açıkça yükseltmediğiniz sürece üç temizlik hook'u 1,5 saniyeyi aralarında paylaşır.

Kısa versiyon

  • 30 olay var. Altısı meşhur.
  • stdout ajana yalnızca UserPromptSubmit, UserPromptExpansion ve SessionStart olaylarında ulaşır. Diğer her yerde stderr ile birlikte çıkış 2 kullanın ya da JSON içinde additionalContext kullanın.
  • 15 olay çıkış 2'de engeller, 15'i bunu yok sayar. Koruma bariyerleri PreToolUse'a konur.
  • Matcher'lar, özel bir karakter onları sabitlenmemiş bir regex'e dönüştürene kadar tam dizedir.
  • Altı ayar kaynağı toplamalı biçimde birleşir. Hiçbir şey hiçbir şeyin yerine geçmez.
  • Yanlış yazılmış bir olay adı tamamen sessizce başarısız olur.

Bu olaylar hakkında akıl yürütmek yerine tetiklenmelerini izlemek istiyorsanız, biz tam olarak bunu inşa ettik: AgentsRoom, her hook tetiklenmesini ajan başına, proje başına, çalıştırma başına gösterir; onlarca paralel ajan ve alt ajan oturumları genelinde. Kendi ayarlarınızda yapılandırdığınız hook'lar tam yazıldığı gibi çalışmaya devam eder, çünkü AgentsRoom gerçek CLI'yi çalıştırır.

Okumaya devam et

AgentsRoom'u Indirin

Yapay zeka ajanlarınızı (Claude, Codex, Antigravity CLI, OpenCode, Aider, Grok Build, Mistral Vibe, Kimi Code) tüm projelerinizde tek bir pencereden çalıştırın.

ÜcretsizAgentsRoom'u Indir

Yardımcı uygulama: hareket halindeyken ajanlarinizi izleyin

Claude, Codex, Antigravity CLI veya başka bir AI sağlayıcı kullan.

Uzantıyı yükleyin
Chrome Web Store

Hataları ve istekleri doğrudan genel backlogunuza gönderin.

AgentsRoom'a kısa bir bakış.

Çoklu proje
Çoklu sağlayıcı
Çoklu ajan
Canlı durum
Diff ve commit
Mobil uygulama
Canlı önizleme
Ajan ekipleri
Tarayıcı otomasyonu
Backlog odaklı dev
Prompt kütüphanesi
Beceri kütüphanesi
Tüm özellikleri gör