Claude Code v2.1.284 Major Updates - Sonnet 5.5 Arrives and Auto Mode Default Expansion to All Plans

Claude Code v2.1.284 Major Updates - Sonnet 5.5 Arrives and Auto Mode Default Expansion to All Plans

Claude Code v2.1.284 released. Adds Sonnet 5.5, defaults to auto mode when permissions unset. Security and model improvements. Migration results using /claude-api migrate for Sonnet 5 code included.
2026.09.29

This page has been translated by machine translation. View original

"""Sample that looks up the weather and gives a one-line clothing advice (for Claude Sonnet 5.5)"""
import json
import sys

import anthropic

MODEL = "claude-sonnet-5-5"

client = anthropic.Anthropic()

# Re-run the same request with a different model when rejected by the safety classifier (Claude API only)
FALLBACK_OPTIONS = {
    "betas": ["server-side-fallback-2026-07-01"],
    "fallbacks": "default",
}

# Since tool_choice enforcement is not available, call verification and retries are handled in code
MAX_TOOL_ATTEMPTS = 3

WEATHER_TOOL = {
    "name": "get_weather",
    "description": "Get the current weather for the specified city",
    "strict": True,
    "input_schema": {
        "type": "object",
        "properties": {"city": {"type": "string", "description": "City name"}},
        "required": ["city"],
        "additionalProperties": False,
    },
}

def get_weather(city: str) -> dict:
    # Fixed data for demo purposes (in practice, call a weather API)
    return {"city": city, "condition": "Sunny", "temperature_c": 24}

def check_refusal(response) -> None:
    """Reject refused responses (HTTP 200 + stop_reason="refusal") before reading content"""
    if response.stop_reason == "refusal":
        category = response.stop_details.category if response.stop_details else None
        raise RuntimeError(f"Request was refused (category={category})")

def ask_weather(question: str) -> dict:
    """Have the model call the get_weather tool and retrieve weather from the tool input"""
    for _ in range(MAX_TOOL_ATTEMPTS):
        response = client.beta.messages.create(
            model=MODEL,
            max_tokens=16000,
            system="Please call the get_weather tool to retrieve the weather for the city mentioned in the question.",
            tools=[WEATHER_TOOL],
            output_config={"effort": "low"},
            messages=[{"role": "user", "content": question}],
            **FALLBACK_OPTIONS,
        )
        check_refusal(response)
        tool_use = next((b for b in response.content if b.type == "tool_use"), None)
        if tool_use is not None:
            return get_weather(**tool_use.input)
    raise RuntimeError(f"The get_weather tool was not called after {MAX_TOOL_ATTEMPTS} attempts")

def advise(weather: dict) -> str:
    """Return a one-line clothing suggestion for the weather (set effort to low to prioritize response speed)"""
    response = client.beta.messages.create(
        model=MODEL,
        max_tokens=16000,
        output_config={"effort": "low"},
        messages=[
            {
                "role": "user",
                "content": f"Please give me a one-line clothing suggestion for the following weather: {json.dumps(weather, ensure_ascii=False)}",
            }
        ],
        **FALLBACK_OPTIONS,
    )
    check_refusal(response)
    return next(b.text for b in response.content if b.type == "text")

if __name__ == "__main__":
    question = sys.argv[1] if len(sys.argv) > 1 else "What's the weather in Tokyo?"
    weather = ask_weather(question)
    print(weather)
    print(advise(weather))

This is Ishikawa from the Cloud Business Division. Claude Code v2.1.284 (released 2026-09-28) has been released. Today, I tried using /claude-api migrate to automatically migrate code for the new Sonnet 5.5.

The update also includes a change to the behavior when starting permission modes, so please also check the breaking changes.

The previous update article is here.

https://dev.classmethod.jp/articles/20260924-cc-updates-v2-1-283/

Update Summary

v2.1.284 includes 100 changes. In this article's classification, there are 53 fixes, 21 improvements, 13 new features, 6 security updates, 5 breaking changes, and more. In addition to changes for the VS Code extension (18) and Claude Tag (10), there are also a batch of changes related to the Claude apps gateway and usage limits.

Also, Sonnet 5.5 has been announced—smarter, more efficient, and 30% faster than Sonnet 5. Since it will be up to 30% cheaper for most tasks, usage of Claude Code will expand even further. Use it for well-defined everyday tasks such as bug fixes and rapid feature iteration.

https://x.com/ClaudeDevs/status/2104641318555353400

Notable Updates

New Feature: Addition of Claude Sonnet 5.5

Claude Sonnet 5.5 (claude-sonnet-5-5) has been added and has become the default Sonnet model for the Anthropic API. With 1M context, pricing is $2 input / $10 output per million tokens, and $0.20 for cache reads.

Those using sonnet with the Anthropic API will want to be aware that the default Sonnet is changing.

Bug Fix: Fixed issue where "Prompt is too long" error persisted after compact

The bug where "Prompt is too long" errors continued after compact has been fixed. If the request after compact is still too long, it reduces the amount of recent conversation retained and compacts again.

This feels like a fix that will help those who have experienced getting stuck in an error loop even after compact in long sessions. On the other hand, since re-compacting reduces the amount of recent conversation retained, it's worth being aware that the most recent instructions may be dropped from the summary.

Bug Fix: Fixed issue where raw errors were displayed for corrupted response streams

The bug where raw errors such as "JSON Parse error" or "undefined is not an object" were displayed for corrupted response streams, or where the word "undefined" was written into responses, has been fixed. They will now be retried or reported as interrupted responses.

Since having "undefined" mixed into a response could lead to using it without noticing, I find it reassuring that they will now be treated as retries or interruptions.

Security: Auto mode startup when permission mode is not set expanded to all plans and providers

When no permission mode is set, interactive terminal and VS Code sessions will now start in auto mode. This applies to all plans and providers, and if permissions.defaultMode is set, that takes precedence.

I think this will have a greater impact on those who have been using it without being conscious of permission modes. If you want to continue using Manual mode, I recommend explicitly setting permissions.defaultMode using the configuration example in the breaking changes section below.

Security: Fixed pre-authorization of plugins under allowManagedPermissionRulesOnly

Under the managed setting allowManagedPermissionRulesOnly, the issue where marketplace, claude.ai, and npm-sourced plugins could pre-authorize their own tools via allowed-tools has been fixed. Pre-authorization is only maintained for plugins from official Anthropic sources and plugins from sources trusted by managed settings.

For organizations that centralize permission rules on the admin side with allowManagedPermissionRulesOnly, tools from plugins whose sources are not trusted by managed settings will no longer be pre-authorized, so if there are plugins you want to maintain pre-authorization for, you will need to trust that source in managed settings.

Security: Sanitizing invisible characters and tags mimicking Claude Code markup in MEMORY.md

When loading automatic memory, invisible characters and tags that mimic Claude Code's own markup contained in MEMORY.md and called memory notes are now sanitized before being passed to Claude.

For those using automatic memory, I see this as an improvement that applies simply by updating, without any special configuration.

Update Details

