⏳ This skill is pending AI review.

Scores will appear once the review pipeline completes.

version unknown

cachebeat

@arahim3⭐ 70 stars

Keep the Anthropic prompt cache warm by firing a tiny heartbeat only after N minutes of true session inactivity (any exchange resets the clock), so the next real turn reads the conversation at cached price / cached quota instead of a full uncached re-read. The heartbeat is a background Stop hook this skill registers (asyncRewake) - it re-arms itself after every turn, with no tool calls and no permission prompts. Use when the session may sit idle (training runs, CI, downloads, the user stepping away) longer than the cache TTL. Args - idle threshold in minutes (default 50), optional max hours (default 8), or "stop".

Choose how to use this skill

You do not need every option. Choose the path your AI client supports. The stable page stays the same; versioned files are immutable.

1. Native installer

This listing has no registered native installer command. Use the complete package or source fallback below, depending on what your client supports.

Do not guess an installer command or replace an existing version without reviewing the diff.

2. Complete package recommended

Download the ZIP when available. It includes SKILL.md plus the references, security notes and version metadata.

No complete ProSkills package is published for this listing yet.

3. Prompt-only

Copy the prompt above when the agent can read the stable page or when you want to adopt the workflow without installing a skill.

Need only the instruction file?

Download SKILL.md only if your client requires a single file. The complete ZIP is safer for a full installation because it preserves the references and release context.

No path installs or executes anything by itself. Your agent still needs access to the project files. Before updating, compare the installed version and review the diff.

—/10

// RATINGS

⭐GitHub Stars
⭐⭐ 70 on GitHubGitHub ↗

Growing

🟢ProSkills Score
—
📍

Not yet listed on ClawHub or SkillsMP

// README

cachebeat 🫀

Stop paying full price to say "I'm back" to your own Claude Code session.

A tiny Claude Code skill that keeps your prompt cache warm while a session sits idle — so your next message reads the conversation from cache instead of re-billing it from scratch. Anthropic bills cache reads at 0.1× the input rate (published ratio, every model) — an uncached return costs ~10× more.

This is not just an API-billing thing. On Pro/Max subscriptions the same accounting drains your 5-hour window and weekly usage limit: come back to a long session cold, and one "how's it going?" can eat a visible chunk of your quota that a warm cache would barely have touched.

Why this exists

It was born in a real session: a multi-day model fine-tune babysat by Claude — training runs that took hours, checkpoints landing overnight, a human who occasionally sleeps. Every time the session went quiet for longer than the cache window, the next "how's it going?" re-billed the entire conversation history at full input price. On a long, tool-heavy session that's hundreds of thousands of tokens, re-billed every single time you stepped away too long.

One inactivity-triggered heartbeat later, it didn't.

The problem, concretely

Claude is stateless: your whole conversation is re-sent to the API on every turn. Anthropic's prompt caching makes this affordable — cached input costs ~10 % of the normal rate — but the cache expires after a TTL (up to 1 hour on long-TTL sessions). The failure mode:

  1. You run something long (training, CI, a big download) or just step away.
  2. The session is silent past the TTL. The cache dies.
  3. You come back, type one line — and the entire history is re-processed uncached: ~10× the tokens a cached read would have counted. On the API that's money; on a subscription that's your 5-hour window and weekly limit draining for nothing.

Do that a few times a day on a long-running session and the "idle tax" quietly becomes the biggest line in your bill — or the reason you hit your usage limit by mid-week.

The fix

/cachebeat arms a silent background watcher inside your session. It's an inactivity timer, not a metronome: it fires only when the session has been truly silent for N minutes — any message, reply, or answered background event already refreshed the cache and resets the clock. On firing, Claude wakes, answers with a single ., and the cache TTL restarts. The next timer starts by itself.

