
Claude Code의 Remote Control이 멈추는 문제를 Python Watchdog으로 자동 복구하기
요약
Claude Code의 Remote Control 기능 사용 중 세션이 멈추는 문제를 Python Watchdog을 활용해 자동으로 복구하는 방법을 소개합니다. 세션 상태 파일을 감시하여 멈춤을 감지하고, 동일한 터미널 탭 내에서 프로세스를 재시작하여 연속성을 유지합니다.
핵심 포인트
- Claude Code Remote Control의 세션 멈춤 현상 해결
- Python Watchdog을 이용한 프로세스 상태 모니터링
- 동일한 터미널 탭 내에서 세션을 재시작하여 복구 효율 극대화
- LLM 없이 순수 Python 스크립트로 구현하여 토큰 비용 제로
서론
Claude Code의 Remote Control(claude --remote-control, 스마트폰에서 내 손안의 세션을 조작하는 기능)을 사용하다 보면, 승인 작업 후에 세션이 멈추는 경우가 있습니다. 스마트폰에서 승인해도 터미널에 반영되지 않고, status가 waiting(승인 대기) 상태인 채로 잠겨버립니다——내 PC에서 마우스를 움직이면 복구되지만, 화면이 슬립(Sleep) 상태라면 외부에서는 손을 쓸 방법이 없습니다.
이 문제를 단 두 개의 스크립트만으로 자동 복구할 수 있도록 만들었습니다. 메커니즘은 다음 두 가지뿐입니다.
- 탐지: Claude Code 스스로가 작성하는 상태 파일(
~/.claude/sessions/<pid>.json)을 읽기만 함 - 복구: "같은 터미널 탭 안에서" 세션을 재시작하기만 함
LLM은 전혀 사용하지 않습니다. 순수하게 Python이 프로세스를 kill할 뿐이므로, 토큰 소비가 제로이며 완전히 결정론적(Deterministic)으로 동작합니다. 대상은 Claude Code를 CLI로 사용하는 macOS 사용자입니다.
전체상과 사용법
하고 싶은 것은 Remote Control 세션을 "멈춰도 알아서 고쳐지는" 상태로 만드는 것입니다. 하는 일은 단순합니다.
- 감시 역할을 하는 프로그램을 상주시켜, 세션이 멈춰 있는지 정기적으로 체크한다
- 멈춘 세션을 발견하면, 그것을 일단 종료시킨다
- 같은 탭에서 즉시 다시 실행하여, 중단된 작업의 다음 단계를 이어가게 한다
포인트는 이것을 "새 창을 열지 않고, 지금 있는 탭 안에서" 수행한다는 점입니다. 새 창을 여는 방식은 PC 화면이 슬립 상태일 때 동작하지 않을 수 있지만, 같은 탭 안에서 재시작하면 화면이 꺼져 있어도 복구할 수 있습니다.
실체는 다음 2개의 스크립트 + 1개의 로그뿐입니다.
| 파일 | 역할 |
|---|---|
~/.local/bin/claude-rc.sh | 실행 담당. Remote Control 세션을 띄우고, 중단되면 같은 탭에서 재시작한다 |
~/.local/bin/claude-rc-watchdog.py | 감시 담당. 멈춘 세션을 찾아 종료시킨다 (kill할 뿐이다) |
~/.claude-rc/watchdog.log | 감시 담당의 동작 로그 |
claude-rc.sh(실행 담당)와 claude-rc-watchdog.py(감시 담당)가 역할을 분담하고 있는 것이 핵심입니다. 감시 담당은 "멈추면 중단한다"만, 실행 담당은 "중단되면 같은 탭에서 다시 띄운다"만 수행하며 서로 불필요한 일을 하지 않습니다. 무엇을 보고 멈춤이라고 판단하는지와 같은 내용은 후반부의 "메커니즘"에서 설명하겠습니다.
셋업과 실행
후술할 2개 파일을 ~/.local/bin/에 두고, 실행 권한을 부여합니다 (다른 곳에 둔다면 claude-rc.sh 내의 WATCHDOG를 수정해 주세요).
chmod +x ~/.local/bin/claude-rc.sh ~/.local/bin/claude-rc-watchdog.py
그 후 작업 디렉토리에서 실행 담당을 실행하기만 하면 됩니다. 감시 담당도 자동으로 시작됩니다.
cd <작업 디렉토리> && claude-rc.sh
/exit나 Ctrl-D로 나갔을 때는 (멈춘 것이 아니므로) 재시작하지 않습니다. claude-rc.sh -c와 같이 전달한 인수는 그대로 claude로 전달됩니다 (~/.local/bin이 PATH에 등록되어 있다는 전제입니다).
소스 코드
2개 파일 모두 전문을 접기(Folding) 형태로 게재합니다. 서두의 주석에 "무엇을 하는 것인지" 적혀 있습니다.
claude-rc.sh — 같은 탭에서 자기 재시작을 하는 실행 담당
#!/usr/bin/env bash
# claude-rc.sh — remote-control 세션을 "같은 탭에서 자기 재시작"하는 실행 래퍼(Wrapper).
#
...
claude-rc-watchdog.py — 멈춤을 감지하여 kill하는 감시 담당 (kill 전용)
#!/usr/bin/env python3
"""
claude-rc-watchdog.py — remote-control 세션의 잠금 감지 와치독(Watchdog) (kill 전용)
...
메커니즘
탐지: 상태 파일 읽기만 수행
CPU 사용률이나 터미널 출력을 들여다보는 식의 추측은 하지 않고, Claude Code 스스로가 ~/.claude/sessions/<pid>.json에 기록하는 상태를 읽습니다. 내용은 다음과 같은 형태입니다.
{
"pid": 30868,
"sessionId": "861b7e26-40b3-47ff-b62a-2626c44e7a5b",
...
확인하는 것은 두 가지뿐입니다. status (idle / busy / waiting)와, 하트비트(heartbeat) 역할을 하는 updatedAt (최종 업데이트 시각)입니다. 프로세스가 멈추면 updatedAt의 업데이트가 중단되므로, "현재 시각 - updatedAt"이 경과 시간(stale)이 됩니다.
감시 대상을 구분하기 위해 ps를 사용하며, claude이면서 인자(argument)에 --remote-control을 포함하는 프로세스만 포착합니다. 이 인자는 Remote Control 세션만이 가지므로, 일반 세션이나 감시 데몬(daemon) 자신을 실수로 kill 하는 일은 없습니다.
판정: status에 따라 임계값 변경
| status | 임계값 | 이유 |
|---|---|---|
waiting (승인 대기) | 120초 (2분) | 승인 대기 중 멈추는 경우가 실질적인 피해의 대부분. 빠르게 kill 하고 싶음 |
busy (처리 중) | 600초 (10분) | 장시간 빌드나 긴 생성 과정을 실수로 kill 하지 않기 위한 보험. 길게 설정 |
그 외 (idle 등) | 대상 제외 | 대기 중인 상태는 멈춘 것이 아님. 아무것도 하지 않음 |
waiting은 "본래 바로 진행되어야 하는데 진행되지 않는" 상태이므로 2분이면 충분합니다. busy는 정당한 장시간 처리를 휘말리게 하지 않도록 10분으로 길게 설정했습니다.
복구: 동일한 탭에서 재시작
watchdog는 kill만 수행하며, 재시작은 claude-rc.sh의 while 루프가 종료 코드(exit code)로 판단합니다.
143(SIGTERM) /137(SIGKILL) = watchdog의 kill →--continue로 동일한 탭에서 재시작- 그 외 (
/exit의 0,Ctrl-C의 130 등) → 재시작하지 않음
watchdog가 보내는 것은 SIGTERM/SIGKILL뿐이므로, 이 종료 코드의 구분을 통해 "사용자의 의도적인 종료"와 확실히 구별할 수 있습니다. 재시작 시에는 --continue와 함께 다음 프롬프트를 덧붙여, 중단된 작업을 히스토리에서 다시 불러오게 합니다.
이전 작업이 멈춰서 중단되었습니다. 직전에 수행하려던 처리를 히스토리에서 확인하고, 이어서 다시 진행해 주세요.
요약
Remote Control이 멈추는 문제를 다음과 같은 구성으로 자동 복구할 수 있게 되었습니다.
- 탐지: 상태 파일의
status와updatedAt(하트비트)을 읽기만 함. 추측하지 않음 - 판정:
status별 임계값 적용 (waiting= 2분 /busy= 10분 / 그 외 = 대상 제외) - 복구: 동일한 탭에서 자기 재시작. 새 창을 띄우지 않으므로 화면이 꺼져 있어도 복구됨
- LLM 미사용, 토큰 소비 제로, 결정론적(deterministic) 방식
주의사항으로:
- 이것은 비공식적인 접근 방식이며, 상태 파일의 형식이나
status값은 향후 변경될 수 있습니다. - 여러 Remote Control 세션을 동시에 운용하는 것은 본래 server mode를 상정한 예외적인 사용법입니다.
- 임계값 (
waiting= 120초 /busy= 600초)은 사용 환경에 맞춰 조정하십시오.
공식 API가 아닌 이상 업데이트로 인해 작동이 멈출 가능성은 있지만, "상태 파일을 읽어 kill 하고, 재시작은 별도의 루프가 담당한다"는 책임 분리(separation of concerns) 원칙은 사양이 바뀌더라도 개념적으로 유용하게 활용할 수 있을 것입니다. 같은 고민을 하는 분들에게 도움이 되기를 바랍니다.
Discussion

AI 자동 생성 콘텐츠
본 콘텐츠는 Zenn AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기