Reddit

Cachebeat – keep your Claude Code prompt cache warm while a session is idle

Cachebeat – 세션이 idle인 동안 Claude Code 프롬프트 캐시를 따뜻하게 유지하는 스킬

Claude Code 세션이 일정 시간 idle 상태일 때 자동으로 작은 응답을 발생시켜 프롬프트 캐시 TTL을 갱신해주는 단일 파일 스킬입니다. Anthropic은 캐시 읽기를 입력 요금의 0.1배로 과금하므로, 캐시가 만료된 뒤 돌아오면 전체 대화 이력이 약 10배 비용으로 재처리됩니다. 긴 세션에서 반복되는 이 'idle tax'를 차단하는 것이 목표입니다.

본문

Cachebeat는 Claude Code 세션이 조용히 놓여 있는 동안 프롬프트 캐시(prompt cache)가 만료되지 않도록 지켜주는, SKILL.md 파일 하나로 이루어진 작은 스킬입니다. Anthropic은 캐시 읽기를 모든 모델에서 입력 요금의 0.1배로 과금하기 때문에, 캐시가 죽은 상태로 돌아와서 보내는 한 줄의 메시지는 대화 전체를 약 10배 비용으로 다시 처리하게 만듭니다. 이는 API 과금에만 해당하는 문제가 아니라, Pro/Max 구독에서도 동일한 계산이 5시간 윈도와 주간 사용량 한도를 갉아먹습니다.

왜 필요한가

Claude는 stateless이므로 매 턴마다 전체 대화가 API로 다시 전송됩니다. 프롬프트 캐싱이 이를 감당 가능하게 만들지만, 캐시는 TTL(긴 세션 기준 최대 1시간)이 지나면 만료됩니다. 긴 작업(학습, CI, 대용량 다운로드)을 돌려놓거나 잠시 자리를 비우면 세션이 TTL 너무 오래 조용해져 캐시가 죽고, 돌아와서 '잘 돼가?' 한 줄을 치는 순간 이력 전체가 uncached로 재처리됩니다. 도구를 많이 쓰는 긴 세션에서는 수십만 토큰이 자리 비울 때마다 통째로 재과금됩니다. 이 프로젝트는 실제로 며칠간 이어진 모델 파인튜닝 감독 세션에서 태어났습니다. 학습이 몇 시간씩 걸리고 체크포인트가 밤새 떨어지는 동안, 세션이 캐시 윈도보다 오래 조용해질 때마다 같은 재과금이 반복됐다고 합니다.

동작 방식

/cachebeat는 세션 안에 백그라운드 모니터 하나를 띄웁니다. 이것은 정해진 간격마다 울리는 metronome이 아니라 inactivity 타이머로, 세션이 실제로 N분간 조용했을 때만 발동합니다. 어떤 메시지든, 응답이든, 백그라운드 이벤트 응답이든 이미 캐시를 갱신하므로 시계가 리셋됩니다. 발동하면 Claude가 깨어나 몇 단어로 답하고('Okay, still here.' 수준), 캐시 TTL이 다시 시작됩니다. 손익분기 계산은 단순합니다. 한 번 cold가 되는 비용이 heartbeat 열 번 비용과 같으므로, 세션에 한 번만 돌아와도 이미 이득이며 세션이 클수록 절대 절감액이 커집니다(10배 비율은 고정이지만 토큰 수는 아니므로). 방치된 세션이 무한히 과금하지 않도록 기본 8시간 후에는 스스로 종료됩니다.

설치는 SKILL.md 하나를 ~/.claude/skills/cachebeat/(사용자 레벨) 또는 <프로젝트>/.claude/skills/cachebeat/(프로젝트 레벨)에 복사하면 끝입니다. 사용법은 '/cachebeat'(50분 idle 후 발동, 8시간 후 자동 정지), '/cachebeat 40'(idle 임계값 지정, 5~55분으로 클램프), '/cachebeat 40 4'(임계값 + 4시간 후 자동 정지), '/cachebeat stop'입니다.

구현 세부사항과 검증

