카테고리 없음

클로드 코드 텔레그램 연동 · claude code telegram notification: Notification 훅에 sendMessage 한 번, 부르는 건 승인이 필요할 때만

코드짜는아빠 2026. 10. 20. 10:19

필요한 건 셋: 봇 토큰, 알림을 받을 대화의 chat_id, Claude Code 설정 파일의 Notification 훅 한 블록. Claude Code는 입력이나 권한 승인을 기다릴 때 알림을 보내고, 그때 Notification 훅이 돈다. 훅이 부르는 스크립트는 텔레그램 Bot API sendMessage 한 번이면 끝. matcher 에 permission_prompt 를 적으면 도구 사용 승인을 기다릴 때만 보낸다. 남는 건 어느 순간에 부르게 하느냐인데, 우리는 승인이 필요한 순간에만 보내고 일반 승인 요청의 답은 텔레그램 답장이 아니라 작업하던 채팅에서 받는다. 출처는 Claude Code 훅 문서 · 훅 안내 · 채널 문서 · Telegram Bot API · 봇 기능 문서, 모두 2026-10-20 조회.

1단계: BotFather 에서 봇을 만들고 토큰을 받는다

텔레그램에서 BotFather 를 열고 /newbot 을 보낸다. 표시 이름과 bot 으로 끝나는 사용자명을 정하면 토큰이 나온다. 봇 기능 문서의 경고 한 줄: 「토큰은 안전하게 보관하라. 누구든 그 토큰으로 봇을 조종할 수 있다.」 잃어버렸거나 샌 것 같으면 BotFather 의 /token 으로 새로 만든다. 그래서 아래 예시는 토큰을 설정 파일이나 스크립트 본문에 적지 않고, 나만 읽을 수 있는 파일 하나에 따로 둔다.

mkdir -p ~/.config
[ -e ~/.config/notify-telegram.conf ] || install -m 600 /dev/null ~/.config/notify-telegram.conf

파일은 권한부터 600 으로 만들고, 값은 편집기로 넣을 것. echo 로 넣으면 토큰이 셸 기록에 남는다.

# ~/.config/notify-telegram.conf  (권한 600)
BOT_TOKEN='<BOT_TOKEN>'
CHAT_ID='<CHAT_ID>'   # 2단계에서 찾은 숫자로 바꾼다

값은 꺾쇠까지 지우고 작은따옴표 안에 넣는다.

2단계: 봇에게 한 번 말을 걸고 getUpdates 로 chat_id 를 찾는다

chat_id 를 알아내는 한 가지 방법은 봇에게 아무 메시지나 한 번 보낸 뒤 getUpdates 를 부르는 것.

source ~/.config/notify-telegram.conf   # 이 단계에선 BOT_TOKEN 만 진짜 값으로 바꾼 상태
curl -sS -K <(printf 'url = "https://api.telegram.org/bot%s/getUpdates"\n' "$BOT_TOKEN") \
  | jq '.result[].message.chat.id'

나온 숫자가 그 대화의 chat_id. getUpdates 는 봇에 웹훅이 걸려 있으면 동작하지 않고, 업데이트는 24시간을 넘겨 보관되지 않는다. 이 숫자도 토큰처럼 글이나 캡처에 올리지 말 것.

3단계: 훅이 부를 스크립트 — sendMessage 한 번

훅은 표준 입력으로 JSON 을 받는다. Notification 이면 공통 필드에 더해 알림 문구 message, 있을 때만 오는 title, 어떤 종류인지 알려 주는 notification_type 이 들어온다. 이 중 종류와 문구만 꺼내 보내는 예시.

#!/bin/bash
# ~/.claude/hooks/notify-telegram.sh
set -euo pipefail
source "$HOME/.config/notify-telegram.conf"

INPUT=$(cat)
TYPE=$(jq -r '.notification_type // "unknown"' <<< "$INPUT")
MSG=$(jq -r '.message // ""' <<< "$INPUT")

