πŸŽ“ Claude Architect KB CCAR-F Β· CCAR-P study guide

Pro Domain 2 Β· Claude Models, Prompting & Context Engineering (13%)

What this domain asks you to do. The Professional exam describes the minimally qualified candidate in two quotes. This person "designs, implements, and governs Claude-powered AI solutions within production environments". This person also "understands trade-offs related to cost, latency, performance, safety, and maintainability." In this domain, that means five decisions. You make each one, and you can explain why:

Foundations Domain 3 taught you to write one good prompt and get a usable answer. Foundations Domain 5 taught you that the window is a budget. This page assumes you know both. It moves to the architect's job: the same prompt is sent 200,000 times a day, by three teams, under a latency target, and a policy change arrives every month.

πŸ“– New here? One policy assistant, three teams, and the month the prompt drifted

Meet Halden Mutual, an insurance company. Its claims-policy assistant answers questions from adjusters (the staff who assess claims). It answers from an 8,000-token underwriting policy. It started as one prompt in one notebook. Twelve months later, three teams run three copies: claims, fraud review, and the portal that customers use. Each copy has slowly changed in its own way. Legal changed a clause in March, but the portal's copy still has the old wording.

The first problem was money and latency. Every request sent the whole policy again. On the portal, the median time to first token was 2.4 seconds, because the model read 8,000 tokens again before it wrote a word. The fix was not a smaller model and not a shorter policy. The fix was to order the request so the stable policy came first, and to mark its end with a cache boundary. The answers stayed the same; they came faster and cost less. That is the exam's Sample 2 in one sentence, and it is the typical pattern for this whole domain.

The second problem was model choice. The fraud team put everything on the largest tier "to be safe". It spent far over budget on 40,000 yes/no triage checks per day. On the golden set, the fastest tier answered those checks just as well. At the same time, the portal used the fastest tier to combine coverage facts from many documents. It got shallow summaries that were wrong but sounded sure. Neither team had a matrix (a table that maps each step to a tier); both teams followed a habit.

The third problem was drift. The compliance preamble (the standard opening text) was copied into 40 prompt files. The architect fixed the structure. There is now one preamble module, which the application inserts when it builds each request. A version stamp goes into the request metadata. And the procedure that teams kept copying is now packaged as an Agent Skill, with a SKILL.md that everyone loads instead of typing it again.

The fourth problem was the window. The claims agent crashed after thirty turns. Each tool returned a full 8,000-token claim record, and nobody made it smaller. The fix was arithmetic. Reserve space for the output. Limit tool results to the fields the model needs. Compact the history when it reaches a threshold. And keep a structured state object that survives compaction.

What this means for the exam: every question stem in this domain is one of these four problems, with a number added. The correct option changes the structure of the request or the pipeline. The wrong options (distractors) do one of three things: they remove context that is needed, they move to a smaller model without measuring, or they move text to a place that does not create the property the stem asks for.

Where every decision lands β€” the request map

The architect's map. Read the table once, as a picture: five decisions, five owners, five places. Each section below explains one row.

Decision Who decides Where it lives Opens
Which model tier runs this step your router code, informed by evals the request's model field, set per step from a registry Model selection matrix Β· model (field)
Standing instructions, tenant rules, guardrail text your application, never the user the system field β€” a string or an array of text blocks system (field) Β· Guardrail prompt layer
Task wording, placeholders, examples the prompt author, versioned in git a prompt template rendered into system and messages Prompt template
Zero-shot, few-shot, or chain-of-thought the prompt author, per step, by measurement example blocks in system or messages; a thinking setting in the request Choosing a technique Β· few-shot
How much of the window each part may use the harness, enforced in code a token ledger checked before each call; max_tokens reserves output Context budget Β· Token optimization
What is reused across requests and teams the architect a cache boundary in the request; module files assembled at build time; a SKILL.md folder Prompt reuse strategy Β· Skills as reuse

Two things the map does not contain. First, authorization is not in this table. A guardrail written in system asks the model to obey. A permission check in your harness makes it happen. Second, the model's context limit is not in this table. It is a property of the model you select. Your context budget must read it from configuration, not guess it.

Select appropriate Claude models based on trade-offs

Select appropriate Claude models based on trade-offs

Trade-off, not ranking. The Foundations page introduced [model tiering](term:model tiering) as "assign different configurations to different kinds of work based on evaluation." The Professional exam asks you to make that choice under limits, and to explain it. Four axes (dimensions of comparison) matter. A stem usually names two of them:

Axis What it measures Which tier wins Stem phrase that signals it
Depth multi-step reasoning, synthesis across documents, nuance the larger tier "nuanced", "synthesize across", "ambiguous"
Speed time to first token and tokens per second the faster tier "interactive", "voice", "must respond within"
Cost input and output tokens per call Γ— volume the faster tier at volume "200,000 per day", "budget", "per-request cost"
Context how much input the step must hold at once the tier with the larger window "entire contract", "full transcript"

Who decides and where it lives. A router in your application code makes the decision. It writes the result into the request's model field. A production system keeps the step-to-tier mapping in a registry, not in text strings spread across many services. Then a tier change is one edit and one regression run. The registry below is illustrative (an example, not a real product file). The tier names are your own labels. At deploy time, configuration turns each label into a real model id.

JSON
{
  "tiers": {
    "fast": {"env": "MODEL_FAST", "max_input_tokens": 180000},
    "balanced": {"env": "MODEL_BALANCED", "max_input_tokens": 180000},
    "deep": {"env": "MODEL_DEEP", "max_input_tokens": 180000}
  },
  "steps": {
    "ticket_classify": {"tier": "fast", "golden_set": "evals/classify.jsonl", "min_accuracy": 0.96},
    "coverage_synthesis": {"tier": "deep", "golden_set": "evals/synthesis.jsonl", "min_accuracy": 0.90},
    "escalation_summary": {"tier": "balanced", "golden_set": "evals/escalation.jsonl", "min_accuracy": 0.92}
  }
}

Reading the registry. Each step names three things: a tier, the golden set that justified the tier, and the accuracy floor (minimum score) that a regression run must keep. Your context budget reads the number in max_input_tokens. You keep this value in configuration and match it to the documented limit of the selected model. The code does not assume it as a constant. The env field points to an environment variable instead of a model id. Because of this, [model pinning](term:model pinning) and rollback are configuration changes, not code changes.

The router is ordinary code. It reads the registry, finds the tier, and sets the field. This is illustrative Python for an application with a configured client. This page does not run any of it.

PYTHON
import json
import os
from anthropic import Anthropic

client = Anthropic()
REGISTRY = json.load(open("config/model-registry.json"))


def model_for(step: str) -> str:
    tier = REGISTRY["steps"][step]["tier"]
    return os.environ[REGISTRY["tiers"][tier]["env"]]


def classify_ticket(ticket_text: str):
    return client.messages.create(
        model=model_for("ticket_classify"),
        max_tokens=64,
        system="Classify the support ticket into exactly one of the 12 labels listed. Reply with the label only.",
        messages=[{"role": "user", "content": ticket_text}],
    )
