A task hangs, gets killed, prompts for input, or calls vx run on itself. Each one gets a clear line from vx instead of a mystery. Plus timeouts, forwarded arguments, and two runs that politely take turns.
DX
DX
Most tasks run and exit. The rest hang, die, ask a question, or loop
back into vx. These are the cases that cost an afternoon, so vx says
what happened in plain words.
flowchart LR
T[task] --> H{what went wrong?}
H -->|ran too long| A[killed, reported as a timeout]
H -->|killed by a signal| B[exit code named by its signal]
H -->|vx run inside itself| C[refused with the reason]
H -->|config typo| D[the key, the line, no stack]
style B stroke:#c6f84e,stroke-width:2px
Exit 137 means nothing to most people. vx names the signal and the usual
suspects:
Terminal window
$vxrun@demo/api#killed
┌─@demo/api#killed> $ kill-9$$
[vx] exit 137 is how the shell reports a death by SIGKILL (9): nothing catches it — on Linux the kernel's OOM killer (dmesg, or the memory limit of the container's cgroup) or an explicit kill; vx's own timeout reports itself as a timeout
A task that calls vx run on its own workspace hides its work from the
graph, the scheduler and the cache key, and a loop back to itself would
fork forever. vx sets VX_RUN_WORKSPACE and VX_RUN_TASK on every task
and refuses the nested run:
Terminal window
$vxrun@demo/api#nested
┌─@demo/api#nested> $ vxrun@demo/api#echo
vx:task@demo/api#nestedruns`vx run`insideitsownworkspace:anestedrunisinvisibletotheoutergraph (its tasksescapetheschedule,theconcurrencybudgetandthecachekey) and a loop back to this task forks without bound. Declare what it needs with dependsOn instead.
└─@demo/api#nested── (129ms) failed (exit1)
Driving a different workspace from a task is fine.
A task with exec.interactive: true, such as a database migration that
asks before it applies, gets vx’s own terminal. It runs alone, its output
is passed straight through, and it is never cached. Off a terminal, on CI
or in a pipe, its input is empty, so a prompt reads end of input and
never hangs.
Start a second vx run in the same workspace and it waits for the first.
After a second it says who it is waiting for:
[vx] waiting for another vx run (pid N) on this workspace to finish….
A broken build skips what depends on it and nothing else. Every skipped task names the failure that blocked it. Pick fail-fast or run-everything with one flag, and set how many tasks run at once as a count or a share of the CPUs.
DX
Dev servers as graph nodes: readiness instead of sleep
The hard part of 'start the tests once the server is up' is knowing when it is up. vx watches a persistent task's output for a pattern, holds its dependents until the line appears, and tears the server down when the run ends.
vx watch does not filter filesystem events against your input globs. It re-runs the graph and lets the cache key decide, which is tens of milliseconds for an irrelevant edit and exactly right for a relevant one.
Turborepo, Nx and other product names are trademarks of their owners. vx is not affiliated with or endorsed by them.