# Hooki w Claude Code dla początkujących: automatyzacja powtarzalnych czynności

> Kompletny praktyczny przewodnik po konfiguracji hooków w Claude Code: automatyczny linting, formatowanie, walidacje pre-commit, powiadomienia oraz automatyzacja headless.

## 1. Czym są Hooks w Claude Code i dlaczego są potrzebne

Pracując z asystentem AI w terminalu, programiści często muszą powtarzać te same rutynowe komendy: *"uruchom teraz ESLint"*, *"sformatuj kod przez Prettier"*, *"sprawdź typy przed commitem"*. Nawet jeśli zasady te zostaną wpisane do instrukcji systemowych `CLAUDE.md`, model językowy może od czasu do czasu zapomnieć o ich wykonaniu lub pominąć je ze względu na oszczędność tokenów.

**Hooks (haki)** w Claude Code rozwiązują ten problem radykalnie: są to deterministyczne wyzwalacze, które automatycznie uruchamiają komendy systemowe lub skrypty w konkretnych momentach cyklu życia pracy asystenta.

Logika haków jest prosta:
> **Jeśli Claude wykonał zdarzenie X → system operacyjny gwarantuje uruchomienie akcji Y.**

```mermaid
flowchart LR
    subgraph Текстова_інструкція["CLAUDE.md (Ймовірнісна)"]
        A["Промпт: 'Завжди запускай лінтер'"] --> B{"Модель пам'ятає?"}
        B -->|Іноді| C["Запуск перевірки"]
        B -->|Пропустила| D["Помилки накопичуються"]
    end
    subgraph Нативний_Hook["Hooks у settings.json (Детермінована)"]
        E["Подія: Редагування файлу"] --> F["Автоматичний тригер ОС"]
        F --> G["Гарантоване виконання npx eslint"]
    end
```

### Porównanie podejść do automatyzacji

| Charakterystyka | Ręczne prompty | Instrukcje w CLAUDE.md | Natywne Hooks |
| :--- | :--- | :--- | :--- |
| **Niezawodność wykonania** | Niska (zależy od pamięci człowieka) | Średnia (probabilistyczne zachowanie LLM) | 100% (deterministyczna przechwytywka zdarzeń) |
| **Zużycie tokenów** | Wysokie (tokeny zapytania zużywane za każdym razem) | Średnie (zasada ładowana do każdego kontekstu) | Zerowe (wykonywane lokalnie w shellu) |
| **Szybkość reakcji** | Wolna (ręczne wprowadzanie komend) | Wymaga dodatkowej rundy generowania | Natychmiastowa (natywne wywołanie procesu) |
| **Możliwość blokady** | Brak | Brak | Tak (niezerowy exit code zatrzymuje akcję) |

> [!NOTE]
> Haki Claude Code konfiguruje się w formacie JSON w pliku `.claude/settings.json` na poziomie pojedynczego repozytorium lub globalnie w `~/.claude/settings.json`.

---

## 2. Cykl życia zdarzeń: PreToolUse, PostToolUse, Notification, Stop

W Claude Code przewidziano cztery fundamentalne punkty przechwytujące (zdarzenia), do których można przypiąć zautomatyzowane komendy.

```mermaid
sequenceDiagram
    autonumber
    actor Dev as Розробник
    participant Agent as Claude Code
    participant Hook as Система Hooks
    participant Tool as Інструмент (Bash/Edit/Write)

    Dev->>Agent: Запит на модифікацію коду
    Agent->>Hook: Спроба виклику інструмента
    Note over Hook: PreToolUse Hook
    Hook-->>Agent: Перевірка пройдена (Exit Code 0)
    Agent->>Tool: Виконання операції
    Tool-->>Agent: Результат успішний
    Agent->>Hook: Подія завершення операції
    Note over Hook: PostToolUse Hook
    Hook-->>Agent: Результат лінтингу / форматування
    Agent->>Hook: Завершення відповіді моделі
    Note over Hook: Stop Hook (Сповіщення)
    Agent-->>Dev: Фінальна відповідь
```

### Główne punkty wyzwalające