Not supplied in this example β€” defaults and disabled features
Setting not supplied or not visible Meaning for this example
context_management β€” not supplied here No server compaction strategy is enabled by this body. Host/manual compaction is separate.
output_config β€” not supplied here No output_config schema or effort override is supplied. A prompt asking for JSON does not provide schema enforcement.
tools β€” not supplied here No tools are offered through this field.
tool_choice β€” not supplied here With tools supplied, the default is auto: the model chooses whether to request a tool. Without tools, no supplied tool can be selected.
stop_sequences β€” not supplied here No custom stop strings are configured. Generation can still stop for end_turn, tool_use, max_tokens, or another documented reason.
stream β€” not supplied here For a direct non-streaming create/parse call, the result is one message rather than an event stream. A stream helper configures this separately.
thinking β€” not supplied here No explicit thinking override is shown. Behavior depends on the selected model; omission does not universally mean thinking is off.
cache_control β€” not supplied here No top-level automatic cache marker is supplied. Check nested system/tool/content blocks for separate cache_control markers.
metadata β€” not supplied here No application user reference is supplied through metadata. Authentication still comes from the request credentials.
betas β€” not explicitly supplied No beta list appears in these calls. SDK/client configuration can add headers; inspect those before assuming no beta header is sent.

Full request catalog and omission rules. JSON has no comments; these notes are outside the payload.

The decision table the exam expects you to carry.

Step shape Tier to start with Why Verify with
Fixed-label classification, extraction into a closed [schema](term:structured outputs), yes/no triage at volume fastest the task is narrow; volume multiplies every token [golden set](term:golden set) accuracy β‰₯ floor; watch usage
Drafting, single-document summarization, routine agent turns balanced needs fluency, not deep reasoning an eval with rubric scoring
Multi-document synthesis, ambiguous policy judgement, planning in an [agent loop](term:agent loop) deep errors here are expensive and hard to detect downstream rubric evals plus human review sample
Interactive turns with a strict first-token target fastest, with [prompt caching](term:prompt caching) on the stable prefix latency is dominated by input processing you can cache measure time to first token, not only tokens
One step that needs both speed and depth split the step: fast tier answers, deep tier handles the routed hard cases the evaluator-optimizer or a confidence gate decides the route track the routed fraction

Extended thinking is a fifth axis, not a tier. Some models support [extended thinking](term:extended thinking). It gives deeper reasoning on each call. The cost is thinking tokens and more latency. You set it per request in the thinking field. So the same tier can run "shallow" on triage and "deep" on the hard cases. A bigger tier and thinking are two separate levers (controls). A stem that says "latency is the concern" usually wants you to turn one of them off on the simple path. It does not want you to remove the deep path.

The wrong choice and its failure. "Use the largest model everywhere to be safe" has two results. The bill grows with your busiest step, and latency has a minimum you cannot lower. It is the reverse of "downsizing blindly": upsizing blindly. "Use the smallest model regardless of task fit" is a wrong option written in the exam guide itself. It risks quality on the steps that needed depth. The failure shows up as answers that sound sure but are shallow: they pass format checks and get the facts wrong. Both choices are habits. The correct answer is always the matrix plus the measurement. Model portability explains what happens when the tier under a step changes.

Design system prompts, templates, and guardrails

Design system prompts, templates, and guardrails

Two shapes of one field. Foundations taught the [system prompt](term:system prompt) as "the application's standing instructions." The Professional detail: the system field accepts two shapes, and choosing the shape is an architecture decision. As a plain string, it is one instruction that cannot be split. As an array of text blocks, each block can have its own cache_control marker, and each block can come from a different source. Everything else in the request stays the same.

Shape 1 β€” a string. This is fine for a tool with one tenant and a short prompt. Illustrative request body; the model placeholder stands for any supported model.

JSON
{
  "model": "YOUR_SUPPORTED_MODEL",
  "max_tokens": 512,
  "system": "You answer adjusters' questions about the Halden underwriting policy. Use only the policy text supplied. If the policy does not cover the question, say so and name the escalation queue.",
  "messages": [
    {"role": "user", "content": "Does a cracked windshield count as collision damage under section 4?"}
  ]
}
Not supplied in this example β€” defaults and disabled features
Setting not supplied or not visible Meaning for this example
context_management β€” not supplied here No server compaction strategy is enabled by this body. Host/manual compaction is separate.
output_config β€” not supplied here No output_config schema or effort override is supplied. A prompt asking for JSON does not provide schema enforcement.
tools β€” not supplied here No tools are offered through this field.
tool_choice β€” not supplied here With tools supplied, the default is auto: the model chooses whether to request a tool. Without tools, no supplied tool can be selected.
stop_sequences β€” not supplied here No custom stop strings are configured. Generation can still stop for end_turn, tool_use, max_tokens, or another documented reason.
stream β€” not supplied here For a direct non-streaming create/parse call, the result is one message rather than an event stream. A stream helper configures this separately.
thinking β€” not supplied here No explicit thinking override is shown. Behavior depends on the selected model; omission does not universally mean thinking is off.
cache_control β€” not supplied here No top-level automatic cache marker is supplied. Check nested system/tool/content blocks for separate cache_control markers.
metadata β€” not supplied here No application user reference is supplied through metadata. Authentication still comes from the request credentials.

Full request catalog and omission rules. JSON has no comments; these notes are outside the payload.

Shape 2 β€” layered blocks. The same field, now as an array. The block order is chosen on purpose: the largest and most stable content first, the per-tenant content next, and the guardrail last. The cache marker sits on the last block that is byte-identical (exactly the same, byte for byte) in every request. The policy text is shortened here so you can read it. In production it is the full 8,000 tokens.

JSON
{
  "model": "YOUR_SUPPORTED_MODEL",
  "max_tokens": 512,
  "system": [
    {
      "type": "text",
      "text": "HALDEN UNDERWRITING POLICY v2026-03. Section 1: Definitions. Section 2: Covered perils. Section 3: Exclusions. Section 4: Glass and windshield claims are comprehensive, not collision, unless the glass damage results from a collision event recorded in the same claim.",
      "cache_control": {"type": "ephemeral"}
    },
    {
      "type": "text",
      "text": "REGION RULES: Adjuster region is Pacific Northwest. State-specific glass deductible waivers apply; cite the state code in your answer."
    },
    {
      "type": "text",
      "text": "GUARDRAILS: Answer only from the policy text above. Never state a coverage decision as final; adjusters make decisions. If a question requires facts not in the policy, reply with the single line ESCALATE: <reason>."
    }
  ],
  "messages": [
    {"role": "user", "content": "Does a cracked windshield count as collision damage under section 4?"}
  ]
}
Not supplied in this example β€” defaults and disabled features
Setting not supplied or not visible Meaning for this example
context_management β€” not supplied here No server compaction strategy is enabled by this body. Host/manual compaction is separate.
output_config β€” not supplied here No output_config schema or effort override is supplied. A prompt asking for JSON does not provide schema enforcement.
tools β€” not supplied here No tools are offered through this field.
tool_choice β€” not supplied here With tools supplied, the default is auto: the model chooses whether to request a tool. Without tools, no supplied tool can be selected.
stop_sequences β€” not supplied here No custom stop strings are configured. Generation can still stop for end_turn, tool_use, max_tokens, or another documented reason.
stream β€” not supplied here For a direct non-streaming create/parse call, the result is one message rather than an event stream. A stream helper configures this separately.
thinking β€” not supplied here No explicit thinking override is shown. Behavior depends on the selected model; omission does not universally mean thinking is off.
cache_control β€” not supplied here No top-level automatic cache marker is supplied. Check nested system/tool/content blocks for separate cache_control markers.
metadata β€” not supplied here No application user reference is supplied through metadata. Authentication still comes from the request credentials.

