Автоматична перевірка коду з Hooks: якість гарантована при написанні

PostToolUse Hooks автоматично запускають lint після кожного запису файлу. Код виходу 2 повертає помилки Claude для автоматичного виправлення.


Claude Code пише код швидко, але не завжди пам'ятає запустити lint. Ви просите його "перевірити заодно" — іноді робить, іноді ні. Hooks вирішують цю проблему: переносять відповідальність за перевірку коду з Claude на систему.

Ця стаття зосереджена на одному: використовувати PostToolUse Hooks для автоматичного запуску перевірок після написання коду Claude, щоб кожна зміна файлу відповідала вашим стандартам.


Підхід: PostToolUse + фільтрація за типом файлу

Логіка Hook перевірки коду проста:

  1. Claude викликає Write або Edit для запису файлу
  2. Hook перехоплює подію та отримує шлях до файлу
  3. За розширенням визначає, який інструмент запустити
  4. Перевірка пройшла: код виходу 0, Claude продовжує
  5. Перевірка не пройшла: код виходу 2, помилки передаються Claude для виправлення

Код виходу 2 — ключовий: Claude отримує помилку та автоматично виправляє її, формуючи цикл "написати→перевірити→виправити".


Базове налаштування: проекти на одній мові

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'"
          }
        ]
      }
    ]
  }
}

Розширене налаштування: багатомовні проекти

Створіть .claude/hooks/lint.sh:

#!/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:

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

Автоматичне виправлення через Claude

Код виходу 2 + stderr запускає автоматичне виправлення:

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
}

Виключення файлів, що не потребують перевірки

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

На практиці

Після налаштування робочий процес виглядає так:

  1. Просите Claude написати Ruby-файл
  2. Claude записує його інструментом Write
  3. Hook автоматично запускає rubocop -A — знаходить 3 проблеми
  4. RuboCop автоматично виправляє 2; третя потребує людського судження
  5. Третя помилка надсилається Claude через stderr
  6. Claude виправляє код, Hook спрацьовує знову
  7. Друга перевірка пройдена — готово

Вам не потрібно вручну запускати жодних команд перевірки.


Глобальний vs. рівень проекту

Глобальний (~/.claude/settings.json): Коли використовуєте однакові правила у всіх проектах.

Рівень проекту (.claude/settings.json у git): Рекомендується для команд. Будь-хто, хто відкриває репозиторій, автоматично отримує правильну конфігурацію.

Обидва рівні співіснують; hooks проекту об'єднуються з глобальними.


Підсумок

Автоматична перевірка коду з Hooks зводиться до трьох кроків:

  1. PostToolUse + matcher "Write|Edit" для перехоплення запису файлів
  2. Отримати шлях до файлу та направити до потрібного linter за розширенням
  3. При помилці вийти з кодом 2, щоб Claude побачив помилку та виправив

Почніть з однієї мови. Коли запрацює — додайте інші. Збережіть скрипти в .claude/hooks/ для спільного доступу команди.