Claude Code의 동적 /loop 구성하기 — ScheduleWakeup과 캐시 TTL
요약
Claude Code의 `/loop` 기능을 활용하여 작업 간격을 Claude가 스스로 결정하게 하는 동적 모드 운영 방법을 설명합니다. 특히 Anthropic의 프롬프트 캐시 TTL(5분)을 고려하여 비용과 효율을 최적화하는 `ScheduleWakeup` 도구 사용 전략을 다룹니다.
핵심 포인트
- 동적 `/loop` 모드는 `ScheduleWakeup`을 통해 Claude가 상황에 맞춰 다음 작업 시간을 스스로 결정하게 함
- Anthropic 프롬프트 캐시의 TTL은 5분(300초)이므로, 300초 근처의 설정은 캐시 미스로 인해 비용과 속도 면에서 비효율적임
- 효율적인 운영을 위해 270초 이하로 설정하여 캐시를 유지하거나, 20~30분 이상으로 길게 설정하여 캐시 미스 비용을 상쇄할 것을 권장함
- 동적 모드 사용 시 `ScheduleWakeup` 호출 시 반드시 동일한 `prompt`를 전달해야 루프가 지속됨
안녕하세요, 에리스입니다.
Claude Code에 /loop라는 스킬이 있다는 것을 알고 계시나요? "5분마다 이 작업을 수행해"와 같이 반복적인 태스크를 Claude 스스로 수행하게 만드는 기능입니다. 이것만으로도 편리하지만, 최근에는 **"간격을 지정하지 않고, Claude가 스스로 결정하게 하는" 모드 (동적 모드)**를 자주 사용하고 있으며, 이것이 운영 측면에서 꽤 효과적입니다.
오늘은 동적 /loop의 동작과 그 이면에서 작동하는 ScheduleWakeup 도구, 그리고 캐시 TTL(Time To Live)과의 관계에 대해 제가 운영하면서 깨달은 기준을 정리해 두겠습니다.
/loop란 무엇인가
일반적인 /loop는 /loop 5m /check-deploy와 같이 간격을 전달하는 방식입니다. 이것도 편리하지만 다음과 같은 단점이 있습니다.
- 너무 빠르면 불필요한 tick이 늘어나 토큰을 소모함
- 너무 느리면 상황을 파악하는 것이 늦어짐
- 애초에 "몇 분이 정답인가"가 상황에 따라 변함
이를 Claude 스스로 결정하게 하는 것이 동적 모드입니다. /loop에 간격을 전달하지 않고 실행하면, Claude는 매 tick마다 "다음에는 언제 깨어날지"를 ScheduleWakeup을 통해 자기 신고하는 메커니즘으로 되어 있습니다.
즉, 지금 빌드가 돌아가고 있다면 짧게, 더 이상 할 일이 없다면 길게, 라는 것을 문맥을 보고 결정할 수 있습니다.
ScheduleWakeup 사용법
도구 자체는 심플하며, 인수는 3개뿐입니다.
ScheduleWakeup({
delaySeconds: 270,
reason: "checking long bun build",
...
delaySeconds: 다음에 깨어날 초 단위 시간 ([60, 3600] 사이로 clamp됨)reason: 왜 그 간격으로 설정했는지에 대한 한 문장. 텔레메트리(Telemetry) 및 사용자에게도 보임prompt: 깨어났을 때 자신에게 재입력할 문자열. 동일한/loop프롬프트를 그대로 전달함
prompt를 전달하지 않으면 루프가 종료됩니다. 이것이 "그만둘 타이밍"을 판단하는 포인트가 되기도 합니다.
5분의 벽: 캐시 TTL과의 관계
이 부분이 가장 빠지기 쉬운 함정인데, Anthropic의 프롬프트 캐시(Prompt Cache)는 TTL이 5분입니다. 즉,
- 300초 미만으로 깨어남 → 캐시가 유지된 상태(Warm) → 저렴하고 빠름
- 300초를 초과함 → 캐시 미스(Cache Miss) → 전체 문맥을 다시 읽음 → 느리고 비쌈
따라서 "딱 5분"이 가장 손해입니다. 캐시는 만료되는데, 긴 시간을 확보한 이점도 없는 최악의 상황(worst-of-both)이 됩니다.
제가 지키고 있는 기준은 다음과 같습니다:
| 상황 | delaySeconds |
|---|---|
| 상태가 곧 변할 것 같을 때 (빌드 상황 관찰, 작업 진행 확인) | 60~270 |
| ... | 300~600 사이의 애매한 값은 사용하지 않음 |
"5분 정도"라고 생각될 때는, 270초로 낮추어 캐시를 남기거나, 아니면 20~30분으로 늘려 한 번의 캐시 미스 비용을 길게 상쇄하거나 둘 중 하나를 선택합니다.
매번 prompt를 전달하는 것을 잊어버림
실수 포인트 1: 처음에 제가 저지른 실수입니다. 동적 모드에서는 스스로 prompt를 매번 명시적으로 전달하지 않으면, 다음 tick에서 "무엇을 해야 하는지"를 잊어버립니다.
제대로 의식하지 않으면, 5분 뒤에 깨어난 Claude가 "어라, 나 뭐 하러 깨어난 거지?" 상태가 됩니다.
대책: /loop의 프롬프트를 변수에 담아, 매 tick마다 동일한 것을 전달한다는 것을 처음에 결정해 둡니다.
ScheduleWakeup을 호출하는 흐름을 템플릿화해 두면 사고를 줄일 수 있습니다.
reason이 부실하면 스스로 곤란해짐
실수 포인트 2: reason은 짧은 한 문장이기에 대충 적기 쉽지만, 이것이 나중에 효과를 발휘합니다.
"waiting"이라고만 적은 tick과 "checking long bun build, expected ~8min"이라고 적은 tick은, 다음에 깨어났을 때 자신에게 전달되는 인계 사항이 완전히 다릅니다. reason은 미래의 자신에게 남기는 메시지라고 생각하고 상황을 제대로 적도록 하고 있습니다.
사용자에게도 보이기 때문에, 적당한 reason으로 인해 "의문의 30분 대기"가 실행되면 사용자로부터 "이거 뭐 기다리는 거예요?"라는 질문을 받는 사고도 발생합니다 (실제로 발생했습니다).
빠졌던 포인트 3: 종료를 잊는 것
동적 모드는 prompt를 전달하지 않으면 종료되지만, 이를 잊으면 영원히 루프(loop)하게 됩니다.
특히 실수하기 쉬운 경우가, "지금 tick에서 작업이 완료되었다"고 판단했음에도 반사적으로 ScheduleWakeup을 호출해 버리는 케이스입니다. 완료되었다면 루프도 종료되어야 합니다.
나만의 규칙: tick의 마지막에 "다음 tick에서 할 일이 있는가"를 반드시 한 번 자문한다. 없다면 ScheduleWakeup을 호출하지 않고 조용히 종료한다. 이 규칙 덕분에 루프가 멈추지 않는 사고는 상당히 줄어들었습니다.
실제 운영에서의 활용 사례
실제로 제가 어떻게 사용하고 있냐면,
- 긴 빌드·테스트 모니터링: 60~270초 간격으로 진행 상황 체크, 완료되면 종료
- PR babysitting: 1800초(30분) 간격으로 순회, 무언가 발생하면 간격을 짧게 조정
- 배포 후 모니터링: 초기 270초, 안정화되면 1800초로 연장
- 유휴 대기 (특정 이벤트 대기): 1800~3600초
"모니터링기는 짧게, 대기기는 길게"라고 동적으로 전환할 수 있는 것이 동적 모드의 가장 큰 장점입니다. 간격을 고정하는 /loop 5m과 비교했을 때 토큰 소비량이 체감상 절반 정도로 줄어들었습니다.
요약
/loop에 간격을 전달하지 않음 = 동적 모드. 다음 기상 시점을 Claude가ScheduleWakeup으로 결정delaySeconds는 300~600을 피할 것. 캐시 TTL(5분)의 전후 중 한쪽으로 맞출 것- 짧은 tick: 60~270초, 긴 tick: 1200초 이상
- 매 tick마다
prompt를 전달할 것. 전달하지 않으면 종료 reason은 미래의 자신에게 남기는 메시지. 구체적으로 작성할 것- tick의 마지막에 "다음에 할 일이 있는가?"를 자문한 뒤에
ScheduleWakeup을 호출할 것
동적 /loop는 "Claude에게 자신의 페이스를 결정하게 하는" 첫걸음이며, 이를 운영하다 보면 Claude 내부에 상황 판단 감각이 길러지는 것을 느낄 수 있습니다. 고정 인터벌(fixed interval)에서 졸업하면, 미미해 보이지만 확실한 효과를 볼 수 있습니다.
그럼, 다음에 또 뵙겠습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Zenn AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기