curl -sS -o /dev/null \
  -K <(printf 'url = "https://api.telegram.org/bot%s/sendMessage"\n' "$BOT_TOKEN") \
  --data-urlencode "chat_id=${CHAT_ID}" \
  --data-urlencode "text=[Claude Code] ${TYPE}: ${MSG}"

토큰이 든 주소는 명령줄 인자 대신 curl 설정(-K)으로 넘겼다. 입력에 같이 오는 작업 폴더(cwd)나 대화 기록 경로(transcript_path)는 일부러 보내지 않는다. 알림 문구는 텔레그램 서버를 거쳐 가니까.

4단계: settings.json 의 Notification 훅에 건다 (2026-10-20 공식 문서 기준)

스크립트에 실행 권한(chmod +x, 5단계)을 주고, 사용자 설정 ~/.claude/settings.json 의 hooks 안에 Notification 을 더한다.

{
  "hooks": {
    "Notification": [
      {
        "matcher": "permission_prompt",
        "hooks": [
          {
            "type": "command",
            "command": "\"$HOME\"/.claude/hooks/notify-telegram.sh",
            "timeout": 10
          }
        ]
      }
    ]
  }
}

이미 hooks 가 있다면 통째로 바꾸지 말고 Notification 을 옆 키로 더한다. 공식 안내 그대로. matcher 를 비우면 모든 알림 종류에 돈다. 공식 표에는 열두 가지가 있고, 이 글에 닿는 건 이 셋이다.

matcher 언제 도나(공식 문서)
permission_prompt 도구 사용이나 샌드박스 명령의 네트워크 요청을 승인해야 하고, 승인 창이 6초쯤 기다렸을 때
idle_prompt Claude가 응답을 마치고 60초쯤 지났는데 입력이 없을 때
agent_needs_input 에이전트 뷰가 열려 있는 동안 백그라운드 세션이 입력을 기다리기 시작할 때

timeout 은 초 단위. 명령형 훅의 기본값은 600초라, 알림 하나에 그만큼 기다릴 이유가 없어 10초로 줄였다. 스크립트 경로는 공식 보안 권고대로 절대 경로로 적었고, 셸 형태라 큰따옴표로 감쌌다. 훅은 내 사용자 권한 그대로 도니까, 남이 준 스크립트는 읽어 보고 넣을 것. 대화형 세션에서는 그 폴더의 작업 공간 신뢰 창을 받아들이기 전까지 사용자 설정의 훅도 돌지 않는다. Notification 훅은 알림을 막거나 바꾸지 못하고, 문서도 바깥 서비스로 알림을 넘기는 용도라고 적는다.

5단계: /hooks 로 확인하고 시험 메시지를 보낸다

Claude Code 프롬프트에서 /hooks 를 치면 Notification 아래에 방금 넣은 훅이 보여야 정상. 안 보이면 JSON 끝의 쉼표나 주석부터. 스크립트만 따로 시험하려면 예시 JSON 을 넣어 돌려 본다.

chmod +x ~/.claude/hooks/notify-telegram.sh
echo '{"notification_type":"permission_prompt","message":"Claude needs your permission"}' \
  | ~/.claude/hooks/notify-telegram.sh
echo $?

텔레그램에 메시지가 오고 종료 코드가 0 이면 스크립트 쪽은 된 셈. 끝으로 공식 안내의 시험 순서대로 Shift+Tab 을 눌러 상태 줄에 manual mode on 이 보이게 하고, 권한이 필요한 일을 시킨 뒤 터미널에서 다른 창으로 옮겨 본다. 승인 창이 6초쯤 기다리면 알림이 와야 한다. 자판을 칠 때마다 6초가 뒤로 밀리니, 손을 떼고 기다릴 것.

언제 부르게 했나: 승인이 필요한 순간에만, 답은 채팅으로

