Appearance
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
- Trigger — any push to
main. - Compute next version — fetch the last published
latest.jsonfrom the blob and patch-bump it. Only an HTTP 404 (the very first release) falls back to0.0.0; any other fetch failure aborts the build rather than guess a version — a transient blob outage must never reset the channel to0.0.1and strand every forward-only client. - Build binaries —
bun install --frozen-lockfile, pinpackage.jsonto the computed version, thenbun run buildcross-compiles three standalone targets (windows-x64,darwin-arm64,linux-x64) and emitsdist/latest.json(scripts/build.ts). - Publish to blob — upload order matters so a client never reads a manifest whose binaries aren't up yet:
- a versioned copy under
v<version>/(immutable — rollback + edge-cacheable), - the live
vlx-*binaries (no-cache), latest.jsonlast (no-cache).
- a versioned copy under
- Publish docs —
cd docs-site && bun run docs:build, then deploy.vitepress/distto 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. - Commit the bump — commit
package.json+src/db/migrations.generated.tsback tomainasrelease: 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.botis a Cloudflare Worker that rewrites the Host header to the origin blob and caches at the edge. - Immutable versioned paths.
latest.jsonpoints each binary at itsv<version>/copy — a URL that never changes once published — so the edge can cache it forever, cutting Azure egress.latest.jsonitself staysno-cacheso 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.3while stable is0.0.40).compareVersionsorders them numerically, so0.0.40.3 > 0.0.40but0.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.tscomputes the next.<n>from the currentlatest-insider.json, cross-compiles, uploads the immutablev<version>/copies, then writeslatest-insider.jsonlast. It never toucheslatest.jsonor the mutable rootvlx-*pointers, so a bad insider build can't strand stable clients. Requires the sameBLOB_ACCOUNT/BLOB_KEY/BLOB_CONTAINER/BLOB_BASE_URLenv 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 tomain(which ships stable via the pipeline).
Required pipeline variables
Set under Pipelines → Edit → Variables:
| Variable | Purpose |
|---|---|
BLOB_ACCOUNT | storage account name |
BLOB_CONTAINER | release container (public blob read) |
BLOB_KEY | storage account key (secret) |
BLOB_BASE_URL | public base URL of the container |
SWA_DEPLOY_TOKEN | Static 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.