Claude Code · operational guide

Make cache timing visible.
Never miss a quiet finish.

A copyable, reversible, agent-executable setup: refresh a TTL estimate every 60 seconds and request checks with /loop 50m. Actual cadence can change through cron rounding, jitter, and busy-turn delays.

CONTESTED

TTL is not observable truth

The display is the last assistant record plus an assumed TTL. It is not a live Claude Code cache API.

PRESERVE

Preserve the existing statusline

The installer multiplexes the original command, makes a backup, and supports rollback.

SESSION-SCOPED

The heartbeat is not a daemon

/loop belongs to the current Claude Code session and is not a persistent scheduler.

Separate the mechanisms

They are related, but not interchangeable.

1. API cache TTL

Anthropic's API docs confirm a default 5-minute TTL and an extra-cost 1-hour option. They do not prove that every Claude Max or Claude Code session uses one hour.

2. Statusline indicator

The script finds the last type: assistant record near the transcript tail and adds a configurable TTL. Treat it as a heuristic.

3. Background heartbeat

50m is a requested value, not a strict interval. The heartbeat remains useful for missed completion notifications, but cannot guarantee a run before an assumed one-hour cache expiry.

4. Overage claim

The claim that Max uses one hour and overage falls back to five minutes lacks a stable public specification. Keep it contested and never infer account state automatically.

Configure the statusline

Prefer giving agent-setup.md to an agent. The manual path follows.

1

Download the release assets

tmp="$(mktemp -d)"
cd "$tmp"
curl -fsSLO https://claude-code-cache-heartbeat.pages.dev/assets/ttl_statusline.py
curl -fsSLO https://claude-code-cache-heartbeat.pages.dev/assets/statusline_mux.py
curl -fsSLO https://claude-code-cache-heartbeat.pages.dev/assets/install_statusline.py
2

Run a dry check first

python3 install_statusline.py --check

This reports the plan without modifying files or printing the existing command body.

3

Apply and verify

python3 install_statusline.py --apply
python3 install_statusline.py --verify

The installer backs up ~/.claude/settings.json, preserves an existing command through a mux, and sets refreshInterval: 60.

Do not replace the whole settings.json. Only the statusLine object should change. Preserve hooks, permissions, plugins, and project settings.
Executable trust boundary: the mux uses /bin/sh only to re-execute the pre-install command with its existing semantics. Status JSON is stdin data, not interpolated command text. Stop if that command's origin is not trusted. --verify checks the mux-config hash and requires mode 0600 on settings, config, receipt, and backups.

Resulting core configuration

{
  "statusLine": {
    "type": "command",
    "command": "python3 ~/.claude/claude-cache-heartbeat/statusline_mux.py",
    "refreshInterval": 60
  }
}

Existing keys such as padding and hideVimModeIndicator are preserved.

Change the assumed TTL

# 5-minute heuristic
export CLAUDE_CACHE_TTL_SECONDS=300

# 1-hour heuristic (default)
export CLAUDE_CACHE_TTL_SECONDS=3600

This only changes the display heuristic; it does not alter server-side cache policy.

Rollback

python3 install_statusline.py --uninstall

How it works

Claude Code status JSON (stdin) | transcript_path v statusline_mux.py --> original statusline command (preserved) | +-----------> ttl_statusline.py | tail read 256 KiB -> 4 MiB | parse JSONL; last type=assistant v ttl~ HH:MM or TTL estimate expired
Why refreshInterval: 60 is required: official docs state event-driven updates can go quiet while idle. Without a timer, a time-based segment freezes.

Approximate 50-minute heartbeat (requested cadence)

Use it for a long-running task in the current session when completion notifications may be missed.

/loop 50m Cache/heartbeat check-in. If a background task is running, do a quick non-blocking peek at its progress and report anything notable. Stop this loop once the task is done, or after 3 consecutive checks with no completion and no new progress. Otherwise reply "ok".
Not a strict 50-minute interval: Claude converts intervals to cron and may round to a representable cadence. Recurring tasks that run more often than hourly also receive deterministic jitter up to half the interval. A busy current turn delays them further. The loop therefore cannot guarantee a refresh before a one-hour TTL. After creation, read Claude's confirmation and list scheduled tasks to verify the actual schedule and job ID.

Keep each check non-blocking

Read process state or new output. Do not turn the heartbeat itself into another long wait.

Two stop conditions

Stop immediately when complete; also stop after three observed checks with neither completion nor new progress. Rounding, jitter, and busy-turn delay mean this is not a fixed 150 minutes.

Lifecycle: /loop is session-scoped. Unexpired tasks can return with --resume/--continue; recurring tasks fire once more and delete themselves seven days after creation. Use a durable scheduler across sessions, restarts, or longer periods.

Verification checklist

CheckExpected
python3 install_statusline.py --verifySettings, mux, TTL script, and receipt pass
Send a message and observeA dim ttl~ HH:MM segment appears
Wait 60 to 120 secondsThe time-based segment is timer-refreshed
Short TTL testTemporarily set CLAUDE_CACHE_TTL_SECONDS=60; the segment becomes a red block after expiry
Original statuslineExisting model, quota, git, or other segments remain
After heartbeat creationConfirm Claude's actual cron cadence and job ID; do not assume strict 50m
HeartbeatThe loop stops after completion or three observed no-progress checks; recurring tasks last at most seven days

Agent entry points

llms.txt

Discovery entry, claim boundaries, and resource map.

guide.md

The complete Markdown guide.

agent-setup.md

Execution contract: inspect, check, backup, apply, verify, rollback.

manifest.json

Machine-readable files, versions, and claim status.

Evidence and limitations

Sources checked on 2026-08-06. Claude Code and cache behavior can change; an executing agent should re-check official docs.