심화 8단계 커스텀 명령어와 훅(Hook)

"부를 때 실행되는 단축 버튼"과 "그 순간이 오면 무조건 실행되는 규칙" 만들기

Claude 심화 과정 8/12 · 2026년 9월 기준 · ⏱ 1~2시간 · ★ = 꼭 해볼 것

이번 단계에서 배우는 것 — 이번 글은 Claude Code 기능입니다. 기초 과정에서 익힌 터미널 사용과 JSON 파일 편집에 익숙하면 수월합니다.
커스텀 명령어
자주 하는 부탁을 /pr-summary 같은 한 단어로 만들기 (요즘은 스킬로 통합)
훅의 개념
어떤 "순간(이벤트)"에 무엇을 걸 수 있는지, 설정 파일은 어디에 두는지
실습 3종
★ 자동 포맷 · 위험 명령 차단 · 작업 완료 알림
안전하게 쓰기
훅은 내 권한으로 도는 셸 명령이라는 점, 무한 루프 조심하기

1 명령어 vs 훅 — "부탁"과 "규칙"

둘 다 "자동화"처럼 보이지만 성격이 완전히 다릅니다.

회사로 비유하면, 명령어는 "김 대리, 주간보고 양식대로 정리해 줘"라고 내가 부를 때만 움직이는 부탁입니다. 훅은 "퇴근 전에는 반드시 문단속" 같은 사내 규칙입니다. 누가 부르지 않아도, 그 순간이 오면 무조건 실행됩니다.

커스텀 명령어
내가 /이름 을 입력할 때 실행. 내용은 Claude에게 주는 지시문(프롬프트)이라 Claude가 판단해서 수행합니다.
훅(Hook)
"파일을 고친 직후", "명령을 실행하기 직전" 같은 순간에 자동 실행. 내용은 셸 명령이라 Claude의 판단과 상관없이 반드시 실행됩니다.
언제 훅을 쓰나? — CLAUDE.md에 "파일 고치면 꼭 포맷 돌려"라고 적어도 Claude가 가끔 잊을 수 있습니다. 절대 빠지면 안 되는 일은 부탁(CLAUDE.md·명령어) 대신 규칙(훅)으로 거세요.

2 커스텀 명령어 만들기 — 이제는 스킬로

예전에는 .claude/commands/ 폴더에 md 파일을 두는 방식이었습니다. 지금은 명령어가 스킬로 통합되었습니다.

.claude/commands/deploy.md
기존 방식. 여전히 동작합니다. 이미 만들어 둔 명령어는 그대로 두어도 됩니다.
.claude/skills/deploy/SKILL.md
★ 새 방식. 둘 다 똑같이 /deploy 를 만듭니다. 참고 파일·스크립트를 함께 둘 수 있어 새로 만들 땐 스킬을 권장합니다.

따라해 보기: /pr-summary 명령어 만들기

1. 폴더 만들기
프로젝트 루트에 .claude/skills/pr-summary/ 폴더를 만듭니다. (모든 프로젝트에서 쓰려면 ~/.claude/skills/)
2. SKILL.md 작성
아래 내용을 붙여넣습니다.
---
name: pr-summary
description: 현재 브랜치의 변경 사항으로 PR 설명 초안을 만든다
argument-hint: [관련 이슈 번호]
disable-model-invocation: true
---
## 현재 변경 사항
!`git diff HEAD`

## 할 일
위 변경 사항을 보고 PR 설명을 한국어로 작성해 줘.
- 제목 한 줄
- 변경 요약 (3~5줄 불릿)
- 테스트 방법
- 관련 이슈: $ARGUMENTS
3. 실행
Claude Code에서 /pr-summary 142 라고 입력합니다.

여기 쓰인 문법 정리

!`git diff HEAD`
Claude가 읽기 전에 명령을 먼저 실행해서 그 결과를 본문에 끼워 넣습니다. 매번 "diff 보여줘"라고 말할 필요가 없습니다.
$ARGUMENTS
명령어 뒤에 적은 말이 들어갑니다. /pr-summary 142 면 "142". 개별 인자는 $0 $1.
disable-model-invocation: true
Claude가 알아서 꺼내 쓰지 못하게 하고, 내가 입력할 때만 실행. 배포·커밋처럼 타이밍이 중요한 명령에 씁니다.
블로그 작업에 응용 — "/new-post 주제"를 입력하면 프로젝트의 sample.html 스타일로 초안을 만드는 명령어도 같은 방식으로 만들 수 있습니다. 6단계 스킬과 다른 점은 disable-model-invocation 으로 "내가 부를 때만"으로 묶어 둔다는 것뿐입니다.

3 훅의 기본 개념 — 어떤 "순간"에 걸 수 있나

훅은 이벤트(순간) + 조건(matcher) + 실행할 명령 세 가지로 이루어집니다. 자주 쓰는 이벤트는 아래와 같습니다(이 밖에도 더 있습니다).

