[BUG] Windows desktop app: agent tool writes creating new entries at the %APPDATA% / %LOCALAPPDATA% root silently land in the MSIX container

Status Open
Maintainer reply None cached
Activity 0 comments · opened Aug 24, 2026
Corrected 2026-08-24. An earlier version of this report overstated the scope, claiming all writes to %APPDATA%/%LOCALAPPDATA% were redirected. Testing narrowed it to the rule below: only new entries at the root are affected, and editing existing files works normally.

Summary

The Claude desktop app on Windows is an MSIX-packaged app. The tool subprocesses it spawns (Bash, and the Write/Edit tools) inherit its package identity, so Windows applies MSIX file-system redirection to them.

The rule, established by probe:

  • Creating a new entry directly at the %APPDATA% or %LOCALAPPDATA% root — a new file, or a new directory — is silently redirected into the package container at C:\Users\<user>\AppData\Local\Packages\Claude_pzs8sxrjxfjjc\LocalCache\{Roaming,Local}\.
  • Writes inside a subdirectory that already exists in the real filesystem pass through normally, including creating new files there.
  • Reads fall through to the real path.

The failure is silent. The tool reports success, and reading the file back returns the redirected copy, so the agent's own verification confirms a write that never reached the intended path.

This is correct Windows behaviour for a packaged app. It is nevertheless a mismatch for a coding agent, whose purpose is to modify the user's real filesystem.

What this does and does not affect

Affected — first-time creation of a tool config directory. This is the case that surfaced the bug: an agent asked to configure yt-dlp creates %APPDATA%\yt-dlp\config. yt-dlp\ does not exist, so the whole directory is redirected. The agent reports success, verifies by reading the file back, and the config never reaches the real path. The user's yt-dlp continues to behave as if unconfigured, with no error anywhere.

An independent example from the same session: gh created %LOCALAPPDATA%\GitHub CLI\device-id while running under the agent. New directory at the root — redirected. This is not specific to how our tools write files.

Not affected — editing existing configs. %APPDATA%\Claude\claude_desktop_config.json, %APPDATA%\Code\User\settings.json and similar are edited normally, because their parent directories already exist. An earlier version of this report claimed otherwise; that was wrong, and testing disproved it.

The practical exposure is therefore narrower than "config editing is broken", but it lands squarely on first-time setup tasks — a common category of agent work, and the one where the user is least likely to have a prior state to compare against.

Related issues

MSIX redirection has been reported against several desktop subsystems: #25579 (wrong userData path), #26073 ("Edit Config" opens the wrong claude_desktop_config.json), #47977 (DXT ${__dirname}), #48362 (session persistence, EXDEV inside the container), #55320 (saveTrust logs success but writes nothing — closed as duplicate), #63633 (Cowork bundlePath), #58421 (system prompt cites non-existent Roaming\Claude paths).

I read #88999 and #55320 in full; the others I reviewed only via their titles and summaries, but they appear to concern the desktop app's own reads and writes. This report covers a different surface: the agent's tool subprocesses writing to arbitrary user-owned paths. I could not find an existing issue covering that.

Environment

| | |
|---|---|
| Claude desktop app | Claude_1.34493.1.0_x64__pzs8sxrjxfjjc (v1.34493.1.0) |
| Install location | C:\Program Files\WindowsApps\Claude_1.34493.1.0_x64__pzs8sxrjxfjjc |
| OS | Windows 11 Pro for Workstations, 10.0.26200.0 |
| Shells | PowerShell 5.1 and Git Bash, both via the app's tools |
| Not WSL | Native Windows |

Reproduction

From the Claude desktop app on Windows, have the agent run:

echo "probe" > "$APPDATA/probe.txt"          # new entry at the root
mkdir -p "$APPDATA/newdir" && echo "x" > "$APPDATA/newdir/inner.txt"
ls -l "$APPDATA/probe.txt"                   # agent sees it: EXISTS

Then, in a PowerShell window the user opens themselves:

Test-Path "$env:APPDATA\probe.txt"           # False
Test-Path "$env:APPDATA\newdir\inner.txt"    # False
Test-Path "$env:LOCALAPPDATA\Packages\Claude_pzs8sxrjxfjjc\LocalCache\Roaming\probe.txt"   # True

Contrast — this passes through, because the parent directory already exists in the real filesystem:

# user creates the directory and file first
New-Item -ItemType Directory -Force "$env:APPDATA\existing-dir" | Out-Null
Set-Content "$env:APPDATA\existing-dir\target.txt" "ORIGINAL"
# agent then writes into it, via Bash or the Edit tool
echo "MODIFIED" > "$APPDATA/existing-dir/target.txt"
echo "new" > "$APPDATA/existing-dir/newfile.txt"
Get-Content "$env:APPDATA\existing-dir\target.txt"    # MODIFIED  - real file changed
Test-Path   "$env:APPDATA\existing-dir\newfile.txt"   # True      - real file created

The Write tool reproduces the redirected case identically, reporting File created successfully.

Evidence

All Test-Path results below were run by the user in their own PowerShell, outside the app. Where they disagree with the agent's view, the agent reported success.

| Write | Real? |
|---|---|
| New file at %APPDATA% root | No — silent |
| New directory + file at %APPDATA% root | No — silent |
| New file at %LOCALAPPDATA% root | No — silent |
| Modify existing file in existing real subdir of %APPDATA% (Bash) | Yes |
| Modify existing file in existing real subdir of %APPDATA% (Edit tool) | Yes |
| New file in existing real subdir of %APPDATA% | Yes |
| %LOCALAPPDATA%\Programs\Python\...\site-packages (existing subdir) | Yes |
| %USERPROFILE% root, %USERPROFILE%\.claude, project working dir | Yes |
| C:\ root | No — but a loud ACL error |

The C:\ row is the control: genuine OS denials surface correctly, so the silence is specific to redirection.

Redirected files were subsequently located in the container:

...\Packages\Claude_pzs8sxrjxfjjc\LocalCache\Roaming\root-probe-2.txt
...\Packages\Claude_pzs8sxrjxfjjc\LocalCache\Roaming\newdir-probe\inner.txt
...\Packages\Claude_pzs8sxrjxfjjc\LocalCache\Roaming\yt-dlp\config
...\Packages\Claude_pzs8sxrjxfjjc\LocalCache\Local\GitHub CLI\device-id

Two independent Claude Code sessions saw each other's redirected files, consistent with one shared package container rather than a per-process overlay.

On detectability

The obvious check does not catch this: reading back the file just written returns the redirected copy, so the agent's own verification confirms a write that never landed.

Detection is possible — checking whether the file appeared under ...\LocalCache\Roaming\ proves redirection occurred — but it requires already suspecting MSIX redirection. In our case the agent only found it after roughly an hour of misdiagnosis, having first chased %APPDATA% values, ACLs, elevation, PowerShell profile scripts, reparse points, Controlled Folder Access, and Windows Terminal's own package container. Nothing in the tool output pointed toward the cause.

Ruled out

  • Not the machine: the user's own writes to %APPDATA% land in the real folder, and their os.listdir shows the genuine directory contents.
  • Not the tool layer: Bash, Write and Edit behave consistently with the rule above.
  • Not permission mode: enabling Bypass Permissions changed nothing.
  • Not working-directory scope: a session scoped to C:\, which places %APPDATA% inside the working directory, behaved the same.
  • Not the documented Bash sandbox: the docs state native Windows is unsupported, and this reproduces regardless of dangerouslyDisableSandbox, which does not lift it.
  • Not reparse points, not Defender Controlled Folder Access (disabled), not Git Bash path mistranslation (no C:\c\... artifacts).

Suggested fixes

  1. Preferred — break tool subprocesses out of the package container. Windows provides PROC_THREAD_ATTRIBUTE_DESKTOP_APP_POLICY with PROCESS_CREATION_DESKTOP_APP_BREAKAWAY_ENABLE_PROCESS_TREE for packaged apps that launch desktop tooling. Spawned shells would then see the same filesystem as the user.
  2. Fallback — detect and warn. If the app has package identity, detect writes that create new entries at a redirected root and warn, or fail loudly rather than silently succeeding.
  3. Minimum — document it, so agents and users have something to search for when a file goes missing.

Workaround

Keep anything the real system must read out of the %APPDATA%/%LOCALAPPDATA% roots, or have the user pre-create the directory so writes pass through. Verify writes from a shell outside the app rather than by reading them back.

Running Claude Code as a CLI from an ordinary terminal should avoid this entirely, since such a process has no package identity — this follows from the user's own shell writing normally to these paths, though I did not test the CLI directly.

View original on GitHub ↗