Find and delete old .venv, conda, poetry, pipenv, uv and more β safely, in seconds.
uvx killpy --path ~killpy is npkill for Python β but it understands every environment manager, instead of matching folders by name.
β Featured in awesome-python β a curated list of the best Python tools
- The Problem
- Quickstart
- killpy vs alternatives
- Interactive TUI
- CLI cheatsheet
- FAQ
- Roadmap
- Pre-commit hooks
- Safety
- Contributing
If you have been writing Python for more than a year, your disk is probably full of environments you forgot about.
Every project gets a .venv. Every tutorial leaves a Conda environment behind. Every poetry install creates a hidden virtualenv somewhere in ~/.cache. pyenv versions stack up. tox creates a .tox folder in every repo you ever tested. __pycache__ directories scatter everywhere. Build artifacts from old pip install -e . runs stay forever.
None of these get cleaned up automatically.
A typical developer machine accumulates 10β40 GB of Python environments over a few years β most of them abandoned and completely useless.
killpy scans your filesystem, shows you everything with its size, and lets you delete it β either from a slick interactive terminal UI or via a single headless command.
That makes it useful if you are trying to:
- find old Python virtual environments
- delete unused Conda environments
- inspect Poetry environment disk usage
- clean up
pipxpackage environments - remove Python caches and build artifacts
- free disk space consumed by Python development tools
pipx run killpy --path ~
# or
uvx killpy --path ~killpy supports 11 environment types across every major Python tool:
| Type | What is detected | Typical location |
|---|---|---|
venv |
.venv dirs and any folder containing pyvenv.cfg |
project root |
poetry |
Poetry virtual environments | ~/.cache/pypoetry/virtualenvs |
conda |
Conda environments (conda env list) |
~/anaconda3/envs, ~/miniconda3/envs |
pipx |
Installed pipx packages |
~/.local/share/pipx/venvs |
pyenv |
pyenv-managed Python versions | ~/.pyenv/versions |
pipenv |
Pipenv virtualenvs | ~/.local/share/virtualenvs |
hatch |
Hatch environments | ~/.local/share/hatch/env |
uv |
uv tool environments (uv tool install) and uv-managed Pythons |
~/.local/share/uv |
tox |
tox environments | .tox/ inside repo |
cache |
__pycache__, .mypy_cache, .pytest_cache, .ruff_cache, plus global pip/uv caches when the scanned path contains them |
project tree, ~/.cache |
artifacts |
dist/, build/, .egg-info, .dist-info |
project root |
Instant run β no install needed:
pipx run killpy
# or
uvx killpyInstall permanently:
pip install killpy
# or
pipx install killpy
# or
uv tool install killpyScan current directory:
killpyScan your entire home folder:
killpy --path ~Exclude paths matching a pattern:
killpy --path ~ --exclude "backups,archive,work"Delete everything non-interactively (CI / scripts):
killpy --path ~/projects --delete-all --yesAlso available as a pre-commit hook β see Pre-commit hooks below.
More documentation: https://tlaloc-es.github.io/killpy/
| Tool | venv | conda | poetry | pipx | pyenv | caches | artifacts | TUI | search | multi-select |
|---|---|---|---|---|---|---|---|---|---|---|
| killpy | β | β | β | β | β | β | β | β | β | β |
npkill |
by name | β | β | β | β | node_modules by default |
by name | β | β | β |
pyclean |
β | β | β | β | β | __pycache__ only |
β | β | β | β |
conda clean |
β | partial | β | β | β | conda only | β | β | β | β |
pip cache purge |
β | β | β | β | β | pip only | β | β | β | β |
find . -name .venv -exec rm |
venv only | β | β | β | β | β | β | β | β | β |
npkill is a great tool and pioneered this exact concept for node_modules; its --target flag can match any folder by name. What it lacks is tool awareness: conda, poetry, pipx and pyenv keep their environments in central locations that folder-name matching cannot discover. killpy knows where each toolchain lives β no other single tool discovers, sizes, and removes environments across all major Python toolchains.
killpy
killpy --path /path/to/scan
killpy --path ~ --exclude "company-projects"The TUI starts immediately and streams results as each detector finishes β no waiting for a full scan before you can start browsing. Select items, mark them, and confirm; nothing is deleted without explicit action.
Environments flagged with β οΈ are actively in use (the environment killpy runs from, or the pyenv global version) β the TUI shows them but refuses to delete them.
| Key | Action |
|---|---|
β / β or k / j |
Move cursor up / down (vim-style) |
/ |
Open live search/filter bar (substring match) |
Escape |
Close search bar and clear filter |
T |
Toggle multi-select mode on / off |
Space |
(Multi-select) Toggle current row selected |
A |
(Multi-select) Select all visible / deselect all |
D |
Mark highlighted item for deletion |
Ctrl+D |
Delete all marked items (or all selected in multi-select mode) |
Shift+Delete |
Delete highlighted item immediately, no mark step |
o |
Open the item's parent folder in the OS file manager |
P |
Remove all __pycache__ folders under the scanned path |
U |
Uninstall the selected pipx package |
Ctrl+Q |
Quit |
Press / to open the filter bar at the bottom of the screen. Type any text β the venv table filters by path substring (case-insensitive) and updates live as you type. Press Escape or submit an empty value to clear the filter and return to the full list.
Press T to enter multi-select mode. A status bar shows the current selection count.
Spaceβ toggle the highlighted rowAβ select all visible non-deleted rows (press again to deselect all)Ctrl+Dβ delete every selected row in one operationTagain β exit multi-select mode (selection is cleared)
Multi-select coexists with the existing D / Ctrl+D mark-and-delete flow β both work independently.
Everything the TUI does is also scriptable. Start here:
killpy --path ~ # interactive TUI over your home folderThe one-liners you will actually use:
killpy list --json # every environment, machine-readable
killpy list --min-size 500MB # only environments worth reclaiming
killpy delete --older-than 180 --yes # remove stale envs, no prompt
killpy doctor # health report β what is safe to delete
killpy stats # disk usage breakdown by typeπ Full CLI reference β every subcommand (list, find, delete, stats, clean, doctor) with every flag, example outputs, and demos: tlaloc-es.github.io/killpy β CLI
My Mac/Linux disk is almost full β can killpy help?
Yes. Run killpy --path ~ to scan your home folder. The stats command gives an immediate breakdown of how many GB each env type is consuming. Most developers reclaim 5β30 GB.
How do I delete all unused virtual environments at once?
killpy delete --type venv --older-than 90 --yesDeletes every .venv / pyvenv.cfg env not modified in the last 90 days, without prompting.
How do I use killpy in a CI pipeline or script?
# List as machine-readable JSON (progress goes to stderr, JSON to stdout)
killpy list --json
# Suppress progress output entirely with --quiet / -q
killpy list --json --quiet | jq '.[] | .size_human'
# Stream results as NDJSON in real time
killpy list --json-stream | jq '.size_bytes'
# Delete everything without a TUI
killpy --path ./build_artifacts --delete-all --yesProgress messages always go to stderr, so stdout is clean for piping even without --quiet. Use -q when you want no output at all on stderr.
How do I skip certain directories?
killpy --path ~ --exclude "company,production,do-not-touch"Any environment whose path contains one of the comma-separated patterns is silently skipped.
How do I clean up Poetry virtualenvs?
Poetry stores virtualenvs in ~/.cache/pypoetry/virtualenvs. killpy detects and deletes them automatically β no manual path hunting required.
killpy list --type poetry
killpy delete --type poetry --older-than 60How do I find all .venv folders on my computer?
killpy list --type venv --path ~Or for a quick JSON export:
killpy list --type venv --path ~ --jsonHow do I free up disk space used by Conda?
killpy list --type conda # inspect
killpy delete --type conda # delete selectedkillpy runs conda env list internally and lets you delete individual environments. Alternatively, killpy --path ~ will surface them in the TUI.
Can I combine filters?
Yes. For example:
killpy delete --type venv --older-than 90 --dry-runHow do I remove all __pycache__ folders recursively?
killpy clean --path /path/to/projectOr press P in the TUI to clean them for the scanned path.
What does
The environment is currently in use β it is the environment killpy itself runs from, or your pyenv global version. killpy shows it so you are aware of it, but refuses to delete it: the TUI always skips it, and killpy delete / --delete-all skip it unless you pass --force.
Does it fail if Conda, pipx or pyenv are not installed?
No. Missing tools are handled gracefully β that detector is simply skipped. You get results for everything that is available on the system.
Does killpy auto-delete anything?
Never. Deletion always requires an explicit action: a key press in the TUI, --yes on the CLI, or an interactive prompt. killpy is fully read-only on startup.
Can I preview what would be deleted without actually deleting?
killpy delete --dry-runNothing is removed. You see exactly what would happen.
How do I disable the one-line hint shown after deletions?
Set KILLPY_NO_HINT=1. The hint is a single line shown only in interactive terminals β it never appears in pipes, scripts, JSON output, or CI.
Why is Python using so much disk space?
Each virtual environment is a full copy (or symlinked tree) of a Python interpreter plus all installed packages. A typical project .venv with common dependencies weighs 200 MBβ1 GB. Multiply by dozens of projects and you get tens of gigabytes β all orphaned when the project is archived.
Development happens in the open β the issue tracker is the roadmap: new filters and flags for the CLI, TUI improvements, better Windows support, and more.
Want to contribute? Start with a good first issue β each one is small, scoped, and comes with pointers to the relevant code.
Missing a detector for your favourite tool? Propose it in the detector ideas thread.
killpy ships four hooks for pre-commit. Add the ones you need to your .pre-commit-config.yaml:
- repo: https://github.com/Tlaloc-Es/killpy
rev: 1.3.0
hooks:
- id: killpy # remove __pycache__ on every commit
- id: killpy-clean-caches # also removes .mypy_cache, .pytest_cache, .ruff_cache
- id: killpy-clean-artifacts # remove dist/, build/, *.egg-info before committing
- id: killpy-remove-venv # remove .venv (manual stage β see below)| Hook id | What it removes | Default stage |
|---|---|---|
killpy |
__pycache__ directories |
pre-commit |
killpy-clean-caches |
All local cache dirs (__pycache__, .mypy_cache, .pytest_cache, .ruff_cache) |
pre-commit |
killpy-clean-artifacts |
Build artifacts (dist/, build/, *.egg-info) |
pre-commit |
killpy-remove-venv |
Local .venv environments |
manual |
killpy-remove-venv is staged as manual because deleting the environment on every commit would require you to recreate it each time. Run it explicitly when you want a clean slate:
pre-commit run killpy-remove-venv --hook-stage manualTypical minimal setup (safe for daily use):
- repo: https://github.com/Tlaloc-Es/killpy
rev: 1.3.0
hooks:
- id: killpyAdd killpy-clean-artifacts if your project generates dist/ or build/ locally and you want to guarantee they are never staged by accident.
killpy performs destructive, irreversible actions. Always review the selection before confirming removal. The --dry-run flag lets you preview everything safely. Environments marked β οΈ are actively in use and are skipped by every delete path unless you explicitly pass --force.
You are responsible for files deleted on your system.
See CONTRIBUTING.md for the full guide β setup, workflow, how to add a new detector, and GIF recording instructions.
# Quick local checks
uv run python -m compileall killpy
uv run pytest
pre-commit run --all-filesProject architecture and guardrails are documented in AGENTS.md.
MIT. See LICENSE.
Stars help killpy appear when developers search for Python disk cleanup tools.
It takes 2 seconds and makes a real difference for discoverability.