Skip to content

Instantly share code, notes, and snippets.

@Hofer-Julian
Last active March 28, 2025 16:09
Show Gist options
  • Save Hofer-Julian/df7364634c330d49bc8fbe95223c4ffd to your computer and use it in GitHub Desktop.
Save Hofer-Julian/df7364634c330d49bc8fbe95223c4ffd to your computer and use it in GitHub Desktop.
Enhanced Task Design Document

Enhanced Task Design Proposal

Goals

  • More powerful tasks
  • Backwards compatibility with existing tasks

Existing Behavior

[tasks]
build = "cargo build"

When running the following command, the arguments will be appended to the task.

pixi run build --release --manifest-path /path/to/Cargo.toml

Inside the pixi environment, the following command will be executed:

cargo build --release --manifest-path /path/to/Cargo.toml

We want to preserve that behavior. It is intuitive, powerful and doesn't involve any scaffolding.

Problems With The Current System

The current behavior also has disadvantages.

  • It only allows appending arguments at the end of a task
  • It doesn't allow passing on arguments to dependent tasks
  • It has no way of communicating in which environment task dependecies should run

Argument Expansion

When the args key is defined, the arguments are not automatically forwarded anymore. A simple case would look like this:

[tasks.test_single]
cmd = "pytest tests/{{ python-file }} || echo tests failed"
args = ["python-file"] # This argument is mandatory
# will run `pytest tests/test.py
pixi run test_single test.py

We would also allow default arguments. All default arguments have to be specified at the end to avoid ambiguities.

[tasks.install]
cmd = "cargo install {{ type }} --path {{ path }}"
args = ["path", { arg = "type", default = "--release }] # `path` is mandatory, `type` is optional with a default

Both work:

pixi run install /path/to/manifest
pixi run install /path/to/manifest --debug

If you want to pass multiple parameters to a single argument, you can just quote:

pixi run install /path/to/manifest "--debug --verbose"

Error

[tasks.test_single]
cmd = "pytest tests/{{ python-file }} {{ invalid-arg }} || echo tests failed"
args = ["python-file"] # This argument is mandatory

If an argument isn't defined (like invalid-arg in the example), then we should error out.

Depending on Tasks

Arguments can be passed on like this:

[tasks]
# Define the argument to be passed to the task
install-release = { depends-on = [{ task = "install", args = ["/path/to/manifest", "--debug"] }]}

Tasks can be run in multiple environments. If you want to specify in which environment one of your tasks dependencies run, you can do it like this:

[feature.c.tasks]
something = { depends_on = [{ task = "test", environment = "a" }] }

Environment Selection

pixi run --environment=env_name task hints in which environment tasks should run.

It will ignore the hint for task dependencies, if:

  • The task doesn't exist in that environment, but exists in others
  • If another environment has specifically been requested:
[feature.c.tasks]
something = { depends_on = [{ task = "test", environment = "a" }] }

Short-Circuit Composition

[tasks.test]
cmd = "pytest tests/{{ test-type }}"

[tasks]
test-all = [{ task = "test", args = ["all"] }]
# Equivalent to: test-all = { depends-on = [{task = "test", args = ["all"] }]}

Note: we already allow the following:

[tasks]
test = ["cargo", "test"]

This is a bit unfortunate, but we can disambiguate since one list only contains of dictionaries and the other only of strings.

@prsabahrami
Copy link

Cool stuff!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment