Official Changelog
No official entryNew Features
3 itemsClaude Platform on Google Cloud #
Claude Code can now connect to Claude running on Google Cloud infrastructure via claude.googleapis.com, using Application Default Credentials or an explicit bearer token provider.
# Set your GCP project and let Claude Code discover the workspace
export ANTHROPIC_GOOGLE_CLOUD_PROJECT=my-gcp-project
export ANTHROPIC_GOOGLE_CLOUD_LOCATION=us-east5 # optional, defaults to global
export ANTHROPIC_GOOGLE_CLOUD_WORKSPACE_ID=my-workspace
# Or provide a full base URL directly
export ANTHROPIC_GOOGLE_CLOUD_BASE_URL=https://claude.googleapis.com/v1alpha/projects/...
# Enable the Google Cloud path
export CLAUDE_CODE_USE_ANTHROPIC_GOOGLE_CLOUD=true
# Skip auth entirely (if your infrastructure handles it externally)
export CLAUDE_CODE_SKIP_ANTHROPIC_GOOGLE_CLOUD_AUTH=true
- Routes to
https://claude.googleapis.com/v1alpha/projects/{project}/locations/{location}/workspaces/{workspace}/invoke - Authenticates using Google Application Default Credentials (ADC) automatically when no other auth is provided — no API key required
- Accepts an explicit
bearerTokenProvidercallback, agoogleAuthobject, or anauthClientdirectly - The deprecated text Completions API is not available on this provider
- GCP environment variable values for project, workspace, and location are validated to only contain letters, digits, hyphens, and underscores — URL metacharacters that could rewrite the request path are rejected with a clear error
- The
anthropicGoogleCloudprovider is now recognized in the provider enum in SessionStart hooks and other SDK schema positions
AnthropicGoogleCloud client implementation (search for "Claude Platform on Google Cloud", "https://claude.googleapis.com", ANTHROPIC_GOOGLE_CLOUD_PROJECT)
/import — Migrate Config from Other AI Coding Agents #
A new /import slash command (and claude import CLI subcommand) scans for OpenAI Codex and Google Gemini CLI configuration and imports it into Claude Code — MCP servers, slash commands, subagents, skills, and instructions.
# From the terminal (interactive picker)
claude import # auto-detect Codex or Gemini
claude import codex # Codex only
claude import gemini # Gemini only
claude import --dry-run # preview without writing
claude import --yes # apply all user-level items without prompting
# From inside a Claude Code session
/import # scan and list what's importable
/import --yes # apply everything without the picker
/import --dry-run # show what would be imported
- Detects Codex config at
~/.codex/config.tomland.codex/(project-level) - Detects Gemini config at
~/.gemini/settings.jsonand.gemini/(project-level) - Imports MCP servers, slash commands (skills), subagents, and system instructions
- Project-level config from
.codex/or.gemini/directories is listed but NOT auto-imported — anyone with repo write access could author those, so they must be reviewed manually - Shell-exec markers (
!{…}in Gemini,!cmd`` in Claude Code) are flagged and require manual porting - Items with no automatic mapping generate a helper skill at
skills/import-to-claude-code/for follow-up review - Gemini extensions, project-level settings, and subdirectory-organized commands are listed as needing manual review
- The
--yesflag onclaude -p(headless/scripted) applies the same import that the interactive picker would; on plainclaude -psessions without a terminal, it instructs users to runclaude importfrom an interactive terminal instead - Codex permission mode
defaultmaps todefaultMode: autoin Claude Code; tool restrictions differ and are dropped with a warning
CLI entry point (search for "claude import [codex|gemini] [--dry-run] [--yes]"), Gemini config support (search for ".gemini/settings.json"), Codex support (search for ".codex/config.toml")
CLAUDE_CODE_NO_MODEL_FALLBACK — Prevent Model Substitution #
A new environment variable that locks Claude Code to exactly the configured model and disallows any automatic fallback to a different model — including during compaction.
export CLAUDE_CODE_NO_MODEL_FALLBACK=true
claude --model claude-opus-4-5 ...
- When set, the availability fallback chain collapses to
[primary]only — no alternate models are tried - Compaction is disabled with the message "Compaction unavailable: CLAUDE_CODE_NO_MODEL_FALLBACK is set and model substitution is disabled · unset it to allow the swap"
- If code attempts a model-fallback pivot while the flag is active, a tripwire throws an error identifying the call site (this is a developer safety net, not a normal user-visible error)
- The flag is intended for environments where model consistency is a hard requirement (compliance, billing, reproducibility)
Tripwire implementation (search for "CLAUDE_CODE_NO_MODEL_FALLBACK tripwire: a model-fallback pivot was attempted", "CLAUDE_CODE_NO_MODEL_FALLBACK")
Improvements
17 itemsBackground Sessions: Clearer "No Terminal" Error Messages #
Error messages that previously said "in a background session" now say "no terminal is attached to this background session" and include instructions on how to attach. Three affected messages:
- MCP server authentication: "Can't authenticate MCP servers while no terminal is attached to this background session. Attach to it and try again."
/install-github-app: "Can't run /install-github-app while no terminal is attached to this background session. Attach to it and run the command again."/mcppanel: "Can't open MCP settings while no terminal is attached to this background session. Attach to it and run /mcp again, or use \/mcp enable|disable|reconnect <server>\to steer without the panel."
Background session guards (search for "no terminal is attached to this background session")
SDK Protocol: aborted Field on Assistant Messages #
The SDK wire schema now includes an optional aborted: true field on assistant messages that were cut short by an interrupt or abort before the stream completed.
- Present when
stop_reasonwas never received and content may end mid-word - Absent on normally completed messages
- Allows SDK hosts to visually distinguish truncated responses from complete ones
Schema addition (search for "True when this assistant message was truncated by an interrupt/abort")
SDK Protocol: task-notification subkind: "scheduled-trigger" #
The task-notification origin kind now carries an optional subkind field. When subkind is "scheduled-trigger", the turn is the automatic firing of a stored scheduled prompt.
- Lets SDK integrations distinguish scheduled task deliveries from other background notifications
- The harness frames scheduled triggers using a
[SCHEDULED TASK - AUTOMATED FIRING OF A CONFIGURED PROMPT]prefix instead of the generic background-notification frame
Schema addition (search for "Present when the delivery is the fired stored prompt of a scheduled task/routine", "[SCHEDULED TASK - AUTOMATED FIRING OF A CONFIGURED PROMPT]")
SDK Protocol: Heartbeat and Subagent-Retry tool_progress Filtering #
The SDK message adapter now silently drops tool_progress frames that carry heartbeat or subagent-retry payloads instead of surfacing them as messages.
tool_progressframes withheartbeat: trueor asubagent_retryobject are now filtered- These frames exist for session keepalive and retry signaling; passing them to SDK consumers as messages caused confusion
- A debug log entry is written:
[sdkMessageAdapter] Ignoring heartbeat/subagent-retry tool_progress frame
Filter logic (search for "[sdkMessageAdapter] Ignoring heartbeat/subagent-retry tool_progress frame")
SDK Protocol: Plugin Version Field #
Plugins now expose their version as declared in plugin.json through the SDK wire format.
- The version string is emitted verbatim from the plugin manifest (plugin-author-controlled — validate before trusting)
- Omitted when the manifest declares no version
- The
versionfield appears in thepluginsarray in two SDK message types: thesystem:initmessage (sent at session startup listing all loaded plugins) and thereload_pluginsengine-control response (sent after a plugin reload) - In both locations the field is typed as
S.string().optional(), so hosts must handle its absence for plugins that omit aversionin their manifest - A separate
plugin_versionattribute is also recorded in telemetry events for marketplace-approved plugins when a skill command is invoked, enabling per-version usage metrics on the server side; third-party plugins emit"third-party"as the repository sentinel and no version is sent to telemetry
Schema addition (search for "The plugin's version as declared in its plugin.json manifest, emitted verbatim"); wire positions (search for u7a used in system:init plugins array and reload_plugins response schema)
SDK Protocol: matched_ask_rule in Permission Requests #
When Claude Code escalates a tool call to the host for permission (auto-mode escalation), the permission request now includes a matchedAskRule object describing which rule triggered the ask.
- Fields:
source,toolName, and optionallyruleContent - Lets SDK hosts make informed decisions about why a specific call was escalated rather than just seeing that it was
Permission protocol addition (search for "matched_ask_rule" in SDK message schema)
Hook System: policySettings Source #
A new hook source type policySettings is recognized in the hook source registry. It joins userSettings, projectSettings, localSettings, pluginHook, sessionHook, and builtinHook.
- Represents enterprise managed settings delivered out-of-band by an administrator; displayed to users as
"managed"(short),"Managed"(header), and"enterprise managed settings"(long form) in the settings/hooks UI - Unlike
userSettings,projectSettings, andlocalSettings,policySettingsis always included in the allowed sources list regardless of the--allow-setting-sourceCLI flag (it is force-added alongsideflagSettingsin the source filter) policySettings.disableAllHooks = truedisables all hooks entirely — even plugin hooks — across all sourcespolicySettings.allowManagedHooksOnly = truerestricts hook execution to onlypolicySettings.hooks; user, project, and local hooks are silently ignored for the session- If
qi().disableAllHooksistruebutpolicySettings.disableAllHooksis nottrue, hooks from managed settings still run (the setting overrides only non-managed hooks) - Hooks declared under
policySettings.hooksare therefore the only hooks an administrator can guarantee will always run; user-side hooks can be suppressed without touching the user's own settings files - In hook priority sorting, hooks sourced from
policySettingsshare bucket 999 withpluginHookandbuiltinHook, making them sort after user/project/local hooks in the display
Hook source labels (search for "policySettings" in hook source map at new TJt variable); hook resolution logic (search for Lzi, iOe, QX, allowManagedHooksOnly, disableAllHooks)
SessionStart Hook: fork Source Value #
The source field on SessionStart hook events now accepts a new "fork" value, in addition to the existing "startup", "resume", "clear", and "compact".
- Fires when a session is loaded with
forkSession: true— the code path activated when a skill carriescontext: "fork"or when the fork-subagent experiment (tengu_copper_fox/tengu_fork_subagent_enabled) spawns a subagent by resuming an existing conversation under a new session ID - The hook JSON payload is
{ hook_event_name: "SessionStart", source: "fork", agent_type: <string>, model: <string>, session_title: <string> }— same fields as"resume"events - Unlike
"clear"and"compact", a"fork"event does propagate the session title returned by the hook (same behaviour as"startup"and"resume"): the title is stored so the forked session can be labelled distinctly - The new session ID passed in the hook is the forked child's fresh ID (not the parent's); the hook fires after the fork's conversation history is loaded but before the first turn runs
- Skills with
context: "fork"are excluded from being re-dispatched inside the fork they created, preventing recursive expansion - Hook output (additional context messages,
reloadSkills,watchPaths) works identically to otherSessionStartsources — hooks can inject context or block the fork by returning a blocking error
Schema enum (search for "fork" in SessionStart hook schema alongside "startup", "resume", "clear", "compact"); fork dispatch (search for forkSession, x$e("fork", "fork" : "resume", aye = "fork", tengu_copper_fox)
Docker: Additional Global Flag Pass-Through #
Several additional Docker CLI global flags are now recognized and passed through in the Bash safety analysis, preventing them from being treated as suspicious when used before a subcommand.
New flags recognized: -r, --url, --connection, --identity, --remote, --module, --out
Docker argument list (search for "--connection" in Docker flags array)
Shell Safety: Command Length Limit #
Very long Bash commands now bypass static analysis rather than attempting to parse them, avoiding edge cases where the parser could diverge from what the shell sees.
- Commands exceeding the length limit return
{ behavior: "passthrough", message: "Command too long for read-only analysis" } - The command is still executed; only the safety pre-flight parse is skipped
Length check (search for "Command too long for read-only analysis")
Shell Safety: Improved Redirect Analysis #
The Bash parser now validates redirect nodes for additional dangerous patterns that could hide behavior from the safety classifier.
New cases detected:
fd-variable assignment— a redirect that uses a shell variable ({var}>) as the file descriptor; this modifies the variable as a side effectclose-fd redirect followed by a word—>&-or<&-followed by text that bash would pass as a hidden argument to the commandredirect target starting with -after>&or<&— bash treats the dash as a close-fd operator and passes the remainder as an argument
Redirect analysis (search for "Redirect uses", "fd-variable assignment", "Close-fd redirect is followed by a word")
Shell Safety: Test Command Gap Analysis #
The Bash safety parser now checks test commands ([[ ... ]]) for unparsed bytes between children or after the last child, which would indicate the parser missed content the shell will actually see.
- A new recursive function
dnu()walkstest_commandAST nodes and their four nested compound-expression node types:unary_expression,binary_expression,negated_expression, andparenthesized_expression - For each node the function tracks a byte-position cursor from
startIndextoendIndexand measures the gap before each child and after the last child; gaps that contain only whitespace (spaces, tabs), backslash-newline continuations, or (in bash mode) comment characters are allowed - Between-children gap: if the bytes between two adjacent parsed children are non-trivial, the function returns
{ kind: "too-complex", reason: "Test command has unparsed bytes between children — parser dropped content that shell will see" } - After-last-child gap: if bytes remain between the last child's
endIndexand the node's ownendIndex, the function returns{ kind: "too-complex", reason: "Test command has unparsed bytes after its last child — parser dropped content that shell will see" } - Child out-of-bounds: if a child's span extends outside the parent's span, the function returns
{ kind: "too-complex", reason: "Test command child extends past the node span — gap byte accounting is untrustworthy" } - All three cases produce a
"too-complex"result; the safety classifier treats"too-complex"as inability to determine read-only status, so the command is not automatically approved — the user sees the standard "approve this command?" prompt rather than a silent pass-through - This closes a semantic gap where a tree-sitter parse failure inside
[[ ]]could have caused the classifier to analyse a truncated/simplified version of the condition and incorrectly allow a command that the shell would evaluate differently
Test command validation (search for "Test command has unparsed bytes between children", "Test command has unparsed bytes after its last child"); gap-check implementation (search for dnu, Zru, unu)
OTEL: Configurable Content Truncation Limit #
The length at which telemetry content is truncated is now configurable via environment variables, and respects standard OpenTelemetry limit variables.
export CLAUDE_CODE_OTEL_CONTENT_MAX_LENGTH=8192 # Claude Code specific cap
# Or use standard OTel variables (Claude Code takes the minimum):
export OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT=4096
export OTEL_LOGRECORD_ATTRIBUTE_VALUE_LENGTH_LIMIT=4096
export OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT=4096
- Previously the limit was hardcoded to 60 KB
- The truncation message now includes the actual limit:
[TRUNCATED - Content exceeds NKB limit]
Configurable limit implementation (search for "CLAUDE_CODE_OTEL_CONTENT_MAX_LENGTH", "OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT")
Host OTLP Telemetry for SDK Integrations #
SDK host integrations can now emit custom telemetry events into Claude Code's OTLP pipeline using a host.* namespace. The system includes rate limiting and deduplication of error messages to avoid log spam.
- Events must follow the naming pattern
host.<lowercase.dotted.name> - Attributes must use
snake_casekeys with string values - Payload is validated and rejected if it uses reserved namespaces (
claude_code.*) or has invalid shapes - Rate cap: 240 tokens, refilling over time
- Error categories:
bad_envelope,bad_event_name,bad_attributes_shape,too_many_attributes,bad_attribute_key,bad_attribute_value,payload_too_large,emit_failed
OTLP routing implementation (search for "host OTLP event dropped", "host OTLP event route error", "host OTLP event emit failed")
Org Memory: Silo and Grouping Selection [Gradual Rollout] #
The org memory system (controlled by tengu_haze_glass) now supports selecting specific memory silos or groupings within an organization, rather than mounting all granted stores.
- Controlled by the
tengu_moth_lanternfeature flag - Users can have a stored memory selection (persisted in settings as
orgMemorySelection) that pins them to a specific silo - If the selected silo is no longer in the grant, the system degrades gracefully to the full grant
- The
orgMemorySelectionAccountfield validates the selection belongs to the current account
Silo selection logic (search for "silo_id", "grouping_id", "selection_degraded", "tengu_moth_lantern")
Usage URL Updated #
The URL shown when users reach their usage limit now includes a tracking parameter.
Old: claude.ai/settings/usage New: claude.ai/settings/usage?from=cc_cli_limit_message
This change is internal but users will see the updated URL in limit messages.
URL constant (search for "claude.ai/settings/usage?from=cc_cli_limit_message")
Memory System: Multiple Team Mount Directories #
The memory system's prompt generation now supports multiple team memory directories with per-mount read/write modes, instead of a single team directory.
- The
teamMountsparameter replacesteamDirin internal memory prompt construction - Each mount can be individually read-only or read-write
- Prompt text accurately describes which directories are writable vs. read-only
Memory prompt builder (search for "read-only — do not write there" in new memory prompt logic)
Bug Fixes
5 items- Shell redirect parser no longer misses content between children in test commands — the gap-byte accounting check is now applied to
test_commandnodes (search for"Test command comparison is missing its right-hand side") - The
set_permission_modeengine control now validates the mode value and returns a descriptive error for unrecognized modes instead of silently failing (search for"[engine] set_permission_mode rejected — unrecognized mode","Cannot set permission mode: must be one of") - GCP environment variable values containing URL metacharacters (
:,/,\,?,#,@, whitespace) now raise a clear error instead of silently corrupting the request path (search for"GCP path-segment env var failed the charset gate") - Error codes
ENODEV,ENOMEM,EUNKNOWN,UNKNOWN, andUnknown system error *are now treated as retryable I/O errors (previously onlyEDEADLK,EINTR,ENXIO,ECANCELED,ENEEDAUTH,ESTALEwere) (search for"ENODEV"in retryable error check) - Frontmatter parser now detects ambiguous
---closing delimiters (a value containing"---"could cause part of the block to be read as body) and reports arewriteHazardwarning instead of silently truncating (search for"the closing --- is ambiguous")
Removals
1 itemMorning Brief Feature Removed #
The morning brief feature (CLAUDE_CODE_ENABLE_MORNING_BRIEF, CLAUDE_CODE_MORNING_BRIEF_PROMPT) has been removed. The environment variables no longer have any effect. This was a limited-availability feature that has been deprecated.
Removal of CLAUDE_CODE_ENABLE_MORNING_BRIEF and CLAUDE_CODE_MORNING_BRIEF_PROMPT from environment variable registry (confirmed absent in new version, confirmed present in old version via string diff).