Full request catalog and omission rules. JSON has no comments; these notes are outside the payload.

Who writes each layer, and where it lives. Legal owns the policy block. It is stored as a versioned document, and your build copies it in. Nobody edits it inside a prompt file. The region block is filled in per tenant from your database, when your code builds the request. The architect owns the guardrail block. Security reviews it, and a [golden set](term:golden set) of attack-style questions tests it. An application user never writes any of the three. Text from users belongs in messages, as Foundations Domain 3's injection defense requires.

Templates β€” the file behind the field

A template is the source; the request is the rendered result. A prompt template is a versioned file with named placeholders. Your code fills them in before the call. Use placeholders for data only. The structure and the labels stay fixed, so the stable part is byte-identical in every request after rendering. This is a plain-text template with the four Foundations sections. A real one is longer.

TEXT
[SYSTEM Β· block 0 Β· cached]
{{policy_document}}

[SYSTEM Β· block 1 Β· per tenant]
REGION RULES: Adjuster region is {{region_name}}.
{{region_rules}}

[SYSTEM Β· block 2 Β· guardrail]
Answer only from the policy text above. Never state a coverage decision as final.
If facts are missing, reply with the single line ESCALATE: <reason>.

[USER]
<question>
{{adjuster_question}}
</question>

Rendering is ordinary string work. Its output is the array shown above. The important line puts the cache marker on block 0 and on no other block.

PYTHON
from pathlib import Path


def render_system(policy_text: str, region: dict) -> list:
    return [
        {"type": "text", "text": policy_text, "cache_control": {"type": "ephemeral"}},
        {"type": "text", "text": f"REGION RULES: Adjuster region is {region['name']}.\n{region['rules']}"},
        {"type": "text", "text": Path("prompts/guardrail-v3.txt").read_text().strip()},
    ]

Guardrails β€” what a prompt layer can and cannot do

A guardrail layer is instruction text, and nothing more. The guardrail prompt layer tells the model three things: what to refuse, what to escalate, and how to format a refusal so your code can detect it. When things go well, it guides behaviour. When things go wrong, it gives your code a signal it can parse (ESCALATE:). It does not authorize anything. The Foundations guardrail card and the Domain 1 HITL gate describe the other half: enforcement in code. Exam questions in this domain test whether you know which half a change belongs to.

Layer Owner Lives in Changes how often Cacheable?
Shared policy / knowledge legal, product system[0], from a versioned document monthly or less yes β€” marker here
Tenant, role, region rules your application at request-build system[1] per tenant only if you cache per tenant, which usually is not worth it
Guardrail and output contract architect + security system[2] (or last) rarely, but tested when it does after the marker, so edits do not evict the policy cache
Examples of the desired answer prompt author system or completed messages turns, before the varying task with the template version yes, if before the marker β€” see few-shot placement
The user's task and documents the user, untrusted messages, wrapped in XML tags every request no β€” that is the point

The wrong choice and its failure. Putting the tenant name at the top of the policy string looks harmless. But it removes the policy from the cache on every request. The exam describes this as "cache reads stay at zero" or "no reduction in latency after enabling caching." Another trap: putting a role that the user claims into system because "it needs to be authoritative". This is the admin-claim trap: text cannot verify who someone is. A third trap: writing "never issue refunds over $500" as a guardrail block and calling it a control. That mixes up a written instruction with an authorization check. The answer keys say: "prompt guardrails are advisory, harness gates are preventive."

Apply prompt engineering techniques (zero-shot, few-shot, chain-of-thought)

Apply prompt engineering techniques (zero-shot, few-shot, chain-of-thought)

Start at zero. The Foundations prompt template is a zero-shot prompt: role, task, format, and no examples. It uses the fewest tokens, and it is the first thing you measure. Add a technique only when a golden set shows a specific failure. Then add the technique that targets that failure. The card Choosing a technique has the same table as a drill.

Symptom on the golden set Technique What you add to the request Cost Does not fix
Right answer, wrong shape or wording few-shot 2–5 inputβ†’output pairs in system or completed messages turns tokens per request (cacheable if stable) reasoning errors
Skipped step, arithmetic slip, wrong intermediate fact chain-of-thought an instruction to reason inside a tagged section before the answer output tokens and latency on every call format drift
Hard multi-step cases the model gets wrong even with CoT [extended thinking](term:extended thinking) on a supporting model the thinking field with a budget thinking tokens, latency; only where routed high-volume simple steps
Correct content, application cannot parse it [structured output](term:structured outputs) output_config.format with a schema negligible wrong facts
Long document, answer ignores it long-context placement document first, question after, quote-then-answer none an oversized document

Zero-shot: the baseline you keep. This is the extraction request before any technique is added. It is a complete request body. The explanations are outside the JSON.

JSON
{
  "model": "YOUR_SUPPORTED_MODEL",
  "max_tokens": 64,
  "system": "Extract the date of loss from the claim note. Reply with the date only, in ISO 8601 format YYYY-MM-DD.",
  "messages": [
    {"role": "user", "content": "Insured reports hail damage to the roof discovered on the morning of March 3rd, 2026, after the storm the night before."}
  ]
}
Not supplied in this example β€” defaults and disabled features
Setting not supplied or not visible Meaning for this example
context_management β€” not supplied here No server compaction strategy is enabled by this body. Host/manual compaction is separate.
output_config β€” not supplied here No output_config schema or effort override is supplied. A prompt asking for JSON does not provide schema enforcement.
tools β€” not supplied here No tools are offered through this field.
tool_choice β€” not supplied here With tools supplied, the default is auto: the model chooses whether to request a tool. Without tools, no supplied tool can be selected.
stop_sequences β€” not supplied here No custom stop strings are configured. Generation can still stop for end_turn, tool_use, max_tokens, or another documented reason.
stream β€” not supplied here For a direct non-streaming create/parse call, the result is one message rather than an event stream. A stream helper configures this separately.
thinking β€” not supplied here No explicit thinking override is shown. Behavior depends on the selected model; omission does not universally mean thinking is off.
cache_control β€” not supplied here No top-level automatic cache marker is supplied. Check nested system/tool/content blocks for separate cache_control markers.
metadata β€” not supplied here No application user reference is supplied through metadata. Authentication still comes from the request credentials.

