Claude Code 훅·스킬·CLAUDE.md 차이와 고르는 기준
빈 데모 프로젝트에 “편집한 뒤 tools/stamp.sh를 실행한다”는 지시를 세 곳에 따로 넣어 봤습니다. CLAUDE.md에 한 줄, PostToolUse 훅으로 하나, 스킬로 하나. 그리고 파일 두 개를 고치는 같은 요청을 세 번씩 보냈어요.
스크립트가 돈 횟수는 CLAUDE.md가 매번 1회, 훅이 매번 2회, 부르지 않은 스킬은 0회였습니다. 같은 문장인데 자리에 따라 결과가 이렇게 갈리더라고요.
그래서 저는 셋 중에 고를 때 “판단 없이 매번 똑같이 돌아야 하나”부터 묻습니다. 그렇다면 훅(settings.json), 매 세션 알아야 하는 사실·관례면 CLAUDE.md, 특정 경로에서만 필요한 지침이면 paths를 붙인 .claude/rules/, 가끔 쓰는 절차나 참고 자료면 스킬(SKILL.md)입니다. “절대 안 된다”는 규칙은 글로 적지 말고 훅으로 막으세요.
실험은 2026년 9월 14일 Ubuntu 24.04 · Claude Code 2.1.270에서 직접 실행한 결과이고, 공식 문서도 같은 날 다시 확인했습니다. 10월 14일에는 Windows 11 · PowerShell 5.1 테스트 환경의 Claude Code 2.1.296에서 같은 실험을 다시 돌렸습니다.
각 기능의 문법은 훅으로 매번 실행되는 검사 거는 법, SKILL.md로 반복 작업 묶는 법, CLAUDE.md에 무엇을 적고 무엇을 빼는지에 따로 있고, 여기서는 셋 중 무엇을 고를지만 다룹니다.
확인한 버전·환경
- Claude Code 2.1.296 · Windows 11 · Windows PowerShell 5.1 · 확인일 2026-10-14
- Claude Code 2.1.270 · Ubuntu 24.04 · bash · 확인일 2026-09-14
같은 지시를 세 곳에 넣어 봤다
데모 프로젝트에는 stamp.log에 한 줄을 덧붙이는 스크립트 tools/stamp.sh만 두었습니다. 요청은 매번 같았어요. “notes.txt의 첫 줄을 hello 로 바꾸고, src/api/handler.ts의 값 1을 2로 바꿔 주세요.” 한 턴에 파일 두 개를 고치는 요청이고, stamp.log의 줄 수가 곧 실행 횟수입니다.
| 지시를 넣은 곳 | 1회차 | 2회차 | 3회차 |
|---|---|---|---|
CLAUDE.md의 작업 규칙 한 줄 |
1 | 1 | 1 |
PostToolUse 훅(Edit|Write 매처) |
2 | 2 | 2 |
.claude/skills/stamp/SKILL.md(부르지 않음) |
0 | 0 | 0 |
모델은 Claude Haiku 4.5였고, CLAUDE.md·스킬 쪽은 그 스크립트를 승인 없이 돌릴 수 있게 허용해 두었습니다. 훅 쪽은 허용 없이 돌렸고, CLAUDE.md에서는 그 줄을 지웠습니다.
숫자 셋이 각각 다른 이야기를 합니다.
CLAUDE.md는 지키긴 했는데 한 번으로 뭉뚱그렸습니다. 편집은 두 번인데 실행은 한 번이었죠.
“편집한 뒤”를 “작업을 마친 뒤”로 읽은 셈인데, 틀렸다기보다 자연어 지시에 남는 여지라고 봅니다. 포맷터라면 괜찮지만 “편집마다 감사 로그”라면 한 건이 빕니다.
도구 호출마다 돌아야 하는 일이라면 PostToolUse 훅으로 옮기세요.
훅은 편집마다 돌았습니다. Claude는 스크립트가 있는지도 모르고 Bash 허용도 없었는데 매번 2회였어요.
스킬은 부르지 않으면 아무것도 하지 않았습니다. 설명이 “편집한 파일에 도장을 찍습니다”인데도 0회였고, /stamp로 직접 부르자 1회가 나왔습니다.
허용을 빼고 CLAUDE.md 규칙만 둔 채 돌리면 결과가 또 달랐습니다. 스크립트는 돌지 않았고, Claude는 “프로젝트 규칙에 따라 bash tools/stamp.sh를 실행해야 하는데 승인이 필요하다”고 답했어요.
규칙이 시킨 명령도 일반 도구 호출이라 권한 계층을 그대로 지나가지만, 훅의 셸 명령은 그 계층을 거치지 않습니다. CLAUDE.md에 적은 명령이 승인 질문에서 멈춘다면 그 명령을 허용 목록에 넣거나, 승인 없이 매번 돌아야 하는 일이면 훅으로 옮기면 됩니다.
권한 규칙의 평가 순서는 Claude Code 권한 설정 글에 있습니다.
Windows · 2.1.296에서 다시 돌려 보니
10월 14일 Windows 11 · Claude Code 2.1.296에서 모델만 Haiku 5.5로 바꿔 같은 요청을 세 번씩 보냈습니다.
| 지시를 넣은 곳 | 1회차 | 2회차 | 3회차 |
|---|---|---|---|
CLAUDE.md의 작업 규칙 한 줄 |
1 | 1 | 1 |
PostToolUse 훅(Edit|Write 매처) |
2 | 2 | 2 |
스킬(설명: Stamps edited files., 부르지 않음) |
0 | 0 | 0 |
스킬(설명 끝에 Run after editing files. 추가) |
1 | 1 | 1 |
앞의 세 줄은 리눅스와 같았고, -p "/stamp"로 직접 부르면 1회였습니다. 달라진 건 넷째 줄이에요. 설명에 언제 실행할지를 한 문장 적자, 부르지 않았는데도 Claude가 편집을 마친 뒤 스스로 스킬을 꺼내 한 번 돌렸습니다.
이 실험에서는 스킬이 자동으로 쓰이느냐가 설명 한 문장으로 갈렸습니다. 다만 이것도 편집마다가 아니라 한 턴에 한 번이었으니, 편집마다 돌아야 하는 일은 여전히 훅의 몫입니다.
허용 규칙을 넣는 자리에도 함정이 있었습니다. 신뢰 확인을 한 번도 하지 않은 폴더에서 -p로 돌리니, .claude/settings.json의 allow는 Ignoring 1 permissions.allow entry from .claude/settings.json: this workspace has not been trusted.라는 경고와 함께 무시되고 CLAUDE.md 쪽 스크립트는 승인 대기에서 멈췄어요. 같은 파일에 적은 훅은 그 폴더에서도 그대로 돌았습니다. 위 표의 허용은 --allowedTools "Bash(bash tools/stamp.sh)"로 넘긴 결과입니다.
횟수가 갈린 이유: 언제 읽히고, 누가 실행을 정하나
셋은 같은 일을 하는 세 가지 문법이 아닙니다. 컨텍스트에 들어가는 시점과 실행을 정하는 주체가 다릅니다.
| 방식 | 컨텍스트에 들어가는 때 | 실행을 정하는 쪽 |
|---|---|---|
CLAUDE.md |
매 세션 시작 | Claude의 판단 |
.claude/rules/(paths 없음) |
매 세션 시작 | Claude의 판단 |
.claude/rules/(paths 있음) |
맞는 파일을 다룰 때 | Claude의 판단 |
| 스킬 | 설명만 상시, 본문은 쓸 때 | Claude 또는 /이름 |
| 훅 | 들어가지 않음(밖에서 실행) | 이벤트가 나면 항상 |
훅은 컨텍스트를 차지하지 않으므로 출력을 넣지 않는 한 비용도 0입니다. 스킬도 설명만 상시 로드되고 본문은 쓸 때만 올라가니, 본문이 긴 참고 자료라도 쓰기 전까지는 비용이 거의 없어요.
어느 파일이 언제 읽혔는지는 직접 확인할 수 있습니다. InstructionsLoaded 훅을 걸면 CLAUDE.md와 규칙 파일이 로드될 때마다 기록이 남거든요.
{
"hooks": {
"InstructionsLoaded": [
{ "hooks": [{ "type": "command", "command": "cat >> instructions-loaded.log; echo >> instructions-loaded.log" }] }
]
}
}
규칙 파일 두 개(하나는 paths 없이, 하나는 paths: src/api/**/*.ts)를 두고 src/api/ 아래 파일을 건드리게 했더니 로그에 세 줄이 쌓였습니다(긴 필드는 줄였습니다).
{"hook_event_name":"InstructionsLoaded","file_path":"~/demo/CLAUDE.md","memory_type":"Project","load_reason":"session_start"}
{"hook_event_name":"InstructionsLoaded","file_path":"~/demo/.claude/rules/style.md","memory_type":"Project","load_reason":"session_start"}
{"hook_event_name":"InstructionsLoaded","file_path":"~/demo/.claude/rules/api.md","memory_type":"Project","load_reason":"path_glob_match"}
볼 곳은 load_reason입니다. CLAUDE.md와 paths 없는 규칙은 session_start로, 경로를 건 규칙은 그 파일을 다룰 때 path_glob_match로 들어왔어요. 3회 모두 같았습니다.
Windows · 2.1.296에서도 같은 세 줄이 쌓였고, 경로는 C:\work\…\.claude\rules\api.md처럼 역슬래시로 찍혔습니다. path_glob_match 줄에는 규칙을 불러온 파일이 trigger_file_path(…\src\api\handler.ts)로 함께 남아요.
스킬은 이 로그에 나오지 않습니다. 이 이벤트는 CLAUDE.md와 규칙 파일만 다루고, 스킬은 설명만 미리 올라가 있다가 쓸 때 본문이 로드되기 때문입니다.
저는 “매번 돌아야 하나”부터 묻습니다
질문 하나로 대부분 갈립니다. 실행이 보장돼야 하는 일인가, 판단이 필요한 일인가.
| 이런 일 | 적을 곳 |
|---|---|
편집 후 포맷, 커밋 전 테스트, .env 쓰기 차단 |
훅 |
| 빌드·테스트 명령, 기본값과 다른 코드 규칙 | CLAUDE.md |
| API 핸들러 규칙, 테스트 파일 작성 규칙 | paths 붙인 .claude/rules/ |
| 배포·릴리스 절차, 긴 API 참고 문서 | 스킬 |
공식 문서는 이 경계를 한 문장으로 정리합니다. “An instruction like “never edit .env” in CLAUDE.md or a skill is a request, not a guarantee. A PreToolUse hook that blocks the edit is enforcement.” 막아야 하는 것은 훅으로 내리고, 나머지는 컨텍스트 비용을 보고 고르면 됩니다.
그럼 전부 훅으로 걸면 되지 않느냐 하면, 그건 안 됩니다. 훅은 판단을 못 하거든요. “이 변경이 API 규칙에 맞는지 보라” 같은 일은 셸 명령으로 짤 수 없으니, 그런 지침은 CLAUDE.md나 규칙 파일에 두고 Claude가 읽게 해야 합니다.
셋을 같이 쓰는 것도 물론 됩니다. 늘 필요한 규칙은 CLAUDE.md, 필요할 때 읽을 참고 자료는 스킬에 두는 조합이 기본이에요. 같은 내용을 겹쳐 적는 것만 피하세요.
사용자·프로젝트·하위 폴더의 CLAUDE.md는 서로 덮어쓰지 않고 모두 더해지는데, 지시가 충돌하면 어느 파일이 이긴다는 규칙이 없고 Claude가 판단하거나 임의로 하나를 고를 수 있습니다. 충돌하는 지시는 주기적으로 찾아 정리하는 편이 안전합니다.
헷갈리기 쉬운 경계
.claude/rules/로 옮긴다고 더 잘 지켜지진 않는다
paths가 없는 규칙은 .claude/CLAUDE.md와 같은 우선순위로 시작 때 로드됩니다. 규칙 폴더로 옮기는 이유는 강제력이 아니라 정리, 그리고 paths로 로드 조건을 거는 것이에요. CLAUDE.md가 권장 길이(파일당 200줄 이하)를 넘기기 시작할 때 쪼개는 자리라고 보면 됩니다.
훅은 발동을 보장할 뿐, 결과까지는 아니다
셸 명령을 돌리거나 exit 2로 호출을 막는 훅은 실행 자체가 결과입니다. 하지만 UserPromptSubmit처럼 텍스트를 컨텍스트에 넣는 훅은, 넣은 뒤부터 다시 모델의 판단이에요.
또 exit 2가 모든 이벤트를 막지는 않습니다. SessionStart 같은 이벤트는 exit 2여도 stderr를 사용자에게 보여 주고 그대로 진행합니다.
스킬은 자동으로 도는 게 아니라 기다리는 절차다
Claude는 관련 있다고 판단할 때만 스킬을 씁니다. 위 실험에서 하는 일만 적은 설명으로는 0회였고, 언제 실행할지를 한 문장 더하자 한 턴에 한 번 불렸지만 편집마다 돌지는 않았어요. 반드시 돌아야 하면 훅으로 옮기거나 /이름으로 부르세요.
규칙이 안 먹을 때 먼저 볼 것
규칙이 안 지켜진다면 /context의 Memory files 목록에 파일이 실제로 로드됐는지부터 보세요. 로드는 됐는데 안 지켜진다면, 모호하거나 서로 부딪히는 지시일수록 엄격한 준수가 보장되지 않으니 지시를 더 구체적으로 고치거나 훅으로 내립니다.
paths를 붙인 규칙이 아예 로드되지 않는 경우도 있습니다. 경로 규칙은 모든 도구 호출이 아니라 맞는 파일에 Read·Write·Edit 도구를 쓸 때만 로드돼요.
Claude Code 2.1.288 이전에는 Read만 규칙을 불러왔고, Write·Edit로 범위 안 파일을 만들거나 고칠 때는 로드되지 않았습니다. 그러니 2.1.288보다 낮으면 먼저 업데이트하고, 그다음 위의 InstructionsLoaded 훅으로 load_reason이 path_glob_match로 찍히는지 보세요.
안 찍히면 글로브가 실제 경로와 맞는지 확인하면 됩니다.
다른 사람들이 겪은 문제
위의 경계는 공개 사례에서도 그대로 드러납니다. 아래 네 건은 각 작성자가 공개한 기록입니다.
- DrJLWilliams(2026-01-16, #18660):
CLAUDE.md가 로드되고 모델이 규칙을 되풀이해 말할 수도 있는데, 작업을 끝내는 쪽으로 흘러 일관되게 지키지 않는다며 강제 수단을 요청했습니다. not planned로 닫힘. - minatoplanb(2026-03-08, #32163): 200줄 넘는 규칙을 “좋은 날에 60~70%” 지킨다고 스스로 추정하며
@enforce표시를 요청했습니다. 측정 방법이 공개돼 있지 않아 체감 수치로 읽는 편이 맞습니다. not planned로 닫힘. - wujekbogdan(2026-03-03, #30387, Claude Code 2.1.63, Sonnet): 직접 만든 Jira 스킬은 잘 불리는데 git 스킬은 절반쯤 무시되고,
.claude/CLAUDE.md에 “ALWAYS invoke…“를 적어도 효과가 없었다고 보고했습니다. not planned로 닫힘. - Chris-tmas(2026-01-21, #19659, Claude Code 2.1.14, Windows):
UserPromptSubmit훅이 스킬 사용을 지시하는 텍스트를 넣었고 전달까지 확인됐는데 다른 도구가 쓰였다고 보고했습니다. 훅이 발동하지 않은 게 아니라 넣은 텍스트가 지켜지지 않은 사례입니다. 중복으로 닫힘.
네 건 모두 지켜지지 않은 건 글로 적은 지시였습니다. 앞의 두 건은 규칙을 코드로 강제할 수단을, 뒤의 두 건은 적어 둔 대로 스킬을 부르기를 바랐다는 점만 달라요.
마치며
같은 문장을 세 자리에 넣어 세어 보니, 차이는 문법이 아니라 “누가 실행을 정하느냐”에 있었습니다. 매번 돌아야 하는 일은 훅, 늘 알아야 하는 사실은 CLAUDE.md, 가끔 쓰는 절차는 스킬에 두고, “절대 안 된다”는 글이 아니라 훅으로 막는 게 제 기준입니다. 다만 3회 실행은 통계가 아니니, 자기 프로젝트에서도 stamp.log 같은 방식으로 한 번 세어 보시는 게 가장 확실합니다.
손대기 좋은 출발점은 CLAUDE.md에서 “반드시”, “절대”가 들어간 줄을 찾아 훅으로 옮길 수 있는지 보는 것입니다. 한 저장소에서 여러 CLI의 설정 파일을 함께 쓴다면 CLAUDE.md·AGENTS.md·GEMINI.md를 나란히 놓고 비교한 글을 이어서 보세요.
참고한 공식 자료
모두 2026년 9월 14일에 확인했습니다(변경 기록은 10월 4일).
- Extend Claude Code — CLAUDE.md·규칙·스킬 로드 시점 비교, 훅과 스킬의 결정성, 기능별 컨텍스트 비용, 지시 충돌
- How Claude remembers your project —
CLAUDE.md가 강제 설정이 아니라는 점,.claude/rules/의 우선순위와paths동작, 200줄 권고, 안 지켜질 때 점검 순서 - Hooks reference —
InstructionsLoaded이벤트와load_reason값, exit 코드별 동작 - Automate actions with hooks — 훅의 결정성, 매처 없는 훅의 발동 범위
- Extend Claude with skills — 설명만 상시 로드되는 구조, 자동 호출 제어 필드
- Claude Code 변경 기록 — 2.1.288에서 경로 규칙이 Write·Edit에서도 로드되도록 바뀐 항목
인용한 공개 사례
- DrJLWilliams, CLAUDE.md instructions are read but not reliably followed - need enforcement mechanism (2026-01-16) — 규칙이 로드되는데도 일관되게 지켜지지 않는다는 보고
- minatoplanb, Hard-enforce CLAUDE.md rules via code (2026-03-08) — 규칙을 코드로 강제해 달라는 요청과 작성자의 준수율 추정
- wujekbogdan, Custom skills are not reliably auto-triggered by the model (2026-03-03) — 스킬 자동 호출이 도메인에 따라 갈린다는 보고
- Chris-tmas, Claude ignores hook instructions despite system prompt directive (2026-01-21) — 훅이 넣은 텍스트가 지켜지지 않은 보고
변경 이력
- 2026-10-14 — 같은 실험을 Windows 11 · Claude Code 2.1.296 · Haiku 5.5로 다시 돌린 결과를 더했습니다. 횟수는 1·2·0으로 같았고, 스킬 설명에 실행 시점을 적으면 부르지 않아도 1회가 됐습니다. 신뢰하지 않은 폴더의 -p 실행에서 허용 규칙은 무시되고 훅은 도는 것도 적었습니다. 같은 날 스킬이 0회였던 이유를 일반화한 문장을, 설명 문구에 따라 0회와 한 턴 1회로 갈린 Windows 실측에 맞게 고쳤습니다.
- 2026-10-04 — Claude Code 2.1.288부터 경로 규칙이 Read뿐 아니라 Write·Edit로 범위 안 파일을 만들거나 고칠 때도 로드돼, 오류 절의 원인 설명과 문서 인용을 고쳤습니다.
- 2026-09-29 — 공식 문서 문구가 바뀌어 InstructionsLoaded 훅 인용과, 여러 CLAUDE.md의 지시가 충돌할 때의 설명(더 구체적인 지시가 우선한다는 부분 삭제)을 현재 문서에 맞게 고쳤습니다.