Claude Code Hook Message Settings

개발자, Bono·2026년 1월 12일

Claude Code

목록 보기
1/1
post-thumbnail

클로드코드의 특정이벤트를 이용해서 메시지 보내기

Step 1

  • 클로드코드 설정에 훅설정을 추가해준다.
  • 훅의 종류에 따라 원하는 이벤트(command)를 통해 하고자하는 작업을 설정한다.

사용하는 이벤트 목록

  • Stop (작업완료)
  • PreToolUse (도구호출 직전)
  • PostToolUse (도구호출 완료)

Step 2

  • 아래 예시는 완료필터(Stop), 작업도구 필터(PreToolUse,PostToolUse) 총 2가지 부류로 필터해 이벤트를 수행하게 해 두었다.

  • PreToolUse에서 자동수행으로 설정하게 되면 도구를 묻지않는 상태도 발생하기 때문에 PreToolUse 이벤트에서 10초의 딜레이를 발생하였다.

  • 10초내에 PostToolUse에서 완료처리가 되었다면 이벤트 메시지 발송을 취소하도록 처리하여 불필요한 메시지 전송을 방지하였다.

  • 딜레이를 발생시켜도 큐에 담지 않는 이상은 정상적인 처리가 불가하다고 판단하여. 위 기능은 폐기하도록 함.

  • Bash|Write|Edit는 메시지를 많이 발생시키지만 종종 이 도구들이 확인을 묻는 경우가 발생함. 훅이 확인해야하는지 안해야하는지 까지 판별하지 못하기 때문에 거슬리면 삭제하여 한번씩 확인하던지, 예정/완료 메시지를 교차로 확인해 완료가 안되고 있으면 확인해보던지 둘중 하나의 방법으로 임시 처리함.(나중에 시간되면 더 좋은 방식으로 처리할 예정)

path .claud/settings.json
{
  "alwaysThinkingEnabled": true,
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "/home/persol/.claude/hooks/telegram-notify.sh",
            "timeout": 10000
          }
        ]
      }
    ],
    "PreToolUse": [
      {
        "matcher": "Bash|Write|Edit|AskUserQuestion|ExitPlanMode",
        "hooks": [
          {
            "type": "command",
            "command": "/home/persol/.claude/hooks/telegram-notify.sh",
            "timeout": 10000
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Bash|Write|Edit|AskUserQuestion|ExitPlanMode",
        "hooks": [
          {
            "type": "command",
            "command": "/home/persol/.claude/hooks/telegram-notify.sh",
            "timeout": 10000
          }
        ]
      }
    ]
  }
}

Step 3

이후 쉘스크립트로 취향에 맞게 텔레그램,슬랙 등 메시지를 받을 주체를 선택해서 스크립트를 작성하면 된다.

  • 실제 운영해보니 Bash|Write|Edit 도구까지 추가하면 너무 많은 메시지가 발송된다.
    특별한일 없으면 AskUserQuestion|ExitPlanMode 만 넣어줘도 될 듯 함.

샘플 쉘 스크립트(텔레그램)

telegram-notify.sh

#!/bin/bash

# 텔레그램 설정 - 환경변수 또는 직접 설정
TELEGRAM_BOT_TOKEN="${TELEGRAM_BOT_TOKEN:-8487791962:AAGSMwdIDZDhPX6JYP_MvWoDRvXwee2ikhY}"
TELEGRAM_CHAT_ID="${TELEGRAM_CHAT_ID:-290471427}"

# stdin에서 JSON 데이터 읽기
INPUT=$(cat)

# 디버깅용 로그 (나중에 삭제)
echo "$INPUT" >> /tmp/claude-hook-debug.log

# grep과 sed를 사용하여 JSON 파싱 (jq 대체)
# Perl 정규식(-P)으로 더 정확한 매칭
get_json_value() {
  echo "$INPUT" | grep -oP "\"$1\"\s*:\s*\"\K[^\"]*" 2>/dev/null | head -1
}

# hook 이벤트 타입 추출
EVENT=$(get_json_value "hook_event_name")
NOTIFICATION_TYPE=$(get_json_value "type")
SESSION_ID=$(get_json_value "session_id")
PERMISSION_MODE=$(get_json_value "permission_mode")
TOOL_NAME=$(get_json_value "tool_name")

# cwd에서 프로젝트명 추출
CWD=$(get_json_value "cwd")
PROJECT_NAME=$(basename "$CWD")
PROJECT_PREFIX=""
if [ -n "$PROJECT_NAME" ]; then
  PROJECT_PREFIX="📁 [$PROJECT_NAME]
"
fi