Full request catalog and omission rules. JSON has no comments; these notes are outside the payload.

Few-shot: show the shape, keep it stable, put it before the marker. The developer writes the examples as demonstrations. They go in system, after the instruction, so the whole block can be cached. The claim note changes on each request, and it is the only thing in messages. Foundations shows both placements. The Professional point: the examples are part of the stable prefix. So they cost full tokens once per cache lifetime, not once per request.

JSON
{
  "model": "YOUR_SUPPORTED_MODEL",
  "max_tokens": 64,
  "system": [
    {
      "type": "text",
      "text": "Extract the date of loss from the claim note. Reply with the date only, in ISO 8601 format YYYY-MM-DD.\n\nExamples (demonstrations, not the current task):\nNote: Water damage found Jan 9 2026 after pipe burst.\nAnswer: 2026-01-09\nNote: Theft reported; incident occurred 14 Feb 2026.\nAnswer: 2026-02-14\nNote: Hail on the evening of 2 March 2026; damage found next morning.\nAnswer: 2026-03-02",
      "cache_control": {"type": "ephemeral"}
    }
  ],
  "messages": [
    {"role": "user", "content": "Insured reports hail damage to the roof discovered on the morning of March 3rd, 2026, after the storm the night before."}
  ]
}
Not supplied in this example β€” defaults and disabled features
Setting not supplied or not visible Meaning for this example
context_management β€” not supplied here No server compaction strategy is enabled by this body. Host/manual compaction is separate.
output_config β€” not supplied here No output_config schema or effort override is supplied. A prompt asking for JSON does not provide schema enforcement.
tools β€” not supplied here No tools are offered through this field.
tool_choice β€” not supplied here With tools supplied, the default is auto: the model chooses whether to request a tool. Without tools, no supplied tool can be selected.
stop_sequences β€” not supplied here No custom stop strings are configured. Generation can still stop for end_turn, tool_use, max_tokens, or another documented reason.
stream β€” not supplied here For a direct non-streaming create/parse call, the result is one message rather than an event stream. A stream helper configures this separately.
thinking β€” not supplied here No explicit thinking override is shown. Behavior depends on the selected model; omission does not universally mean thinking is off.
cache_control β€” not supplied here No top-level automatic cache marker is supplied. Check nested system/tool/content blocks for separate cache_control markers.
metadata β€” not supplied here No application user reference is supplied through metadata. Authentication still comes from the request credentials.

Full request catalog and omission rules. JSON has no comments; these notes are outside the payload.

Read the third example carefully. It teaches a rule that the instruction did not state: the date of loss is the date of the storm, not the date someone found the damage. That is what few-shot is for: a pattern that is easier to show than to write. The illustrative answer to the request is 2026-03-02, and a reviewer can now see why.

Chain-of-thought: ask for reasoning when reasoning is the problem. Take a coverage question that needs two policy sections combined. Ask for a tagged reasoning section first and the decision last. Then your code can remove the reasoning and keep the answer. Foundations explains two points. First, this reasoning is generated text you can inspect, not a record of the model's private computation. Second, writing "think step by step" does not turn on [extended thinking](term:extended thinking). The two are separate. Prompted CoT is text inside the answer. Extended thinking is a request setting, on models that support it, with its own token budget. The API spec shows it in full.

JSON
{
  "model": "YOUR_SUPPORTED_MODEL",
  "max_tokens": 800,
  "system": "You answer coverage questions from the supplied policy. First reason inside <analysis> tags: quote the relevant policy sentences, then apply them to the facts. Then give the answer inside <answer> tags as one of COVERED, EXCLUDED, or NEEDS_FACTS with one sentence of justification.",
  "messages": [
    {"role": "user", "content": "<policy>Section 2: Hail is a covered peril. Section 3: Damage discovered more than 30 days after the event is excluded unless reported within 5 business days of discovery.</policy>\n<facts>Storm on 2026-03-02. Damage discovered 2026-04-10. Reported 2026-04-11.</facts>"}
  ]
}
Not supplied in this example β€” defaults and disabled features
Setting not supplied or not visible Meaning for this example
context_management β€” not supplied here No server compaction strategy is enabled by this body. Host/manual compaction is separate.
output_config β€” not supplied here No output_config schema or effort override is supplied. A prompt asking for JSON does not provide schema enforcement.
tools β€” not supplied here No tools are offered through this field.
tool_choice β€” not supplied here With tools supplied, the default is auto: the model chooses whether to request a tool. Without tools, no supplied tool can be selected.
stop_sequences β€” not supplied here No custom stop strings are configured. Generation can still stop for end_turn, tool_use, max_tokens, or another documented reason.
stream β€” not supplied here For a direct non-streaming create/parse call, the result is one message rather than an event stream. A stream helper configures this separately.
thinking β€” not supplied here No explicit thinking override is shown. Behavior depends on the selected model; omission does not universally mean thinking is off.
cache_control β€” not supplied here No top-level automatic cache marker is supplied. Check nested system/tool/content blocks for separate cache_control markers.
metadata β€” not supplied here No application user reference is supplied through metadata. Authentication still comes from the request credentials.

Full request catalog and omission rules. JSON has no comments; these notes are outside the payload.

What the harness does with that answer. It parses <answer>. It logs <analysis> for review. It never shows the analysis to a customer as if it were the decision. If the step is simple and runs at high volume, first measure whether CoT changes accuracy at all. Only then pay for it on every call. The Foundations card says the same.

The wrong choice and its failure. Adding chain-of-thought to a format problem increases output tokens and latency, and the format stays wrong. Turning on extended thinking for a classifier that runs 200,000 times a day makes a cheap step the most expensive step in the pipeline, with no measured gain. Another mistake: twelve few-shot examples that change on every request, because they are sampled from live data. They break the cache, and the behaviour slowly changes. Examples must be stable and versioned. The answer keys use the phrase "targeted technique versus blanket technique" (one step versus every step). "Measured on the golden set" always decides between two close options.

Optimize context windows and manage token usage

Optimize context windows and manage token usage

The arithmetic, written down. Foundations Domain 5 introduced the budget mindset with a walkthrough of turn 42. The Professional version is a ledger (a running account of token use). Your harness checks it before every call. Take a window limit W from the model registry. Nothing below assumes a particular model.

Line Symbol Illustrative value Rule
Model context limit (from registry) W 180,000 read from configuration, never hard-coded
Reserved output (max_tokens) O 4,000 reserved from the same window
Thinking budget, if enabled T 0 on the simple path counts against output space on supporting models
Room for input W βˆ’ O βˆ’ T 176,000 the ceiling for everything below
Stable prefix: tools + system (cached) P 11,000 paid at cache-read rates after the first call, still occupies the window
Working ceiling for variable content W βˆ’ O βˆ’ T βˆ’ P 165,000 what history, tool results, and documents share
Soft threshold to trigger compaction 0.8 Γ— working ceiling 132,000 compact before you hit the wall, not after the error

