본문 바로가기
claudecode.to
문서 목록
Hooks 코스고급

UserPromptSubmit 훅 — 프롬프트 가공과 기밀 정보 차단

UserPromptSubmit 훅은 사용자가 프롬프트를 전송했을 때 발화해 입력을 가공·검증할 수 있는 Hooks 이벤트입니다. stdin JSON에서 prompt를 읽는 법, stdout으로 컨텍스트를 추가하는 법, API 키를 감지해 차단하는 법을 다룹니다.

22분2026-08-22 갱신

UserPromptSubmit 훅은 사용자가 Claude Code에 프롬프트를 전송했을 때 자동 실행되어, 입력을 가공·검증하거나 추가 정보를 부여할 수 있는 Hooks 이벤트입니다. 프롬프트를 보내기 전에 추가 지시를 컨텍스트에 주입하거나, 무심코 넣은 API 키를 전송 전에 차단할 수 있습니다.

SubagentStop 훅까지의 훅이 도구와 에이전트의 동작을 다뤘다면, 이 훅은 사용자 입력 자체를 다룬다는 점에서 독특한 자리에 있습니다. Hooks 코스의 마지막 글입니다.

핵심 요약

  • UserPromptSubmit 훅은 사용자가 프롬프트를 전송했을 때 발화합니다.
  • stdin에서 JSON 형식으로 프롬프트를 받아, prompt 필드로 사용자 입력을 취득합니다.
  • stdout에 출력한 내용이 컨텍스트에 추가됩니다.
  • API 키 등의 기밀 정보를 감지해 차단할 수 있습니다.
  • 매처(패턴 지정)를 쓰지 않고 프롬프트 전송 시마다 매번 실행됩니다.

UserPromptSubmit 훅의 역할은 무엇인가

역할설명
추가프롬프트에 컨텍스트나 추가 지시를 주입합니다
차단기밀 정보를 감지해 전송을 차단합니다

Hooks의 기본 구조는 훅(Hooks)으로 동작 강제하기를 참고하세요.

stdin에서 JSON을 어떻게 받나

UserPromptSubmit 훅은 stdin(표준 입력)으로 JSON 형식의 데이터를 받습니다. stdin은 프로그램에 데이터를 넘기기 위한 입구로, 터미널에서 echo "Hello" | cat처럼 파이프로 데이터를 넘기는 것과 같은 원리입니다. Claude Code가 스크립트의 표준 입력으로 아래와 같은 JSON을 넘겨 줍니다.

{
  "session_id": "abc123",
  "prompt": "안녕하세요, 오늘 날씨를 알려줘",
  "cwd": "/Users/username/project",
  "hook_event_name": "UserPromptSubmit"
}

가장 중요한 것은 prompt 필드로, 사용자가 입력한 텍스트가 여기에 들어 있습니다. 환경 변수가 아니라 JSON으로 받는 이유는 프롬프트에 줄바꿈이나 특수 문자가 들어갈 수 있어 안전하게 주고받도록 설계했기 때문입니다. Hooks 환경 변수와는 전달 경로가 다른 셈입니다.

jq로 prompt 필드 꺼내기

JSON에서 데이터를 꺼내려면 jq 명령이 편리합니다. macOS에서는 brew install jq, Ubuntu/Debian에서는 sudo apt-get install jq로 설치합니다.

# stdin에서 JSON을 읽고 prompt 필드를 추출
prompt=$(cat | jq -r '.prompt')
부분설명
cat표준 입력에서 데이터를 읽습니다
파이프다음 명령에 데이터를 넘깁니다
jq -r '.prompt'JSON에서 prompt 필드 값을 꺼냅니다 (-r은 날것 문자열로 출력)
prompt=$(...)결과를 변수 prompt에 저장합니다

기본 설정 구조

설정은 settings.json의 hooks 섹션에 기술합니다. 설정 파일 위치와 sh 파일화 요령은 Hooks 설정 방법을 참고하세요.

{
  "hooks": {
    "UserPromptSubmit": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "실행할 명령"
          }
        ]
      }
    ]
  }
}
항목설명
matcher매처에 대응하지 않으므로 생략합니다
type"command"를 지정해 셸 명령을 실행합니다
command실행할 명령을 기술합니다
stdout출력한 내용이 컨텍스트에 추가됩니다

