When Reads And Writes Disagree
In March, a Claude Code user filed a data-loss report that is worth separating from the usual “the model ran a bad shell command” story.
The public issue is anthropics/claude-code#40321. The report says a session on macOS, running Claude Code 2.1.86, started inside a valid Next.js monorepo with normal git context. Claude was asked to create a new app under the existing repo. It created directories and wrote files, then read the tree back and did not see what it had just written.
That is the dangerous part. The issue describes a half-sandboxed state: writes reached the real filesystem, while reads came from an isolated view that did not match the real project. The model kept trying to create the files it could not see. By the time the user noticed, the report says the local repo was destroyed, including .git, source files, .env files, and local configuration.
I cannot verify the private project or reconstruct the original session. What I can verify is the public report, its current labels, and its status. As of August 3, 2026, #40321 is closed as not planned and labeled bug, area:sandbox, area:security, data-loss, has repro, platform:macos, and stale.
This is not evidence that current Claude Code still reproduces the same failure. It is a design case for the kind of contradiction an agent should treat as environmental corruption rather than as a normal file-writing problem.
Why This Case Matters
Most agent safety failures I work on sit above the tool boundary. A model proposes rm -rf, git clean -fdx, terraform destroy, or a write to a protected file. Those are hookable. A PreToolUse hook can inspect the proposed Bash, Write, Edit, or Read request and block it before it runs.
This report sits below that boundary.
If the runtime gives the agent inconsistent filesystem views, a hook can be running inside the same confused environment. It may see the same false read path the model sees. It can block known dangerous tool calls, but it cannot prove that the platform’s read and write isolation are symmetric unless it performs its own probe and treats a contradiction as a hard stop.
That distinction matters because the model’s behavior in the report was not exotic. It wrote files, checked whether they existed, failed to see them, and tried again. That is normal task completion behavior in a broken environment.
The failure is that the environment contradicted itself and the agent kept going.
The Check I Want Agents To Learn
Before an agent creates or rewrites a lot of files, it should be able to prove one boring invariant. Create a temporary probe directory, write a tiny file into it, read that file back, compare the contents, and remove the probe.
That does not make sandboxing safe. It only answers one narrow question: can this session read back a file it just wrote at the path it thinks it is using?
For a human terminal, this looks trivial. For an agent runtime, it is a useful tripwire. If mkdir succeeds but ls, cat, or test -f disagrees immediately afterward, the right action is not to keep editing. It is to stop and report that the filesystem view is inconsistent.
I would rather lose one coding session to a false alarm than let an agent continue after its environment has started lying about state.
A minimal probe from the repository root can be as boring as this:
probe_dir="$(mktemp -d .claude-fs-probe.XXXXXX)" || exit 1
probe_file="$probe_dir/read-after-write.txt"
trap 'rm -f "$probe_file"; rmdir "$probe_dir" 2>/dev/null' EXIT
payload="claude-fs-probe-$(date +%s)"
printf '%s\n' "$payload" > "$probe_file" &&
read_back="$(cat "$probe_file")" &&
test "$read_back" = "$payload"
probe_status=$?
exit "$probe_status"
The important part is not this exact shell. The important part is treating failure as a stop condition, not as another file-writing task for the model to push through.
This probe is also not a guarantee that every future tool call will see the same filesystem. It only proves that this session, at this path, can read back a file it just wrote. That is enough to catch the specific contradiction before a broad file-creation task starts.
What Actually Protects The Project
The unglamorous answer is still the strongest one:
-
Keep source code pushed to a remote.
-
Keep secrets outside the repo and recoverable from a vault or another machine.
-
Use local snapshots for files that are intentionally not in git.
-
Run large agent edits in a disposable worktree when possible.
-
Treat any read-after-write contradiction as a stop condition.
Hooks help with item 5 if they are designed to probe and fail closed. They do not replace item 1, item 2, or item 3.
That is the broader lesson from #40321. CLAUDE.md rules, permission prompts, sandboxing, hooks, and backups are not interchangeable safety layers. They fail in different places.
A prompt rule fails when the model stops prioritizing it. A permission prompt fails if the runtime executes after denial. A hook fails if the tool call never reaches it or if the runtime underneath it lies. A sandbox fails if reads and writes do not describe the same world.
The only layer in that list that still works after local state is destroyed is a copy somewhere else.
The Practical Version
If you maintain hook tooling, add a small filesystem consistency probe before high-impact write workflows.
If you use Claude Code on serious projects, do not let “it is sandboxed” be your backup plan. Make sure the repo is pushed, secrets are recoverable, and snapshots exist before letting an agent perform broad file creation or cleanup.
And if the model writes a file and cannot immediately read it back, stop the session. That is no longer a coding problem. It is an environment-integrity problem.