하네스 엔지니어링
프롬프트는 부탁이고, Hook은 시스템이다.
Claude Code Hook으로 에이전트 워크플로를 코드로 강제하는 방법을 정리한 교육자료입니다.
👉 인터랙티브 교육자료 보기 — 흐름도, 채팅 시뮬레이션이 포함된 풀 디자인 버전
01. 부탁 vs 강제, 무엇이 다른가?
프롬프트 엔지니어링은 에이전트에게 "이렇게 해줘"라고 부탁하는 거고, 하네스 엔지니어링은 규칙을 어기면 도구 자체가 실행되지 않도록 만드는 거예요.

Soft Guardrail — 프롬프트 엔지니어링
CLAUDE.md에 "초안 전에 아웃라인을 먼저 작성하세요"라고 지침을 남깁니다. 대부분 따르지만, 맥락이 길어지거나 사용자가 재촉하면 무시될 수 있어요.
비유: "출입증을 꼭 패용하세요" 공지문
Hard Guardrail — 하네스 엔지니어링
Hook 스크립트가 outline.md 존재 여부를 검사합니다. 없으면 exit 2를 반환하여 Write 도구 자체를 물리적으로 차단합니다.
비유: 출입증 없으면 문이 안 열리는 시스템
02. 실습 시나리오 — 책 챕터 작성에 워크플로 강제 걸기
"아웃라인 없이 초안 작성 불가"라는 규칙을 Hook으로 구현합니다. Claude가 아무리 시도해도, outline.md가 없으면 draft.md를 쓸 수 없어요.
프로젝트 구조
book/
ch01/
outline.md ← 이게 있어야
draft.md ← 이걸 쓸 수 있음
ch02/
outline.md
ch03/
(아직 비어있음)
.claude/
settings.json
hooks/
require-outline.sh
03. Hook 코드 — 규칙을 코드로 만들기
require-outline.sh
#!/bin/bash
# stdin으로 들어오는 JSON 파싱
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name')
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // ""')
# draft.md 작성 시도를 감지
if [[ ("$TOOL_NAME" == "Write" || \
"$TOOL_NAME" == "Edit") && \
"$FILE_PATH" == *"/draft.md" ]]; then
# 같은 폴더에서 outline.md 확인
CHAPTER_DIR=$(dirname "$FILE_PATH")
OUTLINE="$CHAPTER_DIR/outline.md"
if [[ ! -f "$OUTLINE" ]]; then
echo "⛔ outline.md가 없습니다."
echo " 아웃라인을 먼저 작성해주세요."
exit 2 # ← 도구 실행 차단!
fi
fi
exit 0 # ← 통과
settings.json — Hook 등록
{
"PreToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "bash .claude/hooks/require-outline.sh"
}
]
}
]
}
03-B. Prompt Hook — 문체 윤문도 Hook으로 강제할 수 있다
아웃라인 검사는 "파일이 있냐 없냐"라서 bash로 충분했지만, 문법 교정이나 문체 일관성은 자연어 판단이 필요하거든요. 이럴 때 prompt 타입 Hook을 쓰면 됩니다.
Command vs Prompt — 두 가지 타입 비교
Command Hook (결정론적 검사) — 파일 존재 여부, 줄 수 확인, 패턴 매칭 등. bash 스크립트로 빠르게 판단합니다. 예를 들어 outline.md 없으면 차단하는 경우예요.
Prompt Hook (LLM 기반 판단) — 문체 일관성, 맞춤법, 톤 검수 등. 자연어 추론이 필요한 품질 검사입니다. 예를 들어 "~합니다" 문어체를 구어체로 교정하는 경우죠.
시나리오: 초안 작성 후 문체 자동 검수
Claude가 draft.md를 작성하면, PostToolUse Hook이 자동으로 문체를 검수합니다. 딱딱한 문어체, "콜론+목록" 패턴, AI 냄새 나는 표현이 감지되면 Claude에게 피드백을 보내 스스로 수정하게 만들어요.
{
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "prompt",
"prompt": "방금 작성된 파일이 draft.md라면, 다음 문체 규칙을 위반했는지 검사하세요: 1. '~합니다/~됩니다'만 반복하는 딱딱한 문어체 금지 → '~거든요', '~더라고요', '~예요' 같은 구어체 사용 2. 'XXX의 장점:' 뒤에 불릿 리스트 나열 금지 → 자연어로 흐름을 이어갈 것 3. '또한', '뿐만 아니라', '이를 통해' 같은 AI 표현 금지. 위반이 있으면 구체적 위치와 수정 제안을 반환하세요. 위반이 없으면 'approve'를 반환하세요."
}
]
}
]
}
문체 검수 Hook 작동 예시
AI: ch03/draft.md 초안을 작성했습니다.
✅ Write → ch03/draft.md (통과 — 아웃라인 확인됨)
🧠 PostToolUse 문체 검수 결과:
⚠️ 3건 감지
- 2번째 문단: "이를 통해 성능이 향상됩니다" → "이렇게 하면 성능이 확 좋아지거든요"
- 4번째 문단: "MCP의 장점:" + 불릿 나열 → 자연어로 풀어서 설명할 것
- 전반적 톤: "~됩니다" 12회 반복 → 구어체 비율 높일 것
AI: 문체 피드백을 반영하여 수정하겠습니다. 문어체를 구어체로, 목록을 자연어로 풀어서 다시 작성합니다.
Command vs Prompt — 언제 뭘 쓸까?
Command가 적합한 경우: 파일 존재 확인, 줄 수 제한, 금지 패턴 grep, 린트 실행, 테스트 통과 여부
Prompt가 적합한 경우: 문체 검수, 코드 리뷰, 보안 취약점 분석, 비즈니스 로직 검증, 완성도 판단
04. Exit Code 규칙 — 세 가지만 기억하면 됩니다
exit 0 — 통과. 검사 OK, 도구 실행을 허용합니다.
exit 2 — 차단. 규칙 위반 감지, 도구 실행을 물리적으로 막습니다.
echo — 피드백. 차단 시 출력한 메시지가 Claude에게 전달됩니다.
05. 동작 흐름 — Hook이 작동하는 순간
- 사용자 요청 — "ch03 초안 작성해줘"
- Claude 시도 — Write → ch03/draft.md
- PreToolUse Hook — outline.md 존재 여부 검사
- 분기:
- 없음 →
exit 2→ 차단 + 피드백 ("아웃라인부터 작성하겠습니다") - 있음 →
exit 0→ 통과 ("초안 작성을 시작합니다")
- 없음 →
06. 실제 대화 — Claude는 어떻게 반응할까?
Hook이 차단하면 Claude는 피드백 메시지를 읽고 스스로 우회 경로를 찾습니다.
👤 사용자: ch03 드래프트 써줘. 주제는 MCP 서버 구축이야.
🤖 Claude: ch03/draft.md를 작성하겠습니다.
⛔ Hook: outline.md가 없습니다. 아웃라인을 먼저 작성해주세요.
🤖 Claude: ch03에 아웃라인이 없네요. 먼저 outline.md를 작성하겠습니다.
✅ Write → ch03/outline.md (통과!)
🤖 Claude: 아웃라인 완료. 이제 초안을 작성합니다.
✅ Write → ch03/draft.md (통과!)
outline.md는 draft.md가 아니므로 Hook에 걸리지 않아 자유롭게 생성됩니다.
코드가 어려우면? 자연어로 Hook을 만들 수 있다
위의 bash 스크립트나 settings.json 문법이 낯설어도 걱정할 필요가 없어요. Claude Code에게 자연어로 Hook을 설계해달라고 요청하면 되거든요.
예를 들어 이렇게 프롬프트를 던져보세요.
"Claude Code의 PreToolUse Hook을 만들어줘. Write나 Edit 도구로 draft.md를 작성하려고 할 때, 같은 폴더에 outline.md가 없으면 차단하는 bash 스크립트와 settings.json 설정을 같이 생성해줘."
이러면 Claude가 require-outline.sh 스크립트와 settings.json 설정을 둘 다 만들어주거든요. 문법을 외울 필요가 없어요.
문체 검수용 Prompt Hook도 마찬가지예요.
"PostToolUse Hook을 만들어줘. draft.md 파일을 작성한 뒤에 문체를 자동 검수하는 prompt 타입 Hook이야. 딱딱한 문어체, 콜론+목록 패턴, AI 냄새 나는 표현을 감지해서 피드백을 주는 프롬프트를 작성해줘."
핵심은 "어떤 상황에서, 어떤 도구를, 어떤 조건으로 차단/검수할지"만 자연어로 설명하면 된다는 거예요. Hook의 문법은 Claude가 알아서 처리합니다.
핵심 요약
프롬프트 엔지니어링이 "교육"이라면, 하네스 엔지니어링은 "시스템"이에요. 프롬프트는 확률적으로 대부분 따르지만, Hook은 결정론적으로 100% 강제합니다. 그리고 단순히 막는 것이 아니라, 피드백 메시지로 Claude를 올바른 방향으로 유도해요.
CLAUDE.md + Hook = 왜(Why) + 강제(How)
