A sandbox refusal names the path and the grant to add. Two tasks writing the same folder are stopped before they delete each other. A config that hangs times out with its name. And a pure config is read back as data, not run again.
correctness
correctness
A refusal is only useful if it says what to do next. Each guard in this
post stops something real, and each one ends with the fix.
flowchart LR
T[a task or a config] --> G{guard}
G -->|write outside its grants| S[names the path and the grant]
G -->|two tasks, one output| O[names both and the fix]
G -->|config hangs| C[names the config]
style S stroke:#c6f84e,stroke-width:2px
vx cleans a task’s outputs before it runs and before a cache restore. Two
tasks that declare the same output would delete each other’s work, so the
run is refused before anything starts:
Terminal window
$vxrun@demo/api#bundle
vx:@demo/api#bundleand@demo/api#buildbothdeclaretheoutput"dist/**"incache.outputs.files—vxcleansatask's declared outputs before it runs and before a cache-hit restore, so whichever of these runs second DELETES the other'soutput.Giveeachtaskitsownoutputpath,orsetrules:{exclusiveOutputs:false}invx.workspace.tstoletadependantaddtoitsupstream's outputs.
This is a workspace rule. Rules are checks that keep vx fast and
correct, on by default. Turning one off allows a shape vx still runs
correctly, only slower, and never changes a cache key:
upfrontKeys refuses a task whose inputs match another task’s outputs
in the same run, because its key cannot be known before that task
finishes. The message names the glob to exclude.
A vx.config.ts is code, and code can hang: an await on a server that
is down, or a loop. Each config gets 30 seconds, and then the load fails
and names the config. A real evaluation takes about 10 ms.
VX_CONFIG_WORKER_TIMEOUT_MS changes the limit.
Most configs only call defineProject with plain data. vx proves that
from the imports, then stores the evaluated result. The next run reads it
back as data instead of running the file again. A config that imports
anything else, reads the environment or calls Math.random is evaluated
every run, as it should be.
Files, env vars, tool versions and upstream tasks go into the key. Outputs and both output streams come back. A warm hit restores nothing at all, and a damaged artifact is a miss, never a wrong build.
Edges in dependsOn, selections in --filter. A small grammar covers upstream builds, cross-project tasks, groups, dependents, folders and tags. And a name that matches nothing stops the run before it starts.
A vx.config.ts can import a preset, compute a command, read a constant from another file. The cache key sees the evaluated object, so all of that participates in the key. Static JSON tools cannot see it at all.
Turborepo, Nx and other product names are trademarks of their owners. vx is not affiliated with or endorsed by them.