Introducing conda-tasks: the missing task runner for conda

Image credit: Emily Ranquist on Pexels
Conda handles environments and packages well, but it has never had a built-in way to define project tasks -- the kind of thing you'd otherwise put in a Makefile, tox.ini, or a pile of shell scripts. Today we're releasing conda-tasks, a conda plugin that fills that gap. Define tasks in your project, wire up dependencies between them, and run everything through conda task (or the standalone ct command).
What it looks like
Create a conda.toml in your project root:
[tasks]
lint = "ruff check ."
[tasks.build]
cmd = "python -m build"
inputs = ["src/**/*.py", "pyproject.toml"]
outputs = ["dist/*.whl"]
[tasks.test]
cmd = "pytest tests/ -v"
depends-on = ["build"]
[tasks.check]
depends-on = ["test", "lint"]
description = "Run all checks"
Then run it:
conda task run check
# or, using the standalone CLI:
ct run check
conda-tasks resolves the dependency graph, runs build and lint first (in the right order), then test, and skips anything whose inputs haven't changed since the last run. That's it -- no new package manager, no new environment format. It works with your existing conda environments.
Why this exists
The conda ecosystem has had several tools for running commands from project definitions. anaconda-project was one of the first, combining conda environments with named project commands, platform-specific variants, and automatic environment setup. conda-project, its community successor, modernized that workflow with conda-lock integration. Both focus on reproducible project execution -- setting up environments and launching commands -- but neither supports dependencies between commands, caching, or templating.
On the other side, general-purpose Python task runners like tox, nox, and invoke work well for their respective use cases but don't integrate with conda environments or conda's plugin system.
pixi by prefix.dev changed things by shipping a full-featured task runner alongside its package manager: task dependencies with topological ordering, platform overrides, input/output caching, template variables, and task arguments. It demonstrated that a proper task system belongs in every project workflow.
conda-tasks brings that task runner to conda. The task system design is directly inspired by pixi's -- if you've used pixi run, the concepts will be familiar. The difference is scope: pixi manages both environments and tasks, while conda-tasks handles only the task-running side and leaves environment management to conda.
Features
Task dependencies
Tasks can depend on other tasks. conda-tasks resolves the full dependency graph using topological sorting and detects cycles:
[tasks]
lint = "ruff check ."
[tasks.compile]
cmd = "gcc -o main main.c"
[tasks.test]
cmd = "./main --test"
depends-on = ["compile"]
[tasks.check]
depends-on = ["test", "lint"]
Jinja2 templates
Commands support Jinja2 templates with context variables that expose conda's runtime state:
[tasks.info]
cmd = "echo Building on {{ conda.platform }} with conda {{ conda.version }}"
[tasks.clean]
cmd = "{% if conda.is_win %}rd /s /q build{% else %}rm -rf build/{% endif %}"
Available variables include conda.platform, conda.environment.name, conda.prefix, conda.is_win, conda.is_unix, conda.is_linux, conda.is_osx, and more.
Input/output caching
Specify inputs and outputs on a task, and conda-tasks will skip re-execution when inputs haven't changed. The cache uses a fast (mtime, size) pre-check before falling back to SHA-256 hashing, so the overhead on cache hits is minimal:
[tasks.build]
cmd = "python -m build"
inputs = ["src/**/*.py", "pyproject.toml"]
outputs = ["dist/*.whl"]
Platform overrides
Override task fields per platform, so the same task definition works across operating systems:
- target key
- Jinja2 conditional
[tasks.clean]
cmd = "rm -rf build/"
[target.win-64.tasks]
clean = "rd /s /q build"
[tasks.clean]
cmd = "{% if conda.is_win %}rd /s /q build{% else %}rm -rf build/{% endif %}"
Task arguments
Tasks can accept named arguments with defaults, so you don't need separate task definitions for common variations:
[tasks.test]
cmd = "pytest {{ test_path }} -v"
args = [{ arg = "test_path", default = "tests/" }]
conda task run test src/tests/unit/
Environment targeting
Run tasks in any conda environment using the same -n/-p flags you already use with conda:
conda task run test -n py311-compat
Tasks can also declare a default-environment so they always run in the right place:
[tasks.test]
cmd = "pytest tests/ -v"
default-environment = "py311-compat"
Multiple file formats
conda-tasks reads task definitions from four file formats, checked in this order:
pixi.toml-- reads the[tasks]table directlyconda.toml-- conda-native TOML formatpyproject.toml-- reads[tool.conda.tasks],[tool.conda-tasks.tasks], or[tool.pixi.tasks].condarc-- readsplugins.conda_tasks.tasksvia conda's settings API
If you already have tasks in a pixi.toml, conda-tasks can read them as-is. You can also export them to the canonical format:
conda task export --file pixi.toml
Install and try it
- conda / mamba
- pixi
- pip
conda install --channel conda-forge conda-tasks
pixi global install conda-tasks
pip install conda-tasks
Then create a conda.toml and run your first task:
conda task run <task-name>
conda task list
# or use the standalone CLI:
ct run <task-name>
ct list
What it doesn't do
conda-tasks is a task runner, not a package manager. It does not create environments or install dependencies -- that's conda's job. If you're coming from pixi where pixi run handles both, see the migration guide.
Get involved
conda-tasks is a conda-incubator project. Contributions, bug reports, and feature requests are welcome:
Acknowledgements
conda-tasks would not exist without the work of the prefix.dev team on pixi. The task system design -- dependency graphs, platform overrides, caching, template variables, and the overall developer experience -- comes directly from their implementation. We're grateful for their contribution to the conda ecosystem and for demonstrating what a project task runner should look like.
Thanks also to the anaconda-project and conda-project teams for exploring project-level automation in the conda ecosystem long before conda-tasks existed.
