Hooks ile Otomatik Kod Denetimi: Yazarken Kalite Güvencesi

PostToolUse Hooks ile Claude dosya yazdıktan sonra lint otomatik çalışır. Çıkış kodu 2, hataları Claude'a geri göndererek otomatik düzeltme sağlar.


Claude Code kod yazarken hızlıdır, ancak lint çalıştırmayı her zaman hatırlamaz. "Yazarken bir de kontrol et" diyorsunuz, bazen yapıyor bazen atlamıyor. Hooks bu sorunu çözüyor — kod denetimini "Claude'un sorumluluğu"ndan "sistemin sorumluluğu"na taşıyor.

Bu makale tek bir şeye odaklanıyor: Claude kod yazdıktan sonra otomatik olarak denetim başlatmak için PostToolUse Hooks kullanmak ve her dosya değişikliğinin standartlarınızı karşılamasını sağlamak.


Yaklaşım: PostToolUse + Dosya Türü Filtreleme

Kod denetimi Hook'unun mantığı basittir:

  1. Claude bir dosya yazmak için Write veya Edit çağırır
  2. Hook bu olayı yakalar ve dosya yolunu alır
  3. Uzantıya göre hangi denetim aracının çalıştırılacağını belirler
  4. Denetim geçti: çıkış kodu 0, Claude devam eder
  5. Denetim başarısız: çıkış kodu 2, hatalar Claude'a gönderilerek düzeltmesi istenir

Çıkış kodu 2 kilit noktadır — Claude hatayı alır ve otomatik düzelterek "yaz→denetle→düzelt" döngüsü oluşur.


Temel Yapılandırma: Tek Dilli Projeler

Ruby (RuboCop)

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "bash -c 'file=$(echo \"$CLAUDE_TOOL_INPUT\" | jq -r .file_path 2>/dev/null); [[ \"$file\" == *.rb ]] && rubocop -A \"$file\" --no-color -q || true'"
          }
        ]
      }
    ]
  }
}

JavaScript/TypeScript (ESLint)

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "bash -c 'file=$(echo \"$CLAUDE_TOOL_INPUT\" | jq -r .file_path 2>/dev/null); [[ \"$file\" =~ \\.(js|ts|jsx|tsx)$ ]] && npx eslint --fix \"$file\" || true'"
          }
        ]
      }
    ]
  }
}

Python (ruff)

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "bash -c 'file=$(echo \"$CLAUDE_TOOL_INPUT\" | jq -r .file_path 2>/dev/null); [[ \"$file\" == *.py ]] && ruff check --fix \"$file\" && ruff format \"$file\" || true'"
          }
        ]
      }
    ]
  }
}

Gelişmiş Yapılandırma: Çok Dilli Projeler

Denetim mantığını bağımsız bir betiğe taşımak, JSON'a komut yığmaktan daha kolay yönetilir.

.claude/hooks/lint.sh oluşturun:

#!/bin/bash
set -e

input=$(cat)
file=$(echo "$input" | jq -r '.tool_input.file_path // empty')

[[ -z "$file" ]] && exit 0
[[ ! -f "$file" ]] && exit 0

ext="${file##*.}"

case "$ext" in
  rb)    rubocop -A "$file" --no-color -q ;;
  js|ts|jsx|tsx) npx eslint --fix "$file" --quiet ;;
  py)    ruff check --fix "$file"; ruff format "$file" ;;
  go)    gofmt -w "$file"; golangci-lint run "$file" 2>&1 ;;
  *)     exit 0 ;;
esac

settings.json'da betiği referans alın:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [{ "type": "command", "command": "bash .claude/hooks/lint.sh" }]
      }
    ]
  }
}

Claude'un Otomatik Düzeltmesini Sağlamak

Çıkış kodu 2 + stderr, Claude'un otomatik düzeltmesinin anahtarıdır:

run_lint() {
  local output exit_code
  output=$(rubocop "$file" --no-color 2>&1)
  exit_code=$?
  if [[ $exit_code -ne 0 ]]; then
    echo "$output" >&2
    exit 2
  fi
  rubocop -A "$file" --no-color -q
}

Denetim Gerektirmeyen Dosyaları Hariç Tutma

skip_patterns=("vendor/" "node_modules/" "db/schema.rb" ".min.js" "_test.go")
for pattern in "${skip_patterns[@]}"; do
  [[ "$file" == *"$pattern"* ]] && exit 0
done

Pratikte Sonuç

Yapılandırıldıktan sonra iş akışı şöyle görünür:

  1. Claude'dan bir Ruby dosyası yazmasını istiyorsunuz
  2. Claude Write aracıyla yazar
  3. Hook otomatik olarak rubocop -A çalıştırır — 3 sorun bulur
  4. RuboCop 2'sini otomatik düzeltir; 3.'sü insan değerlendirmesi gerektirir
  5. 3. hata stderr üzerinden Claude'a gönderilir
  6. Claude kodu düzeltir, Hook yeniden tetiklenir
  7. İkinci denetim geçti — tamamlandı

Hiçbir zaman manuel olarak denetim komutu çalıştırmanız gerekmez.


Global ve Proje Düzeyi

Global (~/.claude/settings.json): Tüm projelerde aynı kuralları kullandığınızda uygundur.

Proje düzeyi (git'e commit edilen .claude/settings.json): Ekipler için önerilir. Depoyu açan herkes otomatik olarak doğru yapılandırmayı alır.

İkisi bir arada bulunabilir; proje düzeyi hook'lar globallerle birleşerek ikisi de çalışır.


Özet

Hooks ile otomatik kod denetimi üç adıma iner:

  1. PostToolUse + "Write|Edit" matcher ile dosya yazmalarını yakalamak
  2. Dosya yolunu alıp uzantıya göre doğru linter'a yönlendirmek
  3. Başarısız olduğunda exit code 2 ile çıkarak Claude'un hatayı görüp düzeltmesini sağlamak

Bir dille başlayın. Çalışınca diğerlerini ekleyin. Betikleri .claude/hooks/'a commit edin ve ekiple paylaşın.