{"id":50548525,"url":"https://github.com/vishwaksena-dingari/dehoard","last_synced_at":"2026-06-04T01:00:43.196Z","repository":{"id":362361291,"uuid":"1256757167","full_name":"vishwaksena-dingari/dehoard","owner":"vishwaksena-dingari","description":"A configurable, preview-first zsh disk-space cleaner for macOS developers and ML engineers. Previews by default; deletes only with --apply.","archived":false,"fork":false,"pushed_at":"2026-06-03T20:49:59.000Z","size":161,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-03T22:18:27.397Z","etag":null,"topics":["cli","developer-tools","disk-cleanup","machine-learning","macos","zsh"],"latest_commit_sha":null,"homepage":null,"language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/vishwaksena-dingari.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-02T04:12:26.000Z","updated_at":"2026-06-03T20:50:02.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/vishwaksena-dingari/dehoard","commit_stats":null,"previous_names":["vishwaksena-dingari/dehoard"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/vishwaksena-dingari/dehoard","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vishwaksena-dingari%2Fdehoard","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vishwaksena-dingari%2Fdehoard/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vishwaksena-dingari%2Fdehoard/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vishwaksena-dingari%2Fdehoard/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vishwaksena-dingari","download_url":"https://codeload.github.com/vishwaksena-dingari/dehoard/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vishwaksena-dingari%2Fdehoard/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33886153,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-03T02:00:06.370Z","response_time":59,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","developer-tools","disk-cleanup","machine-learning","macos","zsh"],"created_at":"2026-06-04T01:00:37.288Z","updated_at":"2026-06-04T01:00:43.185Z","avatar_url":"https://github.com/vishwaksena-dingari.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# dehoard\n\nA disk-space cleaner for macOS, aimed at developers and ML engineers. It removes the regenerable\njunk that piles up in dev and ML toolchains (caches, virtual environments, build artifacts, Docker\ndisk images, editor leftovers) and leaves your real data alone. It also finds the same model\ndownloaded into more than one tool, which is often the biggest single thing eating space on a\nmachine that runs models locally.\n\ndehoard is one zsh script you can read top to bottom before trusting it. It previews by default: a\nplain run prints what it would delete and removes nothing until you pass `--apply`.\n\nThe part general cleaners don't do: it detects the same LLM sitting in HuggingFace, Ollama, and LM\nStudio at once and tells you which copies are redundant.\n\n---\n\n## Safety contract\n\ndehoard runs `rm`, so here is what it guarantees before you run anything.\n\n- Preview by default. A plain run deletes nothing; it prints what it would remove. You pass `--apply`\n  to actually delete.\n- `--apply` is the only thing that enables deletion. No other flag deletes without it, and `--dry-run`\n  forces preview even when `--apply` is also present.\n- It refuses to run as root, so it can't touch system-owned files.\n- The delete primitive only removes paths under `$HOME`, `/var/folders`, or `/tmp`. Anything outside\n  those roots is refused, even if `$TMPDIR` is mis-set, and bare `/` and `$HOME` themselves are always\n  refused.\n- Deletion is a real `rm`, not a move to the Trash, so it is irreversible. That is why preview comes\n  first: run it, read it, then `--apply`.\n- It never touches your data. Model weights, model outputs, chat and session history, source code, git\n  history, and configs are detected and kept. Only regenerable caches and artifacts get removed.\n- Every path dehoard removes through `_rm` is logged to `~/.cache/dehoard/run-\u003ctimestamp\u003e.log` when\n  you `--apply`.\n- Provided \"as is\", without warranty ([MIT](LICENSE)). The safeguards are real, but you run it on your\n  own machine and you are responsible for what you delete. Preview first.\n\nThe guard diagram and the test suite behind these claims are in [docs/SAFETY.md](docs/SAFETY.md).\n\n---\n\n## How a run works\n\nThis traces one run: the root check, the read-only branch, and the gates every deletion candidate\npasses through before anything is removed.\n\n```mermaid\nflowchart TD\n    A([dehoard run]) --\u003e B{running as root?}\n    B -- yes --\u003e X[refuse and exit]\n    B -- no --\u003e C{\"--report / --json ?\"}\n    C -- yes --\u003e R[read-only audit\u003cbr/\u003enothing is deleted] --\u003e Z([exit])\n    C -- no --\u003e D[\"run selected tiers\u003cbr/\u003e(Tier 1 default · --deep · --models · --scan;\u003cbr/\u003e--pick = scan picker only)\"]\n    D --\u003e E[for each cleanup candidate]\n    E --\u003e F{in ignore list?}\n    F -- yes --\u003e G[\"⊘ skip and announce\"]\n    F -- no --\u003e H[show preview line]\n    H --\u003e I{\"--apply given?\"}\n    I -- no --\u003e P[preview only\u003cbr/\u003enothing deleted]\n    I -- yes --\u003e J{confirm?}\n    J -- no --\u003e P\n    J -- yes --\u003e K[_rm safe-root guard]\n    K --\u003e L{\"path under $HOME / var-folders / tmp ?\"}\n    L -- no --\u003e Y[refuse path]\n    L -- yes --\u003e M[delete + log]\n```\n\nNearly every candidate goes through the same gates: the ignore list, the preview/apply gate, an\noptional confirmation, and the safe-root guard inside the delete primitive (`_rm`). A few audited\ndeletions run outside `_rm`, all still `--apply`-gated: `--deep`'s root-owned system-cache sweep\n(`sudo rm`) and `--models`' `ollama rm`; see [docs/SAFETY.md](docs/SAFETY.md).\nThe read-only modes (`--report`, `--json`) branch off early and never reach a delete.\n\n`--scan --pick` adds an interactive selection layer on top of these gates rather than replacing them:\nit opens one `fzf` picker per category (biggest first; interactive-only, so it skips the Tier 1\nsweep), and for each category reprints what you marked and asks once. It still needs `--apply`, an\nempty selection or Esc skips that category (deletes nothing), and every path dehoard removes directly\nstill passes the safe-root guard; environment managers (conda/uv/Android/Rust) use their own uninstaller.\n\n---\n\n## Quickstart\n\nPreview before you apply.\n\n```sh\n./dehoard.sh --report                          # fast map: biggest dirs, reclaimable caches, duplicate models (start here)\n./dehoard.sh --deep --models --scan --dry-run  # exhaustive preview: every item that would be deleted, deletes nothing\n./dehoard.sh --apply                            # reclaim the always-safe Tier 1\n./dehoard.sh --scan --pick --apply              # pick interactively which project artifacts to delete\n```\n\nFlags combine in any order, and without `--apply` (or with `--dry-run`) any combination only previews.\n`--report` is its own read-only mode: it prints the map and exits, so it does not stack with the\naction-flag preview; run both to see everything (the report for the duplicate-model finder, the\ndry-run combo for the exact per-item delete list). The `--pick` picker covers `--scan` project\nartifacts only: Tier 1 is a safe batch, and model weights are removed solely through `--models`, so\nneither appears in the picker.\n\n## Install\n\n```sh\n# one file; read it before you run it\ncurl -fsSL https://raw.githubusercontent.com/vishwaksena-dingari/dehoard/main/dehoard.sh -o dehoard.sh\nchmod +x dehoard.sh\n\n# or clone\ngit clone https://github.com/vishwaksena-dingari/dehoard \u0026\u0026 cd dehoard\n```\n\nRequires macOS and zsh (the default shell since Catalina).\n\n## Usage\n\n| Command | What it does |\n|---|---|\n| `dehoard --report` | Read-only audit: biggest dirs, reclaimable caches, model inventory, cross-tool duplicates. Deletes nothing. |\n| `dehoard` | Preview the always-safe (Tier 1) cleanup. Deletes nothing. |\n| `dehoard --apply` | Reclaim the Tier 1 safe stuff. |\n| `dehoard --deep` | Add Tier 2: aggressive caches (Library caches, Xcode DerivedData, Docker prune, git gc). Pair with `--apply`. Like Tier 1 it runs as a batch with no per-item prompt (just the preview/apply gate), so preview it first. |\n| `dehoard --models` | Interactive cleanup of LLM/ML weights (HuggingFace, PyTorch, Ollama, LM Studio, NLTK). |\n| `dehoard --scan` | Interactive scan of project artifacts (venvs, `node_modules`, build dirs, editor leftovers, orphaned tools). |\n| `dehoard --scan --pick --apply` | Same scan, but instead of prompting per item it opens **one `fzf` picker per category, biggest first** (a per-category summary of counts + sizes prints first as a contents page). In each category: TAB to mark, **Ctrl-A** all, **Ctrl-D** none, Enter to confirm, **Esc skips that category**; the preview shows last-modified, the recreate command, and any caveat. Interactive-only (skips the Tier 1 sweep); needs `fzf` and `--apply`; falls back to per-item prompts without `fzf`. |\n| `dehoard --json` | Machine-readable model inventory and duplicates as pure JSON on stdout. |\n| `dehoard --dry-run` | Force preview even with `--apply` (the safe default, made explicit). |\n| `dehoard --yes` / `-y` | Auto-confirm prompts. Combine with `--apply`; use with care. |\n| `dehoard --list-ignored` / `--unignore \u003cpath\u003e` / `--reset-ignore` | Manage the always-skip ignore list. |\n| `dehoard --help` | Full breakdown of every action and why it's safe. |\n| `dehoard --version` / `-V` | Print the version and exit. |\n\nFlags combine in any order. A sensible order is `--report`, then a preview, then `--apply`. Tier\nbehavior is in [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md); the full per-item list is in\n[docs/CLEANS.md](docs/CLEANS.md).\n\n---\n\n## Cross-tool duplicate-model detection\n\nThe same model often sits in several tools under different names. `dehoard --report` finds those and\nseparates true duplicates (the same build, where keeping one copy is safe) from related variants (a\ndifferent quant or base/instruct, which are not interchangeable):\n\n```text\n$ dehoard --report\n\n━━ True cross-tool duplicate models (same build in 2+ tools) ━━\n   Same family, size, quant \u0026 variant, safe to keep one.\n  ● llama-8b        2 copies, ~16.0G total (keep 1 → reclaim ~8.0G)\n       HF             8.0G  Meta-Llama-3-8B-Instruct-Q8\n       Ollama         8.0G  llama3:8b-instruct-q8\n  ────────\n  ⭐ Potential reclaim from cross-tool duplicates: ~8.0G\n\n── Related cross-tool variants (same model, DIFFERENT build, NOT counted) ──\n   Same family+size but a differing quant (Q4≠Q8) or variant (base≠instruct).\n  ● mistral-7b      2 builds, ~13.0G total, DIFFERENT builds, not redundant\n       LMStudio       6.0G  Mistral-7B-Instruct-Q4   [q4/instruct]\n       HF             7.0G  Mistral-7B               [?/base]\n```\n\nThis shows how each model gets sorted into one bucket or the other.\n\n```mermaid\nflowchart TD\n    HF[HuggingFace hub] --\u003e N\n    OL[\"Ollama (ollama list)\"] --\u003e N\n    LM[\"LM Studio .gguf files\"] --\u003e N\n    PT[PyTorch hub checkpoints] --\u003e N\n    N[\"normalize each model\u003cbr/\u003efamily+size key · quant · variant\"] --\u003e Grp[group by family+size]\n    Grp --\u003e Cnf{\"≥2 known quants\u003cbr/\u003eOR ≥2 variants?\"}\n    Cnf -- yes --\u003e Rel[\"RELATED variants\u003cbr/\u003edifferent build · NOT counted\"]\n    Cnf -- no --\u003e Tru[\"TRUE duplicates\u003cbr/\u003ereclaim = total - largest copy\"]\n```\n\nDuplicate detection is report-only. Matching is by normalized name, so a `Q4` is never treated as a\n`Q8`, and weights are never deleted automatically. You remove a redundant copy yourself with\n`--models` after checking it. The normalization rules and where each tool stores models are in\n[docs/MODELS.md](docs/MODELS.md).\n\n## `--json` for scripting\n\n`dehoard --json` prints a JSON inventory of the cross-tool models it tracks (HuggingFace, Ollama,\nLM Studio, PyTorch hub) plus the duplicate analysis. (Framework caches like Keras or Whisper appear\nas a size footprint in `--report`, not as individual `models[]` entries.) It's read-only, deletes\nnothing, and writes only JSON to stdout (progress text is suppressed), so it pipes into `jq`:\n\n```sh\ndehoard --json | jq '.total_reclaim_bytes'              # reclaimable bytes from true duplicates\ndehoard --json | jq '.cross_tool_duplicates[].family'  # which models are duplicated across tools\ndehoard --json | jq '.models[] | select(.quant==\"q4\")' # every Q4 model on the machine\n```\n\nThe schema is stable; `schema_version` only changes on a breaking change. It's documented in\n[docs/MODELS.md](docs/MODELS.md#json-schema).\n\n## What it cleans\n\nA short map. The full per-item list, with the reason each item is safe to remove, is in\n[docs/CLEANS.md](docs/CLEANS.md) and `dehoard --help`.\n\n- AI/ML tooling: regenerable temp and cache for ComfyUI, Automatic1111, AI CLIs, and MATLAB (logs,\n  crash dumps, and caches; the installed runtime, prefs, history, and code are kept). Models,\n  outputs, and chat/session history are kept. Also flags orphaned data from uninstalled dev/ML tools.\n- ML model caches: HuggingFace hub, PyTorch hub, Ollama, LM Studio, and NLTK, cleaned through\n  `--models`. Keras, Whisper, llama.cpp, and GPT4All caches also show up in `--report`.\n- Python: venvs (found by `pyvenv.cfg`, any folder name), conda and uv, `__pycache__`,\n  `.pytest_cache`, `.mypy_cache`, `*.egg-info`, and the pip cache.\n- JS and other languages: `node_modules`, npm/pnpm/yarn caches, Rust `target/` and cargo, Go modules,\n  Gradle, Maven, NuGet, CPAN.\n- Containers: Docker `system prune`, build cache, and disk-image (`Docker.raw`) reporting.\n- Apple/Xcode: DerivedData, iOS simulators, Library caches, Metal and Clang caches.\n- Editors: VS Code-family stale extension versions (read from each editor's own `.obsolete`), plus\n  Electron app caches.\n- System: Trash, old DMGs, `.DS_Store`, editor swap files, large project logs.\n\nScope: dehoard sticks to dev and ML tooling and does not scan all of `~/Library`. General application\nand preference cleanup is out of scope; that's a different job with a different trust model.\n\n## Configuration\n\nSet via environment variables, for example in `~/.zshrc`:\n\n| Variable | Default | Effect |\n|---|---|---|\n| `DEHOARD_APPLY_DEFAULT` | `false` | `true` makes `--apply` the default (`--dry-run` still forces preview). |\n| `DEHOARD_IGNORE_ENABLED` | `true` | `false` disables the ignore list entirely (no \"Always skip?\" prompts; the file is never written or read). |\n| `CACHE_MIN_MB` | `100` | Minimum size in MB for a cache dir to appear in the generic sweep. |\n| `DEHOARD_PM_TIMEOUT` | `120` | Seconds before a single external package-manager cleanup (brew/npm/yarn/trunk/…) is timed out and skipped, so one hung tool can't freeze the run. |\n| `NO_COLOR` | unset | Set to any value to disable terminal color ([no-color.org](https://no-color.org)). Color is also off when stdout isn't a TTY (e.g. piped), and never appears in `--json` or the deletion log. |\n| `CLICOLOR_FORCE` | unset | Set to `1` to force color even when stdout isn't a TTY. `--json` stays pure JSON regardless. |\n\nThe ignore list lets you mark a path \"always skip\" at the moment you decline a prompt. It's a\nplain-text file you can edit by hand. Its lifecycle, and the `--list-ignored` / `--unignore` /\n`--reset-ignore` flags, are in [docs/SAFETY.md](docs/SAFETY.md#ignore-list).\n\n## Documentation\n\n- [docs/SAFETY.md](docs/SAFETY.md): the safety model, the `_rm` guard, the ignore list, and the test suite.\n- [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md): the tier model, run flow, and how to add a new cleanup scanner.\n- [docs/MODELS.md](docs/MODELS.md): where local LLMs live on disk, the duplicate-detection rules, and the `--json` schema.\n- [docs/CLEANS.md](docs/CLEANS.md): the full inventory of what every mode cleans.\n- [docs/PHILOSOPHY.md](docs/PHILOSOPHY.md): the design stance, why trust is the only feature that matters and why the tool stays small on purpose.\n\n## Contributing\n\nIssues and pull requests are welcome; see [CONTRIBUTING.md](CONTRIBUTING.md). To add support for a new\ntool, start with [\"Anatomy of a scanner\"](docs/ARCHITECTURE.md#anatomy-of-a-scanner).\n\n## License\n\nMIT. See [LICENSE](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvishwaksena-dingari%2Fdehoard","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvishwaksena-dingari%2Fdehoard","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvishwaksena-dingari%2Fdehoard/lists"}