New Features

  • Addition of Claude Sonnet 5.5 (claude-sonnet-5-5) (see Notable Updates)
  • "Yes, but ask again next time" has been added to the confirmation before reading outside the working directory in auto mode. This allows only that one read, and subsequent reads will prompt again
  • /mcp reconnect all has been added to the interactive terminal, allowing you to reconnect MCP servers that failed to connect or require authentication all at once
  • Key binding actions effortSlider:decreaseEffort, increaseEffort, and toggleUltracode have been added, making it possible to reassign the arrow keys and Tab key of the /effort slider in keybindings.json
  • Regarding Claude apps gateway spend limits, if the gateway is running on this version or later, the amount (e.g., "$271.40 / $500.00 spent this month") will now be displayed in /usage and the status line. used_usd, limit_usd, and period have been added to rate_limits.spend_limit in the status line
  • In Claude apps gateway, a startup warning is now displayed when availableModels in the management policy is empty, or when the startup model for Claude Code is not included without setting model or enforceAvailableModels
  • You can now specify auth: { google: {} } as the destination for telemetry.forward_to in Claude apps gateway, allowing you to directly export telemetry to Google Cloud OTLP endpoints using the gateway's Google Cloud credentials
  • Certificate-based client authentication (private_key_jwt) between Claude apps gateway and identity providers is now supported. This is for identity providers that issue certificate credentials rather than client secrets
  • [VS Code] An option to display timestamps above each prompt and response has been added, with a date line inserted where the date changes (Setting "Claude Code: Show Message Timestamps", default off)
  • [VS Code] Plugin loading errors and notes are now displayed on each row of Manage plugins, and a popup has been added where you can disable, uninstall, or copy errors
  • [VS Code] An Ultracode on/off switch has been added below the Effort slider, replacing the Ultracode stage on the slider. The model pill will display "· Ultracode" at any effort level
  • [Claude Tag] You can now select a model family like "Opus (latest)" as default for threads, channels, and DMs, and the selection will follow the latest model of that family
  • [Claude Tag] A spending forecast chart in analytics now includes the portion of spending that counts toward organization-wide limits and the percentage of limit usage

Improvements

  • Improved startup time and memory usage by constructing the settings schema only for the parts actually used in the settings files
  • Retries after a connection drop mid-response now share the same retry count pool as other retries for that request. Requests that keep failing will be cut off sooner
  • In non-interactive mode on the first turn, even if CLAUDE_CODE_MCP_STARTUP_WAIT_MS is 0, connecting MCP servers specified by --allowedTools or mcp_tool hooks will now wait up to 2 seconds
  • Improved the usage limit waiting display. The limit status and a countdown including usage credits options are consolidated into one block below the prompt, and the countdown is no longer repeated in the limit message
  • /rate-limit-options now appears in /help and the command menu for claude.ai subscribers, making it easier to find the command that usage limit notifications direct you to
  • The notification when a Sonnet model's safeguard flags a message has been changed to explain the reason and show the option to edit and retry
  • The "No such tool available" error when tools in Claude in Chrome are called without a prefix now indicates the correct tool name to call
  • Monitor event rows now display the output content of each event rather than repeating descriptions, and no longer repeat "Waiting for N … to finish" lines with no change for each event
  • /claude-api has been improved. hillclimb no longer spends rounds on rephrasing prompts too small to be measured by eval, and additional pages requested alongside report.html are created as single local files that load nothing from the network
  • In lists such as /tasks, /copy, and /hooks, details following each name are aligned in one column if they fit, and placed at the right edge if they don't
  • claude plugin marketplace add now displays a message and instructions for undoing when replacing a marketplace that was already added from a different source with the same name
  • The startup rejection message when API keys, tokens, or apiKeyHelper are configured while managed settings require sign-in (forceLoginMethod or forceLoginOrgUUID) now shows the credentials in use, where they are configured, and how to remove them
  • Running claude remote-control in an untrusted folder now prompts for workspace trust in the terminal without exiting
  • /recap has been changed to issue a brief notification and decline to run when relayed via chat threads (including your own), routines, or webhooks. It will still run as before when input from the terminal, Claude app, Remote Control, -p, or SDK host
  • On artifact pages, Claude now writes design policies within the page rather than in a reply, and uses names already given by the user as page titles
  • When the Artifact tool is passed a claude.ai chat or project link, an artifact from within a chat, or only an artifact ID, it now asks for the correct link or content without stopping processing
  • The filter tabs in /artifacts are now displayed as single-word labels (All · Mine · Shared) next to the title, using the same tab bar as /config and /plugin
  • [Claude Tag] For @mentions from users who have not connected a Claude account, a private sign-in prompt is now posted every time rather than only the first time. Additionally, improvements have been made to the delivery scope of "Notify members now" in management settings, wait notifications for on-demand runners in self-hosted environments, error display and GitHub sign-in when adding channel managers, and the display of channel access lists

