Claude Code hooks — kompletní průvodce guardraily, které reálně fungují

Claude Code hooks — kompletní průvodce guardraily, které reálně fungují

PreToolUse, PostToolUse, Notification. Co jsou Claude Code hooks, jak je nakonfigurovat v settings.json a tři vzory, které nasazuju do každého produkčního repa.

Jakub Kontra
Jakub Kontra
Developer

Shrnutí

Claude Code hooks jsou shell příkazy, které se spouštějí automaticky kolem volání nástrojů — před tím, než se příkaz spustí, po tom, co se zapíše soubor, když agent čeká na vstup. Žijí v settings.json, mohou volání nástroje rovnou zablokovat a jsou jediný mechanismus v celém stacku, který agent nedokáže obejít. Pokud provozujete Claude Code na čemkoli, co se dotýká produkce, a ještě nemáte hooks nakonfigurované, je to ten největší upgrade spolehlivosti, který máte k dispozici.

Tenhle průvodce projde tři typy hooks, schema v settings.json, kontrakt na exit kódy a tři vzory, které nasazuju do každého repa, kterého se dotknu.


Proč hooks existují

Prompty jsou doporučení. Hooks jsou smlouvy.

Do CLAUDE.md můžete napsat „vždycky spusť pnpm format po úpravě kódu" a agent to většinou dodrží. Většinou nestačí, když cenou za selhání je rozbitý main branch, uniklý secret nebo PR, který potichu obejde vaše lint pravidla. Hooks tu mezeru zavírají — posouvají chování z „model se snaží poslouchat" na „systém to vynucuje".

Viděl jsem týmy strávit týdny debatováním nad zněním CLAUDE.md, aby model dotlačily ke svým konvencím. Deset řádků hooku dělá to samé deterministicky.

Tři typy hooks

PreToolUse — běží před spuštěním nástroje

Dostane jméno nástroje a argumenty. Může volání schválit, zamítnout, nebo ho pustit s varováním. Nejdůležitější hook ve vašem setupu, protože tady se blokují akce, na kterých vám skutečně záleží.

Typické použití:

  • Zablokovat rm -rf mimo sandbox adresář
  • Zablokovat git push --force na main/master
  • Odmítnout Bash volání, která obsahují zjevné secrets nebo credentials
  • Vynutit, aby Write nikdy nesáhl na migrations/ nebo src/auth/ bez explicitního approval flagu

PostToolUse — běží po spuštění nástroje

Dostane jméno nástroje, argumenty a výsledek. Nedokáže volání vrátit zpět, ale umí formátovat, validovat, logovat. Tady reálně bydlí „agent nemůže zapomenout naformátovat".

Typické použití:

  • Automaticky spustit prettier --write (nebo black, gofmt, rustfmt) po každém Write
  • Přidat záznam do changelogu po editu package.json
  • Vypustit strukturovaný log záznam pro audit
  • Spustit rychlý lint a ohlásit chyby zpět agentovi

Notification — běží, když agent potřebuje vstup

Dostane prompt, na který agent čeká. Ideální pro „desktop notifikaci, když Claude stojí" a podobnou low-stakes automatizaci.

Typické použití:

  • Pingnout macOS notification center, abyste se vrátili k agentovi, co čeká už dvě minuty
  • Poslat zprávu do Slack kanálu, když agent chce lidský review
  • Pípnout — ano, obyčejný terminálový zvonek je pořád nejrychlejší způsob, jak vás upozornit

Schema v settings.json

Hooks se konfigurují v .claude/settings.json (per projekt) nebo ~/.claude/settings.json (per uživatel). Projektové nastavení vyhrává.

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": ".claude/hooks/block-dangerous-bash.sh"
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": ".claude/hooks/format.sh"
          }
        ]
      }
    ]
  }
}

Dvě věci, které stojí za to vědět:

  • matcher je regex na jméno nástroje. "Bash" matchne jen Bash. "Write|Edit" matchne oba. ".*" matchne všechno — užitečné, občas nebezpečné.
  • command dostane vstup nástroje jako JSON na stdin. Váš skript ho parsne, rozhodne co dělat, skončí.

Kontrakt na exit kódy

