Claude Code v2.1.248, released 27 August 2026, added a field to subagent frontmatter that most Claude Code users will never write themselves: experimental.cacheTtl. It sets the prompt cache lifetime for one specific subagent's requests, independent of whatever the session's subagentPromptCacheTtl setting says everyone else should get. It's a narrow feature, and understanding it means first understanding a subtlety in how subagents interact with the cache at all, which is why this piece treats it as a standalone topic rather than folding it into the broader settings covered in Claude Code's promptCacheTtl setting explained.
The problem this field solves
A subagent starts its own conversation with its own system prompt, entirely separate from the parent session's. That means its first request never reads the parent's cache, prefix matching only works when two requests share the same starting content, and the parent's history isn't part of a subagent's prompt at all. Each subagent instead builds and warms a cache of its own, turn by turn, within its own run.
Claude Code buckets every request it sends into one of two groups for cache-TTL purposes: the main conversation (interactive turns, non-interactive -p runs, Agent SDK calls) and "everything else" (subagents, workflows, in-process teammates, forks, compaction, and session titles). Subagents fall into the second bucket regardless of what TTL the main conversation is using. Unless you set subagentPromptCacheTtl yourself, that bucket defaults to five minutes on every billing type, a Claude subscription included, aside from a small set of server-controlled helper requests that get the hour automatically.
Five minutes is fine for a subagent that runs once and finishes. It's a real cost for one that gets called repeatedly across a session with gaps longer than five minutes between calls: a code-review subagent invoked after each of several separate edits, say, or a research subagent a workflow calls back into on a schedule. Each call past the five-minute gap reprocesses that subagent's entire system prompt as uncached input. subagentPromptCacheTtl: "1h" fixes that for every subagent in the session. experimental.cacheTtl fixes it for one.
Where it goes in the frontmatter
The field is a key inside an experimental map, not a top-level frontmatter field, and it only takes effect in a subagent's own file:
---
name: repo-auditor
description: Audits a large repository and reports what it finds
experimental:
cacheTtl: 1h
---
Claude Code reads it only from subagent definitions: .claude/agents/, ~/.claude/agents/, or a plugin's own agents/ directory. Put it in a top-level cacheTtl field, or in a project's CLAUDE.md, or in any file that isn't a subagent definition, and Claude Code ignores it, since the field doesn't exist outside that one location.
The two allowed values
cacheTtl takes exactly 5m or 1h, the same two fixed lifetimes the underlying Claude API offers everywhere else in Claude Code. Any other value is ignored, silently, the same way promptCacheTtl and subagentPromptCacheTtl ignore anything outside that pair. There's no numeric TTL, no minutes-based scale; a typo like 1hr behaves as though the field were never set.
The trade-off is the same one that applies to the session-wide settings. The one-hour TTL bills cache writes at a higher rate than the five-minute TTL, and it only pays for itself when the subagent's calls are spaced further apart than five minutes: cross a longer gap without reprocessing the whole prefix, at the cost of paying more per write along the way. A subagent called in a tight loop, seconds apart, gets nothing from 1h beyond the higher write rate, since it never idles long enough for the five-minute default to actually expire.
The usage-credits catch
Claude Code ignores a 1h value in experimental.cacheTtl specifically while your Claude subscription is drawing on usage credits, the extra usage available once you've gone past your plan's included allowance. This mirrors how the session-wide TTL settings behave: once you're being billed per token for usage credits, Claude Code stops applying the higher cache-write rate automatically and drops back to the cheaper default for that bucket, on the reasoning that a longer, costlier cache lifetime shouldn't be assumed once real per-token spend is involved.
Practically, this means a subagent's 1h setting can appear to work fine during a normal session and then silently stop mattering the moment that session crosses into usage-credit territory partway through. If a subagent's cache behaviour seems to change mid-session with no configuration change on your end, check whether the session went over its plan limit first.
How it ranks against the session-wide settings
experimental.cacheTtl doesn't stand alone. Claude Code decides the TTL for any given request by working through a fixed list of controls, in order, and stopping at the first one that applies:
FORCE_PROMPT_CACHING_5M=1, which forces five minutes for both buckets regardless of anything else- The bucket's environment variable (
CLAUDE_CODE_PROMPT_CACHE_TTLfor the main conversation,CLAUDE_CODE_SUBAGENT_PROMPT_CACHE_TTLfor everything else) - The bucket's setting (
promptCacheTtlorsubagentPromptCacheTtl) - For a subagent's own requests specifically, the
cacheTtlvalue in that subagent'sexperimentalfrontmatter field ENABLE_PROMPT_CACHING_1H=1, which requests one hour for both buckets- The default for that bucket
The position matters. experimental.cacheTtl sits below the session-wide subagentPromptCacheTtl setting and its environment variable, not above them. A managed subagentPromptCacheTtl: "5m" deployed through an organisation's managed settings, or an environment variable set on the machine, wins over whatever an individual subagent's frontmatter asks for. The field is a fallback for when no session-wide control has already decided the answer, not an override that beats them.
That also means experimental.cacheTtl never touches promptCacheTtl, the main-conversation setting, at all. A subagent's frontmatter can't extend or shorten the parent session's own cache lifetime; the two are entirely separate buckets with entirely separate controls.
A worked example: two subagents, two TTLs
Say a project defines a code-reviewer subagent invoked after most edits, several times an hour with gaps well past five minutes, and a changelog-writer subagent called once at the end of a session. Only the first benefits from a longer TTL:
# .claude/agents/code-reviewer.md
---
name: code-reviewer
description: Reviews a diff for correctness and style issues
experimental:
cacheTtl: 1h
---
# .claude/agents/changelog-writer.md
---
name: changelog-writer
description: Drafts a changelog entry from the session's changes
---
code-reviewer gets the hour-long cache for its own requests, so repeat calls across the session read its system prompt from cache instead of reprocessing it each time. changelog-writer is left at whatever subagentPromptCacheTtl (or its default) already applies, since a subagent called once per session has nothing to gain from a longer lifetime.
Subagents versus forks: why only one needs this field
It's worth being precise about which of Claude Code's parallel-execution mechanisms experimental.cacheTtl actually applies to, because the two look similar from the outside and behave very differently against the cache. A subagent starts an entirely new conversation, its own system prompt, its own tool set, so its first request never reads anything the parent already cached; it has to build a cache of its own from nothing. A fork, by contrast, inherits the parent's system prompt, tools, and full conversation history exactly as they stand, so its first request reads directly from whatever the parent already had cached. experimental.cacheTtl only makes sense for the first case, since it's specifically about giving one subagent's own, separately-built cache a longer lifetime; a fork doesn't build a separate cache to set a lifetime for in the first place.
This distinction also explains why a workflow fanning out several same-prefix agents in parallel behaves differently from a workflow spawning several unrelated subagents. When a workflow fans out agents that share an identical starting prefix, Claude Code briefly holds back all but the first so the later ones can read the prefix the first agent just cached, rather than each one separately reprocessing the same content from scratch. That optimisation happens automatically and isn't something experimental.cacheTtl changes; the field only affects how long a cache, once built, survives afterward, not whether related agents can share one in the first place.
Checking that it's actually taking effect
There's no field-specific confirmation in /status or /cost yet, but the general prompt-cache diagnostics still apply. As of v2.1.251, /usage shows a Prompt cache (main) line covering the main conversation's hit ratio, misses, and warm-or-cold state, though that line covers the main conversation only, not subagents. For a subagent specifically, the most direct check is watching whether repeated calls to it show the reprocessing cost you'd expect from a cache miss: a call made well within the TTL should be noticeably cheaper and faster than the very first call, and that gap should persist across a longer wait once 1h is set than it would at the five-minute default.
Troubleshooting
The field has no effect at all. Confirm the subagent is actually defined in .claude/agents/, ~/.claude/agents/, or a plugin's agents/ directory, since Claude Code reads experimental.cacheTtl only from those locations. Also confirm you're on Claude Code v2.1.248 or later; the field doesn't exist on earlier versions and is silently ignored rather than erroring.
1h seems to stop working partway through a session. Check whether the session has gone past its plan's included usage and is drawing on usage credits. Claude Code ignores 1h there for this field specifically, and drops back to the normal default.
A session-wide setting seems to override the subagent's frontmatter. That's expected, not a bug. subagentPromptCacheTtl and its environment variable both outrank experimental.cacheTtl in the precedence order; the frontmatter field only wins when nothing higher up the list has already set a value.
The field is written correctly but at the top level of frontmatter. It has to be nested inside an experimental map, not a sibling of name and description. A top-level cacheTtl: key is a different, unrecognised field and does nothing.
A subagent invoked through a workflow fan-out doesn't seem to benefit from 1h. Check whether it's actually running as an independent subagent or as one of several forked, same-prefix agents in that fan-out. Forked agents share the parent's cache directly rather than building their own, so a cacheTtl set on a subagent definition has nothing to act on in that path; the field is specific to a subagent's own, separately-built cache.
The field name itself looks unstable, and that's a fair read. It lives under an experimental namespace deliberately, which is Anthropic's usual signal that a field's shape or behaviour might still change in a later release. Treat it as worth adopting for a genuinely repeated, expensive subagent today, but don't be surprised if a future Claude Code version renames or restructures it the way experimental fields sometimes do.
Where this fits with the rest of Claude Code's cache controls
experimental.cacheTtl is the most granular of three related controls. promptCacheTtl sets the main conversation's lifetime. subagentPromptCacheTtl sets a default for every subagent, workflow, fork, and compaction request in a session. experimental.cacheTtl narrows that down to one subagent when the session default isn't right for it specifically. None of the three substitute for the others, and none of them touch what actually invalidates a cache outright, model switches, effort changes, MCP servers connecting or disconnecting, still apply the same way regardless of which TTL is in effect. For the full mechanics of prompt caching in Claude Code, including exactly which actions invalidate a cache and why subagents build their own from scratch, see promptCacheTtl setting explained and Claude Code's own prompt caching documentation.
For the broader subagent picture, how Claude Code's subagent forking works covers the distinction between a subagent, which starts a fresh conversation and cache, and a fork, which inherits the parent's cache directly. Browse the full Claude Code coverage at getclaudeskills.com/platforms/claude-code.
Verified 29 August 2026 directly against Claude Code's prompt caching documentation and sub-agents reference at code.claude.com, both read in full, following the experimental.cacheTtl field introduced in v2.1.248 (27 August 2026).
