Velven CLI
The Velven CLI publishes a folder to Velven, lists its versions, rolls back, and serves it locally inside Velven's page. It is the npm package @velven/cli, with no dependencies, for Node 20 or later.
Install
Run it with npx, or install it once and run velven:
npx @velven/cli publish ./dist# ornpm install -g @velven/clivelven publish ./distvelven help, or --help after any command, lists the commands and flags, and velven --version prints the release. velven-cli is the same tool under a second name.
login, logout, whoami
velven login # shows a code and opens velven.ai to approve itvelven whoami # @handle on https://velven.aivelven logout # forgets this computer's sign-inlogin is the same device-code sign-in an agent uses: approve the code in your browser and the token is saved in ~/.config/velven/auth.json, readable only by you, one per Velven address. It lasts 90 days. logout forgets it on this computer; revoke it for good in your settings. whoami --json prints { ok, api, handle, profileUrl, tokenFrom }.
publish
velven publish [dir] # a private preview of the folder (default: the current one)velven publish [dir] --prod # live once Velven's safety check passesvelven publish [dir] --prod --waitThe listing comes from velven.json in the folder. The first publish creates the space and writes "space" into velven.json; later publishes update it. When it cannot write the file (read-only, or a folder you cannot write to), it says so, prints what to put in velven.json (the slug, or without an account the claim token) and goes on with the publish; --json carries the sentence as notSaved. Only files Velven does not already have are uploaded.
--prod- Send the version to the safety check; it goes live when the check passes. Without it, the version is a preview for 24 hours.
--wait- Wait here for the preview link, or with
--prodfor the check's verdict, up to 20 minutes; it stops early when the check ended without a verdict (the space was hidden, held or moved, or its checks are over the hourly limit), and a publish checks it again. Without it, the CLI returns after the upload with a link to follow. --title <text>- Override
velven.jsonfor this run. Nothing is written back. --type <type>game,world,toolorwonder.--devices <list>desktop,mobile,vr, comma separated.--description <text>- One line, up to 160 characters.
--engine <engine>- An engine value, such as
three.js. --yes, -y- Never ask. A missing field fails with exit 2 and names every missing field.
--json- Print one JSON object, for scripts and agents.
In a terminal, a missing required field is asked for and your answer is saved in velven.json. Anywhere else, or with --yes or --json, the command fails and names the fields.
Signed out, publish makes an unlisted page: it prints the page, a claim token and a claim link, and saves the token in velven.json as "claim". --prod then exits 3. After velven login, the next publish from the folder claims the page.
versions and rollback
velven versions # the space's versions; * marks the live onevelven versions --json # { ok, space, versions: [{ id, number, status, createdAt, live, files, size, reason }] }velven rollback 3 # version 3 goes live againvelven rollback # in a terminal: lists the versions and asks whichA version's status is uploading, preview, checking, live, refused, unjudged (the check could not judge it), or replaced (a newer version took its place, or the space moved to another address before its check finished). A rollback goes only to a version that was live before.
versions, rollback and reset act on the space velven.json in the current folder names; --space <slug> picks another of yours.
dev
velven dev [dir] # serve the folder and play it on Velvenvelven dev [dir] --port 5173dev serves the folder on your machine, with no caching and the SDK tag added to the entry page as hosting adds it, and honours entry and spa. It opens https://velven.ai/dev, a Velven page that frames your local server with the player in sandbox mode. Signed in on Velven as the space's owner, sign-in, boards, saves, achievements, stats, content and rooms all work on the real API, and everything they write goes to the space's sandbox.
- The sandbox belongs to a space, so publish once first:
devreads the space fromvelven.json. Before that it serves the page, and SDK calls answerunavailable. To test with a friend, send them a preview instead. - Edit a file and reload the page to see it; there is no build step or watcher of its own. Point it at your build's output folder, or run your own dev server and open the
/devpage with its address. - It serves what
publishsends, by the same rule: nothing.velvenignorenames (a file under an ignored folder included), and dotfiles,node_modulesandvelven.jsonnever, in any case, nor a name that ends in a dot or a space or holds:or~, nor a link to anything outside the folder. A path is served only in the letter case the folder spells it, as the live version looks paths up:Assets/Hero.pngdoes not openassets/hero.png, even on a disk that ignores case. - Press Ctrl+C to stop.
Note: For work with no network at all, the SDK's local environment fakes players and boards on the page itself.
reset
velven reset # the whole sandbox, after a confirmationvelven reset --scores --saves # only these kindsvelven reset --player mara --yes # one player's sandbox data, without askingreset deletes the test data previews and velven dev wrote: --scores, --saves, --achievements, --content and --rooms, all of them by default. Live players' data is never touched. Sandbox data also clears itself 30 days after its last write.
Environment variables
VELVEN_TOKEN- A token to use instead of the saved sign-in, for CI. It takes precedence over
velven login. VELVEN_APIA web addressDefaulthttps://velven.ai- The Velven to talk to, when you run one of your own for development.
JSON output
With --json, publish, versions and whoami print one JSON object and nothing else, and every failure prints { ok: false, error, code, fields? }: error a sentence to show a person, code a stable name to branch on.
{ "ok": true, "space": { "slug": "star-hop", "url": "https://velven.ai/s/star-hop" }, "version": { "id": "…", "number": 4 }, "status": "live", "watchUrl": "https://velven.ai/s/star-hop/edit/files?version=…", "pageUrl": "https://velven.ai/mara/star-hop", "uploaded": 2, "reused": 37}status is preview with a previewUrl, checking without --wait, or the verdict with it, with reason and shownOnTake for a version refused or not judged. Signed out, it adds pageUrl, claimToken, claimUrl and expiresAt.
| Code | Meaning |
|---|---|
missing_fields | velven.json lacks a required field; fields names them. |
invalid_config | velven.json is not valid JSON, or a field has the wrong shape. |
no_entry | The folder has no index.html, or no file at entry. |
not_owner | space in velven.json is someone else's space. |
too_large, too_many_files | The version is over the limits; the largest files are named. |
sign_in_required | --prod without an account. |
claim_spent | Exit 3: signed out, with "claim" in velven.json for a page that was claimed (in the browser, say). Run velven login as the account that claimed it and publish again. Claimed while velven publish uploads: "The page was claimed before this version was finished. Run velven login and publish again." Claimed while --wait waits: "The page was claimed. Follow the check on its Files tab", with the link. |
rate_limited | Too many publishes; the sentence says when to try again. |
not_signed_in | A command that needs an account, signed out. |
- Code
missing_fields- Meaning
velven.jsonlacks a required field;fieldsnames them.
- Code
invalid_config- Meaning
velven.jsonis not valid JSON, or a field has the wrong shape.
- Code
no_entry- Meaning
- The folder has no
index.html, or no file atentry.
- Code
not_owner- Meaning
spaceinvelven.jsonis someone else's space.
- Code
too_large,too_many_files- Meaning
- The version is over the limits; the largest files are named.
- Code
sign_in_required- Meaning
--prodwithout an account.
- Code
claim_spent- Meaning
- Exit 3: signed out, with
"claim"invelven.jsonfor a page that was claimed (in the browser, say). Runvelven loginas the account that claimed it and publish again. Claimed whilevelven publishuploads: "The page was claimed before this version was finished. Run velven login and publish again." Claimed while--waitwaits: "The page was claimed. Follow the check on its Files tab", with the link.
- Code
rate_limited- Meaning
- Too many publishes; the sentence says when to try again.
- Code
not_signed_in- Meaning
- A command that needs an account, signed out.
Exit codes
| Code | Meaning |
|---|---|
0 | Done. |
1 | Failed: the network, a server error, a failed upload, or a cancelled prompt. |
2 | A mistake in the command or in velven.json, such as an unknown flag or a missing field. |
3 | Not signed in, or the token was refused, for something that needs an account, such as --prod. |
4 | Refused by Velven: not your space, too large, too many files, not found, invalid fields. |
5 | Rate limited. Try again later. |
6 | With --wait: the safety check refused the version or could not judge it. |
- Code
0- Meaning
- Done.
- Code
1- Meaning
- Failed: the network, a server error, a failed upload, or a cancelled prompt.
- Code
2- Meaning
- A mistake in the command or in
velven.json, such as an unknown flag or a missing field.
- Code
3- Meaning
- Not signed in, or the token was refused, for something that needs an account, such as
--prod.
- Code
4- Meaning
- Refused by Velven: not your space, too large, too many files, not found, invalid fields.
- Code
5- Meaning
- Rate limited. Try again later.
- Code
6- Meaning
- With
--wait: the safety check refused the version or could not judge it.
Publish from CI
Sign in once with velven login, copy the token from ~/.config/velven/auth.json into your CI's secrets as VELVEN_TOKEN, and make sure velven.json with "space" is committed. Then publish with no prompts and wait for the verdict, so the job fails when the check refuses the version:
# .github/workflows/publish.ymlon: push: branches: [main]jobs: publish: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 22 - run: npm ci && npm run build - run: npx @velven/cli publish ./dist --prod --yes --wait env: VELVEN_TOKEN: ${{ secrets.VELVEN_TOKEN }}Note: Revoke a token you no longer use in your settings. A refused token exits 3.