Claude Code 2.1.314, released at 01:06 UTC on 30 October, adds permissions.blockWritesOutsideWorkingDirectories. In 24 headless runs on my laptop the Write and Edit tools refused every path outside the project while it was on: a sibling folder, /tmp, a path through a symlink inside the project, and a path that Write(*) and Edit(*) allow rules let through the moment the setting was off.

The setting covers three tools and nothing else. A printf hi > file in Bash wrote the same file the Write tool had just refused, under the same settings, because an Edit allow rule covered the target and the shell redirect check never consults the block. Shell writes answer to the rules you already had and to the sandbox.

It also changes things the changelog line doesn't mention. A settings.json in any .claude folder becomes a hard refusal instead of a prompt, EnterWorktree and ExitWorktree leave the tool list, additionalDirectories supplied by the repository don't count, and 2.1.312 accepts the key and enforces nothing. Auto-memory and plan files still save. The settings reference has no entry for it yet.

One line in the changelog

The 2.1.314 release notes carry a single line about it: "Added permissions.blockWritesOutsideWorkingDirectories: Write, Edit and NotebookEdit refuse paths outside the working directories in every permission mode." It is the write-side twin of blockReadsOutsideWorkingDirectories, which arrived in 2.1.257 and has a full entry in the settings reference. At 08:31 UTC the write setting appeared on the changelog page and on none of the eight other documentation pages I checked.

Three days before the release, issue #105342 described a subagent-written Rust test whose fixture ran rm -rf ~ from inside cargo test and emptied a good part of someone's home directory. Two commenters there had already worked out that the new setting would not have helped, because the delete ran inside a test process and never went through a file tool. My runs put numbers on where the line sits.

What I ran

Each run was claude -p with --output-format stream-json on Haiku 5.5, in a throwaway git repository in a temp folder, with a sibling folder called outside next to it. The setting went in through --settings '{"permissions":{"blockWritesOutsideWorkingDirectories":true}}' with --setting-sources project. Most runs used acceptEdits mode. The ones marked "allow rules" added Write(*) and Edit(*), which in acceptEdits approve a write anywhere without a prompt.

A headless run can't answer a prompt, so a prompt shows up as a tool error saying Claude requested permission and you haven't granted it. The block shows up as a different error. The 24 runs cost $0.42, 30 cents of which were the two plan-mode runs.

The refusal, and what it beats

Write target, 2.1.314 Setting Allow rules Result
outside/t1.txt on none refused by the block
outside/t1b.txt off none prompt
outside/t2.txt off Write(), Edit() written
outside/t2b.txt on Write(), Edit() refused by the block
proj/linkout/t4.txt, a symlink to outside on Write(), Edit() refused, "resolves through a symlink"
Edit of outside/edit-me.txt on Write(), Edit() refused by the block; Read of the same file allowed
/tmp/t10.txt and $TMPDIR/t10b.txt on Write(), Edit() refused by the block
lab/PROJ/t13.txt, the project folder in different case on Write(), Edit() refused by the block

The error says the path "is outside" the project, "the permissions.blockWritesOutsideWorkingDirectories setting blocks writes outside the working directories. Ask the user to add the directory with /add-dir, or to remove that setting." The third and fourth rows are the point of the feature: same allow rules, a file on disk with the setting off and a refusal with it on.

Two rows will bite people who didn't ask for them. The comparison is case-sensitive, so on my case-insensitive APFS volume the project folder spelled in capitals counted as outside. And /tmp is outside. The sandbox lets shell commands write to the temp folder; the Write tool under this setting can't. If your CLAUDE.md tells Claude to put scratch files in /tmp, each of those steps now ends in the error above and a request for /add-dir.

The redirect that went through