Tokens are counted, not guessed. The token-counting card names three ways to count. The one that matters here is the count endpoint. Your harness calls it with the same system, tools, and messages that it is about to send. The harness compares that number with the ledger and decides: send, trim, or compact. Illustrative Python; the client is configured somewhere else.

PYTHON
BUDGET = {"window": 180000, "reserve_output": 4000, "compact_at": 0.8}


def input_room() -> int:
    return BUDGET["window"] - BUDGET["reserve_output"]


def check_budget(client, model: str, system, tools, messages) -> str:
    count = client.messages.count_tokens(model=model, system=system, tools=tools, messages=messages)
    used = count.input_tokens
    if used > input_room():
        return "over"
    if used > BUDGET["compact_at"] * input_room():
        return "compact"
    return "send"

Where the spending shows up. After each call, the response's usage block tells you what you paid for and whether the cache worked. This is an illustrative usage object from a response with a warm cache (a cache that already holds the prefix). The numbers are examples, not a measured result.

JSON
{
  "input_tokens": 1450,
  "cache_creation_input_tokens": 0,
  "cache_read_input_tokens": 11000,
  "output_tokens": 212
}

Reading it. cache_read_input_tokens of 11,000 means the stable prefix was reused. input_tokens of 1,450 is the part after the cache: the region block, the guardrail, and the user's question. Suppose cache_read_input_tokens is 0 on every call. Then something that changes on each request sits before the marker: a timestamp, a request id, or a tenant name. The fix is the order, not more caching. The tokens versus money card keeps these two measurements separate.

The four cuts, in order of return

Remove the parts that are not worth their space. Token optimization is a sequence of cuts. The exam expects you to know which cut fixes which symptom. Prompt caching is not on this list, because it does not reduce the tokens in the window. It reduces what you pay and how long you wait.

Symptom Cut How Owner
Tool results dominate the window trim each result to the fields the model needs before appending it the harness maps a raw API dump to {id, status, amount, next_action} harness code
History grows without bound compact at the soft threshold: summarize older turns, keep a structured state object your code on the raw API; the product or SDK on hosted runtimes β€” who runs compaction depends on runtime
Documents pre-loaded "just in case" retrieve just in time by tool call when the turn needs them a retrieval tool returns the relevant section, not the corpus tool design
One step needs a huge context, others do not isolate that step in a subagent with its own window and return a summary [context isolation](term:context isolation) orchestration

The state object is what makes compaction safe. When turns 1–20 are replaced by a summary, every fact needed to keep working must survive. It lives in a small JSON object that the harness keeps and adds back into the context. Illustrative shape for the claims agent:

JSON
{
  "claim_id": "CLM-88213",
  "insured": "policy 4471-PNW",
  "loss_event": "hail 2026-03-02",
  "sections_applied": ["2", "3"],
  "open_questions": ["date of discovery unconfirmed"],
  "actions_taken": ["pulled claim record", "quoted section 3 to adjuster"],
  "escalations": []
}

The wrong choice and its failure. Raising max_tokens to fix a context error makes it worse, because the output reservation comes from the same window. Switching to a model with a larger window, without trimming, gives only a few more turns before the same crash. Each turn also costs more, and the model still reasons over noise. Lost in the middle is a quality failure, not only a size problem. Cutting the policy to its first 1,000 tokens (wrong option A in the guide) removes needed context. It is never the answer when the stem says the content is required. The answer keys use the phrase "reduce what enters the window versus reuse what enters the window". The first is optimization; the second is caching. When a stem names both latency and cost, and the content stays the same, it is asking for the second.

Long conversations β€” summarize, slide, or keep state?

Apply context window optimization techniquesβ€”summarization, sliding windows, structured state objects, and selective retentionβ€”to maintain response quality as conversations exceed practical token limits.

Who does this work. The model does not shrink its own context. Your application or harness (the software that builds each request and runs the loop) decides what to send on the next call. On the raw Messages API, that is your code. On a hosted runtime (Claude Code, the Agent SDK, or a server-side compaction setting), the product does the summarizing, but you still choose what must survive. See who runs compaction.

One table: what each technique keeps and what it loses.

Technique What it keeps What it loses Choose it when Who runs it
Summarization (compaction) the meaning of old turns, in few tokens exact wording, exact numbers, ids, quotes the old turns matter as background, not as exact text harness code (raw API) or the hosted product
Sliding window the last N turns, word for word everything older, completely and silently only recent turns matter (a chat about the current screen) harness code
Structured state object facts that must survive verbatim: ids, amounts, dates, decisions, open questions nothing it holds; it only holds what you put in it any fact a later turn depends on exactly harness code keeps it and adds it back each call
Selective retention the turns and tool results still needed; drops finished side paths the dropped material (you choose it, so choose by a rule) tool results that were used once and are now done harness code, by a written rule

They combine; they do not compete. The production pattern is all four at once. Keep the state object outside the summary. Summarize the old turns. Keep a short recent window word for word. Drop tool results that were already used and recorded. The state object above is the piece that makes the other three safe.

The tempting wrong answers.

Situation Tempting choice Why it fails Better choice
Conversation hits the window limit at turn 40 raise max_tokens max_tokens reserves output space from the same window. It leaves less room for input, so the error comes sooner. compact at the soft threshold and keep a state object
Same symptom switch to a model with a larger window it delays the crash by some turns, costs more per turn, and the model still reads old noise (lost in the middle) reduce what enters the window first
After compaction, the agent quotes the wrong claim amount write a better summary prompt a summary is a paraphrase by design; exact values can still drift move the amount into the state object, outside the summary
Old turns vanish and the agent asks again for the policy number make the sliding window bigger a bigger window only moves the cliff put the policy number in the state object
Answers get worse as the chat grows, but no error appears do nothing, because it still fits fitting is not the same as quality; noise in the window lowers quality before any limit selective retention: drop finished tool results
Depth: how the harness rebuilds the request after compaction

Think of the next request in three parts, in this order. First the stable prefix (tools and system), which stays cached. Then one block that holds the state object and the summary. The application builds this block; no person types it. Then the recent turns, word for word, and the new user message. The state object comes before the summary on purpose. If the summary and the state object disagree, the system prompt tells the model that the state object wins. The harness also updates the state object from tool results, never from the model's own prose alone. The model's prose may be wrong; a tool result is the evidence.

Recall fact: a summary keeps meaning and loses exact values; a state object keeps exact values; max_tokens takes space from the same window, so raising it never fixes a context overflow.

Exploring a codebase bigger than one window

Apply context management strategiesβ€”subagent isolation, scratchpad files, and targeted file readingβ€”to sustain coherent codebase exploration across sessions exceeding context limits.

Three strategies, three jobs.

Strategy Problem it solves Where it lives What survives the session
Subagent isolation (subagent) searching fills the main window with files you read once a subagent with its own context window; it returns a summary only what the main session saved
Scratchpad files (scratchpad) findings are lost when the session ends or compacts a file in the repo or working folder, for example notes/deductible-map.md the file, because it is on disk, not in the conversation
Targeted file reading reading whole folders "for context" wastes the window search first (grep, glob), then read only matching files or line ranges nothing by itself; it keeps each session small

