A shell hook that activates your Python venv the moment you cd in β and deactivates it when you leave.
Automatically activate your Python virtual environment when you cd into a project, and deactivate it when you leave. No configuration files, no per-project setup β it just works.
When you change directories, AutoActivator scans the current directory (and up to your home directory) for a virtual environment. If it finds one, it activates it. When you leave the project tree, it deactivates it.
Found venvs are cached per directory, so repeated visits cost nothing. Directories without a venv are re-checked on each visit, so a venv you create later is picked up immediately. The hook fires only on actual directory changes β not on every shell prompt.
If you activate a venv by hand, AutoActivator leaves it alone β no automatic switching happens until you deactivate.
Performance (Ubuntu 24.04):
| Shell | v0.1.0 | v0.2.0 | v0.3.0 |
|---|---|---|---|
| zsh | 2.14s | 0.004s | 0.0002s |
| bash | 1.93s | 0.004s | 0.0002s |
| speedup vs previous | β | ~500Γ | ~20Γ |
Measured as wall-clock time for the hook to fire on a single cd into a project with a .venv, cold cache, in an ubuntu:24.04 container. Reproduce with bench/bench.sh.
- bash or zsh
- git β recommended for installation and updates; without it, the installer falls back to a tarball download (needs curl or wget, plus tar)
- Linux or macOS (both covered by CI, including macOS's stock bash 3.2)
No Python required.
curl -sSL https://autoactivator.aymenkrifa.com/setup.sh | bashNo arguments needed β the installer detects your shell from $SHELL and wires up the matching rc file (creating it if it doesn't exist). Want a specific shell (or both)? Pass it explicitly:
# zsh only
curl -sSL https://autoactivator.aymenkrifa.com/setup.sh | bash -s zsh
# bash only
curl -sSL https://autoactivator.aymenkrifa.com/setup.sh | bash -s bash
# both
curl -sSL https://autoactivator.aymenkrifa.com/setup.sh | bash -s zsh bashManual installation
git clone https://github.com/aymenkrifa/autoactivator.git ~/.autoactivator
chmod +x ~/.autoactivator/setup.sh
~/.autoactivator/setup.sh # optionally pass a shell: ~/.autoactivator/setup.sh zshThen restart your terminal, or source your shell config:
source ~/.bashrc # bash
source ~/.zshrc # zshautoactivator updateThis pulls the latest changes and re-sources the hook in your current shell. The update will refuse to run if you have local modifications in ~/.autoactivator.
Installed without git? autoactivator update will point you back to the install one-liner β re-running it refreshes the install in place (and upgrades it to a git checkout once git is available).
AutoActivator finds venvs that live inside the project tree. Here's how that maps to the common Python tools:
| Tool | Default layout | Supported |
|---|---|---|
python -m venv |
.venv / venv / env in project |
β |
virtualenv |
env in project |
β |
uv venv |
.venv in project |
β |
pyenv + python -m venv |
venv in project | β |
poetry (with virtualenvs.in-project = true) |
.venv in project |
β |
pipenv (with PIPENV_VENV_IN_PROJECT=1) |
.venv in project |
β |
| Custom-named directory in project | any name (set $AUTOACTIVATOR_VENV_NAME) |
β |
poetry (default) |
~/.cache/pypoetry/virtualenvs/β¦ |
β |
pipenv (default) |
~/.local/share/virtualenvs/β¦ |
β |
pyenv-virtualenv plugin |
~/.pyenv/versions/β¦ |
β |
hatch |
~/.local/share/hatch/β¦ |
β |
| Conda / Anaconda / Miniconda | $CONDA_PREFIX/envs/β¦ |
β (use conda activate) |
The rule of thumb: if the venv directory lives anywhere inside your project, AutoActivator will find it. External venv layouts (poetry default, pyenv-virtualenv, hatch) are out of scope for now.
If a directory contains more than one venv, AutoActivator picks the first match in this priority order:
$AUTOACTIVATOR_VENV_NAME(if set and the directory exists).venvvenvenvvirtualenv- First directory in the tree that looks like a venv (alphabetical fallback)
Set AUTOACTIVATOR_VENV_NAME to prefer a non-standard venv name. Add the export to your shell config before the AutoActivator block:
export AUTOACTIVATOR_VENV_NAME=myenv
source ~/.autoactivator/autoactivator_config.shIf the named directory doesn't exist in a given project, AutoActivator falls back to the standard priority list β so the override is a preference, not a hard requirement.
autoactivator uninstallThis removes the ############################# AutoActivator ############################# block (and the matching close marker) from ~/.bashrc and ~/.zshrc. Everything else in those files is left alone, and a fresh timestamped backup is written beside each rc (~/.bashrc.pre-uninstall.<timestamp>) before any change. Open a new shell to fully unload the hook.
The repo at ~/.autoactivator is not deleted by default β the command prints the rm -rf line for you to run. To wipe everything in one go:
autoactivator uninstall --purgeAbout the ~/.zshrc.pre-autoactivator backup
The installer creates ~/.zshrc.pre-autoactivator (or .bashrc.pre-autoactivator) the first time it runs. That file is a snapshot from install time, not a diff. Restoring it (mv ~/.zshrc.pre-autoactivator ~/.zshrc) will erase anything else you've added to your shell config since installing AutoActivator β aliases, other tools' init blocks, PATH edits, all of it. Only use it as a fallback if you're sure nothing else has changed.
autoactivator uninstall avoids this entirely by deleting just the AutoActivator block in place.
Manual removal
If for some reason you can't run the command, delete this block from ~/.bashrc / ~/.zshrc:
############################# AutoActivator #############################
source "/home/<you>/.autoactivator/autoactivator_config.sh"
#########################################################################Then rm -rf ~/.autoactivator if you want the repo gone too.
Activating a venv means source-ing its bin/activate β so cd-ing into an untrusted checkout executes whatever shell code its venv-shaped directories contain. If you routinely clone code you don't trust, inspect it before cd-ing in. (Tools like direnv address this with a per-directory allow-list; AutoActivator deliberately stays zero-config.)
See CONTRIBUTING.md.