Break-even math: going cold once costs as much as ten heartbeats. Come back to the session even once and the heartbeat has paid for itself many times over — and the bigger the session, the bigger the absolute savings (the 10× ratio is flat; the token count isn't).

It also kills itself after a deadline (default 8 h), so an abandoned session doesn't drip-bill forever.

Note (Oct 2026): Claude Code 2.1.285 put a lifetime on background shell commands (30 min by default, 2 h at most) and tells Claude not to restart one that hit the 2 h cap. The previous cachebeat ran as exactly such a command, so it was killed before its first 50-minute beat (or at 2 h on a busy session) and never came back (#1). cachebeat now runs as an asyncRewake Stop hook declared in the skill itself: no lifetime cap, no re-arm tool call, no permission prompt, and one request per beat instead of two. Upgrading? Copy both files again (see Install), then run /cachebeat once in each session you want covered. A session still running the old instructions stops at its next re-arm instead of looping.

Install

User-level (all projects):

mkdir -p ~/.claude/skills/cachebeat
cp SKILL.md beat.sh ~/.claude/skills/cachebeat/

Or project-level: copy both files into <your-project>/.claude/skills/cachebeat/.

That's the whole setup — two small files: the skill, and the watcher script its hook runs. Then in any Claude Code session, type /cachebeat and you're done. There is nothing to approve: hooks don't ask for permission, and Claude never runs a command for it.

Requirements: a recent Claude Code (tested on 2.1.288) with hooks enabled — skill-frontmatter hooks and asyncRewake are standard features, but an organization policy that disables hooks (disableAllHooks, allowManagedHooksOnly) also disables cachebeat.

Usage

/cachebeat            # fire after 50 min of inactivity, auto-stop after 8 h
/cachebeat 40         # custom idle threshold in minutes (clamped to 5–55)
/cachebeat 40 4       # custom threshold + auto-stop after 4 h
/cachebeat stop       # stop it

You can also just ask Claude ("keep the cache warm while this trains") — it invokes the skill for you.

Verifying it's working

You don't have to take it on faith — you can watch the cache stay warm.

  • The heartbeat itself. When a beat fires you'll see a ⏺ cachebeat heartbeat line and Claude answering . — proof the timer is alive and resetting the TTL. If instead Claude tells you cachebeat stopped itself, the beat fired on schedule but the cache had still expired: your session's TTL is too short for any heartbeat to bridge.

  • The status line. Claude Code's token readout looks like tok:312.0k/0.0k — total / served from cache. When you return to an idle session, the second number should be a large fraction of the first (warm). If it reads …/0.0k, the whole context was re-read uncached — the cache had died. With cachebeat armed on a long-TTL session, it should stay warm across your idle gaps.

  • The transcript (exact numbers). Every assistant reply records what it cost. Run this inside the session (prefix a shell command with !):

    F=$(ls ~/.claude/projects/*/"$CLAUDE_CODE_SESSION_ID".jsonl 2>/dev/null | head -1)
    echo "cache_read:     $(tail -n 400 "$F" | grep -oE '"cache_read_input_tokens":[0-9]+'     | tail -1 | grep -oE '[0-9]+')"
    echo "cache_creation: $(tail -n 400 "$F" | grep -oE '"cache_creation_input_tokens":[0-9]+' | tail -1 | grep -oE '[0-9]+')"
    

    A warm turn shows a big cache_read and a tiny cache_creation. A cold turn is the reverse — a large cache_creation means the context was rebuilt from scratch at full price.

How it works

The skill's frontmatter declares a Stop hook with asyncRewake: true. Claude Code registers it when you invoke /cachebeat, and from then on runs beat.sh in the background at the end of every turn. Each run is one inactivity timer. If the hook exits with code 2, Claude Code wakes Claude and shows it what the hook printed:

  1. A turn ends → the Stop hook starts a timer (and any older timer notices and exits).
  2. Every 30 s the timer checks when the last real model response was written to the session transcript (~/.claude/projects/<slug>/<session-id>.jsonl). A new response resets the clock.
  3. After N idle minutes it prints a one-line heartbeat note and exits 2 → Claude wakes, reads the conversation from cache (that read is the heartbeat), and answers ..
  4. That reply ends a turn → step 1. Claude never re-arms anything.

The heart of it:

while :; do
  sleep 30
  [ "$(cat "$S.pid")" = $$ ] || exit 0                  # a newer turn started a newer timer
  SIG=$(sig "$(last_resp)")                             # the last real model response
  [ "$SIG" != "$PREV" ] && { PREV=$SIG; LAST=$NOW; }    # new request -> reset the clock
  IDLE=$((NOW - LAST))
  [ "$IDLE" -ge $((N*60)) ] && { echo "idle heartbeat …" >&2; exit 2; }   # exit 2 wakes Claude
done
exitmeaningwhat Claude does
0nothing to say: not armed, stopped, superseded, or the cache is already coldnothing — no wake-up
2 + "idle heartbeat"the session sat idle for the thresholdreplies . (the reply's turn starts the next timer)
2 + "stopped itself"the last beat *sti

// HOW IT'S BUILT

KEY FILES

SKILL.mdREADME.md

// REPO STATS

70 stars