StorOps
See where your storage goes. Understand why. Move what matters. Clean what doesn't.
StorOps is not a disk scanner and not a disk cleaner. WizTree already answers
"what is taking up space" -- StorOps answers what those things are, whether
they're safe to touch, and carries out a cleanup or migration safely once the
user says go. Full rationale in docs/DESIGN.md.
This file defines how an agent should behave when using StorOps -- not just
which commands exist. Prefer following the workflows below over calling
commands ad hoc; the user should not need to know command names.
Non-negotiable rules
- Analysis before action. Always scan/inspect/identify before proposing
anything, and never skip straight to a write operation.
- Everything defaults to read-only.
storops scan, storops inspect,
storops search, storops identify, storops cleanup plan, and
storops migrate plan never modify the filesystem -- run them freely,
without asking first.
- Never guess what a path is from its name. Only
storops identify (backed
by rules/*.yaml) determines category/risk/deletability. A path with no
matching rule comes back unknown / critical -- treat that as "do not
touch", not as an invitation to reason about it from the folder name.
- Never treat "cache" or "temp" in a name as license to delete. Only act on
what
storops identify/storops cleanup plan actually classified.
- Critical-risk paths (Windows, Program Files, unknown system files, user
documents) are never offered for deletion or migration. This is enforced
in code (
assert_not_critical in src/storops/core/risk.py), not just
by convention -- don't try to route around it.
- Every write operation (
storops cleanup execute, storops migrate execute) requires the user's explicit, itemized confirmation first, and
the CLI itself refuses to run without --confirm. Show the plan, wait for
a real "yes", then pass --confirm -- never on the user's behalf
pre-emptively.
- If an application may be running, do not move its data.
storops migrate plan flags RequiresAppClosed; storops migrate execute refuses to
run without an explicit --app-closed acknowledgement in that case. Tell
the user to close the app -- don't assume it's closed and don't kill the
process yourself.
- For large, re-downloadable AI model/cache data (Hugging Face cache,
Ollama/LM Studio models, etc.), always state the consequence out loud
("this will need to be re-downloaded") before it's included in anything
the user approves.
- Prefer migration over deletion for anything the user identifies as
valuable. Deletion is for reclaimable/disposable data; large model or
project data that isn't disposable should be offered as MOVE, not DELETE.
- Prefer an application's own config-based relocation over a Junction.
storops migrate plan already encodes this precedence -- don't override
it towards Junction just because it seems simpler.
- Verify after every migration (
storops verify against the result file
storops migrate execute writes). If verification fails, say so plainly
and stop -- never delete or further modify anything to "clean up" a
failed verification.
- Don't let the scan backend (WizTree on Windows, gdu/du on Linux/macOS)
become a hard dependency in your reasoning. If it's missing entirely, the
CLI raises a clear error pointing at where to get it (WizTree:
https://diskanalyzer.com/ or
$env:STOROPS_WIZTREE_PATH; gdu:
https://github.com/dundee/gdu or $env:STOROPS_GDU_PATH) -- relay that
to the user rather than trying to work around it some other way.
- On Linux/macOS, every
--json result from a read/plan-tier command
(scan/inspect/search/cleanup plan/migrate plan) carries
Backend and BackendAdvice fields. BackendAdvice is non-null only
when StorOps fell back to the slower du backend because gdu wasn't
found. Mention it to the user once per conversation if it's non-null
(e.g. "by the way, installing gdu would make these scans noticeably
faster") -- don't repeat it on every single command, and don't mention it
at all on Windows or when it's null.
- On macOS, a scan's per-directory sizes will not add up to the volume's
used space, and you must not present them as if they should. Two
separate reasons: StorOps already prunes APFS firmlinks (
/Users and
/System/Volumes/Data/Users are literally the same directory, and an
unpruned du / counts the user's whole home twice), but APFS block
sharing -- file clones, and Time Machine local snapshots -- remains,
and no per-path size can attribute shared blocks to one path. Report
the ranking and the individual sizes, which are sound; do not compute
"everything else" by subtracting the total from the drive's used
figure, and do not tell the user their disk is lying to them.
Workflow: "why is my drive full?"
storops scan C:\ (or the drive the user mentioned) for top-level
consumers and free space. On macOS scan / -- not /System/Volumes/Data:
StorOps prunes the Data volume's firmlinked duplicates when it is handed
the real root, and scanning the Data volume directly reports the same
content under its uglier internal paths.
- To see what's inside several large entries at once, prefer one
storops search <path> --folders --max-depth 2 (bump to 3 if two levels isn't
enough) over storops inspect-ing each one individually. inspect
re-walks its whole target subtree from scratch every time it's called;
inspecting N large (and often nested/overlapping) subdirectories one at a
time repeats stat work a single search pass already covers, and
search's rows carry the same risk/recommended-action info inspect's
do. Reach for storops inspect <path> only to drill into one specific
directory further than that search already went.
- Cross-reference every notable entry with
storops identify (scan/inspect/
search already attach identity + recommended action, but call it
directly for a single path the user asks about).
- Present a ranked breakdown: what it is, how big, and the recommended
action (KEEP / DELETE / MOVE / CHECK) with reason and risk.
- Never delete or move anything at this stage -- this is purely diagnostic.
Workflow: "clean up disk space" / "delete X"
- Make sure the target has already been scanned/identified (run the scan
workflow above first if not).
- Run
storops cleanup plan (default --max-risk low; only raise it if
the user explicitly says they're fine with medium/high-risk items too).
This produces an itemized JSON plan -- nothing is deleted yet.
- Present the plan grouped by risk tier, each item's size, application, and
consequence (call out medium/high-risk consequences explicitly, e.g. "may
need to be re-downloaded"). Show the total reclaimable size.
- Ask the user to confirm. If they only want a subset, regenerate with a
tighter
--max-risk or point out which items to skip -- don't hand-edit
Approved flags in the plan file without telling the user exactly what
changed.
- Only once the user confirms, run
storops cleanup execute --plan-file <path> --confirm.
- Report the result per item (deleted / skipped / failed) and the total
reclaimed size. A
failed item (e.g. file in use) is reported, not
retried forcefully.
Workflow: "migrate X to another drive"
- Identify the source path (
storops identify if not already known from a
scan). If it's not Migratable, say so and explain why (e.g. critical,
or no known migration path) instead of improvising one.
- Run
storops migrate plan <source> <destination>. This decides the
method (application config change, or Junction as fallback), and
produces an ordered step list -- nothing is moved yet.
- Present the plan: source, destination, size, method, and whether the
application must be closed first. If
RequiresAppClosed, explicitly
ask the user to close it before proceeding.
- Ask for confirmation on the plan as a whole.
- Run
storops migrate execute --plan-file <path> --confirm (add
--app-closed once the user has confirmed the app is closed). This
copies the data, verifies file count/size against the source, and only
then removes the original -- for the Junction method it also relinks the
old path.
- If the method was an application config change (not a Junction), tell the
user the exact config change to make (from the plan's
MigrationHint)
-- StorOps does not edit arbitrary app config files itself.
- Run
storops verify --result-file <path from migrate execute output> and
report PASS/FAIL per check. On FAIL, stop and describe exactly what
didn't match -- never delete remaining data to "resolve" a failed
verification.
Workflow: "is it safe to delete/move ?"
Just run storops identify <path> and relay Category, Deletable,
Migratable, CleanupRisk, Consequence, and the recommended action verbatim --
this is the direct, deterministic answer; don't editorialize past what the
rule base actually says, and don't guess for an unknown result.
Command reference
| Tier |
Commands |
Confirmation |
| Read |
storops scan, storops inspect, storops search, storops identify |
none |
| Plan |
storops cleanup plan, storops migrate plan |
none (produces a plan file only) |
| Write |
storops cleanup execute, storops migrate execute |
requires --confirm (and --app-closed for migrations that need it) |
| Verify |
storops verify |
none (read-only re-check) |
Every command supports --json for machine-readable output. Invoke as
python -m storops <command> ..., or storops <command> ... if the package
has been pip install-ed.
See README.md for setup/requirements and rules/README.md for the rule
schema behind identification.
1---2name: storops3description: Storage Operations for AI Agents. Cross-platform (Windows, Linux, macOS): diagnose why a drive or volume is full, identify what specific applications/caches/AI-model files are consuming space, and safely clean up or migrate them -- with mandatory user confirmation before any write and verification after every migration. Use when the user asks things like "why is my C: drive full", "why is my disk full" / "/ is full", "clean up disk space", "move LM Studio / Ollama / Docker / <app> to another drive", or "is it safe to delete <path>".4license: MIT5---67# StorOps89**See where your storage goes. Understand why. Move what matters. Clean what doesn't.**1011StorOps is not a disk scanner and not a disk cleaner. WizTree already answers12"what is taking up space" -- StorOps answers what those things *are*, whether13they're safe to touch, and carries out a cleanup or migration safely once the14user says go. Full rationale in `docs/DESIGN.md`.1516This file defines how an agent should *behave* when using StorOps -- not just17which commands exist. Prefer following the workflows below over calling18commands ad hoc; the user should not need to know command names.1920## Non-negotiable rules21221. Analysis before action. Always scan/inspect/identify before proposing23 anything, and never skip straight to a write operation.242. Everything defaults to read-only. `storops scan`, `storops inspect`,25 `storops search`, `storops identify`, `storops cleanup plan`, and26 `storops migrate plan` never modify the filesystem -- run them freely,27 without asking first.283. Never guess what a path is from its name. Only `storops identify` (backed29 by `rules/*.yaml`) determines category/risk/deletability. A path with no30 matching rule comes back `unknown` / `critical` -- treat that as "do not31 touch", not as an invitation to reason about it from the folder name.324. Never treat "cache" or "temp" in a name as license to delete. Only act on33 what `storops identify`/`storops cleanup plan` actually classified.345. Critical-risk paths (Windows, Program Files, unknown system files, user35 documents) are never offered for deletion or migration. This is enforced36 in code (`assert_not_critical` in `src/storops/core/risk.py`), not just37 by convention -- don't try to route around it.386. Every write operation (`storops cleanup execute`, `storops migrate39 execute`) requires the user's explicit, itemized confirmation first, and40 the CLI itself refuses to run without `--confirm`. Show the plan, wait for41 a real "yes", then pass `--confirm` -- never on the user's behalf42 pre-emptively.437. If an application may be running, do not move its data. `storops migrate44 plan` flags `RequiresAppClosed`; `storops migrate execute` refuses to45 run without an explicit `--app-closed` acknowledgement in that case. Tell46 the user to close the app -- don't assume it's closed and don't kill the47 process yourself.488. For large, re-downloadable AI model/cache data (Hugging Face cache,49 Ollama/LM Studio models, etc.), always state the consequence out loud50 ("this will need to be re-downloaded") before it's included in anything51 the user approves.529. Prefer migration over deletion for anything the user identifies as53 valuable. Deletion is for reclaimable/disposable data; large model or54 project data that isn't disposable should be offered as MOVE, not DELETE.5510. Prefer an application's own config-based relocation over a Junction.56 `storops migrate plan` already encodes this precedence -- don't override57 it towards Junction just because it seems simpler.5811. Verify after every migration (`storops verify` against the result file59 `storops migrate execute` writes). If verification fails, say so plainly60 and stop -- never delete or further modify anything to "clean up" a61 failed verification.6212. Don't let the scan backend (WizTree on Windows, gdu/du on Linux/macOS)63 become a hard dependency in your reasoning. If it's missing entirely, the64 CLI raises a clear error pointing at where to get it (WizTree:65 https://diskanalyzer.com/ or `$env:STOROPS_WIZTREE_PATH`; gdu:66 https://github.com/dundee/gdu or `$env:STOROPS_GDU_PATH`) -- relay that67 to the user rather than trying to work around it some other way.6813. On Linux/macOS, every `--json` result from a read/plan-tier command69 (`scan`/`inspect`/`search`/`cleanup plan`/`migrate plan`) carries70 `Backend` and `BackendAdvice` fields. `BackendAdvice` is non-null only71 when StorOps fell back to the slower `du` backend because `gdu` wasn't72 found. Mention it to the user once per conversation if it's non-null73 (e.g. "by the way, installing gdu would make these scans noticeably74 faster") -- don't repeat it on every single command, and don't mention it75 at all on Windows or when it's `null`.7614. On macOS, a scan's per-directory sizes will not add up to the volume's77 used space, and you must not present them as if they should. Two78 separate reasons: StorOps already prunes APFS firmlinks (`/Users` and79 `/System/Volumes/Data/Users` are literally the same directory, and an80 unpruned `du /` counts the user's whole home twice), but APFS *block81 sharing* -- file clones, and Time Machine local snapshots -- remains,82 and no per-path size can attribute shared blocks to one path. Report83 the ranking and the individual sizes, which are sound; do not compute84 "everything else" by subtracting the total from the drive's used85 figure, and do not tell the user their disk is lying to them.8687## Workflow: "why is my drive full?"88891. `storops scan C:\` (or the drive the user mentioned) for top-level90 consumers and free space. On macOS scan `/` -- not `/System/Volumes/Data`:91 StorOps prunes the Data volume's firmlinked duplicates when it is handed92 the real root, and scanning the Data volume directly reports the same93 content under its uglier internal paths.942. To see what's inside several large entries at once, prefer one `storops95 search <path> --folders --max-depth 2` (bump to `3` if two levels isn't96 enough) over `storops inspect`-ing each one individually. `inspect`97 re-walks its whole target subtree from scratch every time it's called;98 inspecting N large (and often nested/overlapping) subdirectories one at a99 time repeats stat work a single `search` pass already covers, and100 `search`'s rows carry the same risk/recommended-action info `inspect`'s101 do. Reach for `storops inspect <path>` only to drill into one specific102 directory further than that search already went.1033. Cross-reference every notable entry with `storops identify` (scan/inspect/104 search already attach identity + recommended action, but call it105 directly for a single path the user asks about).1064. Present a ranked breakdown: what it is, how big, and the recommended107 action (KEEP / DELETE / MOVE / CHECK) with reason and risk.1085. Never delete or move anything at this stage -- this is purely diagnostic.109110## Workflow: "clean up disk space" / "delete X"1111121. Make sure the target has already been scanned/identified (run the scan113 workflow above first if not).1142. Run `storops cleanup plan` (default `--max-risk low`; only raise it if115 the user explicitly says they're fine with medium/high-risk items too).116 This produces an itemized JSON plan -- nothing is deleted yet.1173. Present the plan grouped by risk tier, each item's size, application, and118 consequence (call out medium/high-risk consequences explicitly, e.g. "may119 need to be re-downloaded"). Show the total reclaimable size.1204. Ask the user to confirm. If they only want a subset, regenerate with a121 tighter `--max-risk` or point out which items to skip -- don't hand-edit122 `Approved` flags in the plan file without telling the user exactly what123 changed.1245. Only once the user confirms, run `storops cleanup execute --plan-file125 <path> --confirm`.1266. Report the result per item (deleted / skipped / failed) and the total127 reclaimed size. A `failed` item (e.g. file in use) is reported, not128 retried forcefully.129130## Workflow: "migrate X to another drive"1311321. Identify the source path (`storops identify` if not already known from a133 scan). If it's not `Migratable`, say so and explain why (e.g. critical,134 or no known migration path) instead of improvising one.1352. Run `storops migrate plan <source> <destination>`. This decides the136 method (application config change, or Junction as fallback), and137 produces an ordered step list -- nothing is moved yet.1383. Present the plan: source, destination, size, method, and whether the139 application must be closed first. If `RequiresAppClosed`, explicitly140 ask the user to close it before proceeding.1414. Ask for confirmation on the plan as a whole.1425. Run `storops migrate execute --plan-file <path> --confirm` (add143 `--app-closed` once the user has confirmed the app is closed). This144 copies the data, verifies file count/size against the source, and only145 then removes the original -- for the Junction method it also relinks the146 old path.1476. If the method was an application config change (not a Junction), tell the148 user the exact config change to make (from the plan's `MigrationHint`)149 -- StorOps does not edit arbitrary app config files itself.1507. Run `storops verify --result-file <path from migrate execute output>` and151 report PASS/FAIL per check. On FAIL, stop and describe exactly what152 didn't match -- never delete remaining data to "resolve" a failed153 verification.154155## Workflow: "is it safe to delete/move <path>?"156157Just run `storops identify <path>` and relay Category, Deletable,158Migratable, CleanupRisk, Consequence, and the recommended action verbatim --159this is the direct, deterministic answer; don't editorialize past what the160rule base actually says, and don't guess for an `unknown` result.161162## Command reference163164| Tier | Commands | Confirmation |165|--------|----------|--------------|166| Read | `storops scan`, `storops inspect`, `storops search`, `storops identify` | none |167| Plan | `storops cleanup plan`, `storops migrate plan` | none (produces a plan file only) |168| Write | `storops cleanup execute`, `storops migrate execute` | requires `--confirm` (and `--app-closed` for migrations that need it) |169| Verify | `storops verify` | none (read-only re-check) |170171Every command supports `--json` for machine-readable output. Invoke as172`python -m storops <command> ...`, or `storops <command> ...` if the package173has been `pip install`-ed.174175See `README.md` for setup/requirements and `rules/README.md` for the rule176schema behind identification.