@vzn/vx 0.0.15 → 0.0.18

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.
Files changed (111) hide show
  1. package/README.md +91 -130
  2. package/index.ts +10 -0
  3. package/launcher.mjs +10 -11
  4. package/package.json +19 -5
  5. package/plugins/local-cache/index.ts +2 -0
  6. package/plugins/local-executor/index.ts +2 -0
  7. package/plugins/schedule-history/index.ts +2 -0
  8. package/src/bin.ts +2 -2
  9. package/src/cache/archive.ts +557 -0
  10. package/src/cache/cache.ts +929 -250
  11. package/src/cache/cas-backend.ts +20 -2
  12. package/src/cache/chained-cache.ts +202 -0
  13. package/src/cache/digest.ts +0 -15
  14. package/src/cache/index.ts +13 -3
  15. package/src/cache/inputs.ts +445 -41
  16. package/src/cache/layered-cache.ts +129 -30
  17. package/src/cache/tar-stream.ts +358 -0
  18. package/src/cli/cache.ts +36 -10
  19. package/src/cli/help.ts +167 -128
  20. package/src/cli/index.ts +74 -43
  21. package/src/cli/info.ts +30 -0
  22. package/src/cli/last.ts +140 -0
  23. package/src/cli/migrate-emit.ts +21 -0
  24. package/src/cli/migrate-nx.ts +23 -0
  25. package/src/cli/migrate-scripts.ts +127 -0
  26. package/src/cli/migrate-turbo.ts +43 -6
  27. package/src/cli/migrate.ts +119 -33
  28. package/src/cli/plan-format.ts +58 -3
  29. package/src/cli/plugin-commands.ts +96 -0
  30. package/src/cli/prune.ts +291 -0
  31. package/src/cli/run.ts +272 -80
  32. package/src/cli/upgrade.ts +7 -6
  33. package/src/cli/watch.ts +259 -61
  34. package/src/cli/why.ts +193 -0
  35. package/src/config.ts +40 -23
  36. package/src/exec/env.ts +7 -1
  37. package/src/exec/executor.ts +239 -0
  38. package/src/exec/index.ts +19 -1
  39. package/src/exec/runner.ts +116 -29
  40. package/src/exec/sandbox-runtime.ts +194 -24
  41. package/src/graph/index.ts +3 -1
  42. package/src/graph/scheduler.ts +92 -18
  43. package/src/graph/task-graph.ts +220 -6
  44. package/src/index.ts +82 -84
  45. package/src/orchestrator/deferred-outputs.ts +144 -0
  46. package/src/orchestrator/download-policy.ts +171 -0
  47. package/src/orchestrator/events.ts +30 -0
  48. package/src/orchestrator/execute-task.ts +328 -94
  49. package/src/orchestrator/failure-mode.ts +61 -0
  50. package/src/orchestrator/framed-output.ts +87 -35
  51. package/src/orchestrator/history.ts +78 -31
  52. package/src/orchestrator/index.ts +43 -90
  53. package/src/orchestrator/local-shortcircuit.ts +22 -0
  54. package/src/orchestrator/logger.ts +196 -14
  55. package/src/orchestrator/metrics.ts +57 -1376
  56. package/src/orchestrator/missing-plugin.ts +9 -0
  57. package/src/orchestrator/options.ts +22 -4
  58. package/src/orchestrator/plan.ts +144 -1
  59. package/src/orchestrator/plugin-host.ts +199 -119
  60. package/src/orchestrator/plugin.ts +144 -57
  61. package/src/orchestrator/prepare.ts +220 -69
  62. package/src/orchestrator/remote-prefetch.ts +27 -8
  63. package/src/orchestrator/resources.ts +20 -34
  64. package/src/orchestrator/run-artifacts.ts +41 -16
  65. package/src/orchestrator/run-context.ts +167 -29
  66. package/src/orchestrator/run-report.ts +73 -46
  67. package/src/orchestrator/run.ts +590 -122
  68. package/src/orchestrator/stable-keys.ts +74 -33
  69. package/src/orchestrator/status-line.ts +47 -8
  70. package/src/orchestrator/summary.ts +22 -1
  71. package/src/orchestrator/tally.ts +78 -35
  72. package/src/orchestrator/task-hash.ts +105 -11
  73. package/src/orchestrator/task-log-buffer.ts +291 -0
  74. package/src/orchestrator/telemetry-host.ts +24 -6
  75. package/src/orchestrator/telemetry.ts +181 -21
  76. package/src/orchestrator/upstream.ts +72 -31
  77. package/src/orchestrator/verify.ts +12 -2
  78. package/src/plugins/local-cache/index.ts +11 -0
  79. package/src/plugins/local-executor/index.ts +45 -0
  80. package/src/plugins/schedule-history/index.ts +109 -0
  81. package/src/util/edit-distance.ts +21 -0
  82. package/src/util/errors.ts +15 -1
  83. package/src/util/index.ts +7 -2
  84. package/src/util/num.ts +37 -0
  85. package/src/util/paths.ts +43 -0
  86. package/src/util/settle.ts +48 -0
  87. package/src/util/size.ts +5 -1
  88. package/src/util/tail.ts +66 -0
  89. package/src/util/timing.ts +63 -0
  90. package/src/workspace/affected.ts +142 -15
  91. package/src/workspace/config-cache.ts +304 -0
  92. package/src/workspace/config-eval.ts +210 -0
  93. package/src/workspace/config-imports.ts +161 -0
  94. package/src/workspace/filter.ts +22 -4
  95. package/src/workspace/fingerprint.ts +16 -1
  96. package/src/workspace/index.ts +15 -3
  97. package/src/workspace/lockfile.ts +13 -2
  98. package/src/workspace/nested-dirs.ts +21 -7
  99. package/src/workspace/package-graph.ts +23 -20
  100. package/src/workspace/project-loader.ts +503 -59
  101. package/src/workspace/workspace.ts +213 -72
  102. package/src/cache/tar.ts +0 -343
  103. package/src/cli/backend.ts +0 -23
  104. package/src/cli/mcp-rpc.ts +0 -292
  105. package/src/cli/mcp.ts +0 -92
  106. package/src/orchestrator/devframe-surface.ts +0 -74
  107. package/src/orchestrator/predict.ts +0 -106
  108. package/src/orchestrator/protocol.ts +0 -156
  109. package/src/orchestrator/run-state.ts +0 -145
  110. package/src/orchestrator/wire-render.ts +0 -92
  111. package/src/orchestrator/wire.ts +0 -212