Security

  • Fix for pre-authorization of plugins under allowManagedPermissionRulesOnly (see Notable Updates)
  • Sanitizing invisible characters and tags mimicking Claude Code markup in MEMORY.md (see Notable Updates)
  • Fixed an issue where the value of ANTHROPIC_FOUNDRY_RESOURCE was embedded in the Foundry endpoint hostname without validation. Values that are not simple resource names are now rejected
  • Fixed a bug where rules symlinked to .claude/rules from outside the project were skipped without ever showing the external import approval confirmation. The same approval is now required for .claude directories symlinked from outside the project
  • Fixed a bug where a key pressed the moment the terminal regained focus could answer the Remote Control activation confirmation before the short safety delay resumed
  • Hardened the Workflow tool sandbox against errors thrown by asynchronous script hooks

Fixes

  • Fixed raw error display for corrupted response streams: See Notable Updates
  • Fixed issue where "Prompt is too long" error persisted after compact: See Notable Updates
  • Fixed bug where a turn ended in error immediately after a thinking block: Fixed a bug where an overloaded error or server error arriving immediately after a thinking block caused the turn to end in error without retrying
  • Fixed crash from invalid image and document blocks in Agent SDK sessions: Fixed a bug where a crash occurred when a user message contained an image with an invalid source, and a bug where all turns after an invalid document block failed. Invalid images are replaced with a descriptive note
  • Fixed bug where MCP tool calls failed in resumed sessions: Fixed a bug where MCP tool calls failed with "No such tool available" while the MCP server was connecting. Calls now wait up to 10 seconds for the server to connect
  • Fixed bug where claude mcp add reported success under MCP server restrictions: Fixed a bug where it reported success when managed settings restricted MCP servers to plugin-sourced only. Servers that won't be loaded are no longer saved, and the command now rejects and shows how to resolve the issue
  • Fixed bug where the Bash tool failed with many plugins enabled on Windows: bin/ directories of non-existent plugins are no longer added to PATH, and inherited entries are no longer added twice
  • Fixed bug where {"decision":"block"} in Elicitation hooks was ignored: {"decision":"block"} returned by Elicitation and ElicitationResult hooks now rejects MCP elicitation in the same way as exit code 2
  • Fixed bug where Explore subagent switched to Opus for unrecognized model IDs: When running a session with a model ID that Claude Code doesn't recognize, such as a custom model via a proxy, the Explore subagent was switching to Opus on the Claude API. Explore now inherits the session's model
  • Fixed bug where Claude apps gateway returned 431 errors: Fixed a bug where requests from sign-ins where the identity provider returned many groups always returned 431 Request Header Fields Too Large. Requests with up to 256 KiB of request headers are now accepted
  • [VS Code] Fixed bug where attaching large text files caused "Prompt is too long" even after compact: This was a bug that occurred when attaching large text files to messages
  • A quietly welcome fix: [VS Code] Fixed a bug where in-chat links to files with non-ASCII characters, spaces, or parentheses in the path could not be opened. For environments using Japanese file names or folder names, being able to open files directly from links in the chat is a welcome improvement.
  • In addition, numerous minor bugs have been fixed in full-screen rendering, vim mode, plugin marketplace and installation, usage limit notifications, the VS Code extension, Claude Tag, and more.

Breaking Changes

Auto mode startup when permission mode is not set expanded to all plans and providers

This is the change to the startup mode for interactive terminal and VS Code sessions introduced in Notable Updates.

Before the change (up to v2.1.283): Example of starting without setting permissions.defaultMode

claude   # Depending on plan and provider, may start in Manual (default) mode

After the change (v2.1.284 and later):

claude   # Starts in auto mode for all plans and providers

To continue starting in Manual mode as before, explicitly set permissions.defaultMode (example configuration in ~/.claude/settings.json).

{
  "permissions": {
    "defaultMode": "default"
  }
}

The official documentation explains that default is the setting value for Manual mode. Note that the official documentation's description of startup modes states that auto mode startup for all plans and providers applies "from v2.1.283 onwards," but the CHANGELOG records it as a v2.1.284 change (as of 2026-09-29). This article follows the CHANGELOG.