1. **`PreToolUse` (Przed użyciem narzędzia):** wyzwala się *przed* tym, jak agent wykona akcję. Jeśli komenda haka zwróci błąd (exit code różny od 0), wykonanie akcji zostaje zablokowane. To idealne miejsce dla zabezpieczających sprawdzeń przed commitami czy pushami.
2. **`PostToolUse` (Po użyciu narzędzia):** wyzwala się *bezpośrednio po* pomyślnym wykonaniu narzędzia. Najpopularniejszy wyzwalacz dla automatycznego formatowania kodu (Prettier) lub lintingu zmodyfikowanego pliku (ESLint).
3. **`Notification` (Powiadomienie):** aktywuje się, gdy asystent musi wysłać ważne komunikaty systemowe lub poprosić o dodatkową autoryzację.
4. **`Stop` (Zakończenie odpowiedzi):** wyzwala się w momencie, gdy Claude Code całkowicie zakończył generowanie odpowiedzi i oczekuje na kolejną wiadomość użytkownika. Używany do odtwarzania sygnałów dźwiękowych oraz powiadomień desktopowych.

![Punkty wyzwalające Hooks w cyklu życia](/api/guides-media/automation/hooks-automation-guide-for-beginners/images/hooks-automation-guide-for-beginners-extra-02.webp)

---

## 3. Struktura konfiguracji w settings.json i składnia Matcher

Konfiguracja haków przechowywana jest w pliku `.claude/settings.json`. Jeśli tego pliku jeszcze nie ma w katalogu głównym Twojego projektu, utwórz go.

### Podstawowa składnia konfiguracji

```json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit",
        "hooks": [
          {
            "type": "command",
            "command": "echo 'Починається редагування файлу...'"
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "echo 'Bash-команда завершена успішно'"
          }
        ]
      }
    ]
  }
}
```

### Jak działa pole Matcher

Pole `matcher` określa, na które konkretne narzędzie agenta ma reagować dany hak:

- `"Edit"` – przechwytuje modyfikację już istniejących plików.
- `"Write"` – wyzwala się przy tworzeniu nowego pliku lub pełnym nadpisaniu.
- `"Bash"` – reaguje na uruchomienie dowolnych komend konsolowych.
- `"Bash(git commit*)"` – precyzyjny wzorzec filtrujący wywołania Bash, które zaczynają się od komendy `git commit`.
- `"*"` – uniwersalny selektor (wildcard), który wyzwala się na każde narzędzie agenta.

> [!TIP]
> Wzorce `matcher` są wrażliwe na wielkość liter. Używaj standardowych nazw narzędzi Claude Code: `Edit`, `Write`, `Bash`, `Glob`, `Grep`.

---

## 4. Automatyczny linting i formatowanie (ESLint + Prettier)

Najbardziej praktyczny scenariusz codzienny to delegowanie formatowania i wstępnej kontroli stylu do narzędzi `Prettier` i `ESLint`. Dzięki temu kod zawsze zapisywany jest w repozytorium w idealnym stanie.

### Konfiguracja PostToolUse dla ESLint i Prettier

```json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit",
        "hooks": [
          {
            "type": "command",
            "command": "npx eslint --fix \"$CLAUDE_FILE_PATH\" 2>/dev/null || true"
          }
        ]
      },
      {
        "matcher": "Write",
        "hooks": [
          {
            "type": "command",
            "command": "npx prettier --write \"$CLAUDE_FILE_PATH\" 2>/dev/null || true"
          }
        ]
      }
    ]
  }
}
```

### Analiza flag bezpieczeństwa w komendzie

- `"$CLAUDE_FILE_PATH"` – dynamiczna zmienna środowiskowa, do której Claude automatycznie podstawia pełną ścieżkę do pliku, który został właśnie zmieniony przez agenta.
- `2>/dev/null` – tłumaczy zbędne komunikaty błędów strumienia stderr, aby nie przeciążać terminala.
- `|| true` – krytycznie ważna konstrukcja bash. Gwarantuje ona, że nawet jeśli linter znajdzie niepoprawialne błędy i zwróci kod `1`, sam hak zakończy się kodem `0` i nie zatrzyma dalszej pracy agenta.

```mermaid
flowchart TD
    A["Claude викликає Edit"] --> B["Файл збережено на диску"]
    B --> C["PostToolUse тригер"]
    C --> D["npx eslint --fix $CLAUDE_FILE_PATH"]
    D --> E{"Успішно або || true"}
    E --> F["Агент продовжує вирішувати задачу"]
```

---

## 5. Zabezpieczenia przed git commit (TypeCheck + Testy)

Jeśli do formatowania używaliśmy "miękkich" haków z `|| true`, to do zatwierdzania zmian w systemie kontroli wersji potrzebujemy surowej kontroli jakości (Quality Gate).

