Skip to main content

Safety model

A cleanup tool should never be the reason you lose data. This page spells out every guard windowsweep applies, what it refuses to touch, and what it will delete. Read it once; refer back when something surprises you.

The chokepoint​

Every file and folder windowsweep removes with its own code passes through one function, Remove-PathSafe (or Send-ToRecycleBin for personal files), with a declared target root. It refuses, in order:

  1. paths with .. segments, UNC paths and drive roots;
  2. fifteen declared roots: Windows, System32, SysWOW64, both Program Files folders, ProgramData, C:\Users with its Default and Public profiles, your profile root, its AppData folder and the Roaming, Local and LocalLow folders inside it;
  3. 66 protected subtrees, 50 path patterns and 13 file names - the lists below;
  4. the tool's own data folder;
  5. any path you excluded yourself;
  6. any path that does not lie strictly inside the target root the calling section declared.

Refusal 5 is the one you set. --exclude-path P names a tree, every section refuses it, and each refusal is logged as excluded: <path> and listed in the --json summary's excluded[].

No flag bypasses refusals 1, 2, 3, 5 or 6. --purge-all changes how much of a cache goes, never where the tool may reach. Nor do --select, --select-file, --permanent or --i-understand-deep.

Refusal 4 has two doors and both are windowsweep's own housekeeping. --prune-history N deletes logs, reports and crash bundles older than N days, and --uninstall-data removes the whole folder after a confirmation --yes does not answer. Neither reaches anything outside %USERPROFILE%\.windowsweep.

The second guard, for browsers and editors​

A browser or editor target is not a path; it is a layout. windowsweep resolves it to the cache folders inside every profile it finds, and each resolved folder must also pass Test-KnownCacheLeaf, an allowlist of cache folder names in lib/actions.ps1. Anything else is refused by name with REFUSE (not a known cache folder for a chromium layout). So a profile folder, a Local Storage folder or an extension folder is refused twice: once by the pattern list, and once because it is not on the allowlist.

Your own exclusions, and the machine-readable list​

--exclude-path P (repeatable, or excludePaths in the config file) names a tree you want left alone. It is enforced at the same chokepoint as everything else rather than inside one section, so it holds for every section: an excluded path is refused, logged as excluded: <path>, and reported once in the excluded[] array of the --json summary. A dry-run applies the same filter before it counts anything, so the rehearsal and the run report the same files and the same bytes.

A path that is both protected and excluded reports the protected reason, not the exclusion. That is deliberate: the protected list is the promise no flag can lift, and it is the stronger thing to tell you.

The protected lists are machine-readable. --list --json carries a protected object with subtrees (every protected folder, resolved for this machine) and categories (the same sentences --list-targets prints). Both readers take that list from one place, so a front end cannot show you a narrower promise than the console does.

What the tools it runs do on their own​

windowsweep makes no network call. Self-test check [9] greps the whole source for HTTP and socket calls and fails the build if one appears, and there is no update check anywhere in it.

The tools it runs for you keep their own habits: winget and npm may check their own sources and send their own telemetry; the engine itself never does.

Concretely: section 24 runs winget list to read what is installed, and winget refreshes its own package sources when they are more than a few minutes old and reports its own usage to Microsoft by default. Sections 1 and 22 run npm commands, and npm checks the registry for a newer npm unless you have set update-notifier=false. Section 1 also runs pnpm store prune inside the default batch.

None of that is windowsweep talking. It is the difference between a program that phones home and a program that runs one which does, and it is worth knowing before you read a firewall log and blame the wrong tool.

Never touched​

CategoryExamples
Your filesDocuments, Pictures, Music, Videos, Desktop, Contacts, Favorites, Links, Saved Games, Searches, 3D Objects, OneDrive, Dropbox, Google Drive, iCloud Drive
Credentials and agent state.ssh, .gnupg, .aws, .azure, .kube, .gcloud, .docker, .secrets, .password-store, .config, .local, .claude, .codex, .agents, .gemini, .copilot, .antigravity, .ollama, .vscode-server, .cursor-server
Toolchains and installed software%APPDATA%\npm, nvm, Volta, fnm, corepack, pnpm global, bun/deno/cargo/go binaries, .rustup, %LOCALAPPDATA%\Programs, WindowsApps, the Android SDK, JetBrains Toolbox
Browser dataprofile folders as a whole; Local Storage, Session Storage, IndexedDB, cookies, logins, history, bookmarks, extensions, Sync Data, Preferences, PWA CacheStorage, Firefox places/logins/prefs
Editor dataUser\settings.json, keybindings.json, snippets, globalStorage, local History
Store appsPackages\*\LocalState, Settings, RoamingState
WindowsPrefetch (clearing it slows boot), Windows\Installer, WinSxS (only DISM touches it), System32\config, Windows\servicing, Windows\Boot, Windows\Fonts, System Volume Information, Recovery, EFI, NTUSER.DAT, UsrClass.dat, hiberfil/pagefile/swapfile (only powercfg touches hiberfil), Recycle Bin contents (only Clear-RecycleBin)

windowsweep --list-targets prints every path each section can reach on your machine, then the 66 protected subtrees one per line. Four summary lines close it: the declared roots; browser profile data; editor user data, UWP LocalState and toolchains; and the protected file names alongside Prefetch, Windows\Installer and WinSxS.

What it deletes, by tier​

TierSectionsRecoverable?
Report - reads and prints, deletes nothing in any mode0, 21, 22, 24, 25Nothing is removed
Rebuilds - caches and temp files the tool or Windows recreates on next use1, 2, 3, 5, 6, 7, 8, 9, 10, 12, 13, 14, 17, 28No undo. Nothing is copied first; a cache comes back because the tool that made it makes it again. Not everything in 12, 13 and 14 does - see below
Slow to rebuild - Android emulator images, recreated in Android Studio4No undo. Recreating one takes minutes and no download while its system image is still installed - but everything installed or saved inside the emulator, and its snapshots, are gone. The per-AVD idle gate exists for that reason
Recycle Bin - personal files or leftover folders you selected18, 19, 23, 27; section 26's second leftover passThe Recycle Bin, until you empty it. Section 19 always recycles selected files; --permanent can bypass recycling for supported other sections
Permanent11 (empty the Recycle Bin), 16 (event logs), 26 (a program's own uninstaller)No undo
Configuration - hibernation off or reduced, disk images compacted, a Chrome AI policy15 (hibernation), 20 (disk-image compaction), 29 (Chrome AI model policy)The setting persists until you change it; section 15 removes hiberfil.sys and powercfg /hibernate on puts it back

Sections 13 and 14 hand their work to Windows' own cleanup and component-store tools, and some of what those remove does not come back: a previous Windows installation, superseded drivers and components, and crash dumps. --reset-base additionally removes the ability to uninstall the updates already installed. The tier name describes the rule; those are the exceptions to it.

The idle gate​

The engine samples each volume to see whether last-access times are live. Where they are, idle age uses write and creation time so an indexer reading an old file does not make it look new. Elsewhere it uses the newest of write, access and creation. The default window is --days 100; temp entries use --temp-days 3. The JSON summary names volumes where last-access is live in access_live_volumes. An idle timestamp is a clue for review, not proof that a personal file is unneeded.

Versioned tool caches (Cypress, Playwright, Gradle distributions, Squirrel app-x.y.z folders) also apply a keep-newest rule: the freshest version of each tool is never removed by the idle gate.

Developer mode​

The saved developer answer changes seven sections, in two ways. Sections 1, 2, 3 and 5 prune by the idle gate when the answer is yes and clear their caches completely when it is no. Sections 4, 17 and 20 are skipped when the answer is no. Nothing in either mode changes what the tool may reach; it changes whether a cache is pruned or cleared, and whether a section runs at all. See Developer mode.

Batch policy​

PolicySectionsUnattended (--all, --only, --profile)
safe0, 1, 2, 3, 5, 6, 7, 8, 9, 10, 21, 28 (+12, 13 when elevated); 22, 24, 25 are read-only and safe but are not in --allrun with --yes
opt-in4, 14run only when named in --only or a profile, with --yes
deep11, 15, 16, 20, 29refused without --i-understand-deep; --dry-run previews are allowed
interactive17, 18, 19, 23, 26, 27never, unless a selection was supplied; they need a person choosing items

--yes never applies to personal files, project files or programs: interactive sections show their selection prompt even with --yes, default to none, and ask a final question --yes does not answer. Section 20's disk picker is the documented exception (deep-gated, --yes selects every disk).

A scripted selection is a person's choice, and it is the one thing that does lift the interactive refusal. --select 1,3 and --select-file paths.txt name exactly which items go, in advance, so a script or a GUI can drive these sections unattended - and because the naming is explicit, the selection also answers the section's final confirmation. It is a narrow, deliberate door: the refusal exists to stop unchosen deletion, not scripted deletion. --yes on its own still selects nothing and still answers nothing, and neither flag reaches anything the deletion chokepoint would otherwise refuse.

Running programs​

A browser, editor or app that is open keeps its cache files locked and half-written. Its targets are skipped with a skipped: X is running line and a hint to re-run the section after closing it. Files any program has open are skipped individually and counted, never treated as errors.

The walker checks the reparse-point attribute before descending, so a junction or symlink is removed as a link and its target is never entered. Paths beyond 260 characters (deep node_modules) are handled through the \\?\ prefix. The self-test proves both with a real junction and a 400+ character path.

Dry-run​

--dry-run short-circuits every deletion helper and every destructive external command (docker, cleanmgr, Dism, powercfg, wevtutil, diskpart, service stop/start, registry writes), printing what would happen and tallying an estimate. The self-test compares a fixture tree's file names, sizes, write times and directories before and after a dry-run to check that it did not change.

No undo​

Sections 11 and 16 have no undo of any kind: they empty the Recycle Bin and clear the Windows event logs. Both require --i-understand-deep. Section 26 also has no undo when you select a program to uninstall. --permanent can delete supported selected leftovers outright, but section 19 always sends selected personal files to the Recycle Bin. The rebuild tiers are one-way as well. There is no copy, no staging folder and no restore command: a cache is gone the moment it is removed, and it comes back only because the tool that made it makes it again. The session log records three shapes rather than one. Remove-PathSafe and Send-ToRecycleBin write a line per path with its size. A prune writes one line per folder instead: how many files went, how many bytes, and from where. An external command writes the command and the code it exited with. The JSON report records every section's outcome. All of it is a record of what happened, not a way to reverse it.

Inspect before you trust​

windowsweep --self-test # the guards, on this machine
windowsweep --list-targets # every path the tool can touch
windowsweep --scan # sizes, read-only
windowsweep --dry-run --all --yes

Last Updated: 2026-11-03