@vzn/vx 0.0.636 → 0.0.637
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +39 -11
- package/docs/caching.md +213 -207
- package/docs/cli.md +699 -655
- package/docs/execution.md +67 -75
- package/docs/features.md +44 -40
- package/docs/patterns.md +26 -25
- package/docs/schema.md +376 -198
- package/docs/security.md +76 -39
- package/launcher.sh +43 -0
- package/package.json +5 -5
- package/schemas/cache.json +41 -19
- package/schemas/info.json +23 -11
- package/schemas/last.json +48 -2
- package/schemas/lock.json +1 -1
- package/schemas/plan.json +2 -2
- package/schemas/show.json +5 -3
- package/schemas/why.json +15 -1
- package/skills/vx/SKILL.md +16 -12
- package/src/bin.ts +17 -2
- package/src/cache/archive.ts +11 -0
- package/src/cache/cache.ts +105 -53
- package/src/cache/git-inputs.ts +277 -63
- package/src/cache/index.ts +7 -1
- package/src/cache/inputs.ts +125 -35
- package/src/cache/key-fold.ts +8 -7
- package/src/cache/layer.ts +8 -17
- package/src/cache/layered-cache.ts +16 -102
- package/src/cache/policy.ts +25 -29
- package/src/cache/run-history.ts +36 -14
- package/src/cache/schema.ts +21 -23
- package/src/cache/scoped-cache.ts +224 -0
- package/src/cli/cache.ts +150 -28
- package/src/cli/completions.ts +2 -2
- package/src/cli/core-alias.ts +1 -1
- package/src/cli/foreign-flags.ts +13 -12
- package/src/cli/help.ts +94 -63
- package/src/cli/index.ts +42 -13
- package/src/cli/info.ts +38 -23
- package/src/cli/init.ts +115 -406
- package/src/cli/last.ts +145 -4
- package/src/cli/lock.ts +333 -111
- package/src/cli/plan-format.ts +2 -2
- package/src/cli/plugin-commands.ts +5 -9
- package/src/cli/plugin-templates.ts +10 -10
- package/src/cli/run.ts +103 -149
- package/src/cli/select.ts +33 -39
- package/src/cli/show.ts +17 -19
- package/src/cli/task-verb.ts +2 -9
- package/src/cli/upgrade.ts +402 -145
- package/src/cli/watch-cycle.ts +9 -2
- package/src/cli/watch-filter.ts +33 -60
- package/src/cli/watch-fs.ts +29 -16
- package/src/cli/watch-judge.ts +12 -3
- package/src/cli/watch-set.ts +16 -42
- package/src/cli/watch.ts +188 -215
- package/src/cli/why.ts +28 -17
- package/src/cli/workspace-config.ts +31 -68
- package/src/config.ts +169 -70
- package/src/exec/env.ts +1 -31
- package/src/exec/executor.ts +1 -5
- package/src/exec/kill-tree.ts +2 -1
- package/src/exec/sandbox-runtime.ts +12 -1
- package/src/exec/sandbox-violations.ts +9 -1
- package/src/graph/dependency-spec.ts +1 -1
- package/src/graph/index.ts +1 -0
- package/src/graph/priorities.ts +1 -1
- package/src/graph/scheduler.ts +19 -7
- package/src/graph/task-graph.ts +44 -20
- package/src/handoff.ts +169 -0
- package/src/index.ts +24 -57
- package/src/orchestrator/affected-tasks.ts +7 -5
- package/src/orchestrator/command-windows.ts +44 -0
- package/src/orchestrator/deferred-outputs.ts +12 -10
- package/src/orchestrator/doctor.ts +98 -110
- package/src/orchestrator/download-policy.ts +3 -3
- package/src/orchestrator/events.ts +19 -3
- package/src/orchestrator/excluded-keys.ts +0 -2
- package/src/orchestrator/execute-task.ts +158 -63
- package/src/orchestrator/fingerprint-watch.ts +18 -15
- package/src/orchestrator/forecast.ts +10 -2
- package/src/orchestrator/framed-output.ts +8 -3
- package/src/orchestrator/graph-stage.ts +5 -5
- package/src/orchestrator/history.ts +70 -30
- package/src/orchestrator/hit-restore.ts +15 -3
- package/src/orchestrator/index.ts +18 -4
- package/src/orchestrator/local-shortcircuit.ts +2 -1
- package/src/orchestrator/lockfile-claim.ts +79 -20
- package/src/orchestrator/logger.ts +71 -39
- package/src/orchestrator/metrics.ts +71 -6
- package/src/orchestrator/miss-save.ts +3 -0
- package/src/orchestrator/options.ts +42 -29
- package/src/orchestrator/output-host.ts +72 -0
- package/src/orchestrator/plan.ts +6 -8
- package/src/orchestrator/plugin-host.ts +87 -63
- package/src/orchestrator/plugin.ts +94 -60
- package/src/orchestrator/prepare.ts +113 -72
- package/src/orchestrator/projects.ts +102 -99
- package/src/orchestrator/remote-prefetch.ts +2 -1
- package/src/orchestrator/run-context.ts +25 -6
- package/src/orchestrator/run-failures.ts +17 -8
- package/src/orchestrator/run-lock.ts +1 -1
- package/src/orchestrator/run-report.ts +9 -9
- package/src/orchestrator/run-settings.ts +48 -0
- package/src/orchestrator/run.ts +121 -95
- package/src/orchestrator/sandbox-fix.ts +39 -20
- package/src/orchestrator/sandbox-request.ts +84 -13
- package/src/orchestrator/signals.ts +1 -1
- package/src/orchestrator/stable-keys.ts +13 -11
- package/src/orchestrator/status-line.ts +48 -6
- package/src/orchestrator/summary.ts +46 -62
- package/src/orchestrator/task-hash.ts +12 -83
- package/src/orchestrator/telemetry.ts +3 -3
- package/src/settings.ts +417 -0
- package/src/util/errors.ts +1 -1
- package/src/util/essential-env.ts +31 -0
- package/src/util/hide-env.ts +107 -0
- package/src/util/index.ts +8 -2
- package/src/util/paths.ts +10 -0
- package/src/util/settle.ts +49 -30
- package/src/util/size.ts +23 -4
- package/src/util/timing.ts +3 -2
- package/src/util/ulid.ts +1 -1
- package/src/util/verbs.ts +0 -15
- package/src/workspace/affected.ts +77 -222
- package/src/workspace/config-eval.ts +15 -20
- package/src/workspace/config-imports.ts +78 -3
- package/src/workspace/config-schema.ts +209 -268
- package/src/workspace/dependency-rules.ts +57 -0
- package/src/workspace/filter.ts +2 -2
- package/src/workspace/fingerprint.ts +11 -121
- package/src/workspace/index.ts +20 -27
- package/src/workspace/load-reads.ts +4 -4
- package/src/workspace/lockfile.ts +96 -140
- package/src/workspace/migration.ts +242 -146
- package/src/workspace/package-graph.ts +30 -216
- package/src/workspace/project-loader.ts +80 -285
- package/src/workspace/repo-id.ts +2 -1
- package/src/workspace/workspace.ts +362 -831
- package/src/cache/config-evals.ts +0 -130
- package/src/workspace/config-cache.ts +0 -661
- package/src/workspace/migrate-scripts.ts +0 -1121
package/docs/execution.md
CHANGED
|
@@ -13,9 +13,9 @@ terminal and a task succeeding or failing. Read it alongside
|
|
|
13
13
|
│ 2. cli/index.ts dispatches by subcommand (run / watch / cache /
|
|
14
14
|
│ lock / init / upgrade / show / info / why / last / docs /
|
|
15
15
|
│ completions / help / version); any other verb is asked of the
|
|
16
|
-
│ workspace's plugins (`commands` seam
|
|
16
|
+
│ workspace's plugins (`commands` seam).
|
|
17
17
|
│ 3. cli/run.ts:parseRunArgs(argv) → RunArgs (validated; resolves
|
|
18
|
-
│ the 4-axis cache policy from --cache / --no-cache / --force).
|
|
18
|
+
│ the 4-axis cache policy from --cache-policy / --no-cache / --force).
|
|
19
19
|
│ 4. cli/run.ts:runCmd resolves the project scope:
|
|
20
20
|
│ - bare positionals respect --all / --filter / --affected / cwd
|
|
21
21
|
│ - anchored positionals (pkg#task) target directly
|
|
@@ -27,51 +27,43 @@ terminal and a task succeeding or failing. Read it alongside
|
|
|
27
27
|
│ --dry / --graph short-circuit into planRun instead.
|
|
28
28
|
│
|
|
29
29
|
├─ Prepare (src/orchestrator/prepare.ts:prepareRun — shared with planRun)
|
|
30
|
-
│ 1. findWorkspaceRoot(cwd) —
|
|
31
|
-
│
|
|
32
|
-
│
|
|
33
|
-
│
|
|
34
|
-
│
|
|
35
|
-
│
|
|
36
|
-
│
|
|
37
|
-
│
|
|
38
|
-
│
|
|
39
|
-
│
|
|
40
|
-
│
|
|
41
|
-
│
|
|
42
|
-
│
|
|
43
|
-
│ for pnpm; the package.json forms read as bytes (readOnce,
|
|
44
|
-
│ shared with step 1) and JSON.parse.
|
|
45
|
-
│ 3. loadWorkspacePlugins — loadWorkspaceConfig reads the optional
|
|
46
|
-
│ vx.workspace.{ts,mts,js,mjs,cts,cjs} at the root (concurrency /
|
|
47
|
-
│ cacheDir / timeout / cacheRetention / affectedBase / cacheScope /
|
|
48
|
-
│ rules / schedule / inputStability / plugins),
|
|
30
|
+
│ 1. findWorkspaceRoot(cwd) — the directory of the nearest
|
|
31
|
+
│ .vx/workspace.* up to the git top-level. An UNSCOPED run (no
|
|
32
|
+
│ explicit project scope, at least one bare task name) then
|
|
33
|
+
│ starts step 12's git enumeration over the whole tree,
|
|
34
|
+
│ overlapping steps 2–11; a scoped run waits, since its
|
|
35
|
+
│ pathspecs depend on which projects the task graph holds.
|
|
36
|
+
│ 2. Read .vx/projects.lock.json: the project directories `vx lock`
|
|
37
|
+
│ found (every directory holding a vx.config.*, git's ignore
|
|
38
|
+
│ rules applied) and their configs. Each locked config file is
|
|
39
|
+
│ stat'ed; one gone is refused ("run `vx lock`").
|
|
40
|
+
│ 3. loadWorkspacePlugins — loadWorkspaceConfig reads the
|
|
41
|
+
│ .vx/workspace.{ts,mts,js,mjs,cts,cjs} the root lookup found (run / cache /
|
|
42
|
+
│ watch / plugins / lock),
|
|
49
43
|
│ then the plugin `config` stage runs on it.
|
|
50
|
-
│ 4.
|
|
51
|
-
│
|
|
52
|
-
│
|
|
53
|
-
│
|
|
44
|
+
│ 4. The plugin `discover` stage: more directories, names and
|
|
45
|
+
│ edges. A project is named by its config's `name`, else a
|
|
46
|
+
│ plugin's, else its path (`//` for the root); two of one name
|
|
47
|
+
│ are refused naming both directories.
|
|
48
|
+
│ 5. buildPackageGraph — project edges the `discover` plugins gave.
|
|
54
49
|
│ 6. Local cache open: new Cache(cacheDir, { read, write }, root)
|
|
55
|
-
│ with the policy's local slice
|
|
56
|
-
│
|
|
57
|
-
│
|
|
58
|
-
│
|
|
59
|
-
│
|
|
60
|
-
│ `unclaimed` (minus the files a `fingerprint` plugin claims —
|
|
61
|
-
│ `@vzn/vx-lockfile` keys those per project; reused for every
|
|
62
|
-
│ task's cache key) and `files` (the bytes, for the mid-run
|
|
63
|
-
│ fingerprint check).
|
|
50
|
+
│ with the policy's local slice. Then
|
|
51
|
+
│ readClaimedFiles: one read of each root file a `fingerprint`
|
|
52
|
+
│ plugin claims (`@vzn/vx-lockfile`: its lockfile and install
|
|
53
|
+
│ settings; nothing without one), the bytes for the mid-run
|
|
54
|
+
│ check. Core folds none of them into a key.
|
|
64
55
|
│ 7. SCOPED config loading — only in-scope projects plus their
|
|
65
|
-
│ transitive dependency closure
|
|
56
|
+
│ transitive dependency closure load ('^task' frontier
|
|
66
57
|
│ expansion never escapes the closure); one staged load,
|
|
67
|
-
│ loadProjects, shared with every reading verb.
|
|
68
|
-
│
|
|
69
|
-
│
|
|
70
|
-
│ semantics; a missing lock or entry is a hard UserError.
|
|
71
|
-
│
|
|
72
|
-
│
|
|
73
|
-
│
|
|
74
|
-
│
|
|
58
|
+
│ loadProjects, shared with every reading verb. A run's configs
|
|
59
|
+
│ load from .vx/projects.lock.json — no evaluation, no staleness check
|
|
60
|
+
│ of its own (vx lock --check is the audit), frozen-env
|
|
61
|
+
│ semantics; a missing lock or entry is a hard UserError. The
|
|
62
|
+
│ verbs that evaluate (vx lock, the readers) use
|
|
63
|
+
│ loadProjectConfigs in one batch: native Bun await import()
|
|
64
|
+
│ with a content-hash query-string bust, every config
|
|
65
|
+
│ evaluated; the loader validates each
|
|
66
|
+
│ TaskConfig shape. Either way the plugin `project` stage runs
|
|
75
67
|
│ on each config with a re-validation after every plugin.
|
|
76
68
|
│ 8. computeNestedProjectDirs — set of projects rooted inside each
|
|
77
69
|
│ project, computed over EVERY config-bearing project (loaded
|
|
@@ -79,8 +71,8 @@ terminal and a task succeeding or failing. Read it alongside
|
|
|
79
71
|
│ 9. expandRequested (see Task selection below).
|
|
80
72
|
│ 10. Cache layer: an injected RunOptions.remoteCache is composed
|
|
81
73
|
│ with the local cache into a LayeredCache (it wins); else
|
|
82
|
-
│ resolveCache
|
|
83
|
-
│
|
|
74
|
+
│ resolveCache layers each plugin's remote over the local
|
|
75
|
+
│ cache, in declared order; else bare local.
|
|
84
76
|
│ 11. buildTaskGraph (see below).
|
|
85
77
|
│ 12. Bulk git populate — the enumeration step 1 started is
|
|
86
78
|
│ awaited, or a scoped run starts it here over the projects
|
|
@@ -163,7 +155,7 @@ terminal and a task succeeding or failing. Read it alongside
|
|
|
163
155
|
│ signal, forward it (SIGHUP as SIGTERM) to everything
|
|
164
156
|
│ in liveChildren + persistentRegistry (and kill any
|
|
165
157
|
│ running cache.inputs.runtime probe, C-65), wait
|
|
166
|
-
│
|
|
158
|
+
│ VX_RUN_KILL_GRACE (2 s) for their groups, SIGKILL
|
|
167
159
|
│ what is still there, let the run finish its own
|
|
168
160
|
│ end (flush, teardown, cache close), then
|
|
169
161
|
│ die of the signal (SIGINT → 130, SIGTERM → 143,
|
|
@@ -250,11 +242,9 @@ terminal and a task succeeding or failing. Read it alongside
|
|
|
250
242
|
│ output (deduped per run; a non-zero exit throws a
|
|
251
243
|
│ UserError that fails this task — its dependents skip,
|
|
252
244
|
│ independent tasks continue)
|
|
253
|
-
│ 2. hashTaskConfig
|
|
254
|
-
│ per run via HashCache)
|
|
245
|
+
│ 2. hashTaskConfig (memoized per run via HashCache)
|
|
255
246
|
│ 3. filterUpstreamHashes (apply cache.inputs.tasks filter)
|
|
256
|
-
│ 4. cache.key({ taskId,
|
|
257
|
-
│ projectPackageJsonHash, taskConfigHash,
|
|
247
|
+
│ 4. cache.key({ taskId, taskConfigHash,
|
|
258
248
|
│ forwardArgs, envValues, runtimeValues,
|
|
259
249
|
│ workspaceRuntimeValues, upstreamHashes,
|
|
260
250
|
│ pluginParts, inputFiles }) → 16-hex xxh3
|
|
@@ -283,9 +273,9 @@ terminal and a task succeeding or failing. Read it alongside
|
|
|
283
273
|
│ exec.timeout SIGTERMs an overrun → real `failed`, never
|
|
284
274
|
│ cached. An attempt that ends while the run is STOPPING
|
|
285
275
|
│ (Ctrl-C teardown) classifies as `aborted` instead, whatever
|
|
286
|
-
│ its exit — not
|
|
276
|
+
│ its exit — not recorded, not retried.
|
|
287
277
|
│ 8. On exit 0 + willSave (willWrite, no tainted upstream):
|
|
288
|
-
│ keyStillTrue() — if
|
|
278
|
+
│ keyStillTrue() — if a claimed root file or an
|
|
289
279
|
│ input moved since the key was taken, the result stands
|
|
290
280
|
│ but the save is withheld (said on the status line).
|
|
291
281
|
│ saveMiss — in the slot: resolveOutputs(outputs) +
|
|
@@ -386,7 +376,7 @@ The child process gets, in priority order (lowest first):
|
|
|
386
376
|
`TMPDIR`, `TEMP`, `TMP`, `LANG`, `LC_ALL`, `LC_CTYPE`, `TERM`,
|
|
387
377
|
`COLORTERM`, `FORCE_COLOR`, `NO_COLOR`, `CI`, `NODE_OPTIONS`,
|
|
388
378
|
`COREPACK_HOME`, `PNPM_HOME` — the list is
|
|
389
|
-
`ESSENTIAL_ENV` in `src/
|
|
379
|
+
`ESSENTIAL_ENV` in `src/util/essential-env.ts`).
|
|
390
380
|
2. **`exec.env.passThrough`** names → values from host `process.env`.
|
|
391
381
|
3. **`exec.env.define`** literal name/value pairs.
|
|
392
382
|
4. **PATH augmentation** — `<projectDir>/node_modules/.bin`, then
|
|
@@ -410,14 +400,16 @@ The child process gets, in priority order (lowest first):
|
|
|
410
400
|
timeout and a shutdown's SIGTERM keep their own lines, and a task the
|
|
411
401
|
run's stop killed (the SIGKILL past the grace too) gets none.
|
|
412
402
|
|
|
413
|
-
Anything not in these four layers is
|
|
403
|
+
Anything not in these four layers is absent from the child's environment, except
|
|
414
404
|
the two vx sets itself — `VX_RUN_WORKSPACE` and `VX_RUN_TASK` — so a
|
|
415
405
|
task that shells out to `vx run` in its own workspace is refused
|
|
416
406
|
before it forks without bound, and `npm_execpath`, the workspace's
|
|
417
407
|
package manager (unkeyed; `schema.md` § `env`). A sandboxed task also gets the sandbox's own
|
|
418
408
|
proxy, CA and `TMPDIR` values
|
|
419
409
|
([`modules/sandbox-runtime.md`](./modules/sandbox-runtime.md#the-environment-srt-sets)). This prevents incidental env leakage
|
|
420
|
-
between machines and gives reproducible runs.
|
|
410
|
+
between machines and gives reproducible runs. It is hygiene, not a
|
|
411
|
+
boundary: an unsandboxed task runs as you and can still read your home
|
|
412
|
+
(vx hides its own environment, `modules/util-hide-env.md`). `exec.sandbox` is the boundary ([`security.md`](./security.md#what-the-sandbox-stops)).
|
|
421
413
|
|
|
422
414
|
The allowlist + isolation contract lives in
|
|
423
415
|
[`modules/env.md`](./modules/env.md) and is the only field the
|
|
@@ -428,22 +420,22 @@ broader access has cache-stability implications).
|
|
|
428
420
|
|
|
429
421
|
## Failure handling
|
|
430
422
|
|
|
431
|
-
| Failure | Behavior
|
|
432
|
-
| ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
433
|
-
| Exec exits non-zero | Task is `failed`; cache NOT written; output streamed live + the failure frame replays at run end
|
|
434
|
-
| `exec.timeout` overrun | SIGTERM to the task's group, SIGKILL for whoever is left after the grace; task is `failed` (timed out), exit 143 (137 when the SIGKILL took it, and the line says so), never cached
|
|
435
|
-
| Child killed by Ctrl-C teardown (SIGINT/SIGTERM/SIGHUP), or by an embedder's `RunOptions.signal` abort — which also completes every never-started task `aborted` | Task is `aborted` — not
|
|
436
|
-
| `execute()` throws (internal error) | Task marked `failed`; stderr written `[vx] internal error in <id>` (a `UserError` reports plainly); a plugin executor's throw reports plainly as `plugin '<p>' (executor '<e>') failed in execute: <reason>` (C-63, C-85)
|
|
437
|
-
| Persistent task exits before ready | Task marked `failed` with `exited before becoming ready (exit N)`; its output already streamed live; `aborted` when the run's stop killed it (C-62)
|
|
438
|
-
| Upstream task fails | Under the default `--continue=deps-ok`, dependents marked `skipped` (exit 1, durationMs 0); no command runs — EXCEPT a restore-tier task, whose confirmed cache hit still restores (its key is dep-independent). `--continue=never` stops dispatch; `--continue=always` runs dependents, never saved
|
|
439
|
-
| Sandbox violation (macOS monitor / Linux structural) | Task is `failed`; violations render in the frame; nothing cached
|
|
440
|
-
| Remote-cache error (500, timeout, corrupt artifact) | Degrades to a cache miss; never fails the run
|
|
441
|
-
| No
|
|
442
|
-
| Same-project task referenced in `dependsOn` not declared | `buildTaskGraph` throws with the offending edge
|
|
443
|
-
|
|
|
444
|
-
| Cycle in task graph | `detectCycle` throws with the cycle path
|
|
445
|
-
| Malformed config | `loadProjectConfigs` throws (UserError) with file + field
|
|
446
|
-
| `cache.inputs.runtime` command exits non-zero | UserError naming the command + exit code; that task is `failed`, dependents skip
|
|
423
|
+
| Failure | Behavior |
|
|
424
|
+
| ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
425
|
+
| Exec exits non-zero | Task is `failed`; cache NOT written; output streamed live + the failure frame replays at run end |
|
|
426
|
+
| `exec.timeout` overrun | SIGTERM to the task's group, SIGKILL for whoever is left after the grace; task is `failed` (timed out), exit 143 (137 when the SIGKILL took it, and the line says so), never cached |
|
|
427
|
+
| Child killed by Ctrl-C teardown (SIGINT/SIGTERM/SIGHUP), or by an embedder's `RunOptions.signal` abort — which also completes every never-started task `aborted` | Task is `aborted` — not recorded in history. An attempt that ends while the run is stopping is `aborted` whatever its exit: a trap that exits 0 is not cached, and a failure is not retried (item 962). What it printed still shows in its frame. A child killed by a signal while the run is NOT stopping (a supervisor's SIGTERM, a `kill` from another shell) is `failed (exit 143, 128 + SIGTERM)`: retried, shown, and fail-fast trips (item 1100) |
|
|
428
|
+
| `execute()` throws (internal error) | Task marked `failed`; stderr written `[vx] internal error in <id>` (a `UserError` reports plainly); a plugin executor's throw reports plainly as `plugin '<p>' (executor '<e>') failed in execute: <reason>` (C-63, C-85) |
|
|
429
|
+
| Persistent task exits before ready | Task marked `failed` with `exited before becoming ready (exit N)`; its output already streamed live; `aborted` when the run's stop killed it (C-62) |
|
|
430
|
+
| Upstream task fails | Under the default `--continue=deps-ok`, dependents marked `skipped` (exit 1, durationMs 0); no command runs — EXCEPT a restore-tier task, whose confirmed cache hit still restores (its key is dep-independent). `--continue=never` stops dispatch; `--continue=always` runs dependents, never saved |
|
|
431
|
+
| Sandbox violation (macOS monitor / Linux structural) | Task is `failed`; violations render in the frame; nothing cached |
|
|
432
|
+
| Remote-cache error (500, timeout, corrupt artifact) | Degrades to a cache miss; never fails the run |
|
|
433
|
+
| No .vx/workspace.* in cwd or any parent up to the git top-level | `findWorkspaceRoot` throws (UserError); `vx run` exits 1 |
|
|
434
|
+
| Same-project task referenced in `dependsOn` not declared | `buildTaskGraph` throws with the offending edge |
|
|
435
|
+
| Two projects of one name | `checkProjectNames` throws with both paths |
|
|
436
|
+
| Cycle in task graph | `detectCycle` throws with the cycle path |
|
|
437
|
+
| Malformed config | `loadProjectConfigs` throws (UserError) with file + field |
|
|
438
|
+
| `cache.inputs.runtime` command exits non-zero | UserError naming the command + exit code; that task is `failed`, dependents skip |
|
|
447
439
|
|
|
448
440
|
By default (`--continue=deps-ok`) failures don't kill the scheduler —
|
|
449
441
|
independent tasks already in flight finish, and unrelated tasks not yet
|
|
@@ -566,7 +558,7 @@ The colors / framing modules:
|
|
|
566
558
|
- `orchestrator/logger.ts` — composes them; resolves the output view
|
|
567
559
|
and applies the per-flow visibility policy.
|
|
568
560
|
- `orchestrator/summary.ts` — the closing footer (wordmark rule,
|
|
569
|
-
projects/tasks/cache meters, info
|
|
561
|
+
projects/tasks/cache meters, info and time rows).
|
|
570
562
|
|
|
571
563
|
## Concurrency
|
|
572
564
|
|
|
@@ -574,7 +566,7 @@ The colors / framing modules:
|
|
|
574
566
|
capped by the cgroup CPU quota a container runs under (`cpu.max` on v2,
|
|
575
567
|
`cpu.cfs_quota_us` on v1, an ancestor's quota binding too; a 1.5-core
|
|
576
568
|
quota is two workers, never below one — `util/cgroup.ts`), or
|
|
577
|
-
|
|
569
|
+
`.vx/workspace.ts`'s `run.concurrency` field when set. Inside a container the
|
|
578
570
|
raw count is the HOST's, and eight workers on a two-core quota is
|
|
579
571
|
oversubscription by four; `--concurrency <n>%` is a percentage of the
|
|
580
572
|
same capped count.
|
|
@@ -621,8 +613,8 @@ mid-debug would be hostile.
|
|
|
621
613
|
|
|
622
614
|
`--force` turns only the READ axes off: every task re-executes, but
|
|
623
615
|
fresh artifacts are still written (outputs ARE cleaned so the saved
|
|
624
|
-
snapshot is clean). `--cache=<spec>` gives per-layer control. Full
|
|
625
|
-
semantics: [`cli.md` § Cache control](./cli.md#cache-control---cache---no-cache---force)
|
|
616
|
+
snapshot is clean). `--cache-policy=<spec>` gives per-layer control. Full
|
|
617
|
+
semantics: [`cli.md` § Cache control](./cli.md#cache-control---cache-policy---no-cache---force)
|
|
626
618
|
and [`caching.md` § Cache policy](./caching.md#cache-policy-readwrite-axes).
|
|
627
619
|
|
|
628
620
|
## Planning paths (`--dry`, `--graph`)
|
package/docs/features.md
CHANGED
|
@@ -15,25 +15,25 @@ config key or an environment variable is missing here.
|
|
|
15
15
|
- **Run a task** (`vx run`) — run a task in the cwd's project, `pkg#task` directly, or several at once. [page](https://vznjs.github.io/vx/features/quickstart/) · post: [The basics, done carefully](https://vznjs.github.io/vx/blog/the-basics/)
|
|
16
16
|
- **Every project** (`--all`) — run the task in every project that declares it. [page](https://vznjs.github.io/vx/features/quickstart/) · post: [The basics, done carefully](https://vznjs.github.io/vx/blog/the-basics/)
|
|
17
17
|
- **pnpm-style filters** (`--filter`) — select projects by name, glob, path, dependencies (`foo...`), dependents (`...foo`), negation or a git range. [page](https://vznjs.github.io/vx/features/affected/) · post: [Say exactly which tasks to run](https://vznjs.github.io/vx/blog/pick-your-tasks/)
|
|
18
|
-
- **Affected only** (`--affected`, `affectedBase`) — run what a change reaches, following task edges from a git base. [page](https://vznjs.github.io/vx/features/affected/) · post: [Run only what a change reaches](https://vznjs.github.io/vx/blog/affected/)
|
|
19
|
-
- **Concurrency** (`--concurrency`, `concurrency`) — a count or a share of the CPUs this process may use (`50%`). [page](https://vznjs.github.io/vx/features/concurrency/) · post: [One failure, and exactly what it takes down](https://vznjs.github.io/vx/blog/when-a-build-fails/)
|
|
18
|
+
- **Affected only** (`--affected`, `run.affectedBase`, `VX_RUN_AFFECTED_BASE`) — run what a change reaches, following task edges from a git base. [page](https://vznjs.github.io/vx/features/affected/) · post: [Run only what a change reaches](https://vznjs.github.io/vx/blog/affected/)
|
|
19
|
+
- **Concurrency** (`--concurrency`, `run.concurrency`, `VX_RUN_CONCURRENCY`) — a count or a share of the CPUs this process may use (`50%`). [page](https://vznjs.github.io/vx/features/concurrency/) · post: [One failure, and exactly what it takes down](https://vznjs.github.io/vx/blog/when-a-build-fails/)
|
|
20
20
|
- **Skip dependencies** (`--exclude-dependencies`) — skip all `dependsOn` edges, or named ones. [page](https://vznjs.github.io/vx/features/skip-dependencies/) · post: [Say exactly which tasks to run](https://vznjs.github.io/vx/blog/pick-your-tasks/)
|
|
21
|
-
- **Failure policy** (`--continue`) — never, deps-ok (default: dependents skip) or always. [page](https://vznjs.github.io/vx/features/skipped-blockers/) · post: [One failure, and exactly what it takes down](https://vznjs.github.io/vx/blog/when-a-build-fails/)
|
|
21
|
+
- **Failure policy** (`--continue`, `run.continue`, `VX_RUN_CONTINUE`) — never, deps-ok (default: dependents skip) or always. [page](https://vznjs.github.io/vx/features/skipped-blockers/) · post: [One failure, and exactly what it takes down](https://vznjs.github.io/vx/blog/when-a-build-fails/)
|
|
22
22
|
- **Every skip names its blocker** — a skipped task says which failure blocked it. [page](https://vznjs.github.io/vx/features/skipped-blockers/) · post: [One failure, and exactly what it takes down](https://vznjs.github.io/vx/blog/when-a-build-fails/)
|
|
23
|
-
- **Retries** (`--
|
|
24
|
-
- **Timeouts** (`--timeout`, `exec.timeout`, `timeout`, `
|
|
23
|
+
- **Retries** (`--retries`, `exec.retries`, `run.retries`, `VX_RUN_RETRIES`) — re-run a failed task; a pass after a failure marks it flaky. [page](https://vznjs.github.io/vx/features/flaky-detection/) · post: [Flaky is a claim only declared inputs can back](https://vznjs.github.io/vx/blog/flaky-tasks/)
|
|
24
|
+
- **Timeouts** (`--timeout`, `exec.timeout`, `run.timeout`, `VX_RUN_TIMEOUT`) — kill and fail a runaway task. [page](https://vznjs.github.io/vx/features/timeouts/) · post: [When a task misbehaves](https://vznjs.github.io/vx/blog/tasks-that-misbehave/)
|
|
25
25
|
- **Argument forwarding** (`--`) — args after `--` reach the task's command and fold into its key. [page](https://vznjs.github.io/vx/features/forward-args/) · post: [When a task misbehaves](https://vznjs.github.io/vx/blog/tasks-that-misbehave/)
|
|
26
26
|
- **Task picker** — `vx run` with no task in a terminal lists tasks to pick. [page](https://vznjs.github.io/vx/features/task-picker/) · post: [The small things](https://vznjs.github.io/vx/blog/the-small-things/)
|
|
27
27
|
- **Typo hints** — an unknown task, project or filter suggests the nearest name. [page](https://vznjs.github.io/vx/features/filter-hints/) · post: [The small things](https://vznjs.github.io/vx/blog/the-small-things/)
|
|
28
28
|
- **Turbo and Nx spellings** (`-t`, `-p`, `--exclude`, `--parallel`, `--base`, `--dry-run`, `--skip-nx-cache`) — accepted, or refused naming the vx spelling. [page](https://vznjs.github.io/vx/features/turbo-nx-flags/) · post: [Flags you already know](https://vznjs.github.io/vx/blog/flags-you-already-know/)
|
|
29
|
-
- **Ctrl-C leaves nothing running** (`
|
|
29
|
+
- **Ctrl-C leaves nothing running** (`--kill-grace`, `--teardown-timeout`, `run.killGrace`, `run.teardownTimeout`, `VX_RUN_KILL_GRACE`, `VX_RUN_TEARDOWN_TIMEOUT`) — the whole process tree stops, then teardown runs. [page](https://vznjs.github.io/vx/features/ctrl-c/) · post: [Ctrl-C leaves nothing running](https://vznjs.github.io/vx/blog/ctrl-c/)
|
|
30
30
|
- **Longest chain first** — the scheduler starts the critical path first; `@vzn/vx-schedule-history` learns it from past runs. [page](https://vznjs.github.io/vx/features/critical-path/) · post: [Bitsets, popcount, and a scheduler tick](https://vznjs.github.io/vx/blog/bitsets-and-the-scheduler/)
|
|
31
|
-
- **Schedule strategy** (`schedule`) — pick the order with no timings: most work waiting (default), longest chain, most direct dependents, or ready order; plugins still lead. [page](https://vznjs.github.io/vx/features/critical-path/) · post: [
|
|
31
|
+
- **Schedule strategy** (`--schedule`, `run.schedule`, `VX_RUN_SCHEDULE`) — pick the order with no timings: most work waiting (default), longest chain, most direct dependents, or ready order; plugins still lead. [page](https://vznjs.github.io/vx/features/critical-path/) · post: [Which task runs first?](https://vznjs.github.io/vx/blog/scheduling-strategies/#pick-the-guess)
|
|
32
32
|
- **No daemon** — every run starts cold and still answers in milliseconds. [page](https://vznjs.github.io/vx/features/no-daemon/) · post: [No daemon, on purpose](https://vznjs.github.io/vx/blog/no-daemon/)
|
|
33
33
|
- **Group tasks** (`dependsOn` with no `exec`) — a task that only runs its dependencies; `dependsOn: []` is a named no-op. [page](https://vznjs.github.io/vx/features/group-tasks/) · post: [Say exactly which tasks to run](https://vznjs.github.io/vx/blog/pick-your-tasks/)
|
|
34
34
|
- **Keyed groups** (`cache` with no `exec`) — a key a dependant folds: it re-runs on those inputs, and nothing spawns or counts for the group. [page](https://vznjs.github.io/vx/features/group-tasks/) · post: [A key with nothing to run](https://vznjs.github.io/vx/blog/keyed-groups/)
|
|
35
35
|
- **Implicit keyed `build`** — a project with no `build` gets a `^build` group keyed on its files, so source-only packages still move their dependants' keys. [page](https://vznjs.github.io/vx/features/implicit-build/) · post: [The basics, done carefully](https://vznjs.github.io/vx/blog/the-basics/)
|
|
36
|
-
- **dependsOn syntax** (`^name`, `pkg#name`, `name.*`, `^name.*`) — upstream, cross-project and pattern edges. [page](https://vznjs.github.io/vx/features/depends-on-syntax/) · post: [Say exactly which tasks to run](https://vznjs.github.io/vx/blog/pick-your-tasks/)
|
|
36
|
+
- **dependsOn syntax** (`^name`, `pkg#name`, `name.*`, `^name.*`) — upstream, cross-project and pattern edges; `^` follows the project edges a plugin supplies, and with none is refused naming the fix. [page](https://vznjs.github.io/vx/features/depends-on-syntax/) · post: [Say exactly which tasks to run](https://vznjs.github.io/vx/blog/pick-your-tasks/)
|
|
37
37
|
- **Every name must resolve** — `vx run lint test typecheck` refuses to start if one name matches no project. [page](https://vznjs.github.io/vx/features/names-must-resolve/) · post: [Say exactly which tasks to run](https://vznjs.github.io/vx/blog/pick-your-tasks/)
|
|
38
38
|
- **Tag filters** (`--filter tag:<pattern>`) — select projects by their config `tags`. [page](https://vznjs.github.io/vx/features/tag-filters/) · post: [Say exactly which tasks to run](https://vznjs.github.io/vx/blog/pick-your-tasks/)
|
|
39
39
|
- **Directory and root filters** (`./<dir>`, `{<dir>}`, `.`, `//`) — select projects by path, or the root project. [page](https://vznjs.github.io/vx/features/dir-filters/) · post: [Say exactly which tasks to run](https://vznjs.github.io/vx/blog/pick-your-tasks/)
|
|
@@ -43,15 +43,16 @@ config key or an environment variable is missing here.
|
|
|
43
43
|
## Output
|
|
44
44
|
|
|
45
45
|
- **Framed output** — each task's log in its own frame, never interleaved. [page](https://vznjs.github.io/vx/features/framed-output/) · post: [A run you can read](https://vznjs.github.io/vx/blog/a-run-you-can-read/)
|
|
46
|
-
- **Output modes** (`--output-logs`) — full, errors-only, hash-only or none; the default follows the flow. [page](https://vznjs.github.io/vx/features/output-modes/) · post: [Output that fits the run](https://vznjs.github.io/vx/blog/output-that-fits-the-run/)
|
|
46
|
+
- **Output modes** (`--output-logs`, `VX_RUN_OUTPUT_LOGS`) — full, errors-only, hash-only or none; the default follows the flow. [page](https://vznjs.github.io/vx/features/output-modes/) · post: [Output that fits the run](https://vznjs.github.io/vx/blog/output-that-fits-the-run/)
|
|
47
47
|
- **Run summary** — one block: projects, tasks, cache, time; nothing prints below it. [page](https://vznjs.github.io/vx/features/run-summary/) · post: [A run you can read](https://vznjs.github.io/vx/blog/a-run-you-can-read/)
|
|
48
48
|
- **Per-task table** (`--verbosity`) — a per-task summary after the run. [page](https://vznjs.github.io/vx/features/per-task-table/) · post: [One failure, and exactly what it takes down](https://vznjs.github.io/vx/blog/when-a-build-fails/)
|
|
49
49
|
- **Failed output kept for agents** — a failure's full log is saved and pointed to. [page](https://vznjs.github.io/vx/features/failed-output-kept/) · post: [Built for the agent at the keyboard](https://vznjs.github.io/vx/blog/built-for-agents/)
|
|
50
50
|
- **Markdown report** (`--report`, `--report-file`) — a run report for a PR or `$GITHUB_STEP_SUMMARY`. [page](https://vznjs.github.io/vx/features/markdown-report/) · post: [Output that fits the run](https://vznjs.github.io/vx/blog/output-that-fits-the-run/)
|
|
51
51
|
- **Run JSON** (`--summarize`) — per-run JSON for scripts, with the time the cache saved (`savedMs`). [page](https://vznjs.github.io/vx/features/run-json/) · post: [See inside a run](https://vznjs.github.io/vx/blog/see-inside-a-run/)
|
|
52
52
|
- **Trace profile** (`--profile`) — Chrome-trace JSON of the run. [page](https://vznjs.github.io/vx/features/profile/) · post: [Output that fits the run](https://vznjs.github.io/vx/blog/output-that-fits-the-run/)
|
|
53
|
+
- **Run branch** (`--branch`, `VX_RUN_BRANCH`) — name the branch a run records in its history and forecasts from; unset, git's branch, then the CI provider's. no post
|
|
53
54
|
- **Run tags** (`--tag`) — label a run; recorded in history. [page](https://vznjs.github.io/vx/features/run-tags/) · post: [See inside a run](https://vznjs.github.io/vx/blog/see-inside-a-run/)
|
|
54
|
-
- **Stage timing** (`
|
|
55
|
+
- **Stage timing** (`VX_DEBUG_TIMING`) — vx's own stage table, for performance work. [page](https://vznjs.github.io/vx/features/stage-timing/) · post: [See inside a run](https://vznjs.github.io/vx/blog/see-inside-a-run/)
|
|
55
56
|
- **Output flows** — what is printed follows the run's intent (focused, broad or CI); a truthy `CI` wins. [page](https://vznjs.github.io/vx/features/output-flows/) · post: [Output that fits the run](https://vznjs.github.io/vx/blog/output-that-fits-the-run/)
|
|
56
57
|
- **Cache-aware glyphs** — each task line's glyph shows ran, fresh, restored locally or remotely, failed, skipped or persistent. [page](https://vznjs.github.io/vx/features/cache-glyphs/) · post: [Output that fits the run](https://vznjs.github.io/vx/blog/output-that-fits-the-run/)
|
|
57
58
|
- **GitHub Actions log groups** — on Actions, each task's block folds in a `::group::` with its outcome and time. [page](https://vznjs.github.io/vx/features/actions-log-groups/) · post: [The basics, done carefully](https://vznjs.github.io/vx/blog/the-basics/)
|
|
@@ -63,10 +64,10 @@ config key or an environment variable is missing here.
|
|
|
63
64
|
|
|
64
65
|
- **Dry run** (`--dry`) — the task graph and the predicted hits and misses, text or JSON (with the predicted wall time and its critical path), nothing runs. [page](https://vznjs.github.io/vx/features/dry-run/) · post: [See the plan before you run it](https://vznjs.github.io/vx/blog/dry-run/)
|
|
65
66
|
- **Graph** (`--graph`) — the task graph as Graphviz DOT. [page](https://vznjs.github.io/vx/features/task-graph/) · post: [See inside a run](https://vznjs.github.io/vx/blog/see-inside-a-run/)
|
|
66
|
-
- **vx why** (`vx why`, `--run`) — why a task re-ran, down to the file, env var or config that changed. [page](https://vznjs.github.io/vx/features/vx-why/) · post: [Why did this re-run?](https://vznjs.github.io/vx/blog/why-did-this-rerun/)
|
|
67
|
-
- **vx show** (`vx show`) — every project, a project's or a task's
|
|
68
|
-
- **vx last** (`vx last`, `--list`, `--failed`, `--log`) — replay a recorded run's summary, list recent runs,
|
|
69
|
-
- **vx info** (`vx info`) — workspace doctor: versions, projects, cache size against `
|
|
67
|
+
- **vx why** (`vx why`, `--run`) — why a task re-ran, down to the file, env var or config that changed, and the task that wrote a moved input. [page](https://vznjs.github.io/vx/features/vx-why/) · post: [Why did this re-run?](https://vznjs.github.io/vx/blog/why-did-this-rerun/)
|
|
68
|
+
- **vx show** (`vx show`) — every project, a project's or a task's resolved config, read from the lock as a run reads it. [page](https://vznjs.github.io/vx/features/vx-show/) · post: [See what a task really is](https://vznjs.github.io/vx/blog/vx-show/)
|
|
69
|
+
- **vx last** (`vx last`, `--list`, `--failed`, `--log`, `--stats`, `--branch`) — replay a recorded run's summary, list recent runs, print one task's output, or per-task history stats (p50 as the live estimate forecasts it on a branch, p99, pass and hit rate, failure mode, peak RSS). [page](https://vznjs.github.io/vx/features/vx-last/) · post: [The last run, on request](https://vznjs.github.io/vx/blog/vx-last/)
|
|
70
|
+
- **vx info** (`vx info`) — workspace doctor: versions, projects, cache size against `cache.retention.maxSize`, every setting and where it came from. [page](https://vznjs.github.io/vx/features/vx-info/) · post: [One command to know your workspace](https://vznjs.github.io/vx/blog/know-your-workspace/)
|
|
70
71
|
- **JSON everywhere** (`--format`) — `show`, `info`, `why`, `last` and `cache` print JSON for agents. [page](https://vznjs.github.io/vx/features/json-everywhere/) · post: [Built for the agent at the keyboard](https://vznjs.github.io/vx/blog/built-for-agents/)
|
|
71
72
|
- **Run analytics in SQLite** — every task's time, CPU, peak memory and cache result, queryable with `sqlite3`. [page](https://vznjs.github.io/vx/features/run-analytics/) · post: [Built for the agent at the keyboard](https://vznjs.github.io/vx/blog/built-for-agents/)
|
|
72
73
|
- **Stable error codes** (`VX_E_…`) — under `--format json` a refusal is a JSON line on stdout with a code an agent branches on and a `docs` link to its fix (`vx docs <code>` offline). [page](https://vznjs.github.io/vx/features/error-codes/) · post: [A refusal an agent can read](https://vznjs.github.io/vx/blog/error-codes/)
|
|
@@ -74,30 +75,31 @@ config key or an environment variable is missing here.
|
|
|
74
75
|
- **Docs for agents** (`llms.txt`, `llms-full.txt`) — the whole site as markdown for coding agents. [page](https://vznjs.github.io/vx/features/llms-txt/) · post: [Built for the agent at the keyboard](https://vznjs.github.io/vx/blog/built-for-agents/)
|
|
75
76
|
- **vx docs** (`vx docs`, `--limit`) — search the CLI, config and cache reference offline; it ships inside vx. [page](https://vznjs.github.io/vx/features/vx-docs/) · post: [The reference, offline](https://vznjs.github.io/vx/blog/vx-docs-offline/)
|
|
76
77
|
- **Affected reasons** (`--affected --dry`) — each kept task says the changed file or the dependency chain that reached it, text or JSON. [page](https://vznjs.github.io/vx/features/affected-reasons/) · post: [See inside a run](https://vznjs.github.io/vx/blog/see-inside-a-run/)
|
|
77
|
-
- **Agent skill** (`skills/vx/SKILL.md`) — an installable skill that teaches a coding agent to run, debug and query vx. [page](https://vznjs.github.io/vx/features/agent-skill/) · post: [Built for the agent at the keyboard](https://vznjs.github.io/vx/blog/built-for-agents/)
|
|
78
|
+
- **Agent skill** (`skills/vx/SKILL.md`, `npx skills add vznjs/vx/packages/vx/skills/vx`) — an installable skill that teaches a coding agent to run, debug and query vx through the CLI's `--format json`; copy it from `node_modules/@vzn/vx/skills/vx/` to match the installed version. [page](https://vznjs.github.io/vx/features/agent-skill/) · post: [Built for the agent at the keyboard](https://vznjs.github.io/vx/blog/built-for-agents/)
|
|
78
79
|
|
|
79
80
|
## Cache
|
|
80
81
|
|
|
81
82
|
- **Opt-in, explicit inputs** (`cache.inputs.files`) — a task caches only when it names its inputs. [page](https://vznjs.github.io/vx/features/explicit-inputs/) · post: [Explicit over magical](https://vznjs.github.io/vx/blog/explicit-over-magical/)
|
|
82
83
|
- **Inputs** (`cache.inputs.env`, `cache.inputs.runtime`, `cache.inputs.tasks`, `cache.inputs.workspaceFiles`, `cache.inputs.workspaceRuntime`) — env vars, tool versions, upstream tasks and workspace files in the key. [page](https://vznjs.github.io/vx/features/key-inputs/) · post: [What goes into a key, and what comes back](https://vznjs.github.io/vx/blog/inside-a-cache-hit/)
|
|
83
84
|
- **Outputs** (`cache.outputs.files`, `cache.outputs.workspaceFiles`) — what a hit restores. [page](https://vznjs.github.io/vx/features/cache-outputs/) · post: [What goes into a key, and what comes back](https://vznjs.github.io/vx/blog/inside-a-cache-hit/)
|
|
84
|
-
- **Input stability** (`cache.inputStability`, workspace `inputStability`, `
|
|
85
|
-
- **
|
|
85
|
+
- **Input stability** (`cache.inputStability`, workspace `cache.inputStability`, `VX_CACHE_INPUT_STABILITY_STRATEGY`, `VX_CACHE_INPUT_STABILITY_SEVERITY`) — an input written while the command runs withholds the save, on CI too, and the saves of every task that ran over its outputs; `strategy: 'mutable'` accepts a task's identical rewrite of its own input, `'unchecked'` skips the check; `severity: 'error'` fails the run instead of warning. no post
|
|
86
|
+
- **Keep outputs on a miss** (`cache.outputs.clean`, workspace `cache.outputs.clean`, `VX_CACHE_OUTPUTS_CLEAN`) — `false` leaves a task's outputs in place for a tool that reads its last output (tsc's `.tsbuildinfo`); if the run leaves any old file unchanged, nothing is cached. no post
|
|
87
|
+
- **Outputs are exactly the snapshot** (`run.rules.exclusiveOutputs`, `VX_RUN_RULES_EXCLUSIVE_OUTPUTS`) — a hit leaves the tree as the run did; two tasks may not own one output without an edge. [page](https://vznjs.github.io/vx/features/strict-outputs/) · post: [The tree is exactly the snapshot](https://vznjs.github.io/vx/blog/strict-output-ownership/)
|
|
86
88
|
- **Keys from git's index** — tracked clean files hash by their blob id, no read. [page](https://vznjs.github.io/vx/features/keys-from-git/) · post: [Your cache key is already in git's index](https://vznjs.github.io/vx/blog/keys-from-git/)
|
|
87
89
|
- **Config keyed as evaluated** — the key sees the resolved config object. [page](https://vznjs.github.io/vx/features/typescript-config/) · post: [Configs are programs](https://vznjs.github.io/vx/blog/resolved-config-hashing/)
|
|
88
90
|
- **Cascade through inputs** — a task's key folds its upstream input keys, never outputs. [page](https://vznjs.github.io/vx/features/cascade/) · post: [Cascade through dependencies](https://vznjs.github.io/vx/blog/cascade-through-inputs/)
|
|
89
|
-
- **Lockfile-aware keys** (`@vzn/vx-lockfile`: `pnpm()`, `bun()`, `npm()`, `yarn()`) — a bump re-keys only the projects whose closure changed. [page](https://vznjs.github.io/vx/features/lockfile-keys/) · post: [A lockfile bump should re-key two tasks](https://vznjs.github.io/vx/blog/lockfile-aware-keys/)
|
|
90
|
-
- **Upfront keys** (`upfrontKeys`) — refuses an input glob a same-project task's outputs could match, so every key is known before anything runs. [page](https://vznjs.github.io/vx/features/upfront-keys/) · post: [Cascade through dependencies by folding input keys, never outputs](https://vznjs.github.io/vx/blog/cascade-through-inputs/)
|
|
91
|
-
- **
|
|
92
|
-
- **Cache
|
|
93
|
-
- **Cache
|
|
94
|
-
- **Cache
|
|
95
|
-
- **
|
|
91
|
+
- **Lockfile-aware keys** (`@vzn/vx-lockfile`: `pnpm()`, `bun()`, `npm()`, `yarn()`) — a bump re-keys only the projects whose closure changed; each also adds every member with a `package.json` as a project named by its `name`, gives vx the project edges the lockfile records (core reads no `package.json`), keys each package's `package.json` as an input and folds its manager's install settings (`.npmrc`, `bunfig.toml`, `pnpm-workspace.yaml`, `.yarnrc.yml`) into every task. Core keys no package file, so without one an install re-keys nothing; `npm()` reads `npm-shrinkwrap.json` first, and `bun()` refuses a lone `bun.lockb`. [page](https://vznjs.github.io/vx/features/lockfile-keys/) · post: [A lockfile bump should re-key two tasks](https://vznjs.github.io/vx/blog/lockfile-aware-keys/)
|
|
92
|
+
- **Upfront keys** (`run.rules.upfrontKeys`, `VX_RUN_RULES_UPFRONT_KEYS`) — refuses an input glob a same-project task's outputs could match, so every key is known before anything runs. [page](https://vznjs.github.io/vx/features/upfront-keys/) · post: [Cascade through dependencies by folding input keys, never outputs](https://vznjs.github.io/vx/blog/cascade-through-inputs/)
|
|
93
|
+
- **Dependency rules** (`run.rules.dependencies`) — `vx lock` refuses a project depending on one a tag or name rule denies or does not allow, every broken edge named (`VX_E_DEPENDENCY_RULE`). [schema](https://vznjs.github.io/vx/schema/) · post: [Say which projects may depend on which](https://vznjs.github.io/vx/blog/dependency-rules/)
|
|
94
|
+
- **Cache controls** (`--no-cache`, `--force`, `--cache-policy`, `--cache-policy`, `VX_CACHE_POLICY`, `cache.policy`) — off, refresh, or per-layer read/write. [page](https://vznjs.github.io/vx/features/cache-controls/) · post: [The cache on your terms](https://vznjs.github.io/vx/blog/the-cache-on-your-terms/)
|
|
95
|
+
- **Cache location** (`--cache-dir`, `cache.dir`, `VX_CACHE_DIR`) — where the cache lives. [page](https://vznjs.github.io/vx/features/cache-location/) · post: [The cache on your terms](https://vznjs.github.io/vx/blog/the-cache-on-your-terms/)
|
|
96
|
+
- **Cache scope** (`cache.scope`, `VX_CACHE_SCOPE`, `--cache-scope`) — a scope reads the default entries, then its own, and writes only its own. [page](https://vznjs.github.io/vx/features/cache-scope/) · post: [The cache on your terms](https://vznjs.github.io/vx/blog/the-cache-on-your-terms/)
|
|
97
|
+
- **Cache pruning** (`vx cache clean`, `--older-than`, `--max-size`, `--global`, `--dry-run`, `cache.retention`, `maxSize`, `olderThan`, `VX_CACHE_RETENTION_MAX_SIZE`, `VX_CACHE_RETENTION_OLDER_THAN`) — evict by age or size, LRU; with no bound, clear this repo's store (shared by its checkouts) and run history; `--global` clears every repo's store. [page](https://vznjs.github.io/vx/features/cache-prune/) · post: [One command to know your workspace](https://vznjs.github.io/vx/blog/know-your-workspace/)
|
|
98
|
+
- **Remote outputs** (`--cache-download`, `cache.download`, `VX_CACHE_DOWNLOAD`) — all, top-level only, or none. [page](https://vznjs.github.io/vx/features/remote-downloads/) · post: [A remote server you can trust in production](https://vznjs.github.io/vx/blog/reapi-in-production/)
|
|
96
99
|
- **One store for every checkout** (`~/.vx/<id>/cache`) — clones and worktrees of a repo share cache entries. [page](https://vznjs.github.io/vx/features/shared-store/) · post: [The cache on your terms](https://vznjs.github.io/vx/blog/the-cache-on-your-terms/)
|
|
97
100
|
- **Warm hits restore nothing** — when outputs on disk already match, a hit costs a few stats. [page](https://vznjs.github.io/vx/features/warm-hits/) · post: [What goes into a key, and what comes back](https://vznjs.github.io/vx/blog/inside-a-cache-hit/)
|
|
98
101
|
- **Hits replay both streams** — stdout and stderr come back in the order the run printed them. [page](https://vznjs.github.io/vx/features/both-streams/) · post: [What goes into a key, and what comes back](https://vznjs.github.io/vx/blog/inside-a-cache-hit/)
|
|
99
102
|
- **Restore lane** — cache restores run on their own lane, up to twice `--concurrency`. [page](https://vznjs.github.io/vx/features/restore-lane/) · post: [What goes into a key, and what comes back](https://vznjs.github.io/vx/blog/inside-a-cache-hit/)
|
|
100
|
-
- **Config evaluation cache** — provably pure `vx.config.ts` files are read back as data, not evaluated again. [page](https://vznjs.github.io/vx/features/config-cache/) · post: [Guard rails that tell you the fix](https://vznjs.github.io/vx/blog/guard-rails/)
|
|
101
103
|
- **Line-ending-correct keys** — files git filters (`eol`, `core.autocrlf`) key on the bytes the build sees. [page](https://vznjs.github.io/vx/features/line-endings/) · post: [Your cache key is already in git's index](https://vznjs.github.io/vx/blog/keys-from-git/)
|
|
102
104
|
- **Background remote uploads** — remote writes drain at the end of the run and never fail the build. [page](https://vznjs.github.io/vx/features/background-uploads/) · post: [What goes into a key, and what comes back](https://vznjs.github.io/vx/blog/inside-a-cache-hit/)
|
|
103
105
|
- **Bring your own remote cache** (plugin `cache`) — plug any cache server in through one interface. [page](https://vznjs.github.io/vx/features/custom-remote-cache/) · post: [Extend vx in an afternoon](https://vznjs.github.io/vx/blog/extend-vx/)
|
|
@@ -105,32 +107,33 @@ config key or an environment variable is missing here.
|
|
|
105
107
|
## Correctness
|
|
106
108
|
|
|
107
109
|
- **Sandboxed tasks** (`exec.sandbox`: `allow`, `deny`, `ignore`, `weakerNetworkIsolation`, `weakerWhenNested`) — a task reads and writes only what it declares; `allow` names `read`, `write`, `network`, `unixSockets`, `localBinding`, `pty`, `systemInfo`, `gitConfig`, `machLookup`. [page](https://vznjs.github.io/vx/features/sandbox/) · post: [The sandbox](https://vznjs.github.io/vx/blog/the-sandbox/)
|
|
108
|
-
- **Env isolation** (`exec.env`: `define`, `passThrough`, `secret`) — a task sees only the env it names; secrets are masked. [page](https://vznjs.github.io/vx/features/env-isolation/) · post: [A task sees only the env it names](https://vznjs.github.io/vx/blog/env-isolation/)
|
|
109
|
-
- **vx lock** (`vx lock`, `--check`, `--format json`,
|
|
110
|
+
- **Env isolation** (`exec.env`: `define`, `passThrough`, `secret`, `VX_DEBUG_DUMPABLE`) — a task sees only the env it names; secrets are masked; vx hides its own env from tasks (Linux and macOS). [page](https://vznjs.github.io/vx/features/env-isolation/) · post: [A task sees only the env it names](https://vznjs.github.io/vx/blog/env-isolation/)
|
|
111
|
+
- **vx lock** (`vx lock`, `--check`, `--format json`, `lock.reviewFiles`, `VX_LOCK_REVIEW_FILES`) — find the projects (every directory holding a `vx.config`), freeze what their configs evaluate to and check the graph rules once; only `vx lock` evaluates configs: runs, `vx show` and `vx info` read the lock and never write it; a pretty `vx.lock.json` beside each config shows reviewers what it resolves to. [page](https://vznjs.github.io/vx/features/vx-lock/) · post: [vx lock: freezing what the key sees](https://vznjs.github.io/vx/blog/lock-and-frozen/)
|
|
110
112
|
- **Flaky detection** — a task that fails then passes is reported flaky. [page](https://vznjs.github.io/vx/features/flaky-detection/) · post: [Flaky is a claim](https://vznjs.github.io/vx/blog/flaky-tasks/)
|
|
111
113
|
- **Project boundaries** — globs never cross into another project. [page](https://vznjs.github.io/vx/features/project-boundaries/) · post: [What goes into a key, and what comes back](https://vznjs.github.io/vx/blog/inside-a-cache-hit/)
|
|
112
114
|
- **Artifact integrity checks** — a CRC-32, a key match and an outputs-only check on every artifact; damage is a miss. [page](https://vznjs.github.io/vx/features/artifact-integrity/) · post: [What goes into a key, and what comes back](https://vznjs.github.io/vx/blog/inside-a-cache-hit/)
|
|
113
115
|
- **Sandbox names what to grant** — a refused write is named beside the failed task with the path to allow. [page](https://vznjs.github.io/vx/features/sandbox-grants/) · post: [Guard rails that tell you the fix](https://vznjs.github.io/vx/blog/guard-rails/)
|
|
114
116
|
- **Strict numeric flags** — `0x10`, `1e3` and `2.7` are refused, never reinterpreted. [page](https://vznjs.github.io/vx/features/strict-numbers/) · post: [An upgrade you can trust](https://vznjs.github.io/vx/blog/upgrade-you-can-trust/)
|
|
115
|
-
- **Verified releases** — binaries carry provenance, `vx upgrade` checks SHA-
|
|
117
|
+
- **Verified releases** — binaries carry provenance, `vx upgrade` checks npm's registry signature and the SHA-512, npm publishes with provenance. [page](https://vznjs.github.io/vx/features/verified-releases/) · post: [An upgrade you can trust](https://vznjs.github.io/vx/blog/upgrade-you-can-trust/)
|
|
116
118
|
|
|
117
119
|
## Daily work
|
|
118
120
|
|
|
119
|
-
- **Watch mode** (`vx watch`, `VX_WATCH_POLL`) — re-run what a change affects, on content, not events. [page](https://vznjs.github.io/vx/features/watch/) · post: [Watch: a content gate](https://vznjs.github.io/vx/blog/watch-mode/)
|
|
120
|
-
- **Dev servers in the graph** (`exec.persistent`, `readyWhen`, `
|
|
121
|
+
- **Watch mode** (`vx watch`, `--poll`, `watch.poll`, `VX_WATCH_POLL`) — re-run what a change affects, on content, not events. [page](https://vznjs.github.io/vx/features/watch/) · post: [Watch: a content gate](https://vznjs.github.io/vx/blog/watch-mode/)
|
|
122
|
+
- **Dev servers in the graph** (`exec.persistent`, `readyWhen`, `--ready-notice`, `run.readyNotice`, `VX_RUN_READY_NOTICE`) — a server is a node; dependents start when it is ready. [page](https://vznjs.github.io/vx/features/dev-servers/) · post: [Dev servers as graph nodes](https://vznjs.github.io/vx/blog/dev-servers-in-the-graph/)
|
|
121
123
|
- **Interactive tasks** (`exec.interactive`) — a task that owns the terminal. [page](https://vznjs.github.io/vx/features/interactive-tasks/) · post: [When a task misbehaves](https://vznjs.github.io/vx/blog/tasks-that-misbehave/)
|
|
122
124
|
- **Shell completions** (`vx completions`) — bash, zsh, fish. [page](https://vznjs.github.io/vx/features/completions/) · post: [The small things](https://vznjs.github.io/vx/blog/the-small-things/)
|
|
123
|
-
- **vx
|
|
125
|
+
- **Project-local vx** (`VX_HANDED_OFF`) — a global vx hands every call to the project's own `@vzn/vx`. [page](https://vznjs.github.io/vx/cli/#which-vx-runs)
|
|
126
|
+
- **vx upgrade** (`vx upgrade`) — upgrade vx the way it was installed: a verified binary, or its package manager. [page](https://vznjs.github.io/vx/features/upgrade/) · post: [An upgrade you can trust](https://vznjs.github.io/vx/blog/upgrade-you-can-trust/)
|
|
124
127
|
- **Help and version** (`vx help`, `vx version`) — every verb's reference. [page](https://vznjs.github.io/vx/features/help-and-version/) · post: [An upgrade you can trust](https://vznjs.github.io/vx/blog/upgrade-you-can-trust/)
|
|
125
128
|
- **Did-you-mean** — a mistyped flag or verb gets the nearest valid spelling. [page](https://vznjs.github.io/vx/features/did-you-mean/) · post: [The small things](https://vznjs.github.io/vx/blog/the-small-things/)
|
|
126
129
|
- **Task typed as a verb** — `vx build app` answers with the exact `vx run` command that does it. [page](https://vznjs.github.io/vx/features/task-as-verb/) · post: [The small things](https://vznjs.github.io/vx/blog/the-small-things/)
|
|
127
130
|
|
|
128
131
|
## Config
|
|
129
132
|
|
|
130
|
-
- **Config in TypeScript** (`vx.config.ts`, `defineProject`,
|
|
133
|
+
- **Config in TypeScript** (`vx.config.ts`, `defineProject`, `.vx/workspace.ts`, `defineWorkspace`) — typed, composable; no named inputs. `.vx/workspace.ts` is required: the nearest one up from the cwd, never above the git top-level, marks the workspace root. [page](https://vznjs.github.io/vx/features/typescript-config/) · post: [Config in TypeScript](https://vznjs.github.io/vx/blog/config-in-typescript/)
|
|
131
134
|
- **Tasks** (`tasks`, `exec.command`, `dependsOn`, `description`, `tags`) — one command per task; the shell is the API. [page](https://vznjs.github.io/vx/features/one-command-tasks/) · post: [One command per task](https://vznjs.github.io/vx/blog/one-command-per-task/)
|
|
132
135
|
- **Workspace rules** (`rules`) — speed-only checks, on by default, configurable. [page](https://vznjs.github.io/vx/features/workspace-rules/) · post: [Guard rails that tell you the fix](https://vznjs.github.io/vx/blog/guard-rails/)
|
|
133
|
-
- **Config worker timeout** (`
|
|
136
|
+
- **Config worker timeout** (`VX_CONFIG_WORKER_TIMEOUT`) — bound a config's evaluation. [page](https://vznjs.github.io/vx/features/config-timeout/) · post: [Guard rails that tell you the fix](https://vznjs.github.io/vx/blog/guard-rails/)
|
|
134
137
|
- **No nested runs** (`VX_RUN_TASK`, `VX_RUN_WORKSPACE`) — set on every task; a `vx run` inside a task of the same workspace is refused. [page](https://vznjs.github.io/vx/features/no-nested-runs/) · post: [When a task misbehaves](https://vznjs.github.io/vx/blog/tasks-that-misbehave/)
|
|
135
138
|
- **Typed config helpers** (`defineProject`) — autocomplete for task names in `dependsOn`, errors while you edit. [page](https://vznjs.github.io/vx/features/typed-helpers/) · post: [Config in TypeScript, and why there are no named inputs](https://vznjs.github.io/vx/blog/config-in-typescript/)
|
|
136
139
|
- **Presets** — a TypeScript function returning a task config, shared across projects. [page](https://vznjs.github.io/vx/features/presets/) · post: [Config in TypeScript, and why there are no named inputs](https://vznjs.github.io/vx/blog/config-in-typescript/)
|
|
@@ -140,30 +143,31 @@ config key or an environment variable is missing here.
|
|
|
140
143
|
|
|
141
144
|
- **Results on GitHub** (`@vzn/vx-ci`: `github()`) — job summary and Checks API annotations. [page](https://vznjs.github.io/vx/features/github-ci/) · post: [Your run, on the pull request](https://vznjs.github.io/vx/blog/results-on-github/)
|
|
142
145
|
- **PR check run** (`github({ checks })`) — a check run on the commit with the run summary as its output. [page](https://vznjs.github.io/vx/features/pr-check-run/) · post: [Your run, on the pull request](https://vznjs.github.io/vx/blog/results-on-github/)
|
|
143
|
-
- **Cache scope from the ref** (`github({ cacheScope })`) — main writes
|
|
146
|
+
- **Cache scope from the ref** (`github({ cacheScope })`) — main writes the default keys; a PR writes only its own scope. [page](https://vznjs.github.io/vx/features/ref-cache-scope/) · post: [The cache on your terms](https://vznjs.github.io/vx/blog/the-cache-on-your-terms/)
|
|
144
147
|
|
|
145
148
|
## Adoption
|
|
146
149
|
|
|
147
|
-
- **Start in a minute** (`vx init`, `--dry`, `--format json`, `--force`, `--mjs`) — write
|
|
150
|
+
- **Start in a minute** (`vx init`, `--dry`, `--format json`, `--force`, `--mjs`) — write `.vx/workspace.ts`, one `vx.config.ts` per package (through `@vzn/vx-migrate`; with no `package.json`, one empty root project) and `.vx/projects.lock.json`; `--dry --format json` hands an agent the plan as data. [page](https://vznjs.github.io/vx/features/quickstart/) · post: [Hello, vx](https://vznjs.github.io/vx/blog/hello-vx/)
|
|
148
151
|
- **Migrate from Turborepo or Nx** (`vx init`, `--native`, `--keep`, `@vzn/vx-migrate`) — native config, or keep `turbo()` / `nx()` as a start. [page](https://vznjs.github.io/vx/features/migrate/) · posts: [From Turborepo](https://vznjs.github.io/vx/blog/from-turborepo/), [From Nx](https://vznjs.github.io/vx/blog/from-nx/)
|
|
149
152
|
- **Keep a Turbo or Nx remote cache** (`turboCache()`, `nxCache()`) — reuse the cache server you have. [page](https://vznjs.github.io/vx/features/keep-remote-cache/) · post: [From Nx: keep the graph, drop the platform](https://vznjs.github.io/vx/blog/from-nx/)
|
|
150
153
|
- **One binary** — one file, nothing to install underneath. [page](https://vznjs.github.io/vx/features/one-binary/) · post: [One binary](https://vznjs.github.io/vx/blog/one-binary/)
|
|
151
154
|
- **The playground** — vx's planner in the browser. [page](https://vznjs.github.io/vx/features/playground/) · post: [Try the planner in your browser](https://vznjs.github.io/vx/blog/the-playground/)
|
|
152
|
-
- **
|
|
155
|
+
- **Graph explorer** (`--dry=json`) — paste your own plan to see what each task waits on, what waits on it, and why. [page](https://vznjs.github.io/vx/guides/graph-explorer/)
|
|
156
|
+
- **Benchmarks you can re-run** (`@vzn/vx-bench`) — vx against Turborepo and Nx. [page](https://vznjs.github.io/vx/features/benchmarks/) · posts: [Benchmarks you can re-run](https://vznjs.github.io/vx/blog/honest-benchmarks/), [Why vx is fast](https://vznjs.github.io/vx/blog/why-vx-is-fast/)
|
|
153
157
|
- **npm pre/post scripts** — `pre<x>` and `post<x>` hooks fold into `x`'s command when `vx init` maps scripts. [page](https://vznjs.github.io/vx/features/npm-hooks/) · post: [From npm scripts or Vite Task](https://vznjs.github.io/vx/blog/from-scripts-and-vite-task/)
|
|
154
|
-
- **Vite Task adoption** (`bunx @vzn/vx-migrate`) — writes configs from vite-plus `run.tasks` as well as Turbo and
|
|
158
|
+
- **Vite Task adoption** (`bunx @vzn/vx-migrate`) — writes configs from vite-plus `run.tasks` as well as Turbo, Nx and `package.json` scripts (`--from scripts` picks them beside the others). [page](https://vznjs.github.io/vx/features/vite-task-adoption/) · post: [From npm scripts or Vite Task](https://vznjs.github.io/vx/blog/from-scripts-and-vite-task/)
|
|
155
159
|
- **Nx executors as one process** (`nx-exec`) — any Nx executor runs as one vx task with its Nx env set. [page](https://vznjs.github.io/vx/features/nx-exec/) · post: [From Nx: keep the graph, drop the platform](https://vznjs.github.io/vx/blog/from-nx/)
|
|
156
160
|
- **Programmatic API** (`run`, `planRun`) — run or plan from your own scripts via `@vzn/vx`. [page](https://vznjs.github.io/vx/features/programmatic-api/) · post: [Extend vx in an afternoon](https://vznjs.github.io/vx/blog/extend-vx/)
|
|
157
161
|
|
|
158
162
|
## Plugins
|
|
159
163
|
|
|
160
|
-
- **A pipeline with seams** (`plugins`, `definePlugin`; stages `config` `discover` `project` `graph` `key` `fingerprint` `schedule` `admit` `executor` `cache` `telemetry` `commands`) — every stage is a plugin seam; an `undefined`, `null` or `false` entry is skipped. [page](https://vznjs.github.io/vx/features/plugins/) · post: [A pipeline with seams](https://vznjs.github.io/vx/blog/pipeline-with-seams/)
|
|
164
|
+
- **A pipeline with seams** (`plugins`, `definePlugin`; stages `config` `discover` `project` `graph` `key` `fingerprint` `schedule` `admit` `executor` `cache` `telemetry` `output` `commands`) — every stage is a plugin seam; an `undefined`, `null` or `false` entry is skipped. [page](https://vznjs.github.io/vx/features/plugins/) · post: [A pipeline with seams](https://vznjs.github.io/vx/blog/pipeline-with-seams/)
|
|
165
|
+
- **A project is a directory with a vx.config** (`name`) — in any language; named by its config's `name`, else a plugin's, else its path (`//` for the root); two of one name are refused. [page](https://vznjs.github.io/vx/features/vx-lock/) · post: [vx lock: freezing what the key sees](https://vznjs.github.io/vx/blog/lock-and-frozen/)
|
|
166
|
+
- **Plugin projects and edges** (`discover`, `DiscoveredProject`) — a plugin adds and names projects and gives them edges as directories: `deps` orders `^task` and reaches `--filter` and `--affected`; `reach` only reaches. [page](https://vznjs.github.io/vx/features/plugins/)
|
|
161
167
|
- **Write a plugin** (`vx init --plugin`) — scaffold a runnable plugin for a seam. [page](https://vznjs.github.io/vx/features/plugins/) · post: [Extend vx in an afternoon](https://vznjs.github.io/vx/blog/extend-vx/)
|
|
162
168
|
- **The local floor** — running and caching here are core's, not plugins. [page](https://vznjs.github.io/vx/features/local-floor/) · post: [The local floor](https://vznjs.github.io/vx/blog/the-local-floor/)
|
|
163
169
|
- **Remote cache and execution** (`@vzn/vx-reapi`, `exec.remote`) — Bazel REAPI cache and workers; the scheduler stays here. [page](https://vznjs.github.io/vx/features/remote-execution/) · post: [Remote execution without moving the scheduler](https://vznjs.github.io/vx/blog/remote-execution/)
|
|
164
170
|
- **OpenTelemetry** (`@vzn/vx-otel`) — each run exported to your OpenTelemetry backend, never breaking it. [page](https://vznjs.github.io/vx/features/opentelemetry/) · post: [Observability that cannot break a run](https://vznjs.github.io/vx/blog/telemetry-never-breaks-a-run/)
|
|
165
|
-
- **vx mcp** (`@vzn/vx-mcp`, `vx mcp`) — cache stats, run history, `vx why`'s full answer, a run tool (`mcp({ run })` limits it to named tasks or turns it off), a plan tool, a task's resolved config, the lock audit, cache pruning, the `vx init` plan, an offline docs search and a task list narrowed by `--filter` / `--affected` for coding agents. [page](https://vznjs.github.io/vx/features/mcp/) · post: [Give your coding agent the build's memory](https://vznjs.github.io/vx/blog/agents-and-mcp/)
|
|
166
|
-
- **vx prune** (`@vzn/vx-lockfile`, `vx prune`, `--production`) — copy projects and their deps, lockfile pruned, for a Docker build; `--production` leaves out what only dev dependencies need. [page](https://vznjs.github.io/vx/features/vx-prune/) · post: [Ship one app, not the whole monorepo](https://vznjs.github.io/vx/blog/vx-prune/), [A runtime image without the dev tools](https://vznjs.github.io/vx/blog/prune-production/)
|
|
167
171
|
- **vx history** (`@vzn/vx-schedule-history`, `vx history`) — what the scheduler learned per task. [page](https://vznjs.github.io/vx/features/vx-history/) · post: [A scheduler that learns from your runs](https://vznjs.github.io/vx/blog/a-scheduler-that-learns/)
|
|
168
172
|
- **Setup and teardown hooks** (`setup`, `teardown`) — plugin code around the run, bounded by a timeout. [page](https://vznjs.github.io/vx/features/setup-teardown/) · post: [Extend vx in an afternoon](https://vznjs.github.io/vx/blog/extend-vx/)
|
|
169
173
|
- **REAPI TLS, mTLS and headers** — connect to hosted servers such as BuildBuddy the way Bazel does. [page](https://vznjs.github.io/vx/features/reapi-tls/) · post: [A remote server you can trust in production](https://vznjs.github.io/vx/blog/reapi-in-production/)
|