package/README.md CHANGED
@@ -3,9 +3,13 @@
3
3
  **The fastest way to build a monorepo.**
4
4
 
5
5
  vx runs your task graph, remembers every result, and never does the
6
- same work twice. Fully cached runs finish in milliseconds — 144 ms
7
- across 100 packages, 0.62 s across a 1090-package graph of 3,270
8
- tasks. Measured, reproducible, on hardware you own.
6
+ same work twice. Fully cached runs finish in milliseconds — 76 ms
7
+ across 46 packages, 559 ms across a 1,090-package graph of 3,270 tasks,
8
+ where Turborepo takes 760 ms and Nx 3.59 s on the identical workspace —
9
+ and a cold build of that graph burns 34 s of CPU in vx, 73 s in Turborepo
10
+ and 114 minutes in Nx.
11
+ Measured, reproducible, on hardware you own
12
+ ([benchmarks](docs/benchmarks.md)).
9
13
 
10
14
  One binary. No daemon. No Node. Nothing to babysit.
11
15
 
@@ -15,9 +19,6 @@ architecture, caching, and the full CLI / config reference.
15
19
  ```sh
16
20
  # From npm — ships the prebuilt standalone binary (no Bun required):
17
21
  npm install -g @vzn/vx # or: pnpm add -g @vzn/vx · bun add -g @vzn/vx
18
-
19
- # Or the zero-dependency install script (no Node/npm needed):
20
- curl -fsSL https://raw.githubusercontent.com/vznjs/vx/main/install.sh | sh
21
22
  ```
22
23
 
23
24
  ```ts
@@ -45,6 +46,7 @@ export default defineProject({
45
46
  ```
46
47
 
47
48
  ```sh
49
+ vx init # scaffold vx.workspace.ts + a vx.config.ts per package from scripts
48
50
  vx run build # cwd project + its workspace deps
49
51
  vx run test --all # every project that declares `test`
50
52
  vx run ci --affected # only what changed since origin/HEAD
@@ -52,58 +54,6 @@ vx watch lint # re-run on file changes
52
54
  vx run build --dry # show the plan, don't execute
53
55
  ```
54
56
 
