Skip to content
vxvx
GitHubBlueskydev.toRSS

Plugins

A plugin changes every run from one place: where tasks run, where the cache lives, what keys hold, who sees the results. Install it and list it in .vx/workspace.ts.

Terminal window
bun add -d @vzn/vx-lockfile @vzn/vx-otel
.vx/workspace.ts
import { defineWorkspace } from '@vzn/vx/config'
import { bun } from '@vzn/vx-lockfile'
import { otel } from '@vzn/vx-otel'
export default defineWorkspace({
plugins: [bun(), otel({ serviceName: 'my-monorepo' })],
})

vx applies no plugin by default. With none, it runs and caches on this machine. A plugin that declines a task hands it back to this machine.


Package Hooks it fills
@vzn/vx-reapi cache, executor (Remote cache, Remote execution)
@vzn/vx-migrate config, discover, project, fingerprint (turbo(), nx()), cache (turboCache(), nxCache()) (Migrate)
@vzn/vx-lockfile discover, project, fingerprint, key (Lockfiles)
@vzn/vx-history schedule, admit, commands
@vzn/vx-otel telemetry (below)
@vzn/vx-ci config, telemetry, commands (GitHub Actions, GitLab CI)
@vzn/vx-cache cache, on a @vzn/vx-cache-server
@vzn/vx-cache-server none: the cache server you host
@vzn/vx-history-server none: the timings server vxHistory() reads
@vzn/vx-devtools none: the CI token check the servers share

One plugin can fill several: @vzn/vx-history fills three at once.


@vzn/vx-otel exports every run as OTLP traces, metrics and logs, with no OpenTelemetry SDK: one trace per run, one span per task. Install it (bun add -d @vzn/vx-otel) and point it at your collector (OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318). Without any endpoint it declines; a signal’s own endpoint alone exports that signal.

.vx/workspace.ts
import { defineWorkspace } from '@vzn/vx/config'
import { otel } from '@vzn/vx-otel'
export default defineWorkspace({
plugins: [otel({ serviceName: 'my-monorepo', headers: { authorization: 'Bearer …' } })],
})
Option Env var Default
endpoint OTEL_EXPORTER_OTLP_ENDPOINT none
tracesEndpoint OTEL_EXPORTER_OTLP_TRACES_ENDPOINT <endpoint>/v1/traces
metricsEndpoint OTEL_EXPORTER_OTLP_METRICS_ENDPOINT <endpoint>/v1/metrics
logsEndpoint OTEL_EXPORTER_OTLP_LOGS_ENDPOINT <endpoint>/v1/logs
serviceName OTEL_SERVICE_NAME vx
headers OTEL_EXPORTER_OTLP_HEADERS (k=v,…) {}
metrics OTEL_METRICS_EXPORTER=none turns it off true
logs OTEL_LOGS_EXPORTER=none turns it off true
timeoutMs OTEL_EXPORTER_OTLP_TIMEOUT 15000
compression OTEL_EXPORTER_OTLP_COMPRESSION (and _<SIGNAL>_) 'none'
live none: send each task as it ends true
Signal Carries
vx.run span vx.run.task_count, vx.run.failed_count, vx.run.aborted_count, vx.run.hit_local_count, vx.run.hit_remote_count, vx.run.up_to_date_count, vx.run.restored_local_count, vx.run.restored_remote_count, vx.run.exit_ok, vx.cache.upload.* (remote uploads, once settled), vx.workspace.id, vx.default_branch, vx.telemetry.schema
vx.task span vx.cache.source, vx.cache.restored (on a hit), vx.task.hash, vx.task.attempts, vx.task.blocked_by, vx.task.timed_out, vx.task.sandbox_violations, vx.task.not_ready, vx.task.command, vx.task.flaky.*, vx.cache.stored_* (on a hit), vx.task.admission_held_ms, vx.task.queued_ms, vx.task.input_files, vx.cache.miss.change_count and vx.cache.miss.changes (what a miss’s key changed since the last saved entry), vx.cache.artifact_bytes, vx.cache.save_ms, vx.cache.fetch_ms; links to the tasks it waited on; vx.task.retry, vx.task.timeout and vx.sandbox.violation events
a span per stage startup, load configs, classify + probe, run graph, … (the VX_DEBUG_TIMING stages), with vx.stage.name
metrics vx.tasks.total, vx.tasks.failed, vx.tasks.cache_hits, vx.tasks.cache_restored, vx.tasks.cache_up_to_date, vx.run.duration_ms, vx.run.time_saved_ms
metrics per task vx.task.duration, vx.task.cpu_time, vx.task.peak_memory, vx.task.time_saved, vx.task.admission_held, vx.task.queued, vx.task.artifact_size, vx.task.cache_save, vx.task.cache_fetch at its end; vx.task.cpu_usage and vx.task.memory each second while it runs; each point names its span as an exemplar
a log per task the task’s output at its end, linked to its span; vx.log.chars_full says when it was cut
every resource service.instance.id (the run id), host.name, host.arch, os.type, vcs.ref.head.*, vcs.repository.*, vx.workspace.path (the workspace root in its repository), and on CI cicd.pipeline.run.url.full, cicd.pipeline.name, vcs.change.id (the pull request), vx.ci.job, vx.ci.attempt: one key joins a run’s traces, metrics and logs

Each task is sent as it ends, so a dashboard follows a CI run live; live: false sends it all at the end. A failed task’s span is ERROR. A failed or slow export warns, and the run still exits green.

To see it locally, run otel-desktop-viewer:

Terminal window
brew tap ctrlspice/otel-desktop-viewer
brew install --cask otel-desktop-viewer
otel-desktop-viewer
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 vx run build --all
Turborepo, Nx and other product names are trademarks of their owners. vx is not affiliated with or endorsed by them.