diffox
Blog

Hook nedir ve kodlama ajanlarında nasıl yazılır?

Kural dosyasına yazdığınız kurala ajan her zaman uymaz; hook ise her seferinde çalışır. Beş araçta hook’un nasıl yazıldığını örneklerle gösteriyoruz.

PaylaşXLinkedIn

Özet. Hook, kodlama ajanının belirli anlarda kendiliğinden çalıştırdığı, sizin yazdığınız bir komuttur. Çalışıp çalışmaması ajanın kararına bağlı olmadığı için, mutlaka uyulması gereken kurallarda kullanılır. Claude Code, Codex, Cursor, Gemini CLI ve GitHub Copilot’ta var. Her bilgiyi 18 Ekim 2026 günü aracın kendi belgesinden kontrol ettik; örnekler, her gün kullandığımız depodan. Google’ın Antigravity CLI’ını 28 Ekim 2026 günü ekledik.

  • Kural dosyası tek başına yetmez. AGENTS.md ya da CLAUDE.md’ye yazdığınız kural ajan için bir bilgidir, uyacağının garantisi yoktur. Beş araçta da ajan bir komut çalıştırmadan önce devreye giren bir hook var.
  • Durdurma yolu aynı, hata durumu farklı. Hook 2 koduyla çıkarsa beş araç da işlemi durdurur. 1 gibi başka bir hata kodunda ise Claude Code, Cursor ve Gemini CLI işleme devam eder, Copilot durdurur. Codex’in belgesi bu durumu anlatmıyor.
  • Takılan bir hook kuralı da devre dışı bırakır. Hook zaman aşımına uğrarsa Claude Code, Cursor ve Copilot işleme devam eder. Claude Code’da onFailure, Cursor’da failClosed ayarıyla bunu değiştirebilirsiniz. Codex ve Gemini CLI belgeleri zaman aşımını anlatmıyor.
  • Depomuzda üç hook kullanıyoruz. Biri oturum açılırken dizinin durumunu söyler, biri onay olmadan yapılan merge’ü durdurur, biri dal değiştiğinde ajanı uyarır.

Kural dosyasına yazmak neden yetmez?

5aracı kendi belgelerinden inceledik
2numaralı çıkış kodu beş araçta da işlemi durdurur
33olaya hook bağlanabiliyor (Claude Code)
3hook’u kendi depomuzda kullanıyoruz

Bir kodlama ajanına bir kuralı iki yoldan söyleyebilirsiniz. Birincisi kural dosyasıdır: AGENTS.md, CLAUDE.md ya da GEMINI.md’ye “merge etmeden önce bana sor” yazarsınız. İkincisi hook’tur: aynı kuralı, ajanın belirli bir anda kendiliğinden çalıştırdığı küçük bir betiğe çevirirsiniz.

Aradaki farkı en net Claude Code’un belgesi anlatıyor: “Claude treats them as context, not enforced configuration. To block an action regardless of what Claude decides, use a PreToolUse hook instead.” Yani kural dosyası ajan için yalnızca bir bilgidir ve ajan onu her zaman dikkate almayabilir. Bir işlemi ajan ne karar verirse versin durdurmak istiyorsanız hook kullanırsınız.

18 Ekim 2026 itibarıyla beş kodlama aracında da hook var: Claude Code, OpenAI’ın Codex’i, Cursor, Google’ın Gemini CLI’ı ve GitHub Copilot (CLI ve bulut ajanı). Hepsinde mantık aynı: hook bir olaya bağlanır, olayın ayrıntısını JSON olarak alır ve gerekirse bir komutu çalışmadan önce durdurur.

Örnekleri, diffox’u geliştirirken her gün kullandığımız depodan aldık. Orada Claude Code kullanıyoruz; anlattıklarımız ürünün bir özelliği değil, ekibin çalışma düzeni.

Beş araçta hook nerede tanımlanır?

