DevClaude Code자동화

Claude Code Hooks로 자동화하는 워크플로우 7가지

2026.04.13

매번 같은 말을 반복하는 게 지겨워졌다

"커밋 전에 lint 한 번 돌려줘", "긴 작업 끝나면 알림 보내줘", "파일 수정하면 prettier 돌려줘". 작업할 때마다 같은 부탁을 하고 있는 나를 발견한 게 시작이었다.

Claude Code Hooks는 이런 부탁을 명시적인 규칙으로 박아두는 시스템이다. 특정 이벤트(파일 수정, 도구 호출, 세션 시작 등)가 발생할 때 자동으로 쉘 명령을 실행한다. 한 번 설정하면 잊고 살 수 있다.

이 글은 내가 실제로 settings.json에 박아둔 7가지 훅이다.

Hook의 기본 구조

훅은 ~/.claude/settings.json 또는 프로젝트의 .claude/settings.json에 정의한다.

{
  "hooks": {
    "<event-name>": [
      {
        "matcher": "<tool-or-path-pattern>",
        "hooks": [
          { "type": "command", "command": "<shell-command>" }
        ]
      }
    ]
  }
}

이벤트 이름은 정해져 있다. PreToolUse, PostToolUse, SessionStart, UserPromptSubmit, Stop 등이다. matcher는 어떤 도구나 경로에 적용할지 필터다.

1. 파일 수정 후 자동 prettier

Edit, Write 도구로 코드 파일이 수정되면 prettier를 돌린다.

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "f=$(jq -r '.tool_input.file_path'); if echo \"$f\" | grep -E '\\.(ts|tsx|js|jsx)$' > /dev/null; then npx prettier --write \"$f\" 2>/dev/null; fi"
          }
        ]
      }
    ]
  }
}

훅은 stdin으로 JSON을 받는다. jq -r '.tool_input.file_path'로 수정된 파일 경로를 꺼낸다. 확장자가 JS/TS 계열일 때만 prettier를 돌린다. 효과는 즉시 체감된다 — AI가 만든 코드가 항상 컨벤션에 맞춰 정렬된 채로 들어온다.

2. 위험한 명령어 차단

PreToolUse로 Bash 호출을 검사해서 위험한 명령을 막는다.

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "if jq -r '.tool_input.command' | grep -E '(rm -rf /|--no-verify|push --force.*main)' > /dev/null; then echo 'BLOCKED: dangerous command'; exit 2; fi"
          }
        ]
      }
    ]
  }
}

PreToolUse 훅이 종료 코드 2를 반환하면 도구 실행이 차단되고, stderr 메시지가 Claude에게 전달된다. 메인 브랜치 force push, 시스템 루트 삭제, hooks 우회 같은 패턴을 미리 잡는다. AI가 막힌다는 걸 알면 다른 방법을 찾는다.

3. 세션 시작 시 컨텍스트 주입

SessionStart 훅으로 매 세션마다 자동으로 환경 정보를 추가한다.

{
  "hooks": {
    "SessionStart": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "echo \"[ENV] node=$(node -v) | branch=$(git branch --show-current 2>/dev/null) | last-commit=$(git log -1 --format=%s 2>/dev/null)\""
          }
        ]
      }
    ]
  }
}

훅의 stdout이 시스템 메시지로 Claude에게 전달된다. 매번 "지금 브랜치가 뭐야?"를 물어볼 필요가 없다. 이미 컨텍스트에 있다.

4. 긴 작업 끝나면 데스크탑 알림

Stop 훅으로 응답이 끝날 때 macOS 알림을 띄운다.

{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "osascript -e 'display notification \"Task complete\" with title \"Claude Code\" sound name \"Glass\"'"
          }
        ]
      }
    ]
  }
}

AI가 5분짜리 작업을 하는 동안 다른 일을 하다가, 알림이 뜨면 돌아오면 된다. Linux면 notify-send, Windows는 PowerShell BurntToast로 바꾸면 된다.

5. 커밋 전 자동 테스트

PreToolUsegit commit Bash 호출을 가로채 테스트를 먼저 돌린다.

