[BUG] Windows desktop app: agent tool writes creating new entries at the %APPDATA% / %LOCALAPPDATA% root silently land in the MSIX container
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 atC:\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 theiros.listdirshows the genuine directory contents. - Not the tool layer: Bash,
WriteandEditbehave 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
- Preferred — break tool subprocesses out of the package container. Windows provides
PROC_THREAD_ATTRIBUTE_DESKTOP_APP_POLICYwithPROCESS_CREATION_DESKTOP_APP_BREAKAWAY_ENABLE_PROCESS_TREEfor packaged apps that launch desktop tooling. Spawned shells would then see the same filesystem as the user. - 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.
- 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.