Ultracode no longer forces xhigh effort

Ultracode has been changed to a standalone toggle within /effort (Tab key, or /effort ultracode [on|off]). It no longer forces xhigh effort and can be kept on at any effort level. In the VS Code extension, an Ultracode on/off switch has also been added below the Effort slider.

Example before the change (up to v2.1.283):

/effort   # Selecting Ultracode fixed effort to xhigh

Example after the change (v2.1.284 and later):

/effort ultracode on   # Turn Ultracode on (effort level stays as-is)
/effort xhigh          # Specify effort level too if you want to use xhigh as before

Safety-related model switching for sessions with an Opus model fixed via ANTHROPIC_DEFAULT_OPUS_MODEL or modelOverrides has changed. On the Anthropic API, instead of using the fixed model, the API selects the fallback model based on the type of flag.

Example before the change (up to v2.1.283): Based on the CHANGELOG description, it is inferred that the fixed model was used as the fallback.

export ANTHROPIC_DEFAULT_OPUS_MODEL=<Opus model ID to fix>
# The fallback for safety-related model switching was the fixed model (inferred)

Example after the change (v2.1.284 and later):

export ANTHROPIC_DEFAULT_OPUS_MODEL=<Opus model ID to fix>
# On the Anthropic API, the API selects the fallback model based on the type of flag

Artifact publishing from files on network shares is rejected

Artifact publishing has been changed to reject files on network shares (\\host\share paths or /net automounts), except for those on mapped network drives added with --add-dir.

Example before the change (up to v2.1.283): Files at paths like the following on network shares (paths are examples). Based on the CHANGELOG description, it is inferred that these files could be published before the change.

\\fileserver\share\report.html
/net/fileserver/share/report.html

After the change (v2.1.284 and later): The above paths are rejected. Publishing is possible when a mapped network drive is added with --add-dir (example).

claude --add-dir Z:\share

[VS Code] CLAUDE_CONFIG_DIR is only applied when it is an absolute path

CLAUDE_CONFIG_DIR in the claudeCode.environmentVariables setting has been changed to only apply when it is an absolute path, and it will now also be passed to terminals that carry over the conversation.

The following are examples of CLAUDE_CONFIG_DIR values specified in claudeCode.environmentVariables. The point that relative paths were also applied before the change is inferred from the CHANGELOG description.

Before the change (up to v2.1.283):

CLAUDE_CONFIG_DIR = .claude-work             # Relative paths were also applied (inferred)

After the change (v2.1.284 and later):

CLAUDE_CONFIG_DIR = /Users/you/.claude-work  # Only applied when it is an absolute path

Trying code migration to Sonnet 5.5 using /claude-api migrate

Claude Sonnet 5.5 has the same 1M context and same token pricing as Sonnet 5, but there are incompatible changes in how the API is used. The Anthropic blog post "Claude Sonnet 5.5: What's New for API Developers" lists 5 breaking changes and 1 response format change that need to be addressed when migrating from Sonnet 5. It also mentions that Claude Code's /claude-api migrate can be used to apply these changes to a codebase, including replacing the model ID.

So I tried using /claude-api migrate to rewrite a Python program written for Sonnet 5 for Sonnet 5.5.

Changes that need to be addressed when migrating from Sonnet 5 to Sonnet 5.5

The blog post linked below lists the following 6 changes. Of these, 1 and 2 apply to the sample used this time.

https://claude.dev/blog/building-with-claude-sonnet-5-5/

# Change description This sample
1 thinking: {"type": "disabled"} results in a 400 error. Use {"type": "between_tools"} to minimize thinking (only when effort is high or lower) Applicable (advise)
2 tool_choice any / tool (forcing tool calls) results in a 400 error. Replace with auto and strict: true tools, and instruct when to use them via prompt Applicable (ask_weather)
3 Thinking blocks are tied to the model and conversation. Conversations should be append-only Not applicable (single requests only)
4 On Claude API and Google Cloud, computer use is only available via computer_toolset_20260801 Not applicable
5 The models that can be combined as advisors in the advisor tool have changed Not applicable
6 Text between tool calls is returned in thinking blocks Not applicable