55
- ## Beyond a task runner — what shipped in the 2026-06 platform arc
56
-
57
- vx now ships an **open platform**, not just a CLI. Every surface
58
- below is built into the binary; no external services required.
59
-
60
- ```sh
61
- vx mcp # Model Context Protocol server (stdio)
62
- # — Claude Code / Cursor / Continue.dev talk to vx as a typed tool
63
-
64
- npm i -g @vzn/vx-cloud # the service CLI — also a standalone binary, no Bun
65
- vx-cloud serve --ui --open # team backend + embedded dashboard (token-authenticated)
66
- vx-cloud agent --url https://ci.acme.dev # join a distributed-execution pool (Nx-Agents-style DTE)
67
- vx-cloud connect https://ci.acme.dev # one-URL analytics + remote cache for every `vx run`
68
- ```
69
-
70
- ### Open platform highlights
71
-
72
- - **Provider-neutral core.** `vx` runs tasks and nothing else — the
73
- dashboard, remote cache, distribution, and telemetry all arrive via
74
- PLUGINS declared in `vx.workspace.ts`. `@vzn/vx-cloud` is the
75
- first-party one; anyone can write another against the same seams
76
- (backend / cache / telemetry).
77
- - **MCP for AI agents, twice.** `vx mcp` (stdio, reads your real
78
- `cache.db`: `getCacheStats`, `getRunHistory`, `explainCacheKey`,
79
- `whyDidThisRerun`) and `POST /mcp` on any `vx-cloud serve` — local
80
- or hosted, behind the bearer token.
81
- - **Provable cache correctness.** `vx run --verify` re-runs each
82
- cacheable task and byte-compares outputs; `--verify=inputs` runs it
83
- sandboxed against the declared inputs and names any undeclared read.
84
- The only runner that PROVES a cache entry safe instead of hoping.
85
- - **Distributed CI (DTE).** `vx-cloud agent` joins a session-keyed
86
- pool; a `vx run` fans tasks out across same-commit agents, outputs
87
- propagate through the shared artifact store, and a standing pool
88
- multiplexes concurrent runs with fair scheduling.
89
- - **Remote cache, one URL.** `vx-cloud connect <url>` wires analytics
90
- ingest AND a Turborepo-wire-compatible artifact store (HMAC signing,
91
- trusted/untrusted tiers derived from the token). Third-party Turbo
92
- cache servers work via two env vars.
93
- - **OTel CI/CD spans.** Declare `otel()` from `@vzn/vx-otel` in
94
- `vx.workspace.ts` — OTLP/HTTP traces + metrics with ZERO
95
- OpenTelemetry SDK dependency; runs flow to Grafana / Honeycomb /
96
- Datadog, including `--verify` hermeticity verdicts as span status.
97
- - **Dashboard embedded in the `vx-cloud` binary.** Runs, flamegraphs,
98
- live run cockpit with the task DAG, per-task logs + artifacts,
99
- cache-key diffs ("why did this re-run?"), flaky-task detection.
100
- Nothing to build or install; Docker image on ghcr for hosting.
101
- - **Predictive scheduling.** Opt in with `predictive: true` — the
102
- scheduler reads run history and starts the longest expected critical
103
- path first.
104
-
105
- Each surface lives behind a design doc under `docs/design/`.
106
-
107
57
  ## A cache that actually understands your build
108
58
 
109
59
  Every task runner caches. vx caches _correctly_ — and stops work
@@ -138,14 +88,10 @@ with the invariant that keeps it valid —
138
88
  `--verify=inputs` sandboxes it against the declared inputs and fails
139
89
  loud naming any undeclared read (completeness). No other runner can
140
90
  prove a cache entry safe.
141
- - **Signed artifacts.** HMAC signing on the remote-cache wire; with a
142
- key configured, unsigned or tampered artifacts are rejected and the
143
- task simply re-runs. A poisoned cache can't reach your machines.
144
- - **Cache trust tiers.** The server derives trusted/untrusted from the
145
- bearer token — a fork-PR artifact can never feed a trusted build.
146
- - **Corruption can't go live.** Artifacts are validated before they
147
- enter the store (zstd-bomb and oversize downloads refused); bad
148
- bytes degrade to a cache miss, never a crash.
91
+ - **Corruption can't go live.** A remote artifact is verified against
92
+ its content digest and validated before it enters the store
93
+ (zstd-bomb and oversize downloads refused); bad bytes degrade to a
94
+ cache miss, never a wrong hit and never a crash.
149
95
  - **Clean exits.** SIGINT/SIGTERM reap every child process — no
150
96
  orphaned dev servers in CI.
151
97
  - **Readiness you can bound.** Persistent tasks gate downstream work
@@ -183,33 +129,59 @@ TypeScript config with real imports · task graph with `^task`
183
129
  resolution that bridges packages without the task · multi-task runs
184
130
  with one shared graph · pnpm-style filters and `--affected` ·
185
131
  watch mode · `--dry` / `--graph` plans · persistent dev servers ·
