How to Tune Claude Opus 5.5's Effort Levels for Coding
Anthropic shipped Claude Opus 5.5 on September 22 with a 20% cut to input and output token prices. The detail that'll actually move your bill, though, is quieter: among Claude Opus 5.5's effort levels, medium is now the default instead of high. Same code, same prompt, different spend if nobody told you the default moved. Here's how to set effort deliberately, sweep it against your own coding tasks, and switch it mid-conversation without losing your prompt cache.
Claude Opus 5.5's effort levels, from low to max
Effort is set with output_config.effort on the Messages API, and it controls every token in the response, thinking included. Adaptive thinking is always on for Opus 5.5 and can't be turned off: a request that sends thinking: {"type": "disabled"} now returns a 400 error. Effort is the replacement lever.
The five levels, per Anthropic's effort docs:
low: most efficient, best for simple or latency-sensitive calls like subagentsmedium: balanced speed, cost and quality, the default on Opus 5.5high: spends whatever it takes for excellent results, the default on every other current Claude modelxhigh: for long-running agentic and coding work, over 30 minutes, millions of tokensmax: no constraint on token spending, reserved for the hardest problems
Anthropic's own guidance is blunt about not assuming: effort behaves differently on Opus 5.5 than on Opus 5, so a setting you tuned before needs re-testing, not copying over.
Step 1: Set effort explicitly on every call
Don't rely on the default. Pass effort so you know exactly what you're paying for:
import anthropic
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-opus-5-5",
max_tokens=8192,
messages=[{
"role": "user",
"content": "Fix the race condition in this connection pool and add a regression test: <paste code>"
}],
output_config={"effort": "high"},
)
for block in response.content:
if block.type == "text":
print(block.text)
Setting effort to medium explicitly behaves identically to omitting it, so this is purely about making the choice visible in your code rather than leaving it implicit.
Step 2: Run a fresh effort sweep against your own coding eval
Because Opus 5.5 thinks more per turn than Opus 5 at the same effort setting, don't reuse an old sweep. Run one against a real task from your codebase:
import time
import anthropic
client = anthropic.Anthropic()
prompt = "Refactor this webhook handler to retry with backoff instead of failing silently: <paste code>"
for effort in ["low", "medium", "high", "xhigh", "max"]:
start = time.time()
response = client.messages.create(
model="claude-opus-5-5",
max_tokens=32000,
messages=[{"role": "user", "content": prompt}],
output_config={"effort": effort},
)
elapsed = time.time() - start
print(effort, response.usage.output_tokens, f"{elapsed:.1f}s")
Check output quality against your test suite at each level, not just token count. The docs note Opus 5.5 often beats other models at their highest settings while running at its own default, so you may find medium already clears your bar for routine changes, with xhigh reserved for the gnarly ones.
Step 3: Split effort across one agentic loop with per-message effort
A single coding session mixes cheap steps (reading files, running linters) with expensive ones (designing the fix). Per-message effort, currently in beta, lets you change levels mid-conversation without restarting the prompt cache:
curl https://api.anthropic.com/v1/messages \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "anthropic-beta: mid-conversation-output-config-2026-07-01" \
-H "content-type: application/json" \
-d '{
"model": "claude-opus-5-5",
"max_tokens": 64000,
"output_config": {"effort": "xhigh"},
"messages": [
{"role": "user", "content": "Design and implement a retry queue for the payment webhook handler."},
{"role": "assistant", "content": "..."},
{"role": "system", "content": [], "output_config": {"effort": "low"}},
{"role": "user", "content": "Now write the unit tests for the happy path only."}
]
}'
The empty-content system message carries only the new effort level; it takes effect from the next user turn onward. Changing the top-level effort between requests instead would invalidate the cached prefix, so use this form whenever you're staying in one conversation.
Step 4: Size max_tokens for the effort level you land on
max_tokens is a hard cap on thinking plus visible response combined, not just the reply. At xhigh or max, a small cap can cut off the model mid-thought:
{
"model": "claude-opus-5-5",
"max_tokens": 64000,
"output_config": {"effort": "xhigh"}
}
Starting around 64k tokens for xhigh and max, then tuning down once you see actual usage, matches Anthropic's own recommendation.
Gotchas
thinking: {"type": "disabled"}now 400s. If your Opus 5 integration disabled thinking, remove that field entirely and lowereffortinstead.- Forced tool use is gone.
tool_choiceof"any"or a named tool returns a 400 on Opus 5.5. Use"auto"with strict tool use if you need schema-valid output. - Progress text between tool calls now hides by default. It arrives in
thinkingblocks with empty text at the default display setting, so a UI that streamed those notes as progress updates will go quiet unless you set athinking.displayvalue that returns them. - Per-message effort is beta. Forget the
mid-conversation-output-config-2026-07-01header and you get a 400, not a silent no-op.
Getting effort right on Opus 5.5 isn't a one-time setting, it's the main dial between what a coding task costs and how well it gets done, and the model changed that dial's default out from under anyone who upgrades without checking.
If your agents run unattended in production, an unexamined default effort level is now a line item on your infra bill, not just a quality knob.