SessionStart
세션이 시작될 때 — 개발 환경 정보를 미리 알려주기 등
UserPromptSubmit
내가 메시지를 보낸 직후, Claude가 처리하기 전
PreToolUse
★ 도구 실행 직전 — 위험한 명령 차단
PermissionRequest
권한 승인 창이 뜰 때
PostToolUse
★ 도구 실행 직후 — 자동 포맷·린트
Notification
Claude가 알림을 보낼 때(입력·승인 대기 등) — OS 알림 띄우기
Stop
Claude가 응답을 마쳤을 때 — "작업 끝" 알림
PreCompact
대화 압축(compact) 직전
SessionEnd
세션이 끝날 때 — 정리 작업
// 훅 설정의 기본 뼈대
{
  "hooks": {
    "PreToolUse": [                       // ① 이벤트
      {
        "matcher": "Bash",                // ② 어떤 도구일 때? (Bash, Edit|Write, * ...)
        "hooks": [
          { "type": "command",            // ③ 실행할 것
            "command": "실행할 셸 명령",
            "timeout": 600 }
        ]
      }
    ]
  }
}

위 뼈대의 // 뒷부분은 이해를 돕기 위한 설명입니다. JSON 파일에는 주석을 넣을 수 없으니 실제 설정에는 빼고 쓰세요.

matcher
"*" 또는 빈 값 = 전부, "Edit|Write" = 둘 중 하나, 그 밖엔 정규식. 대소문자를 구분합니다(bash 는 안 걸림).
훅이 받는 정보
표준 입력(stdin)으로 JSON이 들어옵니다. tool_name, tool_input(실행하려는 명령·파일 경로), cwd, session_id 등.

4 설정 파일은 어디에? — 위치와 우선순위

훅은 별도 파일이 아니라 settings.json 안의 "hooks" 항목에 적습니다. 어느 파일에 적느냐에 따라 적용 범위가 달라집니다.

~/.claude/settings.json
user — 내 모든 프로젝트에 적용. 알림 훅처럼 개인 취향인 것.
.claude/settings.json
project — 깃에 커밋해서 팀과 공유. 포맷·차단 규칙처럼 팀 전체가 지켜야 할 것.
.claude/settings.local.json
local — 이 프로젝트에서 나만. 커밋하지 않습니다.
우선순위 — 회사 관리 설정(managed) > 명령줄 옵션 > local > project > user 순입니다. 규칙이 겹치면 더 좁은(가까운) 쪽이 이깁니다. 회사가 정한 관리 설정은 개인이 덮어쓸 수 없습니다.

5 실습 ① 파일을 고치면 자동 포맷 PostToolUse

Claude가 파일을 수정(Edit)하거나 새로 쓸(Write) 때마다 포매터가 자동으로 돌게 합니다. 프론트엔드 프로젝트라면 prettier를 예로 들 수 있습니다.

1. 파일 열기
프로젝트의 .claude/settings.json 을 엽니다(없으면 만듭니다).
2. 훅 추가
아래 내용을 넣습니다. 이미 다른 설정이 있다면 "hooks" 부분만 합칩니다.
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '.tool_input.file_path' | xargs npx prettier --write"
          }
        ]
      }
    ]
  }
}

전체 폴더를 포맷하는 npx prettier --write . 보다, 위처럼 stdin JSON에서 방금 고친 파일 경로만 꺼내(jq) 그 파일만 포맷하면 훨씬 빠릅니다. jq 가 없다면 먼저 설치하세요.

3. 확인
Claude에게 "src/app.js 에 함수 하나 추가해줘"라고 시킨 뒤, 파일이 포맷되어 있는지 봅니다.
Java·Spring 개발자라면 — command 부분만 팀에서 쓰는 포매터로 바꾸면 됩니다. 예를 들어 빌드 도구에 포매터 플러그인이 설정되어 있다면 그 실행 명령을 넣거나, 포매터 CLI를 호출하는 작은 스크립트를 만들어 연결하세요. 빌드 전체를 돌리는 명령은 느리니 고친 파일만 처리하는 방식을 권합니다. 무엇을 넣을지 모르겠다면 Claude에게 "우리 프로젝트 빌드 설정을 보고 PostToolUse 포맷 훅 명령을 만들어줘"라고 물어보세요.

6 ★ 실습 ② 위험한 명령 차단 PreToolUse

Claude가 셸 명령을 실행하기 직전에 검사해서, 위험한 명령이면 막습니다. Oracle 같은 DB를 다루는 분이라면 특히 추천합니다.

1. 스크립트 만들기
.claude/hooks/block.sh 파일을 만들고 아래 내용을 넣습니다.
#!/bin/bash
INPUT=$(cat)
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command')
if echo "$COMMAND" | grep -q "drop table"; then
  echo "Blocked: dropping tables is not allowed" >&2
  exit 2
fi
exit 0
2. 실행 권한 주기
이걸 빼먹으면 훅이 동작하지 않습니다.
chmod +x .claude/hooks/block.sh
3. 훅 등록
.claude/settings.json 에 추가합니다. $CLAUDE_PROJECT_DIR 은 프로젝트 루트 경로로 바뀌므로 어느 폴더에서 실행해도 스크립트를 찾습니다.
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/block.sh"
          }
        ]
      }
    ]
  }
}
4. 시험
Claude에게 부탁해서 차단되는지 확인합니다.
테스트용이야. 셸에서 echo "drop table users" 를 실행해 봐.
막히면 어떤 메시지를 받았는지 알려줘.