# 이벤트별 메시지 생성
case "$EVENT" in
  "PreToolUse")
    MESSAGE="${PROJECT_PREFIX}[PreToolUse] 🔨 $TOOL_NAME 도구 실행 예정"
    ;;
  "PostToolUse")
    MESSAGE="${PROJECT_PREFIX}[PostToolUse] ✅ $TOOL_NAME 도구 완료"
    ;;
  "PermissionRequest")
    case "$PERMISSION_MODE" in
      "plan")
        # 플랜 모드에서의 권한 요청은 무시 (Stop에서 처리)
        exit 0
        ;;
      "acceptEdits")
        # 편집 모드에서의 권한 요청은 무시 (Stop에서 처리)
        exit 0
        ;;
      *)
        # 실제 권한 요청만 알림
        MESSAGE="${PROJECT_PREFIX}[PermissionRequest] 🔐 $TOOL_NAME 사용 권한이 필요합니다."
        ;;
    esac
    ;;
  "Notification")
    TITLE=$(get_json_value "title")
    BODY=$(get_json_value "body")

    # 알림 타입별 메시지 생성
    case "$NOTIFICATION_TYPE" in
      "permission_prompt")
        MESSAGE="${PROJECT_PREFIX}[Notification] 🔐 권한 승인 필요
확인해주세요."
        ;;
      "idle_prompt")
        MESSAGE="${PROJECT_PREFIX}[Notification] ⏳ 입력 대기 중
입력을 기다리고 있습니다."
        ;;
      "elicitation_dialog")
        MESSAGE="${PROJECT_PREFIX}[Notification] ❓ 선택 필요
$TITLE"
        ;;
      *)
        MESSAGE="${PROJECT_PREFIX}[Notification] 🔔 $TITLE"
        ;;
    esac
    ;;
  "UserPromptSubmit")
    PROMPT=$(get_json_value "prompt")
    # 프롬프트가 길면 앞부분만 표시
    PROMPT_SHORT=$(echo "$PROMPT" | head -c 50)
    if [ ${#PROMPT} -gt 50 ]; then
      PROMPT_SHORT="${PROMPT_SHORT}..."
    fi
    MESSAGE="${PROJECT_PREFIX}[UserPromptSubmit] 📝 사용자 입력: $PROMPT_SHORT"
    ;;
  "Stop")
    # Stop 이벤트는 이벤트명 없이 기존 형식 유지
    STOP_REASON=$(get_json_value "stop_hook_reason")

    case "$STOP_REASON" in
      "end_turn")
        MESSAGE="${PROJECT_PREFIX}✅ 작업 완료
결과를 확인해주세요."
        ;;
      "user_stop")
        MESSAGE="${PROJECT_PREFIX}⏹️ 작업 중단
사용자에 의해 중단되었습니다."
        ;;
      *)
        # 빈 stop_reason이거나 알 수 없는 경우 = 확인 필요
        MESSAGE="${PROJECT_PREFIX}🔔 확인 필요
Claude가 대기 중입니다."
        ;;
    esac
    ;;
  "SubagentStop")
    MESSAGE="${PROJECT_PREFIX}[SubagentStop] ⏹️ 서브에이전트 작업 완료"
    ;;
  "SessionStart")
    SOURCE=$(get_json_value "source")
    MESSAGE="${PROJECT_PREFIX}[SessionStart] 🚀 세션 시작 (Source: $SOURCE)"
    ;;
  "SessionEnd")
    REASON=$(get_json_value "reason")
    MESSAGE="${PROJECT_PREFIX}[SessionEnd] 🛑 세션 종료 (Reason: $REASON)"
    ;;
  "PreCompact")
    TRIGGER=$(get_json_value "trigger")
    MESSAGE="${PROJECT_PREFIX}[PreCompact] 📦 컨텍스트 압축 예정 (Trigger: $TRIGGER)"
    ;;
  *)
    # 알 수 없는 이벤트도 일단 알림
    MESSAGE="${PROJECT_PREFIX}[Unknown] ❓ 알 수 없는 이벤트: $EVENT"
    ;;
esac

# 텔레그램 API로 메시지 전송
if [ -n "$TELEGRAM_BOT_TOKEN" ] && [ -n "$TELEGRAM_CHAT_ID" ]; then
  echo "[$(date '+%Y-%m-%d %H:%M:%S')] Sending message: $MESSAGE" >> /tmp/claude-hook-curl.log
  curl -s -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \
    -d chat_id="$TELEGRAM_CHAT_ID" \
    -d text="$MESSAGE" \
    -d parse_mode="HTML" >> /tmp/claude-hook-curl.log 2>&1
  echo "" >> /tmp/claude-hook-curl.log
fi

exit 0

0개의 댓글