186
- remote caching via one URL (or two env vars, wire-compatible with
187
- existing Turbo artifact servers) · retries, timeouts, `--continue`
188
- modes · per-layer cache control (`--cache=local:r,remote:`) ·
189
- `vx info`, `--summarize`, `--profile` Chrome traces, `--report` ·
190
- `vx cache prune` with TTL and size caps · `vx migrate` from
191
- turbo.json or an Nx graph.
132
+ retries, timeouts, `--continue` modes · per-layer cache control
133
+ (`--cache=local:r,remote:`) · `vx why` explains a re-run from the
134
+ persisted input fingerprints · `vx last` replays a recorded run ·
135
+ `vx prune` cuts a Docker-ready workspace subset · `vx info`,
136
+ `--summarize`, `--profile` Chrome traces, `--report` · `vx cache prune`
137
+ with TTL and size caps · `vx migrate` from turbo.json or an Nx graph.
138
+
139
+ ## A pipeline with seams — plugins decide what happens
140
+
141
+ Core is the pipeline: discover projects, evaluate configs, build the
142
+ task graph, derive keys, schedule, execute, cache, observe. Plugins
143
+ declared in `vx.workspace.ts` hook each stage, Vite-style, on one
144
+ `VxPlugin` object:
145
+
146
+ | Stage | Hook | A plugin can… |
147
+ | --------- | -------------------------- | ----------------------------------------------------------- |
148
+ | workspace | `config(ws, ctx)` | edit the workspace config before it is used |
149
+ | project | `project(config, ctx)` | add, remove or rewrite a project's tasks (keyed like yours) |
150
+ | graph | `graph(nodes, ctx)` | add or drop edges, mark tasks requested |
151
+ | key | `key(task, ctx)` | fold extra material into the cache key (named in `vx why`) |
152
+ | schedule | `schedule(nodes, ctx)` | decide which ready task runs first |
153
+ | execute | `executor(ctx)` | decide WHERE a task's command runs (local, a REAPI worker) |
154
+ | store | `cache(ctx)` | decide where artifacts live (local, a shared remote) |
155
+ | observe | `telemetry(ctx)` / `setup` | receive every run record, or the raw event bus |
156
+ | cli | `commands` | add verbs to `vx` |
157
+
158
+ Core applies **no plugin by default** — even its own local executor and
159
+ cache are plugins your workspace declares, which is what makes "replace
160
+ any part" real rather than promised. First-party plugins:
161
+ [`@vzn/vx-reapi`](packages/vx-reapi) (Bazel Remote Execution API —
162
+ remote cache and remote execution against NativeLink, BuildBuddy,
163
+ Buildbarn or bazel-remote), [`@vzn/vx-otel`](packages/vx-otel)
164
+ (OpenTelemetry traces + metrics + logs, zero SDK deps),
165
+ [`@vzn/vx-github`](packages/vx-github) (Actions job summary + Checks
166
+ API), [`@vzn/vx-mcp`](packages/vx-mcp) (`vx mcp` — a read-only Model
167
+ Context Protocol server for AI coding agents, no SDK), and
168
+ `@vzn/vx/plugins/schedule-history` (order by learned critical path). Nothing distributed ships in this repo; the seams are how you
169
+ build it.
192
170
 
193
171
  ## How it compares
194
172
 