Z pomocą `PreToolUse` można zablokować utworzenie commitu, jeśli w projekcie występują błędy kompilacji TypeScript lub padają testy jednostkowe.

### Konfiguracja blokującego haka Pre-commit

```json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash(git commit*)",
        "hooks": [
          {
            "type": "command",
            "command": "npm run typecheck && npm run lint"
          }
        ]
      }
    ]
  }
}
```

### Co dzieje się po wykryciu błędów

1. Claude formułuje komendę `git commit -m "..."`.
2. Przed jej wykonaniem system aktywuje `PreToolUse`.
3. Uruchamiane są komendy walidacyjne: `npm run typecheck` oraz `npm run lint`.
4. **Jeśli wykryto błąd:** proces zwraca niezerowy kod zakończenia (exit code 1).
5. Claude Code przechwytuje wyjście błędu kompilatora bezpośrednio w swoim kontekście.
6. Zamiast zepsutego commitu asystent analizuje tekst błędu, automatycznie poprawia typy w kodzie i ponawia czystą próbę commitu.

> [!IMPORTANT]
> Zwróć uwagę: w blokujących sprawdzeniach `PreToolUse` **nigdy** nie używaj `|| true`, ponieważ sprawdzenie zawsze zostanie uznane za pomyślne, a bariera ochronna przestanie działać.

---

## 6. Powiadomienia audio i desktopowe po zakończeniu zadań (Stop Hook)

Skomplikowane refaktoryzacje lub uruchomienie pełnego zestawu testów mogą trwać od 2 do 10 minut. Zamiast wpatrywać się bez przerwy w terminal, skonfiguruj powiadomienia poprzez zdarzenie `Stop`.

:::tabs
@tab macOS
```json
{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "afplay /System/Library/Sounds/Glass.aiff && osascript -e 'display notification \"Завдання виконано!\" with title \"Claude Code\"'"
          }
        ]
      }
    ]
  }
}
```
@tab Linux (Ubuntu / Debian)
```json
{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "paplay /usr/share/sounds/freedesktop/stereo/complete.oga 2>/dev/null || notify-send 'Claude Code' 'Завдання успішно виконано!'"
          }
        ]
      }
    ]
  }
}
```
@tab Windows (WSL / PowerShell)
```json
{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "powershell.exe -c \"[System.Media.SystemSounds]::Asterisk.Play(); [System.Console]::Beep(800, 250)\""
          }
        ]
      }
    ]
  }
}
```
:::

> [!TIP]
> Powiadomienie wyzwala się tylko wtedy, gdy agent całkowicie kończy generowanie finalnej odpowiedzi, a nie między pośrednimi wywołaniami narzędzi.

---

## 7. Przekazywanie kontekstu przez zmienne środowiskowe

Aby skrypty automatyzacji były elastyczne i adaptacyjne, Claude Code automatycznie eksportuje metadane bieżącej operacji do systemowych zmiennych środowiskowych (Environment Variables).

![Zmienne środowiskowe Claude Code dla haków](/api/guides-media/automation/hooks-automation-guide-for-beginners/images/hooks-automation-guide-for-beginners-extra-01.webp)

### Słownik systemowych zmiennych Claude Code

| Zmienna środowiskowa | Typ wartości | Opis i przykład zawartości |
| :--- | :--- | :--- |
| **`$CLAUDE_FILE_PATH`** | Bezwzględna ścieżka | Ścieżka do konkretnego pliku, który jest obecnie tworzony lub edytowany (`/Users/dev/project/src/index.ts`) |
| **`$CLAUDE_TOOL_NAME`** | Identyfikator tekstowy | Nazwa narzędzia, które zainicjowało zdarzenie (`Edit`, `Write`, `Bash`) |
| **`$CLAUDE_PROJECT_DIR`** | Bezwzględna ścieżka | Katalog główny projektu, w którym uruchomiona jest bieżąca sesja Claude Code |

### Przykład kontekstowego skryptu Bash dla haka

Utwórzmy skrypt `.claude/hooks/smart-validator.sh`:

```bash
#!/usr/bin/env bash
set -e

# Перевіряємо, чи існує файл і яке у нього розширення
if [[ -f "$CLAUDE_FILE_PATH" ]]; then
  case "$CLAUDE_FILE_PATH" in
    *.ts|*.tsx)
      echo "⚡ Валідація TypeScript файлу: $CLAUDE_FILE_PATH"
      npx eslint --fix "$CLAUDE_FILE_PATH" || true
      ;;
    *.json)
      echo "🔍 Перевірка валідності JSON..."
      jq empty "$CLAUDE_FILE_PATH" 2>/dev/null || echo "Помилка формату JSON!"
      ;;
    *.md)
      echo "📝 Оновлено документацію: $(basename "$CLAUDE_FILE_PATH")"
      ;;
  esac
fi
```

