Hooki w Claude Code: automatyzacja zdarzeń
Automatyzuj pracę przez hooki w Claude Code. Poznaj PreToolUse, PostToolUse, walidację, logowanie i integracje z zewnętrznymi narzędziami.
Hooki w Claude Code pozwalają automatycznie wykonywać działania w odpowiedzi na zdarzenia, takie jak użycie narzędzia, wysłanie promptu czy rozpoczęcie sesji. Ten mechanizm jest przydatny wtedy, gdy chcesz wymuszać reguły jakości, dodawać walidację albo ograniczać ryzykowne operacje.
Czym są hooki?
Hooks to skrypty lub komendy wywoływane automatycznie w odpowiedzi na zdarzenia w Claude Code.
Przykłady użycia:
- Automatyczne formatowanie kodu po edycji
- Logowanie komend Bash do dziennika audytowego
- Walidacja przed wykonaniem ryzykownych operacji
- Wysyłanie notyfikacji do Slacka
- Dodawanie dodatkowego kontekstu do promptów
8 typów zdarzeń hooków
Claude Code wspiera 8 głównych typów hooków zdarzeniowych:
1. PreToolUse
Kiedy: Po utworzeniu parametrów tool przez Claude, przed wykonaniem
Typowe zastosowania:
- Walidacja przed wykonaniem
- Proces zatwierdzania działań
- Logowanie planowanych operacji
- Blokowanie ryzykownych poleceń
2. PostToolUse
Kiedy: Natychmiast po udanym wykonaniu tool
Use cases:
- Auto-formatting po edycji plików
- Running tests po zmianach kodu
- Notyfikacje o zakończeniu
- Cleanup operations
3. UserPromptSubmit
Kiedy: Gdy użytkownik wysyła prompt, przed przetworzeniem przez Claude
Use cases:
- Context injection
- Enriching prompts z dodatkowymi danymi
- User input validation
- Analytics tracking
4. Notification
Kiedy: Claude wysyła notyfikację (permission requests, idle waiting)
Use cases:
- Auto-approval dla trusted operations
- Logging permission requests
- Custom notification routing
5. Stop
Kiedy: Main agent kończy odpowiedź
Use cases:
- Session summary
- Archiving conversation
- Metrics collection
6. SubagentStop
Kiedy: Subagent kończy zadanie
Use cases:
- Subagent result processing
- Performance tracking
- Cleanup po subagent tasks
7. SessionStart
Kiedy: Na początku sesji lub resume
Use cases:
- Environment setup
- Loading context
- Initializing integrations
8. SessionEnd
Kiedy: Zakończenie sesji
Use cases:
- Cleanup operations
- Saving state
- Final reporting
Konfiguracja Hooks
Hooks definiuje się w plikach settings:
~/.claude/settings.json- User-level (wszystkie projekty).claude/settings.json- Project-level (team shared).claude/settings.local.json- Local overrides (gitignored)
Podstawowa Struktura
{
"hooks": {
"EventName": [
{
"matcher": "ToolPattern",
"hooks": [
{
"type": "command",
"command": "bash-command",
"timeout": 60
}
]
}
]
}
}
Matcher Patterns
Matchers określają, które tools powinny wywołać hook.
Case-sensitive patterns:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write", // Dokładne dopasowanie - tylko Write tool
"hooks": [...]
},
{
"matcher": "Edit|Write", // Regex - Edit LUB Write
"hooks": [...]
},
{
"matcher": "Notebook.*", // Regex - wszystkie Notebook tools
"hooks": [...]
},
{
"matcher": "*", // Wildcard - wszystkie tools
"hooks": [...]
}
]
}
}
Popularne tool patterns:
Bash- Shell commandsRead,Write,Edit- File operationsGlob,Grep- File searchingWebFetch,WebSearch- Web operationsTask- Subagent tasksmcp__*- Wszystkie MCP toolsmcp__github__*- Tylko GitHub MCP tools
Hook Input Format
Hooks otrzymują JSON via stdin ze szczegółami eventu:
{
"session_id": "abc123",
"transcript_path": "/path/to/transcript.md",
"cwd": "/project/directory",
"hook_event_name": "PostToolUse",
"tool_name": "Write",
"tool_input": {
"file_path": "/path/to/file.js",
"content": "const x = 1;"
},
"tool_output": "File written successfully"
}
Dostęp do danych w hookach:
Przez environment variables:
$TOOL_NAME- Nazwa użytego tool$TOOL_INPUT_<param>- Parametry (np.$TOOL_INPUT_file_path)$CLAUDE_PROJECT_DIR- Root directory projektu$CLAUDE_CODE_REMOTE-"true"jeśli remote environment
Hook Output i Exit Codes
Exit Codes
# 0 - Success (stdout pokazany w transcript mode)
exit 0
# 2 - Blocking error (stderr przekazany do Claude)
exit 2
# Inne - Non-blocking error (stderr pokazany użytkownikowi)
exit 1
JSON Output (Advanced Control)
{
"continue": true,
"stopReason": "message",
"suppressOutput": true,
"hookSpecificOutput": {
"hookEventName": "EventType",
"permissionDecision": "allow",
"additionalContext": "Extra info for Claude"
}
}
Pola:
continue- Czy kontynuować executionstopReason- Powód zatrzymaniasuppressOutput- Ukryj output hookpermissionDecision-"allow"|"deny"|"ask"(dla Notification hooks)additionalContext- Context dodany do UserPromptSubmit
Praktyczne Przykłady Hooks
Przykład 1: Auto-formatting Po Edycji
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "npx prettier --write \"$TOOL_INPUT_file_path\"",
"timeout": 30
}
]
}
]
}
}
Co robi: Po każdym Write lub Edit, automatycznie formatuje plik przez Prettier.
Przykład 2: Bash Command Logging
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "echo \"[$(date)] Executing: $TOOL_INPUT_command\" >> .claude/bash-audit.log",
"timeout": 5
}
]
}
]
}
}
Co robi: Loguje wszystkie Bash commands przed wykonaniem do audit log.
Przykład 3: Dangerous Command Blocking
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "bash -c 'if echo \"$TOOL_INPUT_command\" | grep -qE \"rm -rf|sudo|curl.*sh\"; then echo \"Dangerous command blocked\" >&2 && exit 2; fi'",
"timeout": 5
}
]
}
]
}
}
Co robi: Blokuje potencjalnie niebezpieczne komendy (exit 2 = blocking error).
Przykład 4: Auto-testing Po Zmianach
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "if echo \"$TOOL_INPUT_file_path\" | grep -q '\\.test\\|spec'; then npm test -- \"$TOOL_INPUT_file_path\"; fi",
"timeout": 120
}
]
}
]
}
}
Co robi: Uruchamia testy automatycznie, gdy edytujesz pliki testowe.
Przykład 5: Context Injection
{
"hooks": {
"UserPromptSubmit": [
{
"matcher": "*",
"hooks": [
{
"type": "command",
"command": "echo '{\"additionalContext\": \"Current branch: $(git branch --show-current)\\nLast commit: $(git log -1 --oneline)\"}'",
"timeout": 10
}
]
}
]
}
}
Co robi: Automatycznie dodaje Git context do każdego promptu (UserPromptSubmit + additionalContext).
Przykład 6: Slack Notifications
{
"hooks": {
"Stop": [
{
"matcher": "*",
"hooks": [
{
"type": "command",
"command": "curl -X POST https://hooks.slack.com/services/YOUR/WEBHOOK/URL -H 'Content-Type: application/json' -d '{\"text\": \"Claude Code session completed\"}'",
"timeout": 10
}
]
}
]
}
}
Co robi: Wysyła notyfikację do Slacka po zakończeniu sesji.
Przykład 7: Environment Setup
{
"hooks": {
"SessionStart": [
{
"matcher": "*",
"hooks": [
{
"type": "command",
"command": "echo 'export PROJECT_NAME=my-app' > \"$CLAUDE_ENV_FILE\" && echo 'export ENV=development' >> \"$CLAUDE_ENV_FILE\"",
"timeout": 10
}
]
}
]
}
}
Co robi: Setup environment variables na początku sesji (przez $CLAUDE_ENV_FILE).
Przykład 8: MCP Tool Monitoring
{
"hooks": {
"PreToolUse": [
{
"matcher": "mcp__github__*",
"hooks": [
{
"type": "command",
"command": "echo \"[$(date)] GitHub MCP call: $TOOL_NAME\" >> .claude/mcp-github.log",
"timeout": 5
}
]
}
]
}
}
Co robi: Loguje wszystkie wywołania GitHub MCP tools.
Zaawansowane Patterns
Multiple Hooks na Event
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "npx prettier --write \"$TOOL_INPUT_file_path\"",
"timeout": 30
},
{
"type": "command",
"command": "npx eslint --fix \"$TOOL_INPUT_file_path\"",
"timeout": 30
},
{
"type": "command",
"command": "git add \"$TOOL_INPUT_file_path\"",
"timeout": 10
}
]
}
]
}
}
Co robi: 3 hooks wykonywane równolegle po edycji: format, lint, git add.
Conditional Hooks
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "if [ \"$CLAUDE_CODE_REMOTE\" = \"true\" ]; then echo 'Remote execution detected' >> remote.log; fi",
"timeout": 5
}
]
}
]
}
}
Co robi: Hook wykonuje się tylko w remote environment.
File Type Specific Hooks
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "case \"$TOOL_INPUT_file_path\" in *.js|*.ts) npx eslint --fix \"$TOOL_INPUT_file_path\" ;; *.py) black \"$TOOL_INPUT_file_path\" ;; *.go) gofmt -w \"$TOOL_INPUT_file_path\" ;; esac",
"timeout": 60
}
]
}
]
}
}
Co robi: Różne formattery dla różnych języków.
Execution Details
Parallel Execution
Wszystkie matching hooks wykonują się równolegle:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write",
"hooks": [
{"type": "command", "command": "hook1.sh"}, // \
{"type": "command", "command": "hook2.sh"}, // |--> Równolegle
{"type": "command", "command": "hook3.sh"} // /
]
}
]
}
}
Deduplication
Identyczne komendy są deduplikowane:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write",
"hooks": [
{"type": "command", "command": "npm test"} // Wykonane
]
},
{
"matcher": "Edit",
"hooks": [
{"type": "command", "command": "npm test"} // Deduplikowane jeśli Write+Edit match
]
}
]
}
}
Timeouts
Domyślny timeout: 60 sekund
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write",
"hooks": [
{
"type": "command",
"command": "long-running-task.sh",
"timeout": 300 // 5 minut
}
]
}
]
}
}
Security Best Practices
1. Validate Input
Zawsze waliduj dane z $TOOL_INPUT_*:
#!/bin/bash
# validate-hook.sh
FILE="$TOOL_INPUT_file_path"
# Check for path traversal
if echo "$FILE" | grep -q '\.\./'; then
echo "Path traversal attempt blocked" >&2
exit 2
fi
# Check for absolute path outside project
if [[ "$FILE" = /* ]] && [[ ! "$FILE" = "$CLAUDE_PROJECT_DIR"* ]]; then
echo "Access outside project blocked" >&2
exit 2
fi
# Proceed with safe operation
prettier --write "$FILE"
2. Quote Variables
Zawsze cytuj zmienne w bash:
# ❌ Niebezpieczne
prettier --write $TOOL_INPUT_file_path
# ✅ Bezpieczne
prettier --write "$TOOL_INPUT_file_path"
3. Avoid Sensitive Files
#!/bin/bash
FILE="$TOOL_INPUT_file_path"
# Blokuj sensitive files
if echo "$FILE" | grep -qE '\\.env$|\\.git/|id_rsa|credentials'; then
echo "Cannot modify sensitive file" >&2
exit 2
fi
4. Use Absolute Paths
#!/bin/bash
# ❌ Relative path - może być exploitation
cd "$TOOL_INPUT_directory" && rm file.txt
# ✅ Absolute path
rm "$CLAUDE_PROJECT_DIR/$TOOL_INPUT_directory/file.txt"
5. Limit Permissions
Hook ma permissions użytkownika - ogranicz dostęp:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "if echo \"$TOOL_INPUT_command\" | grep -q 'sudo'; then echo 'sudo blocked' >&2 && exit 2; fi",
"timeout": 5
}
]
}
]
}
}
Real-World Use Cases
Use Case 1: Code Review Workflow
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "npx eslint \"$TOOL_INPUT_file_path\" --format json > /tmp/lint.json && if [ $(jq '.[] | select(.errorCount > 0) | length' /tmp/lint.json) -gt 0 ]; then echo 'Linting errors detected' >&2 && exit 2; fi",
"timeout": 60
}
]
}
]
}
}
Workflow: Błędy lintingu blokują Claude przed dalszymi zmianami.
Use Case 2: Continuous Testing
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "npm test -- --findRelatedTests \"$TOOL_INPUT_file_path\" --passWithNoTests",
"timeout": 120
}
]
}
],
"Stop": [
{
"matcher": "*",
"hooks": [
{
"type": "command",
"command": "npm test -- --coverage && echo 'Coverage report: file://$(pwd)/coverage/index.html'",
"timeout": 300
}
]
}
]
}
}
Workflow: Testy after każdej zmiany, full coverage na końcu sesji.
Use Case 3: Deployment Gate
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "if echo \"$TOOL_INPUT_command\" | grep -q 'deploy'; then echo 'Deployment requires manual approval' >&2 && exit 2; fi",
"timeout": 5
}
]
}
]
}
}
Workflow: Blokuj auto-deployment, wymagaj manual approval.
Use Case 4: Analytics & Metrics
{
"hooks": {
"UserPromptSubmit": [
{
"matcher": "*",
"hooks": [
{
"type": "command",
"command": "curl -X POST https://analytics.company.com/track -d '{\"event\": \"claude_prompt\", \"user\": \"$USER\", \"timestamp\": \"$(date -Iseconds)\"}'",
"timeout": 10
}
]
}
],
"Stop": [
{
"matcher": "*",
"hooks": [
{
"type": "command",
"command": "curl -X POST https://analytics.company.com/track -d '{\"event\": \"claude_session_complete\", \"session_id\": \"$SESSION_ID\", \"duration\": \"$(date +%s)\"}'",
"timeout": 10
}
]
}
]
}
}
Workflow: Track usage metrics dla team analytics.
Debugging Hooks
Check Hook Configuration
claude
> /hooks
Output pokazuje:
- Załadowane hooks
- Active matchers
- Configuration source (user/project/local)
View Hook Output
Hooks output jest widoczny w transcript mode.
Enable transcript:
claude --transcript
Test Hook Manually
# Symuluj hook input
echo '{"tool_name": "Write", "tool_input": {"file_path": "test.js"}}' | \
TOOL_NAME=Write \
TOOL_INPUT_file_path=test.js \
bash -c 'npx prettier --write "$TOOL_INPUT_file_path"'
Hook Errors
Check stderr output:
- Exit 2 → Claude otrzyma error
- Exit 0 → Success
- Exit 1 → User widzi error, Claude kontynuuje
Snapshot Behavior
Ważne: Hooks są snapshot at startup.
External zmiany w settings wymagają:
claude
> /hooks
Następnie wybierz “Reload hooks” aby zaaplikować nową konfigurację.
Dokumentacja i zasoby
Oficjalna Dokumentacja
Powiązane Artykuły
Podsumowanie
Hooki są najbardziej użyteczne wtedy, gdy rozwiązują konkretny problem: pilnują jakości kodu, blokują niebezpieczne operacje albo przygotowują środowisko pracy. Nie warto zaczynać od zbyt rozbudowanej automatyzacji, bo to zwykle utrudnia diagnostykę i utrzymanie.
Najlepiej wdrażać je etapami. Najpierw prosty PostToolUse do formatowania, potem PreToolUse do walidacji, a dopiero później bardziej złożone działania związane z kontekstem sesji czy integracjami zespołowymi. Taka kolejność daje kontrolę i pozwala łatwo ocenić, które hooki faktycznie pomagają.
Podobał Ci się ten artykuł?
Udostępnij go osobom, którym ten materiał może się przydać.
Powiązane artykuły
Automatyzacja frontendu: Plan Mode i hook PostToolUse
Sprawdź, jak skonfigurować Claude Code, aby planował zmiany, formatował kod, uruchamiał `astro check` i wskazywał brakujące testy.
Hooki Claude Code jako lekkie CI dla frontendu
Budujemy zestaw hooków PostToolUse i Stop, które po każdej zmianie formatują kod, uruchamiają testy i przygotowują raport jakości.
Analiza kodu w Claude Code: Plan Mode i hooki
Jak połączyć tryb tylko do odczytu, rozszerzone myślenie i hook PostToolUse, aby zaplanować refaktoryzację i zebrać metryki testów.