Claude Code ile her gün çalışırken üç sorun sürekli tekrarlıyor: her düzenlemeden sonra format kontrolü, uzun session’larda context kaybı ve context compaction sonrası yarım kalan işlerin kaybolması. Bu sorunların ortak noktası, hepsinin manuel müdahale gerektirmesi. “Format şu dosyayı”, “şu context’i hatırlat”, “nerede kalmıştık” gibi komutları tekrar tekrar yazmak, otomasyon değil yeni bir iş.
Claude Code’un hook sistemi bu tekrarlayan işleri otomatize ediyor. Ama önemli olan hook’ların kendisi değil, hangi sorunu çözdükleri. Bu yazıda 4 katmanlı bir yaklaşımı, her katmanın çözdüğü sorunu ve sonuçları paylaşacağım.
| Hızlı Referans | |
|---|---|
| Kapsam | Claude Code hook sistemiyle workflow otomasyonu |
| Yaklaşım | Problem-driven: her katman bir sorunu çözer |
| Referanslar | Meta-RL (ICLR 2026), GrapeRoot benchmark, SashiDo boring agent, Axe CLI |
| İlişkili kavramlar | Context Yönetimi, LLM Bozulma Modları |
Hook Sistemi: 30 Saniyede
Claude Code’un event lifecycle’ı beş ana olaydan oluşur: PreToolUse (tool çağrısından önce), PostToolUse (tool çağrısından sonra), PreCompact (context compaction öncesi), SessionStart (session başlangıcı) ve Stop (session bitişi). Her olay bir hook tetikleyebilir: shell komutu, script veya HTTP çağrısı.
Hook’lar settings.json içinde tanımlanır. matcher alanı hangi tool’larda çalışacağını belirler:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [{ "type": "command", "command": "ruff format $FILEPATH" }]
}
]
}
}
23 hook event’inin tamamını kapsayan bir referans için shanraisshan’ın claude-code-hooks reposuna bakabilirsiniz. Bu yazıda referans listesi yerine, her hook’un hangi sorunu çözdüğüne odaklanacağım.
Neden Hook? CLAUDE.md Yetmiyor mu?
LLM Bozulma Modları yazısında ele aldığım instruction attenuation ve ceremonialization kavramları burada kritik.
CLAUDE.md’ye “her değişiklikten sonra test çalıştır” yazdığınızda, bu bir probabilistik kural. Model buna uyma olasılığı context uzunluğuna, session süresine ve konuya göre değişir. İlk birkaç değişiklikte çalıştırır, onuncu değişiklikte “test çalıştırdım, geçti” yazar. Belki çalıştırmıştır, belki çalıştırmamıştır. Kuralın kabuğu kaldı, içi boşaldı: ceremonialization.
Hook’lar deterministik kural. Her seferinde aynı şekilde çalışır, istisna tanımaz, ceremonialize olmaz. Probabilistik kurallarla deterministik kontrollerin birlikte çalışması gerekir. CLAUDE.md niyeti tanımlar, hook’lar uygulamayı garanti eder.
Katman 1: Auto-Format (PostToolUse)
Sorun
Claude Code bazen format bozuk kod üretir. Python’da indent tutarsızlığı, JavaScript’te eksik noktalı virgül, import sıralaması karışıklığı. Kod çalışır ama linter kızar. “Format şu dosyayı” demek tekrarlayan ve gereksiz bir iş.
Çözüm
PostToolUse hook’u Edit veya Write tool’u çalıştıktan sonra otomatik tetiklenir:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "ruff format --quiet $FILEPATH"
},
{
"type": "command",
"command": "eslint --fix --quiet $FILEPATH 2>/dev/null || true"
}
]
}
]
}
}
ruff Python dosyalarında, eslint JavaScript/TypeScript dosyalarında çalışır. --quiet flag’i gereksiz çıktıyı bastırır. || true ile eslint’in JS olmayan dosyalarda hata vermesi engellenir.
Sonuç
Format hataları sıfır. PR review’larda “format düzelt” yorumu yok. Claude Code’un ürettiği her dosya proje standartlarına uygun çıkıyor.
Katman 2: Context Enrichment (PreToolUse)
Sorun
Claude Code bir dosyayı okuduğunda, o dosyanın proje içindeki bağlamını bilmez. Hangi modülle ilişkili, hangi API’yi kullanıyor, hangi convention’lara uyması gerekiyor. Her seferinde “bu dosya X modülünün parçası, Y convention’ını kullan” demek gerekiyor.
Çözüm
PreToolUse hook’u Read veya Grep tool’u çalışmadan önce tetiklenir. İlgili knowledge base chunk’larını context’e enjekte eder:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Read|Grep",
"hooks": [
{
"type": "command",
"command": "path/to/enrich-context.sh"
}
]
}
]
}
}
Bu yaklaşım, GrapeRoot benchmark’ının ortaya koyduğu pre-injection stratejisiyle uyumlu. MCP tool call döngüsüne kıyasla pre-injection %31 daha ucuz ve %24 daha az turn kullanıyor1. Dosya okunmadan önce ilgili bilgiyi context’e enjekte etmek, MCP üzerinden ayrı bir tool call yapmaktan daha verimli.
Sonuç
“Bu dosya ne işe yarıyor?” sorusu ortadan kalkıyor. Claude Code her dosyayı proje bağlamıyla birlikte okuyor. Tekrarlayan context açıklamaları eliminate ediliyor.
Katman 3: WIP Persistence (PreCompact + SessionStart)
Sorun
Uzun session’larda Claude Code context compaction yapıyor: eski mesajları özetleyip token tasarrufu sağlıyor. Bu süreçte aktif çalışma durumu (hangi branch, hangi dosyalar değişti, hangi task’lar açık) kaybolabiliyor. Yeni session başladığında “nerede kalmıştık?” sorusuyla başlamak, önceki session’ın son 30 dakikasını tekrar harcamak demek.
Çözüm
İki hook birlikte çalışıyor:
PreCompact (compaction öncesi checkpoint kaydet):
#!/bin/bash
# checkpoint-wip.sh
INPUT=$(cat)
CWD=$(echo "$INPUT" | jq -r '.cwd // empty')
PROJECT_NAME=$(basename "$CWD")
BRANCH=$(cd "$CWD" && git branch --show-current 2>/dev/null)
MODIFIED=$(cd "$CWD" && git diff --name-only 2>/dev/null | head -20)
STATUS=$(cd "$CWD" && git diff --stat 2>/dev/null | tail -1)
LAST_COMMITS=$(cd "$CWD" && git log --oneline -3 2>/dev/null)
jq -n \
--arg branch "$BRANCH" \
--arg modified "$MODIFIED" \
--arg status "$STATUS" \
--arg reflection "$LAST_COMMITS" \
--arg time "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
'{branch: $branch, modified_files: ($modified | split("\n")),
git_status: $status, reflection: $reflection, timestamp: $time}' \
> "$HOME/.claude/state/wip-${PROJECT_NAME}.json"
SessionStart (yeni session’da restore):
#!/bin/bash
# restore-wip.sh
INPUT=$(cat)
CWD=$(echo "$INPUT" | jq -r '.cwd // empty')
PROJECT_NAME=$(basename "$CWD")
CHECKPOINT="$HOME/.claude/state/wip-${PROJECT_NAME}.json"
[ ! -f "$CHECKPOINT" ] && exit 0
# 24 saat kontrolu
FILE_AGE=$(( $(date +%s) - $(stat -f %m "$CHECKPOINT") ))
[ "$FILE_AGE" -gt 86400 ] && rm -f "$CHECKPOINT" && exit 0
BRANCH=$(jq -r '.branch' "$CHECKPOINT")
MODIFIED=$(jq -r '.modified_files | join(", ")' "$CHECKPOINT")
REFLECTION=$(jq -r '.reflection' "$CHECKPOINT")
CONTEXT="[WIP RECOVERED] Branch: $BRANCH | Degisen: $MODIFIED | Son aktivite: $REFLECTION"
jq -n --arg ctx "$CONTEXT" '{additionalContext: $ctx}'
rm -f "$CHECKPOINT"
Checkpoint’teki reflection field’ı, Meta-RL araştırmasının kritik bir bulgusunu pratiğe taşıyor. 2026’da üç bağımsız araştırma grubu (AI2, EPFL, Tsinghua) aynı sonuca ulaştı: agent’a birden fazla deneme hakkı verip her başarısızlık sonrası reflection yaptırmak, performansı önemli ölçüde artırıyor. LaMer (EPFL, ICLR 2026) özellikle ilginç bir bulgu ortaya koydu: sadece reflection text tutmak, full trajectory + reflection’dan daha iyi sonuç veriyor (%80.5 vs %74.4)2.
Bu bulgu WIP checkpoint tasarımını doğrudan etkiliyor: tüm conversation history’yi kaydetmek yerine, son 3 commit mesajını “reflection” olarak tutmak yeterli. Daha az token, daha iyi context.
SashiDo’nun “AI-Assisted Programming That Actually Ships” yaklaşımı da benzer bir felsefe: feature_list.json, progress file, init script ile her session aynı döngüyü izler3. WIP persistence hook’umuz bu yaklaşımın hafif versiyonu.
Sonuç
Context compaction sonrası kayıp sıfıra yakın. Yeni session otomatik olarak önceki durumla başlıyor. 24 saat sonra checkpoint otomatik temizleniyor.
Katman 4: Standalone Agent Bridge (Axe + Docker)
Sorun
Claude Code’un hook sistemi güçlü ama tek bir ekosisteme bağlı. Bazen farklı bir LLM’i farklı bir görev için kullanmak isteyebilirsiniz: kod review, log analizi, commit mesajı üretme. Bu görevler için ayrı bir tool’a ihtiyaç var ama hook’larla entegre çalışması gerekiyor.
Çözüm
Axe, J.R. Swab’ın geliştirdiği Go tabanlı CLI aracı. Unix felsefesiyle tasarlanmış: her agent tek bir iş yapar, stdin/stdout üzerinden compose edilebilir, cron/git hooks/pipe’larla tetiklenebilir4.
Axe’i Docker üzerinden çalıştırıp Claude Code hook’larından tetiklemek, iki ekosistemi birbirine bağlıyor:
# Axe agent config (~/.config/axe/agents/code-reviewer.toml)
name = "code-reviewer"
description = "Reviews git diffs for bugs and security issues"
model = "anthropic/claude-haiku-4-5-20251001"
system_prompt = "You are a concise code reviewer. Focus on bugs, security issues, and logic errors. Max 5 bullet points."
skill = "skills/code-review/SKILL.md"
[params]
temperature = 0.2
max_tokens = 1024
On-demand kullanım:
git diff | docker run --rm -i \
-v ~/.config/axe:/home/axe/.config/axe:ro \
axe run code-reviewer
Test Sonuçları
İlk test, kasıtlı olarak güvenlik açığı içeren bir diff üzerinde:
def get_user(user_id):
conn = sqlite3.connect(os.environ["DB_PATH"])
return conn.execute(f"SELECT * FROM users WHERE id = {user_id}").fetchone()
Axe’in code-reviewer agent’ı 3 issue tespit etti:
- SQL injection:
user_iddoğrudan query’ye interpolate ediliyor - Resource leak: database connection kapatılmıyor
- Missing error handling:
DB_PATHenv var eksikse crash
İkinci test, gerçek bir proje diff’i üzerinde (content-intelligence pipeline): 4 legitimate issue tespit edildi. JSON parsing error handling eksikliği, hash lookup validation, unbounded query, file I/O race condition.
Trade-off
Bu yaklaşım tool-agnostic ve composable. Ama her çağrıda Docker container + LLM call maliyeti var. Bu nedenle her edit sonrası otomatik çalıştırmak yerine on-demand script olarak tutuyorum. Her edit sonrası tetiklemek isteyenler için throttling (son review’dan 5 dakika geçmişse çalıştır) eklenebilir.
Axe maintainer’ı J.R. Swab ile Dev.to’da bu entegrasyonu tartıştık. Swab, OpenClaw ile Axe agent’ları skill step’lerinde tetiklemeyi çalışıyormuş. Editor hook’larından tetikleme henüz denenmemiş, bu yazı ilk documented use case.
Sonuç
İki ekosistem (Claude Code hooks + standalone Axe agents) birlikte çalışıyor. Hook’lar otomatik işleri, Axe on-demand review’ları hallediyor.
Genel Sonuçlar
| Sorun | Hook | Sonuç |
|---|---|---|
| Format hataları | PostToolUse (ruff, eslint) | Sıfır manuel format müdahalesi |
| Context eksikliği | PreToolUse (knowledge enrichment) | Otomatik bağlam enjeksiyonu |
| Context compaction kaybı | PreCompact + SessionStart | WIP otomatik kayıt/restore |
| Tek ekosisteme bağımlılık | Axe + Docker bridge | Tool-agnostic agent tetikleme |
Tam Setup
settings.json
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{ "type": "command", "command": "ruff format --quiet $FILEPATH" },
{
"type": "command",
"command": "eslint --fix --quiet $FILEPATH 2>/dev/null || true"
}
]
}
],
"PreToolUse": [
{
"matcher": "Read|Grep",
"hooks": [
{
"type": "command",
"command": "path/to/enrich-context.sh"
}
]
}
],
"PreCompact": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "path/to/checkpoint-wip.sh"
}
]
}
],
"SessionStart": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "path/to/restore-wip.sh"
}
]
}
]
}
}
Test
Her hook’u test etmek için:
- Auto-format: Bir Python dosyasını Edit tool ile düzenle, ruff’un otomatik çalıştığını kontrol et
- WIP persistence: Birkaç dosya değiştir,
/compactçalıştır, yeni session başlat, checkpoint’in restore edildiğini kontrol et - Axe bridge:
git diff | docker run --rm -i -v ~/.config/axe:/home/axe/.config/axe:ro axe run code-reviewer
İlgili Yazılar
- Claude Code’da Context Yönetimi: Context window optimizasyonu ve bağlam mühendisliği
- LLM Davranışsal Bozulma Modları: Instruction attenuation ve ceremonialization kavramları
- Pre-injection vs MCP: Context Engineering’de İki Yaklaşım: Context delivery stratejileri karşılaştırması
- Context Engineering Ekosistemi: CLAUDE.md, hooks ve MCP’nin birlikte çalışması
- AI Destekli Codebase Audit: Hook’ların ve workflow otomasyonunun 6 track’li audit döngüsündeki rolü
Footnotes
- GrapeRoot vs CodeGraphContext Benchmark (2026). Pre-injection: $0.17/prompt, 8.9 turn. MCP tool call: $0.27/prompt, 11.7 turn. %31 maliyet azalması, %24 daha az turn. ↩
- Meta-RL with Self-Reflection: (1) Gao, Z., et al. (2026). MR-Search. arXiv. (2) Xie, T., et al. (2025). LaMer. ICLR 2026. Reflection-only %80.5 vs full history %74.4. (3) Xu, C., et al. (2026). MAGE. arXiv. ↩
- SashiDo (2026). AI-Assisted Programming That Actually Ships: The Long-Running Agent Harness. Dev.to. ↩
- J.R. Swab (2026). How to Stop Babysitting Your AI Agents. Dev.to. ↩
- 01 Hook'lar CLAUDE.md talimatlarının deterministik versiyonudur: probabilistik kurallar zamanla ceremonialize olur, hook'lar her seferinde aynı şekilde çalışır
- 02 PostToolUse auto-format ile format hataları sıfıra iner, ruff ve eslint her edit sonrası otomatik çalışır
- 03 PreCompact ile WIP persistence, Meta-RL araştırmasının 'reflection-only > full trajectory' bulgusunu pratiğe taşır
- 04 Axe CLI stdin/stdout composability ile hook'lardan bağımsız LLM agent'ları tetiklenebilir, Docker üzerinden izole çalışır
- 05 Hook sistemi Claude Code'u diğer CLI agent'lardan (Codex, Gemini CLI) ayıran temel özelliktir
+ Claude Code hook nedir?
Claude Code'un belirli olaylarda (dosya düzenleme, tool çağrısı, context compaction, session başlangıcı) otomatik olarak çalıştırdığı shell komutları veya script'lerdir. settings.json içinde tanımlanır.
+ Hook'lar CLAUDE.md kurallarından ne farkı var?
CLAUDE.md kuralları probabilistiktir: model bunlara uyma olasılığı context'e ve session uzunluğuna göre değişir. Hook'lar deterministiktir: her seferinde aynı şekilde çalışır, istisna tanımaz.
+ WIP persistence neden gerekli?
Uzun session'larda context compaction eski bilgileri siler. PreCompact hook'u compaction öncesi çalışma durumunu kaydeder, SessionStart hook'u yeni session'da bu durumu restore eder. 24 saat sonra otomatik temizlenir.
+ Axe CLI nedir?
Go ile yazılmış, Unix felsefesine uygun, single-purpose LLM agent'ları çalıştıran bir CLI aracıdır. TOML config + SKILL.md ile tanımlanan agent'lar stdin/stdout üzerinden compose edilebilir.