Hook PermissionRequest w Claude Code uruchamia się w chwili, gdy Claude Code ma ci pokazać prompt o uprawnienia, i może na niego odpowiedzieć za ciebie. Żeby zezwolić, hook kończy się kodem 0 i wypisuje {"hookSpecificOutput": {"hookEventName": "PermissionRequest", "decision": {"behavior": "allow"}}}; żeby odmówić, używa "behavior": "deny" z message dla Claude. Dopasowuje się po nazwie narzędzia, nie może nadpisać twoich reguł deny, a exit code 2 nic przy tym zdarzeniu nie robi. Jeśli hook nie wypisze decyzji, pojawi się zwykły prompt.
01PermissionRequest a PreToolUse i Notification
Z uprawnieniami związane są trzy zdarzenia hooków i każde robi coś innego:
PreToolUsePrzed każdym wywołaniem narzędzia, niezależnie od tego, czy wymaga uprawnieńTak: allow, deny, ask lub deferPermissionRequestTylko gdy Claude Code ma cię o coś zapytaćTak: allow lub denyNotification (permission_prompt)Gdy prompt czeka około sześciu sekund, a ciebie nie maNieUżywaj PermissionRequest, gdy zależy ci na samych promptach: odpowiadaniu na nie, logowaniu ich albo wysyłaniu gdzieś dalej. Odpala się od razu, bez sześciosekundowego opóźnienia. PreToolUse używaj do reguł, które mają dotyczyć każdego wywołania, np. „nigdy nie uruchamiaj rm -rf”, bo działa nawet wtedy, gdy żaden prompt by się nie pojawił. Timing tego zdarzenia wyjaśnia poradnik o Notification hook.
02Co dostaje hook
Oprócz wspólnych pól hook PermissionRequest dostaje tool_name i tool_input wywołania, które chce wykonać Claude, oraz opcjonalną tablicę permission_suggestions:
{
"session_id": "abc123",
"cwd": "/Users/...",
"permission_mode": "default",
"hook_event_name": "PermissionRequest",
"tool_name": "Bash",
"tool_input": {
"command": "rm -rf node_modules",
"description": "Remove node_modules directory"
},
"permission_suggestions": [
{
"type": "addRules",
"rules": [{ "toolName": "Bash", "ruleContent": "rm -rf node_modules" }],
"behavior": "allow",
"destination": "localSettings"
}
]
}
permission_suggestions zawiera zmiany reguł, które Claude Code zasugerowałby dla tej prośby. Nie jest to dokładna kopia opcji z okna dialogowego, bo każde okno buduje własne opcje.
03Obiekt decision
Zwróć decision wewnątrz hookSpecificOutput:
behavior"allow" lub "deny"updatedInputTylko przy allow. Zastępuje całe wejście narzędzia, więc dołącz też niezmienione polaupdatedPermissionsTylko przy allow. Zmiany uprawnień do zastosowania, np. dodanie reguły lub zmiana trybumessageTylko przy deny. Mówi Claude, dlaczegointerruptTylko przy deny. true dodatkowo zatrzymuje ClaudeDwie zasady, o których warto pamiętać:
- Reguły deny i ask nadal obowiązują. Hook zwracający
"allow"nie nadpisuje pasującej reguły deny w ustawieniach, a zmodyfikowane wejście jest ponownie sprawdzane względem tych reguł. - Kod wyjścia
2jest tu ignorowany. W większości zdarzeń wyjście z kodem2blokuje akcję, ale hookPermissionRequest, który kończy się kodem2bez obiektudecision, zostawia prompt bez zmian. Żeby odmówić, zwróć decyzję.
04Przykład: automatyczne zatwierdzanie jednego promptu
Przykład od Anthropic zatwierdza ExitPlanMode, czyli prompt, który pojawia się, gdy Claude skończy plan, więc nie musisz odpowiadać za każdym razem:
{
"hooks": {
"PermissionRequest": [
{
"matcher": "ExitPlanMode",
"hooks": [
{
"type": "command",
"command": "echo '{\"hookSpecificOutput\": {\"hookEventName\": \"PermissionRequest\", \"decision\": {\"behavior\": \"allow\"}}}'"
}
]
}
]
}
}
Trzymaj matchery wąskie. Pusty matcher albo .* z ogólnym allow zatwierdzałby każdy prompt, łącznie z zapisem plików i poleceniami powłoki.
05Przykład: decyzja na podstawie polecenia
Ten skrypt (wymaga jq) odrzuca wszystko, co dotyka git push, podając powód, który Claude może przeczytać, a wszystkie inne prompty zostawia tobie, nic nie wypisując:
#!/bin/bash
# ~/.claude/hooks/permission-check.sh
input=$(cat)
cmd=$(jq -r '.tool_input.command // empty' <<<"$input")
case "$cmd" in
*"git push"*)
jq -nc '{hookSpecificOutput: {hookEventName: "PermissionRequest",
decision: {behavior: "deny",
message: "Pushing is not allowed from this session. Commit and stop."}}}'
;;
esac
exit 0
{
"hooks": {
"PermissionRequest": [
{
"matcher": "Bash",
"hooks": [{ "type": "command", "command": "~/.claude/hooks/permission-check.sh" }]
}
]
}
}
Buduj JSON za pomocą jq, a nie przez sklejanie stringów, żeby cudzysłowy w komunikacie go nie zepsuły. Upewnij się też, że nic innego nie trafia na stdout. Jeśli twój profil powłoki wypisuje jakąś linię, Claude Code nie odczyta decyzji.
06Przykład: zezwól i zapamiętaj na czas sesji
Żeby zatwierdzić żądanie i sprawić, by Claude nie pytał ponownie do końca sesji, dodaj wpis updatedPermissions z destination: "session". Hook może odesłać jedną z otrzymanych permission_suggestions, zmieniając tylko destination:
#!/bin/bash
input=$(cat)
jq -c '{hookSpecificOutput: {hookEventName: "PermissionRequest",
decision: {behavior: "allow",
updatedPermissions: [(.permission_suggestions // [])[]
| select(.type == "addRules")
| .destination = "session"]}}}' <<<"$input"
W tej postaci skrypt zezwala na każde żądanie, które zobaczy, więc połącz go z wąskim matcherem. Destination może też mieć wartość localSettings, projectSettings lub userSettings – wtedy reguła trafia do pliku ustawień zamiast zostać w pamięci.
07Często lepszym narzędziem jest reguła uprawnień
Jeśli odpowiedź nigdy się nie zmienia, nie potrzebujesz hooka. Dodaj regułę do settings.json, a Claude Code zastosuje ją bez uruchamiania czegokolwiek:
{
"permissions": {
"allow": ["Bash(npm run *)"],
"deny": ["Bash(git push *)"]
}
}
Reguły są sprawdzane w kolejności: najpierw deny, potem ask, na końcu allow. Hook ma sens, gdy decyzja zależy od czegoś, czego reguła nie widzi, np. pory dnia, gałęzi, na której jesteś, albo osoby odpowiadającej z innego miejsca. Pozostałe wbudowane opcje opisuje Tryby uprawnień w praktyce.
08Na czym ludzie się potykają
- Uruchomienia nieinteraktywne. Przy
claude -pnie ma kogo zapytać. HookiPermissionRequestnadal się uruchamiają, a jeśli żaden nie zwróci decyzji, wywołanie zostaje odrzucone. - Timeouty. Hook typu command może domyślnie działać do 600 sekund, a Claude czeka. Ustaw
timeout(w sekundach), jeśli hook czeka na coś powolnego, np. na człowieka. - Niektóre prompty go nie wywołują. Żądanie sieciowe polecenia w sandboksie nie uruchamia
PermissionRequest. W tym przypadku użyj typu powiadomieniapermission_prompt. - Bezpieczeństwo. Hook zwracający
"allow"zatwierdza akcje w twoim imieniu, z uprawnieniami twojego użytkownika. Przejrzyj go jak każdy inny kod, który może uruchamiać polecenia.
09Gdzie pasuje Claude Code Notifier
Najczęstszy powód pisania hooka PermissionRequest to odpowiadanie na prompty, gdy nie siedzisz przy klawiaturze. Wersja DIY wymaga, żeby hook wysłał żądanie gdzieś dalej, poczekał na odpowiedź i zwrócił ją przed timeoutem. Da się to zrobić i niektórzy budują to z chatbotem.
Claude Code Notifier robi to za ciebie. Jego darmowe narzędzie CLI, ccn, działa na Macu, Windows i Linux i instaluje swoje hooki w ~/.claude/settings.json. Po sparowaniu aplikacji na iPhone lub Android żądanie uprawnień trafia na telefon, a ty możesz zezwolić raz, zezwolić na czas sesji albo odmówić; ccn zwraca tę decyzję z hooka PermissionRequest. Jeśli pisałeś coś w ciągu ostatnich 30 sekund, nic nie czeka i terminal pyta jak zwykle. Jeśli cię nie ma, terminal czeka na telefon do wybranego przez ciebie limitu (hold_ceiling_seconds, domyślnie 600) i przestaje czekać, gdy tylko dotkniesz klawiatury. To niezależne narzędzie, niestworzone przez Anthropic. Zobacz zatwierdzanie uprawnień z telefonu, żeby poznać workflow, oraz czy zdalne zatwierdzanie jest bezpieczne?, jeśli chodzi o bezpieczeństwo.
10FAQ
Jak automatycznie zatwierdzać uprawnienia hookiem?
Dodaj hook PermissionRequest z wąskim matcherem, niech wypisze decyzję JSON z "behavior": "allow" wewnątrz hookSpecificOutput i zakończy się kodem 0. Jeśli to samo polecenie ma być zawsze dozwolone, reguła permissions.allow w settings.json jest prostsza i nie wymaga hooka.
Dlaczego kod wyjścia 2 nie odrzuca żądania?
PermissionRequest to jedno ze zdarzeń, w których kod wyjścia 2 nie jest respektowany. Claude Code go ignoruje i pokazuje zwykły prompt. Zamiast tego zwróć "behavior": "deny" w obiekcie decyzji.
Czy hook PermissionRequest może nadpisać moje reguły deny?
Nie. Reguły deny i ask są nadal sprawdzane, więc "allow" z hooka nie przejdzie przez pasującą regułę deny. Każde zwrócone updatedInput też jest sprawdzane względem tych reguł.
Czym różni się PermissionRequest od PreToolUse?
PreToolUse uruchamia się przed każdym wywołaniem narzędzia i może zezwolić, odmówić, zapytać lub odroczyć decyzję. PermissionRequest uruchamia się tylko wtedy, gdy Claude Code ma pokazać prompt, i może go zatwierdzić lub odrzucić. Używaj PreToolUse do polityk, a PermissionRequest do odpowiadania na prompty.
Co się stanie, jeśli mój hook nic nie wypisze?
Nic się nie zmieni. Claude Code pokaże zwykły prompt uprawnień w terminalu, jakby hooka nie było.