
Tool 차단을 Claude의 자기 수정으로 바꾸는 hooks 설정
요약
Claude Code의 'deny' 설정 시 발생하는 정보 부재 문제를 해결하기 위해 PreToolUse 훅을 활용하는 방법을 소개합니다. 명령 차단 시 이유를 Claude에게 전달하여 모델이 스스로 오류를 수정하도록 유도하는 최적화 가이드입니다.
핵심 포인트
- 승인 피로(approval fatigue)를 줄이기 위한 기계적 차단 필요성
- deny 설정의 한계인 '이유 미전달' 문제를 훅(hooks)으로 해결
- PreToolUse 훅과 exit 2를 사용하여 Claude의 자기 수정 유도
- rules.jsonl을 통한 정규 표현식 기반의 규칙 관리
명령 실행을 자동으로 차단하면서도, 권장하는 방법으로 유도하는 hooks 설정 방법. Claude Code용.

동작 사례
Claude Code의 deny 설정으로 Bash 도구의 실행을 차단하더라도, Claude는 "왜 차단되었는지"를 이해하지 못합니다. PreToolUse 훅 + exit 2를 사용하여, 이유를 전달하고 그 자리에서 자기 수정(self-correction)을 하게 만들 수 있습니다.
승인 프롬프트가 너무 번거로운 문제
Claude Code에서는 도구 실행 시마다 승인 프롬프트(approval prompt)가 표시됩니다. 하지만 이는 매우 번거롭습니다. 매번 판단을 요구받는 인지 부하(cognitive load)는 크며, 일단 허용하고 보는 경향이 있습니다.
Anthropic의 조사에 따르면, 사용자들은 승인 프롬프트의 93%를 승인했다고 보고되었습니다. 모두가 그렇게 하고 있습니다. 이 상태를 **approval fatigue (승인 피로)**라고 부르며, 설계상의 문제로 다뤄지고 있습니다.
대책은 "매번 판단할 필요가 없는 구조"를 만드는 것입니다. 명백히 문제가 있는 명령은 기계적으로 판정하여 차단합니다. 판단 비용을 정말로 판단이 필요한 상황에만 집중시키는 것입니다.
여기서 settings.json의 deny 설정이 도움이 됩니다. 위험한 명령 실행을 차단할 수 있습니다.
"permissions": {
"deny": ["Bash(cd *)"]
}
"아니, 왜 cd가 안 되는 거야???"
deny 설정으로는 Claude에게 이유가 전달되지 않습니다. Claude 측에서는 그저 "권한 에러"로만 보입니다. 왜 차단되었는지 알 수 없기 때문에, 같은 실수를 반복합니다.
그래서 PreToolUse 훅을 사용하여, Claude에게 이유를 전달하는 메커니즘을 정비했습니다. 명령을 자기 수정하게 하여, 확인이나 설명에 드는 수고를 덜어줍니다.

절대 경로를 차단하여 상대 경로로 유도하는 예시
설정 방법
환경
- Windows 11
- WinGet 버전 Claude Code 2.1.142
- Git Bash
- jq
Windows에 직접 설치한 Claude Code에서의 설정입니다.
Powershell 환경이나 Mac, Linux에서는 명령어가 다를 수 있습니다.
또한 jq를 사용하고 있습니다.
디렉토리 구성
~/.claude/
└─ hooks/
├─ bash/
...
validate.sh
로직 본체입니다.
rules.jsonl의 내용을 바탕으로 Bash 도구의 실행을 차단합니다.
exit 2를 사용하면 실행을 차단하면서, stderr에 작성한 메시지가 Claude에게 직접 전달됩니다.
#!/usr/bin/env bash
# PreToolUse hook: validate Bash commands against JSONL rules.
#
...
rules.jsonl
1행 = 1규칙인 JSONL 형식으로 작성합니다.
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
pattern | string | yes | ERE 정규 표현식. grep -E를 통해 명령 전체에 대해 매칭 |
reason | string | yes | Claude에게 전달할 차단 이유. "왜 금지인지" + "어떻게 고칠지"를 포함 |
enabled | boolean | no | 생략 시 true. false로 설정 시 일시적으로 비활성화 |
필자 환경에서의 설정 예시입니다.
{"pattern": "(^|&&\\s*|;\\s*|\\|\\|\\s*)rm\\s", "reason": "`rm`은 되돌릴 수 없는 삭제를 수행하므로 사용이 금지됩니다. 삭제 방법은 rules/use-bash-tool.md를 참조하세요.", "enabled": true}
{"pattern": "(^|&&\\s*|;\\s*)cd\\s", "reason": "프로젝트 루트에서 실행 중이므로 cd가 불필요하지 않습니까? 명령어를 직접 실행하거나 절대 경로를 지정하세요. 예: 'cd /path && cmd' → 'cmd'", "enabled": true}
{"pattern": ">>?\\s*nul\\b", "reason": "> nul 및 >> nul은 nul 파일이 생성됩니다. Git Bash에서는 '> /dev/null'을 사용하세요", "enabled": true}
...
내용은 취향에 따라 조정해 주세요.
그렇다고 해도 **정규 표현식 (Regular Expression)**을 직접 작성하는 것은 고통스럽습니다.
그래서 Claude에게 모든 것을 맡길 수 있도록 스킬 (Skill)을 준비했습니다.
SKILL.md
disable-model-invocation: true 설정 덕분에 컨텍스트 로드 비용이 0입니다.
사용할 때만 /add-bash-rule로 호출하세요.
/add-bash-rule rm -rf 사용을 차단하고 싶어
---
name: add-bash-rule
description: Add a new validation rule to the Bash PreToolUse hook. Describe what to block in natural language; Claude handles the ERE regex and reason.
...
```bash
echo '테스트용 명령어' | grep -qE 'PATTERN' && echo MATCH || echo NO_MATCH
단계 3: reason 작성하기
Claude에게 전달될 메시지로, 다음 내용을 1~2문장으로 요약합니다:
- 왜 문제가 되는지
...
{"pattern": "...", "reason": "...", "enabled": true}
단계 5: 확인
추가된 규칙의 내용과 테스트 결과를 표시하고 완료를 알립니다.
### settings.json
`PreToolUse`의 hooks를 설정합니다.
차단할 명령어를 `deny`에 넣어두었다면 삭제해 주세요.
hooks 검증 스크립트 실행 전에 차단되어 버립니다.
```json
{
"hooks": {
"PreToolUse": [
...
Discussion

AI 자동 생성 콘텐츠
본 콘텐츠는 Zenn AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기