SpyBara
Go Premium

Documentation 2026-10-24 22:59 UTC to 2026-10-25 23:58 UTC

52 files changed +618 −123. View all changes and history on the product overview
2026
Fri 30 23:01 Thu 29 23:57 Wed 28 23:57 Tue 27 22:59 Mon 26 22:57 Sun 25 23:58 Sat 24 22:59 Fri 23 22:59 Thu 22 22:58 Wed 21 23:02 Tue 20 23:00 Mon 19 23:58 Sat 17 23:57 Fri 16 22:59 Thu 15 23:58 Wed 14 22:58 Tue 13 23:57 Sun 11 23:57 Sat 10 23:01 Fri 9 23:02 Thu 8 22:58 Wed 7 23:59 Tue 6 23:59 Mon 5 23:58 Sun 4 23:58 Sat 3 23:57 Fri 2 22:59 Thu 1 23:59
Details

771 771 

772When a callback exceeds its timeout, Claude Code cancels it and discards its output, and the session continues rather than hanging. What happens next depends on the event:772When a callback exceeds its timeout, Claude Code cancels it and discards its output, and the session continues rather than hanging. What happens next depends on the event:

773 773 

774* `PreToolUse`: Claude Code blocks the tool call. In its place, Claude receives a tool result saying the hook didn't respond before its timeout, and the turn continues. Before v2.1.210, Claude Code reported the timeout to Claude as a user rejection, which made unattended sessions stop and wait for input.774* `PreToolUse`: Claude Code blocks the tool call. If every other hook returned nothing or only an `allow` decision, the tool result tells Claude the hook didn't respond before its timeout, and the turn continues. If another of your hooks already denied the call, its deny still reaches Claude: the tool result includes that hook's reason, and the timeout text can follow it.

775 

776 Before v2.1.210, Claude Code reported the timeout to Claude as a user rejection, which made unattended sessions stop and wait for input.

775* `PostToolUse` and `PostToolUseFailure`: Claude Code keeps the tool result and the turn continues.777* `PostToolUse` and `PostToolUseFailure`: Claude Code keeps the tool result and the turn continues.

776* `UserPromptSubmit` and [`UserPromptExpansion`](https://code.claude.com/docs/en/hooks#userpromptexpansion): Claude Code blocks the prompt with a message naming the hook and the timeout, and the session continues. Before v2.1.208, Claude Code ended the query with `error_during_execution` when a callback on these events timed out.778* `UserPromptSubmit` and [`UserPromptExpansion`](https://code.claude.com/docs/en/hooks#userpromptexpansion): Claude Code blocks the prompt with a message naming the hook and the timeout, and the session continues. Before v2.1.208, Claude Code ended the query with `error_during_execution` when a callback on these events timed out.

777* `Stop` and `SubagentStop`: the timed-out callback counts as returning no decision. The agent or subagent stops as if that callback had allowed it, and a decision from your other hooks on the event still applies. Before Claude Code v2.1.273, a timed-out `Stop` or `SubagentStop` callback counted as a failed hook run, and Claude Code discarded the decisions of your other hooks on the event.779* `Stop` and `SubagentStop`: the timed-out callback counts as returning no decision. The agent or subagent stops as if that callback had allowed it, and a decision from your other hooks on the event still applies. Before Claude Code v2.1.273, a timed-out `Stop` or `SubagentStop` callback counted as a failed hook run, and Claude Code discarded the decisions of your other hooks on the event.

Details

309| `options.dir` | `string` | `undefined` | Project directory to find the session in. When omitted, searches all projects |309| `options.dir` | `string` | `undefined` | Project directory to find the session in. When omitted, searches all projects |

310| `options.limit` | `number` | `undefined` | Maximum number of messages to return |310| `options.limit` | `number` | `undefined` | Maximum number of messages to return |

311| `options.offset` | `number` | `undefined` | Number of messages to skip from the start |311| `options.offset` | `number` | `undefined` | Number of messages to skip from the start |

312| `options.includeSystemMessages` | `boolean` | `false` | When `true`, also return system messages such as compact boundaries alongside user and assistant messages |

312 313 

313#### Return type: `SessionMessage`314#### Return type: `SessionMessage`

314 315 

315| Property | Type | Description |316| Property | Type | Description |

316| :- | :- | :- |317| :- | :- | :- |

317| `type` | `"user" \| "assistant"` | Message role |318| `type` | `"user" \| "assistant" \| "system"` | Message role. `"system"` appears only when `options.includeSystemMessages` is `true` |

318| `uuid` | `string` | Unique message identifier |319| `uuid` | `string` | Unique message identifier |

319| `session_id` | `string` | Session this message belongs to |320| `session_id` | `string` | Session this message belongs to |

320| `message` | `unknown` | Raw message payload from the transcript |321| `message` | `unknown` | Raw message payload from the transcript |


632 }): Promise<SDKControlReloadPluginsResponse>;633 }): Promise<SDKControlReloadPluginsResponse>;

633 reloadSkills(): Promise<SDKControlReloadSkillsResponse>;634 reloadSkills(): Promise<SDKControlReloadSkillsResponse>;

634 reloadOutputStyles(): Promise<SDKControlReloadOutputStylesResponse>;635 reloadOutputStyles(): Promise<SDKControlReloadOutputStylesResponse>;

636 seedReadState(path: string, mtime: number): Promise<void>;

635 accountInfo(): Promise<AccountInfo>;637 accountInfo(): Promise<AccountInfo>;

636 reconnectMcpServer(serverName: string): Promise<void>;638 reconnectMcpServer(serverName: string): Promise<void>;

637 toggleMcpServer(serverName: string, enabled: boolean): Promise<void>;639 toggleMcpServer(serverName: string, enabled: boolean): Promise<void>;

638 setMcpServers(servers: Record<string, McpServerConfig>): Promise<McpSetServersResult>;640 setMcpServers(servers: Record<string, McpServerConfig>): Promise<McpSetServersResult>;

641 setMcpPermissionModeOverride(

642 serverName: string,

643 mode: 'default' | 'auto' | null

644 ): Promise<{ warning?: string }>;

639 readMcpResource(serverName: string, uri: string): Promise<SDKControlMcpReadResourceResponse>;645 readMcpResource(serverName: string, uri: string): Promise<SDKControlMcpReadResourceResponse>;

640 streamInput(stream: AsyncIterable<SDKUserMessage>): Promise<void>;646 streamInput(stream: AsyncIterable<SDKUserMessage>): Promise<void>;

641 stopTask(taskId: string): Promise<void>;647 stopTask(taskId: string): Promise<void>;

648 backgroundTasks(toolUseId?: string): Promise<boolean>;

642 close(): void;649 close(): void;

643}650}

644```651```


