Skip to content

feat: Hierarchical Tasks#5921

Draft
guyEIT wants to merge 6 commits intoprefix-dev:mainfrom
guyEIT:feat/hierarchical-tasks
Draft

feat: Hierarchical Tasks#5921
guyEIT wants to merge 6 commits intoprefix-dev:mainfrom
guyEIT:feat/hierarchical-tasks

Conversation

@guyEIT
Copy link
Copy Markdown

@guyEIT guyEIT commented Apr 19, 2026

Description

Fixes #5003.

Adds hierarchical-tasks as a preview feature. A root workspace can
aggregate nested member workspaces, and you can address a member task
with :::

pixi run a::test
pixi run a::c::test
pixi run all_tests      # root task with depends-on = ["a::test", "a::c::test", "b::test"]

Each member has its own [workspace], its own envs, its own lockfile,
its own .pixi/envs/. cd into the member and pixi run test still
works on its own: the upward walk stops at the member's pixi.toml
and the outer aggregation is invisible. Same as git submodules.

Design

#5003 opened with includes = [...]. I used phuicy's proposal instead.
Two quotes from the issue that shaped this PR:

A pixi.toml applies to its directory and below. Any subdirectory with
its own pixi.toml becomes a child project. Running Pixi at the repo
root implicitly aggregates all descendant projects. Running Pixi in
a subdirectory only sees that sub-project, so standalone usage still
works.

pixi run A::tests    # runs tests task from sub workpackage : A

dependencies on tasks could [be] introduced with a similar mechanism:
depends_on: A::tests

That is what this PR does. Nothing more. No dep merging, no unified
lockfile, no public/private, no -w. All called out as follow-ups
on #5003.

Behavior

  • Discovery walks down from the root. The signal is [workspace]
    presence. [package]-only manifests are transparent — discovery
    walks through them.
  • Each member is loaded as a full standalone Workspace via
    WorkspaceLocator::locate, the same path any standalone pixi
    project uses.
  • a::b::task routing looks the task up in the member's default
    environment. The returned Environment belongs to the member, so
    cwd, activation, lockfile, and install dir all follow naturally.
  • pixi run is lazy: only members you actually touch get their
    lockfile updated and env installed.
  • pixi install at the root is eager: walks every member and
    installs each one's default env.
  • The upward discovery rule is unchanged. Nearest-ancestor
    [workspace] wins. If you're inside a member, that member is your
    root; the outer aggregation is only visible when you run from the
    outer root.

Gated on preview = ["hierarchical-tasks"]. Flag off → zero change
in behavior.

Docs: docs/workspace/hierarchical_tasks.md, linked under Concepts
in mkdocs.yml.

How Has This Been Tested?

  • pixi_manifest::members — 12 unit tests (empty tree, top-level and
    nested members, transparent intermediates, skip list, duplicate
    sibling names, deeply nested chains, insertion order, [package]-only
    transparency).
  • pixi_task::task_environment — 6 integration tests, notably
    asserting env.workspace().root() is the member's directory after
    routing a::test and a::c::test.
  • pixi run test-fast — 1420 tests pass.

To reproduce: build pixi locally, drop this layout in a tempdir, and
run the commands below.

<tmp>/pixi.toml          [workspace] preview = ["hierarchical-tasks"]
                         [tasks] all_tests = { depends-on = ["a::test", "a::c::test", "b::test"] }
<tmp>/a/pixi.toml        [workspace] name = "a" + [tasks] test = "echo a"  where = "pwd"
<tmp>/a/c/pixi.toml      [workspace] name = "c" + [tasks] test = "echo c"  where = "pwd"
<tmp>/b/pixi.toml        [workspace] name = "b" + [tasks] test = "echo b"  where = "pwd"
pixi run a::test                 # runs in a/
pixi run a::c::where             # pwd prints <tmp>/a/c
pixi run all_tests               # each dep runs in its own workspace
cd a/c && pixi run test          # standalone, outer root invisible
pixi install                     # writes pixi.lock in root, a, a/c, b

AI Disclosure

  • This PR contains AI-generated content.
    • I have tested any AI-generated content in my PR.
    • I take responsibility for any AI-generated content in my PR.

Tools: Claude (Opus 4.7).

Checklist:

  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • I have added sufficient tests to cover my changes.
  • I have verified that changes that would impact the JSON schema have been made in schema/model.py. (Worth checking whether the preview-flag list in schema/model.py needs hierarchical-tasks added.)

guyEIT added 2 commits April 18, 2026 20:41
Each member is now its own standalone [workspace] with its own envs,
lockfile, and .pixi/ install dir - the root just aggregates and
dispatches. Fixes the submodule case: cd into a member and
pixi run test works on its own.

find_task routes a::b::task to the member's default env, so cwd,
activation, and lockfile all target the member naturally.
pixi run is lazy (only touches members it uses); pixi install at
the root is eager (walks every member). Stays behind the
hierarchical-tasks preview flag.
@guyEIT guyEIT changed the title Feature :: Hierarchical Tasks feat - Hierarchical Tasks Apr 19, 2026
@guyEIT guyEIT changed the title feat - Hierarchical Tasks feat: Hierarchical Tasks Apr 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature Request: Support Including Sub-Project pixi.toml with Unified Resolution

1 participant