Her araçta hook’lar bir ayar dosyasına yazılır; araçlar arasındaki fark çoğunlukla dosyanın ve olayın adında. Kural koymak için en çok kullanılan olay, ajan bir aracı (komut çalıştırma, dosya düzenleme gibi) kullanmadan hemen önce çalışan olaydır:

Beş kodlama aracında hook: ayar dosyası, araç kullanılmadan önce çalışan olay ve işlemi durdurmanın yolu
AraçAyar dosyası (proje · kullanıcı)Araç kullanılmadan önceDurdurmak için
Claude Code.claude/settings.json · ~/.claude/settings.jsonPreToolUseexit 2 ya da permissionDecision: "deny"
Codex.codex/hooks.json · ~/.codex/hooks.jsonPreToolUseexit 2 ya da permissionDecision: "deny"
Cursor.cursor/hooks.json · ~/.cursor/hooks.jsonpreToolUse; kabuk komutlarında beforeShellExecutionexit 2 ya da permission: "deny"
Gemini CLI.gemini/settings.json · ~/.gemini/settings.jsonBeforeToolexit 2 ya da decision: "deny"
GitHub Copilot.github/hooks/*.json · ~/.copilot/hooks/*.jsonpreToolUseexit 2 ya da permissionDecision: "deny"

Kaynak: her aracın kendi hook belgesi, 18 Ekim 2026. JSON’lu karar, hook’un ekrana (stdout) yazdığı çıktıyla verilir. Codex aynı ayarı config.toml içinde de okur. Copilot’ta kullanıcı dosyası yalnızca CLI’da geçerlidir; bulut ajanı depodaki dosyayı varsayılan daldan okur.

Olay gerçekleştiğinde hook’unuz ayrıntıları JSON olarak alır: hangi aracın, hangi girdiyle çağrıldığını. Claude Code’da bir Bash komutundan önce gelen girdi şöyle görünür:

ÖRNEK. Hook’a gelen bilgi bir JSON nesnesidir. Claude Code · stdin · PreToolUse: { /   "session_id": "abc123", /   "cwd": "/home/dev/proje", /   "hook_event_name": "PreToolUse", /   "tool_name": "Bash", /   "tool_input": { /     "command": "gh pr merge 42 --squash" /   } / }. tool_name: Hangi araç: matcher bu ada bakar. tool_input.command: Çalıştırılacak komut. Çıkış kodu: Betiğin kararı: 2 durdurur.
Claude Code’da Bash aracından önce çalışan PreToolUse hook’una gelen JSON’un kısaltılmış bir örneği. Alan adları Claude Code’un hook belgesinden, 18 Ekim 2026; diğer araçlarda alanların adı değişir.

Araçlar birbirlerinin dosyalarını da okuyabiliyor: Copilot depodaki .claude/settings.json dosyasını da okur, Cursor Claude Code hook’larını yükleyebilir, Gemini CLI de Claude Code için yazılmış betikler bozulmasın diye CLAUDE_PROJECT_DIR değişkenini tanımlar. Yani bir hook’u bir kez yazıp birkaç araçta kullanmak mümkün. Yine de olay adları ve çıktı alanları farklı olduğu için hook’u her araçta ayrıca deneyin.

Google, 18 Haziran 2026’da ücretsiz kullanıcılar ile Google AI Pro ve Ultra aboneleri için Gemini CLI’ın hizmetini durdurup onları Antigravity CLI’a yönlendirdi; ücretli API anahtarıyla ya da şirket lisansıyla Gemini CLI’ı kullanmaya devam edebilirsiniz. Google’ın duyurusuna göre Antigravity CLI’da da hook var; belgesini 28 Ekim 2026 günü okuduk. Hook’lar projede .agents/hooks.json, kullanıcı için ~/.gemini/config/hooks.json dosyasına yazılıyor. Araç kullanılmadan önce çalışan olayın adı Claude Code’daki gibi PreToolUse. İşlemi durdurmak için hook JSON’da decision: "deny" döndürüyor. Zaman aşımı varsayılan olarak 30 saniye; çıkış kodlarının ne yaptığını belge anlatmıyor.

Hook bir işlemi nasıl durdurur?

Hook kararını iki yoldan bildirir: çıkış koduyla ya da ekrana yazdığı JSON’la. Beş araçta da hook 2 koduyla çıkarsa işlem durur ve hook’un hata çıktısına (stderr) yazdığı açıklama ajana iletilir. Araçlar, hook başka bir hata koduyla çıktığında ya da zaman aşımına uğradığında farklı davranıyor:

Araç kullanılmadan önce çalışan hook 2 dışında bir hata koduyla çıkarsa ya da zaman aşımına uğrarsa ne olur
Araç2 dışında bir hata koduZaman aşımıİşlemi durduran ayar
Claude Codeİşlem devam ederİşlem devam eder"onFailure": "block"
CodexBelgede yazmıyorBelgede yazmıyor—
Cursorİşlem devam ederİşlem devam eder"failClosed": true
Gemini CLIUyarı verir, işlem devam ederBelgede yazmıyor—
GitHub Copilotİşlem dururİşlem devam eder—

Kaynak: her aracın hook belgesi, 18 Ekim 2026. “Belgede yazmıyor”: o gün okuduğumuz sayfalarda bu durumu anlatan bir cümle bulamadık. Claude Code’daki ayar 2.1.295 sürümünden beri var. Windows’ta Git Bash yoksa, kabuk biçimli bir PreToolUse komut hook’u hata verdiğinde onFailure olmadan da işlemi durdurabilir.

Önce ilk sütuna bakın. Unix’te hata için genellikle 1 kullanılır. Claude Code, Cursor ve Gemini CLI bu kodu işlemi durdurmayan bir hata olarak görür; Copilot ise aynı kodda işlemi durdurur. Claude Code belgesi bu yüzden kural koyan hook’larda exit 2 kullanmanızı söylüyor. Gemini CLI ise işlemi bilerek durdururken bile 0 ile çıkıp JSON yazmayı öneriyor; hook ekrana JSON olmayan bir şey yazarsa işleme izin veriyor.

İkinci sütundaki sorunu fark etmek daha zor: hook’un dosya yolu yanlışsa ya da betik takılırsa, kural hiç yokmuş gibi olur. İşlemin mutlaka durması gereken yerlerde Claude Code’da onFailure, Cursor’da failClosed ayarını açın.

Aşağıdaki örnek, depomuzdaki merge kontrolünün Claude Code için sadeleştirilmiş hâli. Önce ayar dosyası:

.claude/settings.json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/merge-gate.sh"
          }
        ]
      }
    ]
  }
}

Sonra betik:

.claude/hooks/merge-gate.sh
#!/bin/bash
# Girdi stdin'den JSON olarak gelir. Okunamazsa işlem durur.
COMMAND=$(jq -r '.tool_input.command // empty') || {
  echo "Hook girdiyi okuyamadı, işlem durduruldu." >&2
  exit 2
}

case "$COMMAND" in
  *"MERGE_APPROVED=1 gh pr merge"*) exit 0 ;;  # onay komutta yazılı
  *"gh pr merge"*)
    echo "Merge kararı proje sahibinin. Önce sorun." >&2
    exit 2 ;;                                 # işlem durur
esac
exit 0                                        # itiraz yok

Betik 2 ile çıkınca Claude Code komutu çalıştırmaz ve hata çıktısına yazdığınız cümleyi ajana iletir. Aynı kararı 0 ile çıkıp JSON yazarak da verebilirsiniz: permissionDecision alanına deny (reddet), ask (sor) ya da allow (izin ver) yazılır. PreToolUse hook’ları izin ayarlarından önce çalışır; deny kararı, bütün izin sorularını atlayan bypassPermissions modunda bile geçerlidir. Codex ask değerini henüz desteklemiyor: hook başarısız sayılıyor ve işlem devam ediyor.

Depomuzda hangi hook’ları kullanıyoruz?

Depomuzun .claude/settings.json dosyasında 3 hook var. Üçünü de başımıza gelen bir hatanın tekrarlanmaması için yazdık.

Depomuzdaki üç hook. Biri bilgi verir, biri durdurur, biri uyarır. Dördüncüsünü git çalıştırır. SessionStart Dizinin durumu: Dalı, commit edilmemiş dosyaları ve worktree’leri söyler. PreToolUse · Bash Merge kontrolü: Onay yoksa merge komutunu durdurur. PreToolUse · Edit|Write Dal değişikliği uyarısı: Dal ya da commit değiştiyse ajanı uyarır. git · pre-push Git hook’u: Push’tan önce çalışır; onu ajan değil git çalıştırır.
Depomuzdaki üç Claude Code hook’u ve bir git hook’u. Üçüncüsü Edit|Write|NotebookEdit araçlarından önce çalışır. Kaynak: deponun ayar dosyası ve hook betikleri.

Oturum açılışı. Bir oturum başladığında SessionStart hook’u hangi dalda olunduğunu, kaç dosyanın commit edilmediğini ve açık worktree’leri söyler, sonra bir sonuç verir: “bu dizinde çalışabilirsin” ya da “önce ayrı bir worktree aç”. Bu kural zaten CLAUDE.md’de yazıyordu. Ama bir oturum kuralı okudu, kendi durumuna uygulamadı ve kırk dakikada üç kez dal değiştiren bir dizinde değişiklik planladı. Ajanın hatırlamasına bağlı bir kural koruma sağlamıyor; hook bu soruyu ajanın yerine soruyor.

Merge kontrolü. Depomuzda bir pull request’i proje sahibi onaylamadan merge etmiyoruz. Ama bir ajan, testler geçince sıradaki adım olarak gh pr merge çalıştırmaya kalkabilir. Bash aracından önce çalışan PreToolUse hook’u bu komutu 2 koduyla durdurur ve ajana önce onay istemesini söyler. Onay gelince komut, başına bir ortam değişkeni eklenerek yeniden çalıştırılır; böylece onay, oturum kaydında merge’ün hemen yanında durur. Hook girdiyi okuyamazsa da işlemi durdurur: ilk sürümü okuyamadığı komutları 0 ile çıkıp geçiriyordu.

Dal değişikliği uyarısı. Oturum açılışında verilen sonuç o anki durumu anlatır ve zamanla eskiyebilir: aynı dalda açılmış iki oturumdan biri yeni bir dala geçerse diğerinin çalıştığı yer değişir. Dosya düzenleme araçlarından önce çalışan ikinci PreToolUse hook’u, her düzenlemeden önce dalı ve commit’i oturuma son söylenenle karşılaştırır. Fark varsa ajana şu satırla başlayan bir not gönderir: “drift: this checkout MOVED since the session was last told what it is”. İşlemi durdurmaz; notu additionalContext alanıyla iletir ve 0 ile çıkar.

Git hook’u farklı bir şey. Aynı depoda bir de pre-push hook’u var: korunan dallara doğrudan push yapılmasını engeller. Onu kodlama ajanı değil git çalıştırır; bu yüzden o klondan push yapan herkesi, hangi aracı kullanırlarsa kullansınlar ajanları da kapsar. İkisi de yalnızca sizin makinenizde çalışır: --no-verify ile pre-push atlanabilir, yani sunucu tarafındaki kontrollerin yerini tutmaz.

Hook, skill ve kural dosyası arasındaki fark

Üçü de ajanın nasıl davranacağını belirler, ama farklı zamanlarda devreye girer. Claude Code belgelerindeki karşılaştırma şöyle:

CLAUDE.md, skill ve hook: ne zaman devreye girdiği, her seferinde uygulanıp uygulanmadığı, bağlamda kapladığı yer ve ne için kullanıldığı
CLAUDE.mdSkillHook
Ne zaman devreye girerHer oturumun başında/ad yazınca ya da Claude işe uygun buluncaBağlı olduğu olay her gerçekleştiğinde
Her seferinde uygulanır mıHayır, ajan için bilgidirHayır, Claude yorumlarEvet, olay her olduğunda çalışır
Bağlamda kapladığı yerHer istekte tamamıHer oturumda açıklaması, kullanılınca tamamıÇıktı vermedikçe hiç
Ne için kullanılır“Her zaman şunu yap” kuralları, komutlarTekrar kullanılan iş akışları, başvuru metinleriBiçimlendirme, tehlikeli komutu durdurma, bildirim

Kaynak: Claude Code belgeleri, “Extend Claude Code” sayfası, 18 Ekim 2026.

Kısaca: adımları nasıl uygulayacağına ajan karar verecekse skill, işlem her seferinde aynı şekilde yapılacaksa hook kullanın. Sürüm çıkarmanın kontrol listesi bir skill’dir; kaydedilen her dosyayı biçimlendirmek bir hook’tur. Aynı sayfanın dediği gibi, kural dosyasındaki ya da skill’deki talimat bir ricadır, garanti değildir. Çiğnendiğinde geri alınamayan kuralları (yanlış dala push, erken merge) yalnızca talimata bırakmayın.

Hook’lar yalnızca ayar dosyasında tanımlanmaz; skill’ler ve alt ajanlar da kendi tanımlarında hook taşıyabilir. Claude Code’da alt ajanın hook’u yalnızca o alt ajan çalışırken geçerlidir; skill’in hook’u ise skill bir kez çağrıldıktan sonra oturum bitene kadar çalışmaya devam eder. Copilot’ta özel bir ajanın hook’u yalnızca o ajan seçiliyken çalışır.

Her kuralı hook’a çevirmeyin

Hook her seferinde çalışır; yanlış yazılmış bir hook da her seferinde yanlış çalışır. Yazmadan önce şunlara bakın:

  • Değişmeyen bilgiyi kural dosyasında tutun. Claude Code belgesi sabit bilgiler için CLAUDE.md’yi öneriyor. Hook, o anki durumu (hangi daldasınız, son CI sonucu ne) iletmek için daha uygun.
  • Yorum gerektiren kararları hook’a bırakmayın. “Bu değişiklik test gerektirir mi?” sorusunu basit bir metin kontrolü cevaplayamaz; böyle bir adım skill’e yazılır.
  • Gereksiz yere durdurmayın. Üç hook’umuzdan ikisi yalnızca bilgi verir, işlemi durdurmaz. Haksız yere işi durduran bir hook kısa sürede düzeltilmek yerine kapatılır.
  • Metin arayan bir hook güvenlik önlemi değildir. Merge kontrolümüz, bir değişkene ya da eval içine yazılmış merge komutunu yakalayamaz. Sormayı unutan ajanı durdurur, kuralı bilerek aşmaya çalışanı durduramaz. Codex belgesi de hook’ları “a useful guardrail, not a complete enforcement boundary” diye tanımlıyor. Kesin izin ve yasaklar için Claude Code belgesi izin kurallarını öneriyor.
  • Başkasının yazdığı hook’u kod gibi inceleyin. Komut hook’ları sizin kullanıcı yetkilerinizle çalışır. Codex, depodan gelen bir hook’u siz inceleyip onaylamadan çalıştırmaz; Cursor, proje hook’larını yalnızca güvendiğiniz çalışma alanlarında çalıştırır; Gemini CLI de değişmiş bir hook’u yeni ve güvenilmeyen bir hook olarak görür.

Hook’lar sizin makinenizde, işlem yapılmadan önce çalışır; yazılan kodun doğru olup olmadığına bakmaz. Orası kod incelemesinin işi: diffox bir pull request’i incelerken deponun kural dosyasındaki (AGENTS.md, yoksa CLAUDE.md) uyulması gereken kuralları da inceleme kuralı olarak okur.

Sıkça sorulan sorular

Hook nedir, hangi kodlama araçlarında var?

Hook, kodlama ajanının belirli anlarda kendiliğinden çalıştırdığı, sizin yazdığınız bir komuttur. 18 Ekim 2026 itibarıyla Claude Code, Codex, Cursor, Gemini CLI ve GitHub Copilot’ta var. Hangi olayda hangi komutun çalışacağını ayar dosyasına yazarsınız. Çalışıp çalışmaması ajanın kararına bağlı olmadığı için kural her seferinde uygulanır.

Claude Code’da hook bir komutu nasıl durdurur?

PreToolUse olayına bağlı bir hook 2 koduyla çıkarsa Claude Code komutu çalıştırmaz ve hook’un hata çıktısına yazdığı açıklamayı ajana iletir. 0 ile çıkmak “itirazım yok” demektir; 1 gibi başka bir kod ise işlemi durdurmayan bir hata sayılır. Hook ayrıca 0 ile çıkıp JSON yazabilir: permissionDecision alanı deny, ask ya da allow olur.

Cursor’da hook nasıl kullanılır?

Hook’lar proje için .cursor/hooks.json, kullanıcı için ~/.cursor/hooks.json dosyasına yazılır. Ajan bir aracı kullanmadan önce preToolUse, bir kabuk komutu çalıştırmadan önce beforeShellExecution çalışır. Hook 2 ile çıkarsa ya da JSON’da permission: "deny" döndürürse işlem durur. Başka bir hata kodunda işlem devam eder; failClosed: true ile bunu değiştirebilirsiniz. Proje hook’ları yalnızca güvendiğiniz çalışma alanlarında çalışır.

Codex ve Gemini CLI’da hook var mı?

Var. Codex’te hook’lar .codex/hooks.json ya da config.toml dosyasına yazılır ve varsayılan olarak açıktır; depodan gelen bir hook’u Codex siz inceleyip onaylamadan çalıştırmaz. Gemini CLI’da hook’lar settings.json içindedir ve bir araç kullanılmadan önce çalışan olayın adı BeforeTool’dur. İkisinde de hook 2 koduyla çıkarsa işlem durur.

GitHub Copilot’ta hook nasıl tanımlanır?

Depoda .github/hooks/ klasörüne, Copilot CLI’da kişisel olarak ~/.copilot/hooks/ klasörüne bir JSON dosyası koyarsınız. Dosyada version: 1 ve bir hooks nesnesi bulunur. Bir araç kullanılmadan önce preToolUse çalışır; hook ekrana permissionDecision: "deny" yazarsa ya da 2 ile çıkarsa işlem durur. Bulut ajanı hook dosyasını deponun varsayılan dalından okur.

Hook çökerse ya da zaman aşımına uğrarsa ne olur?

Çoğu araçta işlem devam eder. Claude Code’da hata veren ya da zaman aşımına uğrayan bir hook işlemi durdurmaz; Cursor’da da başarısız bir hook işlemi geçirir; Copilot’ta zaman aşımı her durumda işlemi geçirir. Bunu değiştirmek için Claude Code’da "onFailure": "block", Cursor’da "failClosed": true ayarı var. Copilot’ta ise preToolUse hook’u 2 dışında bir hata koduyla çıkarsa işlem durur.

Hook ile skill arasındaki fark nedir?

Hook, belirli bir olay olduğunda aracın çalıştırdığı bir komuttur ve her seferinde çalışır. Skill ise ajanın okuyup uyguladığı bir talimat dosyasıdır (Claude Code’da SKILL.md): siz adıyla çağırdığınızda ya da ajan işe uygun bulduğunda yüklenir, ne yapılacağına ajan karar verir. İşlem her seferinde aynı şekilde yapılacaksa hook, adımları ajanın duruma göre ayarlaması gerekiyorsa skill kullanın.