어떤 자동화든 그렇지만, 특히 에이전트들은 조용히 죽거나 말썽을 부리기 십상이다. 내가 쓰는 개인 비서 에이전트, 가령 헤르메스나 오픈클로 같은 시스템도 예외는 아니었다.
백그라운드에서 24시간 도는 봇은 늘 그랬듯 예상치 못한 곳에서 발목을 잡았다. 특히 여러 모델을 엮어 쓰는 폴백 체인 구조가 함정이었다.
처음엔 기본 모델이 불안정할 때를 대비해 예비 모델 체인을 여러 개 걸어뒀다. 주 모델이 응답 없으면 다음 모델이, 그것도 안 되면 그 다음 모델이 처리하는 식이었다.
이 정도면 안전하다고 생각했지만, 어느 날 주 모델이 맛이 간 상황에서 예비 모델들이 계속 실패하는 걸 발견했다. 문제는 에이전트가 "폴백 모델을 시도 중입니다" 같은 메시지조차 안 내뱉고 그냥 묵묵부답이었다는 점이다.
원인을 찾아보니, 예비 모델의 API 토큰이 만료되어 있었다. 시스템 입장에서는 '폴백 체인이 등록되어 있으니 문제가 없다'고 판단했지만, 실제로는 이미 고장 난 보험이었다.
그나마 메시지라도 뱉어주면 빨리 알아챘을 텐데, 그냥 조용히 작업을 뱉어냈다. 마치 빈 통장을 믿고 결제하다가 카드 정지당한 느낌이었다.
이전에는 hermes status 명령을 자주 썼다. 이 명령은 대개 'logged in'이라고 보여줬기 때문이다. 하지만 위 폴백 문제처럼 실제 유효성과는 달랐다.
상태 확인이 실제 로그인 여부나 토큰 유효성까지 보장하는 게 아니었다. 단순히 ~/.hermes/token 같은 파일이 있느냐 없느냐로 판단하는 수준이었다. 파일만 있으면 "나는 로그인 상태"라고 외치는 꼴이었다.
겉만 번지르르한 상태 메시지에 속아 넘어간 셈이다. 이 허위 정보 탓에 문제를 파악하는 데 더 오래 걸렸다.
맥클로드 같은 디스코드 봇을 launchd로 띄워 24시간 돌린 적도 있다. launchd는 프로세스가 죽으면 다시 띄워주는 KeepAlive 옵션이 있다. 겉보기엔 완벽한 감시자 같았다.
하지만 문제는 봇 프로세스가 죽지 않고 그냥 작업을 씹는 경우였다. 메모리 누수나 세션 만료, 네트워크 문제 등 원인은 다양했다.
프로세스는 살아있으니 launchd는 아무 문제가 없다고 판단했고, 나는 봇이 온라인으로 떠 있지만 아무 응답도 안 하는 답답한 상황을 몇 번이나 겪었다.
그렇다고 screen 세션에 넣고 hardcopy로 화면을 캡처하는 것도 한계가 있었다. claude 같은 TUI(텍스트 사용자 인터페이스) 앱은 screen hardcopy로 찍어도 텅 빈 파일만 남기 일쑤였다.
직접 세션에 들어가 확인해야 했지만, 일일이 확인하는 건 하루 이틀이지 24시간 자동화와는 거리가 멀었다.
또, launchd 환경 자체의 문제도 있었다. TERM이나 LANG 같은 환경 변수가 없어서 스크립트가 꼬이는 경우도 허다했다.
결국 스크립트 맨 위에 export TERM=xterm-256color나 export LANG=ko_KR.UTF-8 같은 걸 일일이 넣어줘야 했다. 때로는 zsh -l로 로그인 셸 환경을 강제로 로드해야만 제대로 동작하는 경우도 있었다.
이런 사소한 환경 차이 하나가 며칠 밤낮을 새게 만들었다.
게다가 claude 같은 앱은 시작 디렉토리(CWD)가 신뢰할 수 없는 곳이면 폴더 신뢰 프롬프트에서 무한 대기하기도 했다.
launchd에서 cd 명령 없이 바로 앱을 실행하면 ~/Users/me 같은 기본 경로에서 시작해버려 꼼짝없이 멈춰버리는 식이었다.
결국 cd ~/Claudecode && claude ...처럼 명확하게 경로를 지정해야 했다.
자동화 시스템을 위한 외부 감시자 구축
결국 깨달은 건, 봇이나 에이전트 자체의 상태 메시지나 기본 KeepAlive 기능만으로는 부족하다는 점이었다. 외부에서 냉정하게 시스템의 핵심 요소를 주기적으로 점검하는 독립적인 감시자가 필수였다.
나는 이 감시를 위해 별도의 크론 스크립트를 하나 만들었다. 30초마다 돌도록 설정한 이 감시 스크립트는 다음 세 가지를 확인한다.
- 프로세스 생존 여부
pgrep -f "claude --channels"같은 명령으로 실제 봇 프로세스가 살아있는지 확인했다. 단순히launchd가 띄웠다고 끝이 아니라, 봇이 자기 역할을 하고 있는지 점검하는 것이다. 경우에 따라서는lsof -i :포트번호나ps aux | grep "bun server.ts"같은 명령으로 내부 서비스가 제대로 통신 중인지, 핵심 스레드가 작동 중인지 더 깊게 파고들 때도 있었다. - 세션 및 토큰 유효성
가장 중요했던 부분이다. 단순히 파일 존재 유무가 아니라, 실제 API 호출을 시도해서 토큰이 유효한지 확인했다. 최소한의 비용으로list-models같은 가벼운 API를 호출하거나, 짧은 프롬프트로 응답이 오는지 확인하는 식이다. 응답이 없거나 에러가 나면 해당 토큰을 '만료'로 간주하고 알림을 보내도록 했다. - 폴백 체인 건전성
주 모델뿐 아니라 폴백 체인에 있는 모든 모델의 토큰 유효성을 주기적으로 검사했다. 만료된 토큰이 발견되면 즉시 경고하도록 만들었다.
이 감시 스크립트가 만약 이상을 감지하면, 디스코드로 알림을 보내고 자동으로 봇 프로세스를 재시작하도록 했다.
단순 재시작이 아니라, launchd로 띄울 때 발생했던 CWD, TERM/LANG 환경 변수 문제까지 고려해 cd와 export 명령을 명시한 셸 스크립트를 호출하게 만들었다.
결국 자동화된 시스템은 스스로가 '괜찮다'고 말하는 것만 믿어서는 안 된다. 외부에서 그 말을 검증해 줄 독립적인 감사관이 반드시 필요하다.
정기적인 세션, 토큰, 프로세스 생존 점검은 조용히 찾아오는 장애에 대비하는 가장 기본적인 보험이었다.

'기타팁 및 문제 해결' 카테고리의 다른 글
| 맥 시작 시 프로그램 자동 실행, launchd 설정과 안 될 때 확인할 것 (0) | 2026.09.08 |
|---|---|
| 내부 스크립트 외부 공개: 사용자 친화적 문서화로 전환 (0) | 2026.09.06 |
| 맥 환경변수 설정하는 법, zshrc에 넣었는데 안 먹을 때 (0) | 2026.09.03 |
| 맥에서 외장 SSD가 안 보일 때, 어디부터 봐야 하나 (0) | 2026.09.02 |
| 윈도우에서 npm 설치했는데 명령어가 안 먹을 때, PATH부터 확인 (0) | 2026.09.01 |