먼저 간단한 예로 확인하기

Hooks 설정 방법에서 만든 ~/Desktop/hooks-test 디렉터리를 그대로 사용합니다. 아직 없다면 아래 명령으로 만들어 주세요.

mkdir -p ~/Desktop/hooks-test/.claude/hooks
cd ~/Desktop/hooks-test
  1. 프롬프트를 로그에 기록하는 스크립트를 .claude/hooks/log-prompt.sh로 만듭니다.
#!/bin/bash
# stdin에서 JSON을 읽고 prompt 필드를 추출
prompt=$(cat | jq -r '.prompt')

# 로그 파일에 기록
echo "$(date): $prompt" >> ~/Desktop/hooks-test/prompt.log

exit 0
  1. 스크립트에 실행 권한을 부여합니다.
chmod +x ~/Desktop/hooks-test/.claude/hooks/log-prompt.sh
  1. ~/Desktop/hooks-test/.claude/settings.json에 아래 설정을 추가합니다.
{
  "hooks": {
    "UserPromptSubmit": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "~/Desktop/hooks-test/.claude/hooks/log-prompt.sh"
          }
        ]
      }
    ]
  }
}
  1. ~/Desktop/hooks-test에서 Claude Code를 실행하고 "안녕하세요" 같은 질문을 입력한 뒤 로그 파일을 확인합니다.
cat ~/Desktop/hooks-test/prompt.log
# Tue Dec 30 08:55:07 CST 2025: 안녕하세요

방금 입력한 프롬프트가 기록되어 있으면, UserPromptSubmit 훅이 프롬프트를 받아 스크립트를 실행하고 있다는 뜻입니다.

사용처 1 — 컨텍스트에 추가 지시를 주입하기

stdout에 출력한 내용은 컨텍스트에 추가되므로, 매번의 프롬프트에 "주의사항"을 부여할 수 있습니다. Claude Code에는 사용자가 선택식으로 답할 수 있는 AskUserQuestion 도구가 있는데, 모호한 지시에는 이 도구로 되묻도록 촉구하는 스크립트를 .claude/hooks/add-guardrail.sh로 만들어 봅니다.

#!/bin/bash
# stdin을 소비
cat > /dev/null

# 추가 지시를 출력
echo "사용자로부터의 프롬프트가 모호한 경우엔, AskUserQuestion 도구를 사용해 사용자에게 확인하고 나서 작업을 진행해 주세요."

exit 0

**cat > /dev/null에 대해** — Claude Code의 훅에는 method나 id를 갖지 않는 심플한 JSON 데이터가 stdin으로 전달됩니다. cat > /dev/null은 "보내진 데이터를 읽고 버리는" 처리입니다. 이걸 넣지 않으면 데이터가 버퍼에 남은 채가 되어 드물게 통신이 잘 안 되는 경우가 있습니다. 우편함에 도착한 편지를 꺼내지 않고 방치하면 다음 편지가 안 들어가는 것과 같습니다. 생략해도 동작하는 경우가 많지만, 프로토콜상 올바른 작법으로 넣어 두는 것이 무난합니다.

settings.json은 아래처럼 됩니다.

{
  "hooks": {
    "UserPromptSubmit": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "~/Desktop/hooks-test/.claude/hooks/add-guardrail.sh"
          }
        ]
      }
    ]
  }
}

이 설정으로 사용자의 프롬프트에 더해 "모호한 경우엔 확인한다"는 가이드라인이 컨텍스트에 추가됩니다. Claude Code는 확률론적으로 동작하므로 매번 확인해 준다고는 할 수 없지만, 확인 빈도는 올라갑니다. Claude Code에 질문을 던진 뒤 Ctrl + o로 트랜스크립트를 표시하면 가이드라인이 컨텍스트에 들어간 것을 확인할 수 있습니다.

> 로그 파일을 편집해줘
  ⎿ UserPromptSubmit hook succeeded: 사용자로부터의 프롬프트가 모호한 경우엔, AskUserQuestion 도구를 사용해 사용자
    에게 확인하고 나서 작업을 진행해 주세요.