Tohle je část, na které lidi nejčastěji padají.

  • Exit 0 — schvaluji (pro PreToolUse) nebo no-op (pro PostToolUse). Volání nástroje pokračuje.
  • Exit 2 — blokuji. Volání nástroje je zamítnuto. Stderr vašeho skriptu se ukáže agentovi jako důvod blokace. Takhle se z „prosím ne" stane „systém to nedovolí".
  • Jakýkoli jiný non-zero — chyba. Volání selže, ale jako error, ne jako záměrná blokace. Rezervujte si to pro skutečné selhání hooku.

Pište jasné stderr zprávy u exit 2. Agent je čte a přizpůsobí se. „Blokováno: force-push na main není povolený, otevřete PR" agentovi říká, co má dělat dál. „Error" ho nenaučí nic.

Tři vzory, které nasazuju do každého repa

Vzor 1: blokuj destruktivní Bash

#!/usr/bin/env bash
# .claude/hooks/block-dangerous-bash.sh
set -euo pipefail

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

if echo "$command" | grep -qE '(rm -rf /|git push.*--force.*main|git push.*-f.*main)'; then
  echo "Blokováno: detekován destruktivní příkaz" >&2
  exit 2
fi

exit 0

Pokrývá 90 % případů „agent rozmlátil repo" deseti řádky. Regex časem rozšiřujte, jak budou přibývat nové footguny.

Vzor 2: automatický formát po zápisu

#!/usr/bin/env bash
# .claude/hooks/format.sh
set -euo pipefail

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

case "$file_path" in
  *.ts|*.tsx|*.js|*.jsx|*.json|*.md|*.mdx)
    pnpm prettier --write "$file_path" >/dev/null 2>&1 || true
    ;;
  *.py)
    ruff format "$file_path" >/dev/null 2>&1 || true
    ;;
  *.go)
    gofmt -w "$file_path" >/dev/null 2>&1 || true
    ;;
esac

exit 0

Všimněte si || true — selhání formátteru by nemělo agenta zablokovat, prostě se přeskočí. Další lint reálné problémy stejně vytáhne.

Vzor 3: vyžaduj explicitní approval pro citlivé cesty

#!/usr/bin/env bash
# .claude/hooks/guard-sensitive-paths.sh
set -euo pipefail

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

case "$file_path" in
  *migrations/*|*src/auth/*|*.env*)
    if [ ! -f ".claude/allow-sensitive.flag" ]; then
      echo "Blokováno: $file_path je citlivý. Pokud to opravdu chcete editovat, vytvořte pro tuhle session .claude/allow-sensitive.flag." >&2
      exit 2
    fi
    ;;
esac

exit 0

Vzor s flag souborem vám dává explicitní bránu „vím, co dělám". Agent si flag sám vytvořit nemůže — to děláte vy. Po session ho smažete. Paranoidní, levné, funguje.

Debugging hooks

Tři věci na zkontrolování, když hook „nefunguje":

  1. Je settings.json validní JSON? Claude Code tiše ignoruje rozbitou konfiguraci. Pro jistotu spusťte jq . .claude/settings.json.
  2. Je skript spustitelný? chmod +x .claude/hooks/*.sh. Tohle jsem přehlédl víckrát, než bych chtěl přiznat.
  3. Čte se stdin? Pokud váš skript visí, nejspíš čeká na stdin. Vždycky input=$(cat) na začátku.

Logujte během vývoje verbose:

echo "hook invoked: $(date) $0" >> .claude/hooks.log
echo "$input" >> .claude/hooks.log

Po odladění logování smažte.

Kam hooks zapadají v širším obrazu

Hooks jsou jeden ze šesti stavebních bloků, které popisuju v delším postu o nasazení AI. CLAUDE.md dává agentovi kontext, skilly mu dávají opakovaně použitelné recepty, hooks vynucují invarianty. Dohromady je v tom rozdíl mezi agentem, který vás občas překvapí, a agentem, který se chová jako spolehlivý kolega.

Pokud váš tým zavádí Claude Code a tahle část vám přijde mlhavá, napište mi — vedu on-site školení, která přesně tohle procházejí. me@jakubkontra.com