The migration guide included with the claude-api skill bundled in Claude Code contains the error messages that occur when 1 and 2 are sent directly to Sonnet 5.5.

"thinking.type.disabled" is not supported for this model. Use "thinking.type.between_tools" for the lowest thinking setting, or "thinking.type.adaptive" and "output_config.effort" to control thinking behavior.
tool_choice: type "tool" and "any" are not supported for this model.

In other words, simply replacing the model ID with claude-sonnet-5-5 will not make the sample work.

Step 1: Prepare a sample for Sonnet 5

I prepared a sample for Sonnet 5 that looks up the weather and gives a one-line clothing advice. In ask_weather, tool_choice is used to force a call to the get_weather tool, and in advise, thinking is disabled to prioritize response speed. Both are valid approaches for Sonnet 5 that would result in 400 errors on Sonnet 5.5.

weather_bot_before.py
"""Sample that looks up the weather and gives a one-line clothing advice (for Claude Sonnet 5)"""
import json
import sys

import anthropic

MODEL = "claude-sonnet-5"

client = anthropic.Anthropic()

WEATHER_TOOL = {
    "name": "get_weather",
    "description": "Get the current weather for the specified city",
    "input_schema": {
        "type": "object",
        "properties": {"city": {"type": "string", "description": "City name"}},
        "required": ["city"],
    },
}

def get_weather(city: str) -> dict:
    # Fixed data for demo purposes (in practice, call a weather API)
    return {"city": city, "condition": "Sunny", "temperature_c": 24}

def ask_weather(question: str) -> dict:
    """Force the get_weather tool to be called and retrieve weather from the tool input"""
    response = client.messages.create(
        model=MODEL,
        max_tokens=1024,
        tools=[WEATHER_TOOL],
        tool_choice={"type": "tool", "name": "get_weather"},
        messages=[{"role": "user", "content": question}],
    )
    tool_use = next(b for b in response.content if b.type == "tool_use")
    return get_weather(**tool_use.input)

def advise(weather: dict) -> str:
    """Return a one-line clothing suggestion for the weather (disable thinking to prioritize response speed)"""
    response = client.messages.create(
        model=MODEL,
        max_tokens=1024,
        thinking={"type": "disabled"},
        messages=[
            {
                "role": "user",
                "content": f"Please give me a one-line clothing suggestion for the following weather: {json.dumps(weather, ensure_ascii=False)}",
            }
        ],
    )
    return next(b.text for b in response.content if b.type == "text")

if __name__ == "__main__":
    question = sys.argv[1] if len(sys.argv) > 1 else "What's the weather in Tokyo?"
    weather = ask_weather(question)
    print(weather)
    print(advise(weather))

Step 2: Run /claude-api migrate

In a Claude Code interactive session, enter the following.

/claude-api migrate weather_bot_before.py to weather_bot_after.py

20260929-cc-updates-v2-1-281-1

Specify the target model for migration. This time, it's sonnet5.5.

20260929-cc-updates-v2-1-281-3

Then weather_bot_after.py is created.

weather_bot_after.py
"""Sample that looks up the weather and gives a one-line clothing advice (for Claude Sonnet 5.5)"""
import json
import sys

import anthropic

MODEL = "claude-sonnet-5-5"

client = anthropic.Anthropic()

# Re-run the same request with a different model when rejected by the safety classifier (Claude API only)
FALLBACK_OPTIONS = {
    "betas": ["server-side-fallback-2026-07-01"],
    "fallbacks": "default",
}

# Since tool_choice enforcement is not available, call verification and retries are handled in code
MAX_TOOL_ATTEMPTS = 3

WEATHER_TOOL = {
    "name": "get_weather",
    "description": "Get the current weather for the specified city",
    "strict": True,
    "input_schema": {
        "type": "object",
        "properties": {"city": {"type": "string", "description": "City name"}},
        "required": ["city"],
        "additionalProperties": False,
    },
}

