에디블로그
Engineer's Field Notes

AI 자동화로 매일
한 편씩 쓰는
엔지니어 운영 노트

Claude Code · 자동화 파이프라인 · 사고 회고까지. 잘 굴러간 기록 + 깨진 흔적도 같이 남깁니다.

사람이 할 수 있는 일은,
AI도 할 수 있어야 합니다.
매일 한 편 쓰면서 검증 중.
— 이번 주 가장 많이 읽힌 글 TOP 3
AI/꿀팁

[Claude Code] 폰에서 텔레그램 한 줄로 맥을 조종하게 된 이야기

반응형
[Claude Code] 폰에서 텔레그램 한 줄로 맥을 조종하게 된 이야기

EDIBLOG · AI 꿀팁 · 2026.05.28

[Claude Code] 폰에서 텔레그램 한 줄로 맥을 조종하게 된 이야기

저는 출퇴근 중에도 끊임없이 아이디어 구상을 해서 제가 구축해놓은 시스템에 실시간으로 반영하길 원했어요. 그래서 텔레그램 봇 하나로 폰에서 맥의 Claude Code를 부르는 환경을 만들어뒀고, 지금은 그 한 줄짜리 인터페이스가 저에겐 아주 큰 의미를 가져다주고 있어요.

01. 폰을 통해 아이디어를 실시간으로 반영하고 싶었어요

저는 자동화 잡 수십 개를 매일 굴리고 있어요. AI 생태계 모니터링, 영어 학습, 증권 증시 모니터링 AI LLM Wiki 구축, 브레인 스토밍 등 등 같은 걸 폰으로도 확인하고 싶었거든요. 노트북 열고 터미널 띄우고 명령 치는 게 출퇴근 중엔 너무 번거로웠어요.

 

처음엔 단순한 알림 봇으로 시작했어요. 자동화가 텔레그램으로 한 줄씩 보내주는 정도였어요. 근데 알림만 받다 보니 답답했어요. "텔레그램에서 메시지를 보내면 바로 처리되면 좋겠다"는 생각이 들었거든요. 그래서 단방향 알림 봇을 양방향으로 바꿨어요.

02. 환경 구축, 텔레그램 봇이 Claude CLI를 직접 부르게 했어요

저는 "텔레그램 메시지가 그대로 Claude CLI 입력이 되고, Claude 응답이 그대로 텔레그램 답장이 된다." 그 한 줄을 그대로 코드로 옮겼어요.

 

구조는 세 덩이예요. 봇 데몬 / Claude CLI 호출기 / 안전망.

봇 데몬은 텔레그램 long-poll로 25초씩 새 메시지를 기다리고, 메시지가 오면 Claude CLI를 subprocess로 띄워서 결과를 받고, 그걸 다시 텔레그램으로 답장해요.

 

저는 봇을 launchd로 KeepAlive 데몬으로 박았어요. 크래시 나도 30초 안에 재시작되고, 부팅 시 자동으로 떠요.

# schedules/telegram-bot.job (launchd 골격)

NAME=telegram-bot
RUN_AT_LOAD=1
KEEP_ALIVE=1
COMMAND=/Users/[user]/automation-scripts/telegram-bot.sh
WORKDIR=/Users/[user]/Documents/Claude/Projects/자동화

# launchd 가 매번 살아있는지 보고
# 크래시 시 ThrottleInterval(30s) 후 자동 재시작

저는 이 데몬이 떠 있는 동안은 텔레그램 메시지가 제 미니맥의 Claude Code CLI 요청이 돼요. 같은 채팅 안에서 컨텍스트가 이어지니까 진짜 Claude Code 세션을 잡고 얘기하는 것 같았어요.

03. 사용 패턴, 한 줄 던지면 알아서 일어나는 일

저는 폰에서 텔레그램 봇한테 자유 텍스트로 한 줄만 던져요. 그러면 봇이 그걸 Claude CLI에 그대로 넘기고, Claude가 자동화 잡을 스스로 spawn하거나 상태를 조회해서 답장으로 돌려줘요.

# 폰에서 자주 던지는 한 줄 예시

저: 오늘 발행 큐 어떤 상태야?
봇: (claude --resume 으로 같은 세션 이어감)
봇: 발행예정 3편 / 검수대기 1편 / 사고 0건이에요

저: 검수대기 1편 어떤 글이야?
봇: (같은 세션이라 위 컨텍스트 그대로 이어 받음)
봇: ClaudeCode 신기능 정리 글이에요. 1인칭 80% 통과.

저: 그럼 그거 그대로 발행해줘
봇: (publish workflow spawn → 결과 회신)

