Prompts are contracts
By Bob Ulrich
Anthropic’s prompting documentation ships a warning that almost nobody has read. A code review prompt that says “be conservative” or “only flag high-severity issues” can cause Opus 4.7 to silently drop real bugs. The model investigates as carefully as Opus 4.5 did, and it identifies the bug. Then the report omits it, because the instruction said to be conservative.
That is one of five prompt patterns that broke between Opus 4.6 and Opus 4.7. Anthropic ships a warning for each one, inside docs that almost no migration toolchain surfaces. pip install -U anthropic catches none of them, and none produce a 400 error. Most produce silently worse output that looks the same as what you had before.
The two contracts
Prompting on Opus 4.7 is no longer a single instruction-following contract. It is two contracts:
- A budget contract: the
effortparameter decides how hard the model tries before answering.xhighis the recommended default for coding, andmaxis “the trap” (more on that in Mistake 5). - A literalness contract: the model executes what you said, not what you meant. Per Anthropic’s launch announcement, “Where previous models interpreted instructions loosely or skipped parts entirely, Opus 4.7 takes the instructions literally. Users should re-tune their prompts and harnesses accordingly.”
Both contracts changed in April 2026. Half your prompt library is signed against the old terms.
Anthropomorphism is the wrong frame here. Opus 4.7’s post-training shifted instruction-following weights toward narrow execution. Where 4.6 generalized from one example to a class of similar items, 4.7 stops at the example. Where 4.6 inferred unstated requests from context, 4.7 asks. None of this is the model “being more careful” or “being more obedient.” A different post-training distribution scores narrow execution higher than loose interpretation, and the resulting policy is what you now prompt against.
Karpathy’s “Software 2.0” essay (2017) traced the arc from “what code does” to “what code learns.” Adaptive thinking and the literalness shift are the next step on the same arc: not just what the model does, but how hard it tries and exactly what it executes. Your prompt is no longer an instruction. It is a multi-dimensional contract, and migrating between models means re-signing it.
Boris Cherny, who leads Claude Code at Anthropic, posted on launch day that “it took a few days for me to learn how to work with it effectively” (X, 2026-04-16). If the lead engineer of Claude Code spent days recalibrating, the rest of us will not coast on 4.6 muscle memory. Your prompt library from 2025 deserves a closer look than the changelog suggests.
Half your prompt library is signed against the old terms.
Mistake 1: the conservative-prompt trap
This is the failure mode the post opens with, and it makes the literalness contract concrete. From Anthropic’s prompting best practices doc:
When a review prompt says things like “only report high-severity issues,” “be conservative,” or “don’t nitpick,” Claude Opus 4.7 may follow that instruction more faithfully than earlier models did — it may investigate the code just as thoroughly, identify the bugs, and then not report findings it judges to be below your stated bar.
The mechanism is the literalness contract from the previous section. Opus 4.5’s review pass would silently bump moderate-severity bugs into the “high-severity” bucket, because the surrounding instruction said “find the important problems.” Opus 4.7’s pass partitions strictly. It finds everything, applies your stated filter, and reports only what survives the filter. The investigation cost was paid, and the output was discarded.
Catch-rate regressions like this never show up in your CI dashboard. The count of findings stays roughly constant, and so do latency and cost. What drops is the catch rate on bugs sitting just below your stated severity bar, and that is where the bugs you actually want to find tend to live.
Eval methodology
Treat the headline as a falsifiable hypothesis, not a confirmed regression. Here is the eval to run on your own codebase:
- Sample 10-20 known-bug diffs. Use real PRs from open-source projects with CVE-tagged commits, or your own historical PRs where the post-merge fix landed within a week.
- Run identical review prompts against
claude-opus-4-6andclaude-opus-4-7, both ateffort: "xhigh"(the new recommended coding default). - Run again with restraint language stripped. Remove every instance of “be conservative,” “only flag high-severity,” “skip nitpicks,” “don’t be pedantic.” Keep everything else identical.
- Score on three axes: catch rate (did the review name the actual bug), false positive rate, and severity grading. For severity, name your grader explicitly. If you use a calibrated GPT-5 or Sonnet-4.6-as-judge, validate the grader against a held-out human-labeled set before trusting its grades. LLM-as-judge needs its own eval, and “I asked Claude to grade Claude” without that step is the same vibes problem this post argues against.
I have not yet run this eval at scale. The opening anecdote is what Anthropic’s docs warn about, not a controlled measurement I am asserting. The methodology above is what I run next; results and a companion repo land in part 2 of this post by 2026-06-10. There is no companion repo URL yet, by design: I will not link a repo that does not exist. Until then, run the eval on your own codebase before changing your review prompts.
Fix
Audit every review or triage prompt for restraint language. Rewrite as “Report all findings. Mark severity (critical, high, medium, low, nit). Let the human filter.” The post-trained policy now treats restraint instructions as a stricter filter on what to surface. Move the filter from the prompt to the human reading the output.
Eval for your codebase: before adopting the rewrite, run 20 production review prompts pre/post and compare bugs caught at moderate severity. If the rewrite catches things the conservative version missed, the trap was real for you.
Mistake 2: the scaffolding tax
Every prompt that says “think step by step” or “plan before acting” or “double-check your work” was scaffolding around a reasoning gap in earlier Claude models. Adaptive thinking at the high/xhigh defaults does the planning, the chain-of-thought, and the verification natively. Anthropic’s docs say “at the default effort level (high), Claude almost always thinks” and continues to think on tasks the model judges substantive. Your scaffolding pays for the same reasoning twice: once in compelled chain-of-thought tokens that satisfy your literal instruction, and once in the model’s own thinking blocks that did the actual reasoning. The scaffolding tax is real output-token cost on work the model would have done anyway.
A narrower variant of the same advice appears in Anthropic’s prompting best practices: “If you’ve added scaffolding to force interim status messages (‘After every 3 tool calls, summarize progress’), try removing it.” That doc only flags the interim-status case. Extending it to chain-of-thought scaffolds is my generalization, not Anthropic’s. The mechanism is the same in both: adaptive thinking subsumes the work the scaffold was paying for.
| Era | Prompt | Output composition | Output-token cost |
|---|---|---|---|
Opus 4.5 with "think step by step" | scaffolding present | compelled chain-of-thought + final answer | ~1.7× baseline |
Opus 4.7 at xhigh effort | no scaffolding | native adaptive thinking blocks + final answer | ~1.0× baseline |
Same output quality, same workload. A different prompt produces a different bill, and the difference is the tax.
Fix
Delete the scaffolding. Raise effort one notch (high to xhigh, or xhigh to max if the workload genuinely earns it), and re-baseline against your eval. The default state on Opus 4.7 is “the model does the planning.” Re-add scaffolding only if the eval shows it earned its place back.
Eval for your codebase: pick 10 representative tasks. Run identical prompts at xhigh effort with and without “think step by step.” Measure output quality and total output_tokens. If quality holds and cost drops, the scaffolding was the tax.
Mistake 3: silent omission
On Opus 4.7, thinking.display defaults to "omitted" instead of "summarized". Streaming UIs that relied on summarized thinking blocks for progress indication now hang on a long blank pause before text starts. Thinking blocks still emit, but their thinking field is empty. Your reasoning panel goes dark, and then text streams. From the user’s seat, the model “thought for ten seconds about nothing” and then produced an answer.
A live GitHub issue on the claude-code repo shows users tripping over this immediately after the migration. The SDK changes the default with no warning, and the docs note the change in a paragraph that is easy to miss. The symptoms look like a streaming bug rather than a config change.
This is a defaults problem more than a user error. Anthropic chose the new default to optimize time-to-first-text-token. That choice was right for batch workloads where reasoning is internal, and it broke chat workloads where reasoning is the UX. The fix lives in your config, but the root cause lives in the SDK defaults, and the right migration tooling would auto-detect streaming and pick summarized.
Either way, you are charged for the full thinking tokens whether you display them or not. display: "omitted" is a latency optimization, not a cost optimization.
Fix
If you stream reasoning to a user-facing UI, set thinking.display to "summarized" explicitly:
thinking = { "type": "adaptive", "display": "summarized",}If your application does not surface reasoning to anyone, leave display at the new default. The faster time-to-first-text-token is real.
Eval for your codebase: stream a 1k-token reasoning task with the new default and with display: "summarized". Measure time-to-first-text-token and time-to-first-thinking-token. If your UX shows progress to users, the second config is what they will see.
Mistake 4: re-engagement cost
Chat patterns that worked on Claude 3.5 Sonnet are now the most expensive prompt pattern on Opus 4.7: “do X” → result → “now also Y” → result → “actually also Z.” Each new user turn invites adaptive thinking to re-engage and generate fresh thinking tokens, billed at the output rate. A 10-turn drip-feed conversation generates roughly 10x as much thinking output as one fully-specified single turn at the same effort level.
Get the mechanism right, because the obvious story is wrong. Prior-turn thinking blocks are not re-executed. They are preserved in the input context, cached after the first occurrence and billed at the input cache-read rate. What costs money is the new thinking the model generates for each new turn. The literalness contract means the model treats each new user request as its own scoped task and re-derives the reasoning from scratch.
Anthropic’s best-practices post for Opus 4.7 with Claude Code puts the workflow shift directly:
Specify the task up front, in the first turn. Well-specified task descriptions that incorporate intent, constraints, acceptance criteria, and relevant file locations give Opus 4.7 the context it needs to deliver stronger outputs. Ambiguous prompts conveyed progressively across many turns tend to reduce both token efficiency and, sometimes, overall quality.
That advice does not survive contact with conversational UX. Real human-in-the-loop workflows cannot always specify everything upfront, because the human is figuring out what they want as they go. Real agentic loops cannot either, because the next step depends on the result of the previous one. When you can spec upfront, do. When you cannot, define explicit phases, reset the conversation between phases, and treat each phase as its own first turn with a full spec.
| Pattern | Turns | Fresh thinking generated | Billed where |
|---|---|---|---|
| Drip-feed: “do X” → “now Y” → “now Z” → … | 10 | ~9,000 tokens | output rate, every turn |
| Full-spec single turn with intent + constraints + acceptance criteria | 1 | ~1,200 tokens | output rate, once |
Prior thinking is preserved as cached input either way. The cost difference is the fresh output thinking the model generates each turn, because the literalness contract makes it re-derive its scoping from scratch.
Fix
For workloads you can spec upfront: write the full task in turn 1, with intent, constraints, acceptance criteria, and file locations. For workloads you cannot: define explicit phases, reset the conversation between phases, and treat each phase’s first turn as the full spec for that phase.
Eval for your codebase: pick a 5-step task you would normally drip-feed. Run it as 5 separate turns and as one fully-spec’d turn. Compare total output_tokens (mostly thinking) and total wall-clock. That delta is your re-engagement cost.
That advice does not survive contact with conversational UX.
Mistake 5: the max effort trap
Two opposite mistakes hit the same workload from different directions. The first is leaving the API at its implicit high default while running coding workloads, where Anthropic explicitly recommends xhigh. The second is jamming max on every call, which overthinks, costs more, and sometimes produces worse output. Towards AI’s empirical 12-coding-problem effort sweep calls max “a trap” because of diminishing returns past xhigh, plus overthinking risk on bounded problems where additional reasoning produces second-guessing rather than insight.
Anthropic’s effort docs state plainly: “The API default is high. To use xhigh, set effort explicitly; the value you pass overrides the default.” The recommended starting point for Opus 4.7 is xhigh for coding and agentic work, high minimum for intelligence-sensitive workloads, and max only for genuinely frontier problems where evals show measurable headroom. Boris Cherny confirmed the same operational default in his launch-day Opus 4.7 thread: xhigh for most tasks, max reserved for the hardest.
Migration-day teams keep tripping over two operational details. First, effort settings persist within a session: change once, and it stays until the next reset. Second, like silent omission, this is partly a defaults problem. The implicit high default is reasonable for chat-style workloads and underspends on agentic coding, where Anthropic’s own guidance is one notch up. The fix lives in your config, but the cause is a default tuned without knowing which workload you actually run.
| Workload | Effort | Why |
|---|---|---|
| Chat / Q&A | medium | Drop from default high; skip thinking on simple lookups; cuts cost |
| Code generation | xhigh | Native planning, reasoning, verification; cheaper than scaffolding |
| Agentic loops | xhigh | Adaptive thinking enables interleaved reasoning between tool calls |
| Hard math / proofs | max | Earned only when evals show measurable headroom past xhigh |
| Routine triage | low-medium | Stricter scoping; faster; explicit step-down from default |
Fix
Default to xhigh for coding and agentic workloads. Escalate to max selectively, only on workloads where you have measured the improvement.
Eval for your codebase: run your top-10 production prompts at high, xhigh, and max. Compare task-success grading and median cost. Where xhigh ≈ max on success and max costs 1.5-3x more, max is the trap for that workload.
Mistake 6: you shipped without a regression eval
Five mistakes worth of behavioral shifts, and most teams migrated by changing one config line and shipping. The most common production failure on model migrations is not any single behavior change. It is the absence of the regression eval that would have caught whichever of mistakes 1-5 are real for your codebase.
A useful regression eval is small and cheap. Take thirty to one hundred graded examples sampled from your production traffic. Score them on three axes: task-success rate (did the model do the thing), median cost per call, and median latency. Measure cost in dollars rather than tokens, so the tokenizer change in the next section becomes visible. Run the eval pre-migration and post-migration. If any of mistakes 1-5 are real for your prompt library, the eval surfaces them as regressions on at least one axis. If none are real, you have shipped the model upgrade with evidence.
Without the eval, you are trusting vibes, including the vibes in this post. Every recommendation here is testable on your codebase, and every team should test before adopting. Eugene Yan’s “Patterns for Building LLM-based Systems & Products” and Hamel Husain’s “Your AI Product Needs Evals” are the two canonical references on what this should look like in practice. Both predate Opus 4.7 by a year, and both apply unchanged.
Sidebar: cost surprises behind the unchanged $5/$25 sticker
Opus 4.7 lists at the same per-MTok price as Opus 4.6. Three things behind the price tag changed:
- Tokenizer change. Per Cloudzero’s pricing analysis, the new tokenizer can use up to 1.35x as many tokens per character on the same text. Code-heavy and structured-data workloads cluster at the high end. The per-MTok price is unchanged; the per-task cost is up by whatever your tokenizer-change ratio turns out to be.
- Image tokens. Per the migration guide, the per-image cap moved from roughly 1,600 tokens to roughly 4,784 tokens. Workloads that pass full-resolution screenshots or PDFs straight into the model see an immediate 2-3x cost increase per image with no client-side change.
- Banned sampling parameters.
temperature,top_p, andtop_know return a 400 error. Anthropic’s position is thattemperature = 0never actually guaranteed determinism on prior models, so the parameter is gone rather than deprecated. Existing migration scripts that pass these values now error on the first call.
Manual extended thinking’s budget_tokens parameter also returns a 400 error on Opus 4.7. Adaptive thinking is the only supported mode, and the migration guide covers the swap. Anyone who has migrated has hit this; it is command #1 in the harness audit below.
Sidebar: this pattern is cross-provider
Budget-and-literalness as a contract shift is not unique to Anthropic. Gemini 2.5’s thinking_budget parameter and OpenAI’s reasoning_effort represent the same architectural shift toward adaptive reasoning across model families. The five mistakes in this post translate to either provider with different parameter names, and the shape of the migration is the same. If your stack runs Claude alongside Gemini or GPT, you are running the same audit, and your prompt-library cleanup is the same cleanup.
Without the eval, you are trusting vibes, including the vibes in this post.
The harness audit (Monday morning)
Six grep commands to find every place in your codebase that hits one of the five mistakes:
# 1. Find every place still passing budget_tokens (now a 400)git grep -nE 'budget_tokens|"enabled".*budget' --
# 2. Find every "be conservative" / "only high severity" restraint promptgit grep -niE '(be conservative|only.*high|skip.*nitpick|don.{1,2}t.*nitpick)' --
# 3. Find reasoning scaffolding now redundant under adaptive thinkinggit grep -niE '(think step by step|plan before|double[- ]check|chain of thought)' --
# 4. Find adaptive-thinking call sites missing display: summarizedgit grep -lE 'thinking.*adaptive' | while read f; do if ! grep -qE '"summarized"|display.*summarized' "$f"; then echo "$f: adaptive thinking without explicit display:summarized" fidone
# 5. Find banned sampling params still setgit grep -nE '(temperature|top_p|top_k)\s*[:=]' -- '*.py' '*.ts' '*.json'
# 6. Audit cache hit ratio before/after migration# (run against your usage logs, not the codebase)jq '[.cache_creation_input_tokens, .cache_read_input_tokens] | add' usage-logs/*.jsonl | awk '{sum+=$1} END {print "total cached:", sum}'# Compare 30 days pre-migration vs 30 days post.# A drop in the cache-read ratio means the tokenizer change shifted your cache breakpoints.The new defaults
A tight checklist for sane Opus 4.7 defaults across your prompt library:
- Set
thinking: {type: "adaptive"}explicitly (silent omission of the field gives no thinking at all) - Set
effort: "xhigh"as your default for coding and agentic workloads - Set
display: "summarized"if your UX surfaces reasoning to users - Specify the full task in turn 1 (intent, constraints, acceptance criteria, file locations)
- Delete restraint language from review and triage prompts
- Delete reasoning scaffolding (“think step by step,” “plan before acting,” “double-check”)
- Build verification into the agentic loop instead of asking the model to verify itself
- Drop
temperature,top_p,top_kfrom your client (they 400 now) - Audit cache breakpoints in your usage logs before and after migration
- Ship a regression eval before the migration, not after
What Anthropic should ship next
What follows is one author’s wishlist, not panel consensus. Anthropic shipped Opus 4.7 in a defensible state. Hard-erroring on budget_tokens instead of warning may be the right call when the parameter has no semantic meaning under adaptive thinking. A deprecation warning would silently run the wrong mode for one release while the user thinks they have time to migrate. Tradeoffs are not free. The migration surface is still large enough that some of these would land:
- A
claude migrate <path>command that reads a codebase, surfaces the five mistakes from this post, and suggests rewrites. The grep audit above is what that command would run. Doing it once and shipping it as tooling is the difference between a workaround manual and a migration plan. - An SDK default for
displaytied to whether the request is a streaming request. Batch workloads keepomitted, and streaming workloads picksummarizedautomatically. The current default optimizes for one workload while silently breaking the other. - A model-release regression-eval template. Every model release is a contract change. A 50-prompt regression eval template that maps to common workload patterns (chat, coding, agentic) would do more for migration adoption than any blog post.
- A
cost_auditflag in the SDK that surfaces tokenizer-change deltas and cache-breakpoint shifts in usage logs, without custom jq pipelines.
If you push 4.7 the way you pushed 4.6, the model will tell you it disagrees, do a modified version of what you asked, and re-argue when corrected. That is not a regression. That is the model holding up the part of the contract that says “follow instructions literally.” The fix is to write the contract more clearly.
The harness is now the bottleneck, and this post is the workaround manual. Part 2 ships the eval results and a companion repo by 2026-06-10, 30 days from publish. If the eval does not replicate the warnings in Anthropic’s docs, Part 2 says so, because falsifying is the publication. Separate from either of mine, the post Anthropic should write is the migration tooling that makes the harness retune itself. If Anthropic does not ship claude migrate, the third-party tool that does will own the migration moment for every model release going forward. That is the category this contract change opens.