Rehber

Claude Code hooks: ajan kurallarını garantiye nasıl dönüştürürsünüz

Güncellendi: · Skillaria.Top

Claude Code hooks, Claude Code'un belirli olaylarda kendisinin çalıştırdığı shell komutlarıdır: araç çağrısından önce ve sonra, prompt gönderildiğinde, oturum başlarken ve ajan durmadan hemen önce. Settings.json içinde tanımlanırlar; çıkış kodu 2 eylemi engeller ve ajana hata mesajı döndürür. Bu sayede CLAUDE.md'deki bir kural, model tarafından unutulamayacak bir garantiye dönüşür.

Claude Code hooks nedir

Hook, komutu model değil, Claude Code programının kendisi belirli bir anda çalıştırdığı bir komuttur. Ajan rm -rf çalıştırmak istediğinde hook devreye girer ve komutun geçip geçmeyeceğine karar verir. Ajan bir dosyayı düzenlediğinde hook biçimlendiriciyi çalıştırır. Ajan işini bitirmek istediğinde hook testleri çalıştırır ve testler kırmızıyken durmasına izin vermez.

CLAUDE.md'deki talimatlardan temel farkı şudur: talimat, modelin belli bir olasılıkla dikkate aldığı bir metindir; hook ise deterministik koddur. Bağlam ne kadar uzun olursa olsun, ajan neyi "kararlaştırdıysa" ve oturumun yüzüncü dakikasında kuralı unutup unutmadığından bağımsız olarak her zaman çalışır. Bu yüzden claude code hooks, bir dileği garantiye çevirmenin temel yoludur.

Neden CLAUDE.md kuralları yetmez

Tipik bir durum: ajan bir özelliği ekledi, birim testleri yeşil, sohbette kendinden emin bir "Tamam" yazıyor. Ama uçtan uca senaryo çalıştırılmamış, linter koşulmamış, migrasyon ortada patlamış. CLAUDE.md'de ise "bitirmeden önce testleri çalıştır" yazıyor. Model bilerek yalan söylemiyor; sadece kendi işini kendisi değerlendiriyor ve bu öz değerlendirme güvenilir değil.

Buradan harness ilkesi çıkar: mekanik olarak kontrol edilebilen her şeyi model değil, mekanizma kontrol eder. "Linter'ı çalıştır" kuralı, linter'ı çalıştıran bir hook olur. "Prod yapılandırmasına dokunma" kuralı, o dosyaya yazmayı engelleyen bir hook olur. Metin talimat olarak kalır, ama artık ajana neden durdurulduğunu açıklamaktan başka bir işe yaramaz.

Olaylar: hook'lar ne zaman çalışır

Her hook, oturumun yaşam döngüsündeki bir olaya bağlıdır. Başlıca olaylar:

OlayNe zaman çalışırTipik kullanım
PreToolUsearaç çağrısından önce (Bash, Edit, Write vb.)tehlikeli komutları yasaklama, dosyaları koruma
PostToolUsearaç çağrısı başarıyla tamamlandıktan sonrabiçimlendirici, linter, düzenlemeden sonra hızlı testler
UserPromptSubmitkullanıcı prompt'u gönderdi, işlenmeden öncebağlam ekleme, içinde sır olan prompt'u durdurma
Stopajan yanıtı bitirmek üzereykenkontroller geçmeden durmasına izin vermeme
SubagentStopbir alt ajan işini bitirirkenalt ajan sonucunu doğrulama
SessionStartoturum başladığında veya devam ettirildiğindedurumu yükleme: git status, plan, ilerleme günlüğü
SessionEndoturum sona erdiğindetemizlik, log kaydı
NotificationClaude Code bildirim gönderdiğinde (örneğin izin beklediğinde)ses veya telefona mesaj
PreCompactbağlam sıkıştırılmadan öncesıkıştırmadan önce önemli bilgileri kaydetme

Güvenilirlik açısından en faydalı olanlar PreToolUse, PostToolUse ve Stop'tur: ajanın üç zayıf noktasını kapatırlar — tehlikeli eylemler, kontrolsüz düzenlemeler ve erken "bitti" beyanı.

Hook'lar nerede tanımlanır: settings.json

Hook'lar Claude Code'un ayar dosyalarında tanımlanır:

  • ~/.claude/settings.json — kişisel ayarlar, tüm projeler için;
  • depodaki .claude/settings.json — ekip için ortak, git'e commit edilir;
  • .claude/settings.local.json — projeye özel yerel ayarlar, git'e girmez.

Yapı şöyledir: olay → matcher içeren grupların listesi → komutların listesi.

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/lint.sh",
            "timeout": 60
          }
        ]
      }
    ]
  }
}

matcher, araç adı veya ona uygulanan düzenli ifadedir: Bash, Edit|Write, .*. Araçlarla ilgili olaylar için gerekir; Stop veya UserPromptSubmit için atlanabilir. CLAUDE_PROJECT_DIR değişkeni proje kökünü gösterir, bu yüzden betikleri .claude/hooks/ içinde tutup bu değişken üzerinden çağırmak uygundur. Mevcut hook'ları Claude Code içinde /hooks komutuyla görebilirsiniz.