195
- | | vx | Turborepo | Nx |
196
- | ------------------------- | --------------------------------------------------------------------- | ------------------------------ | ------------------- |
197
- | Fully cached, 100 pkgs¹ | **144 ms** | 279 ms | 583+ ms |
198
- | Config | TypeScript, evaluated into the cache key | JSON (static) | JSON (static) |
199
- | Output ownership | **Strict** — wiped before exec AND restore | Additive (stale files survive) | Additive |
200
- | Clean-tree hashing | **Zero reads** (git index OIDs) | git OIDs | re-hash / daemon |
201
- | Daemon required for speed | **No** | Optional | Yes |
202
- | Artifact signing | **Hard-fail** on unsigned | Soft | No |
203
- | Per-task sandbox | **Yes** — kernel-level, opt-in | No | No |
204
- | Provable cache safety | **Yes** — `--verify` (determinism) + `--verify=inputs` (completeness) | No | No |
205
- | MCP server for AI agents | **Yes** (`vx mcp` stdio + `POST /mcp` on the serve) | No | No |
206
- | Distributed CI execution | **Yes** — OSS, self-hostable (`vx-cloud agent`, Nx-DTE-style) | No | Paid (Nx Cloud DTE) |
207
- | Dashboard SPA | **Yes** — embedded in `vx-cloud serve --ui`: runs, logs, DAG, flaky | No | Paid |
208
- | Self-hosted cloud | **Yes** — `vx-cloud` binary or the ghcr Docker image; one stack | Vercel-only | No (proprietary) |
209
- | Plugin API | **Yes** — backend / cache / telemetry seams | No | Yes (TS-tied) |
210
- | Predictive scheduling | **Yes** (opt-in: `predictive: true`) | No | No |
211
- | OTel CI/CD spans | **Yes** — `otel()` plugin, zero OTel-SDK deps | No | Paid |
212
- | Install | **Single binary** — npm or 1 curl line, no Node/Bun needed | npm + Node | npm + Node |
173
+ | | vx | Turborepo | Nx |
174
+ | ------------------------- | --------------------------------------------------------------------- | ------------------------------ | ---------------- |
175
+ | Fully cached, 100 pkgs¹ | **144 ms** | 279 ms | 583+ ms |
176
+ | Config | TypeScript, evaluated into the cache key | JSON (static) | JSON (static) |
177
+ | Output ownership | **Strict** — wiped before exec AND restore | Additive (stale files survive) | Additive |
178
+ | Clean-tree hashing | **Zero reads** (git index OIDs) | git OIDs | re-hash / daemon |
179
+ | Daemon required for speed | **No** | Optional | Yes |
180
+ | Per-task sandbox | **Yes** — kernel-level, opt-in | No | No |
181
+ | Provable cache safety | **Yes** — `--verify` (determinism) + `--verify=inputs` (completeness) | No | No |
182
+ | Plugin API | **Yes** — executor / cache / telemetry seams | No | Yes (TS-tied) |
183
+ | OTel CI/CD spans | **Yes** — `otel()` plugin, zero OTel-SDK deps | No | Paid |
184
+ | Install | **Single binary** — npm or 1 curl line, no Node/Bun needed | npm + Node | npm + Node |
213
185
 
214
186
  ¹ Wall-clock, direct binaries, same machine and workspace — full
215
187
  methodology and more scenarios in
@@ -259,7 +231,7 @@ Differences to know:
259
231
  - vx requires `cache.inputs.files` when caching is enabled (no default `$TURBO_DEFAULT$`).
260
232
  - vx defaults caching **off**; opt in per task by adding the `cache` block.
261
233
  - Persistent tasks: `persistent: { readyWhen: 'regex' }` (Turbo uses just `persistent: true`).
262
- - Remote cache: same wire format. Existing `VERCEL_*` / Turbo-cache-server tokens work via `VX_REMOTE_CACHE_TOKEN`.
234
+ - Remote caching is a plugin, not a built-in — connect one and every `vx run` reads through it.
263
235
 
264
236
  Side-by-side feature matrix + every known gap: [`docs/comparison.md`](./docs/comparison.md).
265
237
 