∴ Thinking…
  사용자는 "로그 파일을 편집해줘"라고 말하고 있는데, 이건 모호한 요청입니다. 어느 로그 파일을 편집하는지,
  어떤 편집을 하는지가 명확하지 않습니다.

⏺ 요청이 모호하므로 확인하겠습니다.
어느 로그 파일을 편집할까요? 파일 경로를 알려 주세요.
❯ 1. 파일을 찾는다
  2. 경로를 지정
  3. Type something.

주입된 지시를 Claude Code가 이해하고, 실제로 AskUserQuestion 도구로 되묻는 것을 확인할 수 있습니다. 팀에서 Claude Code를 쓸 때 통일된 규칙을 적용하기에 가장 추천하는 사용처입니다.

셸 스크립트를 준비하는 것이 번거롭다면 한 줄로 설정할 수도 있습니다. 추가 문자열을 늘 삽입하는 용도라면 이 정도로 충분합니다.

{
  "hooks": {
    "UserPromptSubmit": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "echo '사용자로부터의 프롬프트가 모호한 경우엔, AskUserQuestion 도구를 사용해 사용자에게 확인하고 나서 작업을 진행해 주세요.'"
          }
        ]
      }
    ]
  }
}

사용처 2 — 기밀 정보를 감지해 차단하기

개발 중에 API 키나 시크릿을 프롬프트에 포함해 버리는 일이 있을 수 있습니다. 그런 정보가 Claude Code에 전송되기 전에 감지해 차단하는 스크립트를 .claude/hooks/filter-secrets.sh로 만듭니다. 직접 커스터마이즈할 때는 Claude Code에 도움을 받으면 간단히 만들 수 있습니다.

#!/bin/bash
# stdin에서 JSON을 읽고 prompt 필드를 추출
prompt=$(cat | jq -r '.prompt')

# API 키 패턴을 감지 (OpenAI 형식: sk-xxx)
if echo "$prompt" | grep -qE "sk-[a-zA-Z0-9]{20,}"; then
    echo '{"decision": "block", "reason": "API 키가 포함돼 있을 가능성이 있습니다. 기밀 정보를 삭제하고 나서 다시 시도해 주세요."}'
    exit 0
fi

exit 0

JSON 형식으로 {"decision": "block", "reason": "..."}를 반환하면 프롬프트 전송이 차단되고 사용자에게 이유가 표시됩니다. 시험 삼아 sk-로 시작하는 더미 API 키를 프롬프트로 입력해 봅니다.

> API 키를 당신에게 알려줄게요. sk-abcdefghijklmnopqrstuvwxyz123456 입니다.

그러면 Claude Code에 전송되기 전에 차단되고, 스크립트에서 설정한 메시지가 표시됩니다.

⏺ UserPromptSubmit operation blocked by hook:
  API 키가 포함돼 있을 가능성이 있습니다. 기밀 정보를 삭제하고 나서 다시 시도해 주세요.
  Original prompt: API 키를 당신에게 알려줄게요. sk-abcdefghijklmnopqrstuvwxyz123456 입니다.

이걸로 무심코 API 키를 전송해 버리는 일이 없어집니다. 종료 코드를 쓴 차단 제어의 상세는 종료 코드로 제어를 참고하세요.

정리

  • UserPromptSubmit 훅은 프롬프트 전송 시마다 발화하며, stdin JSON의 prompt 필드로 사용자 입력을 받습니다.
  • 컨텍스트 추가: stdout에 출력한 추가 지시가 프롬프트에 주입됩니다. 팀 규칙을 통일하는 데 편리합니다.
  • 기밀 정보 차단: {"decision": "block", "reason": "..."}를 출력하면 API 키 같은 기밀 정보의 오전송을 막을 수 있습니다.
  • 매처는 쓰지 않으며, stdin을 쓰지 않는 스크립트도 cat > /dev/null로 입력을 소비해 두는 것이 무난합니다.
  • 이것으로 Hooks 코스는 끝입니다. 이벤트 전체 목록과 설계 원칙은 훅(Hooks)으로 동작 강제하기에서 다시 확인할 수 있습니다.

자주 묻는 질문

HooksUserPromptSubmit기밀 정보jq컨텍스트

팀에 Claude Code를 도입하려면 실제 코드베이스에 맞춘 설계가 필요합니다.

무료 상담 신청