Name the runtime. In Claude Code, subagents are a product feature. The docs say: "Use a subagent when you need context isolation or when your context window is getting full." The built-in Explore subagent and custom subagents in .claude/agents/ both work this way; Domain 2 shows two subagents in sequence. In a custom app on the Messages API, a "subagent" is just another API call with its own messages list, which your coordinator code starts and whose summary your code keeps. In both cases, the scratchpad is an ordinary file. It is not a special API feature. Foundations Domain 5 covers scratchpads and crash-recovery manifests.

The tempting wrong answers.

Situation Tempting choice Why it fails Better choice
Exploration hits the limit halfway through the repo read the whole repo into one big-window model quality falls before the limit; you pay for every file on every turn subagents for search, then targeted reads
A new session repeats yesterday's search rely on the old conversation history the history may be compacted or stale; findings are not organized write findings to a scratchpad file and read it first
The subagent's answer is too long to use give the main session more window the subagent returned raw files, not a summary tell the subagent what to return: a short list with file paths and line numbers
The team stores findings only in a long summary trust compaction to keep them a summary is a paraphrase; paths and line numbers can be lost keep paths and decisions in the scratchpad file

Recall fact: a subagent protects the main window (it returns a summary); a scratchpad file protects findings across sessions (it lives on disk); targeted reading protects each single session (read only what the question needs).

Resuming a session after the code changed

Apply session resumption techniquesβ€”including targeted re-analysis of changed files and context injectionβ€”to restore agent state accurately without repeating prior work.

What a resumed session restores, in Claude Code. These facts come from the Claude Code docs (sessions page and CLI reference).

Command or flag What it does
claude --continue (-c) resumes the most recent conversation in the current directory
claude --resume <id or name> (-r) resumes a specific session; with no argument it shows a picker
--fork-session (with --resume or --continue) creates a new session id instead of reusing the original, so the original stays unchanged
BASH
# Illustrative: resume yesterday's session and name the changed files
git diff --name-only <monday-commit> HEAD
claude --resume deductible-map

Agent SDK β€” the same three choices in code. The Agent SDK (the library for building your own agent on the Claude Code engine) sets these on the query() options. Capture the session id from the result message (session_id) so you can resume later.

Choice Python option TypeScript option
resume the most recent session in the directory continue_conversation=True continue: true
resume one specific session resume=<session_id> resume: <session_id>
branch from it, keep the original fork_session=True forkSession: true

Resume or start fresh? The decision.

Situation Evidence Choose Why the tempting alternative is wrong
A few files changed since the last session git diff lists 3 files; the rest of the analysis still holds resume, name the changed files, re-read only those re-analyzing everything repeats correct work; resuming silently trusts stale reads of the 3 files
Many files changed, or the branch was rebased the history describes code that no longer exists start a fresh session and inject a short summary of what still holds (the scratchpad file, the state object) resuming makes the model reason from old file contents it saw in history
You want to try a risky direction without losing the current state the current session is good --fork-session (Claude Code) or fork_session=True (SDK) resuming the original changes the original
The resumed session cannot reach an MCP server it used before the session started with --mcp-config pass --mcp-config again launch flags are not restored by resume
A custom Messages API app must continue tomorrow there is no session feature; your code owns messages store the state object and summary; rebuild the next request from them the API keeps no conversation between calls; nothing is "resumed" unless your code saves it

Context injection, named precisely. Context injection means your application (or you, typing in Claude Code) puts known facts into the new session's input at the start. In Claude Code, that is your first message, or a file the session reads, such as the scratchpad. In a Messages API app, the application builds that block itself; it is not typed by a person. Inject facts that are still true and small: the decisions, the open questions, the file map. Do not inject the old raw history.

Recall fact: --resume and --continue restore the conversation, not the files; after files change, name the changed files and re-read only those, or start fresh with an injected summary when the history is stale.

Implement prompt reuse strategies (caching, modular prompts, Skills)

Implement prompt reuse strategies (caching, modular prompts, Skills)

Three levels, three artifacts. The prompt reuse strategy card is the drill. This section shows each artifact in full.

Level Reuses Unit of reuse Artifact Verified by
Caching processing of an unchanged input prefix one request's tools + system + leading messages a cache_control marker on the last stable block cache_read_input_tokens > 0 in usage
Modular prompts text shared across many prompts a module file with a version an assembly step at build or request-build time a CI test that every prompt carries the current module version
Skills a procedure across teams, sessions, and hosts a folder: SKILL.md + references + scripts Agent Skills format, loaded by the host the host lists the Skill; a golden task passes

Caching β€” the stable-prefix order, in one full request

The order is tools β†’ system β†’ messages, and the marker ends the stable part. This is the guide's Sample 2 as a real request. Tool definitions come first, because they rarely change. The 8,000-token policy comes second, with a marker on the policy block. Then comes the short user message, which changes each time. Nothing is cut off, and nothing is moved into examples. The policy text is shortened so you can read it. This is a complete request body; the explanations are outside the JSON.

JSON
{
  "model": "YOUR_SUPPORTED_MODEL",
  "max_tokens": 600,
  "tools": [
    {
      "name": "get_claim",
      "description": "Return the claim record for a claim id: status, loss date, sections applied, and open questions.",
      "input_schema": {
        "type": "object",
        "properties": {"claim_id": {"type": "string"}},
        "required": ["claim_id"]
      }
    }
  ],
  "system": [
    {
      "type": "text",
      "text": "HALDEN UNDERWRITING POLICY v2026-03. Section 1: Definitions. Section 2: Covered perils include hail, wind, fire, and theft. Section 3: Exclusions. Section 4: Glass and windshield claims are comprehensive unless caused by a recorded collision event.",
      "cache_control": {"type": "ephemeral", "ttl": "1h"}
    },
    {
      "type": "text",
      "text": "GUARDRAILS: Answer only from the policy. Adjusters make final decisions. If facts are missing, reply with the single line ESCALATE: <reason>."
    }
  ],
  "messages": [
    {"role": "user", "content": "For claim CLM-88213, is the roof hail damage covered?"}
  ]
}
Not supplied in this example β€” defaults and disabled features
Setting not supplied or not visible Meaning for this example
context_management β€” not supplied here No server compaction strategy is enabled by this body. Host/manual compaction is separate.
output_config β€” not supplied here No output_config schema or effort override is supplied. A prompt asking for JSON does not provide schema enforcement.
tool_choice β€” not supplied here With tools supplied, the default is auto: the model chooses whether to request a tool. Without tools, no supplied tool can be selected.
stop_sequences β€” not supplied here No custom stop strings are configured. Generation can still stop for end_turn, tool_use, max_tokens, or another documented reason.
stream β€” not supplied here For a direct non-streaming create/parse call, the result is one message rather than an event stream. A stream helper configures this separately.
thinking β€” not supplied here No explicit thinking override is shown. Behavior depends on the selected model; omission does not universally mean thinking is off.
cache_control β€” not supplied here No top-level automatic cache marker is supplied. Check nested system/tool/content blocks for separate cache_control markers.
metadata β€” not supplied here No application user reference is supplied through metadata. Authentication still comes from the request credentials.

