
AI에게 "규칙을 지켜줘"라고 말하는 대신, hook으로 물리적으로 막는 메커니즘을 만든 이야기
요약
AI의 프롬프트 지시 사항 위반 문제를 해결하기 위해 Claude Code의 hook 메커니즘을 활용하여 물리적인 제어 장치를 만드는 방법을 소개합니다. PreToolUse hook을 통해 규칙 위반 시 동작을 강제로 차단하고, additionalContext를 통해 AI에게 피드백을 전달하는 실전 팁을 다룹니다.
핵심 포인트
- 프롬프트 대신 hook을 사용하여 규칙을 OS 수준의 강제력으로 변환
- PreToolUse hook으로 파일 편집 전 규칙 준수 여부 판정 가능
- AI에게 거부 이유를 전달하려면 additionalContext를 반드시 사용
- hook 스크립트의 타임아웃 설정과 Fail-open 설계의 중요성
몇 번을 말해도, AI는 같은 지점에서 같은 실수를 한다
Claude Code에게 "메모는 짧게 써줘"라고 몇 번을 말해도, 정신을 차려보면 다시 장문이 되어 있다——그런 경험은 없는가.
나는 Obsidian에서 개인적인 메모를 키워나가고 있으며, Claude Code에게 그 파일에 "오늘 깨달은 점"을 추가하도록 하는 운용을 하고 있다. 처음에는 "1개 토픽당 200자 정도"라고 규칙을 정해두면 충분하다고 생각했다.
그런데, 한동안 운용해 보니 아무렇지도 않게 수천 자의 토픽이 섞이기 시작했다. AI에게 악의는 없다. 그저 "지켜줬으면 하는 규칙"을 매번 성실하게 떠올려 줄 정도로 AI가 꼼꼼하지 않을 뿐이다.
그래서 깨달았다. 입으로 말하는 것을 그만두고, 어겼을 때 물리적으로 동작이 멈추는 메커니즘을 직접 만들면 된다. Claude Code의 hook을 사용하면 그것이 가능하다.
hook이란 무엇인가
hook이란 Claude Code가 특정 동작(파일 편집, 커맨드 실행 등)을 하기 직전 혹은 직후에, 자신이 준비한 스크립트를 끼워 넣을 수 있는 메커니즘이다.
예를 들어 "파일을 편집하기 직전"에 발화하는 PreToolUse라는 종류의 hook을 사용하면, 스크립트 측에서 "이 편집을 허용해도 되는가"를 판정할 수 있다. 판정이 "안 됨"이라면, Claude Code는 그대로는 편집을 실행할 수 없다.
즉, AI의 기억력이나 성실함에 의존하지 않고, 규칙을 OS적인 강제력으로 변환할 수 있다.
최소한의 동작 예시
"1회의 추가 내용이 200자를 초과하면 거부한다"는 hook을 만들어 본다.
먼저, .claude/settings.json에 설정을 추가한다.
{
"hooks": {
"PreToolUse": [
...
다음으로, 판정하는 스크립트 본체(check_length.sh). Claude Code는 표준 입력으로 JSON 형식의 정보(어떤 파일에 무엇을 쓰려고 하는가 등)를 전달해 오므로, 거기서 추가될 부분의 글자 수를 세기만 하면 된다.
#!/bin/bash
payload=$(cat)
new_text=$(echo "$payload" | jq -r '.tool_input.new_string // .tool_input.content // ""')
...
이것만으로도 "200자를 초과하는 추가 내용"은 물리적으로 차단된다. AI는 거부된 이유를 읽고, 다시 써서 다시 제출한다.
6가지 함정 (전부 실제로 겪어본 것)
1. additionalContext만 사용하기
AI에게 전달되는 장소는 systemMessage나 permissionDecisionReason에 이유를 써도, 그것은 인간의 화면에 표시될 뿐이며 AI 자신에게는 전달되지 않는다. AI에게 "왜 안 됐는지"를 전달하여 다시 쓰게 하고 싶다면, additionalContext에 넣어야 한다. 처음에는 이 부분을 반대로 생각해서, AI가 이유도 모른 채 같은 실수를 반복하는 상태를 한 번 만들고 말았다.
2. timeout의 단위는 초. 기본값은 600초
command 타입의 hook은 지정이 없으면 기본적으로 600초(10분)까지 응답을 기다린다. 판정 스크립트가 프리즈(freeze)되면, 그대로 파일 편집 자체가 10분 동안 멈춘다. 명시적으로 짧은 타임아웃을 지정해 두는 것이 안전하다. 나는 10초로 설정했다.
3. 망설여지면 통과시킨다 (Fail-open)
판정 스크립트 자체에 버그가 있어 "알 수 없는" 상태가 되었을 때, 거기서 거부 쪽으로 기울면 작업 전체가 멈춘다. 규칙을 지키게 하려는 메커니즘이 버그 하나 때문에 아무것도 할 수 없게 된다면 본말전도다. 판정할 수 없을 때는 통과시킨다는 설계로 해둔다.
4. 모든 편집에서 무거운 처리를 돌리면 쓸모가 없어진다
대상 외의 파일까지 성실하게 체크하고 있으면 체감될 정도로 느려진다. 이전에 비슷한 메커니즘을 성능 문제로 단념한 적이 있다. 이번에는 대상 외의 파일은 쉘 표준 기능만으로 즉시 걸러내도록 하여, 무거운 처리(jq를 호출하는 부분 등)는 대상 파일에 대해서만 실행되도록 했다. 대상 외는 1자리 밀리초(ms), 대상 내에서도 100밀리초(ms)대로 유지되고 있다.
5. hook은 서브 에이전트(sub-agent)의 작업에도 발화한다
Claude Code가 백그라운드에서 실행하는 다른 에이전트의 작업에도 동일한 hook이 똑같이 적용된다. 역설적으로 말하면, 우회로를 만들었다고 생각한 경로가 존재하지 않았다. 설정 변경도 재시작 없이 즉시 반영된다.
6. 「단 한 번의 편집만 보고 있다」는 한계
이 hook은 1회의 Edit/Write 단위로만 길이를 판정한다. 즉, "한 번에 10자씩, 20회에 나누어 추가한다"와 같은 방식을 사용하면 전체 길이를 제한할 수 없다. 이는 구조상의 한계이며, "여러 번에 걸친 합계"까지 확인하려 하면 판정이 갑자기 복잡해진다. 현재로서는 거기까지 추적하지 않는 설계로 되어 있다.
말로 하는 것을 그만두고, 메커니즘에 맡기기
이것을 만들기 전에는 "AI가 규칙을 지켜주기를" 매번 기도했다. 만든 후에는 지킬지 말지를 기도하는 대상이 AI에서 내가 작성한 스크립트로 바뀌었다. 스크립트 쪽이 훨씬 더 신뢰할 수 있다.
Claude Code를 사용하면서 "몇 번을 말해도 고쳐지지 않는다"라고 느껴진다면, 그것은 말로 하는 단계를 끝내고 hook으로 물리적으로 막는 메커니즘으로 전환해야 할 타이밍일지도 모른다.
Discussion

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