Windows: /tmp/ path diverges between Python and az, shipping stale zips
Summary
On Windows + Git Bash, a /tmp/foo argument resolves to two different filesystem locations depending on which tool reads it. Python (as a child process) resolves it drive-relative to C:\tmp\foo. Windows CLIs invoked through Git Bash (e.g. az, docker, kubectl) have the argument rewritten by MSYS before it reaches the executable, landing at %LOCALAPPDATA%\Temp\foo.
When a single Bash command chain uses both tools and shares a /tmp/ literal between them, Python writes to path A and the second tool reads from path B. The second tool's command succeeds because the MSYS location often contains a leftover file from a prior session — so az webapp deploy ships a stale zip while reporting Deployment has completed successfully. Health checks and status endpoints continue to pass because the stale zip is itself a valid build, just not the one that was just compiled.
User preferences did not redirect the Bash tool away from this pattern. The user had PowerShell configured as the preferred shell in settings.json (PowerShell has no MSYS layer and resolves /tmp/foo consistently across tools). The preference was not honored: the Bash tool continued to generate az webapp deploy command chains using /tmp/ literals. Adding the same rule to a memory file mid-session also did not change the Bash tool's subsequent command generation. Because neither channel altered the pattern, the fix likely needs to live inside the Bash tool's command-generation path rather than as user-facing configuration.
Reproduction
Standalone demo, Python stdlib only, deterministic:
git clone https://github.com/signalyer/splitbraindemo.git
cd splitbraindemo
python demo.py
| Pattern | Python arg | az arg | Result |
|---|---|---|---|
| 1 | /tmp/x | /tmp/x | Stale bytes shipped |
| 2 | tempfile.gettempdir() + 'x' | /tmp/x | Fresh |
| 3 | Explicit Windows path in both | Same | Fresh |
| 4 | C:/tmp/x in both | Same | Fresh |
The demo simulates both tools' path resolution in-process for portability and determinism. The same split is observable with actual Git Bash + real Python + real az webapp deploy on Windows; the demo avoids requiring Azure credentials.
Impact
The bug is not caught at deploy time because (a) az reports success, (b) downstream health checks pass (the stale zip is still a valid build), and (c) the changes shipped are typically not externally distinguishable from the code on disk. Silent deploy of prior-session code persists until someone ships a change whose presence can be verified externally (e.g., a new response header checkable with curl).
Suggested mitigation
At the Bash tool's command-generation layer: when a Bash command being generated contains both (a) a Python invocation opening a path for writing and (b) a subsequent command passing the same POSIX-style path literal to a Windows CLI (az, docker, kubectl, etc.), substitute the path for tempfile.gettempdir() in the Python side or an explicit Windows path throughout. This is detectable via a pattern check on the command text before execution.
At the agent default-behavior layer: prefer tempfile.gettempdir() over /tmp/ literals when writing files that will subsequently be consumed by a different tool in the same chain. Generalizes across shells and OSes.
Because settings.json preferences and memory rules were empirically insufficient to prevent the pattern, user-facing configuration alone is not a sufficient fix.
Environment
- Windows 10 / 11, Git Bash (MSYS2)
- Python 3.12
- Azure CLI 2.x
- Claude Code 1.x via Bash tool
Related
- #9883 (MSYS / cygpath)
- #2602 (Git Bash path conversion)
- #4507 (Git Bash path with spaces)
These describe Claude Code's own infrastructure interaction with MSYS. This issue is about the downstream two-tool-chain consequence in user deploy workflows — which none of them cover.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