@diousk/pi-warm-cache0.2.8
Pi extension that keeps supported provider prompt caches warm during long idle gaps
Untested on omp
This is a pi package. No one has reported whether it works on omp yet. If you try it, add your result below.
Reports 0
No reports yet.
Readme
pi-warm-cache
Keeps supported provider prompt caches warm during long idle gaps in Pi sessions.
Large prompts often sit in a provider cache. That cache expires if you leave the session idle. The next turn then pays a cold read or a costly rewrite. This extension sends a small keepalive probe before that is likely to happen.
The minimum supported Pi version is 0.85.1. CI runs tests, type checks, and lint against the supported versions listed in the workflow and the latest stable release on each push to main and pull request. The latest job resolves one version for all three Pi packages. Development dependencies remain pinned to 0.85.1; newer Pi-only APIs are isolated behind a compatibility layer. Future releases are considered validated only after their compatibility checks pass.
Pi 0.86 native cache warming
Version 0.2.6 uses an explicit mode to choose one owner for main-session
warming. idle, tools, and both let this extension manage scheduling;
off stops both extension and native session warming while the extension is
loaded. These modes veto native warming even on unsupported routes, or while
extension limits pause probes. Use mode=native to delegate to Pi's
cacheWarming setting. On Pi 0.85.1 that mode has no native warmer to invoke.
/warm status shows ownership, which does not imply a scheduled probe.
Unloading the extension restores Pi's own policy; no Pi settings are modified.
Legacy JSON with enabled: false migrates to mode: "native", preserving its
old native-delegation behavior. A migration notice explains that the new
/warm off alias now means mode=off. An already-dispatched native request
cannot be cancelled by the decision hook; the veto applies to future decisions.
Native warming reuses the provider-request hook without starting an agent turn.
The extension fences requests following a native decision until the next real
turn, so native probes do not reset its anchor, idle cutoff, or spend ledger.
Pi uses the last decision override: another extension loaded later can override
our stop. Avoid competing decision handlers, or disable Pi's native warmer
explicitly when strict single-warmer ownership is required.
Advisor recognition resolves the effective prompt and tools through Pi 0.86's transcript helpers when available, with the 0.85.1 fields as fallback. Custom prompts and effective nonempty tool inventories still fail closed.
How it works
The extension copies the last real provider request and replays it with provider-legal output controls. Supported direct OpenAI Responses models use no-output prewarming; most other routes use a tiny output limit. The Codex endpoint rejects output-limit fields, so exact Codex replay is deliberately uncapped and protected by an oversized-output guard. Native API replay does not rebuild the conversation. The optional Claude Code bridge adapter instead refreshes a shared prefix in an isolated, unsaved SDK fork. It does not change your real turns. It does not run tools.
Automatic keepalive runs only on verified routes. After compaction, a model change, a thinking-level change, or a branch change, it waits for the next real turn before probing again.
Savings numbers use only the prices on the active model.
If those prices are missing, the status shows n/a.
Install
pi install npm:@diousk/pi-warm-cache
Restart or reload Pi after install.
Commands
Type /warm (with a trailing space) to see the available commands and settings
with descriptions. Keep typing to filter the menu; duration and limit suggestions
can be edited before submitting.
/warm # show status and savings
/warm config # show effective runtime configuration and JSON file path
/warm status # show warm statistics and status
/warm savings # show only the savings summary
/warm mode=both # warm while idle and during eligible tools (default)
/warm mode=idle # warm only while idle
/warm mode=tools # warm only during eligible tools
/warm mode=off # stop extension and native session warming
/warm mode=native # delegate to Pi native policy (0.86+)
/warm on # alias for mode=both
/warm off # alias for mode=off
/warm interval=auto # follow the provider refresh cadence
/warm spend=2 maxidle=30m
/warm mode=idle scope=session # temporary override; no file write
/warm now # send one probe when the current route allows it
/warm resume # clear a sticky automatic-warm block
/warm codex-on # enable Codex timer warming
/warm codex-off # disable Codex timer warming
/warm codex=auto # adapt after a suffix branch miss (default)
/warm codex=exact # replay Codex exactly (output is not hard-capped)
/warm codex=suffix # keep the bounded OK-suffix replay
/warm auto # alias for interval=auto
/warm log # write a local diagnostic log
/warm nolog # stop the diagnostic log
/warm interval=3.5m max=2 maxidle=2h spend=2.5
/warm tools=gradle toolmin=3m toolmax=6
You can also set this when Pi starts:
pi --warm-cache
pi --warm-cache=off
pi --warm-cache="mode=both interval=auto"
What stays warm
Automatic keepalive is on for these registered routes:
| Route | What you get |
|---|---|
| Anthropic | Probe about every 4 minutes, or about every 48 minutes when the request already uses a 1-hour cache |
Claude Code / claude-bridge (experimental adapter) |
Session-scoped SDK prefix warming, including long Pi tools; requires the cooperating bridge patch, not the stock npm bridge |
| OpenAI | No-output prewarm on supported GPT-5.6+ Responses models; capped replay on older models |
| Azure OpenAI | Same OpenAI response strategy |
| OpenAI Codex | Adaptive replay by default; switches from the bounded suffix to exact replay when a suffix hit is followed by a comparable real-turn miss |
| GitHub Copilot | Automatic warming for keyed Responses, Completions, and Anthropic models whose captured request contains cache markers |
| xAI Grok 4.5 | Best-effort probe about every 4 minutes when the request has a stable cache key |
| OpenCode Go (default setup) | Keepalive on short Anthropic and keyed Responses routes; no timer on Completions because that cache already lasts a long time |
GPT-6.1 Sol (Pi 0.99.1+)
On direct OpenAI Responses, GPT-6.1 Sol uses
prompt_cache_options.prewarm: true for probes, refreshing the cache without
generating output. Existing TTL, caching mode, breakpoints, cache key, reasoning,
tools, and input are preserved; real requests are never changed. Pi's explicit
cache capability flag selects this behavior, not a model-name allowlist.
The same documented prewarm mechanism applies to supported GPT-5.6+ models.
The cache lifetime is at least 30 minutes after the latest write or reuse, with
a refresh at about 24 minutes when using /warm auto (an explicit interval
still overrides the provider cadence). Sol cache reads cost 5% of uncached
input and writes cost 125%; savings estimates use the active Pi catalog's base
prices rather than hardcoded model rates. Cacheable prefixes must have
at least 1,024 tokens. A cold prewarm still incurs a cache-write charge.
This no-output mechanism is restricted to openai / openai-responses at
https://api.openai.com. Azure, proxy routes, and the legacy OpenAI Codex
subscription endpoint retain their existing replay policies; the OpenAI API's
prewarm field is not assumed to work there.
If OpenAI returns a parameter-rejection HTTP 400 for a probe's newly added
prompt_cache_options, the extension retries once with a small output cap and
uses the older implicit-cache cadence for that model/endpoint until reload.
The downgrade survives new real turns and model switches, but does not affect
other routes or change Pi's model metadata. Existing cache options captured
from real requests are never stripped, and unrelated API errors are not retried.
Sources: OpenAI prompt caching and GPT-6.1 Sol. The Pi 0.99.1 host test verifies the catalog prices and real Responses adapter with mocked HTTP responses for both cache reads and writes. It is not a live provider cache-hit guarantee.
/warm now is a one-shot probe.
It does not start a timer.
These routes allow /warm now only:
- Other first-party xAI models, when the captured request is safe to replay
- OpenRouter, on the registered OpenRouter endpoint
- Some non-default OpenCode Go retention settings
Unlisted proxies and other compatible APIs stay off. The extension will not call the provider for those routes.
GitHub Copilot is registered as its own mixed-API provider. Responses models
must have a stable prompt_cache_key; Anthropic models must have on-wire
cache_control markers. Copilot models that fail either payload gate remain
off, as do Copilot-compatible custom endpoints. Available Copilot models still
depend on the user's Copilot plan and model policy. /warm codex-on applies
only to the separate OpenAI Codex provider; it does not control Copilot timers.
New installations default to interval=auto: the captured provider route
selects the cadence (for example 4 minutes for short Anthropic caches, 48
minutes for a captured one-hour cache, or 24 minutes for supported direct
OpenAI prewarm). Explicit intervals override the cadence, but never override
retention or safety gates. This setting does not change the cache TTL itself.
Legacy JSON retains its saved interval, or its previous 4-minute default when
omitted. Use /warm auto to deliberately switch it to automatic cadence.
Copilot Responses/Completions use a best-effort 4-minute probe interval by
default (an explicit intervalMs overrides it). This is not a guaranteed TTL,
including for non-OpenAI models served through OpenAI-compatible transports.
If the captured request asks for prompt_cache_retention: "24h", automatic
probes are suppressed even with an interval override; this does not prove the
gateway honored retention. Anthropic uses its captured cache markers (about
4 minutes for short retention, 48 minutes for a 1-hour marker).
Copilot support has unit-test coverage, not live cache-refresh validation.
The internal verified route classification means registered replay eligibility,
not a live-tested TTL or a guarantee of savings. Pi 0.85.1's normalized usage
does not expose the Copilot SDK's cacheExpiresAt, so this extension does not
schedule from that SDK field. Existing miss and spend safeguards still apply.
See Copilot SDK usage events
and Microsoft's Copilot caching article.
xAI Grok 4.5 keepalive is best effort. The 4-minute cadence is not a provider TTL promise. If probes keep returning no cache read, warming stops until the next real turn.
OpenCode Go must use the registered endpoints: Anthropic at https://opencode.ai/zen/go, and OpenAI-style APIs at https://opencode.ai/zen/go/v1.
Pi's newer https://opencode.ai/inference/go and /inference/go/v1 endpoints support explicit manual probes on the same three transports. They remain unverified: automatic warming stays off and savings are not claimed until cache evidence is recorded for those endpoints. The Google transport is unsupported.
Azure Responses recognizes both the current azure provider and its older azure-openai-responses name.
Claude Code via pi-claude-bridge
The optional bridge adapter setup and validation guide uses Claude Code's existing login and official Agent SDK. Stock bridge 0.9.0 is not enabled just by updating this package; it needs the supplied versioned adapter patch. The normal session stays unchanged and probe tools are inert.
It shares /warm settings and the normal scheduler. The bridge uses actual SDK
cache-write usage to distinguish a 1-hour-only prefix (normally refreshed at
50 minutes) from a 5-minute/mixed or unknown prefix (at most 4 minutes). An
explicit /warm 5m keeps the short cadence. The 15-second UI updates,
long-tool policy and two-consecutive-miss stop still apply. Unlike
native Messages API replay, probes may use more than one output/thinking token
to preserve Claude Code's implicit cache identity. SDK usage consumes quota;
zero bridge prices do not mean free requests. See the guide before enabling.
Current Claude models (native Messages API)
Claude Fable 5.1, Opus 5.5, Sonnet 5.5 and Haiku 4.5 use the existing Anthropic Messages replay path; no extension model whitelist is required. Pi must still register the selected model. This extension does not ship or replace Pi's model catalog; update Pi or configure a custom model if its ID is absent. Provider/endpoint safety checks remain unchanged.
Automatic warming uses the greater of minCachedTokens (default 512) and
the known Claude model minimum:
| Claude models | Minimum tokens |
|---|---|
| Fable 5.1 / 5, Mythos 5.1 / 5, Opus 5.5 / 5, Sonnet 5.5 | 512 |
| Opus 4.8 / 4.1 / 4, Sonnet 5 / 4.6 / 4.5 / 4 | 1,024 |
| Mythos Preview, Opus 4.7, Haiku 3.5 | 2,048 |
| Opus 4.6 / 4.5, Haiku 4.5 | 4,096 |
Dated IDs and dotted aliases are recognized. Unknown models and non-Claude
Anthropic-compatible models retain the configured threshold. /warm status
shows the effective minCachedTokens; /warm config shows the saved setting.
Below the effective threshold, comparable real turns are classified unknown
rather than misses, and automatic probes are skipped. /warm now remains a
manual diagnostic probe. Total prompt usage is only an eligibility hint:
the prefix ending at a cache breakpoint must itself reach the minimum.
Claude deadlines count from request start, including time spent generating the response. For example, a three-minute response leaves about one minute until the default four-minute refresh. An overdue refresh is scheduled as soon as eligible. The same timing applies to independent rpiv-advisor requests and to the probes themselves. Tool minimum-runtime, concurrency and other safety gates can still delay a refresh beyond the TTL; warming is not guaranteed while those gates apply. Other providers retain their existing cadence.
Captured block-level and top-level automatic cache_control settings, thinking
and output_config.effort are replayed unchanged. The extension never adds
another breakpoint or upgrades the request to a 1-hour TTL. It retains the
stream-compatible one-token probe (or the legal thinking-budget minimum).
Claude's zero-output max_tokens: 0 prewarm mode cannot be used with Pi's
current streaming adapter, so it is not enabled here.
See Anthropic prompt caching and the Claude model overview.
When this helps
Use it when a supported route holds a large prompt and you often leave Pi idle long enough for the cache to expire.
It does not help when:
- The prompt is below the effective minimum cached-token threshold (default 512, raised for known Claude models)
- The route is unsupported or manual-only (no timer)
- The model has no usable prices (savings show
n/a) - You just compacted, changed model, or changed thinking level (wait for the next real turn)
Configuration
Independent @juicesharp/rpiv-advisor warming (experimental)
/warm advisor=on opts in to warming the independent advisor tool provided by
@juicesharp/rpiv-advisor; /warm advisor=off disables it. This setting applies
only to that rpiv-advisor integration, not arbitrary subagents or advisor-like
tools. It persists as warmAdvisor in the usual configuration file and defaults
to false. /warm status includes a separate rpiv-advisor status. /warm now
still probes only the main agent, not rpiv-advisor.
This bridge targets Pi 0.85.1's private modelRegistry.runtime.completeSimple
path and the stock rpiv-advisor system prompt fingerprint. It does not modify
rpiv-advisor files. Unknown/custom prompts, ambiguous parallel tool executions,
legacy global completion paths, and unavailable runtimes are not captured.
Custom authentication/environment/fetch overrides are also skipped, rather than
silently replayed with different credentials or routing.
The normal rpiv-advisor response is preserved. The runtime wrapper is removed on
shutdown and is not installed twice on the same runtime.
For recognized requests, a missing session ID is supplied before dispatch, so
rpiv-advisor's real requests and probes share a stable cache identity distinct
from the executor. Existing IDs and explicit cacheRetention: none are respected.
This changes cache routing for opted-in requests, not their conversation content.
Each completed successful rpiv-advisor request supplies an independent payload
and timer. Codex rpiv-advisor warming caps the effective interval at three minutes because live
tests found the four-minute boundary could already miss; a shorter configured
interval is preserved. Other advisor routes use the configured interval;
Claude advisor deadlines count from the original request's dispatch, not its completion.
Provider eligibility, idle cutoff, output,
failure, spend, and process-wide concurrency safeguards still apply. rpiv-advisor
probes do not enter session history and do not invoke advisor tools.
Probes preserve the chosen transport and timeout/retry settings, but use their
own cancellation signal and do not invoke callbacks belonging to the real call.
For Codex rpiv-advisor requests, probes replay the captured endpoint exactly
instead of appending the main-agent OK suffix. The stock rpiv-advisor prompt
already constrains its answer, and exact replay refreshes the endpoint future
rpiv-advisor calls extend.
Main-agent Codex warming uses codexWarmMode: "auto" by default. It starts with
the bounded OK suffix because the Codex route has no hard output-token cap. If
the provider reports a hit for that suffix but the next comparable real turn has
no cache read, the extension records the branch as unsafe and uses exact replay
for subsequent probes. Set /warm codex=exact to force exact replay from the
first probe, or /warm codex=suffix to retain suffix replay. If an adaptive
exact probe returns 256 or more output tokens, warming falls back to suffix and
does not automatically promote to exact again for the rest of that Pi session.
The /warm status output shows exactFallback=paused. Repeated oversized
responses still block automatic warming to protect against excess token use;
explicit /warm codex=exact keeps the existing two-spike safeguard.
The rpiv-advisor idle cutoff is measured from its own captured request, not
executor activity. Its timer is independent of the main agent's tool-batch probe
count. New rpiv-advisor executions, session changes, compaction, and shutdown
invalidate old captures. Changes to the persisted rpiv-advisor selection or an
inactive advisor tool are checked before a scheduled probe; they stop further
probes. Status is exposed through /warm status, without replacing the main
agent's widget.
Coverage includes simulated provider replay, stable identity, request isolation,
callbacks, cancellation fencing, selection changes, idle cutoffs, and cleanup.
An end-to-end Luna/Codex test with unmodified rpiv-advisor 2.10.1 verified that
an exact-replay probe at the three-minute cadence rebuilt the cache and the next
real advisor call read 4,864 cached tokens. The probe itself reported zero cache
reads in that run; that means it created a new cache entry, not that warming
failed. Provider reuse and net savings remain best-effort rather than guaranteed,
and the feature consumes additional model usage. Do not add API-only
prompt_cache_options or prompt_cache_breakpoint fields to this Codex route:
the tested endpoint rejects them.
Create ~/.pi/agent/warm-cache.json with the v2 format, or use /warm commands:
{
"schemaVersion": 2,
"mode": "both",
"tools": "all",
"interval": "auto",
"maxIdle": "30m",
"spend": 2,
"showWidget": true,
"warmAdvisor": false,
"warmModels": [],
"toolWarmMinRuntimeMs": 180000,
"toolWarmMaxProbes": 6
}
mode selects when to warm; tools selects eligible tool names ("all"
or an array such as ["gradle", "bash"]). No second tool boolean is needed.
interval accepts "auto" or a duration such as "4m". maxIdle accepts
"auto", a duration, or "unlimited". spend accepts "auto", a nonnegative
USD number, or "unlimited". Auto spend means $1 on OpenCode Go and no ceiling
elsewhere. Limits are per provider per warming campaign within one process,
not an account-wide budget. Legacy command spend=0 / maxidle=0 aliases
remain accepted for unlimited; prefer the explicit word.
Commands validate the entire change before applying it. By default they save
only the requested settings, merging against the latest disk file under an
exclusive lock and atomically replacing it. Unrelated CLI, environment and
session overrides are not saved. Use scope=session to apply without saving.
A validation or save failure leaves live settings unchanged. A busy lock is
reported for retry; after a crashed writer, remove its stale .lock file only
when no writer is active. Other running sessions keep their runtime settings
until reload. No provider requests are needed to change configuration.
Precedence: defaults, saved JSON, environment debug flag, CLI, then runtime
commands. The file is loaded on session start/reload. Invalid JSON stops
extension and native session warming until corrected and reloaded. Read-only
commands, /warm now, and standalone /warm resume do not save settings.
Legacy JSON remains readable. Migration preserves limits, model filters and
saved intervals; omitted legacy intervals retain 4 minutes. An explicit old
tool allowlist without warmAllTools now restricts tools, with a migration
notice. Explicit warmAllTools: true remains all-tools. Legacy disabled state
becomes mode=native; the next saved command writes v2. Do not mix legacy
keys (enabled, warmAllTools, warmDuringTools, intervalMs,
maxIdleWarmMs, warmSpendCeilingUsd) into a v2 document. Older extension
versions cannot read v2; keep a copy of your legacy file before downgrading.
Automatic warming stops after two consecutive probe failures by default. A new
real turn resets the failure streak; set maxConsecutiveFailures in the JSON
configuration to change this retry budget.
Other advanced keys retain their names from WarmCacheConfig in
src/types.ts. Unknown keys and invalid values are rejected. The old 5m,
1h, and ttl= commands are deprecated preferences, not cache-TTL controls;
they remain accepted with a notice. Set Pi/provider retention on real requests
and use interval=auto for the corresponding refresh cadence.
Useful tokens for /warm and --warm-cache:
| Token | Meaning | Default |
|---|---|---|
mode=both|idle|tools|off|native |
Phase and ownership policy | both |
on / off |
Aliases for mode=both / mode=off | both |
auto / interval=auto |
Provider refresh cadence | auto |
interval=4m |
Explicit refresh interval | unset |
scope=session |
Do not save this command | saved |
codex=auto|exact|suffix |
Codex replay policy: adapt, exact endpoint replay, or legacy bounded suffix | auto |
max= |
Max concurrent warm sessions | 3 |
maxidle= |
Stop after this idle time; unlimited removes the cutoff |
about 30 minutes, or longer for 1-hour families |
spend= |
Probe-spend ceiling in USD; unlimited removes the ceiling |
$1.00 on OpenCode Go only |
model= |
Restrict warming to one or more selectable provider/model-id values; model=all resets |
all models |
log / nolog |
Local JSONL log | off |
tools= |
Tool policy: all, an exact tool name, gradle, or off |
all |
tools=all |
All tool names and commands ("tools": "all" in v2 JSON) |
all |
toolmin= |
Minimum matching-tool runtime before warming | 3 minutes |
toolmax= |
Maximum probes per uninterrupted tool batch | 6 |
advisor=on / advisor=off |
Warm the independent @juicesharp/rpiv-advisor tool (experimental) |
off |
mode=both and mode=tools allow tool warming; tools=all is the default
selector. Use /warm tools=gradle or /warm tools=ask_user_question to restrict
it. The legacy /warm tools=off alias clears the selector (no eligible tools)
but does not change the mode or idle policy. Selecting tools never enables a
disabled mode. Independent advisor warming is still opt-in; its completed
requests use the idle phase, so tools-only mode does not schedule advisor probes.
Model warming includes all models by default ("warmModels": []). Type
/warm model= to browse models selectable in the current Pi session; choices
show provider/model id, model name and catalog input/cache-read prices when
available. Selecting a model narrows warming to that model; repeat model=
with another choice to add it. Use /warm model=all to clear the allowlist and
return to all models. This filter applies to the active Pi model and independent
rpiv-advisor probes, and is saved in ~/.pi/agent/warm-cache.json. On Pi
versions with native warming, the extension also prevents native warming from
bypassing an explicit model exclusion while the extension is enabled. This is
an allowlist, not a fan-out: only the active request model with a valid real-
turn cache anchor can be warmed; other listed models become eligible when
selected in Pi.
The minimum runtime, probe count, idle cutoff, spend/route gates and payload
revision fencing still apply. Tools must actually be executing; model
generation alone is not eligible. This mode also includes browser, custom
tools and subagents, which may themselves make network/model requests that
the parent extension cannot observe. Use /warm tools=gradle to narrow the policy
or /warm tools=off to disable tool warming. The extension never executes tool
calls returned by a warm probe.
The v2 tools array accepts exact Pi tool names such as
"ask_user_question". Exact names are matched case-insensitively; only selected
names and presets are eligible unless tools is "all".
The Gradle shell preset accepts a single gradle, gradlew, or ./gradlew
command with plain arguments, optionally prefixed by cd android && (or
another literal directory). Quoted arguments, substitutions, pipelines,
background jobs and trailing commands are deliberately rejected. For example,
./gradlew build is eligible but ./gradlew --version; sleep 3600 is not.
Changing /warm settings during a tool run preserves its lifecycle tracking.
When real work resumes, an outstanding probe is cancelled and any late result
is ignored; cancellation is not counted as a provider failure. Cancellation
cannot guarantee that the provider stops processing or billing the request.
The 1-hour Anthropic mode follows the cache retention already on the Pi request. This extension does not add 1-hour markers to your real turns.
/warm now ignores the idle cutoff and the spend ceiling.
Status and savings
/warm config shows the current effective settings, including startup JSON,
CLI and runtime overrides, not a fresh read of the config file. It also shows
the config file path, mode, source summary, readable limits, v2 JSON and the
resolved strategy/pause reason. Saved settings can differ from running overrides.
/warm status and bare /warm are read-only equivalents:
they report lifecycle, route, tool policy, next probe, hits/misses, probe cost,
estimated savings, failure/deferral state and the last attempt. These commands
do not toggle warming, reset counters, change timers or send a probe.
/warm shows whether warming is active, the current route, the next probe time, and a savings summary.
The single live widget above the input field shows Cache warming active and
an integer minutes/seconds countdown such as Next refresh in 2m 45s, updated
every 15 seconds. No duplicate warming text is shown in the bottom status bar.
While the agent is working without an eligible tool-warming schedule, the widget
shows Cache warming standby · Agent working. Warming remains enabled and resumes
automatically when eligible; cancelled countdowns are replaced in the widget.
showWidget: false (or /warm nowidget) hides the persistent warming UI entirely;
/warm status remains available for on-demand diagnostics.
During tools, standby explains why no refresh is scheduled: tool warming is off,
a tool (including a parallel sibling) is not eligible, the tool refresh limit
was reached, or the cache anchor changed. Changing /warm tools=… immediately
re-evaluates running tools without resetting their start time or refresh count.
After the first warming response, it shows Cache hits: M · Misses: N for
warming requests only; request errors are reported separately. Estimated
savings are omitted from the live widget and remain available in /warm savings.
probeHits and probeMisses count extension probes only, not your real turns.
OpenCode Go savings are subscription budget-dollars, not a card invoice.
Enable a local log with /warm log or PI_WARM_CACHE_DEBUG=1.
The file is .pi/warm-cache.jsonl in the working directory.
It stores route names, counts, and redacted fingerprints.
It does not store prompts or API keys.
/warm log (or /warm log=on) now also records main-agent cache diagnostics;
/warm log=off stops logging immediately and clears the diagnostic baseline.
You do not need the standalone diagnostic extension or a preload script.
cache_diagnostic_request: SHA-256 settings/key fingerprints and whether the previous serialized prefix, settings or model route changed. Captured after all request-rewriting hooks, not from an intermediate payload.cache_diagnostic_response: raw Responses/Codex cache usage, response ID, previous response ID, returned model/tier, and a conservative reason label.cache_diagnostic_http: only status andx-request-id, when exposed by Pi.
An explicit zero is cachedTokens: 0; missing/invalid usage is null and is
never treated as a confirmed miss. cachedTokensPresent separately records
whether the raw field existed. provider_zero_cache_unknown_cause means the
provider returned zero while the observed prefix and settings stayed stable;
it does not prove eviction, routing, TTL expiry, or a billing error.
settings_changed, prefix_changed, and route_changed identify observed
differences, not a provider-confirmed root cause. no_prior_request means there
is no comparison baseline since logging started, not necessarily a cold cache.
Hosts/providers without the raw Responses stream event log
raw_response_unavailable instead. Existing normalized usage/probe logs remain
available. These new events cover real main-agent requests, not advisor/native
warming or extension probes, and do not alter their counters or behavior.
Connection counters still require the optional standalone preload; normal
/warm log does not claim to know backend routing or WebSocket reuse.
Correlation IDs are intended for private support reports. Full prompts, model
output, authorization, cookies, and other HTTP headers are not stored by these
diagnostic events.
Common cases
- After compaction or a model change, wait for the next real turn.
- If the agent is busy at a tick, that probe is deferred.
- With
tools=gradle, an exact captured request may be replayed while a matchinggradle/gradlewshell command runs. Unallowlisted parallel sibling tools, a new provider request, compaction, branch/model changes, or the probe limit stop in-tool warming. - Session resume waits for the first real turn.
- In print or RPC mode, warming can still run; the widget is hidden when there is no UI.
- Codex can pause automatic warming if probe output is repeatedly huge; use
/warm resumeor/warm codex-off.
License
MIT
This repository is derived from ribbons-digital/pi-warm-cache. Original copyright and license notices are retained.