{
  "matcher": "Bash",
  "hooks": [
    {
      "type": "command",
      "command": "if jq -r '.tool_input.command' | grep -E 'git commit' > /dev/null; then npm test --silent || (echo 'Tests failed'; exit 2); fi"
    }
  ]
}

테스트가 깨지면 커밋이 차단된다. AI가 "테스트는 다음에"를 못 하게 막는 강제 장치다. CI에서 잡힐 깨진 커밋을 로컬에서 미리 거른다.

6. 사용자 프롬프트에 자동 라벨 붙이기

UserPromptSubmit 훅으로 입력에 메타데이터를 붙인다.

{
  "hooks": {
    "UserPromptSubmit": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "echo \"[date=$(date +%F) | cwd=$(pwd | xargs basename)]\""
          }
        ]
      }
    ]
  }
}

훅의 stdout이 사용자 입력 앞에 추가 컨텍스트로 붙는다. 날짜와 작업 디렉토리를 매번 자동 주입하니까, "지금 날짜를 모르는 AI" 문제가 사라진다.

7. PostToolUse로 Notion에 작업 로그 적재

길게 협업하는 프로젝트에서는 어떤 변경이 있었는지 기록이 필요하다. PostToolUse에서 변경 정보를 외부로 보낸다.

{
  "matcher": "Edit|Write",
  "hooks": [
    {
      "type": "command",
      "command": "f=$(jq -r '.tool_input.file_path'); curl -s -X POST https://my-logger.internal/log -H 'Content-Type: application/json' -d \"{\\\"file\\\":\\\"$f\\\",\\\"ts\\\":\\\"$(date +%s)\\\"}\" || true"
    }
  ]
}

|| true를 붙여서 외부 서버가 죽어도 작업이 멈추지 않게 한다. 훅의 실패가 작업 자체를 막으면 안 되는 케이스다.

훅 디버깅 팁

훅을 처음 짜면 안 동작하는 경우가 절반이다. 내가 만난 흔한 실수들이다.

settings.json은 strict JSON

주석을 못 단다. 마지막 콤마(trailing comma)도 안 된다. 한 글자 틀리면 통째로 무시된다. cat ~/.claude/settings.json | jq .으로 일단 파싱이 되는지 확인한다.

stdin JSON 필드 이름 정확히

훅 입력 데이터는 환경변수가 아니라 stdin으로 들어오는 JSON이다. tool_name, tool_input.file_path, tool_input.command 같은 필드를 jq로 꺼내 쓴다. $CLAUDE_PROJECT_DIR 정도가 모든 훅에서 쓸 수 있는 환경변수다. 어떤 이벤트에서 어떤 필드가 들어오는지는 공식 문서에서 확인한다.

훅이 stdin/stdout을 막으면 안 된다

대화형 명령(vim, read 등)을 훅에 박으면 Claude Code가 멈춘다. 훅은 항상 비대화형, 빠르게 끝나야 한다. 오래 걸리는 작업은 &로 백그라운드 처리하거나, 별도 큐에 넣는다.

훅 실행 로그

문제 진단할 때는 훅 안에서 stderr로 디버그 로그를 남긴다.

echo "[hook] file=$(jq -r '.tool_input.file_path') ts=$(date)" >&2

stderr는 사용자에게 보이지 않지만, Claude Code 로그에는 남는다.

정리

Hooks는 작은 시스템이지만 효과가 크다. 하루에 같은 부탁을 5번 하고 있다면, 그건 훅 후보다. 한 번 박아두면 그 부탁을 다시는 안 해도 된다.

내가 추천하는 시작점은 PostToolUse + prettier 하나다. 효과가 즉각적이라 훅이 무엇을 하는지 감이 빠르게 잡힌다. 거기서부터 알림, 차단, 컨텍스트 주입 순서로 늘려가면 된다.

설정 파일 한 개에 자동화가 박혀 있으니, 새 컴퓨터로 옮길 때도 그 파일만 복사하면 끝이다. dotfiles에 settings.json을 넣어둔 다음부터, 환경 세팅이 분 단위로 짧아졌다.