VPM
The VOLT Cloud plugin registry CLI — authenticate, publish, install, and manage VOLT plugin packages from the terminal.
TL;DR — vpm is the npm-installed CLI for the VOLT plugin Registry. It logs in via a device-code flow, publishes multi-platform plugin bundles, and installs them into a shared on-disk cache that the Python SDK and ClusterDaemon read from.
Overview
vpm (VOLT Package Manager) is a Node CLI for two services: the Registry (package metadata, bundles, search) and the Console (authentication, personal access tokens). CI publishes plugins with it on tag pushes (see plugin-development); run it directly to discover and install plugins.
| Package | @voltstack/vpm |
| Binary | vpm |
| Node | ≥ 20 |
| License | MIT |
| Registry | https://registry.voltcloud.dev |
| Console | https://server.console.voltcloud.dev |
| Links | GitHub · npm |
Installation
npm install -g @voltstack/vpm
vpm --versionAuthentication
vpm login
Runs an OAuth-style device-code flow against the Console: requests a code, prints a verification URL and user code, opens the browser (unless --no-browser), then polls until you approve. On success, stores the access/refresh tokens and your profile.
vpm login
vpm login --no-browser # print the URL/code, don't auto-openvpm whoami
Resolves the current bearer token against the Console; prints account id, email, and username. Exits non-zero if not logged in.
vpm logout
Revokes the refresh token on the Console and clears stored credentials. --keep-remote clears locally without revoking the server session.
Personal access tokens
PATs are non-interactive credentials for CI. Manage them with vpm token:
vpm token list # alias: ls
vpm token create --label "ci" --scope publish # prints the token ONCE
vpm token create --label "ci" --expires 2026-01-01T00:00:00Z
vpm token revoke <id>--scope is repeatable (default read); --scope-mask <n> sets a numeric bitmask; --expires takes an ISO 8601 timestamp. In CI, pass the resulting token to publish/deprecate via --token.
Credential storage
| Backend | Location |
|---|---|
OS keyring (default, via keytar) | service voltcloud, account default |
Falls back to the file backend when the keyring is unavailable or VPM_NO_KEYRING=1. Requests use the PAT if present, otherwise the stored access token.
Command reference
Discover
vpm search <query> [--kind workflow|engine|lib] [--page 1] [--page-size 20] [--json]
vpm info <@user/name> # packument: dist-tags, versions, downloads
vpm info <@user/name@version> # one version: publish info, size, sha256, platformsConsume
vpm install <@user/name>[@version|@tag|@range] # alias: i
vpm install @user/name --platform linux-x86_64 --force
vpm uninstall <@user/name>[@version] # alias: rm
vpm list # alias: ls — what's in the cacheinstall resolves the version (see Reference resolution), downloads the bundle for the current platform tag, extracts it into the cache, and makes files under bin/ and scripts/ executable. Workflow plugins also get their manifest cached. --force reinstalls over an existing copy.
Author & publish
vpm init --name @user/name --kind workflow|engine|lib [--version 0.1.0] [--publisher u] [--description d]
vpm pack [dir] [--out file.tgz]
vpm publish [dir] [--bundle <tag>=<path>...] [--bundle-dir ./bundles] [--token <t>] [--dry-run]
vpm deprecate <@user/name@version> "<message>" [--token <t>]The manifest (vpm.json)
init scaffolds a vpm.json; pack and publish find it by walking up from the target directory. Validated with Zod before any publish.
| Field | Required | Notes |
|---|---|---|
name | yes | @username/name — lowercase, must match ^@[a-z0-9][a-z0-9-]*\/[a-z0-9][a-z0-9._-]*$ |
version | yes | version string |
kind | yes | workflow · engine · lib |
publisher | yes | scope owner (defaults to the username from name) |
description | no | short summary |
license | no | SPDX id (scaffold defaults to MIT) |
homepage | no | URL |
repository | no | { type, url } |
keywords | no | string array |
entrypoints | no | { binary?, workflow? } |
nodeTypes | no | string array |
platforms | no | required platform tags — publish fails if a bundle is missing |
voltsdk / coretoolkit | no | compatibility hints |
files | no | glob-ish top-level entries to include in pack (scaffold: ["dist","bin"]) |
Publishing flow
vpm publish builds a multipart PUT /packages/:user/:name request:
- Resolve the manifest and confirm
nameis@user/name. - Collect platform bundles. Pass
--bundle <tag>=<path>(repeatable), or let vpm auto-discover*.tgz/*.tar.gz/*.tar.zstfiles in./bundles(override with--bundle-dir). A bundle's tag is its filename up to the first dot, so name files after their platform tag, e.g.linux-x86_64.tar.zst. - Validate coverage. If the manifest lists
platforms, every listed tag must have a bundle; otherwise at least one bundle is required. - Attach
README.mdif present (becomes the rendered package readme). - Authenticate with the stored token or
--token. - Upload — manifest JSON + readme + each bundle blob.
--dry-runreports what would be sent and uploads nothing.
Server responses map to errors: 409 version already exists, 403 not authorized for that scope, 422 invalid manifest, 401 bad/missing token.
The Registry never serves bundles inline. install expects a 307 redirect to a signed URL; an inline 200 is treated as an error.
Building bundles
vpm pack produces a single gzipped tarball of the package directory (vpm.json, README.md, LICENSE, dist, bin by default, or vpm.json + the manifest's files). Use it for inspection and library packages. For native plugins, the per-platform .tar.zst bundles are produced by CoreToolkit's reusable CI workflow and uploaded by publish — see plugin-development.
Reference resolution
Plugin references, with an optional version suffix:
| Input | Meaning |
|---|---|
@user/name | scope/name |
@user/name@1.2.0 | exact version |
@user/name@latest | a dist-tag |
@user/name@^1.0.0 | semver range → highest match |
With no version, install uses the latest dist-tag. Resolution order: exact dist-tag → exact semver → semver range (maxSatisfying).
Platform tags
The platform tag is <os>-<arch>, derived from the host (override with --platform):
| OS | linux · darwin · windows |
|---|---|
| Arch | x86_64 (x64) · arm64 · i686 (ia32) |
Common tags: linux-x86_64, darwin-arm64, windows-x86_64.
Cache layout
All state lives under the cache root (VOLT_CACHE_DIR, else ~/.cache/volt):
<cache root>/
plugins/<publisher>/<name>/<version>/<platform>/ # extracted bundle
downloads/ # downloaded archives
manifests/<publisher>/<name>.json # cached workflow manifestsArchive formats
Downloaded archives are detected by magic bytes (with an extension fallback) and extracted accordingly:
| Format | Magic | Handling |
|---|---|---|
.tar.zst | 28 B5 2F FD | decompressed via @mongodb-js/zstd, then untarred |
.tar.gz / .tgz | 1F 8B | gzip untar |
.zip | 50 4B | extracted with the system unzip |
Registry & Console protocol
vpm is a thin client over these HTTP endpoints.
| Service | Method & path | Used by |
|---|---|---|
| Registry | GET /-/search | search |
| Registry | GET /packages/:user/:name | info, install |
| Registry | GET /packages/:user/:name/:version | info, install |
| Registry | GET /packages/:user/:name/:version/-/:platform.tgz | install (→ 307 signed URL) |
| Registry | PUT /packages/:user/:name | publish |
| Registry | POST /packages/:user/:name/:version/deprecate | deprecate |
| Console | POST /auth/device-code, POST /auth/device-token | login |
| Console | POST /auth/refresh, POST /auth/logout | session lifecycle |
| Console | GET /auth/whoami | whoami |
| Console | GET/POST /auth/tokens, DELETE /auth/tokens/:id | token |