-
[Claude Code] 작업 완료 시 윈도우 알림 받기 (PowerShell Hook)[참고자료] 2026. 7. 2. 22:48
Claude Code로 오래 걸리는 작업을 시키고 나서, 언제 끝났는지 몰라 계속 화면을 들여다본 적 있으신가요? 혹은 권한 확인이 필요한 순간을 놓쳐서 세션이 그냥 멈춰 있던 적은요?
이 글에서는 Claude Code의 Hooks(후크) 기능을 이용해서, 작업이 끝나거나(Stop) Claude가 사용자 확인을 요청할 때(Notification) 윈도우 알림(토스트)을 띄워주는 PowerShell 스크립트를 만들고 적용하는 방법을 정리합니다.
이 가이드에서 하는 일
- Claude Code의 Stop, Notification 이벤트가 발생하면
- PowerShell 스크립트가 해당 이벤트 정보를 받아 한 문장으로 요약하고
- 윈도우 알림 창(토스트)으로 띄워줍니다
구조는 이렇습니다.
Claude Code 이벤트 (Stop / Notification) │ (JSON을 표준입력으로 전달) ▼ notify-claude.ps1 ← 이벤트 파싱 + 메시지 요약 │ ▼ auto-notification.ps1 ← 실제 윈도우 알림 표시 │ ▼ 화면 우측 하단 토스트 알림역할을 나눠둔 이유는 단순합니다. auto-notification.ps1은 "제목/내용을 받아서 알림만 띄우는" 범용 스크립트로 두고, notify-claude.ps1은 "Claude Code가 보내는 JSON을 해석해서 알림에 필요한 값을 만드는" 역할만 하도록 분리한 것입니다. 이렇게 하면 나중에 다른 곳(예: 다른 자동화 스크립트)에서도 auto-notification.ps1을 재사용할 수 있습니다.
사전 준비물
- Windows 10/11
- Claude Code CLI가 설치되어 있고, 실행 가능한 상태
- PowerShell (Windows 기본 내장 powershell.exe로 충분합니다)
1단계. 스크립트 두 개 준비하기
1-1. auto-notification.ps1 — 실제 알림을 띄우는 스크립트
System.Windows.Forms의 NotifyIcon을 이용해 트레이 풍선 알림(윈도우에서는 자동으로 토스트 알림으로 변환되어 표시됩니다)을 띄우는 범용 스크립트입니다. 제목, 메시지, 유지 시간을 파라미터로 받습니다.
# Windows notification via NotifyIcon balloon tip (auto-converted to a toast by Windows) param( [string]$Title = "Claude Code", [string]$Message = "Task completed", [int]$Duration = 15 ) Add-Type -AssemblyName System.Windows.Forms $icon = New-Object System.Windows.Forms.NotifyIcon $icon.Icon = [System.Drawing.SystemIcons]::Information $icon.Visible = $true $icon.BalloonTipTitle = $Title $icon.BalloonTipText = $Message $icon.ShowBalloonTip($Duration * 1000) # Keep the tray icon alive long enough for Windows to display and queue the notification Start-Sleep -Seconds ($Duration + 1) $icon.Dispose()1-2. notify-claude.ps1 — Claude Code 후크 진입점
Claude Code는 후크가 실행될 때 이벤트 정보를 JSON 형태로 표준입력(stdin) 에 실어서 넘겨줍니다. 이 스크립트는 그 JSON을 읽어서:
- Notification 이벤트면 Claude Code가 제공한 message 값을 그대로 사용하고
- Stop 이벤트라 message가 따로 없으면 transcript_path(대화 로그 파일)를 열어 Claude의 마지막 응답 텍스트를 가져온 뒤
- 너무 길면 첫 문장 또는 80자 내외로 잘라 요약하고
- 최종적으로 auto-notification.ps1을 호출해 알림을 띄웁니다.
# Reads a Claude Code hook payload from stdin and shows a Windows notification. # Stop event: summarizes Claude's last message from the transcript. # Notification event: uses the message Claude Code provides directly. $stdinStream = [Console]::OpenStandardInput() $reader = New-Object System.IO.StreamReader($stdinStream, [System.Text.Encoding]::UTF8) $raw = $reader.ReadToEnd() $hookInput = $null try { $hookInput = $raw | ConvertFrom-Json } catch {} $eventName = $hookInput.hook_event_name $summary = $hookInput.message if (-not $summary) { $transcriptPath = $hookInput.transcript_path if ($transcriptPath -and (Test-Path $transcriptPath)) { $lines = [System.IO.File]::ReadAllLines($transcriptPath, [System.Text.Encoding]::UTF8) for ($i = $lines.Count - 1; $i -ge 0; $i--) { $entry = $null try { $entry = $lines[$i] | ConvertFrom-Json } catch { continue } if ($entry.type -eq "assistant" -and $entry.message.content) { $textParts = @($entry.message.content | Where-Object { $_.type -eq "text" } | ForEach-Object { $_.text }) if ($textParts.Count -gt 0) { $summary = ($textParts -join " ").Trim() break } } } } } if (-not $summary) { $summary = "작업이 완료되었습니다." } # Shorten to a one-sentence summary instead of dumping the whole message $normalized = ($summary -replace '\s+', ' ').Trim() $window = if ($normalized.Length -gt 150) { $normalized.Substring(0, 150) } else { $normalized } $sentenceMatch = [regex]::Match($window, '^.*?[\.!?]') if ($sentenceMatch.Success -and $sentenceMatch.Value.Length -ge 5) { $summary = $sentenceMatch.Value.Trim() } elseif ($normalized.Length -gt 80) { $cut = $normalized.Substring(0, 80) $lastSpace = $cut.LastIndexOf(' ') if ($lastSpace -gt 20) { $cut = $cut.Substring(0, $lastSpace) } $summary = $cut + "..." } else { $summary = $normalized } $title = if ($eventName -eq "Notification") { "Claude 확인 필요" } else { "Claude 작업 완료" } & "C:\Users\user\bin\auto-notification.ps1" -Title $title -Message $summary⚠️ 주의: 맨 마지막 줄의 C:\Users\user\bin\auto-notification.ps1 경로는 예시입니다. 아래 2단계에서 실제로 스크립트를 저장할 경로에 맞게 반드시 수정해야 합니다.
2단계. 스크립트를 저장할 위치
두 파일을 저장할 전용 폴더를 하나 만드는 것을 추천합니다. 예를 들어:
C:\Users\<사용자명>\bin\- 위 경로로 폴더가 없다면 새로 만듭니다.
- auto-notification.ps1, notify-claude.ps1 두 파일을 이 폴더에 저장합니다.
- notify-claude.ps1 맨 아래 줄의 경로를 실제 저장 경로로 맞춰줍니다.
& "C:\Users\<사용자명>\bin\auto-notification.ps1" -Title $title -Message $summary💡 꼭 bin 폴더일 필요는 없습니다. C:\Users\<사용자명>\.claude\hooks\ 처럼 Claude 설정 폴더 아래에 두는 것도 흔한 방식입니다. 어디에 두든 두 파일의 경로가 서로 일치하기만 하면 됩니다.
PowerShell 실행 정책 확인 (선택)
스크립트를 더블클릭하거나 터미널에서 직접 실행해서 테스트하려는 경우, 실행 정책 때문에 막힐 수 있습니다. 이 문제가 발생하면 PowerShell(관리자 권한 필요 없음, 현재 사용자 범위)에서 아래 명령을 한 번 실행해두면 됩니다.
Set-ExecutionPolicy -Scope CurrentUser RemoteSigned뒤에서 Claude Code 후크에 등록할 때는 -ExecutionPolicy Bypass 옵션을 명령어에 직접 넣을 것이므로, 이 설정을 건너뛰어도 후크 자체는 정상 동작합니다. 스크립트를 수동으로 테스트해볼 때만 필요합니다.
3단계. Claude Code 설정 파일에 후크 등록하기
Claude Code의 후크는 settings.json 파일에 등록합니다. 적용 범위에 따라 위치가 다릅니다.
범위 경로 설명
전역(사용자 전체) C:\Users\<사용자명>\.claude\settings.json 모든 프로젝트에 공통 적용 프로젝트 단위 <프로젝트 폴더>\.claude\settings.json 해당 프로젝트에서만 적용, 팀과 공유 가능 개인 로컬 오버라이드 <프로젝트 폴더>\.claude\settings.local.json 커밋하지 않는 개인 설정 특별한 이유가 없다면 전역 설정(C:\Users\<사용자명>\.claude\settings.json)에 등록해서 어떤 프로젝트에서 작업하든 알림이 뜨도록 하는 것을 추천합니다. 파일이 없다면 새로 만들면 됩니다.
파일 안에 아래처럼 hooks 항목을 추가합니다. 이미 다른 설정이 있다면 hooks 키만 병합해서 넣어주세요.
{ "hooks": { "Stop": [ { "hooks": [ { "type": "command", "command": "powershell -NoProfile -ExecutionPolicy Bypass -File \"C:\\Users\\<사용자명>\\bin\\notify-claude.ps1\"" } ] } ], "Notification": [ { "hooks": [ { "type": "command", "command": "powershell -NoProfile -ExecutionPolicy Bypass -File \"C:\\Users\\<사용자명>\\bin\\notify-claude.ps1\"" } ] } ] } }- Stop : Claude Code가 응답(작업)을 끝냈을 때 발생
- Notification : Claude Code가 사용자의 확인/입력을 필요로 할 때 발생 (권한 승인 대기 등)
두 이벤트 모두 같은 notify-claude.ps1을 호출하도록 했고, 스크립트 내부에서 hook_event_name 값을 보고 알림 제목을 다르게("Claude 작업 완료" / "Claude 확인 필요") 표시합니다.
📌 JSON 안에서 윈도우 경로를 쓸 때는 백슬래시(\)를 두 번(\\)씩 써야 이스케이프 오류가 나지 않습니다.
4단계. 적용 및 테스트
- settings.json을 저장합니다.
- 이미 실행 중이던 Claude Code 세션이 있다면 종료 후 다시 시작합니다.
- Claude Code에게 시간이 좀 걸리는 작업을 하나 시켜보고, 응답이 끝나는 시점에 화면 우측 하단에 알림이 뜨는지 확인합니다.
- 권한 승인이 필요한 작업(예: 파일 쓰기 등)을 시켜서 Notification 알림도 함께 확인합니다.
알림이 뜨지 않는다면, PowerShell에서 아래처럼 직접 JSON을 넣어 스크립트만 단독으로 테스트해볼 수 있습니다.
'{"hook_event_name":"Stop","message":"이것은 테스트 알림입니다."}' | powershell -NoProfile -ExecutionPolicy Bypass -File "C:\Users\<사용자명>\bin\notify-claude.ps1"이 명령을 실행했을 때 알림이 뜬다면 스크립트 자체는 정상이고, Claude Code 쪽 settings.json 경로나 문법을 다시 확인하면 됩니다.
보너스: 알림에 소리 추가하기
기본 상태에서는 무음이거나 윈도우 기본 알림음 정도만 납니다. auto-notification.ps1에 사운드 재생 코드를 추가하면 알림이 뜰 때 소리도 함께 낼 수 있습니다.
방법 1. 윈도우 기본 사운드 파일 재생
윈도우에는 C:\Windows\Media\ 폴더에 기본 알림음(.wav)들이 이미 들어있습니다. System.Media.SoundPlayer로 재생하면 됩니다.
param( [string]$Title = "Claude Code", [string]$Message = "Task completed", [int]$Duration = 15, [string]$SoundPath = "C:\Windows\Media\Notify.wav" ) Add-Type -AssemblyName System.Windows.Forms # 알림음 재생 (파일이 없으면 조용히 건너뜀) if (Test-Path $SoundPath) { try { (New-Object System.Media.SoundPlayer $SoundPath).Play() } catch {} } $icon = New-Object System.Windows.Forms.NotifyIcon $icon.Icon = [System.Drawing.SystemIcons]::Information $icon.Visible = $true $icon.BalloonTipTitle = $Title $icon.BalloonTipText = $Message $icon.ShowBalloonTip($Duration * 1000) Start-Sleep -Seconds ($Duration + 1) $icon.Dispose()C:\Windows\Media\ 폴더를 탐색기로 열어보면 Notify.wav, chimes.wav, ring05.wav 등 다양한 사운드가 있으니 원하는 파일로 $SoundPath만 바꿔주면 됩니다.
방법 2. 간단한 비프음 (파일 없이)
사운드 파일 없이 간단하게 삑 소리만 내고 싶다면 Console.Beep을 사용할 수 있습니다.
[console]::beep(800, 300) # 800Hz, 0.3초이 한 줄을 auto-notification.ps1의 $icon.ShowBalloonTip(...) 호출 앞뒤 어디에 넣어도 됩니다.
방법 3. 이벤트별로 다른 소리 내기
작업 완료(Stop)와 확인 필요(Notification)를 소리로도 구분하고 싶다면, notify-claude.ps1에서 auto-notification.ps1을 호출할 때 -SoundPath를 이벤트별로 다르게 넘겨주면 됩니다.
$soundPath = if ($eventName -eq "Notification") { "C:\Windows\Media\Windows Notify Calendar.wav" } else { "C:\Windows\Media\Notify.wav" } & "C:\Users\<사용자명>\bin\auto-notification.ps1" -Title $title -Message $summary -SoundPath $soundPath트러블슈팅 체크리스트
- 알림 자체가 안 뜬다 → PowerShell 실행 정책 문제일 수 있습니다. 후크 명령에 -ExecutionPolicy Bypass가 들어있는지 확인하세요.
- "경로를 찾을 수 없습니다" 오류 → notify-claude.ps1 안의 auto-notification.ps1 경로, 그리고 settings.json에 적은 notify-claude.ps1 경로가 실제 저장 위치와 정확히 일치하는지 확인하세요.
- 한글이 깨져서 표시된다 → 두 스크립트 파일을 저장할 때 인코딩을 UTF-8로 저장했는지 확인하세요 (메모장 기준 "UTF-8" 또는 "UTF-8 BOM 포함").
- 알림은 뜨는데 내용이 너무 길거나 이상하다 → notify-claude.ps1의 요약 로직(문장 단위 자르기)을 원하는 길이/방식으로 조정하면 됩니다.
- 소리가 안 난다 → $SoundPath로 지정한 .wav 파일이 실제로 그 경로에 존재하는지 탐색기에서 확인하세요.
마무리
이렇게 하면 Claude Code가 작업을 끝내거나 사용자 확인이 필요할 때마다 윈도우 알림으로 바로 알 수 있어서, 다른 작업을 하다가도 놓치지 않고 대응할 수 있습니다. 후크는 Stop, Notification 외에도 PreToolUse, PostToolUse, SessionStart 등 다양한 이벤트를 지원하므로, 같은 패턴으로 슬랙 알림, 로그 기록, 자동 포맷팅 등으로 얼마든지 확장할 수 있습니다.
더 자세한 이벤트 종류와 설정 옵션은 Claude Code 공식 문서의 Hooks 레퍼런스를 참고하세요.
'[참고자료]' 카테고리의 다른 글
[Git & Github] PR(Pull Request) 문서 작성 요령 (0) 2026.06.23 [Git & Github] branch 관련 명령어 정리 (0) 2026.06.23 GitHub 레포지토리 클론 (0) 2026.06.02 Git & GitHub 연동 및 SSH 설정 종합 가이드 (1) 2026.05.26