acpmux: start Claude Code on the one-hour prompt cache by default

Merged
TE
2d ago
+769-2

Summary

Claude Code keeps a chat's prompt cache for one hour only on a Claude subscription. On an API key, a custom ANTHROPIC_BASE_URL, Bedrock, Vertex or Foundry it caches for five minutes, and subagents cache for five minutes everywhere. Any pause longer than five minutes (reading a reply, a long tool call, a review) then rewrites the whole prompt at the cache-write price.

Leo (2026-11-03), on the measured gap: "holy sh** that's such a big win that cmux-next/acpmux can get....", and earlier the same day: "HOW DO WE GET THAT 1HOUR THING WE GOTTA GET IT NOW NOW NOW".

After this change acpmux starts every Claude Code chat on the one-hour cache:

  • prompt_cache_env.rs (new) fills CLAUDE_CODE_PROMPT_CACHE_TTL=1h, CLAUDE_CODE_SUBAGENT_PROMPT_CACHE_TTL=1h and ENABLE_PROMPT_CACHING_1H=1 in the spawn env (hub/spawn.rs, next to the tool-search default). Only variables that are still unset get filled, so a profile, route or person that names a TTL keeps it. Nothing is set under FORCE_PROMPT_CACHING_5M. Claude Code's settings-file env still wins over the process env, as it does for every variable.
  • New setting agents.promptCache (Settings > Agent Chat > Prompt Cache: 1 Hour / 5 Minutes, default 1 Hour). Help text: "How long Claude Code keeps a chat's prompt cached. One hour keeps replies after a pause cheap; its cache writes cost a little more." acpmux reads it at each Claude Code start, so a change applies to the next chat. 5m fills the two TTL variables with 5m. It is the person's setting (agentRefusedKeys, .userOnly): an agent can't change what its owner pays.
  • On a subscription this is the TTL Claude Code already picks, so nothing changes there.

Prior art: #33084 (open, ours) shows the cache countdown in the context card from the tier each call reports. It doesn't touch the spawn env. With this change, that card shows one hour for chats on any endpoint.

Generated settings exports (schemas/settings/settings-schema.json, docs/mdm/*, the defaults snapshot, the settings reference) are left to the PR autofix, as CLAUDE.md asks.

Performance

metricbefore (5 min)after (1 h)deltaharness or run link
Replay of 86K Claude Code calls, at $4 input / $5 5-min write / $8 1-hour write / $0.20 read per MTok~$6.8K~$5.3K-22%replay of recorded call usage; 3% of call gaps exceed 5 minutes
One cold call through a custom endpoint, cache-write tierephemeral_5m_input_tokens > 0ephemeral_1h_input_tokens: 80462, ephemeral_5m: 0all writes on the 1-hour tierclaude -p with the three variables set
Cache-read share, custom-endpoint sessions vs subscription sessions (~200 sessions)94.3% vs 98.1%pendingsession usage logs
Cost per call, custom-endpoint vs subscription sessions (relative units)~35.1K vs 27.5Kpendingsession usage logs
Fleet before/after (2 h of traffic)94.3% read sharependingadded in a comment after 2 h

No new timer, observer or loop: one settings-file read per Claude Code start (the same read defaultPermissionMode already does).

Testing

  • Unit: cargo test -p acpmux --lib prompt_cache_env covers the three variables, a profile's own value winning, FORCE_PROMPT_CACHING_5M (and its off values), the 5m setting, and parsing.
  • Integration: cargo test -p acpmux --test agent_tools. The routed Claude Code profile (custom ANTHROPIC_BASE_URL) and the plain one both start with the three variables. A profile with FORCE_PROMPT_CACHING_5M=1 gets none.
  • Red/green, same fleet run: see the test comment below (fleet run in progress at open)

Observed / Not run

  • Ran: the commands above on fleet Linux.
  • Not run: the Settings row, cmux settings get|set agents.promptCache and MCP settings_get on a tagged build. The descriptor uses the same .choice kind as agents.defaultPermissionMode, which all three surfaces already handle.

Changelog

Changed: Claude Code chats keep their prompt cache for one hour on any API key or custom endpoint, not just on a Claude subscription; Settings > Agent Chat > Prompt Cache switches back to 5 minutes.

Proof

No capture: a settings row of an existing kind plus a spawn-env default. The tests above show the env.

Agent session: agent session

🤖 Generated with Claude Code


Autofix with [code]smith
Open in [code]smith · Need help on this PR? Tag @codesmith-bot with what you need.


Summary by cubic

Claude Code chats now start on a one-hour prompt cache by default on API keys and other non-subscription endpoints, instead of five minutes, keeping prompts cached across longer pauses. Existing profile TTL values, login-shell exports, and FORCE_PROMPT_CACHING_5M or DISABLE_PROMPT_CACHING* switches are respected; subscription behavior is unchanged.

  • Agent Chat > Prompt Cache lets the person choose 1 Hour or 5 Minutes; changes apply to new chats, and agents cannot change this user-owned setting.