def get_weather(city: str) -> dict:
    # Fixed data for demo purposes (in practice, call a weather API)
    return {"city": city, "condition": "Sunny", "temperature_c": 24}

def check_refusal(response) -> None:
    """Reject refused responses (HTTP 200 + stop_reason="refusal") before reading content"""
    if response.stop_reason == "refusal":
        category = response.stop_details.category if response.stop_details else None
        raise RuntimeError(f"Request was refused (category={category})")

def ask_weather(question: str) -> dict:
    """Have the model call the get_weather tool and retrieve weather from the tool input"""
    for _ in range(MAX_TOOL_ATTEMPTS):
        response = client.beta.messages.create(
            model=MODEL,
            max_tokens=16000,
            system="Please call the get_weather tool to retrieve the weather for the city mentioned in the question.",
            tools=[WEATHER_TOOL],
            output_config={"effort": "low"},
            messages=[{"role": "user", "content": question}],
            **FALLBACK_OPTIONS,
        )
        check_refusal(response)
        tool_use = next((b for b in response.content if b.type == "tool_use"), None)
        if tool_use is not None:
            return get_weather(**tool_use.input)
    raise RuntimeError(f"The get_weather tool was not called after {MAX_TOOL_ATTEMPTS} attempts")

def advise(weather: dict) -> str:
    """Return a one-line clothing suggestion for the weather (set effort to low to prioritize response speed)"""
    response = client.beta.messages.create(
        model=MODEL,
        max_tokens=16000,
        output_config={"effort": "low"},
        messages=[
            {
                "role": "user",
                "content": f"Please give me a one-line clothing suggestion for the following weather: {json.dumps(weather, ensure_ascii=False)}",
            }
        ],
        **FALLBACK_OPTIONS,
    )
    check_refusal(response)
    return next(b.text for b in response.content if b.type == "text")

if __name__ == "__main__":
    question = sys.argv[1] if len(sys.argv) > 1 else "What's the weather in Tokyo?"
    weather = ask_weather(question)
    print(weather)
    print(advise(weather))

Step3: Check the diff

Use diff to confirm exactly how the code was rewritten.

