스킬은 내 일상 워크플로우에서 없어서는 안 될 방법이 되었다. 세 번 이상 반복되는 일이 있으면, 나는 그것을 스킬로 전환하는 것을 고려한다. 단지 시간을 절약하기 위해서가 아니라, 매번 방향과 단계가 엇나가지 않도록 보장하기 위해서다. 적어도 이론적으로는 그렇다.
하지만 AI는 여전히 엇나간다
그 말은 다소 과장되었다. 현실은 AI가 여전히 단계를 건너뛴다는 것이다. 내가 매일 사용하는 위챗 공개계정 글쓰기 스킬을 예로 들어보자. 나는 초안을 보여주고 수정을 거친 후에야 오타 교정을 진행하도록 설정했다. 간단해 보이지? 하지만 실제로 실행될 때, 계속 단계를 건너뛴다: 초안을 완성하고도 나에게 보여주지 않고 바로 교정과 편집으로 넘어간다. 내가 알아챌 때쯤이면 이미 조용히 파일을 수정해버린다. 내가 지적하면 사과하며 “죄송합니다, 제 실수입니다"라고 말하지만, 다음 번에도 똑같은 일을 반복한다. 사과만으로는 문제가 해결되지 않는다.
AI가 항상 단계를 건너뛰는 이유
이 문제는 직관에 반한다. 처음에는 AI가 충분히 똑똑하지 않다고 생각했지만, 나는 이미 ChatGPT 5.4와 Opus 4.6 같은 최상위 대형 모델을 사용하고 있었다. 나중에는 규칙이 충분히 명확하지 않다고 생각해서 스킬의 규칙을 몇 번이고 수정했다. 조금 나아지긴 했지만, 근본 원인은 해결되지 않았다. 조사 끝에 AI가 단계를 건너뛰는 것은 “규칙을 보지 못해서"가 아니라 생성 메커니즘에 의해 결정된다는 것을 알게 되었다:
- 확률 기반의 “가속 충동”. 대규모 언어 모델은 본질적으로 다음 토큰을 예측한다. 작업을 완료하는 가중치는 자연스럽게 “7단계에 머물며 사용자를 기다리는 것"보다 높다. 완료에 대한 감각이 모델의 내재적 동기다.
- 긴 맥락에서 규칙의 약화. 처음에 설정한 규칙은 모델이 3000번째 토큰에 도달할 때쯤이면 주의 가중치가 희석된다. 특히 긴 스킬 문서에 규칙을 묻어두면 더 쉽게 주변부로 밀려난다.
- 자동 모드에서 특히 심각. 자동 모드로 글을 쓸 때 모델은 “모든 단계를 한 번에 실행"하는 경향이 있다. 내가 개입할 수 있는 창은 더욱 좁아진다.
- CLAUDE.md와 스킬 문서는 본질적으로 “소프트 제약” 이다. 이들은 모델의 “자기 규율"에 의존하여 따르도록 하는 프롬프트다. 그리고 자기 규율은 “이 작업을 빨리 끝내고 싶다"는 압박 앞에서 취약하다.
결론은: 언어적 제약은 작업 중심 압박 아래에서 실패한다. 단순히 문서를 작성하고, 느낌표를 추가하거나, AI를 심리적으로 압박하는 것은 문제를 완화할 뿐 근본적으로 해결하지 못한다. 진정으로 해결하려면 모델의 자기 규율 영역 밖으로 꺼내야 한다—물리적으로 단계를 건너뛸 수 없게 만드는 것. 바로 여기에 훅(Hook)이 등장한다.
훅이란 무엇인가
Claude Code에는 Hook이라는 메커니즘이 있다. 이는 스킬도, 프롬프트도, CLAUDE.md와도 다르다—Claude Code 생명주기의 주요 지점에 연결된 로컬 셸 스크립트다. 핵심 차이점:
- CLAUDE.md / 스킬은 모델이 관찰하고 실행한다—모델이 무시할 수 있다.
- Hook은 시스템이 강제한다—모델이 무시하고 싶어도 무시할 수 없다.
Anthropic 공식 문서에서 Hook에 관한 핵심 문장: Hook은 시스템 이벤트에 의해 트리거되며, 모델 결정에 의해 트리거되지 않는다. 즉, Hook은 전체 Claude Code 런타임에 연결된다. 모델이 호출하는 모든 도구 호출(Write, Edit, Bash)은 먼저 Hook의 검토를 통과해야 한다. Hook이 deny를 반환하면, --dangerously-skip-permissions가 활성화되어 있어도 거부된다. 이것이 내가 “하드 제약"이라고 부르는 것이다—AI가 스스로 선택하지 못하게 하고, 대신 도구 호출이 실제 셸 스크립트 감사를 통과하도록 강제한다.
일반적인 Hook 트리거 지점:
PreToolUse: AI가 도구를 호출하기 전에 가로챈다.UserPromptSubmit: AI에게 전달하기 전에 사용자의 메시지를 처리한다.SessionStart: 세션이 시작되거나 재개될 때 트리거된다.Stop: Claude가 응답을 마쳤을 때 트리거된다.
처음 두 가지에 집중하면 된다—이것만으로도 “단계 잠금"을 구축하기에 충분하다.
실제 적용: 내 위챗 계정 스킬을 위한 단계 게이트(Step Gate)
모든 이야기는 구체적인 예시 없이는 소용없다. 이 스크린샷은 이 글을 쓰는 동안의 Claude Code 인터페이스다. 빨간 상자 안에서 AI가 나에게 “pass step3 0090"이라고 답변해 달라고 요청한다—이 패스프레이즈가 바로 Step Gate Hook이 작동하고 있다는 증거다. 지금 당신이 읽고 있는 이 글은 내가 패스프레이즈를 보내고 Hook이 허용한 후에 작성된 것이다.