Full request catalog and omission rules. JSON has no comments; these notes are outside the payload.

Placement, line by line. The marker is at system[0].cache_control. Everything before that point, plus that block itself, is the reusable prefix: the tools array and the policy. The guardrail block sits after the marker, so an edit to the guardrail does not remove the policy from the cache. ttl makes the cache last longer, for a prompt that is reused all day. Leave it out to get the default lifetime. The user's question comes last and is never cached. On later requests, the service reuses the prefix when it is byte-identical and the cache entry has not expired. Check usage; do not assume. Foundations covers string versus block placement, tool caching, and growing conversations. The caching-strategy card has the production decision.

Three facts the exam tests about caching. First, cached content still takes space in the window: caching is not compaction. Second, the content before the marker must reach a minimum length, and that minimum depends on the model. So a very small system prompt may never be cached. Third, any byte that changes before the marker starts a new cache entry: a timestamp, a tenant id, or tools in a new order. The symptom is cache_creation_input_tokens on every call and cache_read_input_tokens of zero.

Modular prompts β€” one source, many prompts

A module is a versioned piece of text with a clear purpose. A modular prompt system keeps each piece of shared text in its own file: a compliance preamble, a refusal contract, an output format. A manifest (a list file) says which prompts include which modules. The build puts each prompt together from its modules. It writes the versions into request metadata or your logs. Then an audit can prove which preamble was in force when a given answer was produced.

YAML
modules:
  compliance_preamble:
    file: modules/compliance-preamble.md
    version: 2026.09.1
    owner: legal
  refusal_contract:
    file: modules/refusal-contract.md
    version: 3
    owner: architecture
  claim_summary_format:
    file: modules/claim-summary-format.md
    version: 5
    owner: claims-platform

prompts:
  claims_assistant:
    system_blocks: [compliance_preamble, refusal_contract]
  fraud_triage:
    system_blocks: [compliance_preamble, refusal_contract]
  portal_answer:
    system_blocks: [compliance_preamble, claim_summary_format, refusal_contract]

Assembly always gives the same result, and you can test it without a model. The function below reads the manifest and returns the system array. It puts the marker on the last module that every prompt shares. So the shared prefix is cached across all three products. Illustrative Python.

PYTHON
import yaml
from pathlib import Path

MANIFEST = yaml.safe_load(Path("prompts/manifest.yaml").read_text())


def assemble_system(prompt_name: str) -> list:
    names = MANIFEST["prompts"][prompt_name]["system_blocks"]
    blocks = []
    for i, name in enumerate(names):
        module = MANIFEST["modules"][name]
        text = Path(module["file"]).read_text().strip()
        block = {"type": "text", "text": text}
        if i == 0:
            block["cache_control"] = {"type": "ephemeral"}
        blocks.append(block)
    return blocks


def module_versions(prompt_name: str) -> dict:
    names = MANIFEST["prompts"][prompt_name]["system_blocks"]
    return {n: str(MANIFEST["modules"][n]["version"]) for n in names}

What this gives you. Legal edits one file. The next build updates 40 prompts. A CI test fails any prompt whose rendered system text does not contain the current preamble version. Drift becomes impossible, instead of being found in a review every three months. That is the "preventive versus detective" difference that the guide's answer keys use, applied here to prompt text.

Skills β€” a procedure packaged for reuse across teams and hosts

A Skill is a folder, and SKILL.md is its front door. Agent Skills is an open format. A Skill is a directory with a SKILL.md file, plus optional reference files and scripts. That file has YAML frontmatter, which the host parses, and a Markdown body, which the model reads. Claude Code is one host. Other hosts that support the format can load the same folder. Foundations Domain 2 names the frontmatter keys that the exam tests, and it separates Skills from tools and MCP. The Professional point is Skills as a reuse strategy: the procedure that the three teams were copying and pasting becomes one versioned artifact with an owner.

MARKDOWN
---
name: claim-summary
description: Use when asked to write or review a claim summary for an adjuster, the fraud queue, or the customer portal. Produces the Halden standard summary format.
allowed-tools: Read, Grep
argument-hint: <claim-id> [audience: adjuster|fraud|portal]
metadata:
  owner: claims-platform
  version: "4.2"
  policy_version: "2026-03"
---

# Claim summary procedure

1. Read `references/summary-format.md` for the required sections and field order.
2. Read `references/policy-sections.md`; quote the section numbers you rely on.
3. Never state a coverage decision as final. Adjusters decide.
4. If the audience is `portal`, remove internal notes and follow `references/portal-tone.md`.
5. Output the summary only, in the format from step 1. No preamble.

Reading the frontmatter. The host shows name and description to the model, so the model can choose the Skill when a task matches. The description holds the trigger phrases. allowed-tools pre-approves the listed tools while the Skill runs, so they run without a prompt. It does not remove other tools: current Claude Code docs say every tool remains callable. For example, if a read-only summary procedure must not be able to write files, run it in a subagent whose tools: lists only read tools, or add permissions.deny rules. argument-hint shows a hint to a developer who calls the Skill without arguments. metadata is free-form. Put the Skill's version there, and the policy version it was written for, so a Skill can be audited like a module. The body is the procedure. The reference files hold the long content. This keeps the body short, and the model reads the details only when it needs them.

Where Skills live and who owns them. For a project team, a Skill lives in the repository under .claude/skills/<name>/. Or it is shipped as a plugin, so other projects install the same version. Personal versions go under ~/.claude/skills/ with a different name, so they never hide (shadow) the team's Skill. The owner is whoever owns the procedure. A new version is a pull request. Skill or agent? explains how to combine them when the procedure needs isolation or a specific executor.

Which level for which problem.

Problem in the stem Level Not this
"Same 8,000-token system prompt on every request; latency and cost" caching truncating, downsizing, moving to examples
"Cache reads are zero after enabling caching" caching β€” fix the order; volatile content after the marker a longer TTL, a bigger model
"Legal updates the preamble monthly; some prompts miss it" modular prompts with a version test a quarterly review checklist
"Three teams maintain three copies of the same procedure" a Skill with an owner and a version pasting it into each team's CLAUDE.md
"The procedure must run with read-only access" a Skill that runs in a subagent whose tools: lists only read tools (allowed-tools only pre-approves) a sentence in the prompt asking the model not to write
"Each team needs the same tool connection" not reuse at all β€” that is MCP a Skill (procedure) cannot open a connection

