Motivation#
What conda-self is#
conda-self is a conda plugin that manages conda installations
themselves – specifically the base environment where conda, its
plugins, and their dependencies live. It provides safe commands to
install, update, and remove plugins in base, and integrates with
conda doctor to protect base from accidental modification.
The name conda self reflects this purpose: conda managing itself.
The problem#
The conda base environment is unique: it contains conda itself and
is always activated. This makes it a tempting target for installing
packages directly, but doing so creates real risks:
Installing a package with conflicting dependencies can break conda
A broken base environment means you cannot use conda to fix it
Over time, base accumulates packages that are difficult to untangle
There is no built-in way to “undo” what was installed in base
Many users have experienced the frustration of a broken base environment. The usual advice is “don’t install anything in base,” but conda itself needs plugins (like the solver, authentication handlers, or custom subcommands) installed there to be discovered.
How we got here#
conda-self evolved through several iterations, shaped by UX testing and community feedback:
The project started as a way to protect and manage the base environment. Early versions had a
conda self protectcommand that froze base.UX testing showed that “protect” did not communicate what the command actually does – cloning base to a working environment and locking down the original. The command was renamed to
conda self migrate(laterconda migrate).Rather than introducing a new top-level subcommand, the protection logic was integrated into conda’s existing health check system via
conda doctorandconda doctor --fix. This makes base protection discoverable alongside other environment health checks.The name
conda self(rather thanconda base) was chosen because the plugin manages the conda installation, not just any environment named “base.”Reset functionality evolved from a simple “strip to essentials” to supporting multiple snapshot sources: the installer-provided state (e.g. from Miniforge), the pre-protection state saved by
conda doctor --fix, and the current essential packages.
Prior art#
Manual discipline#
The most common approach is to simply avoid installing packages in base. This works until you need to install a conda plugin, which must live in base to be discovered. There is no tooling to enforce this discipline.
conda-protect#
An earlier plugin that explored freezing environments to prevent accidental modification. conda-self builds on this idea by integrating protection directly into conda’s health check system and providing safe commands for the operations that do need to modify base.
Package managers with self-management#
Tools like rustup (Rust), pipx (Python CLI tools), and
brew (macOS) separate the tool installation from user packages.
conda-self brings a similar separation to conda: the base
environment is for conda and its plugins, while user packages
live in named environments.
Design choices#
- Subprocess over in-process API
conda self installuses subprocess calls to conda install rather than the in-process Solver API. This ensures frozen environment protection (which lives in conda’s CLI layer) is always respected. It also means all of conda’s safety checks, channel resolution, and reporting work exactly as users expect. See issue #15 for the discussion that led to this decision.- Plugin validation after install
Rather than pre-validating packages (which would require maintaining a list of known plugins), conda-self installs first and then checks
importlib.metadataentry points. If the package is not a plugin, it is automatically rolled back. This is future-proof and works with any plugin, including third-party ones.- Snapshot-based recovery
Snapshots use conda’s
@EXPLICITformat – a list of exact package URLs. This is the most reliable way to reproduce an environment state, as it bypasses the solver entirely. Multiple snapshot sources (installer, base-protection, current) give users flexibility in how far back to restore.- Channel configuration over inline specs
conda self install conda-forge::pkgis rejected. Instead, channels are configured via conda config, keeping channel settings consistent across install, update, and dependency resolution.- Health checks over custom subcommands
Base protection is implemented as a
conda doctorhealth check rather than a standaloneconda self protectorconda migratecommand. This makes it discoverable viaconda doctor --listand follows the pattern conda already provides for environment maintenance.
What’s next#
conda-self is on track to graduate from the conda-incubator organization to the main conda organization, becoming a default plugin shipped with conda. See issue #89 for details.