전체 Step Gate는 단 두 개의 셸 스크립트와 settings.json의 작은 설정만을 사용한다. 하나씩 설명하겠다.
settings.json에 두 개의 Hook 등록하기
~/.claude/settings.json에 다음을 추가한다:
"PreToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{ "type": "command",
"command": "~/.claude/skills/writing-gongzhonghao/scripts/gate_check.sh" }
]
}
],
"UserPromptSubmit": [
{
"hooks": [
{ "type": "command",
"command": "~/.claude/skills/writing-gongzhonghao/scripts/gate_mark.sh" }
]
}
]
이 설정의 의미:
- AI가 Write 또는 Edit 도구를 호출하려고 할 때마다
gate_check.sh가 먼저 실행되어 검토한다. - 내가 메시지를 보낼 때마다
gate_mark.sh가 먼저 실행되어 메시지를 파싱한다.
gate_check.sh: 가로채기 처리
이 스크립트의 로직은 매우 간단하다:
- AI가 새 파일
04-Output/NNNN xxx.md를 Write하려고 하면(3단계: 새 글 작성에 해당), 상태 파일step3.ok가 존재하는지 확인한다. 없으면deny를 반환한다. - AI가 기존 글을 Edit하려고 하면(7단계 이후 교정에 해당),
step7.ok가 존재하는지 확인한다. 없으면 역시deny를 반환한다.
거부할 때는 다음과 같은 프롬프트도 포함한다: “3단계 주제 논의가 확인되지 않았습니다: 먼저 개요/방향 승인을 제공해 주세요. 확인 후 ‘pass step3 NNNN’이라고 답변하면 새 파일을 생성할 수 있습니다.” 이 프롬프트는 AI에게 직접 표시되므로, AI는 막혔다는 것을 인지하고 나에게 패스프레이즈를 요청한다.
gate_mark.sh: 패스프레이즈 해제 처리
어떻게 “해제"할까? AI가 스스로 해제하게 할 수는 없다—그러면 제약이 전혀 없게 된다. 규칙은 다음과 같다: 내 메시지에 특정 패스프레이즈가 포함된 경우에만 상태 파일이 생성된다. gate_mark.sh는 내가 메시지를 보낼 때마다 실행되며, pass stepN NNNN 패턴을 스캔한다. 일치하면 해당 디렉토리에 .ok 파일을 생성한다.
따라서 전체 체인은 다음과 같아진다:
- AI가 개요를 완성하고 새 글을 작성하려고 함 →
gate_check.sh에 의해 차단됨 - AI가 나에게 패스프레이즈를 요청: “방향을 확인해 주세요. ‘pass step3 0090’이라고 답변하세요.”
- 내가 “pass step3 0090"을 보냄 →
gate_mark.sh가 step3.ok를 생성함 - AI가 다시 파일을 생성하려고 시도함 → 이번에는
gate_check.sh가 허용함 - 초안을 완성한 후 교정을 위해 Edit을 진행하려고 함 → step7.ok에 의해 다시 차단됨
- 내가 초안을 읽고 “pass step7 0090"을 보냄 → 교정이 시작될 수 있음
전체 과정에서 AI는 “자기 규율"을 발휘할 여지가 없다. 단계를 건너뛰고 싶어도 시스템 수준에서 도구 호출이 차단되기 때문에 불가능하다.
허점 막기: AI가 스스로 상태 파일을 건드릴 수 없음
첫 번째 버전을 설계한 후, 나는 계획을 한참 들여다보다가 허점을 발견했다—AI가 Bash를 사용해 스스로 touch step3.ok를 실행하면 어떨까? 그러면 제약을 우회할 수 있지 않을까? 그래서 나는 스킬 문서에 특정 규칙을 추가했다: AI는 스스로 상태 파일을 건드리면 안 된다. 그렇지 않으면 자신의 제약을 제거하는 것이 된다. 이 규칙 자체는 여전히 소프트 제약이지만, Hook의 하드 차단과 결합하면 충분히 폐쇄된 루프를 형성한다—AI가 이 규칙을 적극적으로 위반하지 않는 한(그리고 Claude는 실제로 협조적이다), Hook 제약은 실질적으로 유효하다. 더 엄격하게 하려면 PreToolUse에 Bash 매처를 추가하여 touch와 같은 명령도 차단할 수 있다. 하지만 나는 아직そこ까지 가지 않았다. 지금도 충분히 잘 작동한다.
코드를 몰라도 당황하지 마라
이러한 셸 스크립트나 JSON 설정을 직접 작성할 필요는 없다(사실 나도 직접 작성하지 못한다). 접근 방식은 간단하다: 이 글과 당신의 스킬 파일을 Claude나 Codex에 던져주고, 읽게 한 후 수정하도록 도움을 요청하라—필요한 곳에 스크립트를 만들고, settings.json을 수정하라. AI는 “문서에 따라 환경을 구성하는” 이런 작업에 특히 신뢰할 만하며, 처음부터 코드를 작성하는 것보다 훨씬 안정적이다. AI는 글에서 원리를 배우면서 동시에 당신의 스킬 요구사항에 따라 Hook을 작성하며, 결과가 엇나가는 경우는 거의 없다.
한 문장으로 요약
CLAUDE.md, 스킬 문서, 굵은 표시, 세 번 반복, 심리적 압박—이 모든 것은 AI에 대한 언어적 제약이다. 효과는 있지만 한계가 낮다.
Hook은 AI에 대한 코드 제약이다. 규칙을 AI가 닿을 수 없는 곳으로 옮겨, “규칙 따르기"를 모델의 자기 규율 문제에서 실행 환경의 필수 요구사항으로 바꾼다.
만약 AI에게 “왜 또 단계를 건너뛰는 거야?“라고 반복해서 말하고 있다면, 이제 Hook을 사용해 제약할 때가 되었다.