종료 코드(exit code)의 의미

exit 0
성공 — 그대로 진행.
exit 2
★ 차단 — 도구 실행을 막고, stderr(>&2)로 쓴 메시지를 Claude에게 "이유"로 전달합니다. Claude는 그걸 보고 다른 방법을 찾습니다.
그 밖의 코드
훅 자체의 오류로 처리되고 작업은 막지 않습니다. 차단하려면 반드시 2
더 정교하게 — 위 예시는 소문자 "drop table"만 잡습니다. 실제로는 grep -qi(대소문자 무시)로 바꾸고 truncate, rm -rf 등 막을 단어를 늘리세요. 종료 코드 대신 JSON으로 permissionDecision 을 allow·deny·ask 중 하나로 돌려주는 방법도 있습니다(ask 는 나에게 확인을 받게 함).

7 실습 ③ 작업이 끝나면 알림 받기 Notification · Stop

긴 작업을 맡기고 다른 창에서 일하다 보면, Claude가 승인을 기다리는지 모를 때가 많습니다. 알림 훅을 걸어 둡니다. 개인 취향이니 user 설정(~/.claude/settings.json)에 넣는 것을 추천합니다.

예시 (Linux) — notify-send 사용

{
  "hooks": {
    "Notification": [
      { "matcher": "",
        "hooks": [ { "type": "command",
          "command": "notify-send 'Claude Code' 'Claude가 확인을 기다리고 있어요'" } ] }
    ],
    "Stop": [
      { "hooks": [ { "type": "command",
          "command": "notify-send 'Claude Code' '작업이 끝났어요'" } ] }
    ]
  }
}
# 예시 (macOS) — command 부분만 바꿔 넣기
osascript -e 'display notification "작업이 끝났어요" with title "Claude Code"'
예시일 뿐입니다 — 알림 명령은 운영체제마다 다릅니다(Windows는 또 다른 방법이 필요). 내 환경에 맞는 명령을 모르겠다면 "내 OS에서 알림을 띄우는 Notification 훅을 만들어줘"라고 Claude에게 물어보세요. 소리를 내거나 메신저 웹훅으로 보내는 것도 가능합니다.

8 확인하기와 주의사항

/hooks
지금 적용된 훅을 이벤트별로 보여주는 읽기 전용 화면입니다. 수정은 settings.json 파일을 직접 고쳐야 합니다.
"disableAllHooks": true
settings.json에 넣으면 훅을 한꺼번에 끕니다. 뭔가 이상할 때 원인이 훅인지 가려내는 용도로 좋습니다.

꼭 기억할 3가지

내 권한으로 실행
훅은 Claude가 아니라 내 컴퓨터에서 내 계정 권한으로 도는 셸 명령입니다. 승인 창도 없이 실행되므로, 잘못 쓰면 파일이 지워질 수도 있습니다.
복붙 전 검토
블로그·깃허브에서 가져온 훅(이 글 포함!)은 명령이 무슨 일을 하는지 이해한 뒤 넣으세요. 모르면 Claude에게 "이 훅이 뭘 하는지 설명해줘"부터.
무한 루프 조심
예를 들어 Stop 훅이 매번 "아직 끝내지 마"라고 막으면 Claude가 멈추지 못하고 계속 돕니다. 훅이 또 다른 훅을 부르는 구조도 피하세요. 이상하면 disableAllHooks 로 바로 끄기.

9 정리 & 체크리스트

명령어는 "부를 때", 훅은 "그 순간 무조건". 아래를 모두 해봤다면 8단계 완료입니다.

☐ 차이 이해
명령어(부탁)와 훅(규칙)의 차이를 예를 들어 설명할 수 있다
☐ 명령어
.claude/skills/pr-summary/SKILL.md 를 만들어 /pr-summary 를 실행해 봤다
☐ 자동 포맷
PostToolUse 훅으로 파일 수정 후 포매터가 도는 것을 확인했다
☐ 위험 명령 차단
★ PreToolUse 스크립트로 차단되는 것을 보고, exit 2 의 의미를 이해했다
☐ 알림
내 OS에 맞는 Notification·Stop 알림 훅을 user 설정에 넣었다
☐ 점검 습관
/hooks 로 적용 상태를 보고, 문제 시 disableAllHooks 로 끄는 법을 안다
여기서 만든 명령어와 훅은 7단계 플러그인의 skills/ 와 hooks/hooks.json 에 넣어 팀에 그대로 배포할 수 있습니다. 다음 단계에서는 플러그인의 마지막 부품, 서브에이전트를 만듭니다.
이전 글: 심화 7단계 플러그인과 마켓플레이스 · 다음 글: 심화 9단계 서브에이전트 — AI 팀 꾸리기
공식 문서: 훅 시작하기 · 훅 레퍼런스 · 스킬(명령어) · 설정 파일

+ Recent posts