665| `reloadPlugins(options?)` | Reloads plugins from disk, so plugins you install or edit mid-session reach the running session. Resolves with an [`SDKControlReloadPluginsResponse`](#sdkcontrolreloadpluginsresponse) listing the session's commands, subagents, plugins, and MCP server status. Requires Agent SDK v0.2.85 or later. The [`holdOnCacheImpact` option](#sdkcontrolreloadpluginsresponse) requires Agent SDK v0.3.268 or later |672| `reloadPlugins(options?)` | Reloads plugins from disk, so plugins you install or edit mid-session reach the running session. Resolves with an [`SDKControlReloadPluginsResponse`](#sdkcontrolreloadpluginsresponse) listing the session's commands, subagents, plugins, and MCP server status. Requires Agent SDK v0.2.85 or later. The [`holdOnCacheImpact` option](#sdkcontrolreloadpluginsresponse) requires Agent SDK v0.3.268 or later |

666| `reloadSkills()` | Reloads skills from disk, so skills you add or edit mid-session become available to the running session. Resolves with an [`SDKControlReloadSkillsResponse`](#sdkcontrolreloadskillsresponse) listing the skills available after the reload. Requires Agent SDK v0.3.163 or later |673| `reloadSkills()` | Reloads skills from disk, so skills you add or edit mid-session become available to the running session. Resolves with an [`SDKControlReloadSkillsResponse`](#sdkcontrolreloadskillsresponse) listing the skills available after the reload. Requires Agent SDK v0.3.163 or later |

667| `reloadOutputStyles()` | Re-reads [output styles](https://code.claude.com/docs/en/output-styles.md) from disk, so a style file you add or edit mid-session becomes available to the running session. Resolves with an [`SDKControlReloadOutputStylesResponse`](#sdkcontrolreloadoutputstylesresponse) listing the style names available after the reload. Requires Agent SDK v0.3.261 or later |674| `reloadOutputStyles()` | Re-reads [output styles](https://code.claude.com/docs/en/output-styles.md) from disk, so a style file you add or edit mid-session becomes available to the running session. Resolves with an [`SDKControlReloadOutputStylesResponse`](#sdkcontrolreloadoutputstylesresponse) listing the style names available after the reload. Requires Agent SDK v0.3.261 or later |

675| `seedReadState(path, mtime)` | Marks a file as already read so a later Edit doesn't fail with `File has not been read yet`. See [`seedReadState()`](#seedreadstate). Requires TypeScript SDK v0.2.83 or later |

668| `accountInfo()` | Returns account information |676| `accountInfo()` | Returns account information |

669| `reconnectMcpServer(serverName)` | Reconnect an MCP server by name. If the name also matches an entry in a settings file such as `.mcp.json` or `~/.claude.json`, Claude Code reconnects the server you configured through [`mcpServers`](#options) or `setMcpServers()`, not the settings-file entry. That resolution order requires Claude Code v2.1.257 or later |677| `reconnectMcpServer(serverName)` | Reconnect an MCP server by name. If the name also matches an entry in a settings file such as `.mcp.json` or `~/.claude.json`, Claude Code reconnects the server you configured through [`mcpServers`](#options) or `setMcpServers()`, not the settings-file entry. That resolution order requires Claude Code v2.1.257 or later |

670| `toggleMcpServer(serverName, enabled)` | Enable or disable an MCP server by name, with the same name resolution as `reconnectMcpServer()`. Disabling a server disconnects it and removes its tools. See [`toggleMcpServer()`](#togglemcpserver) for the Claude Code version this needs for each kind of server |678| `toggleMcpServer(serverName, enabled)` | Enable or disable an MCP server by name, with the same name resolution as `reconnectMcpServer()`. Disabling a server disconnects it and removes its tools. See [`toggleMcpServer()`](#togglemcpserver) for the Claude Code version this needs for each kind of server |

671| `setMcpServers(servers)` | Replace the MCP servers this method manages: servers added through it and [in-process SDK servers](#createsdkmcpserver). Resolves with an [`McpSetServersResult`](#mcpsetserversresult) naming which servers were added and removed, and any errors; that section says which other servers stay connected |679| `setMcpServers(servers)` | Replace the MCP servers this method manages: servers added through it and [in-process SDK servers](#createsdkmcpserver). Resolves with an [`McpSetServersResult`](#mcpsetserversresult) naming which servers were added and removed, and any errors; that section says which other servers stay connected |

680| `setMcpPermissionModeOverride(serverName, mode)` | Overrides the permission mode for one MCP server's tools with a stricter mode than the session's, or clears the override with `null`. Only available in streaming input mode. See [`setMcpPermissionModeOverride()`](#setmcppermissionmodeoverride). Requires TypeScript SDK v0.3.187 or later |

672| `readMcpResource(serverName, uri)` | *Alpha.* Reads one MCP Apps `ui://` resource from a connected MCP server so your application can render a tool's widget. Resolves with an [`SDKControlMcpReadResourceResponse`](#sdkcontrolmcpreadresourceresponse). Requires TypeScript Agent SDK v0.3.280 or later |681| `readMcpResource(serverName, uri)` | *Alpha.* Reads one MCP Apps `ui://` resource from a connected MCP server so your application can render a tool's widget. Resolves with an [`SDKControlMcpReadResourceResponse`](#sdkcontrolmcpreadresourceresponse). Requires TypeScript Agent SDK v0.3.280 or later |

673| `streamInput(stream)` | Stream input messages to the query for multi-turn conversations |682| `streamInput(stream)` | Stream input messages to the query for multi-turn conversations |

674| `stopTask(taskId)` | Stop a running background task by ID |683| `stopTask(taskId)` | Stop a running background task by ID |

684| `backgroundTasks(toolUseId?)` | Moves the running Bash commands and subagents that the turn is waiting on to the background, the same as pressing Ctrl+B in the interactive terminal. See [`backgroundTasks()`](#backgroundtasks). Requires TypeScript SDK v0.2.139 or later |

675| `close()` | Close the query and terminate the underlying process. Forcefully ends the query and cleans up all resources |685| `close()` | Close the query and terminate the underlying process. Forcefully ends the query and cleans up all resources |

676 686 

687#### `setMcpPermissionModeOverride()`

688 

689Overrides the permission mode for one MCP server's tools with a stricter mode than the session's, or clears the override with `null`. Use it when a session runs in a mode that skips per-action prompts but one server's tools should still be reviewed. Requires TypeScript SDK v0.3.187 or later.

690 

691Pass one of three values as `mode`:

692 

693* `'default'`: Claude Code evaluates that server's tool calls as [Manual mode](https://code.claude.com/docs/en/permission-modes.md#available-modes) does.

694* `'auto'`: Claude Code routes that server's tool calls through the [auto mode](https://code.claude.com/docs/en/permission-modes.md#eliminate-prompts-with-auto-mode) classifier. Claude Code rejects this value when the classifier isn't available to the session.

695* `null`: clears the override.

696 

697The override only takes effect while the session is in a mode that skips per-action prompts: `bypassPermissions` or `auto`. In any other session mode Claude Code ignores the override, so it can never widen what the session allows.

698 

699The promise resolves with `{ warning }` when no server by that name is known yet. Claude Code stores the override anyway and applies it once a server with that exact name connects, so the warning is a typo check, not a failure.

700 

701Only available in streaming input mode, the same constraint as `setModel()` and `setPermissionMode()`.

702 

703#### `seedReadState()`

704 

705Marks a file as already read so a later Edit doesn't fail with `File has not been read yet`. Use it when your application has dropped an earlier `Read` result from the conversation context and Claude will edit that file next. Requires TypeScript SDK v0.2.83 or later.

706 

707Pass `mtime` as the file's modification time at the moment of that earlier read, in whole milliseconds since the epoch, for example `Math.floor(stat.mtimeMs)`. If the file on disk changed after that time, Claude Code skips the mark.

708 

709The promise resolves whether or not the file was marked, so a resolved promise doesn't tell you which happened.

710 

711#### `backgroundTasks()`

712 

713Moves the running Bash commands and subagents that the turn is waiting on to the background, the same as pressing Ctrl+B in the interactive terminal. Pass the `toolUseId` of a tool call to background only the Bash command or subagent that call started, or omit it to background every foreground task. Requires TypeScript SDK v0.2.139 or later.

714 

715Each backgrounded tool call returns to Claude immediately with a running-in-the-background result, the turn continues, and Claude Code emits an [`SDKTaskNotificationMessage`](#sdktasknotificationmessage) when the task finishes.

716 

717In a session where background tasks are enabled, the promise resolves to a boolean:

718 

719* **`true`**: a task was backgrounded, or you omitted `toolUseId`.

720* **`false`**: the `toolUseId` you passed matched no foreground task.

721 

722If background tasks are disabled for the session, such as with [`CLAUDE_CODE_DISABLE_BACKGROUND_TASKS`](https://code.claude.com/docs/en/env-vars), the promise rejects instead and nothing is backgrounded.

723 

677#### `applyFlagSettings()`724#### `applyFlagSettings()`

678 725 

679Changes [settings](https://code.claude.com/docs/en/settings.md) on a running session without restarting the query. Use it when a setting that has no dedicated setter needs to change mid-session, such as tightening `permissions` after the agent reads untrusted input. `setModel()` and `setPermissionMode()` are dedicated setters for those two keys; `applyFlagSettings()` is the general form that accepts any subset of the settings keys, and passing `model` here behaves the same as `setModel()`.726Changes [settings](https://code.claude.com/docs/en/settings.md) on a running session without restarting the query. Use it when a setting that has no dedicated setter needs to change mid-session, such as tightening `permissions` after the agent reads untrusted input. `setModel()` and `setPermissionMode()` are dedicated setters for those two keys; `applyFlagSettings()` is the general form that accepts any subset of the settings keys, and passing `model` here behaves the same as `setModel()`.


1472 | SDKPermissionDeniedMessage1519 | SDKPermissionDeniedMessage

1473 | SDKPromptSuggestionMessage1520 | SDKPromptSuggestionMessage

1474 | SDKAPIRetryMessage1521 | SDKAPIRetryMessage

1522 | SDKControlRequestProgressMessage

1523 | SDKModelRefusalFallbackMessage

1524 | SDKModelRefusalNoFallbackMessage

1475 | SDKMirrorErrorMessage1525 | SDKMirrorErrorMessage

1476 | SDKInformationalMessage1526 | SDKInformationalMessage

1477 | SDKConversationResetMessage;1527 | SDKConversationResetMessage;

1478```1528```

1479 1529 

1530Three messages in this union report control-request progress and model refusals. Each has `type: "system"`, so tell them apart by the `subtype` listed with each one:

1531 

1532* `SDKControlRequestProgressMessage`, `subtype: "control_request_progress"`: reports progress on a long-running control request that your client sent. `request_id` matches the message to that request, and `status` is `"started"` or `"api_retry"`. Requires Agent SDK v0.3.203 or later.

1533* `SDKModelRefusalFallbackMessage`, `subtype: "model_refusal_fallback"`: emitted when the model ends the stream with a refusal and the turn is retried on a fallback model. Carries `original_model` and `fallback_model`. Requires Agent SDK v0.3.170 or later.

1534* `SDKModelRefusalNoFallbackMessage`, `subtype: "model_refusal_no_fallback"`: emitted when the model ends the stream with a refusal and no retry runs, for example because no fallback model is configured. Carries `original_model`. Requires Agent SDK v0.3.193 or later.

1535 

1480### `SDKAssistantMessage`1536### `SDKAssistantMessage`

1481 1537 

1482Assistant response message.1538Assistant response message.


1636 stop_reason: string | null;1692 stop_reason: string | null;

1637 ttft_ms?: number;1693 ttft_ms?: number;

1638 ttft_stream_ms?: number;1694 ttft_stream_ms?: number;

1695 time_to_request_ms?: number;

1639 user_message_uuid?: string;1696 user_message_uuid?: string;

1640 user_message_uuids?: string[];1697 user_message_uuids?: string[];

1641 resume_reason?: string;1698 resume_reason?: string;


1701* `api_error_status`: the HTTP status code of the API error that terminated the conversation. Absent or `null` when the turn ended without an API error.1758* `api_error_status`: the HTTP status code of the API error that terminated the conversation. Absent or `null` when the turn ended without an API error.

1702* `ttft_ms`: time to first token in milliseconds, measured when the first complete assistant message arrives. Present on the success arm only.1759* `ttft_ms`: time to first token in milliseconds, measured when the first complete assistant message arrives. Present on the success arm only.

1703* `ttft_stream_ms`: time in milliseconds until the first `message_start` stream event, when the response stream opens. Lower than `ttft_ms`; the gap between the two is time spent streaming the first message. Present on the success arm only.1760* `ttft_stream_ms`: time in milliseconds until the first `message_start` stream event, when the response stream opens. Lower than `ttft_ms`; the gap between the two is time spent streaming the first message. Present on the success arm only.

1761* `time_to_request_ms`: time in milliseconds from the start of the turn until Claude Code sends the API request. Present on the success arm only. Requires Claude Code v2.1.162 or later.

1704* `user_message_uuid`: the `uuid` of the message you sent that this turn answered. See [`user_message_uuid`](#user_message_uuid) for which results carry it.1762* `user_message_uuid`: the `uuid` of the message you sent that this turn answered. See [`user_message_uuid`](#user_message_uuid) for which results carry it.

1705* `user_message_uuids`: the `uuid`s of every message you sent that Claude Code answered in this turn. See [`user_message_uuids`](#user_message_uuids).1763* `user_message_uuids`: the `uuid`s of every message you sent that Claude Code answered in this turn. See [`user_message_uuids`](#user_message_uuids).

1706* `resume_reason`: why this turn continues one that a restart interrupted. Present on both arms. See [`resume_reason`](#resume_reason).1764* `resume_reason`: why this turn continues one that a restart interrupted. Present on both arms. See [`resume_reason`](#resume_reason).


1772* Turns that answer no message of yours, or answer a message you sent without a `uuid`1830* Turns that answer no message of yours, or answer a message you sent without a `uuid`

1773* Results that answer no message you sent, such as the zeroed result after a crashed worker process1831* Results that answer no message you sent, such as the zeroed result after a crashed worker process

1774 1832 

1833When a [`UserPromptSubmit`](https://code.claude.com/docs/en/hooks#userpromptsubmit) hook blocks a message that starts its own turn, or stops it with `continue: false`, you still get a result for that message. It's a success result with `is_error: false` and `num_turns: 0`, its `result` is the [block message](https://code.claude.com/docs/en/hooks.md#what-a-blocked-prompt-leaves-behind) or [stop message](https://code.claude.com/docs/en/hooks.md#json-output), and it echoes the message's `uuid` under the same rules as any other result. The result has no `terminal_reason`, and nothing on it besides the `result` text says a hook ended the turn. A message that a hook blocks while another turn is running may get no result: see [`user_message_uuids`](#user_message_uuids).

1834 

1775#### `user_message_uuids`1835#### `user_message_uuids`

1776 1836 

1777The `uuid`s of every message you sent that Claude Code answered in this turn. When you send several messages close together, Claude Code can merge them into one turn, and `user_message_uuid` then names only the last of them. To match the reply to any of the merged messages, look for that message's `uuid` anywhere in this list. Requires Agent SDK v0.3.259 or later.1837The `uuid`s of every message you sent that Claude Code answered in this turn. When you send several messages close together, Claude Code can merge them into one turn, and `user_message_uuid` then names only the last of them. To match the reply to any of the merged messages, look for that message's `uuid` anywhere in this list. Requires Agent SDK v0.3.259 or later.

1778 1838 

1779Claude Code sets the list together with `user_message_uuid` on each reply frame that carries that field and on the result. For the full set of turn frames that echo the answered message's `uuid`, and the version each requires, see [`user_message_uuid`](#user_message_uuid). The list always contains `user_message_uuid` and holds at most 64 entries.1839Claude Code sets the list together with `user_message_uuid` on each reply frame that carries that field and on the result. For the full set of turn frames that echo the answered message's `uuid`, and the version each requires, see [`user_message_uuid`](#user_message_uuid). The list always contains `user_message_uuid` and holds at most 64 entries.

1780 1840 

1781When Claude Code picks up a regular message you sent while a turn was running, it adds that message's `uuid` to the result's list.1841When Claude Code picks up a regular message you sent while a turn was running, it adds that message's `uuid` to the result's list. When a [`UserPromptSubmit`](https://code.claude.com/docs/en/hooks#userpromptsubmit) hook blocks the message at pickup, Claude Code drops it instead: the message never reaches Claude and isn't kept for a later turn. You get no result for it, and its `uuid` appears in no result's list. If a hook can block messages, set a timeout on waiting for a result that lists a message you sent while a turn was running.

1842 

1843That holds when the hook's output is a block alone. If the output sets `continue: false`, even beside `decision: "block"`, or the hook is a prompt hook that answers [`ok: false`](https://code.claude.com/docs/en/hooks#response-schema) without `continueOnBlock: true`, Claude Code stops the message instead of dropping it. The message waits for its own turn, you get a result for it, and its text stays in the conversation, so Claude sees it on the next turn.

1782 1844 

1783When a first reply or result carries `user_message_uuid` without the list, it came from an earlier Claude Code version, so fall back to the single field.1845When a first reply or result carries `user_message_uuid` without the list, it came from an earlier Claude Code version, so fall back to the single field.

1784 1846 

Details

582}582}

583```583```

584 584 

585A remote reply that doesn't exactly match the expected format fails in one of two ways, and in both cases the local terminal dialog stays open:585If a remote reply has no effect and the local terminal dialog stays open, check for these causes:

586 586 

587* **Different format**: your inbound handler's regex fails to match, so text like `approve it` or `yes` without an ID falls through as a normal message to Claude.587* **The format is wrong**: your inbound handler's regex fails to match, so text like `approve it` or `yes` without an ID falls through as a normal message to Claude.

588* **Right format, wrong ID**: your server emits a verdict, but Claude Code finds no open request with that ID and drops it silently.588* **The ID is wrong**: your server emits a verdict, but Claude Code finds no open request with that ID and drops it silently.

589* **The ID was used by an earlier prompt**: your server emits a verdict with the ID from the request, but an earlier prompt in the session had the same ID. Once an ID repeats, Claude Code drops any channel verdict carrying it, so that a reply meant for one prompt can't approve the other. An ID is five random letters, so a repeat is rare. Answer at the terminal instead.

589 590 

590### Full example591### Full example

591 592 

Details

90 90 

91### Messages sent mid-turn not checkpointed91### Messages sent mid-turn not checkpointed

92 92 

93In the rewind menu, a message you [typed while Claude was still working](https://code.claude.com/docs/en/interactive-mode.md#queue-messages-while-claude-works) can be marked **No code restore**. Claude read that message before its turn ended. [Checkpoints are taken for prompts that start a turn](#how-checkpoints-work), so this message has none of its own. The edits Claude made after reading it count toward the prompt that started the turn.93In the rewind menu, a message you [typed while Claude was still working](https://code.claude.com/docs/en/interactive-mode.md#queue-messages-while-claude-works) can be marked **No code restore**. The marked message has no [checkpoint](#how-checkpoints-work) of its own.

94 94 

95You don't need to do anything about the message itself. To undo the file changes from that part of the session, select the prompt that started the turn and choose **Restore code** or **Restore code and conversation**. That reverts Claude's file edits from the whole turn, including the ones from before your message arrived. Selecting the marked message still offers **Restore conversation**, which rewinds the conversation to it and leaves your files as they are.95To undo the file edits Claude made after that message, select the prompt that started the turn and choose **Restore code** or **Restore code and conversation**. That reverts Claude's file edits from the whole turn, including the ones from before your message arrived.

96 96 

97### Symlinked and hard-linked paths not restored97### Symlinked and hard-linked paths not restored

98 98 

Details

98 98 

99The warnings and the percentage come from the `anthropic-ratelimit-unified-*` headers, which the gateway adds to each successful `/v1/messages` response for a developer who has a cap. The headers always describe the developer's own cap: the gateway strips the upstream provider's rate-limit headers, which describe your shared quota, and never forwards them.99The warnings and the percentage come from the `anthropic-ratelimit-unified-*` headers, which the gateway adds to each successful `/v1/messages` response for a developer who has a cap. The headers always describe the developer's own cap: the gateway strips the upstream provider's rate-limit headers, which describe your shared quota, and never forwards them.

100 100 

101The spend a developer sees is the gateway's own [estimate](#how-requests-are-priced), the same figure it enforces the cap with, and not an amount from your provider's bill. Claude Code reads the dollar amounts with a separate request to the gateway. If you set `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC` on developers' machines, as [Compliance posture](https://code.claude.com/docs/en/claude-apps-gateway-deploy.md#compliance-posture) suggests, Claude Code skips that request. With that variable set, or with a gateway server older than v2.1.284, the bar and the status line stay percentage-only.101The spend a developer sees is the gateway's own [estimate](#how-requests-are-priced), the same figure it enforces the cap with. It isn't an amount from your provider's bill. Claude Code reads the dollar amounts with a separate request to the gateway, which it sends even if you set `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC` on developers' machines. Before v2.1.295, Claude Code skipped that request when the variable was set, and `/usage` and the status line showed the percentage and the reset date, with no dollar amounts.

102 102 

103## Admin API reference103## Admin API reference

104 104 

Details

18 18 

19* **Browser**: [claude.ai/code](https://claude.ai/code), also called Claude Code on the web19* **Browser**: [claude.ai/code](https://claude.ai/code), also called Claude Code on the web

20* **Mobile**: the **Code** tab in the [Claude app](https://code.claude.com/docs/en/mobile.md)20* **Mobile**: the **Code** tab in the [Claude app](https://code.claude.com/docs/en/mobile.md)

21* **Desktop app**: select **Cloud** instead of **Local** when you [start a session](https://code.claude.com/docs/en/desktop.md#run-long-running-tasks-in-the-cloud)21* **Desktop app**: select an environment under **Cloud** in the environment selector when you [start a session](https://code.claude.com/docs/en/desktop.md#run-long-running-tasks-in-the-cloud)

22* **Terminal**: [`claude --cloud`](#from-terminal-to-cloud)22* **Terminal**: [`claude --cloud`](#from-terminal-to-cloud)

23* **Cloud scheduled tasks**: [scheduled and triggered runs](https://code.claude.com/docs/en/routines.md) each run as a cloud session23* **Cloud scheduled tasks**: [scheduled and triggered runs](https://code.claude.com/docs/en/routines.md) each run as a cloud session

24 24 


247 247 

248### Review changes248### Review changes

249 249 

250Each session shows a diff indicator with lines added and removed, like `+42 -18`. Select it to open the diff view, leave inline comments on specific lines, and send them to Claude with your next message.250After Claude pushes its changes to a branch, the **Changes** card in the panel beside the chat shows the lines added and removed, such as `+42 -18`. Click the line counts on the **Changes** card to open the diff view.

251 251 

252The diff view compares the session's changes against its base branch by default. To compare against any other branch in the repository, select **Compare against** and pick one.252* You can also click **Changes** in the session's title bar, or in the bar's **⋮** menu.

253* To show the panel when it's hidden, click the **Show session rail** icon in the session's title bar, or in the bar's **⋮** menu.

254 

255In the diff view, you can comment on lines and compare against another branch:

256 

257* **Comment**: leave inline comments on specific lines, then send the comments to Claude with your next message

258* **Compare**: the diff view compares the session's changes against its base branch by default. To compare against any other branch in the repository, select **Compare against** and pick one

253 259 

254Claude Code computes these diffs from raw git blob content, so diff drivers and `textconv` filters configured in the repository don't apply.260Claude Code computes these diffs from raw git blob content, so diff drivers and `textconv` filters configured in the repository don't apply.

255 261 


313 319 

314### Archive sessions320### Archive sessions

315 321 

316You can archive sessions to keep your session list organized. Archived sessions are hidden from the default session list but can be viewed by filtering for archived sessions.322Archive a session to remove it from the sidebar's session list. To archive one, hover over it in the sidebar, open its **⋯** menu, and select **Archive**.

317 323 

318To archive a session, hover over the session in the sidebar and select the archive icon.324#### Find an archived session

325 

326To see your archived sessions, go to [claude.ai/code/sessions](https://claude.ai/code/sessions) and open the **Archived** tab. To put one back in the sidebar's session list, hover over it on that tab, open its **⋮** menu, and select **Unarchive**.

319 327 

320### Delete sessions328### Delete sessions

321 329 

322Deleting a session permanently removes the session and its data. This action can't be undone. You can delete a session in two ways:330Deleting a session permanently removes the session and its data. This action can't be undone. Delete a session from the sidebar, from the session menu, or from the **Archived** tab if you've already archived it:

323 331 

324* **From the sidebar**: filter for archived sessions, then hover over the session you want to delete and select the delete icon332* **From the sidebar**: hover over the session, open its **⋯** menu, and select **Delete**

325* **From the session menu**: open a session, select the dropdown next to the session title, and select **Delete**333* **From the session menu**: open a session, select the dropdown next to the session title, and select **Delete**

334* **From the Archived tab**: hover over the session on the [**Archived** tab](#find-an-archived-session), open its **⋮** menu, and select **Delete**

326 335 

327You will be asked to confirm before a session is deleted.336You will be asked to confirm before a session is deleted.

328 337 


336 345 

337There are a few ways to turn on auto-fix depending on where the PR came from and what device you're using:346There are a few ways to turn on auto-fix depending on where the PR came from and what device you're using:

338 347 

339* **PRs created in a cloud session**: open the session at claude.ai/code, open the CI status bar, and select **Auto-fix**348* **PRs created in a cloud session**: open the session at claude.ai/code and find the pull request in the [**Changes** card](#review-changes). Open the **⋮** menu next to the pull request's title and turn on **Auto-fix**

340* **From your terminal**: run [`/autofix-pr`](https://code.claude.com/docs/en/commands) while on the PR's branch. Claude Code detects the open PR with `gh`, spawns a cloud session, and turns on auto-fix in one step349* **From your terminal**: run [`/autofix-pr`](https://code.claude.com/docs/en/commands) while on the PR's branch. Claude Code detects the open PR with `gh`, spawns a cloud session, and turns on auto-fix in one step

341* **From the mobile app**: tell Claude to auto-fix the PR, for example "watch this PR and fix any CI failures or review comments"350* **From the mobile app**: tell Claude to auto-fix the PR, for example "watch this PR and fix any CI failures or review comments"

342* **Any existing PR**: paste the PR URL into a session and tell Claude to auto-fix it351* **Any existing PR**: paste the PR URL into a session and tell Claude to auto-fix it

343 352 

344Auto-fix is a per-PR toggle. To stop monitoring, open the CI status bar in the session at claude.ai/code and clear the **Auto-fix** toggle, or tell Claude to stop watching the PR.353To stop monitoring, turn off **Auto-fix** in the pull request's **⋮** menu in the session's [**Changes** card](#review-changes), or tell Claude to stop watching the PR.

345 354 

346### How Claude responds to PR activity355### How Claude responds to PR activity

347 356 


381* Retry after a minute, as capacity is provisioned on demand390* Retry after a minute, as capacity is provisioned on demand

382* Confirm your GitHub connection can reach the repository by following [No repositories appear after connecting GitHub](https://code.claude.com/docs/en/web-quickstart.md#no-repositories-appear-after-connecting-github)391* Confirm your GitHub connection can reach the repository by following [No repositories appear after connecting GitHub](https://code.claude.com/docs/en/web-quickstart.md#no-repositories-appear-after-connecting-github)

383 392 

393### Your new session couldn't start

394 

395Your prompt is back in the box you sent it from.

396 

397* **Connection lost**: check your internet connection and any VPN or proxy you use, then send your prompt again

398* **Server error**: wait a moment, then send your prompt again. If the notice reappears, check [status.claude.com](https://status.claude.com)

399 

400### Can't rewind to this message

401 

402**Rewind to here** fails with this error on any message except the newest when your session runs on a [self-hosted runner](https://code.claude.com/docs/en/self-hosted-environments) with Claude Code before v2.1.246. Ask whoever runs your organization's runners to [upgrade them](https://code.claude.com/docs/en/self-hosted-environments-deploy.md#pin-the-version).

403 

384### Unable to get organization UUID404### Unable to get organization UUID

385 405 

386`claude --cloud` and `claude --teleport` require sign-in with a claude.ai account. If you authenticate with an API key, or your stored account details are stale, you see one of these:406`claude --cloud` and `claude --teleport` require sign-in with a claude.ai account. If you authenticate with an API key, or your stored account details are stale, you see one of these:

Details

111 111 

112The project is now listed under **Projects** in the sidebar, and its conversation is open. [Your first batch](#your-first-batch) covers what to set up before you send it work.112The project is now listed under **Projects** in the sidebar, and its conversation is open. [Your first batch](#your-first-batch) covers what to set up before you send it work.

113 113 

114### Start from an existing cloud session114### Start from an existing session

115 115 

116If a cloud session you started yourself is doing work that belongs in a project, open its sidebar menu and choose **Move to project**, then pick from the submenu:116If a cloud session you started yourself is doing work that belongs in a project, open its sidebar menu and choose **Move to project**, then pick from the submenu:

117 117 


120 120 

121A **Set up project** banner can also appear above a cloud session's message box. If you use it instead of **Continue as new project**, the result is the same, except that the session's running turn stops once the project opens.121A **Set up project** banner can also appear above a cloud session's message box. If you use it instead of **Continue as new project**, the result is the same, except that the session's running turn stops once the project opens.

122 122 

123A local session doesn't have these options. To continue its work in a project, describe the work in the project conversation, or push its branch, add that repository to the project, and name the branch in the task.123A session on your own machine gets the same sidebar menu at claude.ai/code once you connect it through [Remote Control](https://code.claude.com/docs/en/remote-control.md#start-a-remote-control-session). From a project, Claude can't read the transcript of a session that connected while [**Require trusted devices**](https://code.claude.com/docs/en/remote-control.md#trusted-devices) was on for your account. If that setting is off:

124 

1251. If the session isn't connected yet, run `/remote-control` in it. If it connected while that setting was on, disconnect it and connect it again first.

1262. In a browser, find the session's row in the sidebar at [claude.ai/code](https://claude.ai/code), open its menu, and pick from the same submenu.

127 

128If **Require trusted devices** is on, or you don't use Remote Control, describe the work in the project conversation yourself. Or push the session's branch, add its repository to the project, and tell Claude the branch name.

124 129 

125### Set up GitHub access130### Set up GitHub access

126 131 


425* **Cloud sessions**: every thread is a [cloud session](https://code.claude.com/docs/en/claude-code-on-the-web.md) unless you ask Claude to run it on your machine. Either way, Claude starts and tracks it instead of you. You can also bring the work of a cloud session you started yourself into a project: choose [**Move to project**](#start-from-an-existing-cloud-session) in that session's sidebar menu.430* **Cloud sessions**: every thread is a [cloud session](https://code.claude.com/docs/en/claude-code-on-the-web.md) unless you ask Claude to run it on your machine. Either way, Claude starts and tracks it instead of you. You can also bring the work of a cloud session you started yourself into a project: choose [**Move to project**](#start-from-an-existing-cloud-session) in that session's sidebar menu.

426* **Scheduled tasks**: when you ask for scheduled work in a project, Claude creates a [cloud scheduled task](https://code.claude.com/docs/en/routines.md) that runs as threads in that project and appears on its **Scheduled tasks** tab. Scheduled tasks you create outside a project keep working on their own.431* **Scheduled tasks**: when you ask for scheduled work in a project, Claude creates a [cloud scheduled task](https://code.claude.com/docs/en/routines.md) that runs as threads in that project and appears on its **Scheduled tasks** tab. Scheduled tasks you create outside a project keep working on their own.

427* **Remote Control**: [Remote Control](https://code.claude.com/docs/en/remote-control.md) connects claude.ai to a Claude Code session running on your machine. When you ask Claude in a project to run a thread on your computer, the project [uses Remote Control to do it](#run-a-thread-on-your-own-computer).432* **Remote Control**: [Remote Control](https://code.claude.com/docs/en/remote-control.md) connects claude.ai to a Claude Code session running on your machine. When you ask Claude in a project to run a thread on your computer, the project [uses Remote Control to do it](#run-a-thread-on-your-own-computer).

428* **Local sessions and agent view**: a session you start yourself in your terminal, IDE, or the desktop app's local environment can't be added to a project. [Agent view](https://code.claude.com/docs/en/agent-view.md) is a screen for tracking several local sessions side by side, and you still start each one and give it its task yourself.433* **Local sessions and agent view**: a session you start yourself in your terminal, IDE, or the desktop app's local environment stays outside your projects, though you can [bring its work into one](#start-from-an-existing-cloud-session). [Agent view](https://code.claude.com/docs/en/agent-view.md) is a screen for tracking several local sessions side by side, and you still start each one and give it its task yourself.

429* **Worktrees**: a [worktree](https://code.claude.com/docs/en/worktrees.md) gives each local session its own working copy of a repository. Cloud threads don't need them: each clones its repositories into its own cloud sandbox and works on its own branch.434* **Worktrees**: a [worktree](https://code.claude.com/docs/en/worktrees.md) gives each local session its own working copy of a repository. Cloud threads don't need them: each clones its repositories into its own cloud sandbox and works on its own branch.

430* **Agent teams**: an [agent team](https://code.claude.com/docs/en/agent-teams.md) is one session that starts teammate sessions for a single task, on your machine or inside a cloud session, and ends with that task.435* **Agent teams**: an [agent team](https://code.claude.com/docs/en/agent-teams.md) is one session that starts teammate sessions for a single task, on your machine or inside a cloud session, and ends with that task.

431* **Subagents**: a [subagent](https://code.claude.com/docs/en/sub-agents.md) runs inside one session, does a side task in its own context window, and returns a summary to that session. A project's threads are whole sessions that Claude starts and that report back to the project conversation, and a thread can still use subagents for its own side tasks.436* **Subagents**: a [subagent](https://code.claude.com/docs/en/sub-agents.md) runs inside one session, does a side task in its own context window, and returns a summary to that session. A project's threads are whole sessions that Claude starts and that report back to the project conversation, and a thread can still use subagents for its own side tasks.


437 442 

438* Projects are available at claude.ai/code, in the desktop app, and in the Claude mobile app, not in the terminal CLI, the VS Code extension, or the JetBrains plugin, and not through Amazon Bedrock, Google Cloud's Agent Platform, or Microsoft Foundry.443* Projects are available at claude.ai/code, in the desktop app, and in the Claude mobile app, not in the terminal CLI, the VS Code extension, or the JetBrains plugin, and not through Amazon Bedrock, Google Cloud's Agent Platform, or Microsoft Foundry.

439* Project threads are [cloud sessions](https://code.claude.com/docs/en/claude-code-on-the-web.md), or sessions on your own machine through [Remote Control](https://code.claude.com/docs/en/remote-control.md), with Anthropic as the model provider in both cases. [Security](https://code.claude.com/docs/en/security.md) and [Data usage](https://code.claude.com/docs/en/data-usage.md) cover how cloud sessions are isolated and what's retained, and [Connection and security](https://code.claude.com/docs/en/remote-control.md#connection-and-security) covers how a thread on your machine connects and what's stored.444* Project threads are [cloud sessions](https://code.claude.com/docs/en/claude-code-on-the-web.md), or sessions on your own machine through [Remote Control](https://code.claude.com/docs/en/remote-control.md), with Anthropic as the model provider in both cases. [Security](https://code.claude.com/docs/en/security.md) and [Data usage](https://code.claude.com/docs/en/data-usage.md) cover how cloud sessions are isolated and what's retained, and [Connection and security](https://code.claude.com/docs/en/remote-control.md#connection-and-security) covers how a thread on your machine connects and what's stored.

440* You can't add a session you started yourself on your machine to a project. A project reaches your machine only by [running a thread there through Remote Control](#run-a-thread-on-your-own-computer), and that section lists what it needs.445* You can't add a session you started yourself on your machine to a project, though you can [bring its work into one](#start-from-an-existing-cloud-session). A project reaches your machine by [running a thread there through Remote Control](#run-a-thread-on-your-own-computer), and that section lists what it needs.

441* A cloud thread's sandbox pauses between turns and resumes when the thread continues. If the sandbox can't be resumed, the thread continues from a fresh clone, so uncommitted changes can be lost. On long tasks, ask Claude to commit and push work in progress.446* A cloud thread's sandbox pauses between turns and resumes when the thread continues. If the sandbox can't be resumed, the thread continues from a fresh clone, so uncommitted changes can be lost. On long tasks, ask Claude to commit and push work in progress.

442* A project belongs to one user. You can't share a project or its threads with another user, and thread transcripts don't have the share option other cloud sessions have. There are no organization-level controls for projects during the beta.447* A project belongs to one user. You can't share a project or its threads with another user, and thread transcripts don't have the share option other cloud sessions have. There are no organization-level controls for projects during the beta.

443* A thread belongs to the one project that started it. You can't move or copy a thread to another project, or move it out to stand alone. [**Move to project**](#start-from-an-existing-cloud-session) goes the other way only: it brings a cloud session's work into a project. You can't merge two projects into one.448* A thread belongs to the one project that started it. You can't move or copy a thread to another project, or move it out to stand alone. [**Move to project**](#start-from-an-existing-cloud-session) goes the other way only: it brings a cloud session's work into a project. You can't merge two projects into one.

code-review.md +1 −1

Details

67 67 

68* **Findings**: inline comments on the lines concerned, with a summary in the review body68* **Findings**: inline comments on the lines concerned, with a summary in the review body

69* **A check run**: named **Claude Code Review**, with the findings listed in its [details](https://code.claude.com/docs/en/code-review-pull-requests.md#check-run-output). The check run doesn't conclude as a failure.69* **A check run**: named **Claude Code Review**, with the findings listed in its [details](https://code.claude.com/docs/en/code-review-pull-requests.md#check-run-output). The check run doesn't conclude as a failure.

70* **When it finds nothing**: the check run's title reads **Code review found no issues**, and Claude posts the same short note on the pull request70* **A note in place of findings**: posted when the check run's title reads **Code review found no issues**

71 71 

72Code Review chooses the Claude models that reviews run on, and its admin settings don't offer a model choice. To make reviews more or less thorough, change the [review level](#review-levels).72Code Review chooses the Claude models that reviews run on, and its admin settings don't offer a model choice. To make reviews more or less thorough, change the [review level](#review-levels).

73 73 

Details

152 152 

153### What a later review covers153### What a later review covers

154 154 

155A later review that starts on its own, such as after a push, focuses on what changed since the last review and posts fewer nits and pre-existing findings. Its summary counts what it left out, in a line that ends "found and not posted" or "outside the scope of this re-review and not posted."155A later review that starts on its own, such as after a push, focuses on what changed since the last review and posts fewer [nits and pre-existing findings](#severity-levels). To see whether it left findings out as a result, look in the review body for a sentence that counts them:

156 

157* **Findings on code that hasn't changed since the last review**: the sentence ends "outside the scope of this re-review and not posted"

158* **Nits and pre-existing findings**: the sentence ends "found and not posted"

156 159 

157To get a review that leaves none of these out, comment [`@claude review`](#comment-commands). It covers the whole pull request again.160To get a review that leaves none of these out, comment [`@claude review`](#comment-commands). It covers the whole pull request again.

158 161 

Details

15| Check run title | What it means | What to do |15| Check run title | What it means | What to do |

16| :- | :- | :- |16| :- | :- | :- |

17| **Code review queued...** or **Code review in progress...** | The review hasn't finished | Wait for the title to change |17| **Code review queued...** or **Code review in progress...** | The review hasn't finished | Wait for the title to change |

18| **Code review found no issues** | The review finished and found nothing to flag | Nothing |18| **Code review found no issues** | The review finished and posted no findings | If this isn't the pull request's first review, look in the review body for a count of [findings the review left out](https://code.claude.com/docs/en/code-review-pull-requests.md#what-a-later-review-covers). Otherwise, nothing |

19| A title that says issues were found | The review finished with findings | If you don't see them on the diff, see [Find issues that aren't showing as inline comments](#find-issues-that-aren’t-showing-as-inline-comments) |19| A title that says issues were found | The review finished with findings | If you don't see them on the diff, see [Find issues that aren't showing as inline comments](#find-issues-that-aren’t-showing-as-inline-comments) |

20| **Code review skipped — no new changes** | An automatic review didn't run on your latest push | To get a review anyway, comment `@claude review` |20| **Code review skipped — no new changes** | An automatic review didn't run on your latest push | To get a review anyway, comment `@claude review` |

21| **Code review not repeated — earlier findings still open** | An automatic review didn't run on your latest push, and Important findings from the earlier review are still open | Push a fix, or to get a review anyway, comment `@claude review`. See [When a push keeps the earlier result](https://code.claude.com/docs/en/code-review-pull-requests.md#when-a-push-keeps-the-earlier-result) |21| **Code review not repeated — earlier findings still open** | An automatic review didn't run on your latest push, and Important findings from the earlier review are still open | Push a fix, or to get a review anyway, comment `@claude review`. See [When a push keeps the earlier result](https://code.claude.com/docs/en/code-review-pull-requests.md#when-a-push-keeps-the-earlier-result) |

desktop.md +48 −17

Details

223 223 

224#### Hide or show the session details panel224#### Hide or show the session details panel

225 225 

226To hide or show the panel, click **Hide session rail** or **Show session rail** in the session's title bar, or in the bar's **⋮** menu when the window is narrow. If you still don't see the panel, [check which Code tab layout you have](#check-which-layout-you-have).226To hide or show the panel, click **Hide session rail** or **Show session rail** in the session's title bar, or in the bar's **⋮** menu. If you still don't see the panel, [check which Code tab layout you have](#check-which-layout-you-have).

227 227 

228### Run commands in the terminal228### Run commands in the terminal

229 229 


984 984 

985* **System**: an x86\_64 or arm64 processor. The machine also has to meet Claude Code's [system requirements](https://code.claude.com/docs/en/setup.md#system-requirements). On Linux, Claude Code needs glibc 2.17 or later, or musl. To see which one the machine has, run `ldd --version` there. On a musl-based distribution such as Alpine Linux, also install the [packages that Claude Code needs](https://code.claude.com/docs/en/setup.md#alpine-linux-and-musl-based-distributions).985* **System**: an x86\_64 or arm64 processor. The machine also has to meet Claude Code's [system requirements](https://code.claude.com/docs/en/setup.md#system-requirements). On Linux, Claude Code needs glibc 2.17 or later, or musl. To see which one the machine has, run `ldd --version` there. On a musl-based distribution such as Alpine Linux, also install the [packages that Claude Code needs](https://code.claude.com/docs/en/setup.md#alpine-linux-and-musl-based-distributions).

986* **SFTP**: the SSH server has to offer the SFTP subsystem, which a `Subsystem sftp` line in its `sshd_config` turns on. To check, connect to the same host and port with `sftp` in a terminal on your computer. A working server shows the `sftp>` prompt.986* **SFTP**: the SSH server has to offer the SFTP subsystem, which a `Subsystem sftp` line in its `sshd_config` turns on. To check, connect to the same host and port with `sftp` in a terminal on your computer. A working server shows the `sftp>` prompt.

987* **Sessions per connection**: Desktop on macOS and Linux opens several sessions on one SSH connection. If the server's `sshd_config` sets `MaxSessions 1`, raise it, for example to OpenSSH's default of 10.987* **`MaxSessions 1` on the server**: to connect to a server whose `sshd_config` sets `MaxSessions 1`, do one of these:

988 * **Your computer runs macOS or Linux**: update to Claude Desktop v3.1623.0 or later

989 * **Your computer runs Windows**: make sure that Desktop [connects through the OpenSSH client](#use-your-ssh-configuration), because Desktop's built-in SSH client can't connect to that server

990 * **You can change the server**: raise `MaxSessions`, for example to OpenSSH's default of 10

991* **Logins with `MaxSessions 1`**: use a login that works without a prompt, such as a key that your SSH agent holds. Desktop logs in at least twice each time it connects or reconnects. Expect at least one more login for each [terminal](#run-commands-in-the-terminal) tab, and for each Desktop session in which you run commands that start with `!`. Expect none for commands that Claude runs.

992* **One-time codes with `MaxSessions 1`**: if every login prompts you, as with one-time codes, `!` commands fail. Run those commands in a terminal tab instead, which prompts in its own pane.

988* **Install folder**: Desktop installs a helper program and Claude Code under `~/.claude/remote/` in your home directory. It runs them from there, so that folder can't be on a file system mounted `noexec`. Allow about 1 GB of disk space in the home directory of each user who connects. For what that folder holds, see [Files and processes on the remote machine](#files-and-processes-on-the-remote-machine).993* **Install folder**: Desktop installs a helper program and Claude Code under `~/.claude/remote/` in your home directory. It runs them from there, so that folder can't be on a file system mounted `noexec`. Allow about 1 GB of disk space in the home directory of each user who connects. For what that folder holds, see [Files and processes on the remote machine](#files-and-processes-on-the-remote-machine).

989* **Shell**: the shell set for your account on the remote machine has to run commands sent over SSH, as Bash, Zsh, and `sh` do994* **Shell**: the shell set for your account on the remote machine has to run commands sent over SSH, as Bash, Zsh, and `sh` do

990* **Network**: Claude Code runs on the remote machine and makes its network requests from there, so the machine needs the [network access that Claude Code requires](https://code.claude.com/docs/en/network-config.md#network-access-requirements). If the machine can't download Claude Code, Desktop downloads it on your computer and uploads it. Claude Code's other requests still go out from the remote machine. On a Linux remote machine, if those requests need a proxy, [set it for SSH sessions](#set-a-proxy-or-a-ca-certificate-for-ssh-sessions).995* **Network**: Claude Code runs on the remote machine and makes its network requests from there, so the machine needs the [network access that Claude Code requires](https://code.claude.com/docs/en/network-config.md#network-access-requirements). If the machine can't download Claude Code, Desktop downloads it on your computer and uploads it. Claude Code's other requests still go out from the remote machine. On a Linux remote machine, if those requests need a proxy, [set it for SSH sessions](#set-a-proxy-or-a-ca-certificate-for-ssh-sessions).


993 998 

994If a Linux remote machine reaches the internet through a proxy or needs a CA certificate, add the [proxy and CA variables](https://code.claude.com/docs/en/network-config.md) under `env` in `~/.claude/settings.json` there. Add them even if you already export them in `~/.profile`, `~/.bash_profile`, `~/.zprofile`, or `~/.zshrc` on that machine.999If a Linux remote machine reaches the internet through a proxy or needs a CA certificate, add the [proxy and CA variables](https://code.claude.com/docs/en/network-config.md) under `env` in `~/.claude/settings.json` there. Add them even if you already export them in `~/.profile`, `~/.bash_profile`, `~/.zprofile`, or `~/.zshrc` on that machine.

995 1000 

996An SSH session doesn't get them from those files, even when `claude` in a terminal on that machine does. The session can then hang, or show **The connection from … to the API failed** or **Authentication failed**, and signing in again doesn't help.1001In an SSH session, Claude Code doesn't get the variables from those files, even when `claude` in a terminal on that machine does. The session can then hang, or show **The connection from … to the API failed** or **Authentication failed**, and signing in again doesn't help.

997 1002 

998**1. Add the variables**1003**1. Add the variables**

999 1004 


1028 1033 

1029Restart the remote machine, or quit Desktop and end the helper's processes, as in the first two steps to [remove the helper](#files-and-processes-on-the-remote-machine). Do this when no task is running, because either way interrupts Claude's work.1034Restart the remote machine, or quit Desktop and end the helper's processes, as in the first two steps to [remove the helper](#files-and-processes-on-the-remote-machine). Do this when no task is running, because either way interrupts Claude's work.

1030 1035 

1031#### Use your SSH configuration on macOS and Linux1036#### Use your SSH configuration

1032 1037 

1033On macOS and Linux, Desktop connects by running the OpenSSH client on your computer, so it uses your `~/.ssh/config`. Connecting through the OpenSSH client requires Claude Desktop v1.37937.0 or later. Enter a `Host` name from that file in the **SSH host** field to use settings from its entry, such as `HostName`, `User`, `IdentityFile`, `CertificateFile`, `ProxyJump`, and `ProxyCommand`.1038You can use your SSH configuration on macOS, Linux, and Windows when Desktop connects through the OpenSSH client on your computer:

1039 

1040* **macOS and Linux**: Desktop connects by running the OpenSSH client on your computer, so it uses your `~/.ssh/config`. Connecting through the OpenSSH client requires Claude Desktop v1.37937.0 or later.

1041* **Windows**: when Desktop connects through the OpenSSH client, it uses your `%USERPROFILE%\.ssh\config`. If you use a Claude account rather than a third-party provider, connecting through the OpenSSH client requires all of these:

1042 

1043 * Claude Desktop v2.2553.0 or later. To find your version, see [Check your version](#check-your-version).

1044 * Microsoft's OpenSSH 9.4 or later

1045 * Desktop installed with the download buttons at the top of this page, because Desktop from the Microsoft Store doesn't connect through the OpenSSH client

1046 

1047 If you can't meet these requirements, or you use a third-party provider, see [Connect on Windows without the OpenSSH client](#connect-on-windows-without-the-openssh-client).

1048 

1049With the OpenSSH client, enter a `Host` name from your configuration file in the **SSH host** field. Desktop then uses settings from that `Host` entry, such as `HostName`, `User`, `IdentityFile`, `CertificateFile`, `ProxyJump`, and `ProxyCommand`.

1034 1050 

1035Before you add the connection, check the client and the entry in a terminal on your computer:1051Before you add the connection, check the client and the entry in a terminal on your computer:

1036 1052 

1037* **Client version**: run `ssh -V`. The client has to be OpenSSH 7.6 or later.1053* **Client version on macOS and Linux**: run `ssh -V`. The client has to be OpenSSH 7.6 or later.

1038* **Entry**: run `ssh` with the `Host` name, such as `ssh devbox`. If that fails, fix the entry first.1054* **Client version on Windows**: Desktop tries the `ssh` on your `PATH` first, so run `ssh -V`. The client passes if the output shows `OpenSSH_for_Windows_` and 9.4 or later. If it doesn't pass, check the two folders that Desktop tries next: run `.\ssh.exe -V` in `C:\Windows\System32\OpenSSH`, then in `C:\Program Files\OpenSSH`.

1055* **No client passes on Windows**: add the **OpenSSH Client** optional feature in Windows and install pending Windows updates, or install [Microsoft's newer build](https://learn.microsoft.com/en-us/troubleshoot/windows-server/system-management-components/upgrade-in-box-openssh-to-latest-openssh-release). Then quit and reopen Desktop. To see whether Desktop found a usable OpenSSH client, look in [`ssh.log`](#get-desktops-logs-for-an-ssh-problem) for `Windows OpenSSH client:` and a version, or for `no usable Windows OpenSSH client`.

1056* **Entry**: on Windows, use the client that passed the version check. Run `ssh` with the `Host` name, such as `ssh devbox`. If that fails, fix the entry first.

1039 1057 

1040You can leave the **SSH port** and **SSH key (optional)** fields empty. If you fill one in, Desktop uses it with the entry:1058You can leave the **SSH port** and **SSH key (optional)** fields empty. If you fill one in, Desktop uses it with the entry:

1041 1059 

1042* **SSH port**: a value here overrides the entry's `Port`1060* **SSH port**: a value here overrides the entry's `Port`

1043* **SSH key (optional)**: Desktop offers the key file you pick in addition to the entry's `IdentityFile` and the keys in your SSH agent1061* **SSH key (optional)**: with the OpenSSH client, Desktop offers the key file you pick in addition to the entry's `IdentityFile` and the keys in your SSH agent. On Windows, pick a key in OpenSSH format, because `ssh` doesn't read a PuTTY `.ppk` file.

1062 

1063##### Connect on Windows without the OpenSSH client

1064 

1065On Windows, you connect through Desktop's built-in SSH client if your computer doesn't meet [the requirements for the OpenSSH client](#use-your-ssh-configuration). With a third-party provider, you connect through the built-in client by default, and your administrator can change that. For the setting, see [SSH remote sessions in Claude Desktop on 3P](https://claude.com/docs/third-party/claude-desktop/ssh-remote-sessions).

1066 

1067With the built-in client, you can still enter a `Host` name from your SSH configuration in the **SSH host** field if your `PATH` has an `ssh` command, with these limits:

1068 

1069* **Settings from the entry**: Desktop takes `HostName`, `User`, `Port`, and `IdentityFile`. It also takes `ProxyCommand` if an `sh` shell is on your `PATH`.

1070* **SSH key (optional)**: leave this field empty to keep the entry's `IdentityFile`, because a key file that you pick here replaces the `IdentityFile`

1071* **`CertificateFile` and `ProxyJump`**: Desktop ignores `CertificateFile`, and the connection fails if the entry sets `ProxyJump`. To use either setting, [connect through the OpenSSH client](#use-your-ssh-configuration).

1044 1072 

1045##### Reach a machine behind a jump host1073##### Reach a machine behind a jump host

1046 1074 


1095 1123 

1096##### Use variables from your shell in a `ProxyCommand`1124##### Use variables from your shell in a `ProxyCommand`

1097 1125 

1098To use an environment variable of your own in a `ProxyCommand` or `Match exec` command, export it in a shell startup file, such as `~/.zshrc`, then quit and reopen Desktop. When Desktop starts, it reads what your login shell exports, and it keeps those values until you quit.1126On macOS and Linux, to use an environment variable of your own in a `ProxyCommand` or `Match exec` command, export it in a shell startup file, such as `~/.zshrc`. Then quit and reopen Desktop. When Desktop starts, it reads what your login shell exports, and it keeps those values until you quit.

1099 1127 

1100This requires Claude Desktop v2.37337.0 or later and an `env` command that accepts `-0`, which you can check by running `env -0` in a terminal on your computer.1128This requires Claude Desktop v2.37337.0 or later and an `env` command that accepts `-0`, which you can check by running `env -0` in a terminal on your computer.

1101 1129 


1103>1131>

1104> If your shell sets temporary AWS credentials, [give the AWS CLI a profile](#use-aws-credentials-in-a-proxycommand) instead of exporting `AWS_*` variables.1132> If your shell sets temporary AWS credentials, [give the AWS CLI a profile](#use-aws-credentials-in-a-proxycommand) instead of exporting `AWS_*` variables.

1105 1133 

1106##### Use AWS credentials in a `ProxyCommand`1134##### Use AWS credentials in a `ProxyCommand` on macOS and Linux

1107 1135 

1108If you set temporary AWS credentials in a shell startup file, a `ProxyCommand` that runs the AWS CLI can connect in a terminal and fail in Desktop. When your shell exports `AWS_SESSION_TOKEN`, `AWS_SECURITY_TOKEN`, or `AWS_CREDENTIAL_EXPIRATION`, `ssh` and your `ProxyCommand` in Desktop don't get the shell's AWS credentials, `AWS_REGION`, or `AWS_PROFILE`.1136If you set temporary AWS credentials in a shell startup file, a `ProxyCommand` that runs the AWS CLI can connect in a terminal and fail in Desktop. When your shell exports `AWS_SESSION_TOKEN`, `AWS_SECURITY_TOKEN`, or `AWS_CREDENTIAL_EXPIRATION`, `ssh` and your `ProxyCommand` in Desktop don't get the shell's AWS credentials, `AWS_REGION`, or `AWS_PROFILE`.

1109 1137 


1242 1270 

1243##### Prepare a long task1271##### Prepare a long task

1244 1272 

1245* **Update first**: update Desktop before you start a long task. On macOS and Windows, Desktop can restart on its own to install an update that it has downloaded. That restart waits while Claude is working on an SSH task. On macOS with a Claude account, by default the restart can go ahead anyway once the update has waited 72 hours.1273* **Update first**: update Desktop before you start a long task. On macOS and Windows, Desktop can restart on its own to install an update that it has downloaded. That restart waits while Claude is working on an SSH task. By default, once the update has waited 72 hours, the restart can go ahead during the task if Desktop can [rejoin the task afterward](#reopen-a-session-after-you-quit-desktop).

1246* **Don't quit on Windows, or before v2.42304.0 with a third-party provider**: after a quit there you lose the running task, so leave Desktop open during the task. In any other case, see [what you get back](#reopen-a-session-after-you-quit-desktop) before you quit.1274* **Check before you quit**: you don't always get the running task back after a quit or restart, for example after some Desktop updates. For the cases, see [Reopen a session after you quit Desktop](#reopen-a-session-after-you-quit-desktop).

1275* **On an older version, leave Desktop open**: on Windows with Claude Desktop before v3.1623.0, you don't get the running task back after Desktop quits or restarts. The same is true with a third-party provider on macOS or Linux before v2.42304.0. In both cases, leave Desktop open during the task. To find your version, see [Check your version](#check-your-version).

1247* **Reduce requests**: choose a permission mode, rules, or hooks that [make the task wait for you less often](#handle-requests-that-arrive-while-you-are-away)1276* **Reduce requests**: choose a permission mode, rules, or hooks that [make the task wait for you less often](#handle-requests-that-arrive-while-you-are-away)

1248* **Check the jump host**: if your jump host asks for a sign-in, for example a push to a phone, switch to a login that works without a prompt. Otherwise Desktop can send another push each time it tries to reconnect.1277* **Check the jump host**: if your jump host asks for a sign-in, for example a push to a phone, switch to a login that works without a prompt. Otherwise Desktop can send another push each time it tries to reconnect.

1249* **Test the remote machine**: start a short task, quit Desktop while the task is still running, and open the session again well after the task should be done. If the task isn't finished and the session shows no authentication error, check the remote machine for [what can end a task](#limits-while-desktop-is-disconnected).1278* **Test the remote machine**: start a short task, quit Desktop while the task is still running, and open the session again well after the task should be done. If the task isn't finished and the session shows no authentication error, check the remote machine for [what can end a task](#limits-while-desktop-is-disconnected).


1320 1349 

1321After you quit Desktop, the task keeps running on the remote machine, but it stops when the session opens again unless Desktop can rejoin its process. While Desktop is closed, the task runs until it finishes, needs you, or reaches one of the [limits](#limits-while-desktop-is-disconnected).1350After you quit Desktop, the task keeps running on the remote machine, but it stops when the session opens again unless Desktop can rejoin its process. While Desktop is closed, the task runs until it finishes, needs you, or reaches one of the [limits](#limits-while-desktop-is-disconnected).

1322 1351 

1323* **Desktop on Windows**: you don't get the running task back, because Desktop never rejoins after a quit. Start Desktop again only when you expect the task to be done, because the session can open as Desktop starts.1352* **Desktop on Windows, task started in a version before v3.1623.0**: you don't get the task back, even if Desktop has updated since. Start Desktop again only when you expect the task to be done, because the session can open as Desktop starts, and the task stops when the session opens. If you don't know which version you started the task in, also wait until you expect it to be done.

1324* **Third-party provider, task from an earlier version**: if you started the task in a Desktop version before v2.42304.0, you don't get it back on macOS or Linux either. Start Desktop again only when you expect the task to be done.1353* **Third-party provider on macOS or Linux, task started in a version before v2.42304.0**: you don't get the task back. Start Desktop again only when you expect the task to be done.

1325* **Any other task, with Desktop on macOS or Linux**: start Desktop and open the session, and the task goes on if Desktop rejoins. It can't always rejoin, for example after some Desktop updates, so [update before a long task](#prepare-a-long-task).1354* **Any other task**: start Desktop and open the session, and the task goes on if Desktop rejoins. It can't always rejoin, for example after some Desktop updates, so [update before a long task](#prepare-a-long-task).

1326 1355 

1327When Desktop can't rejoin, you also lose any approval or question that was waiting for you. If the task doesn't continue on its own, send a message, and Claude continues from the conversation's saved history.1356When the task stops, the session can show `Restarting Claude Code on <host>…` while Desktop starts a new process. You also lose any approval or question that was waiting for you. If Claude doesn't continue on its own, send a message, and Claude continues from the conversation's saved history.

1328 1357 

1329For third-party deployments, see [SSH remote sessions in Claude Desktop on 3P](https://claude.com/docs/third-party/claude-desktop/ssh-remote-sessions).1358For third-party deployments, see [SSH remote sessions in Claude Desktop on 3P](https://claude.com/docs/third-party/claude-desktop/ssh-remote-sessions).

1330 1359 


1411 1440 

1412To find out who connected to a remote machine, read the SSH server's log on that machine, where a login from Desktop looks like one from a terminal. With Desktop on macOS or Linux, expect an entry each time Desktop connects, not one for each session.1441To find out who connected to a remote machine, read the SSH server's log on that machine, where a login from Desktop looks like one from a terminal. With Desktop on macOS or Linux, expect an entry each time Desktop connects, not one for each session.

1413 1442 

1443If the server sets `MaxSessions 1`, expect at least two entries each time Desktop connects or reconnects. Expect at least one more for each terminal tab, and for each Desktop session in which you run commands that start with `!`.

1444 

1414You won't find Desktop's SSH connections in Claude Code's [metrics and events](https://code.claude.com/docs/en/monitoring-usage.md#available-metrics-and-events). To find out from them which remote machine an SSH session ran on, see [Attribute telemetry to Desktop SSH sessions](https://code.claude.com/docs/en/monitoring-usage.md#attribute-telemetry-to-desktop-ssh-sessions). For Desktop's own record of its connections, see [Get Desktop's logs for an SSH problem](#get-desktops-logs-for-an-ssh-problem).1445You won't find Desktop's SSH connections in Claude Code's [metrics and events](https://code.claude.com/docs/en/monitoring-usage.md#available-metrics-and-events). To find out from them which remote machine an SSH session ran on, see [Attribute telemetry to Desktop SSH sessions](https://code.claude.com/docs/en/monitoring-usage.md#attribute-telemetry-to-desktop-ssh-sessions). For Desktop's own record of its connections, see [Get Desktop's logs for an SSH problem](#get-desktops-logs-for-an-ssh-problem).

1415 1446 

1416#### Connections that close before login1447#### Connections that close before login


2112| - | - | - |2143| - | - | - |

2113| `<host>'s SSH server has SFTP turned off` | `[SFTP_UNAVAILABLE]` | Turn on SFTP in the server's `sshd_config`, as described under [remote machine requirements](#remote-machine-requirements-for-ssh-sessions) |2144| `<host>'s SSH server has SFTP turned off` | `[SFTP_UNAVAILABLE]` | Turn on SFTP in the server's `sshd_config`, as described under [remote machine requirements](#remote-machine-requirements-for-ssh-sessions) |

2114| `SFTP doesn't start on <host>` | `[SFTP_NOT_STARTED]` | Connect to the same host with `sftp` in a terminal on your computer to see what stops it, then check the settings and files that Desktop's message names |2145| `SFTP doesn't start on <host>` | `[SFTP_NOT_STARTED]` | Connect to the same host with `sftp` in a terminal on your computer to see what stops it, then check the settings and files that Desktop's message names |

2115| `<host> allows too few SSH sessions per connection` | `[SESSION_LIMIT]` | Raise `MaxSessions` in the server's `sshd_config`, for example to OpenSSH's default of 10 |2146| `<host> allows too few SSH sessions per connection` | `[SESSION_LIMIT]` | Update to Claude Desktop v3.1623.0 or later, or raise `MaxSessions` in the server's `sshd_config`, for example to OpenSSH's default of 10 |

2116| `<host> is out of disk space` | `[ENOSPC]` or `[EDQUOT]` | Free space or quota on the remote machine, in your home directory or `/tmp` |2147| `<host> is out of disk space` | `[ENOSPC]` or `[EDQUOT]` | Free space or quota on the remote machine, in your home directory or `/tmp` |

2117| `Free up disk space on this computer` | `[ENOSPC]` or `[EDQUOT]`, in a message that starts with `Couldn't prepare the deploy locally` | Free space on your computer |2148| `Free up disk space on this computer` | `[ENOSPC]` or `[EDQUOT]`, in a message that starts with `Couldn't prepare the deploy locally` | Free space on your computer |

2118| `Claude Code won't start on <host>` | `[CLI_UNRESPONSIVE]` | Wait a minute, then try again. If it keeps failing, run the command that the message names on the remote machine to see whether Claude Code answers there. |2149| `Claude Code won't start on <host>` | `[CLI_UNRESPONSIVE]` | Wait a minute, then try again. If it keeps failing, run the command that the message names on the remote machine to see whether Claude Code answers there. |

errors.md +2 −0

Details

327| `Cannot read this as an image: <path> is a pipe or a device` | [Tool errors](#file-is-too-large-to-read-as-an-image) |327| `Cannot read this as an image: <path> is a pipe or a device` | [Tool errors](#file-is-too-large-to-read-as-an-image) |

328| `subagent_type is required: the general-purpose agent is not available in this session` | [Tool errors](#subagent-type-is-required) |328| `subagent_type is required: the general-purpose agent is not available in this session` | [Tool errors](#subagent-type-is-required) |

329| `Error: this write left the memory index at MEMORY.md at ..., over its ... read limit` | [Tool errors](#memory-index-is-over-its-read-limit) |329| `Error: this write left the memory index at MEMORY.md at ..., over its ... read limit` | [Tool errors](#memory-index-is-over-its-read-limit) |

330| `Sandbox is required but failed to initialize: <reason>` | [Sandboxing troubleshooting](https://code.claude.com/docs/en/sandboxing.md#commands-refused-with-sandbox-is-required) |

331| `Sandbox is required (sandbox.failIfUnavailable) and stopped being available in this session: <reason>` | [Sandboxing troubleshooting](https://code.claude.com/docs/en/sandboxing.md#commands-refused-with-sandbox-is-required) |

330| `pkill: refusing to run` | [Tool errors](#pkill-pattern-matches-the-claude-code-process) |332| `pkill: refusing to run` | [Tool errors](#pkill-pattern-matches-the-claude-code-process) |

331| `Failed to write to <name>'s inbox — nothing was sent` | [Tool errors](#failed-to-write-to-a-teammate-inbox) |333| `Failed to write to <name>'s inbox — nothing was sent` | [Tool errors](#failed-to-write-to-a-teammate-inbox) |

332| `Failed to write the plan approval request to the lead's inbox — plan not submitted` | [Tool errors](#failed-to-write-to-a-teammate-inbox) |334| `Failed to write the plan approval request to the lead's inbox — plan not submitted` | [Tool errors](#failed-to-write-to-a-teammate-inbox) |

fast-mode.md +2 −2

Details

80 80 

81Fast mode pricing is flat across the full 1M token context window. For the standard Opus rate to compare against, see the [Claude pricing reference](https://platform.claude.com/docs/en/about-claude/pricing).81Fast mode pricing is flat across the full 1M token context window. For the standard Opus rate to compare against, see the [Claude pricing reference](https://platform.claude.com/docs/en/about-claude/pricing).

82 82 

83The first time you enable fast mode in a conversation, you pay the full fast mode uncached input token price for the entire conversation context. The deeper into a conversation you are, the more this costs, so the charge is smallest when you enable fast mode at the start. The cost applies once per conversation, so toggling fast mode off and on again later doesn't repeat it. For the mechanism, see [how fast mode interacts with the prompt cache](https://code.claude.com/docs/en/prompt-caching.md#turning-on-fast-mode).83The first time you enable fast mode in a conversation, you pay the full fast mode uncached input token price for the entire conversation context. The deeper into a conversation you are, the more this costs, so the charge is smallest when you enable fast mode at the start. Fast mode and standard speed keep [separate caches](https://code.claude.com/docs/en/prompt-caching.md#turning-on-fast-mode), so each later switch reads part or all of the conversation uncached again.

84 84 

85### See where fast mode spend appears85### See where fast mode spend appears

86 86 


167 167 

168Behind a gateway, check for these configurations, in which Claude Code doesn't send the availability check and has no earlier successful check cached:168Behind a gateway, check for these configurations, in which Claude Code doesn't send the availability check and has no earlier successful check cached:

169 169 

170* You point `ANTHROPIC_BASE_URL` at your gateway and set [`ANTHROPIC_API_KEY`](https://code.claude.com/docs/en/llm-gateway-connect#set-the-base-url-and-credential) to a gateway-issued key that isn't in the format of an Anthropic API key. Claude Code withholds such a key from `api.anthropic.com`.170* You point `ANTHROPIC_BASE_URL` at your gateway and set [`ANTHROPIC_API_KEY`](https://code.claude.com/docs/en/llm-gateway-connect#set-the-base-url-and-credential) to a gateway-issued key that isn't in the format of an Anthropic API key.

171* You set [`CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC`](https://code.claude.com/docs/en/env-vars), so Claude Code skips the check.171* You set [`CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC`](https://code.claude.com/docs/en/env-vars), so Claude Code skips the check.

172 172 

173To restore fast mode in either configuration, set `CLAUDE_CODE_SKIP_FAST_MODE_NETWORK_ERRORS=1`.173To restore fast mode in either configuration, set `CLAUDE_CODE_SKIP_FAST_MODE_NETWORK_ERRORS=1`.

Details

262 262 

263**Context cost:** Low until used. User-only skills have zero cost until invoked.263**Context cost:** Low until used. User-only skills have zero cost until invoked.

264 264 

265**In subagents:** Skills work differently in subagents. Instead of on-demand loading, skills listed in the subagent's `skills` field are fully preloaded into its context at launch. Subagents can still discover and invoke unlisted project, user, and plugin skills through the Skill tool.265**In subagents:** The full content of skills listed in a subagent's `skills` field [loads into its context at launch](https://code.claude.com/docs/en/sub-agents.md#preload-skills-into-subagents), rather than on demand. Subagents can still discover and invoke unlisted project, user, and plugin skills through the Skill tool.

266 266 

267> [!TIP]267> [!TIP]

268>268>

glossary.md +2 −2

Details

120 120 

121### Compaction121### Compaction

122 122 

123Automatic summarization of your conversation when the [context window](#context-window) approaches its limit. Older tool outputs are cleared first, then the conversation is summarized. Project-root CLAUDE.md and auto memory survive compaction and reload from disk; instructions given only in conversation may be lost. Run `/compact` to trigger manually, optionally with a focus like `/compact focus on the API changes`.123Automatic summarization of your conversation when the [context window](#context-window) approaches its limit. Project-root CLAUDE.md and auto memory survive compaction, but instructions given only in conversation may not. Run `/compact` to trigger manually, optionally with a focus like `/compact focus on the API changes`.

124 124 

125Learn more: [What survives compaction](https://code.claude.com/docs/en/context-window.md#what-survives-compaction) · [When context fills up](https://code.claude.com/docs/en/how-claude-code-works.md#when-context-fills-up)125Learn more: [What survives compaction](https://code.claude.com/docs/en/context-window.md#what-survives-compaction) · [When context fills up](https://code.claude.com/docs/en/how-claude-code-works.md#when-context-fills-up) · [When Claude Code compacts a conversation you leave idle](https://code.claude.com/docs/en/settings-reference.md#idlecompaction)

126 126 

127### Connector127### Connector

128 128 

hooks.md +15 −5

Details

1426 1426 

1427Setup hooks can't block; execution continues on any exit code. On every exit code, Claude Code discards a Setup hook's [JSON output fields](#json-output), such as `systemMessage`, `continue`, and `hookSpecificOutput.additionalContext`. With `-p`, a Setup hook's stdout, stderr, and exit code appear in the run's output only as [`hook_response` events](https://code.claude.com/docs/en/headless#read-session-metadata) when you launch with `--output-format stream-json --verbose`.1427Setup hooks can't block; execution continues on any exit code. On every exit code, Claude Code discards a Setup hook's [JSON output fields](#json-output), such as `systemMessage`, `continue`, and `hookSpecificOutput.additionalContext`. With `-p`, a Setup hook's stdout, stderr, and exit code appear in the run's output only as [`hook_response` events](https://code.claude.com/docs/en/headless#read-session-metadata) when you launch with `--output-format stream-json --verbose`.

1428 1428 

1429Setup hooks have access to `CLAUDE_ENV_FILE`. Variables written to that file persist into subsequent Bash commands for the session, as in [SessionStart hooks](#persist-environment-variables). Only `type: "command"` hooks run on `Setup`. A `type: "mcp_tool"` hook on `Setup` is always skipped, as described under [MCP tool hook fields](#mcp-tool-hook-fields).1429Setup hooks have access to `CLAUDE_ENV_FILE`. If your hook writes variables to that file, they persist into subsequent Bash commands for the session, as in [SessionStart hooks](#persist-environment-variables). Only `type: "command"` hooks run on `Setup`. A `type: "mcp_tool"` hook on `Setup` is always skipped, as described under [MCP tool hook fields](#mcp-tool-hook-fields).

1430 1430 

1431### InstructionsLoaded1431### InstructionsLoaded

1432 1432 


1483 1483 

1484An [Agent SDK callback hook](https://code.claude.com/docs/en/agent-sdk/hooks.md) on `UserPromptSubmit` that reaches its timeout blocks the prompt with a message naming the hook and the timeout, because a callback there can be acting as a policy gate that must not fail open. The session continues.1484An [Agent SDK callback hook](https://code.claude.com/docs/en/agent-sdk/hooks.md) on `UserPromptSubmit` that reaches its timeout blocks the prompt with a message naming the hook and the timeout, because a callback there can be acting as a policy gate that must not fail open. The session continues.

1485 1485 

1486#### `Esc` during a prompt check

1487 

1488If you press `Esc` or interrupt the session while hooks are still checking a prompt, the check stops and the prompt doesn't reach Claude. Text you typed at the terminal returns to the prompt input, and the hooks check it again when you resend it.

1489 

1490A hook can block the prompt at the same moment you interrupt. The prompt then stays blocked: you see that hook's [block message](#what-a-blocked-prompt-leaves-behind), and the text doesn't return to the input.

1491 

1486#### UserPromptSubmit input1492#### UserPromptSubmit input

1487 1493 

1488In addition to the [common input fields](#common-input-fields), UserPromptSubmit hooks receive the `prompt` field containing the submitted text. Pasted content that collapsed to a `[Pasted text #N]` placeholder arrives expanded in place. In sessions where Claude Code [marks pasted text for Claude](https://code.claude.com/docs/en/terminal-config.md#how-claude-treats-pasted-text), that expanded content sits between a `<pasted_content id="…">` line and a `</pasted_content id="…">` line, so account for those lines if your hook parses the prompt.1494In addition to the [common input fields](#common-input-fields), UserPromptSubmit hooks receive the `prompt` field containing the submitted text. Pasted content that collapsed to a `[Pasted text #N]` placeholder arrives expanded in place. In sessions where Claude Code [marks pasted text for Claude](https://code.claude.com/docs/en/terminal-config.md#how-claude-treats-pasted-text), that expanded content sits between a `<pasted_content id="…">` line and a `</pasted_content id="…">` line, so account for those lines if your hook parses the prompt.


1741 1747 

1742Use [PreToolUse decision control](#pretooluse-decision-control) to allow, deny, ask, or defer the tool call.1748Use [PreToolUse decision control](#pretooluse-decision-control) to allow, deny, ask, or defer the tool call.

1743 1749 

1744An [Agent SDK callback hook](https://code.claude.com/docs/en/agent-sdk/hooks.md) on `PreToolUse` that exceeds its timeout blocks the tool call, and Claude receives an error result naming the timeout.1750An [Agent SDK callback hook](https://code.claude.com/docs/en/agent-sdk/hooks.md#hook-timeout) on `PreToolUse` that exceeds its timeout blocks the tool call.

1745 1751 

1746#### PreToolUse input1752#### PreToolUse input

1747 1753 


2970 2976 

2971Runs when a shell command in the main conversation changes the working directory, for example when Claude executes a `cd` command. Use this to react to directory changes: reload environment variables, activate project-specific toolchains, or run setup scripts automatically. Pairs with [FileChanged](#filechanged) for tools like [direnv](https://direnv.net/) that manage per-directory environment.2977Runs when a shell command in the main conversation changes the working directory, for example when Claude executes a `cd` command. Use this to react to directory changes: reload environment variables, activate project-specific toolchains, or run setup scripts automatically. Pairs with [FileChanged](#filechanged) for tools like [direnv](https://direnv.net/) that manage per-directory environment.

2972 2978 

2973CwdChanged hooks have access to [`CLAUDE_ENV_FILE`](#persist-environment-variables). Variables written to that file persist into subsequent Bash commands until the next CwdChanged event, when Claude Code clears them.2979CwdChanged hooks have access to [`CLAUDE_ENV_FILE`](#persist-environment-variables). If your hook writes variables to that file, they persist into subsequent Bash commands until the next CwdChanged event, when Claude Code clears them.

2974 2980 

2975CwdChanged doesn't support matchers and fires on every occurrence.2981CwdChanged doesn't support matchers and fires on every occurrence.

2976 2982 


3135* Claude Code isolates a [background session](https://code.claude.com/docs/en/agent-view.md#how-file-edits-are-isolated) in its own worktree3141* Claude Code isolates a [background session](https://code.claude.com/docs/en/agent-view.md#how-file-edits-are-isolated) in its own worktree

3136* [`claude remote-control`](https://code.claude.com/docs/en/remote-control#start-a-remote-control-session) in `worktree` mode starts a session in its own worktree3142* [`claude remote-control`](https://code.claude.com/docs/en/remote-control#start-a-remote-control-session) in `worktree` mode starts a session in its own worktree

3137 3143 

3138When Claude runs `git worktree add` through the Bash tool rather than calling `EnterWorktree`, your WorktreeCreate hook doesn't run. To inspect or block that command, add a [`PreToolUse`](#pretooluse) hook with the `Bash` matcher.3144A WorktreeCreate hook doesn't run for a worktree Claude adds through Bash, and a plugin's hook doesn't run for the one created when you launch with `--worktree` and [`--tmux`](https://code.claude.com/docs/en/cli-reference#cli-flags):

3145 

3146* **`git worktree add` through Bash**: to inspect or block that command, add a [`PreToolUse`](#pretooluse) hook with the `Bash` matcher.

3147* **`--worktree` with `--tmux`**: Claude Code creates the worktree before it loads plugins, so a WorktreeCreate hook from a plugin doesn't run. To have your hook run with both flags, define it in a [settings file](#configuration) instead. Before v2.1.300, a plugin's WorktreeCreate hook didn't run with `--worktree` alone either.

3139 3148 

3140By default Claude Code creates the isolated working copy with `git worktree`. Configuring a WorktreeCreate hook replaces that default git behavior, letting you use a different version control system like SVN, Perforce, or Mercurial.3149By default Claude Code creates the isolated working copy with `git worktree`. Configuring a WorktreeCreate hook replaces that default git behavior, letting you use a different version control system like SVN, Perforce, or Mercurial.

3141 3150 


4077 4086 

4078When an async hook fires, Claude Code starts the hook process and immediately continues without waiting for it to finish. The hook receives the same JSON input via stdin as a synchronous hook.4087When an async hook fires, Claude Code starts the hook process and immediately continues without waiting for it to finish. The hook receives the same JSON input via stdin as a synchronous hook.

4079 4088 

4080After the background process exits, Claude Code delivers the `additionalContext` and `systemMessage` fields from the hook's JSON response to Claude on the next conversation turn. Unlike a synchronous hook's `systemMessage`, neither field is shown to you.4089After the background process exits, Claude Code delivers the `additionalContext` and `systemMessage` fields from the hook's JSON response to Claude on the next conversation turn, except for [repeated `SessionStart` output](#limitations). Unlike a synchronous hook's `systemMessage`, neither field is shown to you.

4081 4090 

4082Print the JSON response alone on stdout or on one line of its own:4091Print the JSON response alone on stdout or on one line of its own:

4083 4092 


4145 4154 

4146* Hook output is delivered on the next conversation turn. If the session is idle, the response waits until the next user interaction. Exception: an `asyncRewake` hook that exits with code 2 wakes Claude immediately even when the session is idle.4155* Hook output is delivered on the next conversation turn. If the session is idle, the response waits until the next user interaction. Exception: an `asyncRewake` hook that exits with code 2 wakes Claude immediately even when the session is idle.

4147* Each execution creates a separate background process.4156* Each execution creates a separate background process.

4157* An async `SessionStart` hook runs every time the event fires. Claude Code skips the hook's output when the `additionalContext` and `systemMessage` text matches what Claude last received from that hook, unless a synchronous `SessionStart` hook has added other text since. Claude Code delivers the text when it changes, and again the next time the hook runs after a compaction or `/clear`. Before v2.1.295, Claude Code added the same text to the conversation again on every resume.

4148 4158 

4149## Security considerations4159## Security considerations

4150 4160 

hooks-guide.md +1 −1

Details

954* `PostToolUse` hooks can't undo actions since the tool has already executed.954* `PostToolUse` hooks can't undo actions since the tool has already executed.

955* [`PermissionRequest`](https://code.claude.com/docs/en/hooks#permissionrequest) hooks fire when Claude Code is about to ask you for permission, or when it would otherwise auto-deny a call that can't prompt. In [non-interactive mode](https://code.claude.com/docs/en/headless.md) with the `-p` flag, they still run outside [`dontAsk` mode](https://code.claude.com/docs/en/permission-modes#allow-only-pre-approved-tools-with-dontask-mode), and a call that no hook decides and nothing else can answer is denied.955* [`PermissionRequest`](https://code.claude.com/docs/en/hooks#permissionrequest) hooks fire when Claude Code is about to ask you for permission, or when it would otherwise auto-deny a call that can't prompt. In [non-interactive mode](https://code.claude.com/docs/en/headless.md) with the `-p` flag, they still run outside [`dontAsk` mode](https://code.claude.com/docs/en/permission-modes#allow-only-pre-approved-tools-with-dontask-mode), and a call that no hook decides and nothing else can answer is denied.

956* `Stop` hooks fire whenever Claude finishes responding, not only at task completion. They don't fire on user interrupts. API errors fire [StopFailure](https://code.claude.com/docs/en/hooks.md#stopfailure) instead.956* `Stop` hooks fire whenever Claude finishes responding, not only at task completion. They don't fire on user interrupts. API errors fire [StopFailure](https://code.claude.com/docs/en/hooks.md#stopfailure) instead.

957* When multiple `PreToolUse` hooks return [`updatedInput`](https://code.claude.com/docs/en/hooks#pretooluse) to rewrite a tool's arguments, the last one to finish takes effect. Since hooks run in parallel, the order is non-deterministic. Avoid having more than one hook modify the same tool's input.957* When multiple `PreToolUse` hooks return [`updatedInput`](https://code.claude.com/docs/en/hooks#pretooluse) to rewrite a tool's input, Claude Code doesn't merge the rewrites or guarantee which rewrite the tool runs with. Avoid having more than one hook rewrite the same tool's input.

958 958 

959### Hooks and permission modes959### Hooks and permission modes

960 960 

Details

131 131 

132#### When context fills up132#### When context fills up

133 133 

134Claude Code manages context automatically as you approach the limit. It clears older tool outputs first, then summarizes the conversation if needed. Your requests and key code snippets are preserved; detailed instructions from early in the conversation may be lost. Put persistent rules in CLAUDE.md rather than relying on conversation history.134Claude Code manages context automatically as you approach the limit. It compacts the conversation into a summary. The summary keeps your requests and key code snippets, but detailed instructions from early in the conversation may be lost. Put persistent rules in CLAUDE.md rather than relying on conversation history.

135 135 

136To control what's preserved during compaction, add a "Compact Instructions" section to CLAUDE.md or run `/compact` with a focus (like `/compact focus on the API changes`).136To control what's preserved during compaction, add a "Compact Instructions" section to CLAUDE.md or run `/compact` with a focus (like `/compact focus on the API changes`).

137 137 

Details

659 659 

660To rebind the keys that scroll the file list or change the comparison, see [Diff panel actions](https://code.claude.com/docs/en/keybindings.md#diff-panel-actions).660To rebind the keys that scroll the file list or change the comparison, see [Diff panel actions](https://code.claude.com/docs/en/keybindings.md#diff-panel-actions).

661 661 

662During an unfinished merge, rebase, cherry-pick, or revert, the panel keeps showing the changes it last read from git, so it doesn't fill with the operation's incoming changes. It updates at its first refresh after the operation ends, for example when Claude next edits a file.

663 

662### Diff dialog664### Diff dialog

663 665 

664The diff dialog opens as a bordered block above the prompt and lists your changed files with their added and removed line counts. It compares them against `HEAD`, or against whatever you last [chose in the diff panel](#diff-panel) for this repository.666The diff dialog opens as a bordered block above the prompt and lists your changed files with their added and removed line counts. It compares them against `HEAD`, or against whatever you last [chose in the diff panel](#diff-panel) for this repository.

keybindings.md +4 −4

Details

678 678 

679## Vim mode interaction679## Vim mode interaction

680 680 

681When vim mode is enabled via `/config` → Editor mode, keybindings and vim mode operate independently:681When you enable vim mode with the Editor mode setting in `/config`, keybindings and vim mode operate independently:

682 682 

683* **Vim mode** handles input at the text input level (cursor movement, modes, motions)683* **Vim mode** handles input at the text input level: cursor movement, modes, and motions

684* **Keybindings** handle actions at the component level (toggle todos, submit, etc.)684* **Keybindings** handle actions at the component level, such as toggling todos or submitting a message

685* The Escape key in vim mode switches INSERT to NORMAL mode; it does not trigger `chat:cancel`685* The Escape key in vim mode switches INSERT to NORMAL mode; it doesn't trigger `chat:cancel`

686* Most Ctrl+key shortcuts pass through vim mode to the keybinding system686* Most Ctrl+key shortcuts pass through vim mode to the keybinding system

687* Vim keys aren't remappable through the keybindings file. To map a two-key INSERT-mode sequence such as `jj` to Escape, use the [`vimInsertModeRemaps`](https://code.claude.com/docs/en/interactive-mode#remap-insert-mode-key-sequences) setting687* Vim keys aren't remappable through the keybindings file. To map a two-key INSERT-mode sequence such as `jj` to Escape, use the [`vimInsertModeRemaps`](https://code.claude.com/docs/en/interactive-mode#remap-insert-mode-key-sequences) setting

688* In vim NORMAL mode, `?` shows the help menu (vim behavior)688* In vim NORMAL mode, `?` shows the help menu (vim behavior)

Details

306 306 

307## Add per-directory skills307## Add per-directory skills

308 308 

309Any subdirectory can define [skills](https://code.claude.com/docs/en/skills.md) scoped to its own stack. A skill loads on demand when Claude determines it's relevant, so API-specific tooling doesn't consume context during frontend work.309Any subdirectory can define [skills](https://code.claude.com/docs/en/skills.md) scoped to its own stack. A skill loads on demand when Claude determines it's relevant.

310 310 

311Skills live under `.claude/skills/` inside the directory. Commit them alongside that area's code so anyone who clones the repository gets them. In a monorepo this can be one set of skills per package. In a large single-tree codebase it's one set per subsystem such as `src/db/.claude/skills/`.311Skills live under `.claude/skills/` inside the directory. Commit them alongside that area's code so anyone who clones the repository gets them. In a monorepo this can be one set of skills per package. In a large single-tree codebase it's one set per subsystem such as `src/db/.claude/skills/`.

312 312 


347- Mock external services in `src/__tests__/mocks/`347- Mock external services in `src/__tests__/mocks/`

348```348```

349 349 

350A different subdirectory holds different skills the same way: `packages/web/.claude/skills/component-patterns/` describes the frontend's component conventions instead of testing. When Claude works on a file in `packages/api/`, it loads the api-testing skill. When it works in `packages/web/`, it loads component-patterns instead. Neither directory's skills load during the other's tasks.350A different subdirectory holds different skills the same way: `packages/web/.claude/skills/component-patterns/` describes the frontend's component conventions instead of testing. When Claude works on a file in `packages/api/`, it loads the api-testing skill. When it works in `packages/web/`, it loads component-patterns.

351 351 

352You can also scope a skill by file pattern instead of by placement. The [`paths` frontmatter field](https://code.claude.com/docs/en/skills#frontmatter-reference) takes glob patterns, and Claude loads the skill automatically only when it works with matching files. Use this for a skill that lives in the repository root's `.claude/skills/` but applies only to certain files, such as a database-migration skill scoped to `**/migrations/**`.352You can also scope a skill by file pattern instead of by placement. The [`paths` frontmatter field](https://code.claude.com/docs/en/skills#frontmatter-reference) takes glob patterns, and Claude loads the skill automatically only when it works with matching files. Use this for a skill that lives in the repository root's `.claude/skills/` but applies only to certain files, such as a database-migration skill scoped to `**/migrations/**`.

353 353 

Details

520| `400` errors on every request, in the gateway's own words rejecting an unrecognized tool type, such as `Input tag 'advisor_20260301'`, on Claude Code v2.1.275 | In a gradual rollout on that version, requests carry an [advisor tool](https://code.claude.com/docs/en/advisor.md) entry even with the advisor off. The Anthropic API accepts it, but a gateway or upstream that validates tool types rejects the whole request; one that [forwards request body fields unchanged](https://code.claude.com/docs/en/llm-gateway-protocol.md#forward-as-open-lists) passes it through unaffected. The entry is a declaration that carries no conversation content | Update to v2.1.276 or later, which doesn't send the entry behind an `ANTHROPIC_BASE_URL` gateway unless you turn the advisor on. On v2.1.275, set [`CLAUDE_CODE_DISABLE_ADVISOR_TOOL=1`](https://code.claude.com/docs/en/env-vars), which removes the entry from requests |520| `400` errors on every request, in the gateway's own words rejecting an unrecognized tool type, such as `Input tag 'advisor_20260301'`, on Claude Code v2.1.275 | In a gradual rollout on that version, requests carry an [advisor tool](https://code.claude.com/docs/en/advisor.md) entry even with the advisor off. The Anthropic API accepts it, but a gateway or upstream that validates tool types rejects the whole request; one that [forwards request body fields unchanged](https://code.claude.com/docs/en/llm-gateway-protocol.md#forward-as-open-lists) passes it through unaffected. The entry is a declaration that carries no conversation content | Update to v2.1.276 or later, which doesn't send the entry behind an `ANTHROPIC_BASE_URL` gateway unless you turn the advisor on. On v2.1.275, set [`CLAUDE_CODE_DISABLE_ADVISOR_TOOL=1`](https://code.claude.com/docs/en/env-vars), which removes the entry from requests |

521| Models missing from the `/model` picker | Gateway model names aren't in Claude Code's built-in list, or Claude Code is showing a [`modelPicker`](https://code.claude.com/docs/en/settings-reference#modelpicker) lineup that replaces the built-in options | Enable [gateway model discovery](#add-gateway-models-to-the-model-picker) or add names with the [model configuration](https://code.claude.com/docs/en/model-config.md) variables. If Claude Code shows a replacing `modelPicker` lineup, add the gateway models to it, or ask your administrator to add them when managed settings supply it |521| Models missing from the `/model` picker | Gateway model names aren't in Claude Code's built-in list, or Claude Code is showing a [`modelPicker`](https://code.claude.com/docs/en/settings-reference#modelpicker) lineup that replaces the built-in options | Enable [gateway model discovery](#add-gateway-models-to-the-model-picker) or add names with the [model configuration](https://code.claude.com/docs/en/model-config.md) variables. If Claude Code shows a replacing `modelPicker` lineup, add the gateway models to it, or ask your administrator to add them when managed settings supply it |

522| `/fast` reports `Fast mode unavailable due to network connectivity issues` while inference requests work | The [fast mode](https://code.claude.com/docs/en/fast-mode.md) availability check goes directly to `api.anthropic.com` and doesn't follow `ANTHROPIC_BASE_URL`, so blocked direct egress fails the check | Allowlist `api.anthropic.com` if egress is blocked, or set a skip variable. See [use fast mode behind proxies and LLM gateways](https://code.claude.com/docs/en/fast-mode.md#use-fast-mode-behind-proxies-and-llm-gateways) |522| `/fast` reports `Fast mode unavailable due to network connectivity issues` while inference requests work | The [fast mode](https://code.claude.com/docs/en/fast-mode.md) availability check goes directly to `api.anthropic.com` and doesn't follow `ANTHROPIC_BASE_URL`, so blocked direct egress fails the check | Allowlist `api.anthropic.com` if egress is blocked, or set a skip variable. See [use fast mode behind proxies and LLM gateways](https://code.claude.com/docs/en/fast-mode.md#use-fast-mode-behind-proxies-and-llm-gateways) |

523| `/fast` reports `Fast mode is currently unavailable` in a session that authenticates with a gateway-issued key in `ANTHROPIC_API_KEY` | While `ANTHROPIC_BASE_URL` points at your gateway, Claude Code withholds from `api.anthropic.com` a key that isn't in the format of an Anthropic API key. The [fast mode](https://code.claude.com/docs/en/fast-mode.md) availability check then isn't sent, and without an earlier successful check cached, Claude Code treats fast mode as unavailable | Set `CLAUDE_CODE_SKIP_FAST_MODE_NETWORK_ERRORS=1`; see [use fast mode behind proxies and LLM gateways](https://code.claude.com/docs/en/fast-mode.md#use-fast-mode-behind-proxies-and-llm-gateways) |523| `/fast` reports `Fast mode is currently unavailable` in a session that authenticates with a gateway-issued key in `ANTHROPIC_API_KEY` | While `ANTHROPIC_BASE_URL` points at your gateway and the key isn't in the format of an Anthropic API key, Claude Code doesn't send the [fast mode](https://code.claude.com/docs/en/fast-mode.md) availability check. Without an earlier successful check cached, it treats fast mode as unavailable | Set `CLAUDE_CODE_SKIP_FAST_MODE_NETWORK_ERRORS=1`; see [use fast mode behind proxies and LLM gateways](https://code.claude.com/docs/en/fast-mode.md#use-fast-mode-behind-proxies-and-llm-gateways) |

524| `/fast` reports `Fast mode has been disabled by your organization` in a session authenticated with `ANTHROPIC_AUTH_TOKEN`, even though the organization has fast mode enabled | The availability check requires a claude.ai login or an API key; with only a bearer token, Claude Code treats fast mode as disabled without sending the check | Set `CLAUDE_CODE_SKIP_FAST_MODE_ORG_CHECK=1`; see [use fast mode behind proxies and LLM gateways](https://code.claude.com/docs/en/fast-mode.md#use-fast-mode-behind-proxies-and-llm-gateways) |524| `/fast` reports `Fast mode has been disabled by your organization` in a session authenticated with `ANTHROPIC_AUTH_TOKEN`, even though the organization has fast mode enabled | The availability check requires a claude.ai login or an API key; with only a bearer token, Claude Code treats fast mode as disabled without sending the check | Set `CLAUDE_CODE_SKIP_FAST_MODE_ORG_CHECK=1`; see [use fast mode behind proxies and LLM gateways](https://code.claude.com/docs/en/fast-mode.md#use-fast-mode-behind-proxies-and-llm-gateways) |

525| Claude Code asks you to log in even though the [curl test](#verify-the-connection) succeeds | The CLI has no credential of its own: a reachable base URL isn't one, and in an interactive session an `env` block in a project's `.claude/settings.json` or `.claude/settings.local.json` applies only after the first-run wizard and [trust prompt](https://code.claude.com/docs/en/permissions.md#what-runs-before-you-trust-a-folder) | Set `ANTHROPIC_AUTH_TOKEN` somewhere Claude Code reads before first-run setup: a shell export, the `env` block in `~/.claude/settings.json`, or managed settings |525| Claude Code asks you to log in even though the [curl test](#verify-the-connection) succeeds | The CLI has no credential of its own: a reachable base URL isn't one, and in an interactive session an `env` block in a project's `.claude/settings.json` or `.claude/settings.local.json` applies only after the first-run wizard and [trust prompt](https://code.claude.com/docs/en/permissions.md#what-runs-before-you-trust-a-folder) | Set `ANTHROPIC_AUTH_TOKEN` somewhere Claude Code reads before first-run setup: a shell export, the `env` block in `~/.claude/settings.json`, or managed settings |

526| `ANTHROPIC_API_KEY` is set but ignored, with no prompt | The key needs a one-time approval in interactive sessions, and a previously declined key is ignored without asking again | Enable it under `/config` with the `Use custom API key` option |526| `ANTHROPIC_API_KEY` is set but ignored, with no prompt | The key needs a one-time approval in interactive sessions, and a previously declined key is ignored without asking again | Enable it under `/config` with the `Use custom API key` option |

Details

148| :- | :- |148| :- | :- |

149| `x-claude-code-request-class` | What kind of request this is: `main` for a turn of the main conversation, `subagent` for a turn of a [subagent](https://code.claude.com/docs/en/sub-agents.md), `workflow` for an agent running inside a workflow, `compaction` for the summarization request that compacts a conversation, or `auxiliary` for side requests such as session titles, classifiers, and summaries. Sent on every request |149| `x-claude-code-request-class` | What kind of request this is: `main` for a turn of the main conversation, `subagent` for a turn of a [subagent](https://code.claude.com/docs/en/sub-agents.md), `workflow` for an agent running inside a workflow, `compaction` for the summarization request that compacts a conversation, or `auxiliary` for side requests such as session titles, classifiers, and summaries. Sent on every request |

150| `x-claude-code-agent-type` | The kind of subagent that issued the request: a built-in agent type name such as `Explore`, `Plan`, or `general-purpose`, or `custom` for a user-defined agent, `teammate` for an [agent team](https://code.claude.com/docs/en/agent-teams.md) member running in the lead's process, or `fork` for a [fork](https://code.claude.com/docs/en/sub-agents.md#fork-the-current-conversation). Present only on a subagent's own turns; a subagent's compaction or side requests keep the agent ID but carry no type. A user-chosen agent name is never sent |150| `x-claude-code-agent-type` | The kind of subagent that issued the request: a built-in agent type name such as `Explore`, `Plan`, or `general-purpose`, or `custom` for a user-defined agent, `teammate` for an [agent team](https://code.claude.com/docs/en/agent-teams.md) member running in the lead's process, or `fork` for a [fork](https://code.claude.com/docs/en/sub-agents.md#fork-the-current-conversation). Present only on a subagent's own turns; a subagent's compaction or side requests keep the agent ID but carry no type. A user-chosen agent name is never sent |

151| `x-claude-code-compaction` | Present on the request that summarizes the conversation during a [compaction](https://code.claude.com/docs/en/prompt-caching.md#compacting-the-conversation). The value says what triggered it: `auto` when the context window approached capacity, `manual` for `/compact`, or `reactive` when the API rejected a request as too long. The value is also `auto` for [idle compaction](https://code.claude.com/docs/en/settings-reference.md#idlecompaction). Absent on every other request |151| `x-claude-code-compaction` | Present on the request that summarizes the conversation during a [compaction](https://code.claude.com/docs/en/prompt-caching.md#compacting-the-conversation). The value says what triggered it: `auto` when the context window approached capacity, `manual` for `/compact`, or `reactive` when the API rejected a request as too long. The value is also `auto` for [idle compaction](https://code.claude.com/docs/en/settings-reference.md#idlecompaction) in an interactive terminal session. Absent on every other request, including one that writes a summary in the background before a compaction |

152| `x-claude-code-context-compacted` | Present once, on the first main-conversation request after a compaction, with the same values as `x-claude-code-compaction`. The conversation prefix before this request is no longer used, so a cache keyed on it can be dropped |152| `x-claude-code-context-compacted` | Present once, on the first main-conversation request after a compaction, with the same values as `x-claude-code-compaction`. The conversation prefix before this request is no longer used, so a cache keyed on it can be dropped |

153| `x-claude-code-prev-tool-durations` | Measured run time of the tool calls whose results this request carries, as `<name>=<ms>;<name>=<ms>`, for example `Bash=742;Read=9`. Sent on the next request of the same conversation after a batch of tool calls, from the main session or a subagent |153| `x-claude-code-prev-tool-durations` | Measured run time of the tool calls whose results this request carries, as `<name>=<ms>;<name>=<ms>`, for example `Bash=742;Read=9`. Sent on the next request of the same conversation after a batch of tool calls, from the main session or a subagent |

154| `x-claude-code-prompt-id` | Random UUID that identifies the user prompt a request serves. Requests serving one prompt share the value, including the turns of subagents that prompt started. Requests not attributed to a prompt omit it. Use it to group a session's requests by prompt. Requires Claude Code v2.1.283 or later |154| `x-claude-code-prompt-id` | Random UUID that identifies the user prompt a request serves. Requests serving one prompt share the value, including the turns of subagents that prompt started. Requests not attributed to a prompt omit it. Use it to group a session's requests by prompt. Requires Claude Code v2.1.283 or later |


238* When the upstream rejects only the `cache_control` marker on a mid-conversation system message, Claude Code keeps the system messages and retries once with the marker moved. The marker goes on the last entry in `messages` that isn't a system message, in that retry and in later requests until Claude Code exits238* When the upstream rejects only the `cache_control` marker on a mid-conversation system message, Claude Code keeps the system messages and retries once with the marker moved. The marker goes on the last entry in `messages` that isn't a system message, in that retry and in later requests until Claude Code exits

239* When the upstream rejects a [thinking signature](https://platform.claude.com/docs/en/build-with-claude/extended-thinking), including with a `400` whose message says the block is `bound to a different conversation`, Claude Code removes earlier thinking blocks from the request, retries, and keeps them out of every later request. New responses still include thinking239* When the upstream rejects a [thinking signature](https://platform.claude.com/docs/en/build-with-claude/extended-thinking), including with a `400` whose message says the block is `bound to a different conversation`, Claude Code removes earlier thinking blocks from the request, retries, and keeps them out of every later request. New responses still include thinking

240* When the gateway or its upstream rejects the [advisor tool](https://code.claude.com/docs/en/advisor.md) entry in `tools` as an unrecognized tool type, Claude Code retries the request once without that entry and its `anthropic-beta` value. Later requests to that base URL leave the advisor out until Claude Code exits, and `/advisor` is unavailable to the developer for that time. Claude Code recognizes this rejection by a `400` or `422` response whose message names the tool type after `Input tag`, such as `Input tag 'advisor_20260301'`. Before v2.1.280, Claude Code didn't retry this rejection240* When the gateway or its upstream rejects the [advisor tool](https://code.claude.com/docs/en/advisor.md) entry in `tools` as an unrecognized tool type, Claude Code retries the request once without that entry and its `anthropic-beta` value. Later requests to that base URL leave the advisor out until Claude Code exits, and `/advisor` is unavailable to the developer for that time. Claude Code recognizes this rejection by a `400` or `422` response whose message names the tool type after `Input tag`, such as `Input tag 'advisor_20260301'`. Before v2.1.280, Claude Code didn't retry this rejection

241* When the upstream rejects `output_config.effort`, Claude Code retries the request without effort and leaves it out of later requests to that model until Claude Code exits. Claude Code recognizes this rejection by a `400` whose message names `output_config.effort` together with `Extra inputs are not permitted`, or says the model doesn't support the effort parameter241* When the upstream rejects `output_config.effort` or its `anthropic-beta` value, Claude Code retries and adds neither to requests for that model until Claude Code exits. Your gateway needs no change if it forwards the upstream's `400` unmodified and the message:

242 * Names `output_config.effort` alongside `Extra inputs are not permitted`

243 * Says the model doesn't support the effort parameter

244 * Starts with `Unexpected value(s)` and lists `effort-2025-11-24` for the `anthropic-beta` header. Requires v2.1.310 or later. Developers whose [`ANTHROPIC_BETAS`](https://code.claude.com/docs/en/env-vars) lists the value keep sending it and getting the `400`, so have them remove that entry

242* When the upstream rejects the `context_management` field or its `anthropic-beta` value, the gateway sees the request once more without them. If the gateway sees them again in a later request and the upstream rejects them again, the same retry follows. Claude Code recognizes this rejection by its message, for example one containing `context_management: Extra inputs are not permitted`. Before v2.1.304, Claude Code didn't retry this rejection245* When the upstream rejects the `context_management` field or its `anthropic-beta` value, the gateway sees the request once more without them. If the gateway sees them again in a later request and the upstream rejects them again, the same retry follows. Claude Code recognizes this rejection by its message, for example one containing `context_management: Extra inputs are not permitted`. Before v2.1.304, Claude Code didn't retry this rejection

243* When the upstream rejects a beta tool field other than `defer_loading`, such as `strict`, the `400` reaches the developer. Before it does, the gateway can see the request again [without the tool search fields](#retry-without-tool-search). To stop sending such fields, have developers set [`CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS=1`](#disable-pre-release-capabilities)246* When the upstream rejects a beta tool field other than `defer_loading`, such as `strict`, the `400` reaches the developer. Before it does, the gateway can see the request again [without the tool search fields](#retry-without-tool-search). To stop sending such fields, have developers set [`CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS=1`](#disable-pre-release-capabilities)

244 247 

Details

470If the name doesn't arrive, check for one of these causes:470If the name doesn't arrive, check for one of these causes:

471 471 

472* **You set it on the computer that runs Desktop**: Desktop doesn't pass a value you set there to the SSH session472* **You set it on the computer that runs Desktop**: Desktop doesn't pass a value you set there to the SSH session

473* **You exported it in a login file**: only login shells read a file such as `/etc/profile`. A value you `export` there reaches Claude Code that you start from a login shell. It doesn't reach a Desktop SSH session, because Desktop doesn't start Claude Code through a login shell.473* **You exported it in `/etc/profile` or another file that only login shells read**: the name arrives when you run `claude` from a login shell, but not in a Desktop SSH session. Desktop doesn't start Claude Code through a login shell. Set the variable under `env` in the [managed settings file](https://code.claude.com/docs/en/desktop.md#managed-settings) on the remote machine instead.

474* **A value has a space inside it**: Claude Code then copies none of the keys onto events or datapoints and reports no error. [Take the space out of the value](#multi-team-organization-support).474* **A value has a space inside it**: Claude Code then copies none of the keys onto events or datapoints and reports no error. [Take the space out of the value](#multi-team-organization-support).

475* **Something else already sets the variable**: in a session that the desktop app starts, a variable already set in the launch environment [takes precedence over settings files](https://code.claude.com/docs/en/settings-reference.md#how-env-values-interact-with-your-shell). The [debug log](https://code.claude.com/docs/en/debug-your-config.md) names each ignored variable. When a third-party Desktop deployment [names an OTLP endpoint](#how-managed-settings-lock-the-otlp-destination) in the environment it provides, that environment carries Desktop's own `OTEL_RESOURCE_ATTRIBUTES`.475* **Something else already sets the variable**: in a session that the desktop app starts, a variable already set in the launch environment [takes precedence over settings files](https://code.claude.com/docs/en/settings-reference.md#how-env-values-interact-with-your-shell). The [debug log](https://code.claude.com/docs/en/debug-your-config.md) names each ignored variable. When a third-party Desktop deployment [names an OTLP endpoint](#how-managed-settings-lock-the-otlp-destination) in the environment it provides, that environment carries Desktop's own `OTEL_RESOURCE_ATTRIBUTES`.

476 476 


1403* `pre_tokens`: Approximate token count before compaction1403* `pre_tokens`: Approximate token count before compaction

1404* `post_tokens`: Approximate token count after compaction1404* `post_tokens`: Approximate token count after compaction

1405* `error`: Error message when compaction failed1405* `error`: Error message when compaction failed

1406* `precompute_reuse`: Only set when `trigger` is `"manual"` or for an [idle compaction](https://code.claude.com/docs/en/settings-reference.md#idlecompaction), which reports `trigger` as `"auto"`. Auto-compaction can prepare a summary in the background before the context window fills, and this attribute records whether the compaction reused that prepared summary. `"hit"` means it was reused; `"miss_custom_instructions"`, `"miss_hook"`, and `"miss_not_ready"` give the reason a fresh summary was computed instead1406* `precompute_reuse`: Only set when `trigger` is `"manual"`, or when `trigger` is `"auto"` for an [idle compaction](https://code.claude.com/docs/en/settings-reference.md#idlecompaction) in an interactive terminal session. Auto-compaction can prepare a summary in the background before the context window fills, and this attribute records whether the compaction reused that prepared summary. `"hit"` means it was reused; `"miss_custom_instructions"`, `"miss_hook"`, and `"miss_not_ready"` give the reason a fresh summary was computed instead

1407 1407 

1408#### Subagent completed event1408#### Subagent completed event

1409 1409 

Details

248 248 

249**Web and mobile**249**Web and mobile**

250 250 

251On [claude.ai/code](https://claude.ai/code), use the mode dropdown next to the prompt box. In the mobile app, tap the **+** button in the prompt box, then **Permission**. Cloud sessions and Remote Control sessions offer different permission modes:251On [claude.ai/code](https://claude.ai/code), use the mode dropdown in the row under the prompt box. In the mobile app, tap the **+** button in the prompt box, then **Permission**. Cloud sessions and Remote Control sessions offer different permission modes:

252 252 

253* **[Cloud sessions](https://code.claude.com/docs/en/claude-code-on-the-web.md)**: Accept edits, Plan, and Auto. Accept edits corresponds to `default` mode: cloud sessions pre-approve file edits regardless of mode, so the dropdown shows Accept edits instead of Manual. Cloud sessions still honor `defaultMode: "acceptEdits"` from settings. Auto mode appears only when your organization allows it and the selected model supports it. Bypass permissions isn't available.253* **[Cloud sessions](https://code.claude.com/docs/en/claude-code-on-the-web.md)**: Accept edits, Plan, and Auto. Accept edits corresponds to `default` mode: cloud sessions pre-approve file edits regardless of mode, so the dropdown shows Accept edits instead of Manual. Cloud sessions still honor `defaultMode: "acceptEdits"` from settings. Auto mode appears only when your organization allows it and the selected model supports it. Bypass permissions isn't available.

254* **[Remote Control](https://code.claude.com/docs/en/remote-control.md) sessions** on your local machine: Manual, Accept edits, Plan, and Auto for a session you started yourself, and you can't select Bypass permissions from the app. To use Auto, the session has to meet the auto mode [availability requirements](#eliminate-prompts-with-auto-mode). For a project thread running on your computer, see [Run a thread on your own computer](https://code.claude.com/docs/en/claude-projects.md#run-a-thread-on-your-own-computer).254* **[Remote Control](https://code.claude.com/docs/en/remote-control.md) sessions** on your local machine: Manual, Accept edits, Plan, and Auto for a session you started yourself, and you can't select Bypass permissions from the app. To use Auto, the session has to meet the auto mode [availability requirements](#eliminate-prompts-with-auto-mode). For a project thread running on your computer, see [Run a thread on your own computer](https://code.claude.com/docs/en/claude-projects.md#run-a-thread-on-your-own-computer).

Details

584 584 

585A monitor's command is limited in where it starts and what it can reference:585A monitor's command is limited in where it starts and what it can reference:

586 586 

587* **Interactive sessions only**: plugin monitors start in an interactive session and never in non-interactive mode with the `-p` flag. They also don't start in sessions where the API provider or telemetry settings make the [Monitor tool](https://code.claude.com/docs/en/tools-reference.md#monitor-tool) unavailable587* **Interactive sessions**: plugin monitors don't start in non-interactive mode with the `-p` flag

588* **Minimum version**: on Amazon Bedrock, Claude Platform on AWS, Google Cloud's Agent Platform, or Microsoft Foundry, or with `DISABLE_TELEMETRY` or `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC` set, monitors require Claude Code v2.1.310 or later. The requirement applies when [feature-flag fetching](https://code.claude.com/docs/en/env-vars.md#features-that-need-feature-flag-fetching) is off

588* **No user configuration**: `command` gets the [path variables](#path-variables-and-persistent-data) and `${ENV_VAR}` from the environment, but never `${user_config.*}`. A monitor that references one doesn't start, and monitor processes don't receive `CLAUDE_PLUGIN_OPTION_<KEY>` either589* **No user configuration**: `command` gets the [path variables](#path-variables-and-persistent-data) and `${ENV_VAR}` from the environment, but never `${user_config.*}`. A monitor that references one doesn't start, and monitor processes don't receive `CLAUDE_PLUGIN_OPTION_<KEY>` either

589* **Disabling mid-session**: if you disable a plugin mid-session, Claude Code doesn't stop monitors that are already running. They stop when the session ends590* **Disabling mid-session**: if you disable a plugin mid-session, Claude Code doesn't stop monitors that are already running. They stop when the session ends

590 591 


647 648 

648In the data directory path, `<id>` is the plugin identifier with every character other than letters, digits, `_`, and `-` replaced by `-`, so `my-plugin@my-marketplace` becomes `my-plugin-my-marketplace`.649In the data directory path, `<id>` is the plugin identifier with every character other than letters, digits, `_`, and `-` replaced by `-`, so `my-plugin@my-marketplace` becomes `my-plugin-my-marketplace`.

649 650 

650On Windows, the substituted paths use forward slashes so a shell doesn't read backslashes as escapes.651On Windows, most substituted paths use forward slashes, as in `C:/Users/you/...`. They keep their native backslashes in an [exec-form hook](https://code.claude.com/docs/en/hooks.md#exec-form-and-shell-form) and in a hook that runs through PowerShell, which is the default shell on Windows when Git Bash isn't installed.

651 652 

652### Install dependencies into the data directory653### Install dependencies into the data directory

653 654 

Details

148 148 

149When the two names differ and someone installs by the manifest name, Claude Code reports `Plugin "<manifest-name>" not found in marketplace "<marketplace>"`. Keep the two names the same. For more on how Claude Code uses the two names, see [Plugin loading reference](https://code.claude.com/docs/en/plugins/loading.md#find-where-a-plugin-came-from).149When the two names differ and someone installs by the manifest name, Claude Code reports `Plugin "<manifest-name>" not found in marketplace "<marketplace>"`. Keep the two names the same. For more on how Claude Code uses the two names, see [Plugin loading reference](https://code.claude.com/docs/en/plugins/loading.md#find-where-a-plugin-came-from).

150 150 

151### Keep unused submodules out of the clone

152 

153When someone adds your marketplace, Claude Code clones the repository and fetches only the git submodules that hold plugin files. Requires Claude Code v2.1.295 or later.

154 

155You decide which submodules Claude Code fetches by where you put each plugin:

156 

157* **A plugin in a subdirectory**: Claude Code fetches the submodules inside the plugin's directory and a submodule that contains it. Put a submodule your plugin needs inside the plugin's directory, and keep one it doesn't need outside

158* **A plugin at the marketplace root**: Claude Code fetches every submodule in the repository as soon as one of the plugin's files refers to a path inside any of them. If your repository has a large submodule that only your build uses, move the plugin into a subdirectory

159 

160If a plugin at the root runs a file from a submodule, write the file's path out in the plugin's hook or server configuration, such as `${CLAUDE_PLUGIN_ROOT}/vendor/tool/run.sh`. Claude Code reads those paths to find out whether the plugin needs the submodules. It can't see a path that a script builds while it runs.

161 

162For the full rule, see [Git submodules in the marketplace repository](https://code.claude.com/docs/en/plugins/marketplace-reference.md#git-submodules-in-the-marketplace-repository).

163 

151## Choose a plugin source164## Choose a plugin source

152 165 

153Each plugin entry in `marketplace.json` has a `source` that tells Claude Code where to fetch that one plugin. Pick the source by where the plugin's files are stored. The table lists the sources most marketplace owners use.166Each plugin entry in `marketplace.json` has a `source` that tells Claude Code where to fetch that one plugin. Pick the source by where the plugin's files are stored. The table lists the sources most marketplace owners use.

Details

111Tell users what each protocol needs on their machine:111Tell users what each protocol needs on their machine:

112 112 

113* **SSH**: the key must work without a passphrase prompt, for example because it's loaded in `ssh-agent`. The host must already be in `known_hosts`.113* **SSH**: the key must work without a passphrase prompt, for example because it's loaded in `ssh-agent`. The host must already be in `known_hosts`.

114* **HTTPS**: Claude Code leaves the user's git credential helper enabled but forbids it from prompting. A credential the helper already stores works; one it would have to ask for fails. On GitHub, `gh auth login` followed by `gh auth setup-git` stores one.114* **HTTPS**: Claude Code leaves the user's git credential helper enabled but forbids it from prompting, and doesn't run askpass programs such as one set in `GIT_ASKPASS`. A credential the helper already stores works; one it would have to ask for fails. On GitHub, `gh auth login` followed by `gh auth setup-git` stores one.

115 115 

116For a GitHub Enterprise Server host, users need git access to that host from their machine. See [Plugin marketplaces on GHES](https://code.claude.com/docs/en/github-enterprise-server.md#plugin-marketplaces-on-ghes) for what each Claude Code surface needs to reach a GHES-hosted marketplace.116For a GitHub Enterprise Server host, users need git access to that host from their machine. See [Plugin marketplaces on GHES](https://code.claude.com/docs/en/github-enterprise-server.md#plugin-marketplaces-on-ghes) for what each Claude Code surface needs to reach a GHES-hosted marketplace.

117 117 

Details

238 238 

239A private marketplace is one in a repository you need credentials to clone, on GitHub or any other git host. You add it with the same `/plugin marketplace add` or `claude plugin marketplace add` command as a public one. Claude Code clones it with the git credentials already on your machine and never prompts, so each way of connecting has a requirement:239A private marketplace is one in a repository you need credentials to clone, on GitHub or any other git host. You add it with the same `/plugin marketplace add` or `claude plugin marketplace add` command as a public one. Claude Code clones it with the git credentials already on your machine and never prompts, so each way of connecting has a requirement:

240 240 

241* **HTTPS**: your git credential helpers apply, so access you set up with `gh auth login`, the macOS Keychain, or `git-credential-store` works. Interactive prompts are suppressed, so a host you have never authenticated to fails instead of asking for a password.241* **HTTPS**: your git credential helpers apply, so access you set up with `gh auth login`, the macOS Keychain, or `git-credential-store` works. Git's prompts and askpass programs are off, including one set in `GIT_ASKPASS`, so the clone fails instead of prompting when git would have to ask for a credential.

242* **SSH**: the host must already be in your `known_hosts` file and the key must work without a passphrase prompt. If your git setup names an SSH program in `GIT_SSH_COMMAND`, `GIT_SSH`, or your git config's `core.sshCommand`, Claude Code runs that program.242* **SSH**: the host must already be in your `known_hosts` file and the key must work without a passphrase prompt. If your git setup names an SSH program in `GIT_SSH_COMMAND`, `GIT_SSH`, or your git config's `core.sshCommand`, Claude Code runs that program.

243* **GitHub `owner/repo` shorthand**: Claude Code checks whether your SSH key authenticates to `github.com`, then clones over SSH if it does and over HTTPS if it doesn't. Set [`CLAUDE_CODE_PLUGIN_PREFER_HTTPS=1`](https://code.claude.com/docs/en/env-vars#variables) to skip that check and always clone over HTTPS.243* **GitHub `owner/repo` shorthand**: Claude Code checks whether your SSH key authenticates to `github.com`, then clones over SSH if it does and over HTTPS if it doesn't. Set [`CLAUDE_CODE_PLUGIN_PREFER_HTTPS=1`](https://code.claude.com/docs/en/env-vars#variables) to skip that check and always clone over HTTPS.

244 244 

Details

41* **A marketplace that settings declare but `known_marketplaces.json` lacks**: Claude Code clones it, then reloads plugins and downloads enabled plugins that aren't cached yet41* **A marketplace that settings declare but `known_marketplaces.json` lacks**: Claude Code clones it, then reloads plugins and downloads enabled plugins that aren't cached yet

42* **A declared marketplace whose source changed in settings**: Claude Code re-fetches it from the new source and shows `Plugins changed. Run /reload-plugins to activate.`42* **A declared marketplace whose source changed in settings**: Claude Code re-fetches it from the new source and shows `Plugins changed. Run /reload-plugins to activate.`

43 43 

44An enabled plugin that neither path fetched and that has no usable cache directory shows `Plugin "<name>" not cached at <path>` in the `/plugin` **Errors** tab, and `claude plugin list` adds `— run /plugin to refresh` to the same line. For the fix, see [`Plugin "<name>" not cached at <path>`](https://code.claude.com/docs/en/plugins/troubleshooting#plugin-not-cached-at).44An enabled plugin that neither path fetched and that has no usable cache directory shows `Plugin "<name>" not cached at <path>` in the `/plugin` **Errors** tab. For the fix, see [`Plugin "<name>" not cached at <path>`](https://code.claude.com/docs/en/plugins/troubleshooting#plugin-not-cached-at).

45 45 

46## Find where a plugin came from46## Find where a plugin came from

47 47 

Details

155| `workflows` | Path, or array of paths | [Workflow](https://code.claude.com/docs/en/workflows.md#distribute-a-workflow-in-a-plugin) `.js` files or directories. Replaces the default `workflows/` scan |155| `workflows` | Path, or array of paths | [Workflow](https://code.claude.com/docs/en/workflows.md#distribute-a-workflow-in-a-plugin) `.js` files or directories. Replaces the default `workflows/` scan |

156| `experimental` | Object | Container for `themes`, `monitors`, and `evals`, whose manifest shape may still change |156| `experimental` | Object | Container for `themes`, `monitors`, and `evals`, whose manifest shape may still change |

157| `experimental.themes` | Path, or array of paths | Theme files or directories. Replaces the default `themes/` scan. A top-level `themes` key still loads, with a `claude plugin validate` warning |157| `experimental.themes` | Path, or array of paths | Theme files or directories. Replaces the default `themes/` scan. A top-level `themes` key still loads, with a `claude plugin validate` warning |

158| [`experimental.monitors`](#monitors) | Path, or inline array | A `.json` file holding the monitors array, or the array itself. Defaults to `monitors/monitors.json`. A top-level `monitors` key still loads, with a `claude plugin validate` warning. Monitors run only in interactive sessions, and not on Amazon Bedrock, Google Cloud's Agent Platform, or Microsoft Foundry |158| [`experimental.monitors`](#monitors) | Path, or inline array | A `.json` file holding the monitors array, or the array itself. Defaults to `monitors/monitors.json`. A top-level `monitors` key still loads, with a `claude plugin validate` warning. Monitors [don't start with the `-p` flag](https://code.claude.com/docs/en/plugins/components#monitors) |

159| `experimental.evals` | Path, or array of paths | Directory that holds the plugin's [eval cases](https://code.claude.com/docs/en/plugin-evals.md#use-a-different-eval-directory) when it isn't the default `evals/`. `claude plugin eval --eval-dir` overrides it |159| `experimental.evals` | Path, or array of paths | Directory that holds the plugin's [eval cases](https://code.claude.com/docs/en/plugin-evals.md#use-a-different-eval-directory) when it isn't the default `evals/`. `claude plugin eval --eval-dir` overrides it |

160 160 

161In the Type column, a path is a string relative to the plugin root, such as `"./custom/commands"`.161In the Type column, a path is a string relative to the plugin root, such as `"./custom/commands"`.


606}606}

607```607```

608 608 

609On Windows, the substituted paths use forward slashes so a shell doesn't read backslashes as escapes.609On Windows, most substituted paths use forward slashes, as in `C:/Users/you/...`. They keep their native backslashes in an [exec-form hook](https://code.claude.com/docs/en/hooks.md#exec-form-and-shell-form) and in a hook that runs through PowerShell, which is the default shell on Windows when Git Bash isn't installed.

610 610 

611## Standard layout611## Standard layout

612 612 

Details

172* **`url`**: Claude Code fetches only `marketplace.json`, so relative paths can't resolve. Give each plugin an object source instead, such as `github` or `git-subdir`.172* **`url`**: Claude Code fetches only `marketplace.json`, so relative paths can't resolve. Give each plugin an object source instead, such as `github` or `git-subdir`.

173* **`settings`**: relative paths are rejected outright.173* **`settings`**: relative paths are rejected outright.

174 174 

175#### Git submodules in the marketplace repository

176 

177When Claude Code clones a marketplace repository, it fetches only the git submodules that hold plugin files. Requires Claude Code v2.1.295 or later.

178 

179Earlier versions fetch every submodule, nested ones included. If the repository has a large submodule, Claude Code can then run past the [clone timeout](https://code.claude.com/docs/en/plugins/troubleshooting.md#git-clone-timed-out-after-120s) while fetching it.

180 

181For a plugin in a subdirectory, such as `./plugins/formatter`, Claude Code fetches a submodule in these cases:

182 

183* **The plugin is inside the submodule**: the submodule is the plugin's directory or a directory above it

184* **The submodule is inside the plugin**: the submodule is anywhere under the plugin's directory

185* **A symbolic link points into the submodule**: a link committed to the repository has its target in the submodule

186 

187A plugin at the marketplace root, with `"source": "./"`, gets every submodule in the repository or none of them. Claude Code fetches every submodule when one of these points into any submodule:

188 

189* **A component directory**: a directory at the root that holds plugin components, such as `skills/`, `hooks/`, or `bin/`

190* **A path in the plugin's configuration**: a path in the plugin's marketplace entry, in its `plugin.json`, or in a config file such as `.mcp.json` or `hooks/hooks.json`

191* **A symbolic link**: a link committed to the repository

192* **Text in the plugin's files**: a submodule's path, such as `vendor/tool`, written in a config file or in a file under a component directory

193 

194When none of them does, Claude Code fetches no submodule for that plugin. A repository that is both a project and a plugin often has submodules that only the project's build uses, and this rule leaves them out.

195 

196Claude Code also fetches every submodule where it can't tell which ones hold plugin files, such as:

197 

198* **A `SKILL.md` at the root**: the whole repository is then one skill's directory

199* **A file Claude Code can't read**: the marketplace file, one of the plugin's config files, or `.gitmodules`

200 

201If you add a marketplace with `--sparse`, or its source sets `sparsePaths`, Claude Code checks out only the directories named there and fetches no submodule. Earlier versions do the same.

202 

203To keep a submodule your plugins don't use out of the clone, see [Keep unused submodules out of the clone](https://code.claude.com/docs/en/plugins/create-marketplace.md#keep-unused-submodules-out-of-the-clone).

204 

175#### Bare names under pluginRoot205#### Bare names under pluginRoot

176 206 

177A bare name is a single directory name with no `/`, such as `"formatter"`. To write bare names instead of `./` paths, set [`metadata.pluginRoot`](#top-level-fields) to the directory they resolve under. With `"pluginRoot": "./plugins"`, `"source": "formatter"` resolves to `./plugins/formatter`. Requires Claude Code v2.1.239 or later.207A bare name is a single directory name with no `/`, such as `"formatter"`. To write bare names instead of `./` paths, set [`metadata.pluginRoot`](#top-level-fields) to the directory they resolve under. With `"pluginRoot": "./plugins"`, `"source": "formatter"` resolves to `./plugins/formatter`. Requires Claude Code v2.1.239 or later.

Details

313 313 

314#### What refused calls return314#### What refused calls return

315 315 

316In the results, `<reason>` stands for `the session was stopped and nobody has sent input since`:316In the results, `<reason>` stands for the reason the call was refused. After an interruption, that's `the session was stopped and nobody has sent input since`. For other reasons, see [Calls refused in `claude -p` runs and Agent SDK sessions](#calls-refused-in-non-interactive-runs).

317 317 

318| Some refused calls | Result until the user's next input |318| Some refused calls | Result |

319| :- | :- |319| :- | :- |

320| `$.prompt.submit` | Resolves with `{ drop: '<reason>' }` and queues no prompt |320| `$.prompt.submit` | Resolves with `{ drop: '<reason>' }` and queues no prompt |

321| `$.command.run` | Rejects with an error whose message ends with `<reason>` |321| `$.command.run` | Rejects with an error whose message ends with `<reason>` |


324| `$.session.send` to an [agent team](https://code.claude.com/docs/en/agent-teams.md) teammate | Resolves with `{ isDelivered: false, reason: 'Teammate "<name>" was not messaged: <reason>.' }`, where `<name>` is the teammate's name |324| `$.session.send` to an [agent team](https://code.claude.com/docs/en/agent-teams.md) teammate | Resolves with `{ isDelivered: false, reason: 'Teammate "<name>" was not messaged: <reason>.' }`, where `<name>` is the teammate's name |

325| [`$.tool.call`](https://code.claude.com/docs/en/plugins/mods/reference#mods-api-methods) of Bash with `run_in_background: true`, Monitor, or CronCreate | Resolves with `{ deny: '<tool> was not run: it starts background work, a schedule or a goal, and <reason>' }`, where `<tool>` is the tool's name |325| [`$.tool.call`](https://code.claude.com/docs/en/plugins/mods/reference#mods-api-methods) of Bash with `run_in_background: true`, Monitor, or CronCreate | Resolves with `{ deny: '<tool> was not run: it starts background work, a schedule or a goal, and <reason>' }`, where `<tool>` is the tool's name |

326 326 

327Along with these `$.session.send` and `$.tool.call` results, the user can see the [`Stopped:` toast](https://code.claude.com/docs/en/plugins/mods/troubleshoot#stopped-type-a-message-to-continue).327When one of these `$.session.send` or `$.tool.call` calls is refused after an interruption in an interactive session, the user can see the [`Stopped:` toast](https://code.claude.com/docs/en/plugins/mods/troubleshoot#stopped-type-a-message-to-continue).

328 328 

329#### Work your mod started before the interruption329#### Work your mod started before the interruption

330 330 


341 341 

342When a scheduled job comes due or a monitor raises an event before the user's next input, the user can see the [`Stopped:` toast](https://code.claude.com/docs/en/plugins/mods/troubleshoot#stopped-type-a-message-to-continue).342When a scheduled job comes due or a monitor raises an event before the user's next input, the user can see the [`Stopped:` toast](https://code.claude.com/docs/en/plugins/mods/troubleshoot#stopped-type-a-message-to-continue).

343 343 

344### Calls refused in `claude -p` runs and Agent SDK sessions

345 

346In a `claude -p` run or an [Agent SDK](https://code.claude.com/docs/en/agent-sdk/overview.md) session, a result such as `{ drop: 'the run reached its --max-turns limit' }` means the run refused your mod's call.

347 

348A refused `$.prompt.submit` resolves with `{ drop: '<reason>' }`. Other refused calls, such as `$.command.run` and `$.agent.spawn`, give the results shown in [What refused calls return](#what-refused-calls-return) with the reason in place of `<reason>`. Find your `<reason>` below for what to do about it:

349 

350* **`the run reached its --max-turns limit`**: turns from your mod's prompts and from subagents it spawns count toward [`--max-turns`](https://code.claude.com/docs/en/cli-reference#cli-flags) or the Agent SDK's [turn limit](https://code.claude.com/docs/en/agent-sdk/configuration.md#limit-turns-and-spend). For more turns, start the run with a higher limit. If you can't, have your mod stop making the refused call. If the run takes another prompt from the user or the SDK application, the turn count resets and the run accepts calls again.

351* **`the run is past its --max-budget-usd limit`**: start the run with a higher `--max-budget-usd`, or raise the Agent SDK's [spend limit](https://code.claude.com/docs/en/agent-sdk/configuration.md#limit-turns-and-spend). If you can't, have your mod stop making the refused call. The limit applies to the run's total cost so far. That total keeps adding up when the run takes another prompt, so a retry returns the same reason.

352* **`the host has ended its input`**: for example, the SDK application ended its [streaming input](https://code.claude.com/docs/en/agent-sdk/streaming-vs-single-mode.md), or stdin closed on a run started with [`--input-format stream-json`](https://code.claude.com/docs/en/cli-reference#cli-flags). The run is ending and takes no more input, so a retry returns the same reason. Have your mod stop making the refused call. If you start the run yourself, next time keep that input open until your mod has no more calls to make.

353* **`the session was stopped and nobody has sent input since`**: the run was [interrupted](#calls-and-background-work-after-the-user-interrupts-a-turn), for example with the Agent SDK's [`interrupt()`](https://code.claude.com/docs/en/agent-sdk/typescript#query-object). To make the call again after the next message from the user or the SDK application, follow [Retry a refused or dropped call](#retry-a-refused-or-dropped-call).

354 

355### A `claude -p` run with your mod never exits

356 

357If your mod submits a prompt at the end of every turn, each prompt starts another turn. Without [`--max-turns`](https://code.claude.com/docs/en/cli-reference#cli-flags) or `--max-budget-usd`, a `claude -p` run that loads the mod goes on until you stop it yourself.

358 

359To make the run end on its own, add either flag to the command in your shell. If other people start the run, have your mod stop submitting prompts once its work is done. This command adds `--max-turns`:

360 

361```bash theme={null}

362claude -p "find the TODOs" --max-turns 5

363```

364 

365Once the run reaches that limit, the mod's next prompt is [refused](#calls-refused-in-non-interactive-runs) instead of starting a turn, and the run ends.

366 

367If the run still goes past the limit, run `claude --version` in your shell, and [update Claude Code](https://code.claude.com/docs/en/setup.md#update-claude-code) if yours is earlier than v2.1.304. The mod's prompts are refused at the limit from v2.1.299. If your mod spawns subagents, their turns count toward `--max-turns` from v2.1.304.

368 

344## Send and receive messages between sessions369## Send and receive messages between sessions

345 370 

346A mod can send a plain-text message to another of your sessions, to one of this session's subagents, or to a teammate in its [agent team](https://code.claude.com/docs/en/agent-teams.md). It can also observe the messages that arrive and leave.371A mod can send a plain-text message to another of your sessions, to one of this session's subagents, or to a teammate in its [agent team](https://code.claude.com/docs/en/agent-teams.md). It can also observe the messages that arrive and leave.


390| `$.http` | `fetch(url, init)` over `http` or `https`. It resolves to `{ status, ok, headers, text }` once the body is read. |415| `$.http` | `fetch(url, init)` over `http` or `https`. It resolves to `{ status, ok, headers, text }` once the body is read. |

391| `$.store` | A JSON key-value store of your plugin's own, kept between sessions |416| `$.store` | A JSON key-value store of your plugin's own, kept between sessions |

392| `$.env` | `get` and `set` environment variables. Write the name as a string literal. |417| `$.env` | `get` and `set` environment variables. Write the name as a string literal. |

393| `$.settings` | `read` what the settings files and managed policy hold |418| `$.settings` | `read()` resolves to all settings, merged into one object. With `{ source }` or `{ key }`, it resolves to [one source's settings or one key's value](#read-one-source-or-one-key) instead. |

394| `$.session` | `messages()` returns the transcript as a list of `{ role, text, toolUses }`. Also the working directory, model, and more. [`usage()`](https://code.claude.com/docs/en/plugins/mods/reference#mods-api-methods) returns context window use and plan limits. |419| `$.session` | `messages()` returns the transcript as a list of `{ role, text, toolUses }`. Also the working directory, model, and more. [`usage()`](https://code.claude.com/docs/en/plugins/mods/reference#mods-api-methods) returns context window use and plan limits. |

395| `$.mcp` | `call` a tool on a connected MCP server |420| `$.mcp` | `call` a tool on a connected MCP server |

396 421 


408* **`$.process.spawn started, and a plugin withheld its result:`**: the refusing mod hadn't read the command's output to the end. Claude Code stops the command if it's still running.433* **`$.process.spawn started, and a plugin withheld its result:`**: the refusing mod hadn't read the command's output to the end. Claude Code stops the command if it's still running.

409* **`$.process.spawn ran, and a plugin withheld its result:`**: the refusing mod had read the command's output to the end, so the command had exited434* **`$.process.spawn ran, and a plugin withheld its result:`**: the refusing mod had read the command's output to the end, so the command had exited

410 435 

436### Read all settings, one source, or one key

437 

438`$.settings.read()` resolves to one object that holds the settings from all sources in use, merged by [precedence](https://code.claude.com/docs/en/settings.md#settings-precedence). Pass `{ source }` to read one source instead, `{ key }` to read one key, or both:

439 

440| Call | Resolves to |

441| :- | :- |

442| `$.settings.read()` | The merged settings as one object. Its top-level keys are those of a `settings.json` file, such as `permissions` and `hooks`. |

443| `$.settings.read({ source: 'policy' })` | That one source's settings as one object, or `{}` when that source holds no settings |

444| `$.settings.read({ key: 'spinnerTipsEnabled' })` | That key's value in the merged settings, or `undefined` when the key isn't set |

445| `$.settings.read({ key: 'spinnerTipsEnabled', source: 'user' })` | That key's value in that one source, or `undefined` when that source doesn't set it |

446 

447For `source`, pass the name of the one settings source to read:

448 

449* **`user`**: `~/.claude/settings.json`

450* **`project`**: `.claude/settings.json`

451* **`local`**: `.claude/settings.local.json`

452* **`flag`**: what you pass with `--settings`, and the SDK's inline settings

453* **`policy`**: [managed settings](https://code.claude.com/docs/en/managed-settings.md#how-claude-code-combines-managed-sources)

454 

455For `key`, pass the exact name of one top-level key, not a dotted path into a nested object. The `key` argument requires Claude Code v2.1.304 or later.

456 

411## Next steps457## Next steps

412 458 

413* [React to events](https://code.claude.com/docs/en/plugins/mods/events.md): hook tool calls, prompts, and turns459* [React to events](https://code.claude.com/docs/en/plugins/mods/events.md): hook tool calls, prompts, and turns

Details

48 48 

49Use what you asked for. For the example prompt, the current branch name appears above the prompt box. If the mod doesn't do what you wanted, tell Claude what to change. The mod reloads at the end of each turn that changes its files, so you can try the change as soon as Claude finishes.49Use what you asked for. For the example prompt, the current branch name appears above the prompt box. If the mod doesn't do what you wanted, tell Claude what to change. The mod reloads at the end of each turn that changes its files, so you can try the change as soon as Claude finishes.

50 50 

51If a transcript line that starts with the mod's name says the [change didn't load](https://code.claude.com/docs/en/plugins/mods/troubleshoot.md#this-mods-change-didnt-load), paste that line into your next message when you ask Claude for a fix. Claude doesn't see the line unless you paste it.

52 

51### Use the mod in other sessions53### Use the mod in other sessions

52 54 

53A mod Claude wrote loads only in the session that made it, and Claude Code deletes that session's mods folder once it's older than [`cleanupPeriodDays`](https://code.claude.com/docs/en/settings-reference#cleanupperioddays). To keep the mod, copy its directory out of the mods folder to a place of your own, such as `~/mods/git-branch`. Then choose how to load it:55A mod Claude wrote loads only in the session that made it, and Claude Code deletes that session's mods folder once it's older than [`cleanupPeriodDays`](https://code.claude.com/docs/en/settings-reference#cleanupperioddays). To keep the mod, copy its directory out of the mods folder to a place of your own, such as `~/mods/git-branch`. Then choose how to load it:

Details

93 93 

94## Hook what Claude is doing94## Hook what Claude is doing

95 95 

96Handle these events to see or change a tool call, a prompt, or a turn as it happens. For every event and what a hook can return, see the [events reference](https://code.claude.com/docs/en/plugins/mods/reference.md#events).96Handle these events to see or change a tool call, a prompt, a turn, or a settings read as it happens. For every event and what a hook can return, see the [events reference](https://code.claude.com/docs/en/plugins/mods/reference.md#events).

97 97 

98### Guard or change a tool call98### Guard or change a tool call

99 99 


115 115 

116When Claude tries `git push --force`, the command doesn't run and no permission prompt appears, because the hook never calls `next`. Claude reads the `deny` text as the tool's result, so write it as an instruction Claude can act on. Every other Bash command runs as it would without the mod.116When Claude tries `git push --force`, the command doesn't run and no permission prompt appears, because the hook never calls `next`. Claude reads the `deny` text as the tool's result, so write it as an instruction Claude can act on. Every other Bash command runs as it would without the mod.

117 117 

118If this hook throws or times out, Claude Code skips it and the command goes on as it would without the mod. To refuse the command instead, [add a `.catch` handler](#handle-a-hook-that-fails) to the hook.

119 

118To act after a tool has run, `await next(e)`, do your work, and return what `next` gave you. This hook logs each `.mdx` file Claude changes, with [`$.ui.log`](https://code.claude.com/docs/en/plugins/mods/api#show-something-without-starting-a-turn), which adds a dim line to the transcript that Claude doesn't read:120To act after a tool has run, `await next(e)`, do your work, and return what `next` gave you. This hook logs each `.mdx` file Claude changes, with [`$.ui.log`](https://code.claude.com/docs/en/plugins/mods/api#show-something-without-starting-a-turn), which adds a dim line to the transcript that Claude doesn't read:

119 121 

120```javascript theme={null}122```javascript theme={null}


177* **The user types an answer**: `$.ui.ask` resolves to the typed text. The hook compares it with `Run it`, so any other text refuses the command.179* **The user types an answer**: `$.ui.ask` resolves to the typed text. The hook compares it with `Run it`, so any other text refuses the command.

178* **Nobody answers**: `$.ui.ask` rejects when the user dismisses the question or picks **Chat about this**, and in a `claude -p` run, so the `catch` block leaves the answer at `Refuse`180* **Nobody answers**: `$.ui.ask` rejects when the user dismisses the question or picks **Chat about this**, and in a `claude -p` run, so the `catch` block leaves the answer at `Refuse`

179 181 

180Keep the wait inside a mods API call such as `$.ui.ask`, because that time doesn't count against the hook's [time limit](https://code.claude.com/docs/en/plugins/mods/reference.md#limits). Time spent awaiting a promise of your own does count. Claude Code skips a hook that times out, so the held command would run.182Keep the wait inside a mods API call such as `$.ui.ask`, because that time doesn't count against the hook's [time limit](https://code.claude.com/docs/en/plugins/mods/reference.md#limits). Time spent awaiting a promise of your own does count.

183 

184Claude Code skips a hook that times out, so the held command would run. To refuse it instead, chain [a `.catch` handler](#handle-a-hook-that-fails) onto the registration that `on` returns. That handler is separate from the `catch` block inside the hook.

181 185 

182#### Approve or refuse a tool call before the user is asked186#### Approve or refuse a tool call before the user is asked

183 187 


207 211 

208* **On `main`**: the hook returns `deny`, even when a rule allows `git push`212* **On `main`**: the hook returns `deny`, even when a rule allows `git push`

209* **On another branch, and for other commands**: the call gets the decision it would get without the mod213* **On another branch, and for other commands**: the call gets the decision it would get without the mod

214* **The hook throws or times out**: the call also gets the decision it would get without the mod. To refuse the call instead, [add a `.catch` handler](#handle-a-hook-that-fails) that returns `{ decision: 'deny', reason: 'the reason' }`.

210 215 

211The hook matches the text of the command, so treat it as a reminder for Claude. To block pushes to `main` for everyone, protect the branch on your Git host.216The hook matches the text of the command, so treat it as a reminder for Claude. To block pushes to `main` for everyone, protect the branch on your Git host.

212 217 


269 274 

270When you send a prompt such as `open a PR for this change`, your message looks the same in the transcript, and Claude also reads a line such as `Current branch: feature/auth` after it. A prompt that doesn't mention a pull request goes through unchanged, and `git` doesn't run.275When you send a prompt such as `open a PR for this change`, your message looks the same in the transcript, and Claude also reads a line such as `Current branch: feature/auth` after it. A prompt that doesn't mention a pull request goes through unchanged, and `git` doesn't run.

271 276 

272To stop a prompt, return `{ drop: 'the reason' }` without calling `next`. The text goes back into the user's prompt input, and they see `Prompt dropped by a hook:` followed by your reason, so address the reason to them. If your hook returns a `drop` after its `next(e)` call let the prompt through, the turn still runs, and the hook [fails](#handle-a-hook-that-fails) with a message that includes `a drop after its next() was answered`.277To stop a prompt, return `{ drop: 'the reason' }` without calling `next`. The text goes back into the user's prompt input, and they see `Prompt dropped by a hook:` followed by your reason, so address the reason to them. The prompt still goes through in these cases:

278 

279* **Your hook returns a `drop` after its `next(e)` call let the prompt through**: the turn still runs, and the hook [fails](#handle-a-hook-that-fails) with a message that includes `a drop after its next() was answered`

280* **Your hook throws or times out**: Claude Code skips it and sends the prompt. [Add a `.catch` handler](#handle-a-hook-that-fails) so that a failure doesn't send a prompt the hook would have stopped.

273 281 

274[Other events](https://code.claude.com/docs/en/plugins/mods/reference.md#prompts-and-what-claude-reads) cover the rest of what Claude reads: `prompt.section` for each section of the system prompt, `prompt.context` for the context sent with the first message, and `skill.prompt` for a skill's text. Text from these hooks that changes between requests [invalidates the prompt cache](https://code.claude.com/docs/en/prompt-caching.md). In a `skill.prompt` hook, you can also read [which plugin or file the skill came from](https://code.claude.com/docs/en/plugins/mods/reference.md#skill-prompt-fields).282[Other events](https://code.claude.com/docs/en/plugins/mods/reference.md#prompts-and-what-claude-reads) cover the rest of what Claude reads: `prompt.section` for each section of the system prompt, `prompt.context` for the context sent with the first message, and `skill.prompt` for a skill's text. Text from these hooks that changes between requests [invalidates the prompt cache](https://code.claude.com/docs/en/prompt-caching.md). In a `skill.prompt` hook, you can also read [which plugin or file the skill came from](https://code.claude.com/docs/en/plugins/mods/reference.md#skill-prompt-fields).

275 283 


305 313 

306To see the tool calls that the API ran itself during the request, such as calls to the [advisor tool](https://code.claude.com/docs/en/advisor.md), read `result.serverToolUses`. Claude Code doesn't run these calls, so no `tool.call` or `tool.check` hook fires for them. The field is absent when the response has no such calls, and it requires Claude Code v2.1.290 or later.314To see the tool calls that the API ran itself during the request, such as calls to the [advisor tool](https://code.claude.com/docs/en/advisor.md), read `result.serverToolUses`. Claude Code doesn't run these calls, so no `tool.call` or `tool.check` hook fires for them. The field is absent when the response has no such calls, and it requires Claude Code v2.1.290 or later.

307 315 

316### Change or refuse a settings read

317 

318A `settings.read` hook runs on a mod's read and on Claude Code's own read:

319 

320* **A mod's read**: a mod calls [`$.settings.read`](https://code.claude.com/docs/en/plugins/mods/api#read-one-source-or-one-key).

321* **Claude Code's own read**: Claude Code builds the session's merged settings. This read repeats when settings or the loaded plugins change.

322 

323Before you rely on either read, check the guard and your version:

324 

325* **The built-in guard**: with managed settings, or with a Team or Enterprise [`/login`](https://code.claude.com/docs/en/authentication#authentication-precedence) as the session's credential, the [built-in guard](https://code.claude.com/docs/en/plugins/mods/admin.md#know-what-happens-by-default) can skip this hook in a mod you install or load with `--plugin-dir`. To check, search the [debug log](https://code.claude.com/docs/en/plugins/mods/troubleshoot.md#read-the-debug-log) for `settings.read bypassed by cc-plugin-sec-default`. If a line with that text names your mod, ask your organization's administrator to [install the mod as one of the organization's mods](https://code.claude.com/docs/en/plugins/mods/admin.md#install-your-organizations-mods).

326* **The version**: the event firing on Claude Code's own read, and the `e.layers` field, require Claude Code v2.1.304 or later.

327 

328#### What a `settings.read` hook receives

329 

330| Field | Type | What it holds |

331| :- | :- | :- |

332| `e.layers` | array | One `{ source, settings }` object for each source in use that holds settings, lowest [precedence](https://code.claude.com/docs/en/settings.md#settings-precedence) first: `plugin`, `user`, `project`, `local`, `flag`, `policy`. Empty in `claude plugin test`. |

333| `e.source` | string | The one source a mod asked for, as in `$.settings.read({ source: 'policy' })`. `e.layers` then holds that layer alone. Absent on Claude Code's own read and on any other read of the merged settings. |

334 

335In `e.layers`, `plugin` holds settings that enabled plugins supply, and is a layer name only, not a `source` you can pass to `$.settings.read`. `flag` holds the settings passed with `--settings`, and `policy` holds managed settings.

336 

337#### Tell Claude Code's own read from a mod's read

338 

339On [Claude Code's own read](#settings-read-hook), [`next.origin`](https://code.claude.com/docs/en/plugins/mods/reference#the-hook-function) is `{ plugin: 'engine', tier: 'core' }`, and on a mod's read `next.origin.plugin` is the calling mod's name.

340 

341#### What a `settings.read` hook can return

342 

343Your hook can return [`next(e)`](https://code.claude.com/docs/en/plugins/mods/reference#the-hook-function)'s result unchanged, a `{ value }` of its own, or `{ deny: reason }`. On [Claude Code's own read](#settings-read-hook) and a mod's read, a `{ value }` replaces what the read gives and `{ deny: reason }` refuses the read:

344 

345| Return | On Claude Code's own read | On a mod's read |

346| :- | :- | :- |

347| `{ value }` | For each key you change, what you return replaces that key's whole value in the session's merged settings, if it [fits the key's schema](https://code.claude.com/docs/en/plugins/mods/troubleshoot.md#settings-read-key-refused) | That mod's call resolves to your `value`, or to the `key` it asked for taken from your `value`, so return a whole object and not an array |

348| `{ deny: reason }` | The session keeps the settings as they were merged before any hook answered, and the [debug log records your `reason`](https://code.claude.com/docs/en/plugins/mods/troubleshoot#settings-read-refused) | That mod's call rejects with `<calling mod>: $.settings.read: <reason>` |

349 

350On Claude Code's own read, build your `{ value }` from [`next(e)`'s `value`](#settings-read-next), since a key you leave out is unset. Where Claude Code reads a key such as `env` from each source separately, changing it in your `value` [has no effect](https://code.claude.com/docs/en/plugins/mods/troubleshoot.md#settings-read-key-no-effect).

351 

352#### What `next(e)` gives a `settings.read` hook

353 

354`next(e)` resolves to `{ value }` or to `{ deny }`:

355 

356* **`{ value }`**: `value` is the merged settings, or one source's settings when [`e.source`](#settings-read-receives) is set. If a hook that [runs after yours](#the-order-mods-run-in) returned a `{ value }` of its own, you get that hook's `value` instead.

357* **`{ deny }`**: a hook that runs after yours refused the read. Return that `{ deny }` unchanged.

358 

359#### Change one setting from a `settings.read` hook

360 

361First check [which mods get this event, and from which version](#settings-read-hook).

362 

363To change one key, spread the `value` from [`next(e)`](https://code.claude.com/docs/en/plugins/mods/reference#the-hook-function) and set that key, as this hook does with [`spinnerTipsEnabled`](https://code.claude.com/docs/en/settings-reference#spinnertipsenabled). The hook doesn't check [`next.origin`](#settings-read-origin), so the hook changes the key on [Claude Code's own read](#settings-read-hook) and on a mod's merged read alike:

364 

365```javascript theme={null}

366on('settings.read', async ($, e, next) => {

367 const read = await next(e)

368 // Pass through a read of one source, so that only the merged settings change.

369 // Pass through a { deny } from a later hook too: it has no value.

370 if (e.source || !read.value) return read

371 // Keep every other key and change this one

372 return { value: { ...read.value, spinnerTipsEnabled: false } }

373})

374```

375 

376On Claude Code's own read, if your hook returns a value outside the key's schema, such as a string, that key alone keeps the value merged before any hook answered. The debug log then says [`the answer for <key> is no value the key can hold`](https://code.claude.com/docs/en/plugins/mods/troubleshoot#settings-read-key-refused). If your value fits and the key still doesn't change, see [why a returned key has no effect](https://code.claude.com/docs/en/plugins/mods/troubleshoot.md#settings-read-key-no-effect).

377 

308### Handle the settings hook events378### Handle the settings hook events

309 379 

310Settings hooks are the command, HTTP, prompt, and agent hooks you configure in settings files. Each [settings hook event](https://code.claude.com/docs/en/hooks.md#hook-events), such as `Stop`, `SessionEnd`, or `PostToolUse`, is also an event named `classic.` followed by the settings hook event's name, such as `classic.Stop`. `e` is the JSON a settings hook receives on stdin, including `transcript_path`.380Settings hooks are the command, HTTP, prompt, and agent hooks you configure in settings files. Each [settings hook event](https://code.claude.com/docs/en/hooks.md#hook-events), such as `Stop`, `SessionEnd`, or `PostToolUse`, is also an event named `classic.` followed by the settings hook event's name, such as `classic.Stop`. `e` is the JSON a settings hook receives on stdin, including `transcript_path`.

Details

508* **`Input`**: takes `onSubmit(value)` and `onInput(value)`508* **`Input`**: takes `onSubmit(value)` and `onInput(value)`

509* **`Select`**: takes `onSelect(value)` with its choices in `options`, a list of at least one choice with unique values, such as `[{ value: 'sm', label: 'Small' }, { value: 'lg', label: 'Large' }]`509* **`Select`**: takes `onSelect(value)` with its choices in `options`, a list of at least one choice with unique values, such as `[{ value: 'sm', label: 'Small' }, { value: 'lg', label: 'Large' }]`

510 510 

511A test presses or types into a control by its `key`, so give each control one. Each use of a control also fires [`ui.press`, `ui.input`, or `ui.select`](https://code.claude.com/docs/en/plugins/mods/reference#interface) with the `key` in `e.element`, and another mod can handle those events. Its hook runs before your callback, so it sees what the user types into your `Input` and can change it or answer in place of your callback. The mods API has no method that presses another mod's button.511### Which controls need a `key`

512 

513Give every `Input` and `Select` a `key` prop, such as `key: 'size'`. A `Button` can go without a `key` when it has a `label` prop or a single string child. Its key is then the `label` value or that string.

514 

515Tests and other mods identify a control by its key:

516 

517* **Tests**: a [test](https://code.claude.com/docs/en/plugins/mods/test.md#test-a-drawing) presses or types into a control by its key.

518* **Other mods**: Claude Code fires [`ui.press`, `ui.input`, or `ui.select`](https://code.claude.com/docs/en/plugins/mods/reference#interface) with the control's key in `e.element` before it runs the control's callback. Another mod's hook for that event sees what the user typed into your `Input` and can change that text or keep your callback from running. The mods API gives that mod no method to press your buttons.

519 

520If a message says `needs a key` or `is drawn twice`, [find the cause by that message](https://code.claude.com/docs/en/plugins/mods/troubleshoot.md#needs-a-key).

512 521 

513### Keyboard focus and hotkeys522### Keyboard focus and hotkeys

514 523 

Details

21| `.claude-plugin/plugin.json` | Yes | The plugin [manifest](https://code.claude.com/docs/en/plugins/manifest-reference.md). Mods add no required fields. |21| `.claude-plugin/plugin.json` | Yes | The plugin [manifest](https://code.claude.com/docs/en/plugins/manifest-reference.md). Mods add no required fields. |

22| `hooks/hooks.json` | Yes | `modules`: an array with one path, relative to this file, to the hooks module, as in `"modules": ["./register.js"]`. Can also hold [settings hooks](https://code.claude.com/docs/en/hooks.md) under `hooks`. |22| `hooks/hooks.json` | Yes | `modules`: an array with one path, relative to this file, to the hooks module, as in `"modules": ["./register.js"]`. Can also hold [settings hooks](https://code.claude.com/docs/en/hooks.md) under `hooks`. |

23| The hooks module, such as [`hooks/register.js`](https://code.claude.com/docs/en/plugins/mods/create#write-a-mod-yourself) | Yes | The mod's entry point. Exports `register(on, options)`. Named `.js`, `.mjs`, `.cjs`, `.jsx`, `.ts`, `.mts`, `.cts`, or `.tsx`. An ES module. |23| The hooks module, such as [`hooks/register.js`](https://code.claude.com/docs/en/plugins/mods/create#write-a-mod-yourself) | Yes | The mod's entry point. Exports `register(on, options)`. Named `.js`, `.mjs`, `.cjs`, `.jsx`, `.ts`, `.mts`, `.cts`, or `.tsx`. An ES module. |

24| [`types/index.d.ts`](https://code.claude.com/docs/en/plugins/mods/interface#declare-the-values), named by `types` in the manifest | When the mod uses `$.state` or adds a namespace to the mods API | Declares `PluginState` values and any namespace the mod adds |24| [`types/index.d.ts`](https://code.claude.com/docs/en/plugins/mods/interface#declare-the-values), unless `types` in the manifest names another path | When the mod uses `$.state` or adds a namespace to the mods API | Declares `PluginState` values and any namespace the mod adds. To leave `types` out of the manifest, you need v2.1.299 or later. |

25| Files whose names end in `.test.ts` or `.test.tsx` | No | Tests that [`claude plugin test`](https://code.claude.com/docs/en/plugins/mods/test#write-a-test) runs |25| Files whose names end in `.test.ts` or `.test.tsx` | No | Tests that [`claude plugin test`](https://code.claude.com/docs/en/plugins/mods/test#write-a-test) runs |

26 26 

27`register` receives `on` and `options`. `options` holds the values of the [`userConfig`](https://code.claude.com/docs/en/plugins/components#user-configuration) fields the manifest declares, with defaults filled in.27`register` receives `on` and `options`. `options` holds the values of the [`userConfig`](https://code.claude.com/docs/en/plugins/components#user-configuration) fields the manifest declares, with defaults filled in.


110 110 

111### Commands and configuration111### Commands and configuration

112 112 

113Command and configuration events fire when a command runs or is listed, and when a `/config` row is shown or changed:113Command and configuration events fire when a command runs or is listed, when a `/config` row is shown or changed, and on a settings read:

114 114 

115| Event | Fires when | A hook can return |115| Event | Fires when | A hook can return |

116| :- | :- | :- |116| :- | :- | :- |


118| `command.describe` | Once for each command, for the command list | `{ description, argumentHint, isHidden }` |118| `command.describe` | Once for each command, for the command list | `{ description, argumentHint, isHidden }` |

119| `config.set` | A `/config` row is about to change | `next({ ...e, value })` or `{ deny: reason }` |119| `config.set` | A `/config` row is about to change | `next({ ...e, value })` or `{ deny: reason }` |

120| `config.describe` | Once for each `/config` row | `{ label, description, isHidden }` |120| `config.describe` | Once for each `/config` row | `{ label, description, isHidden }` |

121| [`settings.read`](https://code.claude.com/docs/en/plugins/mods/events#settings-read-hook) | A mod calls [`$.settings.read`](https://code.claude.com/docs/en/plugins/mods/api#reach-files-processes-and-the-network), or Claude Code builds the session's merged settings | `next(e)`, `{ value }`, or `{ deny: reason }` |

122 

123#### `e.layers` and `e.source` on `settings.read`

124 

125* **`e.layers`**: one `{ source, settings }` object for each source in use that holds settings, lowest [precedence](https://code.claude.com/docs/en/settings.md#settings-precedence) first. See [What a `settings.read` hook receives](https://code.claude.com/docs/en/plugins/mods/events#settings-read-receives).

126* **`e.source`**: the one source a mod asked for, as in `$.settings.read({ source: 'policy' })`. Absent on Claude Code's own read and on any other read of the merged settings

127 

128On `settings.read`, the event firing on Claude Code's own read and the `e.layers` field require Claude Code v2.1.304 or later. For when the hook runs and what the hook can return, with an example, see [Change or refuse a settings read](https://code.claude.com/docs/en/plugins/mods/events.md#settings-read-hook).

121 129 

122### Turns130### Turns

123 131 

Details

168 168 

169Before v2.1.292, the call ran a second time, so the prompt was submitted, the command run, or the subagent started twice.169Before v2.1.292, the call ran a second time, so the prompt was submitted, the command run, or the subagent started twice.

170 170 

171### `This mod's change didn't load` or `the earlier version is no longer running`

172 

173A change to a [mod Claude wrote in this session](https://code.claude.com/docs/en/plugins/mods/create.md#ask-claude-for-a-mod) couldn't load. The transcript line starts with the mod's name and ends with the reason:

174 

175* `This mod's change didn't load, so the earlier version is still running: <reason>.`

176* `This mod didn't load, and the earlier version is no longer running: <reason>.`

177 

178Claude doesn't see this line, so paste it into your next message when you ask Claude for a fix.

179 

171### `$.agent.register refused: the hooks module that made the call is no longer loaded`180### `$.agent.register refused: the hooks module that made the call is no longer loaded`

172 181 

173The line starts with your mod's name, as in `first-mod: $.agent.register refused: the hooks module that made the call is no longer loaded (it was reloaded or removed)`, and the agent isn't registered. Your mod was reloaded or unloaded before the call. A reload loads a fresh copy of the hooks module, and this call came from code still running in the old copy, such as a hook that hadn't returned yet.182The line starts with your mod's name, as in `first-mod: $.agent.register refused: the hooks module that made the call is no longer loaded (it was reloaded or removed)`, and the agent isn't registered. Your mod was reloaded or unloaded before the call. A reload loads a fresh copy of the hooks module, and this call came from code still running in the old copy, such as a hook that hadn't returned yet.


225 234 

226Read the reason on that line. Common causes are a prop the element doesn't take and an element the app doesn't have.235Read the reason on that line. Common causes are a prop the element doesn't take and an element the app doesn't have.

227 236 

237### `needs a key`, `is drawn twice`, or `key each once`

238 

239An element in the tree your `ui.render` hook returns has no valid [`key`](https://code.claude.com/docs/en/plugins/mods/interface#which-controls-need-a-key), or two elements share one. Find the message you got:

240 

241* **`<Input> needs a key` or `<Select> needs a key`**: the element has no `key` prop, or its `key` is empty or isn't a string, as in `key: 3`. Give it a non-empty string as its `key`.

242* **`<Button> needs a key`**: give the button a non-empty string as its `key`

243* **`is drawn twice; each takes its own key`**: two elements of the kind the message names have the same `key`, as in `Input "size" is drawn twice; each takes its own key`. Give each element its own `key`.

244* **`key each once` from `press` in a [test](https://code.claude.com/docs/en/plugins/mods/test.md#test-a-drawing)**: the drawing has more than one button with the key you passed. Buttons with the same label and no `key` prop share that label as their key. Give each button its own `key`.

245 

228### A `ui.render` line says `threw while drawn`246### A `ui.render` line says `threw while drawn`

229 247 

230The line names the [render site](https://code.claude.com/docs/en/plugins/mods/reference.md#render-sites), then says `threw while drawn:` and the error, as in `first-mod: ui.render (ToolUse) threw while drawn: <error>; the engine drew its own`. Claude Code hit that error while drawing the tree your [`ui.render`](https://code.claude.com/docs/en/plugins/mods/reference#interface) hook returned, or while drawing the site from the [`props` your hook passed to `next`](https://code.claude.com/docs/en/plugins/mods/interface#change-what-claude-code-already-draws). The ending `the engine drew its own` means the site shows Claude Code's usual content.248The line names the [render site](https://code.claude.com/docs/en/plugins/mods/reference.md#render-sites), then says `threw while drawn:` and the error, as in `first-mod: ui.render (ToolUse) threw while drawn: <error>; the engine drew its own`. Claude Code hit that error while drawing the tree your [`ui.render`](https://code.claude.com/docs/en/plugins/mods/reference#interface) hook returned, or while drawing the site from the [`props` your hook passed to `next`](https://code.claude.com/docs/en/plugins/mods/interface#change-what-claude-code-already-draws). The ending `the engine drew its own` means the site shows Claude Code's usual content.


303 321 

304[Load the saved value again](https://code.claude.com/docs/en/plugins/mods/interface.md#load-a-saved-value-again-after-clear) in a `classic.SessionStart` hook.322[Load the saved value again](https://code.claude.com/docs/en/plugins/mods/interface.md#load-a-saved-value-again-after-clear) in a `classic.SessionStart` hook.

305 323 

324### A key your `settings.read` hook returns doesn't take effect

325 

326Returned `env` entries don't become environment variables. Returned `allow`, `ask`, and `deny` rules aren't checked on tool calls. Set those in a [settings file](https://code.claude.com/docs/en/settings.md), or call [`$.env.set`](https://code.claude.com/docs/en/plugins/mods/api#reach-files-processes-and-the-network) for environment variables.

327 

328For another key, check [which mods get `settings.read` and from which version](https://code.claude.com/docs/en/plugins/mods/events#settings-read-hook), then search the [debug log](#read-the-debug-log) for `settings.read` and look for one of these lines:

329 

330| Log line | Meaning and step |

331| :- | :- |

332| `settings.read hook skipped`, after your mod's name | Your hook failed. [Fix the error the line reports](#hook-skipped). |

333| `settings.read bypassed by cc-plugin-sec-default`, on a line that names your mod ahead of it | The [built-in guard](https://code.claude.com/docs/en/plugins/mods/admin.md#know-what-happens-by-default) skipped your hook. Ask your organization's administrator to [install the mod as one of the organization's mods](https://code.claude.com/docs/en/plugins/mods/admin.md#install-your-organizations-mods). |

334| `settings.read: the answer for <key> is no value the key can hold` | The returned value doesn't fit the key's schema. [Return one it allows](#settings-read-key-refused). |

335| `settings.read: the merge never settles for <key>` | The keys the line names keep the settings sources' values. Set them in a settings file. |

336| `answered settings.read without next()`, after a mod's name | Relevant only if that mod [runs before yours](https://code.claude.com/docs/en/plugins/mods/events.md#the-order-mods-run-in). Then your hook didn't run on that read. [Turn that mod off](https://code.claude.com/docs/en/plugins/mods/overview.md#turn-mods-on-or-off), or if your organization deployed it, ask its administrator to. |

337| `settings.read: refused to the engine` | The read was refused, so no hook's `{ value }` applied. [Find what refused it](#settings-read-refused). |

338 

339If no line explains the key, check the mods that run before yours for a `settings.read` hook that [changes the key](https://code.claude.com/docs/en/plugins/mods/events.md#settings-read-example). Turn that mod off, or ask your organization's administrator to. If no hook does, set the key in a settings file.

340 

341### `the answer for <key> is no value the key can hold`

342 

343This [debug log](#read-the-debug-log) line means Claude Code refused the value your [`settings.read`](https://code.claude.com/docs/en/plugins/mods/events#settings-read-hook) hook returned for the named key, and that key alone:

344 

345```text theme={null}

346settings.read: the answer for <key> is no value the key can hold; the settings' own value stands

347```

348 

349The value you returned for the named key didn't fit that key's schema, for example by type or by range. Return a value that the key's [settings reference](https://code.claude.com/docs/en/settings-reference.md) entry allows. While your value doesn't fit, the key keeps the value merged from the settings sources before any hook answered. The line calls it the settings' own value.

350 

351### `settings.read: refused to the engine`

352 

353This [debug log](#read-the-debug-log) line means [Claude Code's own read](https://code.claude.com/docs/en/plugins/mods/events.md#settings-read-hook) was refused, so no hook's `{ value }` applied, yours included. When a `settings.read` hook refuses that read with [`{ deny: reason }`](https://code.claude.com/docs/en/plugins/mods/events#settings-read-returns), the line carries that hook's reason:

354 

355```text theme={null}

356settings.read: refused to the engine (engine: $.settings.read: <reason>); the settings' own values stand

357```

358 

359Search your own hook's code for the `<reason>` text:

360 

361* **Your code has it**: your hook refused the read. Make it return `{ value }` when [`next.origin`](https://code.claude.com/docs/en/plugins/mods/events#settings-read-origin) shows Claude Code's own read.

362* **Your code doesn't have it**: [turn off](https://code.claude.com/docs/en/plugins/mods/overview.md#turn-mods-on-or-off) your other mods one at a time. After each, rerun this session's command from your shell with one `--debug-file` on a new path, and search that file for `refused to the engine`. If the line is there, turn off the next mod. If not, the last mod you turned off refused the read, so keep it off.

363 

364With no other mod left, use a [settings file](https://code.claude.com/docs/en/settings.md) for the keys your hook returns. Its values hold while the read is refused.

365 

306## Read the debug log366## Read the debug log

307 367 

308The debug log has a line for every module Claude Code loads or refuses, every hook that fails, and every result it refuses, so it's where to look when the transcript shows nothing. To write one, in your shell start Claude Code with `--debug`, or with `--debug-file <path>` to choose where it goes:368The debug log has a line for every module Claude Code loads or refuses, every hook that fails, and every result it refuses, so it's where to look when the transcript shows nothing. To write one, in your shell start Claude Code with `--debug`, or with `--debug-file <path>` to choose where it goes:

Details

251 251 

252First check the repository itself: a misspelled `owner/repo`, a repository that doesn't exist, or a private repository you can't see also ends in this message. Open the repository URL in your browser, or run `git ls-remote <url>` in your terminal, to confirm it exists and you have access.252First check the repository itself: a misspelled `owner/repo`, a repository that doesn't exist, or a private repository you can't see also ends in this message. Open the repository URL in your browser, or run `git ls-remote <url>` in your terminal, to confirm it exists and you have access.

253 253 

254If the repository is right, the cause is credentials. Claude Code runs git with interactive prompts disabled, so it can't ask you for a password, a key passphrase, or a credential the way your terminal would. If git needs to prompt, you see `fatal: Cannot prompt because user interactivity has been disabled` or `terminal prompts disabled` in the original error. Only credentials that already work non-interactively succeed:254If the repository is right, the cause is credentials. Claude Code turns off git's prompts and askpass programs, including one set in `GIT_ASKPASS`, and runs SSH in batch mode. When git needs to prompt, the clone's error includes `fatal: Cannot prompt because user interactivity has been disabled`, `terminal prompts disabled`, or `fatal: unable to get password from user`. Only credentials git can get without a prompt or askpass program succeed:

255 255 

256* **SSH**: `ssh -T git@<host>` must succeed without prompting for a passphrase, and the host must already be in `known_hosts`256* **SSH**: `ssh -T git@<host>` must succeed without prompting for a passphrase, and the host must already be in `known_hosts`

257* **HTTPS**: your credential helper must hold a token for the host. For GitHub, run `gh auth login` and `gh auth setup-git`. For another host, store a personal access token in your git credential helper. Test with `git ls-remote <url>`257* **HTTPS**: your credential helper must hold a token for the host. For GitHub, run `gh auth login` and `gh auth setup-git`. For another host, store a personal access token in your git credential helper. To test, unset `GIT_ASKPASS` in your terminal and run `git -c core.askPass= ls-remote <url>`.

258 258 

259Once `git ls-remote` succeeds in your terminal without a prompt, run the add or update again. A successful add prints `Successfully added marketplace: <name>`. A successful update prints `Successfully updated marketplace: <name>` from your shell, or `✔ Updated 1 marketplace` in a session.259Once the check for your protocol succeeds without a prompt, run the add or update again. A successful add prints `Successfully added marketplace: <name>`. A successful update prints `Successfully updated marketplace: <name>` from your shell, or `✔ Updated 1 marketplace` in a session.

260 260 

261To make Claude Code skip SSH for GitHub `owner/repo` sources, set `CLAUDE_CODE_PLUGIN_PREFER_HTTPS=1`. Without it, Claude Code clones those sources over SSH when an SSH key for `github.com` looks configured, and falls back to HTTPS when the SSH clone fails.261To make Claude Code skip SSH for GitHub `owner/repo` sources, set `CLAUDE_CODE_PLUGIN_PREFER_HTTPS=1`. Without it, Claude Code clones those sources over SSH when an SSH key for `github.com` looks configured, and falls back to HTTPS when the SSH clone fails.

262 262 


318 318 

319If the repository is a monorepo, limit the checkout to the directories you name with `claude plugin marketplace add <source> --sparse <paths>`.319If the repository is a monorepo, limit the checkout to the directories you name with `claude plugin marketplace add <source> --sparse <paths>`.

320 320 

321If the repository has large git submodules, update Claude Code. On v2.1.295 and later, Claude Code fetches only the [submodules that hold plugin files](https://code.claude.com/docs/en/plugins/marketplace-reference.md#git-submodules-in-the-marketplace-repository). Earlier versions fetch every submodule, which can use up the 120 seconds on its own.

322 

321### Marketplace updates keep failing offline323### Marketplace updates keep failing offline

322 324 

323You work in an environment where the marketplace's git host is unreachable, and every session repeats a failed refresh in the background. Your existing checkout of the marketplace stays in place and startup isn't delayed.325You work in an environment where the marketplace's git host is unreachable, and every session repeats a failed refresh in the background. Your existing checkout of the marketplace stays in place and startup isn't delayed.


609| `<Plugin or Dependency> "<name>" has conflicting version requirements` | No version satisfies every range that pins it. The message lists the ranges. | Uninstall or update one of the conflicting plugins, or ask the upstream author to widen its constraint. |611| `<Plugin or Dependency> "<name>" has conflicting version requirements` | No version satisfies every range that pins it. The message lists the ranges. | Uninstall or update one of the conflicting plugins, or ask the upstream author to widen its constraint. |

610| `... has version requirements too complex to intersect` or `has an invalid version requirement` | A range isn't valid semver, or the combined ranges can't be intersected. | Fix the invalid range or simplify long `\|\|` chains. |612| `... has version requirements too complex to intersect` or `has an invalid version requirement` | A range isn't valid semver, or the combined ranges can't be intersected. | Fix the invalid range or simplify long `\|\|` chains. |

611| `... has no git tag satisfying <range>` | The dependency's repository has no `<name>--v*` tag in the range. | Check that the upstream tags releases with that convention, or relax the range. |613| `... has no git tag satisfying <range>` | The dependency's repository has no `<name>--v*` tag in the range. | Check that the upstream tags releases with that convention, or relax the range. |

612| `Dependency "<dep>" (required by <plugin>) is in <marketplace>, which is not in the allowlist` | The dependency is in a different marketplace, and cross-marketplace resolution is off by default. | Install the dependency yourself at the same scope, in your shell with `claude plugin install <dep>@<marketplace>` plus the `--scope` you're installing the plugin at, then retry. |614| `Dependency "<dep>" (required by <plugin>) is in marketplace "<marketplace>", which is not in the allowlist` | The dependency is in a different marketplace, and cross-marketplace resolution is off by default. | Install the dependency yourself at the same scope, in your shell with `claude plugin install <dep>@<marketplace>` plus the `--scope` you're installing the plugin at, then retry. |

613 615 

614To see these programmatically, run `claude plugin list --json` in your shell. Plugins with problems carry an `errors` field with the messages and an `errorDetails` field with a `type` for each: the first three rows are `dependency-unsatisfied` and the fourth is `dependency-version-unsatisfied`.616To see these programmatically, run `claude plugin list --json` in your shell. Plugins with problems carry an `errors` field with the messages and an `errorDetails` field with a `type` for each: the first three rows are `dependency-unsatisfied` and the fourth is `dependency-version-unsatisfied`.

615 617 


979 981 

980### `${CLAUDE_PLUGIN_ROOT}` shows forward slashes on Windows982### `${CLAUDE_PLUGIN_ROOT}` shows forward slashes on Windows

981 983 

982On Windows, a plugin hook receives `${CLAUDE_PLUGIN_ROOT}` as `C:/Users/you/...` rather than `C:\Users\you\...`, and a script that expected backslashes breaks.984On Windows, a plugin hook that runs through Git Bash receives `${CLAUDE_PLUGIN_ROOT}` as `C:/Users/you/...` rather than `C:\Users\you\...`, and a script that expected backslashes breaks.

983 985 

984Claude Code runs shell-form hooks through Git Bash on Windows and substitutes the plugin root in the forward-slash Win32 form on purpose. Bash builtins, MSYS tools, and native Windows binaries all accept that form.986With Git Bash installed, a [shell-form hook](https://code.claude.com/docs/en/hooks.md#exec-form-and-shell-form) runs through Git Bash by default. For a hook that runs through Git Bash, Claude Code passes the path with forward slashes so that Bash doesn't read backslashes as escapes. Bash builtins, MSYS tools, and native Windows binaries all accept that form.

985 987 

986If your script needs backslashes, switch the hook to one of the forms that keep native paths, described under [exec form and shell form](https://code.claude.com/docs/en/hooks.md#exec-form-and-shell-form):988If your script needs backslashes, switch the hook to one of the forms that keep native paths, described under [exec form and shell form](https://code.claude.com/docs/en/hooks.md#exec-form-and-shell-form):

987 989 


1090 1092 

1091Alternatively, host the marketplace in a git repository and tell users to add it with the repository URL. For a git source, Claude Code clones the whole repository, so relative paths resolve. Source types are on the [marketplace reference](https://code.claude.com/docs/en/plugins/marketplace-reference.md).1093Alternatively, host the marketplace in a git repository and tell users to add it with the repository URL. For a git source, Claude Code clones the whole repository, so relative paths resolve. Source types are on the [marketplace reference](https://code.claude.com/docs/en/plugins/marketplace-reference.md).

1092 1094 

1095### A root plugin's files from a git submodule are missing after install

1096 

1097Your plugin is at the marketplace root and runs or reads a file from a git submodule of the repository. After install, the submodule's directory is empty. Before v2.1.295, Claude Code fetched every submodule, so the directory was populated.

1098 

1099When Claude Code clones your marketplace, it fetches only the [submodules that hold plugin files](https://code.claude.com/docs/en/plugins/marketplace-reference.md#git-submodules-in-the-marketplace-repository). For a plugin at the root, it decides by reading the paths in the plugin's configuration and the text of the plugin's files. It can't see a path that a script builds while it runs.

1100 

1101Write a path into the submodule out in full where Claude Code can read it, such as `${CLAUDE_PLUGIN_ROOT}/vendor/tool/run.sh` in a hook command. Claude Code then fetches every submodule in the repository for that plugin.

1102 

1093### Marketplace validation errors1103### Marketplace validation errors

1094 1104 

1095You ran `claude plugin validate .` from your marketplace directory and it reported errors or warnings on the marketplace file itself.1105You ran `claude plugin validate .` from your marketplace directory and it reported errors or warnings on the marketplace file itself.


1121 1131 

1122### `Marketplace source '<source>' is blocked by enterprise policy`1132### `Marketplace source '<source>' is blocked by enterprise policy`

1123 1133 

1124You ran `/plugin marketplace add`, `update`, or an install, and Claude Code refused with this line. For a GitHub or git source, the host follows the source in parentheses, as in `'github:owner/repo' (github.com)`.1134You ran `/plugin marketplace add`, `update`, or an install, and Claude Code refused with this line.

1125 1135 

1126Your administrator set `blockedMarketplaces` or `strictKnownMarketplaces` in managed settings, and this source isn't permitted. Ask your administrator to allow the source, or add one of the allowed sources the message lists.1136Your administrator set `blockedMarketplaces` or `strictKnownMarketplaces` in managed settings, and this source isn't permitted. Ask your administrator to allow the source, or add one of the allowed sources the message lists.

1127 1137 

Details

100 100 

101### Turning on fast mode101### Turning on fast mode

102 102 

103Enabling [fast mode](https://code.claude.com/docs/en/fast-mode.md) adds a request header that is part of the cache key, so the first request Claude Code sends with fast mode on reads the entire conversation history with no cache hits. Claude Code sets that header once when a turn starts and keeps it for the whole turn, so when you turn fast mode on while Claude is working, the cache miss from the header happens on the first request of your next turn. Those uncached input tokens are billed at [fast mode rates](https://code.claude.com/docs/en/fast-mode.md#understand-the-cost-tradeoff), which is why turning it on at the start of a session costs less than turning it on deep into a long one. If your current model doesn't support fast mode, enabling fast mode also [switches your model](#switching-models), and that switch starts a fresh cache on its own from the next request in the running turn.103[Fast mode](https://code.claude.com/docs/en/fast-mode.md) and standard speed keep separate caches, so after you turn fast mode on or off, the next request can't use what the other speed cached. The first time you turn fast mode on in a conversation, the next request reads the whole conversation so far uncached at [fast mode rates](https://code.claude.com/docs/en/fast-mode.md#understand-the-cost-tradeoff). To keep that cost small, turn it on at the start of a session.

104 104 

105The cost applies once per conversation. After the first fast mode turn, Claude Code keeps sending the header and varies only the request's speed setting, which is not part of the cache key. Turning fast mode off, the [automatic fallback to standard speed](https://code.claude.com/docs/en/fast-mode.md#handle-rate-limits) after a rate limit, and turning it back on later all keep the cache. If you [run out of usage credits](https://code.claude.com/docs/en/fast-mode.md#handle-rate-limits) mid-session, Claude Code retries each rejected fast mode request at standard speed the same way, so this fallback also keeps the cache. `/clear` and `/compact` reset this, since they rebuild the cache at those points anyway.105* If you turn it on while Claude is working, that turn finishes at standard speed, and you pay for any uncached read on your next turn's first request.

106* If your current model doesn't support fast mode, enabling fast mode also [switches you to Opus](https://code.claude.com/docs/en/fast-mode.md#toggle-fast-mode). That [model switch](#switching-models) starts a fresh cache on its own from the next request in the running turn.

107 

108Each later toggle reads uncached whatever the speed you switch to doesn't have cached. Speed changes Claude Code makes on its own, such as the [fallback to standard speed](https://code.claude.com/docs/en/fast-mode.md#handle-rate-limits) after a rate limit and the return to fast mode later, count as toggles too.

106 109 

107### Connecting or removing an MCP server110### Connecting or removing an MCP server

108 111 


184>187>

185> Compaction works in your favor when the context you discard is content you no longer need. To choose when its overhead happens, run `/compact` at a natural break in your work, such as between tasks, instead of waiting for auto-compaction to trigger mid-task. If you've gone down a path you want to abandon entirely, [`/rewind`](#rewinding-the-conversation) to an earlier turn instead. Rewinding truncates back to a prefix that is already cached, rather than building a new one as compaction does.188> Compaction works in your favor when the context you discard is content you no longer need. To choose when its overhead happens, run `/compact` at a natural break in your work, such as between tasks, instead of waiting for auto-compaction to trigger mid-task. If you've gone down a path you want to abandon entirely, [`/rewind`](#rewinding-the-conversation) to an earlier turn instead. Rewinding truncates back to a prefix that is already cached, rather than building a new one as compaction does.

186 189 

187If you leave a long conversation idle in a terminal session while it is on the [one-hour TTL](#which-ttl-each-request-gets), Claude Code can compact it shortly before the cache expires. To turn idle compaction off, set [`idleCompaction`](https://code.claude.com/docs/en/settings-reference#idlecompaction) to `false`, which requires Claude Code v2.1.290 or later.190If you leave a long conversation idle while it is on the [one-hour TTL](#which-ttl-each-request-gets), Claude Code can compact it. To turn idle compaction off, set [`idleCompaction`](https://code.claude.com/docs/en/settings-reference#idlecompaction) to `false`, which requires Claude Code v2.1.290 or later.

188 191 

189### Accumulating many images192### Accumulating many images

190 193 


309 312 

310In Claude Code, the cache is effectively scoped to one machine and directory. The system prompt embeds your auto memory paths, and the conversation opens with an announcement of the working directory, platform, shell, and OS version. Two sessions in different directories therefore build different prefixes and miss each other's cache.313In Claude Code, the cache is effectively scoped to one machine and directory. The system prompt embeds your auto memory paths, and the conversation opens with an announcement of the working directory, platform, shell, and OS version. Two sessions in different directories therefore build different prefixes and miss each other's cache.

311 314 

312Sessions you run in parallel in the same directory build matching prefixes and read each other's cache. Sequential sessions share the prefix only when the git status snapshot taken at startup matches, since each conversation also carries the branch and recent commits from that snapshot.315* Sessions you run in parallel in the same directory build matching prefixes and can read each other's cache.

316* Sequential sessions share the prefix only when the git status snapshot taken at startup matches, since each conversation also carries the branch and recent commits from that snapshot.

317 

318The underlying API cache is broader. Caches are isolated between organizations, and on some providers, [between workspaces within an organization](https://platform.claude.com/docs/en/build-with-claude/prompt-caching#cache-storage-and-sharing). Within those boundaries, two requests share a cache only when their model, [speed](#turning-on-fast-mode), and prefix match.

313 319 

314The underlying API cache is broader. Caches are isolated between organizations, and on some providers, [between workspaces within an organization](https://platform.claude.com/docs/en/build-with-claude/prompt-caching#cache-storage-and-sharing). Within those boundaries, any two requests with the same model and prefix read the same cache. For Agent SDK callers running fleets of automated processes, see [improve prompt caching across users and machines](https://code.claude.com/docs/en/agent-sdk/modifying-system-prompts.md#improve-prompt-caching-across-users-and-machines) to move the auto memory location out of the system prompt and share the system prompt's cache entry across users and machines.320For Agent SDK callers running fleets of automated processes, see [improve prompt caching across users and machines](https://code.claude.com/docs/en/agent-sdk/modifying-system-prompts.md#improve-prompt-caching-across-users-and-machines) to move the auto memory location out of the system prompt.

315 321 

316## Check cache performance322## Check cache performance

317 323 

Details

179* **Diff of your changes**: when the session's directory is in a git repository, a connected device's diff pane shows your changes. On a branch that has commits ahead of the repository's default branch, the pane shows the changes since the branch split from it, including your uncommitted edits. On the default branch itself, or on a branch that isn't ahead of it, the pane shows only your uncommitted changes.179* **Diff of your changes**: when the session's directory is in a git repository, a connected device's diff pane shows your changes. On a branch that has commits ahead of the repository's default branch, the pane shows the changes since the branch split from it, including your uncommitted edits. On the default branch itself, or on a branch that isn't ahead of it, the pane shows only your uncommitted changes.

180* **Model**: when you pick a [model](https://code.claude.com/docs/en/model-config.md) from a connected device, Claude Code runs the session on that model. Requires Claude Code v2.1.238 or later. A model you pick from the device's model control applies to the current session only. When you send `/model <name>` from the device to an interactive session, Claude Code also sets your default for new sessions.180* **Model**: when you pick a [model](https://code.claude.com/docs/en/model-config.md) from a connected device, Claude Code runs the session on that model. Requires Claude Code v2.1.238 or later. A model you pick from the device's model control applies to the current session only. When you send `/model <name>` from the device to an interactive session, Claude Code also sets your default for new sessions.

181* **Effort level**: when you set the [effort level](https://code.claude.com/docs/en/model-config.md#adjust-effort-level) from a connected device, with `/effort` or the device's effort control, Claude Code applies it to the session on your machine. If you pinned a level with `CLAUDE_CODE_EFFORT_LEVEL`, the session keeps that level, and Claude Code refuses a different pick from the effort control. Picking a level from the effort control requires Claude Code v2.1.234 or later on your machine.181* **Effort level**: when you set the [effort level](https://code.claude.com/docs/en/model-config.md#adjust-effort-level) from a connected device, with `/effort` or the device's effort control, Claude Code applies it to the session on your machine. If you pinned a level with `CLAUDE_CODE_EFFORT_LEVEL`, the session keeps that level, and Claude Code refuses a different pick from the effort control. Picking a level from the effort control requires Claude Code v2.1.234 or later on your machine.

182* **Reconnecting after a connection failure**: run `/remote-control` to reconnect. If compaction rewrote the conversation or you switched conversations with `/resume` in the meantime, Claude Code archives the server session it was using instead of leaving it in the session list. You can still find it by [filtering for archived sessions](https://code.claude.com/docs/en/claude-code-on-the-web.md#archive-sessions). Switching conversations while a device is still connected doesn't archive the session.182* **Reconnecting after a connection failure**: run `/remote-control` to reconnect. If compaction rewrote the conversation or you switched conversations with `/resume` in the meantime, Claude Code archives the server session it was using instead of leaving it in the session list. You can still find that session among your [archived sessions](https://code.claude.com/docs/en/claude-code-on-the-web.md#find-an-archived-session) at claude.ai/code. Switching conversations while a device is still connected doesn't archive the session.

183 183 

184### Enable Remote Control for all sessions184### Enable Remote Control for all sessions

185 185 


401 401 

402## Troubleshooting402## Troubleshooting

403 403 

404### "Remote Control disconnected" or "Can't reach"

405 

406At [claude.ai/code](https://claude.ai/code) or in the Desktop app, **Remote Control disconnected** or a **Can't reach** message means your browser or app lost contact with Claude Code on your computer. Neither message tells you whether Claude or a subagent you were watching is still working on your computer. On that computer, check the state Claude Code is in and follow the matching step to reconnect:

407 

408* **An interactive session shows `Remote Control disconnected`**: follow [the reconnect steps for the reason that line gives](#session-ended-elsewhere)

409* **Claude Code is running and shows no failure**: an interactive session reconnects by itself once the machine is awake and online, so you don't need to act. If you used `claude remote-control`, see **Extended network outage** under [Limitations](#limitations)

410* **Claude Code isn't running**: [start it again and bring the session back](#resume-sessions-after-stopping-the-server)

411 

404### "Remote Control requires a claude.ai subscription"412### "Remote Control requires a claude.ai subscription"

405 413 

406You're not signed in with a claude.ai account, or another credential is taking precedence over your login. The message takes one of these forms:414You're not signed in with a claude.ai account, or another credential is taking precedence over your login. The message takes one of these forms:


463* **With `/remote-control`, `claude --remote-control`, or [auto-connect](#enable-remote-control-for-all-sessions)**: the session keeps running without Remote Control, and Claude Code archives it at claude.ai471* **With `/remote-control`, `claude --remote-control`, or [auto-connect](#enable-remote-control-for-all-sessions)**: the session keeps running without Remote Control, and Claude Code archives it at claude.ai

464* **With `claude remote-control`**: the server stops and archives the sessions it was serving, then exits472* **With `claude remote-control`**: the server stops and archives the sessions it was serving, then exits

465 473 

466You can still find an archived session by [filtering for archived sessions](https://code.claude.com/docs/en/claude-code-on-the-web.md#archive-sessions).474To find one of these sessions again, open your [archived sessions](https://code.claude.com/docs/en/claude-code-on-the-web.md#find-an-archived-session) at claude.ai/code.

467 475 

468Remote Control doesn't reconnect on its own. To turn it back on after your organization allows it again, run `/remote-control` in the session or `claude remote-control` in your shell. Either command fails with [`Remote Control is disabled by your organization's policy`](#remote-control-is-disabled-by-your-organizations-policy) until Claude Code on this machine has fetched the changed policy. An open session fetches it about once an hour. To find out what is blocking Remote Control, match the full text the command prints against that entry.476Remote Control doesn't reconnect on its own. To turn it back on after your organization allows it again, run `/remote-control` in the session or `claude remote-control` in your shell. Either command fails with [`Remote Control is disabled by your organization's policy`](#remote-control-is-disabled-by-your-organizations-policy) until Claude Code on this machine has fetched the changed policy. An open session fetches it about once an hour. To find out what is blocking Remote Control, match the full text the command prints against that entry.

469 477 

routines.md +24 −4

Details

293 293 

294#### Supported events294#### Supported events

295 295 

296GitHub triggers can subscribe to either of the following event categories. Within each category you can pick a specific action, such as `pull_request.opened`, or react to all actions in the category.296Choose an event from any of the following categories. Within each category you can pick a specific action, such as `pull_request.opened`, or react to all actions in the category.

297 297 

298| Event | Triggers when |298| Event | Triggers when |

299| :- | :- |299| :- | :- |

300| Pull request | A PR is opened, closed, assigned, labeled, synchronized, or otherwise updated |300| Pull request | A PR is opened, closed, assigned, labeled, synchronized, or otherwise updated |

301| Release | A release is created, published, edited, or deleted |301| Release | A release is created, published, edited, or deleted |

302| Issue | An issue is opened, edited, closed, reopened, labeled, assigned, or otherwise updated |

302 303 

303#### Filter pull requests304#### Filter pull requests

304 305 


333 334 

334Click any run to open it as a full session. From there you can see what Claude did, review changes, create a pull request, or continue the conversation. Each run session works like any other session: use the dropdown menu next to the session title to rename, archive, or delete it.335Click any run to open it as a full session. From there you can see what Claude did, review changes, create a pull request, or continue the conversation. Each run session works like any other session: use the dropdown menu next to the session title to rename, archive, or delete it.

335 336 

336> [!NOTE]337Under **History** on the task's detail page, each finished run's row ends with **Error** if the run failed, **Cancelled** if it was cancelled, and neither word if it succeeded. The **Status** filter names the same three outcomes **Failed**, **Cancelled**, and **Succeeded**. These outcomes say how the session ended, not whether Claude completed the work your prompt describes, so open the run and read its transcript to see what happened.

337>338 

338> A green status in the run list means the session started and exited without an infrastructure error. It does not mean the work your prompt describes succeeded. Open the run to read the transcript and confirm what Claude actually did. Blocked network requests, missing connector tools, and failures in the work itself all surface there rather than in the status indicator.339* **Succeeded**: the session ended without Claude Code reporting a failure. Blocked network requests, missing connector tools, and work Claude couldn't complete appear in the transcript rather than on the row

340* **Failed**: the session didn't finish normally. For example, it stopped unexpectedly, ended on an error, or was archived before the run started

341* **Cancelled**: the run didn't fail, and its session was archived. If you archive the session of a run that succeeded, the run changes to **Cancelled**. Nothing in the task needs to change

342 

343If a warning appears under **History**, see ["The last run" warnings](#the-last-run-didnt-start).

339 344 

340### Edit and control scheduled tasks345### Edit and control scheduled tasks

341 346 


499 504 

500An Owner in your Team or Enterprise organization has likely turned off the **Scheduled tasks (Was Routines)** toggle at [**Organization settings > Capabilities > Remote sessions**](https://claude.ai/admin-settings/capabilities). On Claude Code v2.1.227 or later, the same toggle also hides `/schedule` in the CLI. This is a server-side organization setting, so it cannot be overridden from your local configuration. Ask an Owner to turn scheduled tasks back on for your organization.505An Owner in your Team or Enterprise organization has likely turned off the **Scheduled tasks (Was Routines)** toggle at [**Organization settings > Capabilities > Remote sessions**](https://claude.ai/admin-settings/capabilities). On Claude Code v2.1.227 or later, the same toggle also hides `/schedule` in the CLI. This is a server-side organization setting, so it cannot be overridden from your local configuration. Ask an Owner to turn scheduled tasks back on for your organization.

501 506 

507### "The last run" warnings

508 

509When a warning under **History** begins with "The last run", find it in the first column and do what its row says. The warning clears once a later run starts.

510 

511| Warning | What to do |

512| :- | :- |

513| "The last run didn't start because your organization had reached its limit on cloud sessions running at once." | The task needs no change. Click **Run now** later, or wait for the next run |

514| "The last run didn't start because its cloud environment couldn't be found or used." | On the task's detail page, open the menu next to its name, select **Edit**, and find the [cloud environment selector](#environments-and-network-access). If it reads **Unavailable environment**, that environment was archived or is no longer available to your account, so choose another one there and save your changes. Otherwise, retry with **Run now** on the detail page, or pick another environment in the selector and save your changes |

515| "The last run was blocked because it couldn't access something it needs, or your organization's policy doesn't allow it." | Check that your [GitHub access](#repositories-and-branch-permissions) covers the task's repositories. If it does, ask an [Owner](https://code.claude.com/docs/en/server-managed-settings.md#access-control) of your Claude organization whether a policy blocks the task |

516| "The last run didn't start because of a problem that's usually temporary." | Click **Run now** to try again, or wait for the next run |

517| "The last run didn't start because its repository or branch wasn't available." | Check on GitHub that each repository in the task has the [branch the run starts from](#repositories-and-branch-permissions). Also check that your [GitHub access](#repositories-and-branch-permissions) covers each repository, and reconnect GitHub if your connection expired |

518| "The last run didn't start because some of its settings weren't accepted." | On the task's detail page, open the menu next to its name and select **Edit**. The dialog doesn't mark which setting wasn't accepted, so check each one there, including the task's name, prompt, model, repositories, environment, connectors, and triggers |

519| "The last run stopped because a usage limit was reached." | For when the task's runs can start again after a usage limit, see [Usage and limits](#usage-and-limits) |

520| "The last run failed." | Click **Run now** to try again, or wait for the next run. The failed run has no session to open |

521 

502## Related resources522## Related resources

503 523 

504* [`/loop` and in-session scheduling](https://code.claude.com/docs/en/scheduled-tasks): schedule local tasks within an open CLI session524* [`/loop` and in-session scheduling](https://code.claude.com/docs/en/scheduled-tasks): schedule local tasks within an open CLI session

sandboxing.md +26 −2

Details

223* **An ask rule for the parameter**: add an [ask rule](https://code.claude.com/docs/en/permissions.md#match-by-input-parameter) for `Bash(dangerouslyDisableSandbox:true)` to be prompted on Bash retries. You get the prompt in auto mode and `bypassPermissions` mode too, and the rule takes precedence over a matching allow rule223* **An ask rule for the parameter**: add an [ask rule](https://code.claude.com/docs/en/permissions.md#match-by-input-parameter) for `Bash(dangerouslyDisableSandbox:true)` to be prompted on Bash retries. You get the prompt in auto mode and `bypassPermissions` mode too, and the rule takes precedence over a matching allow rule

224* **[`permissions.blockReadsOutsideWorkingDirectories`](https://code.claude.com/docs/en/settings-reference#permissions-blockreadsoutsideworkingdirectories)**: [Actions no mode auto-approves](https://code.claude.com/docs/en/permission-modes.md#actions-no-mode-auto-approves) covers the retries that prompt while it's on224* **[`permissions.blockReadsOutsideWorkingDirectories`](https://code.claude.com/docs/en/settings-reference#permissions-blockreadsoutsideworkingdirectories)**: [Actions no mode auto-approves](https://code.claude.com/docs/en/permission-modes.md#actions-no-mode-auto-approves) covers the retries that prompt while it's on

225 225 

226While commands are refused with a [`Sandbox is required` message](#commands-refused-with-sandbox-is-required), Claude Code ignores the `dangerouslyDisableSandbox` parameter and refuses the retry too.

227 

226#### Turn off the retry with strict sandbox mode228#### Turn off the retry with strict sandbox mode

227 229 

228You can disable the unsandboxed retry by setting `"allowUnsandboxedCommands": false` in your [sandbox settings](https://code.claude.com/docs/en/settings-reference.md#sandbox-settings). With the retry disabled, Claude Code ignores the `dangerouslyDisableSandbox` parameter. While the sandbox is running, commands Claude runs are then sandboxed unless they match an `excludedCommands` entry. To keep Claude Code from running commands unsandboxed when the sandbox can't start, also set [`failIfUnavailable`](https://code.claude.com/docs/en/settings-reference#sandbox-failifunavailable). The `/sandbox` **Overrides** tab shows this setting as **Strict sandbox mode**.230You can disable the unsandboxed retry by setting `"allowUnsandboxedCommands": false` in your [sandbox settings](https://code.claude.com/docs/en/settings-reference.md#sandbox-settings). With the retry disabled, Claude Code ignores the `dangerouslyDisableSandbox` parameter. While the sandbox is running, commands Claude runs are then sandboxed unless they match an `excludedCommands` entry. To keep Claude Code from running commands unsandboxed when the sandbox can't start, also set [`failIfUnavailable`](https://code.claude.com/docs/en/settings-reference#sandbox-failifunavailable). The `/sandbox` **Overrides** tab shows this setting as **Strict sandbox mode**.


899 901 

900### 0-byte read-only files appear at `.claude` settings paths, and "Yes, and don't ask again" doesn't save902### 0-byte read-only files appear at `.claude` settings paths, and "Yes, and don't ask again" doesn't save

901 903 

902On Linux and WSL2, the sandbox holds a write denial on a file that doesn't exist yet by creating a 0-byte read-only placeholder there while a sandboxed command runs. The sandbox removes the placeholder afterward. If a session is killed before that cleanup runs, for example by SIGKILL, the placeholders stay behind. Later sessions bind the placeholders read-only again on every start, so a settings write such as saving a permission choice fails at a path where a placeholder remains.904On Linux and WSL2, the sandbox holds a write denial on a file that doesn't exist yet by creating a 0-byte read-only placeholder there while a sandboxed command runs. The sandbox removes the placeholder afterward.

905 

906A placeholder stays behind in cases such as these:

907 

908* The session is killed before that cleanup runs, for example by SIGKILL

909* The session exits while a sandboxed command is still running, such as a background command

903 910 

904Run `claude doctor` in your terminal to list the leftover placeholder files. The [`Sandbox mask files left behind at write-deny paths`](https://code.claude.com/docs/en/errors#stale-sandbox-mask-files-left-by-a-killed-session) warning names some of them and counts the rest. Delete each file with `rm` while no other Claude Code session is running in that project. Before v2.1.257, Claude Code left the same placeholders behind without flagging them.911Later sessions bind the placeholders read-only again on every start, so a settings write such as saving a permission choice fails at a path where a placeholder remains.

912 

913Run `claude doctor` in your terminal to list the leftover placeholder files. The [`Sandbox mask files left behind at write-deny paths`](https://code.claude.com/docs/en/errors#stale-sandbox-mask-files-left-by-a-killed-session) warning names some of them and counts the rest. Delete each file with `rm` while no other Claude Code session is running in that project. Before v2.1.257, Claude Code left the same placeholders behind when a session was killed, without flagging them.

905 914 

906### `git` over SSH fails with the sandbox on915### `git` over SSH fails with the sandbox on

907 916 


1000 1009 

1001Before v2.1.284, the proxy connected to whatever address an allowed hostname resolved to.1010Before v2.1.284, the proxy connected to whatever address an allowed hostname resolved to.

1002 1011 

1012### Commands are refused with `Sandbox is required`

1013 

1014If you require the sandbox with [`sandbox.failIfUnavailable`](https://code.claude.com/docs/en/settings-reference#sandbox-failifunavailable) and it fails in one of these ways after Claude Code starts, each sandboxed command Claude runs is refused with the message shown. The session keeps running, and the refused command doesn't run unsandboxed:

1015 

1016* **`Sandbox is required but failed to initialize: <reason>`**: Claude Code started, but the sandbox then failed to initialize. Take the step the message gives: `Restart to retry.` or `Fix the sandbox settings to retry`.

1017* **`Sandbox is required (sandbox.failIfUnavailable) and stopped being available in this session: <reason>`**: on Linux or WSL2, the sandbox started and Claude Code then found a dependency missing. Fix what the reason names, such as [installing a missing dependency](#set-up-linux-and-wsl2), then restart Claude Code.

1018 

1019Excluded commands and commands you type yourself keep running, and Claude can't retry a refused command unsandboxed:

1020 

1021* **Excluded commands**: commands that match an [`excludedCommands`](#run-commands-outside-the-sandbox-with-excludedcommands) entry keep running outside the sandbox. When one writes to a [`filesystem.allowWrite`](https://code.claude.com/docs/en/settings-reference#sandbox-filesystem-allowwrite) path outside your working directory, that write goes through the regular permission flow. Under an [admin-required sandbox](#repository-settings-under-an-admin-required-sandbox), Claude Code ignores entries from the repository's settings

1022* **Commands you type at the [`!` shell-mode prompt](https://code.claude.com/docs/en/interactive-mode#shell-mode-with-prefix)**: keep running outside the sandbox. In a [background session](https://code.claude.com/docs/en/agent-view.md), they're refused too

1023* **Unsandboxed retries**: Claude Code ignores the `dangerouslyDisableSandbox` parameter of an [unsandboxed retry](#the-unsandboxed-retry-escape-hatch)

1024 

1025In a Linux session with `CLAUDE_CODE_SUBPROCESS_ENV_SCRUB` set, every command runs sandboxed, so excluded commands and commands you type are refused too.

1026 

1003### `/sandbox` fails with `Sandbox settings are overridden by a higher-priority configuration`1027### `/sandbox` fails with `Sandbox settings are overridden by a higher-priority configuration`

1004 1028 

1005`/sandbox` prints `Error: Sandbox settings are overridden by a higher-priority configuration and cannot be changed locally.` instead of opening its panel when a higher [settings level](https://code.claude.com/docs/en/settings.md#settings-precedence) sets `sandbox.enabled`, `sandbox.autoAllowBashIfSandboxed`, or `sandbox.allowUnsandboxedCommands`. The panel saves your choices to `.claude/settings.local.json`, and a value saved there can't override those levels.1029`/sandbox` prints `Error: Sandbox settings are overridden by a higher-priority configuration and cannot be changed locally.` instead of opening its panel when a higher [settings level](https://code.claude.com/docs/en/settings.md#settings-precedence) sets `sandbox.enabled`, `sandbox.autoAllowBashIfSandboxed`, or `sandbox.allowUnsandboxedCommands`. The panel saves your choices to `.claude/settings.local.json`, and a value saved there can't override those levels.

Details

783 783 

784For the order these sources apply in, see [settings precedence](https://code.claude.com/docs/en/settings.md#settings-precedence).784For the order these sources apply in, see [settings precedence](https://code.claude.com/docs/en/settings.md#settings-precedence).

785 785 

786When Anthropic's control plane supplies a session with [Claude Code hooks](https://code.claude.com/docs/en/hooks.md), the runner installs them alongside, not over, your own configuration. Requires Claude Code v2.1.229 or later.786When Anthropic's control plane supplies a session with [Claude Code hooks](https://code.claude.com/docs/en/hooks.md), the runner installs them alongside, not over, your own configuration. Requires Claude Code v2.1.229 or later; older runners ignore supplied hooks. The supplied hooks run `python3`, so install `python3` in your [runner image](https://code.claude.com/docs/en/self-hosted-environments-deploy.md#build-the-runner-image).

787 787 

788* **Where they land**: the runner writes each supplied hook script to a reserved `hooks/.ccr-launcher/` subdirectory of the session's config directory and registers the scripts in a separate settings file it passes to the session with `--settings`, leaving the seeded `settings.json` and your own scripts at `hooks/<name>` untouched. The runner recreates the reserved subdirectory for each session and doesn't seed host content at `~/.claude/hooks/.ccr-launcher/` into sessions.788* **Where they land**: the runner writes each supplied hook script to a reserved `hooks/.ccr-launcher/` subdirectory of the session's config directory and registers the scripts in a separate settings file it passes to the session with `--settings`, leaving the seeded `settings.json` and your own scripts at `hooks/<name>` untouched. The runner recreates the reserved subdirectory for each session and doesn't seed host content at `~/.claude/hooks/.ccr-launcher/` into sessions.

789* **Who authors them**: the control plane populates the scripts from fixed constants in its own deployment, never from per-session or third-party input.789* **Who authors them**: the control plane populates the scripts from fixed constants in its own deployment, never from per-session or third-party input.

Details

348 348 

349The recipes below use `--capacity 4`, so one container serves up to four concurrent sessions from the same locked owner. That doesn't provide the per-session container isolation in the [hardening section](#harden-your-deployment): before connecting an environment to production systems, either run the recipes at `--capacity 1` with one container per session, or use [on-demand runners](https://code.claude.com/docs/en/self-hosted-environments-configuration.md#on-demand-runners), which also keep the environment secret off session-running hosts. If you add the [Anthropic git proxy](#use-the-anthropic-git-proxy) to one of these recipes, also change `--capacity` to `1`.349The recipes below use `--capacity 4`, so one container serves up to four concurrent sessions from the same locked owner. That doesn't provide the per-session container isolation in the [hardening section](#harden-your-deployment): before connecting an environment to production systems, either run the recipes at `--capacity 1` with one container per session, or use [on-demand runners](https://code.claude.com/docs/en/self-hosted-environments-configuration.md#on-demand-runners), which also keep the environment secret off session-running hosts. If you add the [Anthropic git proxy](#use-the-anthropic-git-proxy) to one of these recipes, also change `--capacity` to `1`.

350 350 

351This Dockerfile is a minimal starting point:351This Dockerfile is a minimal starting point. It installs `python3` because the [hooks Anthropic's control plane supplies](https://code.claude.com/docs/en/self-hosted-environments-configuration.md#how-each-session’s-config-is-assembled) to Claude Tag sessions, including the one that has Claude post its reply in Slack, run `python3`. Keep `python3` on `PATH` in any image that serves Claude Tag sessions:

352 352 

353```dockerfile theme={null}353```dockerfile theme={null}

354FROM debian:bookworm-slim354FROM debian:bookworm-slim

355ARG CLAUDE_CODE_VERSION355ARG CLAUDE_CODE_VERSION

356RUN apt-get update && apt-get install -y --no-install-recommends git curl ca-certificates openssh-client jq \356RUN apt-get update && apt-get install -y --no-install-recommends git curl ca-certificates openssh-client jq python3 \

357 && rm -rf /var/lib/apt/lists/*357 && rm -rf /var/lib/apt/lists/*

358RUN curl -fsSL "https://downloads.claude.ai/claude-code-releases/${CLAUDE_CODE_VERSION:?set with --build-arg CLAUDE_CODE_VERSION}/linux-x64/claude" \358RUN curl -fsSL "https://downloads.claude.ai/claude-code-releases/${CLAUDE_CODE_VERSION:?set with --build-arg CLAUDE_CODE_VERSION}/linux-x64/claude" \

359 -o /usr/local/bin/claude && chmod +x /usr/local/bin/claude359 -o /usr/local/bin/claude && chmod +x /usr/local/bin/claude


363ENTRYPOINT ["claude"]363ENTRYPOINT ["claude"]

364```364```

365 365 

366Swap `linux-x64` for `linux-arm64` if your nodes are ARM, or for `linux-x64-musl` or `linux-arm64-musl` on a musl-based image such as Alpine; see [Alpine Linux setup](https://code.claude.com/docs/en/setup.md#alpine-linux-and-musl-based-distributions) for the extra packages musl images need. The URL is the standard Claude Code release location, so you can verify the downloaded binary against the release's signed manifest as described in [Binary integrity and code signing](https://code.claude.com/docs/en/setup.md#binary-integrity-and-code-signing). The runner requires Claude Code version 2.1.224 or later. Build the image, then push it to your registry and reference it in the recipes below:366Swap `linux-x64` for `linux-arm64` if your nodes are ARM, or for `linux-x64-musl` or `linux-arm64-musl` on a musl-based image such as Alpine; see [Alpine Linux setup](https://code.claude.com/docs/en/setup.md#alpine-linux-and-musl-based-distributions) for the extra packages musl images need. The URL is the standard Claude Code release location, so you can verify the downloaded binary against the release's signed manifest as described in [Binary integrity and code signing](https://code.claude.com/docs/en/setup.md#binary-integrity-and-code-signing). The runner requires Claude Code version 2.1.224 or later, or 2.1.229 or later to serve Claude Tag sessions. Build the image, then push it to your registry and reference it in the recipes below:

367 367 

368```bash theme={null}368```bash theme={null}

369docker build \369docker build \


768 * **With a `checkout` hook**: repositories checked out via a [`checkout` lifecycle hook](https://code.claude.com/docs/en/self-hosted-environments-configuration#checkout) aren't pushed. Snapshot those from the [`post-session` hook](https://code.claude.com/docs/en/self-hosted-environments-configuration#post-session) instead.768 * **With a `checkout` hook**: repositories checked out via a [`checkout` lifecycle hook](https://code.claude.com/docs/en/self-hosted-environments-configuration#checkout) aren't pushed. Snapshot those from the [`post-session` hook](https://code.claude.com/docs/en/self-hosted-environments-configuration#post-session) instead.

769 * **Before enabling the flag**: restrict who can push to `claude/*` refs on the source remote. On resume, the runner fetches the previously pushed branch without verifying who pushed it.769 * **Before enabling the flag**: restrict who can push to `claude/*` refs on the source remote. On resume, the runner fetches the previously pushed branch without verifying who pushed it.

770 * **Uncommitted changes are still lost**: to prompt Claude to commit and push when it finishes responding, see [Prompt sessions to push their work](https://code.claude.com/docs/en/self-hosted-environments-configuration.md#prompt-sessions-to-push-their-work)770 * **Uncommitted changes are still lost**: to prompt Claude to commit and push when it finishes responding, see [Prompt sessions to push their work](https://code.claude.com/docs/en/self-hosted-environments-configuration.md#prompt-sessions-to-push-their-work)

771* **A command cut off by a lost runner can run again**: when the session resumes on another runner, Claude sees the interrupted tool call with a result saying its outcome is unknown.

771* **A repository added mid-session can fail to clone**: Claude clones it with `git clone` over HTTPS. On a runner without [`--use-anthropic-git-proxy`](#use-the-anthropic-git-proxy), the clone fails with a git authentication error if nothing on the host can read the repository. Where you can, select every repository the session needs when you create it.772* **A repository added mid-session can fail to clone**: Claude clones it with `git clone` over HTTPS. On a runner without [`--use-anthropic-git-proxy`](#use-the-anthropic-git-proxy), the clone fails with a git authentication error if nothing on the host can read the repository. Where you can, select every repository the session needs when you create it.

772* **Some connectors don't appear in self-hosted sessions**: a connector you haven't yet connected in claude.ai Settings isn't listed in a self-hosted session, and the session won't prompt you to connect it. Connect it in Settings first, then start a fresh session. Adding a connector to an already-running session also doesn't make its tools available to Claude; start a fresh session to pick up a newly added connector.773* **Some connectors don't appear in self-hosted sessions**: a connector you haven't yet connected in claude.ai Settings isn't listed in a self-hosted session, and the session won't prompt you to connect it. Connect it in Settings first, then start a fresh session. Adding a connector to an already-running session also doesn't make its tools available to Claude; start a fresh session to pick up a newly added connector.

773* **When someone archives or deletes a session, or releases its runner from the session's menu**: don't count on the [`--push-outcome-on-release`](https://code.claude.com/docs/en/self-hosted-environments-reference#runner-cli-flags) push. To save commits in those cases, push `HEAD` to a rescue branch from a [`post-session` hook](https://code.claude.com/docs/en/self-hosted-environments-configuration#post-session). If you start from the example there, make it push even when nothing is uncommitted, because it pushes only after a snapshot commit.774* **When someone archives or deletes a session, or releases its runner from the session's menu**: don't count on the [`--push-outcome-on-release`](https://code.claude.com/docs/en/self-hosted-environments-reference#runner-cli-flags) push. To save commits in those cases, push `HEAD` to a rescue branch from a [`post-session` hook](https://code.claude.com/docs/en/self-hosted-environments-configuration#post-session). If you start from the example there, make it push even when nothing is uncommitted, because it pushes only after a snapshot commit.


824 Once the runner is upgraded or the cause is fixed, retry the session or start a new one. If none of these checks finds the cause, [report an issue](#report-an-issue).825 Once the runner is upgraded or the cause is fixed, retry the session or start a new one. If none of these checks finds the cause, [report an issue](#report-an-issue).

825 826 

826 For the source the session pushes results to, a deleted branch fails the session. For a git source the session only reads from, the runner skips that source and continues on the remaining ones. The runner fails the session when skipping would leave it with no repository at all. Before v2.1.228, such a session started in an empty directory.827 For the source the session pushes results to, a deleted branch fails the session. For a git source the session only reads from, the runner skips that source and continues on the remaining ones. The runner fails the session when skipping would leave it with no repository at all. Before v2.1.228, such a session started in an empty directory.

828* **Claude Tag sometimes doesn't post its reply in Slack**: the reply reminder is a [hook the control plane supplies](https://code.claude.com/docs/en/self-hosted-environments-configuration.md#how-each-session’s-config-is-assembled). Confirm the runner is Claude Code v2.1.229 or later with `claude --version`, since older runners ignore supplied hooks; confirm `python3 --version` succeeds inside the runner image, since the hooks run `python3`; and confirm no settings file turns hooks off, whether `disableAllHooks` in `managed-settings.json`, the runner user's `~/.claude/settings.json`, or the repository's `.claude/settings.json` or `.claude/settings.local.json`, or `allowManagedHooksOnly` or a [`strictPluginOnlyCustomization`](https://code.claude.com/docs/en/settings-reference#strictpluginonlycustomization) that covers hooks in managed settings.

827* **A session starts without one of its repositories**: on a runner with no [`checkout` hook](https://code.claude.com/docs/en/self-hosted-environments-configuration#checkout), the git host can refuse the runner's access check for a repository the session only reads from. The runner then skips that repository, logs a `[runner:warn] could not access context source` line naming the refusal, and starts the session on the remaining ones.829* **A session starts without one of its repositories**: on a runner with no [`checkout` hook](https://code.claude.com/docs/en/self-hosted-environments-configuration#checkout), the git host can refuse the runner's access check for a repository the session only reads from. The runner then skips that repository, logs a `[runner:warn] could not access context source` line naming the refusal, and starts the session on the remaining ones.

828 830 

829 The runner skips only a clear refusal: the host answers that the repository wasn't found, git finds no credentials for the host, or authentication fails. A network failure, a timeout, or an HTTP `403` still fails the session start, as does a refusal for a repository the session pushes results to. The runner still fails a session that skipping would leave with no repository at all. With [`--use-anthropic-git-proxy`](#use-the-anthropic-git-proxy), the runner skips only a repository the git proxy itself denies.831 The runner skips only a clear refusal: the host answers that the repository wasn't found, git finds no credentials for the host, or authentication fails. A network failure, a timeout, or an HTTP `403` still fails the session start, as does a refusal for a repository the session pushes results to. The runner still fails a session that skipping would leave with no repository at all. With [`--use-anthropic-git-proxy`](#use-the-anthropic-git-proxy), the runner skips only a repository the git proxy itself denies.

Details

35 35 

36Install on the host before you start:36Install on the host before you start:

37 37 

38* **Claude Code v2.1.224 or later**, with any of the [standard install methods](https://code.claude.com/docs/en/setup.md). The runner is part of the standard `claude` binary, and earlier versions don't recognize the `self-hosted-runner` subcommand. To pin the exact version your fleet runs, see [Install a specific version](https://code.claude.com/docs/en/setup.md#install-a-specific-version). For container images, see the Dockerfile in [Deploy to production](https://code.claude.com/docs/en/self-hosted-environments-deploy.md#build-the-runner-image).38* **Claude Code v2.1.224 or later**, with any of the [standard install methods](https://code.claude.com/docs/en/setup.md). The runner is part of the standard `claude` binary, and earlier versions don't recognize the `self-hosted-runner` subcommand. A runner that serves Claude Tag sessions needs v2.1.229 or later and `python3` on its `PATH`, since the [hooks the control plane supplies](https://code.claude.com/docs/en/self-hosted-environments-configuration.md#how-each-session’s-config-is-assembled) for those sessions run `python3`. To pin the exact version your fleet runs, see [Install a specific version](https://code.claude.com/docs/en/setup.md#install-a-specific-version). For container images, see the Dockerfile in [Deploy to production](https://code.claude.com/docs/en/self-hosted-environments-deploy.md#build-the-runner-image).

39* **Git 2.24 or newer**. Some git options on the deploy page need newer versions; [Configure git](https://code.claude.com/docs/en/self-hosted-environments-deploy.md#configure-git) states each floor.39* **Git 2.24 or newer**. Some git options on the deploy page need newer versions; [Configure git](https://code.claude.com/docs/en/self-hosted-environments-deploy.md#configure-git) states each floor.

40 40 

41Confirm the host is ready:41Confirm the host is ready:

Details

52| `--retire-at <epoch-seconds>` | `SELF_HOSTED_RUNNER_RETIRE_AT` | unset | Retire the runner at an absolute Unix timestamp in seconds, for infrastructure that kills the runner at a known time; [Runner lifecycle](https://code.claude.com/docs/en/self-hosted-environments#runner-lifecycle) describes the release sequence and how to size the margin. Values before 2001 or after the year 5138 are rejected by the flag and ignored by the environment variable. |52| `--retire-at <epoch-seconds>` | `SELF_HOSTED_RUNNER_RETIRE_AT` | unset | Retire the runner at an absolute Unix timestamp in seconds, for infrastructure that kills the runner at a known time; [Runner lifecycle](https://code.claude.com/docs/en/self-hosted-environments#runner-lifecycle) describes the release sequence and how to size the margin. Values before 2001 or after the year 5138 are rejected by the flag and ignored by the environment variable. |

53| `--server-auto-mode-lists <mode>` | `SELF_HOSTED_RUNNER_SERVER_AUTO_MODE_LISTS` | `no-allow` | Which of the [auto mode](https://code.claude.com/docs/en/permission-modes.md#eliminate-prompts-with-auto-mode) classifier rule lists that the control plane sends with a session may reach that session: `all`, `no-allow`, or `none`. See [Auto mode rule lists](#auto-mode-rule-lists) for what each value applies. An invalid value stops the runner at startup. Requires Claude Code v2.1.295 or later. |53| `--server-auto-mode-lists <mode>` | `SELF_HOSTED_RUNNER_SERVER_AUTO_MODE_LISTS` | `no-allow` | Which of the [auto mode](https://code.claude.com/docs/en/permission-modes.md#eliminate-prompts-with-auto-mode) classifier rule lists that the control plane sends with a session may reach that session: `all`, `no-allow`, or `none`. See [Auto mode rule lists](#auto-mode-rule-lists) for what each value applies. An invalid value stops the runner at startup. Requires Claude Code v2.1.295 or later. |

54| `--session-stop-grace-sec <n>` | `SELF_HOSTED_RUNNER_SESSION_STOP_GRACE_MS` | `5` | How long to wait for the Claude process to exit cleanly after a session ends, before force-killing it. Raise the value if the child's own `SessionEnd` hooks need more time. |54| `--session-stop-grace-sec <n>` | `SELF_HOSTED_RUNNER_SESSION_STOP_GRACE_MS` | `5` | How long to wait for the Claude process to exit cleanly after a session ends, before force-killing it. Raise the value if the child's own `SessionEnd` hooks need more time. |

55| `--startup-timeout-min <n>` | `SELF_HOSTED_RUNNER_STARTUP_TIMEOUT_MS` | `15` | Release a session slot if the child hasn't signaled on the [activity channel](https://code.claude.com/docs/en/self-hosted-environments-configuration.md#keep-stdin-and-file-descriptor-3-attached) that it initialized within N minutes. The N minutes start at spawn, after cloning, and start over at each `user` or `assistant` message the child emits before it has initialized or reported its state. Before v2.1.299, this timeout stopped applying at the session's first such message. For release after the init signal, see `--release-idle-session-min`. `0` disables. |55| `--startup-timeout-min <n>` | `SELF_HOSTED_RUNNER_STARTUP_TIMEOUT_MS` | `15` | How long to wait on a child process that hasn't initialized before releasing the session's slot. See [Session startup timeout](#session-startup-timeout) for where the count starts and which sessions it leaves running. `0` disables the timeout. |

56| `--trust-workspace [bool]` | `SELF_HOSTED_RUNNER_TRUST_WORKSPACE` | on | Seed persisted trust for each session's repository paths so repo-committed `permissions.allow` and `additionalDirectories` are honored. Set `false` to drop repo-committed permission grants and configure allow rules in the host config's `settings.json` instead; repository-committed `sandbox.*` settings still apply either way, which is why the [repo-settings guard](https://code.claude.com/docs/en/self-hosted-environments-deploy.md#harden-your-deployment) scans them regardless of this flag. |56| `--trust-workspace [bool]` | `SELF_HOSTED_RUNNER_TRUST_WORKSPACE` | on | Seed persisted trust for each session's repository paths so repo-committed `permissions.allow` and `additionalDirectories` are honored. Set `false` to drop repo-committed permission grants and configure allow rules in the host config's `settings.json` instead; repository-committed `sandbox.*` settings still apply either way, which is why the [repo-settings guard](https://code.claude.com/docs/en/self-hosted-environments-deploy.md#harden-your-deployment) scans them regardless of this flag. |

57| `--use-anthropic-git-proxy` | `CLAUDE_RUNNER_USE_GIT_PROXY=1` | off | Clone repositories on github.com via the [Anthropic git proxy](https://code.claude.com/docs/en/self-hosted-environments-deploy.md#use-the-anthropic-git-proxy) instead of customer-managed git auth. Requires `--capacity 1` and git 2.32 or later; the runner refuses to start otherwise. Supersedes the rewrite flags. |57| `--use-anthropic-git-proxy` | `CLAUDE_RUNNER_USE_GIT_PROXY=1` | off | Clone repositories on github.com via the [Anthropic git proxy](https://code.claude.com/docs/en/self-hosted-environments-deploy.md#use-the-anthropic-git-proxy) instead of customer-managed git auth. Requires `--capacity 1` and git 2.32 or later; the runner refuses to start otherwise. Supersedes the rewrite flags. |

58 58 


61* **Flag**: startup fails with an error.61* **Flag**: startup fails with an error.

62* **Environment variable**: the runner clamps the value to the timer ceiling rather than rejecting it.62* **Environment variable**: the runner clamps the value to the timer ceiling rather than rejecting it.

63 63 

64### Session startup timeout

65 

66If a session lost its slot during a turn such as `/code-review`, update the runner and the child binary to v2.1.309 or later. From v2.1.299 through v2.1.308, the runner released a session, even mid-turn, once the startup timeout passed without a `user` or `assistant` message.

67 

68With `--startup-timeout-min <n>`, the runner releases a session's slot when its child hasn't initialized within `<n>` minutes after cloning. During a turn that begins before the child initializes, the session keeps its slot until `<n>` minutes pass with no line on the child's [activity channel](https://code.claude.com/docs/en/self-hosted-environments-configuration.md#keep-stdin-and-file-descriptor-3-attached). Once the child initializes, the runner clears that count and `--release-idle-session-min` governs release. To limit a session whose child is alive but stuck, set `--kill-session-after-min`.

69 

64### Auto mode rule lists70### Auto mode rule lists

65 71 

66`--server-auto-mode-lists` lets you decide which [auto mode](https://code.claude.com/docs/en/permission-modes.md#eliminate-prompts-with-auto-mode) classifier rules from outside the runner reach the sessions on your runners. Anthropic's control plane can send rule lists with a session and ask the runner to apply them. Some entries may be rules an admin of your organization wrote. The lists are `environment`, `soft_deny`, and `allow`:72`--server-auto-mode-lists` lets you decide which [auto mode](https://code.claude.com/docs/en/permission-modes.md#eliminate-prompts-with-auto-mode) classifier rules from outside the runner reach the sessions on your runners. Anthropic's control plane can send rule lists with a session and ask the runner to apply them. Some entries may be rules an admin of your organization wrote. The lists are `environment`, `soft_deny`, and `allow`:


374 380 

375#### Join a session's metrics to the runner's381#### Join a session's metrics to the runner's

376 382 

377To put a session's own metrics beside `claude_code_self_hosted_runner_session_idle_seconds`, join on the runner's `session_id`:383To see what idle sessions have cost, join the runner's `claude_code_self_hosted_runner_session_idle_seconds` to Claude Code's cost metric on `ccr_session_id`. The runner's metric doesn't carry that label, so give it one with `label_replace`, as in this query:

384 

385```text theme={null}

386sum by (ccr_session_id) (claude_code_cost_usage_total)

387and on (ccr_session_id)

388label_replace(

389 claude_code_self_hosted_runner_session_idle_seconds > 600,

390 "ccr_session_id", "cse_$1", "session_id", "session_(.*)"

391)

392```

393 

394The query returns one result per session idle for over ten minutes: the cost in US dollars its Claude Code process has counted so far. To join another Claude Code metric, replace `claude_code_cost_usage_total` in the query. The query works at any `--capacity`.

378 395 

379* **At `--capacity` above one**: join directly. On the runner's `/metrics`, the session's series carry the same `session_id` as that metric, in `session_...` form.396* **`session_id`**: on port 9464, that label on Claude Code metrics holds Claude Code's own [`session.id`](https://code.claude.com/docs/en/monitoring-usage#standard-attributes), which matches no runner series. A join on it returns nothing, so join on `ccr_session_id`.

380* **At `--capacity 1`**: join on a converted `ccr_session_id`. By default, each Claude Code metric on port 9464 carries that label, which holds the session ID in `cse_...` form. In a new label, replace its `cse_` prefix with `session_` to get the runner's `session_id`. The metric's own `session_id` holds Claude Code's own [`session.id`](https://code.claude.com/docs/en/monitoring-usage#standard-attributes), which matches no runner series.397* **Claude Code metrics have no `ccr_session_id`**: check that [`OTEL_METRICS_INCLUDE_SESSION_ID`](https://code.claude.com/docs/en/monitoring-usage#metrics-cardinality-control) isn't set to `false`

381 398 

382### Session lifecycle counter semantics399### Session lifecycle counter semantics

383 400 

Details

117| [`gcpAuthRefresh`](#gcpauthrefresh) | Refresh [Google Cloud credentials](https://code.claude.com/docs/en/google-vertex-ai.md#advanced-credential-configuration) with your own command | Authentication and providers | Any file |117| [`gcpAuthRefresh`](#gcpauthrefresh) | Refresh [Google Cloud credentials](https://code.claude.com/docs/en/google-vertex-ai.md#advanced-credential-configuration) with your own command | Authentication and providers | Any file |

118| [`hooks`](#hooks) | Run your own commands as [hooks](https://code.claude.com/docs/en/hooks.md) at points in Claude Code's lifecycle | Hooks and automation | Any file |118| [`hooks`](#hooks) | Run your own commands as [hooks](https://code.claude.com/docs/en/hooks.md) at points in Claude Code's lifecycle | Hooks and automation | Any file |

119| [`httpHookAllowedEnvVars`](#httphookallowedenvvars) | Limit which env vars [HTTP hooks](https://code.claude.com/docs/en/hooks.md) can put in headers | Hooks and automation | Any file |119| [`httpHookAllowedEnvVars`](#httphookallowedenvvars) | Limit which env vars [HTTP hooks](https://code.claude.com/docs/en/hooks.md) can put in headers | Hooks and automation | Any file |

120| [`idleCompaction`](#idlecompaction) | Stop Claude Code from compacting a long conversation while your terminal session is idle | Memory and context | Any file |120| [`idleCompaction`](#idlecompaction) | Stop Claude Code from compacting a long conversation that you've stepped away from | Memory and context | Any file |

121| [`includeCoAuthoredBy`](#includecoauthoredby) | Deprecated; use `attribution` to hide or change commit and PR attribution | Git and attribution | Any file |121| [`includeCoAuthoredBy`](#includecoauthoredby) | Deprecated; use `attribution` to hide or change commit and PR attribution | Git and attribution | Any file |

122| [`includeGitInstructions`](#includegitinstructions) | Remove the built-in commit and PR instructions from Claude's context | Git and attribution | Any file |122| [`includeGitInstructions`](#includegitinstructions) | Remove the built-in commit and PR instructions from Claude's context | Git and attribution | Any file |

123| [`inputNeededNotifEnabled`](#inputneedednotifenabled) | Get a [push notification](https://code.claude.com/docs/en/remote-control.md#mobile-push-notifications) when Claude is waiting on you | Remote, desktop, and notifications | Any file |123| [`inputNeededNotifEnabled`](#inputneedednotifenabled) | Get a [push notification](https://code.claude.com/docs/en/remote-control.md#mobile-push-notifications) when Claude is waiting on you | Remote, desktop, and notifications | Any file |


1230 1230 

1231* **Scope**: [`Any file`](#scopes), with [limits on project and local settings](https://code.claude.com/docs/en/sandboxing.md#repository-settings-under-an-admin-required-sandbox)1231* **Scope**: [`Any file`](#scopes), with [limits on project and local settings](https://code.claude.com/docs/en/sandboxing.md#repository-settings-under-an-admin-required-sandbox)

1232* **Type**: Boolean1232* **Type**: Boolean

1233 * `true`: Claude Code exits with an error at startup when `sandbox.enabled` is `true` but the sandbox can't start1233 * `true`: Claude Code exits with an error at startup when `sandbox.enabled` is `true` but the sandbox can't start. If the sandbox passes that check and then fails to initialize, the session keeps running and Claude Code [refuses each sandboxed command](https://code.claude.com/docs/en/sandboxing.md#commands-refused-with-sandbox-is-required)

1234 * `false`: Claude Code runs commands unsandboxed when the sandbox can't start1234 * `false`: Claude Code runs commands unsandboxed when the sandbox can't start

1235* **Default**: `false`1235* **Default**: `false`

1236 1236 

1237This makes every managed machine sandbox commands or refuse to start:1237This turns the sandbox on for managed machines and sets `failIfUnavailable` to `true`:

1238 1238 

1239```json managed-settings.json theme={null}1239```json managed-settings.json theme={null}

1240{1240{


2415 2415 

2416### `idleCompaction`2416### `idleCompaction`

2417 2417 

2418Idle compaction [compacts](https://code.claude.com/docs/en/context-window.md#what-survives-compaction) a long conversation that you've stepped away from, shortly before its prompt cache expires. Your next message then sends a summary instead of the whole conversation. When you come back, the conversation shows a line that starts with `Compacted while idle, before the prompt cache expired`.2418Idle compaction [compacts](https://code.claude.com/docs/en/context-window.md#what-survives-compaction) a long conversation that you've stepped away from. Your next message then sends a summary instead of the whole conversation. Once compacted, the conversation shows a notice:

2419 

2420* **Terminal**: a line that starts with `Compacted while idle, before the prompt cache expired`

2421* **[VS Code chat panel](#idle-compaction-in-vs-code-and-the-desktop-app)**: a notice that includes `a summary written while you were away`

2422* **[Desktop app](#idle-compaction-in-vs-code-and-the-desktop-app)**: the same notice, inside a row whose label includes `Claude Code notice`. If you don't see that row or its text, switch to the [Verbose view mode](https://code.claude.com/docs/en/desktop.md#switch-view-modes).

2419 2423 

2420Idle compaction is on by default for conversations that meet all of these conditions:2424Idle compaction is on by default for conversations that meet all of these conditions:

2421 2425 

2422* **Session**: you're in an interactive terminal session2426* **Session**: you're in an interactive terminal session, or in the VS Code extension's chat panel or the desktop app's Code tab on an [account that Anthropic selects](#idle-compaction-in-vs-code-and-the-desktop-app)

2423* **Auto-compaction**: [`autoCompactEnabled`](#autocompactenabled) is on2427* **Auto-compaction**: [`autoCompactEnabled`](#autocompactenabled) is on

2424* **Prompt cache**: the conversation is on the [one-hour prompt cache TTL](https://code.claude.com/docs/en/prompt-caching.md#which-ttl-each-request-gets)2428* **Prompt cache**: the conversation is on the [one-hour prompt cache TTL](https://code.claude.com/docs/en/prompt-caching.md#which-ttl-each-request-gets)

2425* **Feature flags**: Claude Code can [fetch feature flags from Anthropic](https://code.claude.com/docs/en/env-vars.md#features-that-need-feature-flag-fetching)2429* **Feature flags**: Claude Code can [fetch feature flags from Anthropic](https://code.claude.com/docs/en/env-vars.md#features-that-need-feature-flag-fetching)


2441}2445}

2442```2446```

2443 2447 

2444To turn idle compaction off or on from inside a session, run `/config` and change the **Idle compaction** row. Your choice is saved to your user settings and applies right away. The row requires Claude Code v2.1.302 or later. If you run one of those versions and `/config` doesn't show the row, check for these causes:2448To turn idle compaction off or on from inside a terminal session, run `/config` and change the **Idle compaction** row. Your choice is saved to your user settings and applies right away. The row requires Claude Code v2.1.302 or later. If you run one of those versions and `/config` doesn't show the row, check for these causes:

2445 2449 

2446* **Another settings source sets the key**: a value in managed settings, the `--settings` flag, or a project or local settings file overrides your user settings. Change the key in that source instead2450* **Another settings source sets the key**: a value in managed settings, the `--settings` flag, or a project or local settings file overrides your user settings. Change the key in that source instead

2447* **Feature flags are unavailable**: where Claude Code can't [fetch feature flags from Anthropic](https://code.claude.com/docs/en/env-vars.md#features-that-need-feature-flag-fetching), idle compaction doesn't run, so there is nothing to turn off2451* **Feature flags are unavailable**: where Claude Code can't [fetch feature flags from Anthropic](https://code.claude.com/docs/en/env-vars.md#features-that-need-feature-flag-fetching), idle compaction doesn't run, so there is nothing to turn off


2462}2466}

2463```2467```

2464 2468 

2469#### Idle compaction in VS Code and the desktop app

2470 

2471A notice like this one means Claude Code [replaced your earlier conversation with a summary](https://code.claude.com/docs/en/context-window.md#what-survives-compaction) that Claude now works from:

2472 

2473```text theme={null}

2474Compacted using a summary written while you were away · turn off with "idleCompaction": false in settings.json

2475```

2476 

2477You don't need to do anything. To turn idle compaction off, set `idleCompaction` to `false` in `~/.claude/settings.json` or another [settings file](https://code.claude.com/docs/en/settings.md#settings-files-and-who-they-affect).

2478 

2479In the VS Code extension's chat panel and the desktop app's Code tab, idle compaction runs for accounts that Anthropic selects. Claude Code writes the summary while you're away, then compacts with it only if your next message comes an hour or more after the last request.

2480 

2465### `plansDirectory`2481### `plansDirectory`

2466 2482 

2467Choose where Claude Code stores the plan files it writes in [plan mode](https://code.claude.com/docs/en/permission-modes.md#analyze-before-you-edit-with-plan-mode). Claude Code resolves the path relative to the project root.2483Choose where Claude Code stores the plan files it writes in [plan mode](https://code.claude.com/docs/en/permission-modes.md#analyze-before-you-edit-with-plan-mode). Claude Code resolves the path relative to the project root.


3522 3538 

3523* **Managed and SDK hooks run**: hooks from managed settings and hooks the [Agent SDK](https://code.claude.com/docs/en/agent-sdk/overview.md) registers in process3539* **Managed and SDK hooks run**: hooks from managed settings and hooks the [Agent SDK](https://code.claude.com/docs/en/agent-sdk/overview.md) registers in process

3524* **Force-enabled plugin hooks run**: hooks from plugins your managed settings force-enable through [`enabledPlugins`](#enabledplugins). Claude Code matches on the full `plugin@marketplace` ID, so a plugin with the same name from a different marketplace stays blocked. This lets you distribute vetted hooks through an organization marketplace while blocking everything else. A [mod](https://code.claude.com/docs/en/plugins/mods/overview.md) in such a plugin loads only when it [counts as your organization's](https://code.claude.com/docs/en/plugins/mods/admin.md#install-your-organizations-mods)3540* **Force-enabled plugin hooks run**: hooks from plugins your managed settings force-enable through [`enabledPlugins`](#enabledplugins). Claude Code matches on the full `plugin@marketplace` ID, so a plugin with the same name from a different marketplace stays blocked. This lets you distribute vetted hooks through an organization marketplace while blocking everything else. A [mod](https://code.claude.com/docs/en/plugins/mods/overview.md) in such a plugin loads only when it [counts as your organization's](https://code.claude.com/docs/en/plugins/mods/admin.md#install-your-organizations-mods)

3541* **Monitors from other plugins are blocked**: a plugin's [monitors](https://code.claude.com/docs/en/plugins/components.md#monitors) don't start unless the plugin is force-enabled. Requires Claude Code v2.1.310 or later

3525* **Everything else is blocked**: user, project, and local hooks, hooks and mods from other installed plugins, and hooks declared in agent frontmatter. [Mods built into Claude Code](https://code.claude.com/docs/en/plugins/mods/overview.md#mods-built-into-claude-code) keep running. To block only users' mods, set [`allowManagedModsOnly`](https://code.claude.com/docs/en/plugins/mods/admin#set-options-on-the-built-in-guard) instead.3542* **Everything else is blocked**: user, project, and local hooks, hooks and mods from other installed plugins, and hooks declared in agent frontmatter. [Mods built into Claude Code](https://code.claude.com/docs/en/plugins/mods/overview.md#mods-built-into-claude-code) keep running. To block only users' mods, set [`allowManagedModsOnly`](https://code.claude.com/docs/en/plugins/mods/admin#set-options-on-the-built-in-guard) instead.

3526* **Command-sourced plugins are disabled**: Claude Code also disables plugins with a [`command` source](https://code.claude.com/docs/en/plugins/marketplace-reference#command-plugin-source), including plugins force-enabled in managed `enabledPlugins`, unless you set [`disableCommandPluginSources`](#disablecommandpluginsources) to `false` explicitly3543* **Command-sourced plugins are disabled**: Claude Code also disables plugins with a [`command` source](https://code.claude.com/docs/en/plugins/marketplace-reference#command-plugin-source), including plugins force-enabled in managed `enabledPlugins`, unless you set [`disableCommandPluginSources`](#disablecommandpluginsources) to `false` explicitly

3527* **Marketplace `headersHelper` commands are blocked**: Claude Code also blocks marketplace [`headersHelper` commands](https://code.claude.com/docs/en/plugins/host-marketplace#authenticate-archive-downloads) unless [`disableCommandPluginSources`](#disablecommandpluginsources) is explicitly set to `false`, except for a marketplace that managed settings themselves declare. Requires Claude Code v2.1.238 or later3544* **Marketplace `headersHelper` commands are blocked**: Claude Code also blocks marketplace [`headersHelper` commands](https://code.claude.com/docs/en/plugins/host-marketplace#authenticate-archive-downloads) unless [`disableCommandPluginSources`](#disablecommandpluginsources) is explicitly set to `false`, except for a marketplace that managed settings themselves declare. Requires Claude Code v2.1.238 or later

statusline.md +1 −1

Details

380* `used_percentage` and `resets_at`: come with every response, so they are present whenever `spend_limit` is. `used_percentage` runs from 0 to 100, or above 100 once you exceed the limit, and `resets_at` is the Unix epoch seconds when the limit's period resets.380* `used_percentage` and `resets_at`: come with every response, so they are present whenever `spend_limit` is. `used_percentage` runs from 0 to 100, or above 100 once you exceed the limit, and `resets_at` is the Unix epoch seconds when the limit's period resets.

381* `used_usd`, `limit_usd`, and `period`: your estimated spend so far and your limit in US dollars, and the period the limit covers, one of `daily`, `weekly`, or `monthly`. The gateway [computes `used_usd` from token counts](https://code.claude.com/docs/en/claude-apps-gateway-spend-limits#how-requests-are-priced), so it's an estimate and not a billed amount. Claude Code reads them from the gateway in a separate request, about every five minutes while you send requests. The dollar amounts can be about five minutes older than `used_percentage`, so the two may briefly disagree. Requires v2.1.284 or later on both Claude Code and the gateway.381* `used_usd`, `limit_usd`, and `period`: your estimated spend so far and your limit in US dollars, and the period the limit covers, one of `daily`, `weekly`, or `monthly`. The gateway [computes `used_usd` from token counts](https://code.claude.com/docs/en/claude-apps-gateway-spend-limits#how-requests-are-priced), so it's an estimate and not a billed amount. Claude Code reads them from the gateway in a separate request, about every five minutes while you send requests. The dollar amounts can be about five minutes older than `used_percentage`, so the two may briefly disagree. Requires v2.1.284 or later on both Claude Code and the gateway.

382 382 

383Treat `used_usd`, `limit_usd`, and `period` as optional even when `spend_limit` is present. Your script receives the percentage before them, and they stay absent if you set `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC`, which turns that request off. Read each with a fallback in your script, such as `jq -r '.rate_limits.spend_limit.used_usd // empty'`.383Treat `used_usd`, `limit_usd`, and `period` as optional even when `spend_limit` is present, because your script receives the percentage before them. Read each with a fallback in your script, such as `jq -r '.rate_limits.spend_limit.used_usd // empty'`. Before Claude Code v2.1.295, they stayed absent if you set `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC`, which turned that request off.

384 384 

385### Prompt cache fields385### Prompt cache fields

386 386 

Details

121* **Background session**: a [background session](https://code.claude.com/docs/en/agent-view.md) doesn't report its status to your terminal, even while you're attached to it. Agent view shows its status instead.121* **Background session**: a [background session](https://code.claude.com/docs/en/agent-view.md) doesn't report its status to your terminal, even while you're attached to it. Agent view shows its status instead.

122* **[`CLAUDE_CODE_DISABLE_TERMINAL_TITLE`](https://code.claude.com/docs/en/env-vars#variables)**: if you set this variable to `1`, Claude Code doesn't check for support or report status. Unset it.122* **[`CLAUDE_CODE_DISABLE_TERMINAL_TITLE`](https://code.claude.com/docs/en/env-vars#variables)**: if you set this variable to `1`, Claude Code doesn't check for support or report status. Unset it.

123 123 

124The tab title doesn't start with a status glyph in a terminal that reports support for the protocol. The terminal shows the session's state itself, so Claude Code leaves out the glyph it puts in front of the title in other terminals.

125 

124## Configure tmux126## Configure tmux

125 127 

126When Claude Code runs inside tmux, by default Shift+Enter submits instead of inserting a newline, and desktop notifications and the [progress bar](https://code.claude.com/docs/en/settings-reference.md#terminalprogressbarenabled) never reach the outer terminal. Add these lines to `~/.tmux.conf`, then run `tmux source-file ~/.tmux.conf` to apply them to the running server:128When Claude Code runs inside tmux, by default Shift+Enter submits instead of inserting a newline, and desktop notifications and the [progress bar](https://code.claude.com/docs/en/settings-reference.md#terminalprogressbarenabled) never reach the outer terminal. Add these lines to `~/.tmux.conf`, then run `tmux source-file ~/.tmux.conf` to apply them to the running server:

Details

258 258 

259A file that changed on disk after Claude last read it can still be edited when `old_string` matches the current content exactly and unambiguously and Claude Code can read the file without prompting. Matching against the file's current content keeps this safe, and the result notes that the file carries other changes so Claude re-reads it before edits that depend on surrounding content. In any other case, such as a stale `old_string` or one that matches more than once without `replace_all`, Claude reads the file again before editing.259A file that changed on disk after Claude last read it can still be edited when `old_string` matches the current content exactly and unambiguously and Claude Code can read the file without prompting. Matching against the file's current content keeps this safe, and the result notes that the file carries other changes so Claude re-reads it before edits that depend on surrounding content. In any other case, such as a stale `old_string` or one that matches more than once without `replace_all`, Claude reads the file again before editing.

260 260 

261Claude can also edit a file without a separate Read after it views the file with a Bash command such as `cat` or `grep`. Those commands are `cat`, `nl`, `bat`, `batcat`, `head`, `tail`, `sed -n 'X,Yp'`, `grep`, `egrep`, `fgrep`, and `rg`, each run on one file with no pipes or redirects. A search that prints no matches doesn't count as a read, nor does any command outside this list.261Claude can also edit a file without a separate Read after viewing it with a Bash command such as `cat` or `grep`. Those commands are `cat`, `nl`, `bat`, `batcat`, `head`, `tail`, `sed -n 'X,Yp'`, `grep`, `egrep`, `fgrep`, and `rg`, each run on one file with no pipes or redirects. If the command printed none of the file's text, as when a search matches nothing, the read-before-edit check still applies.

262 262 

263When Claude views a file this way, Claude Code also loads any [subdirectory `CLAUDE.md`](https://code.claude.com/docs/en/memory#how-claude-md-files-load) and [path-scoped rules](https://code.claude.com/docs/en/memory.md#path-specific-rules) that apply to that file. See [Read and Edit permission rules](https://code.claude.com/docs/en/permissions.md#read-and-edit) for which Bash commands your `Read` and `Edit` deny rules cover.263When Claude views a file this way, Claude Code also loads any [subdirectory `CLAUDE.md`](https://code.claude.com/docs/en/memory#how-claude-md-files-load) and [path-scoped rules](https://code.claude.com/docs/en/memory.md#path-specific-rules) that apply to that file. See [Read and Edit permission rules](https://code.claude.com/docs/en/permissions.md#read-and-edit) for which Bash commands your `Read` and `Edit` deny rules cover.

264 264 


383 383 

384The [WebSocket source](#websocket-source) has its own approval prompt, which the classifier also decides in auto mode.384The [WebSocket source](#websocket-source) has its own approval prompt, which the classifier also decides in auto mode.

385 385 

386The tool is not available on Amazon Bedrock, Google Cloud's Agent Platform, or Microsoft Foundry. It is also not available when `DISABLE_TELEMETRY` or `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC` is set. On Windows, the tool is available only when [Git Bash](https://code.claude.com/docs/en/setup.md#set-up-on-windows) is installed.386Monitor needs a minimum version or Git Bash in these cases:

387 

388* **Minimum version**: on Amazon Bedrock, Claude Platform on AWS, Google Cloud's Agent Platform, or Microsoft Foundry, or with `DISABLE_TELEMETRY` or `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC` set, Monitor requires Claude Code v2.1.310 or later. The requirement applies when [feature-flag fetching](https://code.claude.com/docs/en/env-vars.md#features-that-need-feature-flag-fetching) is off

389* **Windows**: the tool is available only when [Git Bash](https://code.claude.com/docs/en/setup.md#set-up-on-windows) is installed

387 390 

388Plugins can declare monitors that start automatically when the plugin is active, instead of asking Claude to start them. See [plugin monitors](https://code.claude.com/docs/en/plugins/components.md#monitors).391Plugins can declare monitors that start automatically when the plugin is active, instead of asking Claude to start them. See [plugin monitors](https://code.claude.com/docs/en/plugins/components.md#monitors).

389 392 

Details

177 177 

178**1. Open the diff view**178**1. Open the diff view**

179 179 

180A diff indicator shows lines added and removed across the session, for example `+42 -18`. Select it to open the diff view, with a file list on the left and changes on the right.180After Claude pushes its changes to a branch, the **Changes** card in the panel beside the chat shows the lines added and removed across the session, for example `+42 -18`. Click those counts to open the diff view.

181 

182* You can also click **Changes** in the session's title bar, or in the bar's **⋮** menu.

183* To show the panel when it's hidden, click the **Show session rail** icon in the session's title bar, or in the bar's **⋮** menu.

181 184 

182The diff compares the session's changes against its base branch by default. To compare against a different branch, select **Compare against** and pick one.185The diff compares the session's changes against its base branch by default. To compare against a different branch, select **Compare against** and pick one.

183 186 


187 190 

188**3. Create a pull request**191**3. Create a pull request**

189 192 

190When the diff looks right, select **Create PR** at the top of the diff view. You can open it as a full PR, a draft, or jump to GitHub's compose page with a generated title and description.193When the diff looks right, [show the panel again](https://code.claude.com/docs/en/claude-code-on-the-web.md#review-changes) if the **Changes** card is out of view, then create a pull request or a draft from the card:

194 

195* Click **Create PR**. Claude Code creates the pull request with a generated title and description.

196* To open a draft instead, right-click **Create PR**, select **Create draft PR** to change what the button does, then click the button

191 197 

192**4. Keep iterating after the PR**198**4. Keep iterating after the PR**

193 199