← Back to blog

Content-Addressed Prompt Cache Keys: How Hermes Stops Cron Jobs Going Cache-Cold Every Tick

hermescroncachingoptimizationtokensinfrastructure
Content-Addressed Prompt Cache Keys: How Hermes Stops Cron Jobs Going Cache-Cold Every Tick

Recurring cron jobs were re-tokenising the same static prefix from scratch on every fire. Hermes Agent fixed it on June 25 by switching the Codex transport's prompt_cache_key from session_id to a content hash of the static prefix itself. The change is two files and 79 added lines. It turns a recurring cron job from a cache-cold request into a cache-warm one, every tick.

The fix landed in PR #52295, merged by @teknium1 at 2026-06-25T04:46Z. It closes the cluster on issue #51395.

What the fix does

Before the change, the Codex/Responses transport used session_id directly as prompt_cache_key. Cron builds session_id as cron_<job_id>_<timestamp>. The timestamp changed every fire, which changed the cache key every fire. The static prefix - agent identity, system prompt, tool schemas - was being re-tokenised cold on every tick even though it never changed.

After the change, prompt_cache_key is pck_<sha256[:24]> of the static prefix (tools sorted by name, \x00 separator to avoid instruction/tool boundary collisions). session_id is still used for transcript isolation, logs, and the session-scope routing headers - those keep their per-fire identity. Only the cache key is content-addressed.

Property Before After
Two cron fires, same job (diff timestamp) different key, cache cold same key, cache warm
Cache key value raw session_id content hash
Different job, different prompt n/a different key (no collision)
Codex transcript headers session_id session_id (unchanged)
Files touched 2 +79 / -8

Why it matters for cron

Prompt caching cuts input token costs by up to 90% and time-to-first-token by up to 80% on supported providers, but only when the cached prefix matches exactly[^1]. A cron job that fires every five minutes and goes cache-cold every fire is paying the full prefill cost every tick - 1,024+ tokens of agent identity, system prompt, and tool schemas, recomputed and re-tokenised each time. That is the entire point of prompt caching being defeated by a key that changes for no semantic reason.

The new key is stable across fires for any cron job whose static prefix is unchanged. Two consecutive ticks of the same job produce identical pck_ values and hit the warm prefix. A job whose prompt content actually changes gets a different key, which is the correct behaviour - different prompt, different cache, no false reuse.

What the fix deliberately does not do

The cache key is a routing hint, never a correctness boundary. A stale or shared key can only cause a cache miss, never a wrong result. The PR author flagged this in the scope note: the win is real but bounded by provider cache TTL (5-60 minutes depending on provider), so the fix primarily helps sub-TTL-interval jobs. Longer cadences are cache-cold by the next fire regardless, which is provider behaviour, not something this fix can address.

The change is also deliberately narrow. It touches only the Codex transport's _content_cache_key function and the prompt_cache_key assignment. It does not retroactively warm previously-cold jobs (each provider's cache lives at the provider) and it does not introduce a new cache layer on the Hermes side.

Cron-TTL math

The new behaviour creates a clear distinction between cadences:

  • Sub-TTL interval (e.g. every 1-30 minutes) - fires happen inside the provider's cache window. The static prefix stays warm. After the first cold fire, every subsequent fire reuses the cached KV tensors.
  • Above TTL (e.g. every 90 minutes) - provider cache expires between fires. Each fire re-tokenises the prefix cold. The new content-addressed key does not help here, but it does not hurt either.

For a cron job running every five minutes with a 60-minute provider TTL, the first fire pays full prefill. The next 11 fires hit the warm prefix. That is the cache hit rate jumping from 0% to ~92% on a 12-fire window, with corresponding cost and latency reductions on each warm hit.

Credit and provenance

The fix credits @spiky02plateau (issue author, #51396) and @JoaoMarcos44 for the content-hash key naming (#51585). Both credited as co-authors. The transport-level change itself is small because the diagnosis was correct: the cache was working, the key was wrong.

The PR description's infographic shows two adjacent cron fires with identical pck_ keys but different session_id values - the visual that nails the conceptual split. Transcript isolation keeps working, cache routing now works.

For anyone running cron jobs through Hermes with xAI or Codex-compatible providers, this fix is a free cost and latency win on every sub-TTL fire. No configuration change required at the operator level. The PR description's "Test plan" line - tests/agent/transports/test_codex_transport.py 60/60 green - covers the new key derivation and the session-id fallback path.

[^1]: @teknium1. "fix(cache): content-address prompt_cache_key so recurring cron jobs reuse the warm prefix." Hermes Agent. 2026-06-25. [^2]: Anthropic. "Prompt caching for Claude." 2026.

Termagotchi
_

Ryan Underdown

Autodidact. Rarely listens to advice.

Follow on X @catamarammed or GitHub @underdown