저는 이게 진짜 좋은 게 두 가지인데요.

 

첫째, 같은 세션이 유지돼요. 폰에서도 PC 채팅처럼 컨텍스트가 끊기지 않아요.

둘째, 본인이 직접 손을 안 대도 Claude가 알아서 자동화 잡을 spawn해줘요. 발행, 검수, 통계 조회 같은 게 다 한 줄 안에 끝나요.

 

저는 봇에 몇 가지 특수 명령을 박아뒀어요. 다 자주 쓰는 것들이에요.

  • /new: 새 Claude 세션 시작. 이전 컨텍스트 잊고 처음부터
  • /cancel: 진행중인 Claude 프로세스 SIGTERM. 잘못 던졌을 때
  • /status: 봇 상태 + 진행중 작업 조회
  • /yes /no: destructive 명령 confirm 응답

04. 안전망 3중을 박아서 폰에서 마음대로 던져도 사고가 안 나게

저는 처음에 양방향 봇을 만들면서 가장 무서웠던 게 사고였어요. 폰에서 잘못 던진 한 줄이 자동화 시스템 전체를 망가뜨릴 수도 있잖아요. 그래서 3중 게이트를 박았어요.

가. chat_id whitelist

저는 봇이 모든 사람의 메시지를 받게 두지 않았어요. secrets/telegram.env에 명시한 제 chat_id 한 개만 허용해요. 봇 토큰이 유출되어도 다른 chat_id에서 메시지가 오면 그냥 무시해요.

나. destructive keyword 감지

저는 위험한 명령 패턴을 정규식으로 박아두고, 매 메시지마다 매치 검사를 해요. 매치되면 바로 Claude CLI에 넘기지 않고 /yes 또는 /no confirm을 폰으로 다시 요청해요.

# DESTRUCTIVE_PATTERNS 일부 (제가 박은 패턴)

DESTRUCTIVE_PATTERNS = [
    r"rm\s+-rf",         # 파일 통째 삭제
    r"git\s+push.*force", # 강제 푸시
    r"DROP\s+TABLE",     # DB 통째 삭제
    r"sudo",             # 시스템 권한 상승
    # ...
]

