Claude Design: Permanent Durable Project Write Grants #
New
What
The approval model for Claude Design project writes is fundamentally reworked. The old time-limited "4-hour project grant" from finalize_plan scope:"project" is replaced by a permanent durable grant that persists until explicitly revoked at claude.ai/design settings.
Details
- The first write to a project triggers a one-time interactive approval. After approval, Claude can write to any file in the project without further prompts until revoked.
- The approval approval message now reads: "Approving writes the listed files now, and lets Claude write to ANY file in the project…" rather than the previous "without another prompt for up to 4 hours".
- Grants are revocable at any time via claude.ai/design settings.
finalize_plan scope:"project" is now deprecated — the client returns a deny message directing callers to use direct writes instead.copy_files without a plan_token is now always rejected (requires finalize_plan with explicit destination paths).- Write batches that are too large to display in the approval dialog are rejected and must be split or issued via
finalize_plan. - Projects shared from another organization cannot receive durable grants — those require per-batch
plan_token flows. - Durable grants are not available in non-interactive sessions, plan mode, subagent sessions, or PermissionRequest-hook contexts.
Evidence
Replaced approval text (search for "first write under a project grant")
Windows Browser Resolution for Claude in Chrome via App Paths #
New
What
On Windows, Claude in Chrome now uses the Windows Registry App Paths mechanism (via reg.exe) to locate installed browser executables for Edge and Vivaldi, rather than only falling back to rundll32.
Details
- Queries both
HKCU and HKLM registry hives under SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths for msedge.exe and vivaldi.exe. - Falls back to
rundll32 url,OpenURL if registry resolution fails or the exe cannot be verified. - Expands
%VARIABLE% environment-variable tokens in registry values. - Rejects results that point to a directory rather than an executable.
- Uses a timeout to avoid blocking on slow or stale registry entries.
Evidence
Windows App Paths registry key (search for "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths")
Audible Bell Behavior on macOS Terminal.app #
New
What
When Claude Code sets up Option+Enter as a newline key on macOS Terminal.app, it now disables the audible bell instead of switching to a visual bell. Screen-reader users are not affected.
Details
- If Terminal.app is in screen-reader mode, the audible bell setting is left unchanged.
- The setup notification now reads "Option+Enter for newlines and no audible bell" (previously "visual bell").
- If no Terminal.app changes are needed (e.g., Shift+Return already works), a message confirms this without modifying preferences.
Evidence
Updated Terminal.app profile modification messages (search for "Disabled the audible bell")
--callback-port Validation Tightened #
New
What
The MCP OAuth callback port flag (--callback-port) now validates that the port number falls within the valid TCP range [1, 65535], rather than only checking it is a positive integer.
Details
- The error message now reads: "Error: --callback-port must be an integer in [1, 65535]"
- Port 0 is no longer accepted. The validation expression is
!Number.isInteger(m) || m <= 0 || m > 65535, so port 0, negative values, and non-integer inputs (e.g. 1.5 or non-numeric strings that parse to NaN) are all rejected. - The same validation is applied in two separate command paths:
claude mcp add (for SSE and HTTP transports) and claude mcp oauth identity-provider set.
Evidence
Updated validation error string (search for "--callback-port must be an integer in [1, 65535]")
CLAUDE_CODE_RESUME_INTERRUPTED_TURN_MAX_AGE_MS Environment Variable #
New
What
A new environment variable, CLAUDE_CODE_RESUME_INTERRUPTED_TURN_MAX_AGE_MS, controls how old an interrupted assistant turn can be before it is no longer automatically resumed on session restart. This prevents stale interrupted turns from being replayed after a long pause.
Details
- If
CLAUDE_CODE_RESUME_INTERRUPTED_TURN is set and the interrupted turn's timestamp is older than this value, the resume is skipped. - Defaults to 3,600,000 ms (1 hour) when the variable is present but not set to a valid finite positive number; set to
0 to disable age-gating entirely. - The variable is passed through to child processes alongside the existing
CLAUDE_CODE_RESUME_INTERRUPTED_TURN.
Evidence
New env var with fallback (search for "CLAUDE_CODE_RESUME_INTERRUPTED_TURN_MAX_AGE_MS")
OAuth Refresh Lock: Named Error, Compromise Detection, and Longer Stale Timeout #
New
What
The OAuth token refresh lock now uses a named error class (OAuthRefreshLockContendedError), exposes an isCompromised() predicate and an abort signal, and raises the stale-lock timeout from 10 seconds to 60 seconds with a 5-second update heartbeat.
Details
OAuthRefreshLockContendedError is thrown when the lock is contended after max attempts, replacing the previous untyped error.- A new
onCompromised callback receives a dedicated AbortController signal that is aborted when compromise is detected, allowing in-flight refreshes to be cancelled. - The increased stale timeout (60 s) reduces false-positive "lock compromised" events on slow systems.
Evidence
New named error class (search for "OAuthRefreshLockContendedError")
Chrome Tool Error Classification #
New
What
Errors from Chrome bridge tools (javascript_tool, computer, get_page_text) are now classified into structured named error types for telemetry, replacing untyped catch-all error handling.
Details
- JavaScript tool errors:
js_permission_denied, js_timeout, js_execution_error, js_exception, tab_not_found. - Computer (input/action) tool errors:
computer_permission_denied, computer_element_not_found, computer_action_failed, computer_zoom_shortcut_unsupported, computer_exception. - Page text extraction errors:
get_page_text_permission_denied, get_page_text_too_large, get_page_text_no_content, get_page_text_script_error, get_page_text_exception. - Shared cross-tool error:
navigation_blocked, permission_denied_user, authentication_failed, session_expired, domain_blocked, security_check_failed.
Evidence
Error classification registry (search for "js_permission_denied")
Auto Front-Load of Tab Context for Navigate Without tabId #
New
What
When the navigate tool is called with a URL but no tabId, Claude in Chrome now automatically issues a tabs_context_mcp call in the background to acquire a tab, then injects the tab context into the result. The caller no longer needs to call tabs_context_mcp first for simple URL navigation.
Details
- A short timeout bounds the background lookup; if it exceeds the limit, the tool returns an error instructing the caller to retry or call
tabs_context_mcp explicitly. url: "back" and url: "forward" still require an explicit tabId (they have no meaningful default).- The tab context JSON (from the front-loaded lookup) is appended to the successful navigate result for reference.
Evidence
Auto tab lookup logic (search for "The hidden tabs_context_mcp lookup did not respond within")
settings.local.json Ownership Verification Before Canonicalization #
New
What
Before relocating the local settings consent store to the canonical git repository root, Claude now verifies via POSIX uid semantics that the user owns the root directory, its .git entry, and its .claude entry.
Details
- If any of those entries are owned by a different user, the store stays at the current working directory (the pre-canonicalization behavior) and a warning is logged.
- On platforms without uid semantics (Windows), canonicalization is skipped and logged as POSIX-only.
- Protects against shared-repository scenarios where a foreign-owned repo root could have its consent state hijacked.
Evidence
Ownership check log messages (search for "localSettings: not canonicalizing the consent store to")