@@ -268,16 +240,16 @@ Side-by-side feature matrix + every known gap: [`docs/comparison.md`](./docs/com
268
240
  `bin.ts → cli/index.ts` dispatches subcommands.
269
241
  `orchestrator/run.ts:run()` calls `prepareRun()` which discovers the
270
242
  workspace, loads configs, builds the package + task graph, opens the
271
- cache (local SQLite + optional remote layer), and installs plugins
243
+ cache (local SQLite + an optional remote layer), and installs plugins
272
244
  from `vx.workspace.ts`. The two-tier scheduler runs the graph in
273
245
  topological order with bounded concurrency (confirmed cache hits
274
246
  restore ahead of their deps); each task hits the cache (hash → get →
275
247
  restore on hit; spawn → save on miss) or short-circuits as a group /
276
248
  persistent. Every observation flows through one event bus — the
277
- terminal renderer subscribes directly, and PLUGINS receive the
249
+ terminal renderer subscribes directly, and plugins receive the
278
250
  versioned telemetry contract (`TelemetryRecord` / `RunSummaryRecord`)
279
- — that's how `otel()` and `cloud()` export without core knowing them.
280
- Core never imports a plugin; the arrow only points plugin → core.
251
+ — that's how telemetry and cache plugins export without core knowing
252
+ them. Core never imports a plugin; the arrow only points plugin → core.
281
253
  Every module has a docs page; every interface is a swappable seam.
282
254
 
283
255
  Read [`docs/architecture.md`](./docs/architecture.md) for the module
@@ -285,9 +257,8 @@ map; the design record lives under [`docs/design/`](./docs/design/).
285
257
 
286
258
  ## Documentation
287
259
 
288
- Full technical docs live under [`docs/`](./docs/):
289
-
290
- **Core**
260
+ Full technical docs live under [`docs/`](./docs/) and on the
261
+ [documentation site](https://vznjs.github.io/vx/):
291
262
 
292
263
  - [`docs/architecture.md`](./docs/architecture.md) — module map + data flow
293
264
  - [`docs/schema.md`](./docs/schema.md) — every config field
@@ -297,52 +268,42 @@ Full technical docs live under [`docs/`](./docs/):
297
268
  - [`docs/comparison.md`](./docs/comparison.md) — Turbo / Nx / vite-task feature matrix
298
269
  - [`docs/modules/`](./docs/modules/) — one reference page per source module
299
270
 
300
- **Design + 2026-06 platform arc** (`docs/design/`)
301
-
302
- - [`architecture-north-star-2026-06.md`](./docs/design/architecture-north-star-2026-06.md) — the unified vision
303
- - [`architecture-review-2026-06.md`](./docs/design/architecture-review-2026-06.md) — review + applied checklist
304
- - [`wire-protocol-2026-06.md`](./docs/design/wire-protocol-2026-06.md) — JSON-RPC 2.0 + OTel envelope (shipped)
305
- - [`distributed-ci-2026-06.md`](./docs/design/distributed-ci-2026-06.md) — original coordinator/worker (superseded by `vx-cloud agent` DTE — `distributed-execution-2026-07.md`)
306
- - [`vx-cloud-2026-06.md`](./docs/design/vx-cloud-2026-06.md) — original CF cloud (superseded by the standalone `vx-cloud` service)
307
- - [`extension-protocol-2026-06.md`](./docs/design/extension-protocol-2026-06.md) — subscriber/inspector/driver/plugin (Phase 1 shipped)
308
- - [`predictive-execution-2026-06.md`](./docs/design/predictive-execution-2026-06.md) — history-aware scheduling (Phase A-B shipped)
309
- - [`docs/progress/implementation-log-2026-06.md`](./docs/progress/implementation-log-2026-06.md) — phase-by-phase narrative
271
+ The design record lives under [`docs/design/`](./docs/design/); the
272
+ maintainers' handoff is [`docs/STATUS.md`](./docs/STATUS.md).
310
273
 
311
274
  ## Status
312
275
 
313
276
  **Pre-alpha.** The schema is settling; we bump `CACHE_VERSION` rather
314
- than maintain back-compat. **1,400+ tests (core + packages); CI green
315
- on every commit**; the project dogfoods itself (`vx run ci`).
316
- Published on npm: [`@vzn/vx`](https://www.npmjs.com/package/@vzn/vx)
317
- and `@vzn/vx-cloud`, both as prebuilt standalone binaries.
277
+ than maintain back-compat. **~2,500 core tests plus the package suites; CI green on every commit**;
278
+ the project dogfoods itself (`vx run ci`). Published on npm:
279
+ [`@vzn/vx`](https://www.npmjs.com/package/@vzn/vx) (a prebuilt standalone
280
+ binary).
318
281
 
319
282
  Production readiness for the **core task runner**: the semantics are
320
- solid. The main operational rough edge is Windows (unsupported).
321
-
322
- Production readiness for the **platform layer**:
323
-
324
- | Surface | Maturity | Notes |
325
- | ---------------------------------------------- | -------------------------------- | ---------------------------------------------------------------- |
326
- | Core task runner + caching | **production-ready** | dogfooded continuously; 1,150+ core tests, all green |
327
- | `vx run --verify` (provable cache correctness) | **shippable** | determinism + input-completeness proofs; CI-gate recipe in docs |
328
- | `vx mcp` + serve `POST /mcp` | **shippable** | live cache.db tools (stdio); serve-hosted MCP behind the bearer |
329
- | `vx-cloud serve` (ingest + dashboard + /v8) | **shippable** | token-auth, multi-workspace, artifact store, ghcr image |
330
- | `vx-cloud agent` distributed execution | **shippable for self-hosted CI** | session-keyed DTE, shared pools, fair multi-run scheduling |
331
- | Plugin API (backend / cache / telemetry) | **shippable** | crash-isolated; `cloud()` + `otel()` are ordinary plugins |
332
- | Predictive scheduling | **shippable as opt-in** | gated on `predictive: true` + observed data |
333
- | Dashboard SPA (embedded in `vx-cloud`) | **iterating** | runs/logs/DAG/flaky live; data-first entity redesign in progress |
334
- | OTel export (`@vzn/vx-otel`) | **shippable** | declare `otel()` in `vx.workspace.ts`; OTLP traces + metrics |
283
+ solid; it is dogfooded continuously. The main operational rough edge
284
+ is Windows (unsupported).
285
+
286
+ | Surface | Maturity | Notes |
287
+ | ------------------------------------------------ | -------------------- | ---------------------------------------------------------------------------- |
288
+ | Core task runner + caching | **production-ready** | dogfooded continuously; ~2,500 core tests + the package suites, green |
289
+ | `vx run --verify` (provable cache correctness) | **shippable** | determinism + input-completeness proofs; CI-gate recipe in docs |
290
+ | Plugin pipeline (9 hooks, `commands` included) | **shippable** | crash-isolated, re-validated; core's own executor + cache are plugins |
291
+ | `vx init` / `vx migrate` (scripts, Turbo, Nx) | **shippable** | one config per package, TODOs where a source cannot say |
292
+ | REAPI remote cache + execution (`@vzn/vx-reapi`) | **shippable** | Bazel AC + CAS + Execute; NativeLink / BuildBuddy / Buildbarn / bazel-remote |
293
+ | OTel export (`@vzn/vx-otel`) | **shippable** | OTLP traces + metrics + logs, zero SDK deps |
294
+ | GitHub Actions (`@vzn/vx-github`) | **shippable** | job summary + Checks API run |
295
+ | MCP server (`@vzn/vx-mcp`) | **shippable** | `vx mcp` — read-only tools for AI agents, no SDK |
335
296
 
336
297
  ## Development
337
298
 
338
299
  ```sh
339
300
  git clone https://github.com/vznjs/vx && cd vx
340
301
  bun install
341
- bun src/bin.ts run ci # format-check + lint + test
342
- bun src/bin.ts run build # cross-target binaries → dist/
302
+ bun packages/vx/src/bin.ts run ci --all # lint + test + docs build, every package
303
+ bun packages/vx/src/bin.ts run build --filter @vzn/vx # cross-target binaries → packages/vx/dist/
343
304
  ```
344
305
 
345
- vx is self-hosted: every dev task routes through `bun src/bin.ts run <task>` per the repo's own `vx.config.ts`. No `package.json` scripts; CI invokes vx directly.
306
+ vx is self-hosted: every dev task routes through `bun packages/vx/src/bin.ts run <task>` per each package's own `vx.config.ts`. No `package.json` scripts; CI invokes vx directly. Start with [`docs/STATUS.md`](docs/STATUS.md) — the living handoff — and `CLAUDE.md`.
346
307
 
347
308
  ## License
348
309
 
package/index.ts ADDED
@@ -0,0 +1,10 @@
1
+ // Root entry shim. Bun 1.4.0's `--compile` binaries resolve an on-disk
2
+ // package by directory convention (`<pkg>/index.ts`, `<pkg>/<subpath>/index.ts`)
3
+ // and ignore package.json `exports` / `main` (measured 2026-09-03: an
4
+ // entry of `./src/index.ts` resolved to the root `index.ts` regardless of the
5
+ // manifest, and a package with no root file was "not found"). Without this
6
+ // file every `import … from '@vzn/vx'` in a workspace config fails under the
7
+ // standalone binary. The exports map still wins everywhere else and points
8
+ // at the same module, so this is one extra hop for the binary and nothing
9
+ // for anyone else.
10
+ export * from './src/index.js'
package/launcher.mjs CHANGED
@@ -1,12 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
  // npm launcher for a vx command — the entry a published package's `bin` points
3
3
  // at. It execs the prebuilt standalone binary shipped as a per-platform
4
- // optionalDependency, so end users get the command WITHOUT installing Bun. ONE
5
- // launcher serves both `@vzn/vx` and `@vzn/vx-cloud`: everything is derived from
6
- // this package's OWN name, read from the package.json sitting beside this file.
4
+ // optionalDependency, so end users get the command WITHOUT installing Bun.
5
+ // Everything is derived from this package's OWN name, read from the
6
+ // package.json sitting beside this file, so any package built by
7
+ // scripts/build-npm.ts can carry it:
7
8
  //
8
- // @vzn/vx → platform pkg @vzn/vx-<key>, binary `vx`
9
- // @vzn/vx-cloud → platform pkg @vzn/vx-cloud-<key>, binary `vx-cloud`
9
+ // @vzn/vx → platform pkg @vzn/vx-<key>, binary `vx`
10
10
  //
11
11
  // Resolution order:
12
12
  // 1. the matching <name>-<platform> optionalDependency's binary (the normal
@@ -26,11 +26,10 @@ const require = createRequire(import.meta.url)
26
26
  const here = dirname(fileURLToPath(import.meta.url))
27
27
  const pkg = require('./package.json')
28
28
 
29
- // Derive the platform-package prefix + binary basename from this package's name
30
- // so the same launcher works for @vzn/vx and @vzn/vx-cloud. `base` is the
31
- // unscoped name (vx / vx-cloud) — the command AND the binary filename inside the
32
- // platform package. `vxSourceEntry` (a package.json field) is the source-mode
33
- // entry: `src/bin.ts` for vx, `src/cli/bin.ts` for vx-cloud.
29
+ // Derive the platform-package prefix + binary basename from this package's
30
+ // name. `base` is the unscoped name — the command AND the binary filename
31
+ // inside the platform package. `vxSourceEntry` (a package.json field) is the
32
+ // source-mode entry, `src/bin.ts` by default.
34
33
  const name = pkg.name
35
34
  const base = name.replace(/^@[^/]+\//, '')
36
35
  const sourceEntry = pkg.vxSourceEntry ?? 'src/bin.ts'
@@ -86,7 +85,7 @@ process.stderr.write(
86
85
  `${base}: no prebuilt binary for ${key}.\n` +
87
86
  ` Supported platforms: ${supported}.\n` +
88
87
  ` If your platform should be supported, reinstall so npm fetches the\n` +
89
- ` matching ${name}-${key} optionalDependency, or install Bun (>=1.3) to\n` +
88
+ ` matching ${name}-${key} optionalDependency, or install Bun (>=1.4) to\n` +
90
89
  ` run ${base} from source.\n`,
91
90
  )
92
91
  process.exit(1)
package/package.json CHANGED
@@ -1,12 +1,24 @@
1
1
  {
2
2
  "name": "@vzn/vx",
3
- "version": "0.0.15",
3
+ "version": "0.0.18",
4
4
  "description": "An open, extensible monorepo task runner.",
5
5
  "type": "module",
6
6
  "exports": {
7
7
  ".": {
8
8
  "types": "./src/index.ts",
9
9
  "import": "./src/index.ts"
10
+ },
11
+ "./plugins/local-executor": {
12
+ "types": "./src/plugins/local-executor/index.ts",
13
+ "import": "./src/plugins/local-executor/index.ts"
14
+ },
15
+ "./plugins/local-cache": {
16
+ "types": "./src/plugins/local-cache/index.ts",
17
+ "import": "./src/plugins/local-cache/index.ts"
18
+ },
19
+ "./plugins/schedule-history": {
20
+ "types": "./src/plugins/schedule-history/index.ts",
21
+ "import": "./src/plugins/schedule-history/index.ts"
10
22
  }
11
23
  },
12
24
  "types": "./src/index.ts",
@@ -17,15 +29,17 @@
17
29
  "node": ">=18"
18
30
  },
19
31
  "optionalDependencies": {
20
- "@vzn/vx-linux-x64": "0.0.15",
21
- "@vzn/vx-linux-arm64": "0.0.15",
22
- "@vzn/vx-darwin-x64": "0.0.15",
23
- "@vzn/vx-darwin-arm64": "0.0.15"
32
+ "@vzn/vx-linux-x64": "0.0.18",
33
+ "@vzn/vx-linux-arm64": "0.0.18",
34
+ "@vzn/vx-darwin-x64": "0.0.18",
35
+ "@vzn/vx-darwin-arm64": "0.0.18"
24
36
  },
25
37
  "dependencies": {
26
38
  "@anthropic-ai/sandbox-runtime": "^0.0.56"
27
39
  },
28
40
  "files": [
41
+ "index.ts",
42
+ "plugins",
29
43
  "src",
30
44
  "launcher.mjs",
31
45
  "README.md",
@@ -0,0 +1,2 @@
1
+ // Subpath shim for Bun's compiled binaries — see ../../index.ts.
2
+ export * from '../../src/plugins/local-cache/index.js'
@@ -0,0 +1,2 @@
1
+ // Subpath shim for Bun's compiled binaries — see ../../index.ts.
2
+ export * from '../../src/plugins/local-executor/index.js'
@@ -0,0 +1,2 @@
1
+ // Subpath shim for Bun's compiled binaries — see ../../index.ts.
2
+ export * from '../../src/plugins/schedule-history/index.js'
package/src/bin.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env bun
2
2
  import { run } from './cli/index.js'
3
- import { UserError } from './util/index.js'
3
+ import { isUserError } from './util/index.js'
4
4
 
5
5
  // Wrapped in an explicit async main so `bun build --compile` accepts
6
6
  // the file. The compile target doesn't allow top-level await.
@@ -12,7 +12,7 @@ async function main(): Promise<void> {
12
12
  // print the message only; the stack is noise the user can't act
13
13
  // on. Everything else gets the full stack so internal bugs are
14
14
  // debuggable.
15
- if (err instanceof UserError) {
15
+ if (isUserError(err)) {
16
16
  process.stderr.write(`vx: ${err.message}\n`)
17
17
  } else {
18
18
  const message = err instanceof Error ? (err.stack ?? err.message) : String(err)