
vx speaks to agents
vx run speaks JSON, every refusal has a stable code, and vx mcp plans and runs tasks. vx init moves a Turbo or Nx repo to vx in one command.
A live run now says how long is left, vx why follows a re-run to the file that caused it, and a bad config points at its line.

vx 0.0.590 to 0.0.625 all shipped on 2026-10-08. This batch is about
answers: how long a run has left, why a task re-ran, and where a config
is wrong. It also brings Vite Task and Lerna migration, a dev server that
stays up under vx watch, and faster warm runs on large workspaces.
In this release
A second into a live run, the time row says what is left. The forecast
comes from each unfinished task’s median run time in local history, so
it needs no setup. Worker rows mark the task on the critical path and
say how many tasks wait on each (blocks N). In Ghostty, iTerm2,
WezTerm and Windows Terminal, vx also draws progress in the tab and posts
a desktop notification when a run of 10 s or more ends.
1.40s running web#build critical path · blocks 3 1.10s running docs#build time 1.41s · ~3s leftPR #3246
When a task re-ran only because a dependency moved, vx why used to stop
at that dependency and tell you which vx why to run next. It now
follows the chain inside the same run down to the task whose own inputs
changed, and prints it under root cause. --format json carries the
chain as roots.
$ vx why app#build verdict cache key changed: upstream lib#build
what changed (1 component, 5 unchanged): changed upstream lib#build dcdf2a600ba2194d → 921ea5200e280cc9
root cause: app#build ← lib#build ← file packages/lib/src/index.tsflowchart LR F["file packages/lib/src/index.ts"] -->|changed| L["lib#build"] -->|key moved| A["app#build"] style F stroke:#c6f84e,stroke-width:2px
PR #3245. Deep dive: Why did this re-run?
A config refusal now names the file at line:col, relative to your
directory, so a terminal can open it on click. Below the message it
prints the lines leading up to the field with a caret under it.
vx: packages/app/vx.config.ts:8:47: tasks.build.cache.outputs must be an object (fields: files, workspaceFiles), not an array — did you mean `{ files: [...] }`?
6 | dependsOn: ['^build'], 7 | exec: { command: 'sleep 0.6 && mkdir -p dist && cp src/index.ts dist/' },> 8 | cache: { inputs: { files: ['src/**'] }, outputs: ['dist/**'] }, | ^PR #3247
The result line now says how much time the cache saved. The figure is the sum of the stored run times of the tasks it restored, not the time the restore took.
info 4 workers · local cache time 39ms result 2 tasks · all cached · 928ms saved · 39msPR #3242
vx watch dev restarted the dev server on every cycle, even for an edit
inside the app, so the dev tool’s own hot reload never got a chance. The
server now stays up while its task config is unchanged. Each cycle
rebuilds only the libraries an edit reaches, and the dev tool reloads
what changed. A config change or a crash still restarts it.
vx watch devflowchart LR E["edit in lib"] --> L["lib#build reruns"] --> D["dev server stays up"] --> H["hot reload"]
PR #3243. Deep dive: Watch mode
npx @vzn/vx-migrate now reads a repo that uses vite-plus. It loads each
vite.config as vp run does and writes a vx.config.ts per package
from run.tasks and the package scripts. A nested vp run becomes a
dependsOn edge instead of a second runner inside vx. vx run also
accepts the vp run flags you already type: -r reads as --all, -w
as --filter //, --concurrency-limit as --concurrency, and
--ignore-depends-on as --exclude-dependencies.
npx @vzn/vx-migratevx run build -rPRs #2908, #2965. Guide: Vite Task
A Lerna repo whose root scripts call lerna run now migrates through
nx(), since Lerna runs Nx’s task runner underneath. nx.json’s
parallel, defaultBase and maxCacheSize are written into
vx.workspace.ts as concurrency, affectedBase and
cacheRetention.maxSize, where they used to be notes. A run-commands
line that starts with nx <target> <project> becomes a dependsOn edge
instead of a todo. And -p 'apps/*' selects by directory, as Nx does.
npx @vzn/vx-migratevx run build -p 'apps/*'PRs #3072, #3007, #2956, #2887. Guide: Nx
vx show and vx show <task> now select projects the same way
vx run does. This is the vx form of turbo ls --affected and
nx show projects --affected.
$ vx show --affectedapp packages/app 1 tasklib packages/lib 1 taskPR #2986
Four changes cut the overhead of a warm run on the 1,090-package bench. An all-hit run went from 752 ms to 708 ms by reusing group keys. A restore went from 2,356 ms to 2,019 ms by walking outputs once. The scheduler dropped about 25 ms of per-task bookkeeping, and a frozen run loads its configs 2.9× faster. A new check on every PR now holds spawn, hash and SQLite counts on these paths to a baseline.
vx run build --allPRs #3235, #3241, #3239, #3240, #3238
vx-cache-v41: every cached task misses once after upgrading (#3030).exec.env define and passThrough names must be shell identifiers; others are refused at load (#2958).--filter tag: cannot select (**, an upper-case glob) is refused at load (#2966).readonly; copy a resolved list before mutating it (#2938).Cache.storeFallback, Cache.storeMoved and Cache.orphansBeforeReset are removed; open a Cache in 'preview' mode instead of the last (#2976, #3041).See Upgrading.
npm install -D @vzn/vx@latestA standalone binary updates itself with vx upgrade.