Teraz w `.claude/settings.json` wystarczy wskazać wywołanie tego skryptu:

```json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "*",
        "hooks": [
          {
            "type": "command",
            "command": "bash .claude/hooks/smart-validator.sh"
          }
        ]
      }
    ]
  }
}
```

---

## 8. Wzorzec «CI-in-a-Loop»: ciągłe sprzężenie zwrotne

W tradycyjnym rozwoju bez haków pojawia się wzorzec rozszczepienia: agent wprowadza zmiany w dziesiątkach plików, po czym uruchamia się build projektu, który wyrzuca lawinę 40 błędów typów. Agentowi trudno zidentyfikować, która konkretna zmiana doprowadziła do awarii.

**CI-in-a-Loop (Krótka pętla sprzężenia zwrotnego)** odwraca ten proces:

```mermaid
flowchart TD
    A["Claude вносить правку в код"] --> B["Миттєвий запуск tsc"]
    B --> C{"Є помилка?"}
    C -->|Так| D["Claude бачить 1 точкову помилку"]
    D --> E["Миттєвий фікс за 5 секунд"]
    E --> B
    C -->|Ні| F["Перехід до наступного рядка/файлу"]
```

### Konfiguracja cyklicznego audytu TypeScript

```json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit",
        "hooks": [
          {
            "type": "command",
            "command": "npx tsc --noEmit 2>&1 | head -n 20 || true"
          }
        ]
      }
    ]
  }
}
```

### Dlaczego konieczne jest użycie `head -n 20`

Jeśli wyjście kompilatora zwraca setki linii logów, trafiają one do kontekstu modelu i mogą przepełnić limit tokenów. Ograniczenie przez `head -n 20` pokazuje pierwsze, najbardziej krytyczne błędy, dając modelowi precyzyjny punkt orientacyjny do natychmiastowej naprawy bez przeciążania sesji.

---

## 9. Automatyzacja Headless: tryb -p, Cron i Git Hooks

Haki można łączyć z autonomicznym (headless) trybem Claude Code – flagą `-p` (print/prompt). Pozwala to na automatyzację wykonywania zadań całkowicie bez udziału człowieka.

```mermaid
flowchart LR
    A["Розклад Cron (02:00)"] --> B["Скрипт nightly-audit.sh"]
    B --> C["claude -p 'Run test suite, fix bugs, commit'"]
    C --> D["Хуки PostToolUse контролюють код"]
    D --> E["Автоматичний Push результату"]
```

### Autonomiczny skrypt nocnego audytu (nightly-audit.sh)

```bash
#!/usr/bin/env bash
cd /var/www/my-project

# Запуск Claude Code в автономному режимі з фіксованим завданням
claude -p "Run full test suite. If any tests fail, inspect the stack trace and fix them. Ensure typecheck passes. Finally, commit all fixes with a conventional commit." >> /var/log/claude-audit.log 2>&1
```

### Konfiguracja harmonogramu wykonania przez Cron

Otwórz planer zadań (`crontab -e`) i ustaw wykonanie co noc o godzinie 03:00:

```text
0 3 * * * /usr/local/bin/nightly-audit.sh
```

### Uruchomienie sprawdzenia w natywnym Git Hook (.git/hooks/post-merge)

Aby po każdym pobraniu aktualizacji z `git pull` automatycznie uruchamiała się analiza kompatybilności:

```bash
#!/usr/bin/env bash
# .git/hooks/post-merge
echo "🚀 Запуск автоматичної перевірки залежностей через Claude..."
claude -p "Check if package.json was updated. If so, run npm install, verify build, and report summary."
```

Nie zapomnij nadać skryptowi praw do wykonania: `chmod +x .git/hooks/post-merge`.

---

## 10. Najlepsze praktyki inżynierskie i zasady bezpieczeństwa Hooks

Źle skonfigurowane haki mogą zapętlić wykonanie lub zablokować pracę terminala. Przestrzegaj czterech fundamentalnych zasad higieny inżynierskiej.

### Cztery zasady bezpiecznego projektowania haków