Hook veriyi nasıl alır ve nasıl yanıtlar

Girdi: stdin'deki JSON

Claude Code hook'a olay hakkında bir JSON gönderir: oturum kimliği, çalışma dizini, olay adı ve araçlar için tool_name ile tool_input. Bash için komut tool_input.command içinde, Edit ve Write için dosya yolu tool_input.file_path içindedir. Bunu jq ile okumak kolaydır.

{
  "session_id": "abc123",
  "hook_event_name": "PreToolUse",
  "tool_name": "Bash",
  "tool_input": { "command": "rm -rf build/" },
  "cwd": "/home/dev/project"
}

Çıktı: dönüş kodu

KodNe olur
0başarı, iş devam eder; UserPromptSubmit ve SessionStart için stdout ajanın bağlamına eklenir
2engelleyici hata: stderr ajana iletilir ve eylem durdurulur (PreToolUse'da araç çağrısı iptal edilir, Stop'ta ajan çalışmaya devam eder)
diğeriengellemeyen hata: stderr kullanıcıya gösterilir, iş devam eder

Çıkış kodu 2 temel mekanizmadır. Ajan stderr'deki metni geri bildirim olarak alır ve düzeltebilir: komutu yeniden yazar, testi onarır, dosyaya dokunmaz. Bu yüzden stderr'e "hata" değil, net bir neden ve yerine ne yapılacağını yazın.

Dönüş kodunun dışında hook, stdout'a "decision": "block" ve "reason" içeren bir JSON da yazabilir. Bu ince ayar içindir; çoğu iş için kod 2 ve stderr'deki mesaj yeterlidir.

Örnek 1: her düzenlemeden sonra linter ve testler

Edit|Write matcher'ına sahip bir PostToolUse hook'u dosya değiştirildikten sonra çalışır. Araç zaten uygulanmıştır ve düzenleme geri alınamaz, ama kod 2 linter çıktısını ajana döndürür ve ajan hatayı yarım saat sonra değil, hemen düzeltir.

#!/usr/bin/env bash
# .claude/hooks/lint.sh
file=$(jq -r '.tool_input.file_path // empty')
case "$file" in
  *.py)
    if ! out=$(ruff check "$file" 2>&1); then
      echo "Linter $file dosyasında hatalar buldu:" >&2
      echo "$out" >&2
      exit 2
    fi ;;
  *.php)
    if ! out=$(php -l "$file" 2>&1); then
      echo "$out" >&2
      exit 2
    fi ;;
esac
exit 0

Buraya on dakikalık tam test takımını koymayın: hook her düzenlemede çalışır. Düzenlemeden sonra hızlı kontroller (sözdizimi, linter, tek modülün testleri) yapın, ağır olanları Stop hook'una bırakın.

Örnek 2: tehlikeli komutları yasaklama

Bash matcher'ına sahip bir PreToolUse hook'u komutu çalıştırılmadan önce görür. Kod 2 çağrıyı iptal eder ve ajan açıklamayı alır.

#!/usr/bin/env bash
# .claude/hooks/guard.sh
cmd=$(jq -r '.tool_input.command // empty')
if echo "$cmd" | grep -Eq 'rm -rf /|git push (-f|--force)|DROP (TABLE|DATABASE)'; then
  echo "Komut proje politikasıyla engellendi: $cmd. Tehlikeli işlemleri insan yapar." >&2
  exit 2
fi
exit 0

Dosyaları da aynı şekilde korumak mümkündür: Edit|Write üzerindeki bir hook file_path'i kontrol eder ve .env, prod yapılandırmaları, üretilmiş kod veya zaten uygulanmış migrasyon dosyalarına yazmayı engeller. Düzenli ifadeli arama aşılabilir — ajan komutu başka bir biçimde yazabilir. Hook güçlü bir sigortadır, ama erişim hakları ve sandbox'ın yerini tutmaz.

Örnek 3: testler kırmızıyken ajan "bitti" diyemez

Stop hook'u ajan işini bitirmek üzereyken çalışır. Testler geçmiyorsa kod 2 ajanın durmasını engeller ve test çıktısı bir sonraki görev olarak ajana gider. Bu, Tanımlanmış Tamamlanma (Definition of Done) kuralının mekanik bir versiyonudur.

#!/usr/bin/env bash
# .claude/hooks/done.sh
input=$(cat)
# sonsuz döngüye karşı koruma: hook işi bir kez zaten uzattı
if [ "$(echo "$input" | jq -r '.stop_hook_active')" = "true" ]; then
  exit 0
fi
if ! out=$(npm test --silent 2>&1); then
  echo "Testler geçmedi, iş bitmedi:" >&2
  echo "$out" | tail -n 40 >&2
  exit 2
fi
exit 0

