Dante Labs
자료실

하네스 엔지니어링 — Claude Code Hook으로 워크플로 강제하기

튜토리얼

하네스 엔지니어링 — Claude Code Hook으로 워크플로 강제하기

Claude Code Hook으로 에이전트 워크플로를 코드로 강제하는 방법을 배웁니다.

2026. 04. 07.

하네스 엔지니어링

프롬프트는 부탁이고, Hook은 시스템이다.

Claude Code Hook으로 에이전트 워크플로를 코드로 강제하는 방법을 정리한 교육자료입니다.

👉 인터랙티브 교육자료 보기 — 흐름도, 채팅 시뮬레이션이 포함된 풀 디자인 버전


01. 부탁 vs 강제, 무엇이 다른가?

프롬프트 엔지니어링은 에이전트에게 "이렇게 해줘"라고 부탁하는 거고, 하네스 엔지니어링은 규칙을 어기면 도구 자체가 실행되지 않도록 만드는 거예요.

Soft vs Hard Guardrail 비교

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이 작동하는 순간

  1. 사용자 요청 — "ch03 초안 작성해줘"
  2. Claude 시도 — Write → ch03/draft.md
  3. PreToolUse Hook — outline.md 존재 여부 검사
  4. 분기:
    • 없음 → 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)

이런 자료를 계속 받고 싶다면?

AI 자동화와 데이터 사이언스 트렌드를 뉴스레터로 받아보세요.

도움이 되셨다면 커피 한 잔의 응원을 보내주세요 ☕

더 좋은 자료를 만드는 데 큰 힘이 됩니다.

Buy me a coffee