With the block on, plus allow rules Edit(//private/tmp/claude-501/**) and Bash(printf *), I asked for exactly one command: printf hi > outside/t3.txt. Bash reported it completed, and the file is there with "hi" in it. Minutes earlier, under the same block, the Write tool had refused that folder.

Claude Code checks the target of a shell redirect against your Edit allow and deny rules, the protected paths and the working directories. The allow rule covered the target, so the redirect passed. The block is not part of that check, and without the Edit rule the redirect would have prompted, the way it always has. So the setting isn't a leak, and it isn't a fence either. What limits a shell command, and every process it starts, is the sandbox's filesystem layer, which confines subprocess writes to the working directory, the temp folder and the paths you add. That is the control issue #105342 needed. This setting is for a different problem: a mode or a rule set that would otherwise let the file tools write anywhere.

What stays open

Target Result
~/.claude/projects/<project>/memory/test-memory.md, the auto-memory folder written
The session's own plan file in ~/.claude/plans/, in a plan-mode run written
~/.claude/plans/t6-plan.md, an arbitrary name outside plan mode refused by the block
<repo>/.claude/worktrees/agent-<id>/t16.txt, by a worktree-isolated subagent written
outside/t8.txt with --add-dir outside written
outside/t9b.txt with additionalDirectories in the same --settings flag written
outside/t9.txt with additionalDirectories in the repo's .claude/settings.json refused by the block
outside/t11.txt with the setting only in the repo's .claude/settings.json refused, the repo setting was enforced

The two places Claude Code itself tells the model to write, the auto-memory folder and the current session's plan file, are exempt, so memory and plan mode keep working. ExitPlanMode was unavailable in my headless plan-mode runs with the setting on and off alike, which is a -p matter and not this one.

Repository-supplied additionalDirectories don't widen the fence, the same rule the read block follows: a cloned repo shouldn't be able to grant itself your home folder. A cloned repo can narrow the fence, though, as the last row shows.

Settings files become a hard no

Writing proj/.claude/settings.json with the setting on produced a different error: "Writes to Claude Code settings files are blocked while permissions.blockWritesOutsideWorkingDirectories is on, because a settings file can lift that block. While a managed settings folder cannot be resolved, any .json file counts as one." The same came back for proj/sub/.claude/settings.json. With the setting off, that write is a protected-path prompt a human can accept. data.json, package.json and config/settings.json were written normally.

The second sentence of that error is the one to understand before a rollout. From the 2.1.314 binary: Claude Code resolves the managed settings directory, /Library/Application Support/ClaudeCode on macOS, before deciding whether a path is a settings file. A folder that doesn't exist resolves through its nearest existing parent, which is why my Mac, which has no managed folder, never tripped it. Any other failure logs "a managed drop-in directory did not resolve; any .json write counts as a possible drop-in", and from then on every .json write in the project, package.json included, gets the refusal above. I could not produce that condition without root, so I can tell you it exists and not how often it fires.

Two tools gone, one version blind

The init event of a headless run lists the session's tools. With the setting off there were 23, with it on 21. EnterWorktree and ExitWorktree are the two that disappear, and nothing in the changelog says so. The Agent tool's worktree isolation still works.

The last run used the 2.1.312 binary with the same settings and the same prompt. The file landed in outside, and stderr said nothing. The key is unknown to that version, so it is dropped. If you roll this out through managed settings, every developer on anything older than 2.1.314 is unfenced and unwarned.

What to do

If you want the file tools fenced to the project whatever mode a session is in, set the key in user or managed settings, list the folders you need as additionalDirectories in that same file rather than in the repo, and expect any /tmp habit in your instructions to fail until you add it too.

Don't mistake it for subprocess containment. For cargo test, npm run, make and scripts, turn the sandbox on and set allowUnsandboxedCommands to false. And if a workflow of yours has Claude editing .claude/settings.json, it stops under this key, with no prompt to accept.

Not tested: bypassPermissions and auto mode, because my own session's auto mode would not let me spawn a child with the flag bypass requires, NotebookEdit, Windows and WSL, and the interactive /add-dir path. Every run was a scripted prompt against folders on my laptop.