1. **Ekstremalna wydajność:** Haki z wydarzeniem `PostToolUse` uruchamiają się po każdej modyfikacji pliku. Jeśli hak wykonuje się dłużej niż 1-2 sekundy, interaktywna praca z Claude stanie się wolna i niewygodna. Uruchamiaj ciężkie testy E2E tylko w `PreToolUse` przed commitem, ale nie po każdym `Edit`.
2. **Obowiązkowe logowanie wyjścia:** Zawsze przekierowuj wyjście skryptów diagnostycznych do tymczasowego pliku logu:
   ```bash
   "command": "bash .claude/hooks/check.sh >> /tmp/claude-hooks.log 2>&1 || true"
   ```
   Jeśli hak przestanie się wyzwalac, będziesz mógł natychmiast otworzyć `/tmp/claude-hooks.log` i znaleźć przyczynę.
3. **Izolowane testowanie w czystym terminalu:** Zanim dodasz jakąkolwiek komendę do `settings.json`, wykonaj ją ręcznie w zwykłym shellu. Jeśli komenda zwraca błąd w konsoli, gwarantuje to złamanie sesji Claude Code.
4. **Zapobieganie nieskończonej rekurencji:** Nigdy nie konfiguruj komendy w `PostToolUse`, która sama modyfikuje pliki projektu bez flag ignorowania (np. zewnętrzny skrypt, który wywołuje ponowny `Edit`), inaczej agent wpadnie w wieczną pętlę wywołań.

> [!WARNING]
> Nie uruchamiaj przez haki komend, które oczekują interaktywnego wejścia od użytkownika (np. potwierdzenia `read -p` czy `sudo` z pytaniem o hasło). Prowadzi to do zawieszenia procesu terminalowego.

---

## 11. Praktyczny warsztat, ściągawka i podsumowująca checklista

Dla szybkiego startu we własnym projekcie skorzystaj z gotowej, skondensowanej ściągawki i sprawdzonego configu produkcyjnego.

![Ściągawka z wyboru typu Hook do automatyzacji](/api/guides-media/automation/hooks-automation-guide-for-beginners/images/hooks-automation-guide-for-beginners-extra-03.webp)

### Gotowy plik konfiguracyjny `.claude/settings.json`

Skopiuj ten wzorcowy config do folderu `.claude` w swoim projekcie:

```json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash(git commit*)",
        "hooks": [
          {
            "type": "command",
            "command": "npm run typecheck && npm test"
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Edit",
        "hooks": [
          {
            "type": "command",
            "command": "npx prettier --write \"$CLAUDE_FILE_PATH\" 2>/dev/null || true"
          }
        ]
      },
      {
        "matcher": "Write",
        "hooks": [
          {
            "type": "command",
            "command": "npx prettier --write \"$CLAUDE_FILE_PATH\" 2>/dev/null || true"
          }
        ]
      }
    ],
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "osascript -e 'display notification \"Роботу завершено!\" with title \"Claude Code\"' 2>/dev/null || true"
          }
        ]
      }
    ]
  }
}
```

### Szybka samoocena

> **1. Czym `PreToolUse` zasadniczo różni się od `PostToolUse`?**
>
> > [!TIP]
> > **Odpowiedź:** `PreToolUse` uruchamia się *przed* wykonaniem akcji narzędzia i potrafi ją zablokować przy niezerowym exit code. `PostToolUse` uruchamia się *po* pomyślnym zakończeniu operacji i służy do formatowania lub lintingu.

> **2. Po co w hakach formatowania dodaje się `|| true`?**
>
> > [!TIP]
> > **Odpowiedź:** Aby błędy lintera lub formattera nie zwracały statusu awaryjnego i nie zatrzymywały procesu generowania odpowiedzi agenta.

> **3. Która zmienna środowiskowa zawiera ścieżkę do pliku, który był właśnie edytowany?**
>
> > [!TIP]
> > **Odpowiedź:** Zmienna `$CLAUDE_FILE_PATH`.

### Podsumowująca checklista wdrożenia Hooks

- [ ] Utworzono katalog `.claude/` oraz plik `settings.json` w korzeniu projektu.
- [ ] Skonfigurowano automatyczne formatowanie zmodyfikowanych plików przez `PostToolUse` + `Prettier`.
- [ ] Dodano zabezpieczający hak `PreToolUse` dla blokad przed commitami.
- [ ] Przetestowano skrypty izolacyjnie w czystym terminalu przed integracją.