Claude Code Hook Yapısı ve Çalışma Mantığı
Claude Code hook mekanizmasının çalışma prensiplerini, tetiklenen olayları ve exit code 2 durumunun araç çağrılarını nasıl iptal ettiğini teknik detaylarıyla inceleyin.
Claude Code hook nedir
Claude Code hook'ları, Claude Code'un kendi yaşam döngüsü içindeki belirli noktalarda otomatik olarak çalıştırdığı kabuk komutlarıdır. Bir hook ile kural dosyası arasındaki temel fark budur. CLAUDE.md içindeki bir talimat tavsiye niteliğindedir ve model bunu bağlamındaki diğer tüm verilerle birlikte değerlendirir. Hook ise koddur; model kabul etse de etmese de çalışır. Eğer ajanınız iki kez belirttiğiniz biçimlendiriciyi (formatter) atlamaya devam ediyorsa, daha katı bir talimata ihtiyacınız yoktur. Bir hook'a ihtiyacınız vardır.
Mekanizma oldukça basittir. Bir ayar dosyasında bir olay adı altında bir komut tanımlarsınız. O olay tetiklendiğinde, Claude Code komutunuzu çalıştırır ve olay verilerini standart girdi (stdin) üzerinden JSON (JavaScript object notation) formatında yazar. Komutunuz bu veriyi okur, işlemini gerçekleştirir ve bir çıkış durumu (exit status) ile yanıt verir. Bir PreToolUse hook'undan dönen 2 çıkış kodu, araç çağrısını çalışmadan iptal eder ve betiğinizin standart hata (stderr) çıktısına yazdığı her şey, neden olarak modele geri iletilir.
Buradaki olay adları ve alan adları, Ağustos 2026 itibarıyla 2.1.232 sürümü için kontrol edilmiş olan Claude Code hooks referansı kaynağından alınmıştır. Bu arayüz hızla değiştiğinden, bu yazı da dahil olmak üzere herhangi bir blog gönderisinden JSON kopyalamadan önce kendi sürümünüz için referansı kontrol edin. Kendi yapılandırmanızı claude --version ile yazdırabilirsiniz.
Hook yapılandırmasının konumu
Hook, bir ayar dosyasındaki JSON bloğudur. Bir hook, altı farklı konumda bulunabilir ve dosyanın kapsamı, hook'un kapsamını belirler.
~/.claude/settings.json: makinenizdeki her proje için geçerlidir, başkalarını etkilemez..claude/settings.json: tek bir proje için geçerlidir; repoya commit edildiğinden, projeyi klonlayan herkes bu hook'u alır..claude/settings.local.json: tek bir proje için geçerlidir, yalnızca sizin makinenizde çalışır.- Yönetilen ilke ayarları: organizasyon genelinde, bir yönetici tarafından belirlenir.
hooks/hooks.json: bir eklenti içinde yer alır, eklenti etkin olduğu sürece çalışır.- Yetenek veya alt aracı ön bilgisi (frontmatter), ilgili bileşen aktif olduğu sürece çalışır.
Bu dosyalardaki hook girdileri birbirinin üzerine yazmak yerine birleştirilir. Bir proje ayar dosyası, hook'larını kullanıcı ayarlarınızdakilerin yerine geçmek yerine onlara ekler; böylece tek bir olay, farklı dosyalardan gelen birden fazla hook'u barındırabilir. "disableAllHooks": true ayarı, bir istisna dışında hepsini devre dışı bırakır: yönetilen ilke ayarlarından gelen hook'lar, bu ayar yönetilen ayarlarda da uygulanmadığı sürece çalışmaya devam eder.
Şu anda kayıtlı olan her hook'u, olay bazında gruplanmış, kaynak dosyası ve eşleştiricisiyle birlikte listelemek için bir oturum içinde /hooks komutunu çalıştırın. Menü salt okunurdur; bu nedenle bir hook'u değiştirmek için ayar dosyasını düzenlemeniz gerekir. Dosya izleyici (file watcher), genellikle yeniden başlatmaya gerek kalmadan yapılan düzenlemeyi algılar.
Claude Code kanca (hook) olayları nelerdir
Sürüm 2.1.232, SessionStart ile SessionEnd arasında; sıkıştırma (compaction), alt aracılar (subagents), çalışma ağaçları (worktrees) ve yapılandırma dosyalarını kapsayan otuz bir adet olay listeler. Sunucu işleri bunların bir kısmını kullanır.
PreToolUse: bir araç çağrısı yürütülmeden önce. Engelleyici (block) olabilen tek olay budur.PostToolUse: bir araç çağrısı başarıyla tamamlandıktan sonra.PostToolUseFailureise başarısız olduğunda tetiklenir; bu nedenle her sonucu görmesi gereken bir kancanın her ikisine de ihtiyacı vardır.PermissionRequest: bir araç çağrısı izin kararı gerektirdiğinde; bu, onay isteminin görüneceği andır.UserPromptSubmit: bir istem gönderdiğinizde, Claude onu işlemeden önce. Bu kancanın stdout'a yazdırdığı her şey modelin bağlamına eklenir.SessionStartveSessionEnd: bir oturumun her iki ucunda.SessionStartayrıcacompacteşleştirici değeri altında sıkıştırma işleminden sonra tetiklenir.Stop: Claude yanıt vermeyi bitirdiğinde. Bu, tamamlanan görev başına değil, tur başına bir kez gerçekleşir.
Her grup, kancanın hangi durumlarda çalışacağını belirleyen bir matcher taşır. Araç olaylarında bu, araç adına göre filtreleme yapar; dolayısıyla "Edit|Write" yalnızca dosya düzenlemelerinde tetiklenir, başka hiçbir şeyde tetiklenmez. Eşleştiriciler büyük/küçük harfe duyarlıdır. Boş bir eşleştirici her durumda tetiklenir. Bir MCP (model context protocol) sunucusundan gelen araçlar mcp__<server>__<tool> olarak adlandırılır; bu nedenle "mcp__github__.*" şeklindeki bir eşleştirici, tek bir sunucunun araçlarını yakalar ve diğerlerini olduğu gibi bırakır.
Stop kancaları, yazmadan önce bilinmesi gereken bir tuzağa sahiptir. Engelleyici bir Stop kancası, modeli tekrar çalışmaya gönderir ve Claude Code, sekiz ardışık engellemeden sonra kancayı geçersiz kılar. Kanca girdisinden stop_hook_active alanını okuyun ve true olduğunda 0 koduyla çıkış yapın; aksi takdirde kancanız bu sınıra ulaşana kadar döngüye girecektir.
Bir kancanın stdin üzerinden aldığı veriler
Claude npm test işlemini çalıştırmak üzereyken, Bash üzerindeki bir PreToolUse kancası stdin üzerinden şu verileri okur:
{
"session_id": "abc123",
"cwd": "/home/deploy/myproject",
"hook_event_name": "PreToolUse",
"tool_name": "Bash",
"tool_input": {
"command": "npm test"
}
}Her olay session_id, cwd, permission_mode, transcript_path ve hook_event_name verilerini taşır. Araç olayları ise tool_name, tool_input ve tool_use_id bilgilerini ekler. Diğer olaylar kendi alanlarını taşır: UserPromptSubmit, prompt metnini alır; SessionStart ise startup, resume, clear, compact veya fork değerlerinden oluşan bir source alır.
jq, bu veriyi bir shell betiği içinde okumanın standart yoludur ve minimal bir sunucu imajında yüklü gelmeyebilir. Ubuntu ve Debian üzerinde öncelikle sudo apt install -y jq komutu ile kurulumunu yapın.
Çıkış durumunun devam eden araç çağrısı üzerindeki etkisi
Üç olası sonuç vardır.
- Çıkış 0, kancanızın (hook) herhangi bir itirazı olmadığı anlamına gelir.
PreToolUseüzerinde bu onaylandığı anlamına gelmez; normal izin akışı çalışmaya devam eder.UserPromptSubmitveSessionStartüzerinde ise stdout, modelin bağlamına eklenir. - Çıkış 2,
PreToolUsedahil olmak üzere engellenebilir olaylarda işlemi durdurur ve stderr, modele gösterilen gerekçe haline gelir.PostToolUsegibi engellenemeyen olaylarda ise engelleme göz ardı edilir, ancak stderr yine de geri bildirim olarak modele iletilir. - Diğer tüm çıkış kodları, engelleme yapmayan hatalardır. İşlem devam eder. Kayıtta,
Failed with non-blocking status code:metninden sonra stderr'in ilk satırını içeren bir kanca hata bildirimi görünür.
Engelleme veya sessiz kalma dışında bir işlem için çıkış 0 değerini döndürün ve stdout'a bir JSON nesnesi yazdırın. Bir PreToolUse kancası, permissionDecision ile karar verir:
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "Database drops go through a migration, not through the agent."
}
}"allow" etkileşimli istemi atlar, "deny" çağrıyı iptal eder ve gerekçeyi modele gönderir, "ask" ise istemi normal şekilde gösterir. Her kanca için tek bir stil seçin. Çıkış 2 ile stdout üzerinde bir JSON kararı kullanmak, sonucunu kontrol etmeniz gereken bir duruma yol açar.
Birden fazla kanca aynı olayla eşleştiğinde, bunlar paralel olarak çalışır ve her biri tamamlanana kadar devam eder. Bir kancadan gelen deny, diğerlerini durdurmaz; bu nedenle bir güvenlik kancası aynı çağrıyı reddederken, bir günlükleme kancası kendi satırını yazmaya devam eder. Claude Code daha sonra yanıtları birleştirir ve reddetme, erteleme, sorma, izin verme sırasına göre en kısıtlayıcı olanı uygular.
Örnek 1: yıkıcı bir komutu çalışmadan önce engelleme
Bunu projenizde .claude/hooks/block-destructive.sh olarak kaydedin:
#!/bin/bash
# Deny a Bash tool call whose command matches a banned pattern.
INPUT=$(cat)
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty')
for pattern in 'rm -rf /' 'mkfs' 'dd if=' 'DROP TABLE'; do
if printf '%s' "$COMMAND" | grep -qiF -- "$pattern"; then
echo "Blocked by policy: the command matches '$pattern'. A human runs this one." >&2
exit 2
fi
done
exit 0Çalıştırılabilir hale getirin ve ardından .claude/settings.json içindeki PreToolUse üzerinde kaydedin:
chmod +x .claude/hooks/block-destructive.sh{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/block-destructive.sh",
"timeout": 10,
"statusMessage": "Checking the command against policy"
}
]
}
]
}
}Kendi girdisinde çöken bir kanca (hook) korumasız kalacağı için, güvenmeden önce betiği manuel olarak test edin:
echo '{"tool_name":"Bash","tool_input":{"command":"rm -rf /var/lib/postgresql"}}' \
| .claude/hooks/block-destructive.sh
echo $?stderr üzerinde Blocked by policy: satırını ve 2 çıkış kodunu görmelisiniz. ls -la gibi zararsız bir komut gönderdiğinizde ise herhangi bir çıktı görmemeli ve 0 çıkış kodunu almalısınız. Bir oturumda, reddedilen çağrı gerekçe olarak mesajınızla birlikte dökümde görünür; model bu mesajı okur ve uyum sağlar.
Bir özellik, bu işlemi yapmaya değer kılar: PreToolUse kancaları, izin modu denetiminden önce ve her izin modunda tetiklenir; bu nedenle bir engelleme, bypassPermissions altında bile geçerliliğini korur. Bir kancayı, istemlerin kısıldığı ancak kancanın hala tetiklendiği Claude Code otomatik modu ve izin ayarları ile birlikte kullanışlı kılan şey budur.
Bunun ne olduğu konusunda dürüst olun. Bir komut dizisi üzerinde desen eşleştirme (pattern matching), bir ajanın dikkatsizliğine karşı bir güvenlik önlemidir; ajanın zekice davranmasına karşı bir sınır değildir, çünkü aynı komut grep tarafından asla görülmeyen bir biçimde yazılabilir. Katı kurallar, izin sistemine ve sürecin altında çalıştığı hesaba aittir.
Örnek 2: her düzenlemeden sonra biçimlendirme ve lint işlemi
PostToolUse, Edit|Write eşleştiricisi ile birlikte herhangi bir dosya düzenleme aracından sonra çalışır. Bunu .claude/hooks/after-edit.sh olarak kaydedin:
#!/bin/bash
# Format the edited file, then report lint failures back to the model.
INPUT=$(cat)
FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
[ -z "$FILE" ] && exit 0
case "$FILE" in
*.py)
ruff format "$FILE" >/dev/null 2>&1
if ! ruff check "$FILE" >&2; then
exit 2
fi
;;
*.sh)
if ! shellcheck "$FILE" >&2; then
exit 2
fi
;;
esac
exit 0{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/after-edit.sh",
"timeout": 60
}
]
}
]
}
}Claude'dan bir Python dosyasına kötü girintilenmiş bir fonksiyon eklemesini isteyin ve ardından dosyayı açın. Dosya biçimlendirilmiş olarak geri dönecektir. Bu, kancanın (hook) çalıştığının kanıtıdır; çünkü başarılı bir kanca işleminde konuşma ekranında hiçbir şey görünmez.
Buradaki exit 2 komutu hiçbir şeyi geri almaz. PostToolUse, araç zaten çalıştırıldıktan sonra tetiklenir, bu nedenle düzenleme her halükarda diske yazılmıştır. exit 2 kullanmanın avantajı, ruff check çıktısının modele geri bildirim olarak ulaşmasıdır; böylece model bir sonraki adıma geçmek yerine az önce oluşturduğu hatayı düzeltir. Commit zamanında fark ettiğiniz bir lint hatası ile ajanın aynı turda onardığı hata arasındaki fark budur.
Burada iki eşleştirici sınırı önemlidir. Edit|Write, bir shell komutu tarafından değiştirilen dosyaları görmez ve Claude dosyaları yeterince sık bir şekilde Bash aracılığıyla yazar; bu nedenle söz konusu boşluk gerçek bir sorundur. Çağrı başına kapsama alanı için Bash eşleşmesini de kullanın ve betiğin değiştirilen dosyaları git status --porcelain ile listelemesini sağlayın. Tur başına kapsama alanı için ise tarama işlemini bir Stop kancasına yerleştirin.
Örnek 3: denetim için her araç çağrısını günlüğe kaydetme
PostToolUse üzerindeki boş bir eşleştirici, her araç çağrısında tetiklenir. Kaydı ev dizinindeki bir dosyaya yazmak yerine sistem günlüğüne göndermek, kaydın aracın kendi kabuğunun erişim alanı dışında kalmasını sağlar:
{
"hooks": {
"PostToolUse": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "jq -c '{time: now|todate, session: .session_id, cwd: .cwd, tool: .tool_name, input: .tool_input}' | logger -t claude-code -p local0.info"
}
]
}
]
}
}Kayıtları journalctl -t claude-code -o cat | tail -n 5 ile okuyun. Her araç çağrısı için bir JSON satırı görmelisiniz; en yeni kayıtlar en altta yer alır. Hiçbir şey görünmüyorsa kanca çalışmamıştır; aşağıdaki sorun giderme bölümü bu durumu ele almaktadır.
Başarısız olan çağrıları yakalamak için aynı bloğu PostToolUseFailure altına ekleyin; çünkü PostToolUse yalnızca başarı durumunda tetiklenir ve genellikle başarısız olan komutlar daha önemlidir. Ev dizininizdeki bir dosyaya ekleme yapmak yerine logger kullanılmasının nedeni sahiplik durumudur: bir kanca, aracın kabuğuyla aynı kullanıcı yetkileriyle çalışır; dolayısıyla o kullanıcının ekleme yapabildiği her dosyayı, aynı kullanıcı silebilir veya içeriğini boşaltabilir. Günlük kaydı, systemd-journald tarafından kendi hesabı altında yazılır.
Bir kancanın çalışma süresi
The data behind this chart
[
{
"label": "command, http or mcp_tool hook",
"default_timeout_seconds": 600
},
{
"label": "agent hook",
"default_timeout_seconds": 60
},
{
"label": "prompt hook",
"default_timeout_seconds": 30
},
{
"label": "command hook on UserPromptSubmit",
"default_timeout_seconds": 30
},
{
"label": "command hook on MessageDisplay",
"default_timeout_seconds": 10
},
{
"label": "any hook on SessionEnd",
"default_timeout_seconds": 1.5
}
]Bir komut kancası varsayılan olarak 600 saniye, yani on dakika süre alır. Bazı olaylar bu süreyi ciddi oranda kısıtlar. SessionEnd kancaları, aralarında 1.5 saniyelik ortak bir bütçeyi paylaşır; bu nedenle oturum sonu temizlik işlemlerinin hızlı olması gerekir. Ancak kanca üzerinde daha uzun bir timeout ayarlanması, bu ortak bütçeyi 60 saniyeye kadar yükseltir.
Zaman aşımına uğrayan bir kanca iptal edilir ve herhangi bir karar üretmez. Bir PreToolUse güvenlik bariyeri için bu, kancanın engelleme yapmadığı anlamına gelir: araç çağrısı normal izin akışına devam eder. Bu nedenle güvenlik bariyeri betiklerini kısa tutun. Log göndermek gibi kimsenin beklemediği yavaş işlemler için "async": true ayarını kullanın; böylece kanca, araç çağrısını bekletmeden arka planda çalışır.
Kancalar, kural dosyaları, yetenekler ve MCP sunucuları
Dört farklı kavram, ajanın davranışını değiştirdikleri için birbirine karıştırılmaktadır. Bunlardan sadece biri öneri olmaktan çıkar.
Bir kural dosyası (CLAUDE.md veya .claude/rules/ altındaki bir dosya), modelin bağlamına yüklenen metindir. Davranışı şekillendirir ancak hiçbir şeyi zorunlu kılmaz. Uzun bir konuşma, büyük bir diff ve yeni bir kullanıcı isteği karşısında, kural dosyasındaki tek bir satır etkisini yitirebilir. Ajanların yazdığınız talimatları görmezden gelmesinin arkasındaki olağan mekanizma budur.
Yetenek (skill), modelin ilgili olduğunu düşündüğünde yüklediği talimatlar ve betikler klasörüdür. Bu değerlendirme yeteneğin temelidir, ancak aynı zamanda sınırıdır: kararı yine model verir. Ajani çalışan en küçük değişikliğe yönlendiren Ponytail gibi bir yetenekte her iki tarafı da görebilirsiniz; çünkü bu, hiçbir kancanın yapamayacağı şekilde tüm göreve yaklaşım biçimini şekillendirir ve bunu yalnızca model onu yüklemeyi seçtiği sürece yapar.
Bir MCP (model context protocol) sunucusu, modele çağırabileceği yeni araçlar sağlar. Ajanın erişebileceği alanı genişletir. Ajanı bir şeye erişmeye zorlamaz ve yönetmeniz gereken ayrı bir süreçtir; bu başlı başına bir iştir: bir VPS üzerinde MCP sunucuları çalıştırma konusuna bakınız.
Kanca (hook), bu dördü arasında modelin seçimi olmadan çalışan tek mekanizmadır. Bir tercih için kural dosyasını, modelin uygularken izlemesi gereken bir prosedür için yeteneği kullanın. Her zaman gerçekleşmesi gereken bir adım veya asla gerçekleşmemesi gereken bir durum için kancayı kullanın. Bir yeteneğin kural dosyasından ne zaman daha üstün olduğu dahil olmak üzere daha derinlemesine karşılaştırma için yetenekler, MCP ve kural dosyaları karşılaştırması bölümüne bakınız.
Eklenti (plugin), beşinci bir mekanizma değil, bir paketleme biçimidir. Kancaları yeteneklerle birlikte tek bir kurulabilir birimde toplar; bir ekibin aynı güvenlik sınırını her makineye nasıl dağıttığı budur: Claude Code eklentilerinin çalışma mantığı konusuna bakınız.
Paylaşımlı bir VPS üzerinde güvenlik kararı
Hook, agent tarafından tetiklenen ve Claude Code'u başlatan kullanıcı yetkileriyle çalışan koddur. Bu kod, ilgili kullanıcının ortamını ve dosya izinlerini devralır. Bir dizüstü bilgisayarda bu bir iş akışı sorusudur. Bir agent'ın gözetimsiz çalıştığı bir VPS'te ise bu, dört pratik boyutu olan bir güvenlik meselesidir.
Bir repodaki hook, sizin yazmadığınız koddur. .claude/settings.json commit edildiği için, bir repoyu klonlamak ve içinde bir oturum başlatmak, repo ile birlikte gelen hook'ları kaydedebilir. Claude Code, proje hook'larını o klasör için çalışma alanı güven (workspace trust) diyaloğu arkasında tutar; yani güveni onayladığınız an, onları çalıştırmaya karar verdiğiniz andır. Önce hooks bloğunu okuyun.
Bir hook, tüm araç girdisini görür. tool_input kaydı tutan bir denetim hook'u, komut satırında yer alan herhangi bir token dahil olmak üzere, her komutun tüm argümanlarını bir dosyaya yazar. Bu günlük dosyası, daha sonra gizli verinin kendisiyle aynı korumaya ihtiyaç duyar; bu da gizli verileri bir yapay zeka agent'ının erişiminden uzak tutma konusundaki daha geniş sorunun bir parçasıdır.
Bir hook, modelin bağlamına yazabilir. Bir SessionStart veya UserPromptSubmit hook'unun stdout'a yazdırdığı her şey konuşmaya eklenir. Dışarıdan, bir sorun takip sisteminden veya bir günlük dosyasından metin aktaran bir hook, güvenilmeyen metni sanki siz yazmışsınız gibi modele sunar. Aynı VPS üzerindeki başka bir Claude Code oturumundan not ileten bir hook da aynı şeyi yapar ve bir agent'ın çıktısının, sorun takip sistemininkinden daha fazla güvenilirlik iddiası yoktur. Bu stdout çıktısını, bir çıktıdan ziyade bir girdi olarak değerlendirin.
Asıl kontrol yetkilerdedir. Agent'ı, yalnızca ihtiyaç duyduğu sudo kurallarına sahip, yetkisiz ve özel bir kullanıcı olarak çalıştırın. Bir PreToolUse reddi (deny) kullanışlıdır ancak tasarımı gereği "en iyi çaba" (best effort) prensibiyle çalışır: referans dokümanı, if filtresi için de aynı şeyi söyler ve kesin bir engelleme gerektiğinde işletim sisteminin izin mekanizmasını kullanmanızı önerir. İzin kuralları ve sürecin altında çalıştığı hesap, baskı altında ayakta kalan kısımlardır.
Her yapılandırmada geçerli olan tek bir özellik vardır. PreToolUse hook'ları, her izin modunda, izin denetiminden önce tetiklenir; bu nedenle deny döndüren bir hook, bypassPermissions modunda bile aracı engeller. Hook'lar, izin kurallarının izin verdiğini kısıtlayabilir. Ancak bu kuralları gevşetemezler.
Kancam neden tetiklenmiyor?
Bu adımları sırasıyla uygulayın. Her adım, karşılaşacağınız belirtiyi tanımlar.
/hookskomutunu çalıştırın ve kancanın beklediğiniz etkinlik altında görünüp görünmediğini kontrol edin. Menüde eksik olan bir kanca, genellikle ayarlar dosyasında bir JSON sözdizimi hatası olduğu anlamına gelir; çünkü sondaki virgüllere ve açıklama satırlarına izin verilmez veya dosya yukarıda belirtilen alt konumdan birinde değildir.- Eşleştiriciyi (matcher) araç adıyla tam olarak karşılaştırın. Eşleştiriciler büyük/küçük harfe duyarlıdır, bu nedenle
"bash"ifadesiBasharacıyla asla eşleşmez. - Yukarıdaki 1. örnekte olduğu gibi, betiği örnek girdiyle manuel olarak çalıştırın. Beklemediğiniz bir çıkış kodu betiğinizdeki bir hatadır ve Claude Code bunu bir karar olarak değil, bir kanca hatası olarak raporlar.
jq: command not founduyarısı, ilgili makinedejqaracının eksik olduğu anlamına gelir. Kendi betiğiniz için alınan bircommand not foundhatası, yolun çözülemediğini gösterir; bu nedenle${CLAUDE_PROJECT_DIR}komutunu veya mutlak bir yol kullanın. Betik hiç çalışmıyorsa, muhtemelen çalıştırılabilir (executable) değildir.- Kanca geçerli bir JSON çıktısı veriyor ancak hiçbir şey olmuyor. Kabuk biçimindeki (shell-form) bir kanca
sh -cüzerinden çalışır; eğer kabuk profiliniz bir karşılama mesajı (banner) yazdırıyorsa, bu mesaj JSON çıktınızın başına eklenir. Stdout artık{ile başlamadığı için Claude Code çıktının tamamını düz metin olarak okur ve kararı yok sayar. Çıkış kodu 0 olduğunda, hata ayıklama günlüğü (debug log) dışında hiçbir yerde bir rapor oluşturulmaz. Profilinizdeki tümechoçıktılarını, yalnızca etkileşimli kabuklarda çalışacak şekilde sarmalayın. - Hâlâ sorun yaşıyorsanız: oturumu
claude --debug-file /tmp/claude.logile başlatın ve ikinci bir terminaldetail -f /tmp/claude.logkomutunu çalıştırın. Hata ayıklama günlüğü, hangi kancaların eşleştiğini, her birinin hangi çıkış kodunu döndürdüğünü ve stdout ile stderr'e yazılan her şeyi kaydeder.
FAQ
Claude Code hook ile CLAUDE.md talimatı arasındaki fark nedir?
CLAUDE.md talimatı, modelin bağlamındaki metindir; bu nedenle konuşma ve mevcut istek ile dikkat çekmek için rekabet eder ve model bunu diğerleriyle kıyaslayabilir. Hook ise Claude Code'un yaşam döngüsünde sabit bir noktada çalıştırdığı bir shell komutudur; dolayısıyla modelin kararı ne olursa olsun, ilgili olay gerçekleştiğinde her seferinde çalışır. Tercihleriniz için talimatları, her zaman gerçekleşmesi gereken bir adım veya asla gerçekleşmemesi gereken bir eylem için ise hook yapısını kullanın.
Claude Code'un belirli bir shell komutunu çalıştırmasını nasıl engellerim?
.tool_input.command üzerinden komutu okuyan, stderr'e bir neden yazan ve 2 koduyla çıkan bir Bash eşleştiricisine sahip bir PreToolUse hook'u kaydedin. Claude Code çağrıyı iptal eder ve modelinize nedeninizi gösterir. Bu işlem izin modu denetiminden önce gerçekleştiği için, engelleme bypassPermissions modunda bile geçerli kalır. Bir komut dizisi üzerinde desen eşleştirme yapmak bir güvenlik sınırı değil, bir güvenlik önlemidir; çünkü aynı komut, desenin gözden kaçırabileceği bir biçimde yazılabilir. Bu nedenle, bu yöntemi izin kuralları ve yetkisiz bir hesap ile destekleyin.
Hook'um geçerli JSON çıktısı veriyor ancak hiçbir şey olmuyor. Neden?
En yaygın neden shell profilinizdir. args alanı olmayan bir hook, sh -c üzerinden çalışır ve bazı profiller her shell açılışında bir karşılama mesajı yazdırır; bu mesaj JSON'ınızdan önce stdout'a düşer. Çıktı artık { ile başlamadığı için Claude Code bunu düz metin olarak değerlendirir ve kararı yok sayar; 0 çıkış kodunda ise transkriptte hiçbir şey raporlanmaz. Profilinizdeki tüm echo çıktılarını etkileşimli shell testi ile korumaya alın ve ardından claude --debug-file /tmp/claude.log içindeki hata ayıklama günlüğünü okuyarak düzeltmeyi doğrulayın.
Claude Code hook'larını paylaşımlı bir sunucuda çalıştırmak güvenli mi?
Hook'lar, Claude Code'u başlatan kullanıcı olarak ve o kullanıcının dosya izinleriyle çalışır; bu nedenle bir hook, ilgili hesabın yapabileceği her şeyi yapabilir. İki alışkanlık riskin büyük kısmını kapsar: ajanı kısıtlı bir sudo politikasına sahip, özel ve yetkisiz bir hesapla çalıştırın ve çalışma alanı güven diyalogunu kabul etmeden önce herhangi bir deponun hooks bloğunu okuyun; çünkü proje hook'ları .claude/settings.json içinde gelir. Hiçbirinin çalışmasını istemediğinizde ayar dosyanızda "disableAllHooks": true değerini ayarlayın.