여기부터는 우리가 정한 기준. 승인 알림은 사람이 정해야 하는 일에만 보낸다. 밖으로 나가는 실행(게시 · 배포 · 발송 같은 것), 되돌리기 어렵거나 위험이 큰 선택, 범위가 넓어지는 일, 돈 · 고객 · 법 · 보안 결정, 최종 디자인 선택, 정해 둔 기준으로 못 푸는 막힘. 구현 세부, 테스트 고치기, 로컬 검증, 이미 승인된 범위 안에서 되돌릴 수 있는 선택은 알리지 않기로 했다.

알림은 알림일 뿐, 승인이 아니다. 알림이 그 일을 대신 실행하지 않고, 비밀을 담지 않고, 나 말고 다른 곳으로 가지 않는다. Claude Code 훅으로 옮기면 이 기준에 가장 가까운 건 permission_prompt. idle_prompt 는 응답이 끝날 때마다 걸릴 수 있어 이 기준보다 넓다.

답장까지 텔레그램에서 하고 싶다면 공식 기능으로 Channels 가 있다. 실행 중인 세션에 텔레그램 메시지를 넣고 Claude가 같은 대화로 답하는 플러그인 방식이고, 2026-10-20 기준 연구 미리보기. 권한 승인을 채널로 넘기는 경우에 대해 채널 문서는 「채널로 답할 수 있는 사람은 누구나 세션의 도구 사용을 승인하거나 거부할 수 있다」고 적고, 그 권한을 맡길 만한 사람만 허용 목록에 넣으라고 한다. 우리 쪽 일반 승인 요청은 아래 상자의 이유로 답을 채팅에서 받는다.

실제로 겪은 일

우리 승인 요청 알림은 원래 텔레그램 답장으로도 승인을 받게 짜여 있었다. 10월 1일, 8월 1일부터 두 달 치 운영 로그를 다시 보니 승인 요청 알림은 162건 나갔는데 일반 승인 요청에 대한 텔레그램 답장이 기록된 적은 한 번도 없었다. 그동안 실제 승인은 전부 채팅에서 했고, 일이 멈춘 적도 없다. 답장을 읽는 프로그램 둘이 같은 봇에서 따로 업데이트를 받아 가며 서로의 업데이트를 지우고 있었던 것도 그때 드러났다. 그날 나는 「알림만 · 답은 채팅」을 골랐고, 알림 문구에는 「텔레그램 답장은 기록되지 않습니다. 답은 채팅으로 주세요.」가 들어갔다.

내 설정 점검표: 클로드 코드 텔레그램 알림

  1. 토큰과 chat_id 가 settings.json · 스크립트 본문 · 저장소에 들어가 있지 않나. 나만 읽는 파일 하나에 따로 뒀나.
  2. 토큰이 든 주소가 명령줄 인자로 넘어가지 않나.
  3. matcher 가 정말 알림을 받고 싶은 종류인가. 비워 두면 모든 종류에 돈다.
  4. 알림 문구에 작업 폴더 경로 · 대화 기록 경로 · 비밀이 섞이지 않나.
  5. /hooks 에 Notification 훅이 보이나. 시험 JSON 으로 돌렸을 때 텔레그램에 메시지가 오고 종료 코드가 0 인가(curl 은 텔레그램이 오류를 돌려줘도 0 으로 끝난다).
  6. 같은 봇에서 getUpdates 로 답장을 읽는 프로그램이 둘 이상 돌고 있지 않나. 더 큰 offset 으로 부르는 순간 그 앞 업데이트는 확인된 것으로 치고 잊힌다.
  7. 텔레그램 답장을 승인으로 쓸 생각이라면, 그 답장이 어디에 기록되는지부터 확인했나.

같이 읽을 글

다음 글은 클로드 코드 MCP 연결 · 설정. Claude Code에 MCP 서버를 붙이고 설정하는 방법을 다룬다.

다음에 다뤘으면 하는 질문은 댓글로 남기거나 codenara.contact@gmail.com 으로 보내 주세요. 받은 질문은 다음 글감으로 씁니다.