Skip to content

Release pipeline ​

How VeloxSaarthi binaries and these docs get built and published. The story pipeline ships client code; this release/CI pipeline ships vlx itself. It is an Azure DevOps pipeline (azure-pipelines.yml, pipeline id 91, named vlx-release) that runs on every push to main.

Releases only via the pipeline

Binaries are published only by this pipeline — never by a local cross-compile. The self-updater trusts whatever latest.json says, so an out-of-band upload would push an unverified binary to every deployed client.

What it does, step by step ​

  1. Trigger — any push to main.
  2. Compute next version — fetch the last published latest.json from the blob and patch-bump it. Only an HTTP 404 (the very first release) falls back to 0.0.0; any other fetch failure aborts the build rather than guess a version — a transient blob outage must never reset the channel to 0.0.1 and strand every forward-only client.
  3. Build binaries — bun install --frozen-lockfile, pin package.json to the computed version, then bun run build cross-compiles three standalone targets (windows-x64, darwin-arm64, linux-x64) and emits dist/latest.json (scripts/build.ts).
  4. Publish to blob — upload order matters so a client never reads a manifest whose binaries aren't up yet:
    1. a versioned copy under v<version>/ (immutable — rollback + edge-cacheable),
    2. the live vlx-* binaries (no-cache),
    3. latest.json last (no-cache).
  5. Publish docs — cd docs-site && bun run docs:build, then deploy .vitepress/dist to the Azure Static Web App (veloxsaarthi-docs → https://docs.saarthi.bot) via the SWA CLI. This is why every release refreshes the docs you're reading.
  6. Commit the bump — commit package.json + src/db/migrations.generated.ts back to main as release: v<version> [skip ci] (the [skip ci] prevents an infinite loop).

Distribution & caching ​

  • Branded path only. Clients download from https://dl.saarthi.bot/releases, never the raw blob URL. dl.saarthi.bot is a Cloudflare Worker that rewrites the Host header to the origin blob and caches at the edge.
  • Immutable versioned paths. latest.json points each binary at its v<version>/ copy — a URL that never changes once published — so the edge can cache it forever, cutting Azure egress. latest.json itself stays no-cache so clients always see the newest version.
  • The manifest sha256 matches both the root and v<version>/ copies (identical bytes), so the self-updater's integrity check passes regardless of which path it reads.

Self-update (client side) ​

On every vlx daemon start a compiled binary checks the channel (src/update/updater.ts): it fetches latest.json, compares versions, and if newer streams the platform binary down with an incremental sha256, swaps itself on disk (Windows-safe rename-aside), and re-execs into the new binary in the same terminal. Any failure short of a completed swap is non-fatal — the client keeps running the current version. Opt out per-run with --no-update / VLX_NO_UPDATE=1; force with vlx update.

Insider (beta) channel ​

The insider channel exists so a fix can be validated on a real, packaged binary before it ships to users. It is a second manifest, latest-insider.json, next to latest.json in the same container. Only vlx update --insider reads it; the daemon's on-start self-update always tracks stable, so insider builds never leak to normal users.

  • Versioning. Insider builds are 4-part: v<stable>.<n> (e.g. 0.0.40.3 while stable is 0.0.40). compareVersions orders them numerically, so 0.0.40.3 > 0.0.40 but 0.0.41 > 0.0.40.9 — a tester rejoins stable the moment stable moves past their insider build.
  • Published locally, not by the pipeline. Insider is a deliberate, scoped local publish: bun scripts/publish-insider.ts computes the next .<n> from the current latest-insider.json, cross-compiles, uploads the immutable v<version>/ copies, then writes latest-insider.json last. It never touches latest.json or the mutable root vlx-* pointers, so a bad insider build can't strand stable clients. Requires the same BLOB_ACCOUNT / BLOB_KEY / BLOB_CONTAINER / BLOB_BASE_URL env vars as the pipeline, plus the Azure CLI (az).
  • Workflow. Publish an insider build → on a test box vlx update --insider → validate the fix → only then merge the change to main (which ships stable via the pipeline).

Required pipeline variables ​

Set under Pipelines → Edit → Variables:

VariablePurpose
BLOB_ACCOUNTstorage account name
BLOB_CONTAINERrelease container (public blob read)
BLOB_KEYstorage account key (secret)
BLOB_BASE_URLpublic base URL of the container
SWA_DEPLOY_TOKENStatic Web App deployment token (secret)

The build-service identity needs Contribute + Bypass policies when pushing on the repo to commit the version bump back to main.

Internal Veloxcore tool — not a public product.