The wrong choice and its failure. Copying a procedure into every project's CLAUDE.md is reuse by copying. It has three problems: it loads in every session, even when the task does not need it; it drifts; and it has no frontmatter, so it cannot pre-approve tools or run in a restricted subagent. Building an MCP server that returns a prompt string mixes up a connection mechanism with a procedure. A Skill is the format designed for procedures; MCP is for tools and data. Moving the policy into a few-shot block to "reuse" it (wrong option D in the guide) does not change whether it can be cached. It is still input that must sit before a marker to be reused. And examples are not the place for a policy. The answer keys use two phrases: "reuse by reference versus reuse by copy," and "cacheable prefix versus relocated text."

See it run β€” the policy assistant, end to end

πŸ” See it run β€” one adjuster question through tier routing, layered system, cache, budget check, and usage

Entry point. An adjuster in the Pacific Northwest asks the claims assistant: "For claim CLM-88213, is the roof hail damage covered?" Follow this request through every decision on this page.

Step 1 β€” the router picks the tier. The registry says coverage_synthesis runs on the deep tier. model_for("coverage_synthesis") reads the environment variable and returns the model id. This is the only place where the id appears.

Step 2 β€” the harness builds system from modules. assemble_system("claims_assistant") returns two blocks. The first is the compliance preamble plus the policy (cached). The second is the refusal contract. The harness fills in the region block from the adjuster's tenant record and inserts it between them. The template version and the module versions go into the request metadata.

Step 3 β€” the budget check. The harness calls the count endpoint with the tools, the three system blocks, and the current messages. The result is 12,340 input tokens. The input room is 176,000. The decision: "send."

Step 4 β€” the request. Tools come first. System comes second, with the marker on block 0. The user message comes last. Illustrative body; the policy is shortened:

JSON
{
  "model": "YOUR_SUPPORTED_MODEL",
  "max_tokens": 600,
  "metadata": {"user_id": "adjuster-7781"},
  "tools": [
    {
      "name": "get_claim",
      "description": "Return the claim record for a claim id: status, loss date, sections applied, and open questions.",
      "input_schema": {
        "type": "object",
        "properties": {"claim_id": {"type": "string"}},
        "required": ["claim_id"]
      }
    }
  ],
  "system": [
    {
      "type": "text",
      "text": "COMPLIANCE PREAMBLE v2026.09.1. HALDEN UNDERWRITING POLICY v2026-03. Section 2: Covered perils include hail. Section 3: Damage discovered more than 30 days after the event is excluded unless reported within 5 business days of discovery.",
      "cache_control": {"type": "ephemeral"}
    },
    {
      "type": "text",
      "text": "REGION RULES: Adjuster region is Pacific Northwest. Cite the state code for any deductible waiver."
    },
    {
      "type": "text",
      "text": "REFUSAL CONTRACT v3: Answer only from the policy. Adjusters make final decisions. If facts are missing, reply with the single line ESCALATE: <reason>."
    }
  ],
  "messages": [
    {"role": "user", "content": "For claim CLM-88213, is the roof hail damage covered?"}
  ]
}
Not supplied in this example β€” defaults and disabled features
Setting not supplied or not visible Meaning for this example
context_management β€” not supplied here No server compaction strategy is enabled by this body. Host/manual compaction is separate.
output_config β€” not supplied here No output_config schema or effort override is supplied. A prompt asking for JSON does not provide schema enforcement.
tool_choice β€” not supplied here With tools supplied, the default is auto: the model chooses whether to request a tool. Without tools, no supplied tool can be selected.
stop_sequences β€” not supplied here No custom stop strings are configured. Generation can still stop for end_turn, tool_use, max_tokens, or another documented reason.
stream β€” not supplied here For a direct non-streaming create/parse call, the result is one message rather than an event stream. A stream helper configures this separately.
thinking β€” not supplied here No explicit thinking override is shown. Behavior depends on the selected model; omission does not universally mean thinking is off.
cache_control β€” not supplied here No top-level automatic cache marker is supplied. Check nested system/tool/content blocks for separate cache_control markers.

Full request catalog and omission rules. JSON has no comments; these notes are outside the payload.

Step 5 β€” the model asks for the claim record. The first response stops with tool_use. It requests get_claim for CLM-88213. The harness runs the tool and gets a raw record of 7,900 tokens. It cuts the record down to the fields the model needs. Then it adds it to the conversation as a tool_result:

JSON
{
  "claim_id": "CLM-88213",
  "status": "open",
  "loss_date": "2026-03-02",
  "discovery_date": "2026-04-10",
  "reported_date": "2026-04-11",
  "sections_applied": [],
  "open_questions": []
}

Step 6 β€” the second call and its usage. The harness adds the assistant's tool request and the trimmed result to the messages. It checks the budget again (12,900 tokens, so "send"). It calls again with the same prefix. The usage in the response shows that the cache worked:

JSON
{
  "input_tokens": 1610,
  "cache_creation_input_tokens": 0,
  "cache_read_input_tokens": 11200,
  "output_tokens": 148
}

Step 7 β€” the answer. The model's text: "Hail is a covered peril under Section 2. Damage was discovered 39 days after the 2026-03-02 event, which Section 3 excludes unless reported within 5 business days of discovery; it was reported the next day, so the exclusion does not apply. Recommend COVERED, subject to adjuster decision." The harness logs the module versions from step 2 together with the answer.

What each step proved. Tier routing kept the classification steps in other parts of the system on the fast tier. Layering let the policy stay cached while the region block changed. The budget check ran before the call. The trimmed tool result kept the second call far below the limit. The usage block is the evidence that reuse happened. The marker alone is not evidence.

Exam lens β€” how CCAR-P asks about this domain

The typical question. The guide's Sample 2 describes an application that sends a large, unchanging system prompt and policy again on every request. A short message that changes each time follows it. The stem names both latency and cost. The correct option puts the stable content first and turns on prompt caching. Do not memorize the stem. Memorize why each wrong option loses. Cutting the policy short removes required context. Switching to the smallest model "regardless of task fit" gives up quality to save cost, and the stem did not ask for that trade. Moving the policy into a few-shot block does not create a reusable prefix that can be cached. Every question in this domain is built the same way: one fix to the structure, and three moves that each break a limit that the stem stated.

Clues in the stem β†’ which objective is being tested.

Phrases the answer keys use to explain answers. Reuse versus discard: caching keeps the context; cutting it loses it. Targeted versus blanket: apply a technique to the step that showed the failure, not to every step. Preventive versus detective: a version test in CI prevents drift; a review every three months only finds it. Reduce versus reuse: trimming reduces what enters the window; caching reuses what enters it. Advisory versus enforced: a guardrail block asks; a harness gate blocks. When two options both seem right, choose the one that keeps the required content and changes the structure.

Multiple-response items. In this domain, the two correct answers are usually the two halves of one fix. Example: put the marker on the last stable block and move the changing content after it. Another example: trim tool results and compact at a threshold. A common wrong second choice is an option that is correct by itself but fixes a different symptom.

Recall this domain

Recall it one more time, in four pictures: βš–οΈ match the tier to the step Β· 🧱 stable policy β†’ tenant β†’ task Β· πŸ“ window minus output equals room for input Β· ♻️ cache, module, Skill β€” never copy.