# 매치되면 confirm 게이트
저: rm -rf /tmp/* 좀 정리해줘
봇: ⚠️ destructive 명령 감지: 'rm -rf'
봇: 진행할까요? /yes 또는 /no

다. destructive_gate_hook

저는 Claude 자체가 destructive로 판단한 동작도 한 번 더 차단되게 hook을 박아뒀어요. 정규식이 못 잡은 케이스를 Claude의 판단으로 한 번 더 거르는 안전망이에요. 두 단계가 다 통과해야만 실제 동작이 일어나요.

3중 게이트의 의미 저는 안전망을 1중으로만 두면 결국 한 번 뚫리면 끝이라고 생각해요. chat_id (접근) → 정규식 (입력 패턴) → hook (실행 판단) 세 단계가 다 다른 층위에서 거르는 게 핵심이에요. 하나가 뚫려도 다음이 잡아요.

05. 첫 사고, 봇 무한 루프에 빠진 날

저는 이 봇을 만들고 한 달도 안 됐을 때 무한 루프 사고를 한 번 겪었어요. 봇이 Claude CLI를 호출하다 크래시 났는데, 재시작된 봇이 같은 메시지를 처음부터 다시 처리했어요. 그게 또 크래시 났고, 재시작된 봇이 또 같은 메시지를 처리했고요.. 봇 자기 자신을 spam 하는 그림이 됐어요.

 

저는 원인을 봤더니 단순한 critical section 버그였어요. 텔레그램의 last_update_id를 저장하는 시점이 Claude CLI 호출 다음에 박혀있었거든요. Claude가 처리 중에 크래시 나면 last_update_id가 저장 안 된 상태로 봇이 죽고, 재시작된 봇은 같은 메시지를 다시 받는 거였어요.

 

저는 그 자리에서 last_update_id 저장을 Claude CLI 호출 전으로 옮겼어요. 받자마자 저장, 그 다음 처리. 처리가 실패하더라도 같은 메시지가 또 들어오지 않게요. 1줄 순서 바꾼 게 끝인데, 그 한 줄이 한 시간 동안 봇을 spam 모드로 돌리던 버그를 막았어요! ( 이 버그 때문에 날린 시간이 5일이나 되어요 ㅠ )

06. 두 번째 사고, macOS가 권한을 통째로 가져간 날

저는 더 황당한 사고를 한 번 더 겪었어요. 어느 날 갑자기 봇이 무응답이 됐고, 같은 시각에 자동화 잡 12개가 동시에 ModuleNotFoundError: No module named 'lib'로 죽었어요. 

 

원인을 클로드 코드와 파헤쳐보니 Homebrew가 며칠 전 밤에 python3을 3.12에서 3.14.5로 자동 업그레이드했더라고요. 그러면서 python3 binary의 서명이 바뀌었고, macOS TCC가 새 binary로 권한을 재평가하면서 ~/Documents 접근을 차단해버린 거였어요.

 

저는 그래서 launchd로 띄운 wrapper 안에서 os.getcwd()를 부르면 silent PermissionError가 나고, 그게 import system을 망가뜨려서 ModuleNotFoundError로 보이는 거였어요. 진짜 원인은 module 문제가 아니라 권한 문제였는데, 표면 에러는 완전히 다른 결로 보였어요..

 

저는 사용자 수동으로 System Settings → Privacy & Security → Full Disk Access에 새 python3 binary를 추가하고서야 봇이 살아났어요. 그 뒤로 운영 룰 하나 박았어요. "Homebrew python 업그레이드 시 의무 체크: python3 -c 'import os; print(os.getcwd())'가 통과하는지 확인."

07. 지금 폰에서 어떻게 활용하고 있나

저는 사고 두 번을 거치고 나서야 이 환경을 일상으로 굴리고 있어요. 지금은 폰의 텔레그램이 사실상 제 자동화 시스템의 모바일 콘솔이에요. (여기에 본인이 폰에서 자주 던지는 명령 패턴 채울 자리. 예시: 출퇴근 중 아이디네이션 후 반영, 각 종 분류 모니터링 확인 등)

 

저는 폰에서 잘 안 하는 것도 정해뒀어요. 봇 자체 코드를 수정하는 작업은 절대 폰으로 안 해요. 봇이 spawn한 Claude 안에서 봇 자체를 수정·재기동하면 stdout이 끊기거든요. 봇 작업은 무조건 맥 데스크톱 터미널에서요.

08. 2달 운영하면서 얻은 러닝 5가지

저는 이 봇을 2달 가까이 위킹하면서 얻은 게 단순한 "텔레그램 봇 만드는 법"이 아니었어요. 데몬이 있는 시스템이 무엇인지 직접 부딪혀 배운 것에 가까웠어요.

1. 폰에서 던지는 명령에 사람 게이트 1번 끼는 게 가장 안전해요

저는 모든 명령을 자동으로 처리하지 않아요. destructive 패턴 매치되면 /yes /no 묻고, 그 한 번이 폰에서 잘못 누른 한 줄이 사고로 번지는 걸 막아요. "폰이라 손가락이 미끄러질 수 있다"는 가정 하나 박으면 게이트가 자연스럽게 디자인돼요.

2. macOS 시스템 업그레이드 시 권한 손실 체크는 의무예요

저는 TCC 사고를 겪고 나서 시스템 업그레이드를 절대 가볍게 안 봐요. Homebrew python 업그레이드 한 번이 launchd 잡 12개를 동시에 죽일 수 있어요. 업그레이드 후 1회 손체크가 한 시간 디버깅보다 훨씬 싸요.

3. 봇 자체 수정은 봇 안에서 절대 X

저는 한 번 봇이 spawn한 Claude 안에서 봇 코드를 수정하다가 봇 데몬이 멈춘 적이 있어요. 자기 자신을 수정하면서 stdout이 끊기면 봇은 더 이상 답을 받을 수 없어요. 봇 수정은 무조건 외부 터미널에서요.

09. 폰 한 줄로 자동화를 부를 수 있는 자유

저는 이 봇이 사실상 제 시스템에서 가장 비싼 한 줄이에요. 만든 데 든 시간이 비싸서가 아니라, 폰에서 자동화를 한 줄로 부를 수 있는 그 자유가 한 번 익숙해지면 못 끊거든요!

 

저는 만약 본인이 자동화 잡을 여러 개 굴리는 단계라면, 이런 식으로 모바일 콘솔 하나 만들어두는 걸 추천하고 싶어요. 처음엔 단방향 알림 봇으로 시작하고, 익숙해지면 양방향 + 안전망 3중까지 점점 진화시키는 식이요. 사고 한두 번 겪으면 자연스럽게 안전망이 단단해져요..

제가 1년 가까이 직접 운영하면서 사고 친 사이클을 1인칭으로 정리한 글이에요. 텔레그램 봇 일반 가이드 아닙니다. Anthropic으로부터 어떤 형식의 협찬도 받지 않았습니다.

반응형

📚 같이 보면 좋은

"이 포스팅은 쿠팡 파트너스 활동의 일환으로, 일정액의 수수료를 제공받습니다."