Follow Discord
Sweep 02 Oct 2026 · 18:55Z Build v2.1.288 509 read Stable v2.1.285 Latest v2.1.287 Next v2.1.288 Feeds RSS JSON llms.txt llms-full.txt Unofficial
One capture · claude-code

One read of Claude Code CLIclaude-code-20260929T193702Z

6 pages moved out of 210 read.

Pages moved 6 significant first
Pages read 210 in this capture
Captured 19:37 UTC
Corpus hash 0fbd52167cb7 corpus-hash

What this read moved

1-6 of 6

agent-sdk/file-checkpointing Changed · +7 / -126 lines

from line 2
22 
33> Track file changes during agent sessions and restore files to any previous state
44 
5File checkpointing tracks file modifications made through the Write, Edit, and NotebookEdit tools during an agent session, allowing you to rewind files to any previous state. Want to try it out? Jump to the [interactive example](#try-it-out).
5File checkpointing tracks file modifications made through the [Write](/docs/en/tools-reference#write-tool-behavior), [Edit](/docs/en/tools-reference#edit-tool-behavior), and [NotebookEdit](/docs/en/tools-reference#notebookedit-tool-behavior) tools during an agent session, allowing you to rewind files to any previous state. To watch a rewind restore a file, jump to the [interactive example](#try-it-out).
66 
7With checkpointing, you can:
8 
9* **Undo unwanted changes** by restoring files to a known good state
10* **Explore alternatives** by restoring to a checkpoint and trying a different approach
11* **Recover from errors** when the agent makes incorrect modifications
12 
137<Warning>
148 Only changes made through the Write, Edit, and NotebookEdit tools are tracked. Changes made through Bash commands (like `echo > file.txt` or `sed -i`) are not captured by the checkpoint system, and neither are edits a [subagent](/docs/en/agent-sdk/subagents) applies, except a [skill with `context: fork`](/docs/en/skills#run-skills-in-a-subagent) that runs in the foreground.
159</Warning>
from line 22
2822 
2923To use file checkpointing, enable it in your options, capture checkpoint UUIDs from the response stream, then call `rewindFiles()` (TypeScript) or `rewind_files()` (Python) when you need to restore.
3024 
31The following example shows the complete flow: enable checkpointing, capture the checkpoint UUID and session ID from the response stream, then resume the session later to rewind files. Each step is explained in detail below. The examples in this section use the prompt "Refactor the authentication module". Run them in a project that contains an authentication module, or change the prompt to name files that exist in your project, so you can watch files change and see the rewind restore them.
25The examples in this section use the prompt "Refactor the authentication module". Run them in a project that contains an authentication module, or change the prompt to name files that exist in your project, so you can watch files change and see the rewind restore them.
3226 
27This example enables checkpointing, captures the checkpoint UUID and session ID from the response stream, then resumes the session later to rewind files. The example's numbered comments match the steps that follow.
28 
3329<CodeGroup>
3430 ```python Python theme={null}
3531 import asyncio
from line 141
145141 | Enable checkpointing | `enable_file_checkpointing=True` | `enableFileCheckpointing: true` | Tracks file changes for rewinding |
146142 | Receive checkpoint UUIDs | `extra_args={"replay-user-messages": None}` | `extraArgs: { 'replay-user-messages': null }` | Required to get user message UUIDs in the stream |
147143 
148 <CodeGroup>
149 ```python Python theme={null}
150 options = ClaudeAgentOptions(
151 enable_file_checkpointing=True,
152 permission_mode="acceptEdits",
153 extra_args={"replay-user-messages": None},
154 )
155 
156 async with ClaudeSDKClient(options) as client:
157 await client.query("Refactor the authentication module")
158 ```
159 
160 ```typescript TypeScript theme={null}
161 const response = query({
162 prompt: "Refactor the authentication module",
163 options: {
164 enableFileCheckpointing: true,
165 permissionMode: "acceptEdits" as const,
166 extraArgs: { "replay-user-messages": null }
167 }
168 });
169 ```
170 </CodeGroup>
144 The lead example under [Implement checkpointing](#implement-checkpointing) also sets the permission mode to `acceptEdits`, which approves the agent's file edits without a prompt. For more information, see [Permission modes](/docs/en/agent-sdk/permissions#permission-modes).
171145 </Step>
172146 
173147 <Step title="Capture checkpoint UUID and session ID">
from line 150
176150 For most use cases, capture the first user message UUID (`message.uuid`); rewinding to it restores the tracked files to their original state. To store multiple checkpoints and rewind to intermediate states, see [Multiple restore points](#multiple-restore-points).
177151 
178152 Capturing the session ID (`message.session_id`) is optional; you only need it if you want to rewind later, after the stream completes. If you're calling `rewindFiles()` immediately while still processing messages (as the example in [Checkpoint before risky operations](#checkpoint-before-risky-operations) does), you can skip capturing the session ID.
179 
180 <CodeGroup>
181 ```python Python theme={null}
182 checkpoint_id = None
183 session_id = None
184 
185 async for message in client.receive_response():
186 # Capture the first user message UUID as the checkpoint
187 if isinstance(message, UserMessage) and message.uuid and checkpoint_id is None:
188 checkpoint_id = message.uuid
189 # Capture session ID from the result message
190 if isinstance(message, ResultMessage):
191 session_id = message.session_id
192 ```
193 
194 ```typescript TypeScript theme={null}
195 let checkpointId: string | undefined;
196 let sessionId: string | undefined;
197 
198 for await (const message of response) {
199 // Capture the first user message UUID as the checkpoint
200 if (message.type === "user" && message.uuid && !checkpointId) {
201 checkpointId = message.uuid;
202 }
203 // Capture session ID from any message that has it
204 if ("session_id" in message) {
205 sessionId = message.session_id;
206 }
207 }
208 ```
209 </CodeGroup>
210153 </Step>
211154 
212155 <Step title="Rewind files">
213 To rewind after the stream completes, resume the session with an empty prompt and call `rewind_files()` (Python) or `rewindFiles()` (TypeScript) with your checkpoint UUID. You can also rewind during the stream; see [Checkpoint before risky operations](#checkpoint-before-risky-operations) for that pattern.
156 To rewind after the stream completes, resume the session with an empty prompt and call `rewind_files()` (Python) or `rewindFiles()` (TypeScript) with your checkpoint UUID. Enable checkpointing on the resumed session's options too, and call rewind from inside the response loop. You can also rewind during the stream. See [Checkpoint before risky operations](#checkpoint-before-risky-operations) for that pattern.
214157 
215 <CodeGroup>
216 ```python Python theme={null}
217 async with ClaudeSDKClient(
218 ClaudeAgentOptions(enable_file_checkpointing=True, resume=session_id)
219 ) as client:
220 await client.query("") # Empty prompt to open the connection
221 async for message in client.receive_response():
222 if checkpoint_id:
223 await client.rewind_files(checkpoint_id)
224 break
225 ```
226 
227 ```typescript TypeScript theme={null}
228 const rewindQuery = query({
229 prompt: "", // Empty prompt to open the connection
230 options: { ...opts, resume: sessionId }
231 });
232 
233 for await (const msg of rewindQuery) {
234 if (checkpointId) {
235 await rewindQuery.rewindFiles(checkpointId);
236 }
237 break;
238 }
239 ```
240 </CodeGroup>
241 
242158 If you capture the session ID and checkpoint ID, you can also rewind from the CLI. This command requires the `claude` executable, which comes from [installing Claude Code](/docs/en/setup). The SDK enables checkpointing for you, but when you run `claude -p` directly you must set the `CLAUDE_CODE_ENABLE_SDK_FILE_CHECKPOINTING` environment variable:
243159 
244160 ```bash theme={null}
from line 669
753669 
754670This error occurs when you call `rewindFiles()` or `rewind_files()` after you've finished iterating through the response. The connection to the CLI process closes when the loop completes.
755671 
756**Solution**: Resume the session with an empty prompt, then call rewind on the new query:
757 
758<CodeGroup>
759 ```python Python theme={null}
760 # Resume session with empty prompt, then rewind
761 async with ClaudeSDKClient(
762 ClaudeAgentOptions(enable_file_checkpointing=True, resume=session_id)
763 ) as client:
764 await client.query("")
765 async for message in client.receive_response():
766 if checkpoint_id:
767 await client.rewind_files(checkpoint_id)
768 break
769 ```
770 
771 ```typescript TypeScript theme={null}
772 // Resume session with empty prompt, then rewind
773 const rewindQuery = query({
774 prompt: "",
775 options: { ...opts, resume: sessionId }
776 });
777 
778 try {
779 for await (const msg of rewindQuery) {
780 if (checkpointId) {
781 await rewindQuery.rewindFiles(checkpointId);
782 }
783 break;
784 }
785 } catch (error) {
786 // An error here means the rewind didn't complete, for example the checkpoint
787 // wasn't found or the session couldn't be resumed.
788 console.error(`Rewind session ended with an error: ${error}`);
789 }
790 ```
791</CodeGroup>
672**Solution**: Resume the session with an empty prompt, then call rewind on the new query. The lead example under [Implement checkpointing](#implement-checkpointing) shows the resume-and-rewind call in both languages, at the comment marked Step 3.
792673 
793674## Next steps
794675 

errors Changed · +28 / -0 lines

This page is larger than the 256 KiB this site keeps, so one side of the diff below stops where the stored text does.

from line 258
258258| `Its agent definition was not restored: the folder its definition file came from is not trusted` | [Tool errors](#teammate-agent-definition-not-restored) |
259259| `Message too large for cross-session delivery` | [Tool errors](#message-too-large-for-cross-session-delivery) |
260260| `Too many messages to this session just now` | [Tool errors](#too-many-messages-to-this-session-just-now) |
261| `Cross-session message was dropped at the recipient session's inbox` | [Tool errors](#cross-session-message-dropped-at-the-inbox) |
261262| `Refusing to send: reply target is a symlink` / `Refusing to send: cannot vet reply target` | [Tool errors](#refusing-to-send-a-cross-session-message) |
262263| `Refusing to read <path>: its symlink resolution changed after permission was checked (<reason>)` / `Refusing to search <path>: its symlink resolution changed after permission was checked` | [Tool errors](#refusing-after-a-symlink-changed) |
263264| `Refusing to write <path>: its parent-directory symlink resolution changed after permission was checked` / `Refusing to write <path>: it is a symbolic link. Write to the link's target path instead` | [Tool errors](#refusing-after-a-symlink-changed) |
from line 2839
28382839Claude Code couldn't add one of the servers you selected in `claude mcp add-from-claude-desktop`. The command still imports the other selected servers and prints one line per server it couldn't add. Before v2.1.205, the first server that failed stopped the import.
28392840 
28402841```text theme={null}
2841Could not import my server: Invalid name my server. Names can only contain letters, numbers, hyphens, and underscores.
2842```
2843 
2844The text after the server name is the reason. The most common one is the name check: Cla
2842Could not import my server: Invalid name my server. Names can only contain let

permission-modes Changed · +81 / -45 lines

#### Repeated-block thresholds ### How auto mode evaluates actions ### Which paths are critical ### Other targets that count as critical paths ### Removals inside nested commands and inline scripts ### Rewrite a flagged command ### Critical-path removals in each permission mode ### Time limits and denials in auto and bypassPermissions modes

from line 203
203203 
204204 * **[Cloud sessions](/docs/en/claude-code-on-the-web)**: 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.
205205 * **[Remote Control](/docs/en/remote-control) sessions** on your local machine: Manual, Accept edits, and Plan for a session you started yourself, and you can't select Auto or Bypass permissions from the app. For a project thread running on your computer, see [Run a thread on your own computer](/docs/en/claude-projects#run-a-thread-on-your-own-computer).
206 * Except for Bypass permissions, the dropdown shows the permission mode the local session is in, including one set from the terminal. It updates when the permission mode changes in the app or in the terminal. The session never reports Bypass permissions to claude.ai, so switching into it from the terminal doesn't change what the dropdown shows.
206 * Except for Bypass permissions, the dropdown shows the permission mode the local session is in, including one set from the terminal. It updates when the permission mode changes in the app or in the terminal.
207207 * Sessions hosted by the [desktop app](/docs/en/desktop) or the [VS Code extension](/docs/en/vs-code) report permission mode changes to claude.ai as they happen, the same as sessions hosted in a terminal.
208208 * Before v2.1.202, sessions connected with `/remote-control` or `claude --remote-control` didn't report their permission mode at all, so claude.ai and the mobile app could show a permission mode the session wasn't in. The mismatch affected only the label. Claude Code generated permission prompts from the session's actual permission mode, and they still appeared in the app for approval.
209209 
from line 459
459459 
460460When auto mode can't approve your session's actions, what happens depends on the case:
461461 
462* **A blocked action**: Claude Code shows a notification and lists the action in `/permissions` under the **Recently denied** tab, where you can press `r` to retry it with a manual approval. When the classifier produces [no verdict on the action](/docs/en/errors#auto-mode-cannot-determine-the-safety-of-an-action), because a safety check separate from auto mode refused the classifier's own request or its response didn't parse, Claude Code denies the action without the notification or the **Recently denied** entry.
463* **Repeated blocks**: if the classifier blocks an action 3 times in a row or 20 times total, auto mode pauses and Claude Code resumes prompting. Approving the prompted action resumes auto mode. These thresholds are not configurable. Any allowed action resets the consecutive counter, while the total counter persists for the session and resets only when its own limit triggers a fallback. Claude Code doesn't count a denial toward either threshold when [a safety check separate from auto mode refuses the classifier's own request](/docs/en/errors#auto-mode-cannot-determine-the-safety-of-an-action); the linked entry covers how Claude Code handles those denials.
464* **Sessions that can't prompt**: a [non-interactive](/docs/en/headless) `-p` run without a [`--permission-prompt-tool`](/docs/en/cli-reference#cli-flags) has no prompt to fall back to. When repeated blocks reach a threshold, the action doesn't run and Claude keeps working. The same applies when [a safety check separate from auto mode refuses the classifier's request](/docs/en/errors#auto-mode-cannot-determine-the-safety-of-an-action). Claude Code doesn't stop the run in either case.
462* **A blocked action**: Claude Code shows a notification and lists the action in `/permissions` under the **Recently denied** tab, where you can press `r` to retry it with a manual approval.
463* **Repeated blocks**: if the classifier blocks an action 3 times in a row or 20 times total, auto mode pauses and Claude Code resumes prompting. Approving the prompted action resumes auto mode. See [Repeated-block thresholds](#repeated-block-thresholds) for how the blocks are counted.
464* **No verdict from the classifier**: when a safety check separate from auto mode refuses the classifier's own request, or the classifier's response doesn't parse, Claude Code denies the action without the notification or the **Recently denied** entry. See [Auto mode cannot determine the safety of an action](/docs/en/errors#auto-mode-cannot-determine-the-safety-of-an-action) for the message each case shows and what to do.
465465* **No verdict from the server**: under [server-side classifier review](#server-side-classifier-review), Claude Code denies an action the server gives no verdict for, and stops the turn after ten responses in a row with no verdict. See [The server returned no safety verdict](/docs/en/errors#the-server-returned-no-safety-verdict).
466* **A mode switch during a check**: if you switch permission modes while a classifier check is pending, Claude Code discards a verdict the new mode wouldn't have requested rather than applying it: you're prompted for approval instead, or the action is auto-denied in [`dontAsk` mode](#allow-only-pre-approved-tools-with-dontask-mode).
466* **A mode switch during a check**: if you switch permission modes while a classifier check is pending, Claude Code discards a verdict the new mode wouldn't have requested. You're prompted for approval instead, or the action is auto-denied in [`dontAsk` mode](#allow-only-pre-approved-tools-with-dontask-mode).
467467 
468#### Repeated-block thresholds
469 
470The thresholds of 3 blocks in a row and 20 blocks total are not configurable. The total counter persists for the session and resets only when its own limit triggers a fallback. Claude Code doesn't count a denial toward either threshold when a safety check separate from auto mode refuses the classifier's own request.
471 
472A [non-interactive](/docs/en/headless) `-p` run without a [`--permission-prompt-tool`](/docs/en/cli-reference#cli-flags) has no prompt to fall back to. When repeated blocks reach a threshold, the action doesn't run and Claude keeps working. Claude Code doesn't stop the run.
473 
468474Repeated blocks usually mean the classifier is missing context about your infrastructure. Use `/feedback` to report false positives, or have an administrator [configure trusted infrastructure](/docs/en/auto-mode-config).
469475 
476### How auto mode evaluates actions
477 
478The following sections cover the order Claude Code evaluates an action in, how the classifier reviews subagent work, and what classifier calls add in cost and latency.
479 
470480<span id="how-the-classifier-evaluates-actions" />
471481 
472482<AccordionGroup>
from line 643
633643 
634644## Critical paths
635645 
646Critical paths are the directories Claude Code protects from `rm` and `rmdir` commands, such as the filesystem root, your home directory, and your working directory.
647 
636648Claude Code never lets a [`permissions.allow`](/docs/en/permissions#manage-permissions) rule or a [`PreToolUse` hook](/docs/en/permissions#extend-permissions-with-hooks) that returns `"allow"` approve an `rm` or `rmdir` command that targets a critical path, even in modes that skip other prompts. This circuit breaker guards against model error. A matching deny rule still blocks the command outright.
637649 
638What happens instead depends on your permission mode:
650What happens instead [depends on your permission mode](#critical-path-removals-in-each-permission-mode). `Remove-Item` and the `cmd` removal built-ins have their own checks, covered in [Remove-Item in PowerShell](#remove-item-in-powershell).
639651 
640| Mode | What Claude Code does with a critical-path removal |
641| :- | :- |
642| `default`, `acceptEdits` | Asks you to approve it |
643| `plan` | Asks you to approve it. When [the classifier reviews commands during planning](#analyze-before-you-edit-with-plan-mode) and no bypass permissions are available, handles it as in `auto` mode |
644| `auto` | Asks you to approve it in the terminal, with a time limit. Elsewhere, denies it |
645| `dontAsk` | Denies it |
646| `bypassPermissions` | Asks you to approve it, with a time limit in the terminal |
652### Which paths are critical
647653 
648If an explicit [ask rule](/docs/en/permissions#manage-permissions) matches the command, Claude Code asks you instead, even in `auto` mode and without a time limit. In modes that ask, a [`PermissionRequest` hook](/docs/en/hooks#permissionrequest) can answer the prompt.
649 
650The `auto` and `bypassPermissions` handling requires Claude Code v2.1.281 or later. To turn it off, set [`CLAUDE_CODE_DISABLE_DANGEROUS_RM_TIMEOUT=1`](/docs/en/env-vars#variables) in the environment that launches Claude Code. In `auto` mode, critical-path removals then go to the classifier instead, and in `bypassPermissions` mode the prompt has no time limit.
651 
652In `auto` and `bypassPermissions` modes, the terminal prompt shows a two-minute countdown:
653 
654* If the countdown runs out before you answer, Claude Code denies the command and tells Claude what to do instead, so an unattended session keeps working.
655* Press any key while the prompt is open to stop the countdown and keep the prompt waiting for your answer.
656* After three of these prompts run out unanswered in a session, Claude Code stops showing them and denies further critical-path removals immediately. Sending a new message starts the count over.
657 
658In `auto` mode, wherever Claude Code can't show you a terminal prompt, it denies the command immediately, for example in [non-interactive runs](/docs/en/headless) with `-p`, in [Agent SDK](/docs/en/agent-sdk/permissions) sessions, and in the VS Code extension's chat panel and the Desktop app. The denial tells Claude to report what it wanted to delete and leave the removal to you.
659 
660654Claude Code treats an `rm` or `rmdir` target as a critical path when it is any of the following:
661655 
662656* The filesystem root
from line 660
666660* Your working directory and its parents
667661* Your additional working directories and their parents, but only when the removal is a glob under one of them, such as `rm -rf <dir>/*`. `rm -rf <dir>` on the directory itself doesn't trigger this check
668662 
669Claude Code also treats a glob or trailing slash directly under a shell variable, such as `rm -rf "$DIR"/*`, as a critical-path removal, because the command becomes a removal from the filesystem root when the variable is empty.
663### Other targets that count as critical paths
670664 
671The prompt for this variable case names the flagged `rm` and says how to rewrite it so the check passes:
665Claude Code also treats the following `rm` and `rmdir` targets as critical paths. The last column says why each one counts.
672666 
673* For a variable such as `$DIR`, guard each expansion so the shell stops with an error when the variable is unset or empty, as in `rm -rf "${DIR:?}"/*`, or use a literal path
674* For a variable that is normally set, such as `$HOME`, use a literal path
667| Target | Example | Why it counts |
668| :- | :- | :- |
669| A glob or trailing slash directly under a shell variable | `rm -rf "$DIR"/*` | The command becomes a removal from the filesystem root when the variable is empty |
670| The same form under a positional parameter such as `$1` or `$@`, when nothing in the command gives it a value | `rm -rf "$1"/*` | The command expands to a removal from the root |
671| A shell variable followed by one common top-level directory name, such as `mnt`, `tmp`, `usr`, or `Users` | `rm -rf "$TMPDIR/mnt"` | When the variable expands empty, the command removes `/mnt` |
672| A variable that the same command assigns from a directory-printing substitution, such as `$(pwd)` or `$(git rev-parse --show-toplevel)` | `D=$(pwd); rm -rf "$D"` | The value can name your working directory or repository root |
673| A target that is only the output of a command substitution, when the `rm` is recursive | `rm -rf "$(pwd)"` | Claude Code can't check the target before the command runs |
674| A trailing command substitution after a critical path | `rm -rf ~/$(cmd)` | Claude Code checks the path that would remain if the substitution expanded empty, here your home directory |
675| A target that is only backslashes | `rm -rf "\\"` | Git Bash on Windows reads a lone backslash as the current drive's root, so the check applies on every platform |
675676 
676A removal whose expansions are all guarded that way passes this check, so in `bypassPermissions` mode it runs without a prompt unless another check in this section flags it.
677To turn off the check on a target that is only command substitution output, set [`CLAUDE_CODE_DISABLE_SUBSTITUTION_RM_PROMPT=1`](/docs/en/env-vars#variables) in the environment that launches Claude Code.
677678 
678Claude Code also treats these targets as critical paths:
679### Removals inside nested commands and inline scripts
679680 
680* **A shell variable followed by one top-level directory name**, such as `rm -rf "$TMPDIR/mnt"`: when the variable expands empty, the command removes `/mnt`. This covers common top-level names such as `mnt`, `tmp`, `usr`, and `Users`.
681* **A variable that the same command assigns from a directory-printing substitution**, such as `D=$(pwd); rm -rf "$D"` or an assignment from `$(git rev-parse --show-toplevel)`: the value can name your working directory or repository root. A `"${D:?}"` guard doesn't clear this check, because the variable isn't empty; use a literal path instead.
682* **A backslash-only target**, such as `rm -rf "\\"`: Git Bash on Windows reads a lone backslash as the current drive's root, so the check applies on every platform.
683* **Only the output of a command substitution**, such as `rm -rf "$(pwd)"`, when the `rm` is recursive: Claude Code can't check the target before the command runs, so the prompt tells Claude to run the substitution on its own first and then remove the literal paths it prints. To turn off this one check, set [`CLAUDE_CODE_DISABLE_SUBSTITUTION_RM_PROMPT=1`](/docs/en/env-vars#variables) in the environment that launches Claude Code.
681Claude Code also looks inside these constructs:
684682 
685When a trailing command substitution can expand empty, as in `rm -rf ~/$(cmd)`, Claude Code checks the path that would remain, your home directory in this example.
683* **Nested commands**: a subshell with `(...)`, a brace group with `{ ...; }`, command substitution with `$(...)` or backticks, or process substitution with `<(...)`. Claude Code finds a critical-path removal whether it sits inside the nested form, as in `(rm -rf ~)` or `echo "$(rm -rf ~)"`, or elsewhere in the same command.
684* **Inline scripts**: Claude Code checks a script passed to a shell such as `sh -c` or `bash -c` for the shell variable and positional parameter [targets](#other-targets-that-count-as-critical-paths).
685 * When the script is double-quoted, the invoking shell expands its variables before the inner shell receives the script. In `find . -name '*.tmp' -exec sh -c "rm -rf \"$1\"/*" _ {} \;`, the command expands to a removal from the filesystem root once per match, and Claude Code treats it as a critical-path removal.
686 * A single-quoted script that binds `$1` to a real value, as `sh -c 'rm -rf "$1"/*' _ {}` does, isn't flagged.
686687 
687Hiding the removal inside a subshell with `(...)`, a brace group with `{ ...; }`, command substitution with `$(...)` or backticks, or process substitution with `<(...)`, doesn't skip the check. Claude Code finds a critical-path removal whether it sits inside the nested form, as in `(rm -rf ~)` or `echo "$(rm -rf ~)"`, or elsewhere in the same command.
688### Rewrite a flagged command
689 
690How to rewrite a command so it passes the check depends on which of the [other targets](#other-targets-that-count-as-critical-paths) it uses:
691 
692* **A glob or trailing slash under a variable such as `$DIR`**: guard each expansion so the shell stops with an error when the variable is unset or empty, as in `rm -rf "${DIR:?}"/*`, or use a literal path. A removal whose expansions are all guarded that way passes this check, so in `bypassPermissions` mode it runs without a prompt unless another [critical-path](#critical-paths) check flags it.
693* **A glob or trailing slash under a variable that is normally set, such as `$HOME`**: use a literal path.
694* **A variable assigned from a directory-printing substitution**: use a literal path. A `"${D:?}"` guard doesn't clear this check, because the variable isn't empty.
695* **A target that is only command substitution output**: run the substitution on its own first, then remove the literal paths it prints. The prompt tells Claude to do the same.
696 
697For a glob or trailing slash under a variable, the prompt names the flagged `rm` and says how to rewrite it so the check passes.
698 
699### Critical-path removals in each permission mode
700 
701What Claude Code does with a critical-path removal depends on your permission mode:
702 
703| Mode | Outcome |
704| :- | :- |
705| `default`, `acceptEdits` | Asks you to approve it |
706| `plan` | Asks you to approve it. When [the classifier reviews commands during planning](#analyze-before-you-edit-with-plan-mode) and no bypass permissions are available, handles it as in `auto` mode |
707| `auto` | Asks you to approve it in the terminal, with a [time limit](#time-limits-and-denials-in-auto-and-bypasspermissions-modes). Elsewhere, denies it |
708| `dontAsk` | Denies it |
709| `bypassPermissions` | Asks you to approve it, with a time limit in the terminal |
710 
711If an explicit [ask rule](/docs/en/permissions#manage-permissions) matches the command, Claude Code asks you instead, even in `auto` mode and without a time limit. In modes that ask, a [`PermissionRequest` hook](/docs/en/hooks#permissionrequest) can answer the prompt.
712 
713### Time limits and denials in auto and bypassPermissions modes
714 
715In `auto` and `bypassPermissions` modes, the terminal prompt for a critical-path removal shows a two-minute countdown:
716 
717* If the countdown runs out before you answer, Claude Code denies the command and tells Claude what to do instead, so an unattended session keeps working.
718* Press any key while the prompt is open to stop the countdown and keep the prompt waiting for your answer.
719* After three of these prompts run out unanswered in a session, Claude Code stops showing them and denies further critical-path removals immediately. Sending a new message starts the count over.
720 
721In `auto` mode, wherever Claude Code can't show you a terminal prompt, it denies the command immediately, for example in [non-interactive runs](/docs/en/headless) with `-p`, in [Agent SDK](/docs/en/agent-sdk/permissions) sessions, and in the VS Code extension's chat panel and the Desktop app. The denial tells Claude to report what it wanted to delete and leave the removal to you.
722 
723The `auto` and `bypassPermissions` handling requires Claude Code v2.1.281 or later. To turn it off, set [`CLAUDE_CODE_DISABLE_DANGEROUS_RM_TIMEOUT=1`](/docs/en/env-vars#variables) in the environment that launches Claude Code. In `auto` mode, critical-path removals then go to the classifier instead, and in `bypassPermissions` mode the prompt has no time limit.
688724 
689725### Remove-Item in PowerShell
690726 

settings-reference Changed · +42 / -13 lines

#### Sandboxed commands under the block

This page is larger than the 256 KiB this site keeps, so one side of the diff below stops where the stored text does.

from line 1590
15901590 
15911591### `permissions.blockReadsOutsideWorkingDirectories`
15921592 
1593Stop Claude from reading paths outside the session's [working directories](/docs/en/permissions#working-directories) with the Read, Grep, Glob, and LSP tools, in every permission mode including `bypassPermissions`. A Bash command that reads a matching path through a file command Claude Code recognizes, such as `cat`, prompts you even in auto mode and `bypassPermissions` mode. Requires Claude Code v2.1.257 or later.
1593Make Claude's file tools refuse reads outside your [working directories](/docs/en/permissions#working-directories) in every permission mode, including `bypassPermissions`. Claude Code denies `Read`, `Grep`, `Glob`, and `LSP` calls on those paths and tells Claude to ask you to add the directory with `/add-dir`. Files Claude Code itself needs stay readable, such as your skills, plugins, rules, agents, commands, and the `CLAUDE.md` memory file under `~/.claude/`. Requires Claude Code v2.1.257 or later.
15941594 
1595Claude Code doesn't refuse shell commands the same way:
1596 
1597* [Actions no mode auto-approves](/docs/en/permission-modes#actions-no-mode-auto-approves) covers when a shell command that reads such a path prompts you
1598* [Sandboxed commands under the block](#sandboxed-commands-under-the-block) covers what a sandboxed command can read
1599 
15951600A Bash command the shell parser can't trace, such as one that changes directory more than once or runs a subshell, prompts you even in auto mode and `bypassPermissions` mode. The prompt appears even when the command names no path outside the working directories. This prompt doesn't apply when the command runs in the [sandbox](/docs/en/sandboxing) and the sandbox enforces the block.
15961601 
15971602Claude Code also writes `true` here when you choose to block such reads on [auto mode's prompt before the first read outside the working directories](/docs/en/permission-modes#first-read-outside-the-working-directories).
15981603 
1599* **Scope**: [`Any file`](#scopes). If any settings source sets `true`, the block applies, so a repository's checked-in file can turn the block on for a project but can't lift a block you set.
1604* **Scope**: [`Any file`](#scopes). A `true` in any file applies, so a repository can turn the block on for itself but can't lift yours.
16001605* **Type**: Boolean
1601 * `true`: file reads outside the working directories are blocked
1602 * `false`: the same as unset; a `true` in any other settings file still blocks
1603* **Default**: unset, so reads outside the working directories follow your permission mode and rules
1606 * `true`: Claude's file tools refuse reads outside the working directories
1607 * `false`: the same as unset; the block still applies if another file sets `true`
1608* **Default**: unset, so reads outside the working directories follow your [permission mode](/docs/en/permission-modes)
16041609 
16051610```json settings.json theme={null}
16061611{
from line 1615
16101615}
16111616```
16121617 
1613If only a repository's checked-in settings file adds a directory, the block still applies to reads there. When [`autoMemoryDirectory`](#automemorydirectory) comes from the project's `.claude/settings.json`, or from a `.claude/settings.local.json` [treated as repository-supplied](/docs/en/permissions#when-your-local-settings-file-needs-trust), Claude Code loads no [auto memory](/docs/en/memory#storage-location) from that directory and saves none to it. Files Claude Code itself needs stay readable, such as your skills, plugins, rules, agents, commands, and the `CLAUDE.md` memory file under `~/.claude/`.
1618Directories you add with `--add-dir`, `/add-dir`, or `additionalDirectories` in your user or managed settings count as working directories for the block. Directories added only in repository settings don't count: those in `.claude/settings.json`, and those in `.claude/settings.local.json` unless git reports that file as untracked. In a directory that isn't a git repository, or when git tracks the file, Claude Code treats `.claude/settings.local.json` as repository settings, so put directories you want to keep readable in your user settings instead.
16141619 
1615When the [sandbox](/docs/en/sandboxing) is on, the block also denies sandboxed commands read access to home directories and mounted-volume roots outside the working directories. A retry that needs approval to [run outside the sandbox](/docs/en/sandboxing#the-unsandboxed-retry-escape-hatch) prompts you even in `bypassPermissions` mode. Files a tool reads from your home directory, such as `~/.gitconfig`, are denied with the rest; re-open a specific path with [`sandbox.filesystem.allowRead`](#sandbox-filesystem-allowread) when a tool needs it.
1620When [`autoMemoryDirectory`](#automemorydirectory) comes from the project's `.claude/settings.json`, or from a `.claude/settings.local.json` [treated as repository-supplied](/docs/en/permissions#when-your-local-settings-file-needs-trust), Claude Code loads no [auto memory](/docs/en/memory#storage-location) from that directory and saves none to it.
16161621 
1622To lift the block, remove the key from every settings file that sets it, then start a new session.
1623 
1624#### Sandboxed commands under the block
1625 
1626When [sandboxing](/docs/en/sandboxing) is on, the block also covers sandboxed commands. Claude Code denies them read access to your home directory and to the other roots that hold user files: `/Users`, `/home`, `/root`, `/Volumes`, `/mnt`, `/media`, `/run/media`, and `/srv`. It then re-opens the working directories, [worktrees](/docs/en/worktrees) Claude Code creates in the session, the session temp directory, and the parts of `~/.claude` that commands need, such as skills and plugins. While the block is in force, `allowRead` and `allowWrite` entries from repository settings don't count.
1627 
16171628When the session's working directory is a linked [git worktree](/docs/en/worktrees), including one Claude Code entered mid-session, the repository's common `.git` directory stays readable and writable to sandboxed commands, so git keeps working there.
16181629 
1630In these cases the block doesn't reach sandboxed commands, while Claude's file tools keep enforcing it:
1631 
1632* Filesystem isolation is off through [`sandbox.filesystem.disabled`](#sandbox-filesystem-disabled)
1633* [`allowManagedReadPathsOnly`](#sandbox-filesystem-allowmanagedreadpathsonly) is set
1634* The path of the directory you started Claude Code in contains a glob character such as `*`, `?`, or `[`
1635 
1636Under the block, Claude Code re-opens your global git configuration files to sandboxed commands so `git` keeps your identity and settings:
1637 
1638* `~/.gitconfig`
1639* The `config`, `ignore`, and `attributes` files under `$XDG_CONFIG_HOME/git`, which defaults to `~/.config/git`
1640* Files your global git configuration names through `[include]`, `[includeIf]`, `core.excludesFile`, or `core.attributesFile`
1641 
1642Claude Code judges each file separately. When a file lies where a sandboxed command can write, directly or through a symlink, Claude Code doesn't re-open the files it names.
1643 
1644On Linux and WSL2, a configuration file that is a symlink can stay unreadable at its own path, and `git` then runs without it. `~/.git-credentials` and `$XDG_CONFIG_HOME/git/credentials` stay blocked.
1645 
1646If a re-opened file holds a secret, such as an `http.extraHeader` token, add its path to [`sandbox.filesystem.denyRead`](#sandbox-filesystem-denyread). A `denyRead` entry that covers a file always takes precedence over this re-open.
1647 
16191648### `permissions.defaultMode`
16201649 
16211650Set the [permission mode](/docs/en/permission-modes) new sessions start in. When you leave it unset, sessions start in the [built-in default](/docs/en/permission-modes#which-mode-a-session-starts-in) for your surface.
from line 1942
19131942}
19141943```
19151944 
1916Claude Code merges entries across every settings scope the session loads: user, project, local, and managed paths combine rather than replace each other, and Claude Code adds the paths from your `Edit(...)` allow permission rules. An `allowWrite` entry can't lift a [protected path](/docs/en/sandboxing#protected-paths).
1945Claude Code merges `allowWrite` entries and the paths from your `Edit(...)` allow permission rules across every settings scope the session loads, leaving out the ones from repository settings while [`permissions.blockReadsOutsideWorkingDirectories`](#sandboxed-commands-under-the-block) is on. An `allowWrite` entry can't lift a [protected path](/docs/en/sandboxing#protected-paths).
19171946 
19181947### `sandbox.filesystem.denyWrite`
19191948 
from line 2007
19782007}
19792008```
19802009 
1981Claude Code resolves a `.` entry to the project root in project settings and to `~/.claude` in user settings. Claude Code merges entries across every settings file the session loads unless [`allowManagedReadPathsOnly`](#sandbox-filesystem-allowmanagedreadpathsonly) is set.
2010Claude Code resolves a `.` entry to the project root in project settings and to `~/.claude` in user settings. Claude Code merges entries across every settings file the session loads unless [`allowManagedReadPathsOnly`](#sandbox-filesystem-allowmanagedreadpathsonly) is set, and leaves out entries from repository settings while [`permissions.blockReadsOutsideWorkingDirectories`](#sandboxed-commands-under-the-block) is on.
19822011 
19832012### `sandbox.filesystem.allowManagedReadPathsOnly`
19842013 
from line 4175
41464175 
41474176* **Scope**: [`Any file`](#scopes). A `true` in managed settings can't be overridden by `false` elsewhere.
41484177* **Type**: Boolean
4149 * `true`: Claude Code replaces each inline shell command with `[shell command execution disabled by policy]` instead of running it
4150 * `false`: inline shell runs
4151* **Default**: unset, so inline shell runs
4152 
4153```json settings.json theme={null}
4154{
4155 "disableSkillShellExecution": true
4156}
4157```
4158 
4159Bundled skills and skills deployed through managed settings are unaffected.
4160 
4161### `skillOverrides`
4162 
4163Hide or collapse a [skill](/docs/en/skills#override-skill-visibility-from-settings) without editing its `SKILL.md`. Claude Code applies the value under each skill's name to the skill list Claude sees and to your `/` autocomplete.
4164 
4165* **Scope**: [`Any file`](#scopes). The `/skills` menu writes to `.claude/settings.local.json`.
4166* **Type**: object mapping skill name to one of:
4167 * `"on"`: Claude sees the skill and you can type `/name`
4168 * `"name-only"`: Claude sees the skill by name without its description
4169 * `"user-invocable-only"`: Claude doesn't see the skill, but you can still type `/name`
4170 * `"off"`: Claude doesn't see the skill and `/name` is hidden from autocomplete
4171* **Default**: unset, so every skill is `"on"`
4172 
4173This example lists `legacy-context` to Claude by name only and hides `deploy` from Claude and from `/` autocomplete:
4174 
4175```json settings.json theme={null}
4176{
4177 "skillOverrides": {
4178 "legacy-context": "name-only",
4179 "deploy": "off"
4180 }
4181}
4182```
4183 
4184Overrides don't apply to plugin skills, which you manage through `/plugin`.
4185 
4186In managed settings and files passed with `--settings`, a key on a bundled skill's alias, such as `checkup` for `/doctor`, also applies to the skill; see [how alias keys combine with keys on the skill's own name](/docs/en/skills#override-skill-visibility-from-settings).
4187 
4188### `syncClaudeAiSkills`
4189 
4190Turn off the download of the [skills enabled for your claude.ai account](/docs/en/skills#how-synced-skills-behave). Claude Code downloads them into `~/.claude/skills/synced/` in [terminal sessions where you sign in with your claude.ai account](/docs/en/skills#where-synced-skills-load), interactive or non-interactive, and in Cowork and cloud sessions. Set `false` to stop that download and stop loading the skills it already synced. Claude Code honors only `false`: `true` is the same as unset and doesn't turn syncing on where it's otherwise off.
4191 
4192* **Scope**: [`User, local, or managed`](#scopes), and files passed with `--settings`. A repository can't turn it off for you.
4193* **Type**: Boolean
4194 * `false`: Claude Code stops downloading synced skills and stops loading the ones already in `~/.claude/skills/synced/`. In user or managed settings, it also mov
4178 * `true`: Claude Code replaces each inline shell command with `[shell command execution disabled

permissions Changed · +1 / -1 lines

from line 246
246246 
247247#### Read-only commands
248248 
249Claude Code recognizes a built-in set of Bash commands as read-only and runs them without a permission prompt in every mode, except for a path that [`permissions.blockReadsOutsideWorkingDirectories`](/docs/en/settings-reference#permissions-blockreadsoutsideworkingdirectories) fences. The set includes `ls`, `cat`, `echo`, `pwd`, `head`, `tail`, `grep`, `find`, `wc`, `which`, `diff`, `stat`, `du`, `cd`, and read-only forms of `git`. The set is not configurable; to require a prompt for one of these commands, add an `ask` or `deny` rule for it. In auto mode, these commands can also wait for the classifier's review; see [how the classifier evaluates actions](/docs/en/permission-modes#how-the-classifier-evaluates-actions).
249Claude Code recognizes a built-in set of Bash commands as read-only and runs them without a permission prompt in every mode, except as [`permissions.blockReadsOutsideWorkingDirectories`](/docs/en/settings-reference#permissions-blockreadsoutsideworkingdirectories) changes for paths outside your working directories. The set includes `ls`, `cat`, `echo`, `pwd`, `head`, `tail`, `grep`, `find`, `wc`, `which`, `diff`, `stat`, `du`, `cd`, and read-only forms of `git`. The set is not configurable; to require a prompt for one of these commands, add an `ask` or `deny` rule for it. In auto mode, these commands can also wait for the classifier's review; see [how the classifier evaluates actions](/docs/en/permission-modes#how-the-classifier-evaluates-actions).
250250 
251251A redirect such as `ls > out.txt` adds a check on the target. See [Redirections](#redirections).
252252 

sandboxing Changed · +1 / -0 lines

from line 490
490490 
491491* **Default write behavior**: read and write access to the current working directory and its subdirectories, any directories you've added with `--add-dir`, `/add-dir`, or [`permissions.additionalDirectories`](/docs/en/settings-reference#permissions-additionaldirectories), plus the per-user temp directory that `$TMPDIR` points to
492492* **Default read behavior**: read access to the entire computer, except certain denied directories. Note that this default still allows reading credential files such as `~/.aws/credentials` and `~/.ssh/`. Use [`sandbox.credentials`](#protect-credentials) to block reads of these files and unset secret environment variables, or add the paths to `denyRead`.
493* **Read block**: with [`permissions.blockReadsOutsideWorkingDirectories`](/docs/en/settings-reference#permissions-blockreadsoutsideworkingdirectories) on, sandboxed commands also lose read access to your home directory and the other directories that hold user files, apart from the paths that [Sandboxed commands under the block](/docs/en/settings-reference#sandboxed-commands-under-the-block) lists. That section also says when this part of the block doesn't apply.
493494* **Blocked access**: cannot modify files outside the working directory, added directories, and the per-user temp directory without explicit permission, including shell configuration files such as `~/.bashrc` and system binaries in `/bin/`
494495* **Git worktrees**: when the working directory is a [linked git worktree](/docs/en/worktrees), the sandbox also allows writes to the main repository's shared `.git` directory so commands such as `git commit` can update refs and the index. Writes to `hooks/` and `config` inside that directory remain denied.
495496* **Configurable**: define custom allowed and denied paths through settings
Feedback