모니터는 1분마다 Claude Code의 세션 트랜스크립트(~/.claude/projects/<slug>/<session-id>.jsonl)를 읽어 마지막 실제 턴이 언제였는지 확인합니다. 활동 신호로 파일 mtime이 아니라 마지막 라인의 timestamp를 쓰는 것이 핵심입니다. mtime은 recap 재생성이나 atomic save 같은 Claude Code 자체 작업으로도 갱신되어 idle 시간을 과소계상하고, 결과적으로 TTL을 넘긴 뒤 늦게 발동해 정가 재처리라는 바로 그 실패 모드를 유발하기 때문입니다. tail, grep, wc, date +%s 같은 이식 가능한 도구만 쓰고 stat이나 타임스탬프 파싱을 쓰지 않아 GNU와 BSD 차이 문제가 없으며, Linux·WSL2·macOS를 지원하고 네이티브 Windows는 미검증입니다.

캐시가 따뜻하게 유지되는지는 세 가지로 확인할 수 있습니다. 첫째, Claude Code의 상태 표시줄 tok:312.0k/0.0k에서 두 번째 숫자(캐시에서 읽은 양)가 첫 번째의 큰 비중을 차지하면 warm입니다. 둘째, 트랜스크립트에서 cache_read_input_tokens가 크고 cache_creation_input_tokens가 작으면 warm이고, 반대면 cold입니다. 셋째, beat 자체가 uncached로 돌아오면 CACHEBEAT_WARN이 뜨는데, 이는 세션 TTL이 어떤 heartbeat로도 못 메울 만큼 짧다는 뜻이므로 중지해야 합니다.

한계도 명시돼 있습니다. 긴 1시간 TTL 세션에서만 도움이 되며 5분 TTL 세션은 실용적인 heartbeat로 메울 수 없습니다. 각 beat는 작은 캐시 읽기 요청과 몇 개의 출력 토큰을 쓰고 그 교환이 이후 요청이 다시 읽는 컨텍스트에 추가되므로 '공짜가 아니라 싼 것'입니다. idle 임계값은 TTL 아래여야 해서 기본 50분은 1시간 TTL 대비 약 10분 여유입니다. 세션에 돌아올 생각이 없다면 어떤 heartbeat도 순수한 낭비이며, 그래서 자동 정지 데드라인이 있습니다. 라이선스는 MIT입니다.

Reddit 반응

  • @doodlen — '따뜻하게 유지한다'는 게 무슨 뜻인가요? 매번 새로고침할 때마다 토큰을 꽤 쓰는 것 아닌가요?
  • @Open-Adhesiveness-86 — 핑이 토큰을 쓰냐는 질문에 대한 답: 씁니다. 다만 API 가격 기준으로는 일방적입니다. 캐시 읽기는 기본 입력 가격의 약 0.1배이고 1시간 TTL 쓰기는 2배입니다. 200k 컨텍스트에서 heartbeat 한 번은 대략 2만 토큰어치, cold 캐시로 돌아오면 재작성에 약 40만 토큰어치입니다. 유지하는 게 이득이 그쳐지기까지 핑 약 19번입니다. 구독 한도에 어떻게 매핑되는지는 비공개라 그쪽에서는 대략적인 지표로만 보세요. 함정은 프리픽스가 바이트 단위로 동일하게 유지될 때만 핑이 도움이 된다는 겁니다.
  • @Vegetable-Gate-285 — 상시 켜두는 세션들(heartbeat 작업, 챗 브리지)을 위해 8월 중순부터 같은 종류의 keepalive를 돌리고 있습니다. 와이어 레벨 측정에서 얻은 두 가지를 공유합니다. heartbeat 자체의 토큰은 트랜스크립트에 남길 필요가 없습니다. tail-only 롤백(heartbeat 사용자 턴과 응답만 버리고 그 이전은 건드리지 않기)을 하면 기존 프리픽스가 바이트 단위로 동일하게 유지돼 다음 실제 메시지도 warm하게 읽히고, 50분마다 'Okay, still here'가 이력에 쌓이지 않습니다. Fable 5.1에서 당한 주의점: 반드시 꼬리에서만 자르세요. 중간을 편집하면 (프리픽스가 깨집니다).
  • @sisif_ — 여러 방식으로 구현해봤습니다. https://github.com/avirtual/clodex 에 옵션으로도 넣어뒀고, Fable 5.1에는 항상 켜두고 있습니다.
  • @OneMoreName1 — 이걸 쓰는 사람이 충분히 많아지면 모두에게 캐시 가격을 올릴 겁니다. 하지 마세요, 좋은 것도 못 가지게 됩니다.

원문: Reddit / 번역·요약: Trawling