Claude Code 공식 문서 Run prompts on a schedule 이미지
이미지: code.claude.com (Run prompts on a schedule)

빌드나 테스트가 몇 분씩 걸리는 걸 기다리면서 "아직 안 끝났어?"를 반복해서 물어본 적이 많습니다. Claude Code가 매번 다시 상태를 확인해주긴 하는데, 그때마다 새 턴이 소모되고, 제가 질문을 깜빡하면 끝난 결과도 한참 뒤에야 알게 됩니다. /loop로 일정 주기마다 자동으로 다시 물어보게 할 수도 있었지만, 이것도 결국 "아직인가?"를 계속 다시 던지는 구조라 끝날 때까지 턴을 계속 쓰게 됩니다.

어떤 작업이었나

CI에서 테스트 스위트 하나가 끝나는 데 8분 정도 걸리는 상황이었습니다. gh pr checks로 상태를 보면서 기다리는데, 중간에 다른 작업을 하다 보면 끝난 걸 못 보고 지나치기 일쑤였습니다. /loop 2m으로 2분마다 확인하게 걸어두면 되긴 하는데, 8분짜리 작업에 4번 정도 턴이 돌고 그마저 "아직 pending"이라는 똑같은 응답을 4번 받는 셈이었습니다.

AI를 어떻게 활용했나

Claude Code에는 Monitor라는 별도 도구가 있습니다. 셀 명령 하나를 백그라운드로 띄워두고, 그 명령의 stdout 한 줄 한 줄이 그대로 알림(이벤트)이 되는 구조입니다. 턴을 다시 돌려서 묻는 게 아니라, 명령이 알아서 종료될 때까지 지켜보기만 합니다. CI 체크에 쓴 명령은 이런 모양이었습니다.

prev=""
while true; do
  s=$(gh pr checks 1234 --json name,bucket)
  cur=$(jq -r '.[] | select(.bucket!="pending") | "\(.name): \(.bucket)"' <<<"$s" | sort)
  comm -13 <(echo "$prev") <(echo "$cur")
  prev=$cur
  jq -e 'all(.bucket!="pending")' <<<"$s" >/dev/null && break
  sleep 30
done

이 스크립트는 체크 하나가 끝날 때마다 그 결과만 한 줄 출력하고, 전부 끝나면 루프를 빠져나와 종료됩니다. Monitor에 이 명령과 description, timeout_ms를 넘기면 세션은 다른 일을 계속하고, 체크가 하나씩 끝날 때마다 알림이 왔습니다. 전부 끝나면 명령 자체가 종료되면서 감시도 자동으로 멈췄습니다.

처음엔 tail -f ci.log | grep "PASSED"처럼 성공 메시지만 걸러서 보려고 했습니다. 그런데 이렇게 하면 빌드가 중간에 멈추거나 타임아웃이 나도 아무 로그도 안 찍히니 알림이 그냥 조용합니다. 지켜보는 입장에서는 "아직 진행 중"과 "이미 죽었는데 모르고 있음"이 똑같이 침묵으로 보여서 구분이 안 됐습니다. 그래서 필터를 성공 신호 하나가 아니라 실패까지 포함하도록 넓혔습니다.

tail -f build.log | grep -E --line-buffered "PASSED|FAILED|Traceback|Killed|OOM"

결과와 얻은 팁

  • Monitor는 명령이 스스로 끝나는 작업(CI 체크, 빌드)에 잘 맞고, tail -f처럼 끝나지 않는 명령을 "한 번만 알려줘" 용도로 쓰면 타임아웃까지 계속 감시 상태로 남아 있습니다. 한 번만 알림을 받고 끝낼 거라면 Bash를 백그라운드로 돌리면서 종료 조건이 있는 until 루프를 쓰는 쪽이 맞았습니다.
  • 필터를 성공 메시지로만 좁히면 "진행 중"과 "조용히 죽음"을 구분할 수 없습니다. 지켜보는 상태가 크래시했을 때도 뭔가 찍히도록, 실패 신호까지 한 번에 걸러주는 정규식을 만들어두는 편이 안전했습니다.
  • 타임아웃은 기본 5분, 최대 30분으로 제한이 있어서 8분짜리 체크 정도는 문제없이 끝까지 지켜봤지만, 더 긴 작업은 만료 알림을 받고 다시 걸어줘야 했습니다. 알림이 너무 자주 쏟아지면 자동으로 멈추기도 해서, 로그를 그대로 흘려보내기보다 꼭 필요한 줄만 거르는 게 기본이었습니다.