stop_hook_active alanı, ajan bir stop hook'u yüzünden işi zaten sürdürüyorsa true olur. Bu kontrol olmadan hook ajanı sonsuz bir döngüde çalıştırabilir — tam da "bütün gece yanlış yere çalışan ajan" durumu. Otonom döngülerde ayrıca deneme sınırı ve insanı çağıran bir koşul ekleyin.

Örnek 4: oturum başında durumu yükleme

SessionStart'ta hook'un stdout'u bağlama düşer. Mevcut dalı, commit edilmemiş değişiklikleri ve plandaki sonraki görevi yazdırmak faydalıdır; ajan sıfırdan başlamaz.

#!/usr/bin/env bash
echo "Dal: $(git branch --show-current)"
git status --short | head -n 20
[ -f PROGRESS.md ] && tail -n 15 PROGRESS.md
exit 0

Hook'lar kuralları garantiye nasıl çevirir

Harness kurallarını üç katmana bölmek kullanışlıdır. Birincisi CLAUDE.md'deki metin: nasıl çalışılacağını açıklar, ama olasılıksal olarak uygulanır. İkincisi çalıştırılabilir kontroller: testler, E2E, ihlalde düşen bir betik biçimindeki mimari kurallar. Üçüncüsü hook'lar: bu kontrolleri doğru anda, modelin katılımı olmadan otomatik çalıştırırlar.

Pratik kural: ajan aynı kuralı iki kez ihlal ettiyse, CLAUDE.md'ye büyük harflerle bir uyarı daha eklemeyin. Bu ihlalin bir betikle kontrol edilip edilemeyeceğini sorun. Edilebiliyorsa betiği yazın ve hook'a bağlayın. Böylece metin talimat kısalır, davranış ise istikrarlı olur.

Metindeki kuralHook ile garanti
"Kodu standarda göre biçimlendir"PostToolUse, değişen dosyada biçimlendiriciyi çalıştırır
"force ile push atma"Bash üzerindeki PreToolUse komutu engeller, exit 2
"Testler kırmızıyken bitti deme"Stop testleri çalıştırır ve işi bitirmeye izin vermez
"Ortam dosyasını (.env) düzenleme"Edit|Write üzerindeki PreToolUse yolu kontrol eder
"Nerede kaldığını hatırla"SessionStart planı ve git status'u yazdırır

Sık yapılan hatalar

  • Kod 2 yerine 1. Betik 1 koduyla çıkar, ajan bir şey öğrenmez ve eylem geçer. Yalnızca kod 2 engeller.
  • Hatanın stdout'a yazılması. Kod 2'de ajana stderr gider. >&2 ile yazın.
  • Sık tetiklenen olayda yavaş hook. PostToolUse içinde tam test takımı her düzenlemeyi bir dakikalık yapar. Ağır işleri Stop'a koyun.
  • Sonsuz Stop. stop_hook_active kontrolü ya da bir sınır yoksa ajan sonsuz döner.
  • Göreli yollar. Hook oturumun çalışma dizininde çalışır; $CLAUDE_PROJECT_DIR kullanın.
  • Güvenilmeyen hazır hook. Hook, onayınız olmadan sizin yetkilerinizle çalışır. Başka depolardan gelen betikleri güvenmeden önce okuyun.

Sonuç

Claude Code hooks en önemli kuralları metinden koda taşır: PreToolUse tehlikeli eylemleri durdurur, PostToolUse her düzenlemeyi kontrol eder, Stop erken "hazır" beyanını engeller, SessionStart ajana proje hafızasını geri verir. İlk olarak ajanın zaten ihlal ettiği iki üç kuralla başlayın ve stderr mesajlarını anlaşılır tutun; böylece ajan hataları kendisi düzeltir, siz de süreci değil sonucu kontrol edersiniz. Doğrulama, hazır olma kontrolü ve otonom döngüler kursta uygulamalı olarak ele alınır.

Sık sorulan sorular

Hook'ları değiştirdikten sonra Claude Code'u yeniden başlatmak gerekir mi?

settings.json değişiklikleri en güvenilir biçimde yeni bir oturumda uygulanır; mevcut hook yapılandırmasını /hooks komutuyla görebilirsiniz.

Hook'ları bash dışında bir dilde yazabilir miyim?

Evet, hook herhangi bir komuttur: Python, Node.js betiği ya da çalıştırılabilir dosya. Önemli olan stdin'den JSON okuyup doğru çıkış kodunu döndürmektir.

Ajan başarılı bir hook'un çıktısını görür mü?

Genellikle hayır: kod 0 ile çıktı bağlama girmez. İstisnalar UserPromptSubmit ve SessionStart'tır; orada stdout ajanın bağlamına eklenir.

Hook'lar alt ajanlar için de çalışır mı?

Evet, alt ajanların araç çağrıları aynı PreToolUse ve PostToolUse hook'larından geçer; işlerinin bitişi için ayrı bir SubagentStop olayı vardır.

Hook'ları depoya commit etmek güvenli mi?

Evet, .claude/settings.json ve .claude/hooks/ içindeki betikler ekip için yaygın bir uygulamadır; kişisel hook'ları settings.local.json veya ~/.claude/settings.json içinde tutun.