Security / architecture
Local by default. Explicit where it matters.
Cache Warm runs inside Claude Code, reads local transcripts, and exposes a loopback-only dashboard. It ships no server, no telemetry and no runtime dependencies. Here is exactly what it touches.
01 Trust model
A hook, a state directory, and a loopback server.
The plugin is ordinary Node.js launched by Claude Code. Its hooks always exit successfully and never block a prompt. It does not start a daemon, create scheduled tasks, or install a network service. The only listening socket is the optional dashboard, bound to 127.0.0.1.
Each hook error is written to the local event log rather than to stderr. The waker is the one deliberate exception: it exits with code 2 when a session should be woken, which is how Claude Code's asyncRewake hook contract works.
02 Files
What lives in ~/.claude-cache-warm/.
Override the location with CCW_HOME. Session state and settings are readable JSON; deleting the directory removes all plugin state.
| Path | Written by | Contains |
|---|---|---|
config.json | CLI, dashboard, tray, hook | Explicit settings per scope (schema 2). |
plugin-options.json | SessionStart hook | Snapshot of the plugin-tab options. |
sessions/<id>.json | hooks, waker, CLI, dashboard | Identity, activity clocks, background-work snapshot, overrides. |
sessions/<id>.state.json | waker, hooks | Ping history, the last ping's verdict, suspension, the current waker. |
statusline.json, statusline-launcher.mjs | ccw statusline | Status line installs and the launcher they point at. |
events.jsonl | everyone | Append-only local log, rotated at 4 MB. |
analytics-cache.json | dashboard | Incremental transcript parse cache. Safe to delete. |
config.v1.backup.json | migration | The pre-0.3 config, kept as a backup. |
Every JSON write is atomic (temp file plus rename, retried on Windows). Every read-modify-write holds a <file>.lock directory, stale after five seconds; writers give up after two seconds rather than stall a hook. The Rust tray app takes the same lock.
03 Transcripts
Read-only, and only the tail.
The waker reads the tail of the session transcript to learn the context size, model and cache TTL, and to judge whether the last ping was a cache read or a rewrite. The dashboard's analytics parse ~/.claude/projects/**/*.jsonl read-only and keep an incremental offset cache so a cold scan is never repeated. No transcript content is transmitted by the plugin.
04 Dashboard API
Reads are harmless; writes are fenced.
Any web page can fire requests at localhost. The server requires a loopback Host for every request. Write endpoints additionally require a same-origin (or absent) Origin and a JSON content type, which a cross-site form cannot supply without a preflight the server never grants. Responses carry cache-control: no-store and x-content-type-options: nosniff.
GET /api/health { ok: true, version }
GET /api/state scopes, sessions, folders, defaults
GET /api/analytics?days=7
POST /api/scope { scope, patch } or { scope, reset: true }
POST /api/config 0.2 compatibility: global scope
POST /api/sessions/<id> 0.2 compatibility: session overrides
The full file and API contract is in docs/CONTRACT.md.
05 Your settings
Settings files are user property.
- The status line installer backs up a settings file as
*.ccw-backupbefore its first change. - It never wraps its own launcher, never edits a shared project
settings.json, and never writes invalid JSON. offand uninstall restore the originals exactly.- The plugin does not need credentials and never asks for an API key.
06 Reporting
Found a problem?
Please report vulnerabilities privately via the repository's Security tab or the contact details in SECURITY.md. For ordinary bugs, open an issue.
The project is released under the MIT license.