CacheWarm v0.5.2

Reference / schema 2

Every setting, scope, and state.

The configuration surface of Cache Warm v0.5.2, generated from scripts/lib.mjs and the plugin manifest. Defaults below are the values the code ships with.

Plugin v0.5.2 Config schema 2 Source scripts/lib.mjs

01 Resolution

Most specific scope wins.

Each session resolves every setting from the first scope that defines it. Values that are unset simply inherit. Two scopes can never accidentally change each other's surfaces: inside a Claude Code session, an unscoped ccw change applies to that session's surface only.

sessionoverrides › project folderfolder and below › surfacecli · desktop · ide › globalmachine › plugin taboptions › defaultsin code
# what this session actually uses, and where each value comes from
ccw config --session

# the same, for one scope
ccw config --desktop
ccw config --project

# every scope that currently holds a setting
ccw scopes
Surfaces come from the environment.

CLAUDE_CODE_ENTRYPOINT maps to cli; anything containing desktop to desktop; VS Code, JetBrains, Cursor and Windsurf entrypoints to ide. sdk-* runs — claude -p and the Agent SDK — are headless and are never registered or warmed.

02 Settings

8 settings, validated before they are written.

The first five are scoped. The rest make sense once per machine and can only be set at the global scope. Values are stored as JSON in ~/.claude-cache-warm/config.json; only explicitly set values are persisted.

enabled scoped

Warming on

Global master switch. Per-surface, per-project and per-session settings can override it (ccw or the dashboard).

Default
On
Accepted
boolean (the CLI also accepts true / false)
Set with
ccw on / ccw off
warmWhen scoped

Warm a session

background-work: only while a subagent, background task or scheduled task is pending (recommended). always: any idle session.

Default
background-work
Accepted
background-work or always
Set with
ccw when background-work
intervalMinutes scoped

Ping interval (minutes)

Counted from the conversation's last request. auto = 50 on a 1-hour cache, 4 on a 5-minute cache. Otherwise 1 to 59, shorter than the cache TTL.

Default
auto — 50 min on a 1h cache, 4 min on a 5m cache
Accepted
auto, or an integer from 1 to 59
Set with
ccw interval 30
maxIdleMinutes scoped

Stop after idle (minutes)

Stop pinging once nobody has typed and no real work has happened for this long. 0 = never stop.

Default
180 min (0 = never)
Accepted
number ≥ 0; 0 = never stop
Set with
ccw set maxIdleMinutes 180
minContextTokens scoped

Skip sessions below (tokens)

Small contexts are cheap to rebuild; do not warm them.

Default
20,000
Accepted
number ≥ 0
Set with
ccw set minContextTokens 20000
dashboardPort global only

Dashboard port

Local port for ccw dashboard.

Default
4777
Accepted
integer from 1024 to 65535
Set with
ccw set dashboardPort 4777
statusline global only

Status line segment

auto: add the cache segment to your status line (creating one if you have none). wrap-only: only add it to an existing status line. off: remove it and restore your original status line exactly.

Default
auto
Accepted
auto, wrap-only or off
Set with
ccw statusline auto
statuslineSegments global only

Status line parts

Comma-separated, in order. Available: model, folder, branch, pr, warm, context, cache, fill, limits, cost. cost is a list-price estimate, so it is off by default.

Default
model, folder, branch, pr, warm, context, cache, fill, limits
Accepted
comma-separated parts, each one of the available segments
Set with
ccw set statuslineSegments model,folder,warm

03 Plugin tab

Those options in /plugin are a real scope.

Claude Code passes plugin-tab values to hooks as CLAUDE_PLUGIN_OPTION_*. The SessionStart hook snapshots them, so the CLI, status line and dashboard can see them too. Editing a value in the tab makes it win over the override it would otherwise sit behind; untouched tab values never undo edits made with ccw or the dashboard. Edits apply immediately through the ConfigChange hook, and sleeping timers pick them up within a minute.

The tab exposes one extra convenience option that is not a stored setting:

desktopModeplugin tab only

Desktop app sessions

same-as-cli: follow the settings above. off / background-work / always: override them for sessions in the Claude desktop app only.

Default
same-as-cli
Accepted
same-as-cli, off, background-work or always

04 Status line

10 parts, in the order you choose.

Configure with ccw set statuslineSegments model,folder,warm, the plugin tab, or the dashboard's Global tab. Parts without data are omitted. Long lines wrap onto the next row at part boundaries. The segment wraps your existing status line — it never replaces it.

model

Model name, with the effort level when Claude Code reports it.

on by default
folder

Project folder, plus the subfolder you are in when it differs.

on by default
branch

Current git branch, read from .git without spawning a process.

on by default
pr

Open pull request number and review state.

on by default
warm

Warming state, next-ping countdown and pending background jobs.

on by default
context

Tokens currently in the context window.

on by default
cache

Tokens the last request read from the cache, and the percentage.

on by default
fill

Context-window usage as an amount and a percentage.

on by default
limits

5-hour and 7-day subscription usage, when available.

on by default
cost

List-price cost estimate. Opt-in: misleading on a subscription.

