A reuse-friendly prompt, stable to volatile
Top: stable and cached → bottom: changes on every request
- Tool definitionschange rarely — first in the cache order
- Core system promptshared modules: role, policy, style
- Skill metadataname and description only, ~100 tokens each
- Reference materialmanuals, catalogues — daily or weekly
- Conversation so fargrows each turn; auto-cached as it goes
- This requestquestion, timestamp, user data — never cached
Three kinds of reuse, three different problems
| Strategy | What is reused | What it saves | Typical failure |
|---|---|---|---|
| Prompt caching | Processed tokens of an identical prefix | Input cost and time to first token | Cache never hits: a volatile value sits above the breakpoint |
| Modular prompts | Source text of shared prompt sections | Authoring effort, drift, review and test time | Copy-pasted variants diverge across teams |
| Agent Skills | Packaged instructions, files and scripts | Always-on context; repeated re-explaining | Vague description, so the Skill never triggers |
They work together. A modular system prompt assembled in a fixed order produces a stable prefix, which is what caching needs. Skills keep specialised procedures out of that prefix until they are relevant, so the always-on part stays small (context budgeting is covered in 2.4).
Prompt caching: pay once for a stable prefix
Prompt caching stores the processed form of a prompt prefix so later requests that start with the same prefix skip that work. The prefix is built in a fixed order — tools, then system, then messages — and a change at one level invalidates that level and everything after it. Changing a tool definition therefore throws away the whole cache; adding an image affects only the messages.
There are two ways to turn it on. Automatic caching is a single top-level cache_control on the request; the breakpoint moves forward with a growing conversation, which the docs recommend for chat. Explicit breakpoints put cache_control on individual blocks — up to four per request — so sections that change at different rates are cached separately. Place each breakpoint on the last block that is identical across requests. The system looks back at most 20 blocks from a breakpoint for an earlier cache entry, so very long agent turns may need a second breakpoint.
| Setting | Value in current docs | Design implication |
|---|---|---|
| Default lifetime | 5 minutes, refreshed free on each hit | Steady traffic keeps it warm on its own |
| Extended lifetime | "ttl": "1h" | For prefixes reused less often than every five minutes |
| Cache write price | 1.25× base input (5 min) · 2× (1 hour) | A write pays back after about one or two hits |
| Cache read price | 0.1× base input on most models | Opus 5: $0.50 instead of $5 per MTok |
| Minimum length | 512 tokens on Opus 5; 1,024 on Sonnet 5; 4,096 on Haiku 4.5 | Shorter prefixes are silently not cached |
| Rate limits | Cache reads do not count toward input-tokens-per-minute | Caching also raises effective throughput |
response = client.messages.create(
model="claude-sonnet-5",
max_tokens=1024,
tools=TOOLS, # stable: first in the prefix
system=[
{"type": "text", "text": REBOOKING_POLICY, # changes quarterly
"cache_control": {"type": "ephemeral", "ttl": "1h"}},
{"type": "text", "text": TODAYS_DISRUPTIONS, # changes daily
"cache_control": {"type": "ephemeral"}}, # 5-minute default
],
messages=[{"role": "user",
"content": f"Now: {now}. Passenger: {query}"}], # volatile, last
)
u = response.usage
total_in = u.cache_read_input_tokens + u.cache_creation_input_tokens + u.input_tokens
log.info("cache hit ratio %.0f%%", 100 * u.cache_read_input_tokens / total_in)Two details in that code are easy to miss. Longer-lived entries must come before shorter ones, so the one-hour breakpoint sits above the five-minute one. And input_tokens in the response counts only the tokens after the last breakpoint; true input is the sum of the three fields. A dashboard that reads input_tokens alone will show a suspiciously cheap service.
Why the cache never hit
Cache miss on every requesttext
[system]
Current time: 09:41:07
Agent: Sam (id 5521)
You are the disruption desk
assistant for Aurora Air...
<rebooking_policy>
...40,000 tokens...
</rebooking_policy>
← cache_control here
[user]
Passenger question...Stable prefix, volatile tailtext
[system]
You are the disruption desk
assistant for Aurora Air...
<rebooking_policy>
...40,000 tokens...
</rebooking_policy>
← cache_control here
[user]
Current time: 09:41:07
Agent: Sam (id 5521)
Passenger question...Modular prompts: write once, compose everywhere
A modular prompt is assembled from named, versioned sections — a brand-voice module, a data-handling policy, a refusal policy, an output-format module — each owned by one team and reviewed like code. Services compose the modules they need in a fixed order and add their own task section. This extends the template idea from 2.2 from one prompt to a fleet of them.
- One source of truth. Legal changes the data-handling module once; every service picks it up on its next release instead of relying on ten teams to copy the edit.
- Testable units. Each module change runs against every consuming service’s eval set before release, so a harmless-looking wording change cannot quietly break a downstream workflow.
- Cache-friendly by construction. Assemble modules from most stable to least stable. Two services only share a cache entry if their prefixes are byte-identical and they run in the same workspace, so a module shared at the top of the prompt, with identical tools, is where cross-service cache reuse can happen.
- Traceable. Log the module versions with each request, so an output can be traced to the exact prompt that produced it.
Agent Skills: expertise that loads on demand
An Agent Skill is a folder with a SKILL.md file — YAML frontmatter with a name and a description, then instructions — plus any reference files and scripts it needs. Anthropic’s engineering post compares writing one to putting together an onboarding guide for a new hire. The design idea is progressive disclosure: Claude sees only the metadata of every installed Skill, reads the instructions when a task matches, and opens further files or runs scripts only if the instructions call for them.
Progressive disclosure in a Skill
- Metadataname + description, ~100 tokens, always loaded
- Task matchesClaude judges from the description
- SKILL.md bodyinstructions, under 5K tokens
- Files and scriptsread or run only when needed
The authoring guide makes a few rules that carry straight into exam reasoning. The description must say what the Skill does and when to use it, in the third person, because it is injected into the system prompt and is the only thing Claude uses to choose. Keep the SKILL.md body under 500 lines and link reference files one level deep. Prefer bundled scripts for fragile, exact operations: a script runs without its code entering context, and gives the same result every time. And build evaluations first — measure Claude without the Skill, then write just enough to close the gap.
| Surface | How Skills are supplied | Notes an architect needs |
|---|---|---|
| Claude API | container.skills list with type (anthropic or custom), skill_id, version; needs the code execution tool | Up to 20 per request; custom Skills are private to the workspace; pin a version in production, latest in development |
| Claude Code | Folders in ~/.claude/skills/, .claude/skills/, plugins or managed settings | disable-model-invocation: true for side-effect workflows such as deploys; context: fork runs one in a subagent |
| Claude apps | Pre-built document Skills plus uploaded custom Skills | Enabled per account; see the drift note below on syncing |
---
name: formatting-regulatory-submissions
description: Formats clinical study summaries to our
submission template and validates section numbering.
Use when drafting or checking regulatory submission
documents, CTD modules or study summaries.
---
# Formatting regulatory submissions
1. Read TEMPLATE.md for the required section order.
2. Draft the document following that order.
3. Run: python scripts/validate_sections.py draft.docx
4. Fix every error the script reports, then re-run.
For terminology rules, see GLOSSARY.md.Which reuse strategy fits?
- Same long prefix, many callsPrompt cachingstable first, breakpoint last
- Same text, many servicesModular promptsversioned modules, fixed order
- Procedures needed sometimesAgent Skillmetadata always, body on demand
- Work that can waitBatch + cachingdiscounts stack
Traps the wrong answers are built from
| Tempting but wrong | Do this instead |
|---|---|
| Putting timestamps, user IDs or request data at the top of a cached prompt | Keep volatile values after the last breakpoint, in the user turn. |
Reading input_tokens alone to judge cache savings | Sum cache reads, cache writes and input_tokens, and track the hit ratio. |
| Toggling tools per request in a cached deployment | Keep tool definitions stable; changing them invalidates the entire cache. |
| Copy-pasting shared policy text into each service’s prompt | Compose versioned modules in a fixed order and test changes against every consumer. |
| Loading every procedure into an ever-growing system prompt | Package specialist procedures as Skills with a clear what-and-when description. |
You should now be able to
- Lay out prompts from stable to volatile and place cache breakpoints on the last stable block.
- Choose between automatic caching, explicit breakpoints and the one-hour lifetime.
- Verify caching with
cache_read_input_tokensandcache_creation_input_tokensand compute true input. - Design modular, versioned prompt sections that one team owns and many services reuse.
- Explain Skill progressive disclosure and write a description that triggers reliably.
- Deploy Skills per surface, with version pinning and security and retention review.