% diff weather_bot_before.py weather_bot_after.py
1c1
< """天気を調べて服装を一言アドバイスするサンプル(Claude Sonnet 5 向け)"""
---
> """天気を調べて服装を一言アドバイスするサンプル(Claude Sonnet 5.5 向け)"""
7c7
< MODEL = "claude-sonnet-5"
---
> MODEL = "claude-sonnet-5-5"
10a11,19
> # 安全性分類器に拒否されたとき、同じリクエストを別モデルで再実行する(Claude API のみ)
> FALLBACK_OPTIONS = {
>     "betas": ["server-side-fallback-2026-07-01"],
>     "fallbacks": "default",
> }
>
> # tool_choice の強制が使えないため、呼び出しの確認とリトライはコード側で行う
> MAX_TOOL_ATTEMPTS = 3
>
13a23
>     "strict": True,
17a28
>         "additionalProperties": False,
26a38,44
> def check_refusal(response) -> None:
>     """拒否された応答(HTTP 200 + stop_reason="refusal")を content を読む前に弾く"""
>     if response.stop_reason == "refusal":
>         category = response.stop_details.category if response.stop_details else None
>         raise RuntimeError(f"リクエストが拒否されました (category={category})")
>
>
28,37c46,61
<     """get_weather ツールを必ず呼ばせて、ツールの入力から天気を取得する"""
<     response = client.messages.create(
<         model=MODEL,
<         max_tokens=1024,
<         tools=[WEATHER_TOOL],
<         tool_choice={"type": "tool", "name": "get_weather"},
<         messages=[{"role": "user", "content": question}],
<     )
<     tool_use = next(b for b in response.content if b.type == "tool_use")
<     return get_weather(**tool_use.input)
---
>     """get_weather ツールを呼ばせて、ツールの入力から天気を取得する"""
>     for _ in range(MAX_TOOL_ATTEMPTS):
>         response = client.beta.messages.create(
>             model=MODEL,
>             max_tokens=16000,
>             system="質問に含まれる都市の天気を、get_weather ツールを呼び出して取得してください。",
>             tools=[WEATHER_TOOL],
>             output_config={"effort": "low"},
>             messages=[{"role": "user", "content": question}],
>             **FALLBACK_OPTIONS,
>         )
>         check_refusal(response)
>         tool_use = next((b for b in response.content if b.type == "tool_use"), None)
>         if tool_use is not None:
>             return get_weather(**tool_use.input)
>     raise RuntimeError(f"get_weather ツールが {MAX_TOOL_ATTEMPTS} 回呼び出されませんでした")
41,42c65,66
<     """天気に合う服装を一言で返す(応答の速さを優先して thinking を無効化)"""
<     response = client.messages.create(
---
>     """天気に合う服装を一言で返す(応答の速さを優先して effort を low にする)"""
>     response = client.beta.messages.create(
44,45c68,69
<         max_tokens=1024,
<         thinking={"type": "disabled"},
---
>         max_tokens=16000,
>         output_config={"effort": "low"},
51a76
>         **FALLBACK_OPTIONS,
52a78
>     check_refusal(response)

Organizing the diff in line with Claude's explanation categories, we get the following:

Category Change Location
Required Change model ID from claude-sonnet-5 to claude-sonnet-5-5 MODEL
Required Change forced tool_choice to {"type": "auto"} and instruct tool use via system prompt. Retry once if tool is not called ask_weather
Required Add strict: True and additionalProperties: False to tool definition WEATHER_TOOL
Required Remove thinking={"type": "disabled"} and specify output_config={"effort": "low"} advise
Additional changes included Change max_tokens from 1024 to 16000 Both calls
Additional changes included Add handling to raise an exception when stop_reason is refusal Both calls
Additional changes included Switch to client.beta.messages.create and add server-side fallback (betas and fallbacks="default") Both calls

Step4: Cross-reference with the migration guide and verify the syntax

We cross-referenced the Sonnet 5.5 section of the included migration guide against the rewritten code.

  • Disabling thinking: The migration guide recommends first trying adaptive thinking with low effort, and only using {"type": "between_tools"} with high or lower effort when thinking needs to be stopped. The rewritten advise follows the first approach (omitting the thinking parameter and setting effort to low).
  • Forced tool_choice: The migration guide says to replace it with a combination of auto, a prompt indicating when to use tools, and strict: true, and since auto does not guarantee a call, to verify whether the tool was called and retry if not. The rewritten ask_weather follows this pattern.

Summary

Migrating from Sonnet 5 to Sonnet 5.5 is not as simple as just replacing the model ID, but using /claude-api migrate allows you to delegate the work of applying breaking change fixes to your code. The more files a project has to migrate, the greater the benefit.

Finally

We confirmed that Sonnet 5.5 becomes the default Sonnet in the Anthropic API at the same token price as Sonnet 5, and that code migration in the Claude API can be handled with /claude-api migrate. It feels like a release that makes it easy to move to Sonnet 5.5 in both Claude Code and the Claude API.

If you are using Sonnet, why not update and try migrating your Claude API code with /claude-api migrate as well?

References

https://github.com/anthropics/claude-code/blob/main/CHANGELOG.md

https://code.claude.com/docs/en/changelog

https://code.claude.com/docs/en/permission-modes

https://code.claude.com/docs/en/model-config

https://dev.classmethod.jp/articles/20260924-cc-updates-v2-1-283/


Claudeならクラスメソッドにお任せください

クラスメソッドは、Anthropic社とリセラー契約を締結しています。各種製品ガイドから、業種別の活用法、フェーズごとのお悩み解決などサービス支援ページにまとめております。まずはご覧いただき、お気軽にご相談ください。

サービス詳細を見る

Share this article

AI白書

Related articles