opt-in
# default order
ccw set statuslineSegments model,folder,branch,pr,warm,context,cache,fill,limits

# the segment itself: auto (default), wrap-only, off
ccw statusline auto
ccw statusline wrap-only
ccw statusline off        # restores every original exactly

05 States

What the waker decided, and why.

One function — computeStatus() — is the single source of truth. The waker acts on it; the CLI, status line and dashboard only display it. These are the states the code can return.

warming

Eligible and waiting; nextPingAt is set and the waker will exit 2 when it is due.

busy

A turn is in progress, so the conversation is refreshing its own cache. Nothing fires mid-turn.

no-work

The default background-work policy is on and nothing is pending in the background.

off

Warming is switched off at some scope that applies to this session.

small-context

The context is below minContextTokens; rebuilding it is cheap.

idle-cap

Nobody has been active for longer than maxIdleMinutes, and no background work is running.

ping-cap

The session already used its pings for this idle stretch (ceil(idle cap / interval) + 1, hard cap 24).

suspended

The last two verifiable pings missed the cache. Warming resumes when someone is active again.

expired

The cache TTL already elapsed. A ping now would be the expensive rewrite, so none is sent.

ended

The session ended or its process is gone.

06 Commands

Slash commands and the ccw CLI.

In Claude CodeShellWhat it does
/cache-warm:on [scope]ccw on [scope]Switch warming on.
/cache-warm:off [scope]ccw off [scope]Switch warming off.
/cache-warm:statusccw status [--all] [--json]Sessions, what each waits on, next-ping countdown, per-ping and cold-return estimates.
/cache-warm:config …ccw config [scope]Effective settings and the scope each value comes from.
/cache-warm:dashboardccw dashboard [--no-open]Start the loopback dashboard and open it.
/cache-warm:statuslineccw statusline install | auto | offInstall, configure or restore the status line segment.
/cache-warm:testccw testSelf-test this session: one verified ping a minute after the turn, settings restored.
ccw when <background-work|always> [scope]Choose the warming policy.
ccw interval <minutes|auto> [scope]Set the ping interval; auto follows the session's cache TTL.
ccw set <key> <value> [scope]Set any scoped key; global-only keys always write to global.
ccw unset <key> [scope]Drop one key at that scope so it inherits again.
ccw reset [scope]Drop every setting at one scope.
ccw scopesList every scope that currently holds settings.
ccw doctorHealth checks, including verified pings per surface.
ccw events [n]The most recent entries from the local event log.

bin/ccw is on the Bash tool's PATH. From a plain terminal, run node scripts/ccw.mjs <command>, or install the plugin's bin yourself.

07 Scopes

Change one session, one folder, one surface, or everything.

ccw interval 30 --global              # every session
ccw when always --desktop             # every Desktop-app session
ccw off --cli                         # every CLI session
ccw interval 20 --project             # this folder and everything below it
ccw set maxIdleMinutes 600 --session  # just this session
ccw config --session                  # effective values and their sources
ccw reset --desktop                   # that scope inherits everything again
ccw unset intervalMinutes --project   # drop one key at one scope
An unscoped change is not global inside a session.

Run inside Claude Code, ccw off in the Desktop app turns off Desktop sessions, not your CLI ones. Changing every surface at once needs --global. From a plain terminal, unscoped means global.

Scope words for slash commands

session, project, cli, desktop, ide — for example /cache-warm:off desktop or /cache-warm:on session.

08 Cost

One cache read versus one cache write.

The plugin estimates each ping and each avoided rebuild from list prices in its own source. It is an estimate, not a bill — on a subscription the same tokens come out of usage limits.

Ping tokens × input price × cache-read multiplier

Cache reads are 0.1× base input price, except Fable and Mythos 5.1 at 0.025×.

Rebuild tokens × input price × write multiplier

Cache writes are 1.25× for a 5-minute cache and 2× for a 1-hour cache.

For the worked example on the overview — 800K tokens on Opus 5 with a 1-hour cache — the estimator reports roughly $0.40 per ping and $8.00 per cold rebuild, a break-even of about 18 pings. With a 180-minute idle cap, warming cannot continue indefinitely; with maxIdleMinutes at 0 a hard cap of 24 pings per idle stretch still applies.

09 Limits

Bounds the code enforces.

  • Interval 1–59 minutes. It must stay shorter than the cache TTL; auto uses 4m on a 5m cache and 50m on a 1h cache. A fixed interval that is too long produces a warning in ccw status.
  • Idle cap. Pings stop after maxIdleMinutes with no human activity and no real work. 0 means no time cap.
  • Ping cap. At most ceil(maxIdleMinutes / interval) + 1 pings since the last activity. While background work is running, the idle cap and that formula do not apply, but the hard cap of 24 pings since activity still does.
  • Background trust. Work reported by the last Stop is trusted for 12 hours, so a completion notice that never arrives cannot warm forever.
  • Misses. 2 verified cache misses in a row suspend warming until someone is active again.
  • Expired cache. Never pinged: the ping would be the expensive rewrite.
  • Headless. claude -p and Agent SDK sessions are never registered.

Source of truth: scripts/lib.mjs. State files and the HTTP API are documented in docs/CONTRACT.md.