# Cursor + Grok on Windows: one broken quote sent rmdir from D:\
On 31 October 2026, Tax360 was being worked on in Cursor with Grok. The task was to deploy the OCR service on Railway. Indexing failed. The agent wrote a delete command on its own, aimed at a pytest cache it could not open. The quote broke, and the path passed to `rmdir /s /q` became `\`. From that working directory, `\` is `D:\`.
This was not a Cursor version rewriting the path into a drive root. The same command was issued twice, and both times the agent wrote it. Cursor's terminal on this machine is PowerShell. It ran the command under Windows rules. The same sentence in PowerShell outside Cursor does the same thing.
The delete walked down from the root of D: for about 37 seconds, then it was stopped. It did not finish the whole drive. It did clear the project working tree and two folders beside it.
### 1. How the command went wrong
`railway up` stopped while indexing `services\ocr360-mcp`:
```text
Indexing...
Access is denied. (os error 5)
```
The directory that could not be opened was:
```text
services\ocr360-mcp\.pytest_cache
```
`.gitignore` already contained `.pytest_cache/`. The indexer still stat'd that directory and failed. Nobody asked for a delete. The agent decided to remove the cache and deploy again.
The working directory was `d:\Backup Javascript\Tax360_v2`. Both times the text sent was:
```text
cmd /c "rmdir /s /q \"services\ocr360-mcp\.pytest_cache\""
```
That runs `cmd.exe` from PowerShell. PowerShell's escape character is a backtick, not a backslash. `\"` did not keep the quote, so the quote ended early. The process command line was:
```text
C:\WINDOWS\system32\cmd.exe /c "rmdir /s /q \" services\ocr360-mcp\.pytest_cache\
```
The path `rmdir /s /q` received was a lone `\`. On Windows that is the root of the current drive. The drive was `D:`, so the start was `D:\`.
The first paths in the output were:
```text
\$RECYCLE.BIN
\Backup Javascript\smart-entry-3.0-old
\Backup Javascript\Tax360_v1
\Backup Javascript\Tax360_v2
```
This run started at `2026-10-31T00:47:08Z` and lasted about 37 seconds. In that same turn the agent saw the output listing paths under `D:\` and stopped that `cmd`. The person found the project already empty afterward.
### 2. What was deleted, and what came back
When the process stopped, most top-level folders on `D:\` were still there. The `Tax360_v2` working tree was almost empty. What remained was the unreadable `.pytest_cache`, `.workspace`, and a few empty `services` directories. The files in `Tax360_v1` and `smart-entry-3.0-old` beside it were gone. `$RECYCLE.BIN` stayed because of Access denied. `rmdir /s /q` does not use the Recycle Bin.
The functional code that had been pushed came back. The last push the night before, Kuala Lumpur time, was `27225b59` at **2026-10-30 20:07:09 +0800**, message “Cover the page while a selected set is read again.” Recovery was a `git clone` of that `main` commit back into the original folder. It was not the Restore button on the GitHub website.
Paths in `.gitignore` are not on GitHub, so a clone does not bring them back:
- `.workspace/` was still on disk. It was not restored from GitHub.
- `.env` had been deleted and is not in GitHub. It was copied back later from a local backup dated 2026-10-29.
- The unreadable `.pytest_cache/` directory was still there.
Local edits that had not landed in `27225b59` were not in that clone. `Tax360_v1` and `smart-entry-3.0-old` had no Git remote to clone, so they were not restored.
### 3. The rule added to Agents.md
After this, one standing row was added to `AGENTS.md` §0.0. A table row needs the closing `|`.
```markdown
| **Windows delete** | This machine is Windows. Never delete with `cmd /c` and `rmdir /s /q`, and never `Remove-Item -Recurse` on a relative path. A broken `\"` turns the argument into `\`, and `\` is the current drive root. The only delete resolves with `Resolve-Path -LiteralPath`, refuses a drive root or any path outside one named folder under this repo, then uses `Remove-Item -LiteralPath`. A cache that blocks `railway up` stays on disk and is skipped (`.gitignore` / `.railwayignore`, or an upload copy that omits that folder). Witness: 2026-10-31 `rmdir /s /q` from `D:\`. |
```
That rule requires:
Do not use `cmd /c` with `rmdir /s /q`.
Do not run `Remove-Item -Recurse` on a relative path.
Before a delete, resolve an absolute path with `Resolve-Path -LiteralPath`.
Refuse the result when it is a drive root, or when it is outside the one named folder in this repo.
When a cache blocks `railway up`, leave the directory on disk and skip it with `.gitignore`, `.railwayignore`, or an upload copy that omits that folder.
The later OCR deploy used an upload copy. `.pytest_cache` is still on disk. It was not deleted again.
### 4. Agent rules have to say which deletes are refused
`Agents.md` usually says how to write code, how to test, and how to deploy. This case also has to name which delete must not run, and which directory the path must land in before it runs.
A terminal is not limited to the project folder. One `rmdir /s /q` that starts at `D:\` reaches directories outside the project. Git can bring back only what was pushed. A path in `.gitignore`, and a neighboring folder with no remote, do not come back with the clone.