Ecosystem fit#
conda-exec is shaped around a common conda user experience problem: you
often need a tool once, or repeatedly but not permanently, and installing it
into base or a project environment is the wrong amount of commitment.
It gives conda a workflow similar to npx, uvx, or pipx run, while
keeping conda’s solver, channels, package metadata, and platform model as
the source of truth.
The workflow it optimizes#
conda-exec is optimized for commands like these:
conda exec ruff check .
conda exec -c conda-forge -c bioconda samtools flagstat reads.bam
conda exec scripts/report.py --output report.json
The user intent is:
get the command from trusted conda channels
keep the current environment untouched
avoid editing
environment.ymlfor temporary toolingreuse the result when the same tool is run again
remove the environment later without affecting anything else
That is different from managing an application environment, a production service environment, or a shared research environment.
Choosing the right conda workflow#
Tool |
Best fit |
Pros |
Cons |
|---|---|---|---|
Run a command inside an environment you already created with |
Built into conda. Works with named and prefix environments. Good when the environment is meant to be inspected, activated, exported, updated, or shared as an environment. |
The environment lifecycle is yours. |
|
|
Run a command or script whose environment should be declared at the invocation or in the script metadata. |
Creates isolated cached environments without touching |
First run pays the solve/install cost. Cached prefixes are not intended for manual editing or activation. Commands do not become available on |
Install command-line tools that should be available from any shell. |
Gives each tool its own persistent environment. Exposes binaries on |
It is a persistent tool manager, not a per-command dependency declaration. Less natural for one-off commands, script-local dependencies, and reproducible script locks. |
The important distinction is ownership. conda-exec owns disposable cached prefixes. Project tools own project environments. conda run owns the “execute inside an existing environment” path.
If you are replacing an Anaconda Project-style catalog of commands, the choice depends on who owns each environment:
Use
conda execwhen each command should carry its own specs, channels, or script metadata. This is the closest fit for breaking one oversized R-plus-Python environment into smaller command-specific environments.Use
conda globalwhen the customer wants a stable set of everyday CLI tools available onPATH.Use
conda runwhen the customer already has named environments and the catalog only needs to dispatch commands into them.
Why caches are not project environments#
A conda-exec cache entry is a performance optimization, not a user-managed environment. It has a prefix, package records, and binaries, but it is not meant to be activated, edited by hand, or treated as an environment spec.
This lets conda-exec be aggressive about reuse and cleanup:
cache keys are derived from specs, channels, or lock content
each spec combination gets an isolated prefix
--refreshcan remove and recreate one entry--cleancan prune old entries without project coordination
If you need to inspect, modify, or share an environment as an environment, create a named conda environment instead.
Why ce exists#
conda exec is the conda-native spelling. It reads clearly and fits the
plugin model.
ce exists for the moments where process startup and typing overhead
matter:
ce ruff check .
It calls the same parser and execution code but bypasses conda’s plugin subcommand loading. It is also the portable shebang target:
#!/usr/bin/env ce
That mirrors a broader ecosystem pattern: keep the full command discoverable and provide a short executable for frequent use.
How channels shape the UX#
conda users expect channels to be explicit and meaningful. conda-exec keeps that model:
default channel:
conda-forgeexplicit channels via repeated
-c/--channelscript channels in
[tool.conda].channelssolver behavior delegated to conda’s context and channel priority
For domain channels such as bioconda, users should include the support
channels they rely on:
conda exec -c conda-forge -c bioconda samtools view input.bam
This is more verbose than a global package manager, but it matches conda’s core model: package identity includes channel context.
How scripts fit#
Python scripts are often shared as small files before they become packages.
PEP 723 gives those files a standard place to declare Python dependencies.
conda-exec extends that pattern with [tool.conda] so scripts can also
declare native conda packages and channels.
This makes the script itself the user interface:
# /// script
# requires-python = ">=3.12"
# dependencies = ["rich"]
#
# [tool.conda]
# channels = ["conda-forge", "bioconda"]
# dependencies = ["samtools>=1.19"]
# ///
For exploratory work, metadata is enough. For CI, papers, notebooks, reports, or handoffs between machines, generated lock data records the resolved environment while keeping the human-authored metadata readable.
Where conda-exec should stay small#
conda-exec deliberately does not try to become a project manager, a lockfile standard, or a replacement for conda environments.
It delegates:
solving to conda’s configured solver backend
package metadata to channels
lock import and export to conda’s environment plugins
activation environment variables to conda’s activator
cleanup confirmation to conda’s reporter system
That keeps the feature focused: ephemeral execution with conda semantics.