Each case is a small workspace and the outcome a user would see. All six
tools run the same 984 cases, each in a sandbox.
vx 747b26f · Turborepo 2.11.10 · Nx 24.0.2 · Vite Task 1.4.0 · moon 2.6.5 · Nix 2.34.6 · 2026-11-07 · every case
The cases come from every tool's own tests
The cases are compiled from the test suites of Nx, Turborepo, Vite
Task, moon, Nix and vx. A case names no tool's config. It says which
projects exist, what each task runs, and what must hold afterwards.
A thin adapter turns the case into each tool's own config. The harness
marks each command as it starts and ends, so "ran" means it ran.
Where the scores split
| Group | Cases | vx | Nx | Turborepo | moon | Vite Task | Nix |
|---|---|---|---|---|---|---|---|
| graph | 149 | 149 | 113 | 91 | 84 | 86 | 57 |
| inputs | 302 | 302 | 186 | 187 | 192 | 177 | 175 |
| outputs | 223 | 223 | 156 | 160 | 122 | 139 | 158 |
| affected | 97 | 97 | 57 | 68 | 69 | 0 | 0 |
| watch | 31 | 31 | 27 | 28 | 0 | 0 | 0 |
| sandbox | 18 | 18 | 0 | 1 | 0 | 1 | 15 |
A case a tool cannot express counts as not passed. Its users cannot get
that behaviour either.
Each case says why it matters
Args forwarded to a server reach it as typed, never expanded by a shell
vx pass
moon pass
Nx fail seen.txt is "<0><0>…", expected "<$(id -u)><`id -u`>…"
Every case carries three or four sentences on what goes wrong without
it. Here a second shell ran $(id -u), a command nobody typed.
vx misses 2 cases. Both need programs a dependency puts on PATH, which
vx left to the tools you already have.
All cases, filters and each tool's detail: Conformance.
More at vznjs.github.io/vx.
Originally published on the vx blog. vx is open-source (MIT) task orchestration with a build cache: vznjs.github.io/vx · GitHub.
Written with AI assistance.
Top comments (1)
Two methodological choices here are rarer than the scores. The cannot-express-counts-as-fail rule is the right default: score only what every tool supports and the corpus silently rounds down to the common denominator, which is exactly where users don't live. Marking each command's start and end so "ran" means it ran separates "never attempted" from "ran and failed" - most harnesses can't tell those apart, because both leave an empty log. The bias I'd watch is the corpus's provenance: a suite compiled from the union of what six tools already test can only surface known differences. Any failure mode no tool's authors imagined is invisible in all six columns, so 984/984 measures the union's coverage, not correctness. Keeping vx's own two misses in the table is what makes the rest of the table readable.