Claude Code의 PermissionRequest hook은 Claude Code가 권한 prompt를 표시하려는 순간 실행되며, 그 prompt에 대신 응답할 수 있어요. 허용하려면 hook이 0으로 종료하면서 {"hookSpecificOutput": {"hookEventName": "PermissionRequest", "decision": {"behavior": "allow"}}}를 출력하고, 거부하려면 Claude에게 전달할 message와 함께 "behavior": "deny"를 사용해요. 도구 이름으로 매칭하고, deny 규칙을 덮어쓸 수 없으며, 이 이벤트에서는 종료 코드 2가 아무 효과가 없어요. hook이 결정을 출력하지 않으면 일반 prompt가 표시돼요.
01PermissionRequest와 PreToolUse, Notification 비교
권한과 관련된 hook 이벤트는 세 가지이고, 각각 하는 일이 달라요.
PreToolUse권한 필요 여부와 관계없이 모든 도구 호출 전예: allow, deny, ask, deferPermissionRequestClaude Code가 사용자에게 물어보려 할 때만예: allow 또는 denyNotification (permission_prompt)자리를 비운 동안 prompt가 약 6초 대기한 후아니요prompt 자체에 관심이 있을 때, 즉 응답하거나 기록하거나 어딘가로 보내고 싶을 때는 PermissionRequest를 사용하세요. 6초 지연 없이 바로 발생해요. "rm -rf는 절대 실행하지 않기"처럼 모든 호출에 적용해야 하는 규칙에는 PreToolUse를 사용하세요. prompt가 뜨지 않는 경우에도 실행되기 때문이에요. 해당 이벤트의 타이밍은 Notification hook 가이드에서 설명해요.
02hook이 받는 데이터
PermissionRequest hook은 공통 필드와 함께 Claude가 하려는 호출의 tool_name과 tool_input, 그리고 선택적인 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에는 Claude Code가 이 요청에 대해 제안할 규칙 변경이 담겨요. 대화상자마다 자체 옵션을 구성하기 때문에, 대화상자의 옵션과 정확히 일치하지는 않아요.
03decision 객체
hookSpecificOutput 안에 decision을 반환하세요.
behavior"allow" 또는 "deny"updatedInputallow 전용. 도구의 입력 전체를 대체하므로 변경하지 않은 필드도 포함하세요updatedPermissionsallow 전용. 규칙 추가나 모드 변경처럼 적용할 권한 변경messagedeny 전용. Claude에게 이유를 알려 줘요interruptdeny 전용. true이면 Claude도 중지해요기억해 둘 규칙이 두 가지 있어요.
- deny 규칙과 ask 규칙은 여전히 적용돼요. hook이
"allow"를 반환해도 설정에 일치하는 deny 규칙이 있으면 무시되지 않고, 수정된 입력도 이 규칙들로 다시 검사돼요. - 여기서는 exit code
2가 무시돼요. 대부분의 이벤트에서는 exit2가 차단으로 동작하지만,PermissionRequesthook이decision객체 없이2로 종료하면 prompt는 그대로 남아요. 거부하려면 decision을 반환하세요.
04예시: 특정 prompt 하나 자동 승인하기
Anthropic의 공식 예시는 Claude가 계획을 마쳤을 때 나타나는 prompt인 ExitPlanMode를 승인해서 매번 묻지 않도록 해요.
{
"hooks": {
"PermissionRequest": [
{
"matcher": "ExitPlanMode",
"hooks": [
{
"type": "command",
"command": "echo '{\"hookSpecificOutput\": {\"hookEventName\": \"PermissionRequest\", \"decision\": {\"behavior\": \"allow\"}}}'"
}
]
}
]
}
}
matcher는 좁게 잡으세요. 빈 matcher나 .*에 무조건 allow를 붙이면 파일 쓰기와 셸 명령을 포함한 모든 prompt가 승인돼요.
05예시: 명령을 보고 판단하기
이 스크립트(jq 필요)는 git push가 포함된 요청을 Claude가 읽을 수 있는 이유와 함께 거부하고, 나머지 prompt는 아무것도 출력하지 않아서 직접 판단하도록 남겨 둬요.
#!/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" }]
}
]
}
}
JSON은 문자열을 이어 붙이지 말고 jq로 만드세요. 그래야 메시지 안의 따옴표 때문에 깨지지 않아요. 그리고 stdout에 다른 내용이 출력되지 않게 하세요. 셸 프로필이 한 줄이라도 echo하면 Claude Code가 decision을 읽지 못해요.
06예시: 허용하고 세션 동안 기억하기
요청을 승인하고 세션이 끝날 때까지 Claude가 다시 묻지 않게 하려면 destination: "session"을 가진 updatedPermissions 항목을 추가하세요. hook은 전달받은 permission_suggestions 중 하나를 destination만 바꿔서 그대로 돌려줄 수 있어요.
#!/bin/bash
input=$(cat)
jq -c '{hookSpecificOutput: {hookEventName: "PermissionRequest",
decision: {behavior: "allow",
updatedPermissions: [(.permission_suggestions // [])[]
| select(.type == "addRules")
| .destination = "session"]}}}' <<<"$input"
이대로 쓰면 들어오는 모든 요청을 허용하니 좁은 matcher와 함께 사용하세요. destination은 localSettings, projectSettings, userSettings로도 지정할 수 있는데, 이 경우 규칙을 메모리에 두지 않고 설정 파일에 기록해요.
07permission 규칙이 더 나은 경우가 많아요
답이 항상 같다면 hook이 필요 없어요. 규칙을 settings.json에 넣으면 Claude Code가 아무것도 실행하지 않고 바로 적용해요.
{
"permissions": {
"allow": ["Bash(npm run *)"],
"deny": ["Bash(git push *)"]
}
}
규칙은 deny, ask, allow 순서로 평가돼요. hook은 시간대, 현재 브랜치, 다른 곳에서 응답하는 사람처럼 규칙이 알 수 없는 정보에 따라 판단해야 할 때 쓸모가 있어요. 다른 기본 옵션은 permission 모드 설명에서 확인하세요.
08자주 헷갈리는 부분
- 비대화형 실행.
claude -p로 실행하면 prompt에 답할 사람이 없어요.PermissionRequesthook은 그대로 실행되고, 어떤 hook도 decision을 반환하지 않으면 호출이 거부돼요. - 타임아웃. command hook은 기본적으로 최대 600초까지 실행될 수 있고, 그동안 Claude는 기다려요. 사람의 응답처럼 오래 걸리는 것을 기다린다면
timeout(초 단위)을 설정하세요. - 트리거되지 않는 prompt도 있어요. sandbox 안에서 실행된 명령의 네트워크 요청은
PermissionRequest를 실행하지 않아요. 이 경우에는permission_prompt알림 유형을 사용하세요. - 보안.
"allow"를 반환하는 hook은 여러분의 사용자 권한으로, 여러분 대신 작업을 승인하는 셈이에요. 명령을 실행할 수 있는 다른 코드와 똑같이 검토하세요.
09Claude Code Notifier의 역할
PermissionRequest hook을 작성하는 가장 흔한 이유는 자리를 비웠을 때 prompt에 답하기 위해서예요. 직접 만들려면 hook이 요청을 어딘가로 보내고, 응답을 기다렸다가, 타임아웃 전에 반환해야 해요. 충분히 가능한 일이고, 채팅 봇으로 만드는 사람도 있어요.
Claude Code Notifier가 이 작업을 대신해 줘요. 무료 커맨드라인 도구인 ccn은 Mac, Windows, Linux에서 동작하며 ~/.claude/settings.json에 hook을 설치해요. iPhone 또는 Android 앱을 페어링하면 permission 요청이 휴대폰으로 오고, 한 번 허용, 세션 동안 허용, 거부 중에서 고를 수 있어요. ccn은 그 결정을 PermissionRequest hook에서 반환해요. 최근 30초 안에 입력한 적이 있으면 기다리지 않고 terminal이 평소처럼 물어봐요. 자리를 비운 상태라면 terminal은 직접 정한 상한(hold_ceiling_seconds, 기본값 600)까지 휴대폰 응답을 기다리고, 키보드를 건드리는 순간 기다림을 멈춰요. 이 도구는 독립적으로 만들어졌으며 Anthropic이 만든 것이 아니에요. 사용 흐름은 휴대폰에서 permission 승인하기를, 보안 측면은 원격 승인은 안전한가요?를 참고하세요.
10FAQ
hook으로 permission을 자동 승인하려면 어떻게 하나요?
좁은 matcher를 가진 PermissionRequest hook을 추가하고, hookSpecificOutput 안에 "behavior": "allow"가 담긴 JSON decision을 출력한 뒤 0으로 종료하게 하세요. 같은 명령을 항상 허용해야 한다면 settings.json의 permissions.allow 규칙이 더 간단하고 hook도 필요 없어요.
exit code 2로 요청이 거부되지 않는 이유는 뭔가요?
PermissionRequest는 exit 2가 적용되지 않는 이벤트 중 하나예요. Claude Code는 이를 무시하고 평소 prompt를 보여 줘요. 대신 decision 객체에 "behavior": "deny"를 반환하세요.
PermissionRequest hook이 deny 규칙을 무시할 수 있나요?
아니요. deny 규칙과 ask 규칙은 계속 평가되므로 hook이 "allow"를 반환해도 일치하는 deny 규칙을 통과하지 못해요. 반환한 updatedInput도 이 규칙들로 검사돼요.
PermissionRequest와 PreToolUse는 어떻게 다른가요?
PreToolUse는 모든 tool 호출 전에 실행되며 allow, deny, ask, defer를 할 수 있어요. PermissionRequest는 Claude Code가 prompt를 띄우기 직전에만 실행되고, 이를 allow하거나 deny할 수 있어요. 정책에는 PreToolUse를, prompt 응답에는 PermissionRequest를 사용하세요.
hook이 아무것도 출력하지 않으면 어떻게 되나요?
아무것도 바뀌지 않아요. Claude Code는 hook이 없는 것처럼 terminal에 평소 permission prompt를 보여 줘요.