voxalsh
v0.1.8
Published
Voxal CLI for creating and deploying interactive terminal apps over SSH
Maintainers
Readme
voxal
The developer CLI for building and deploying interactive terminal apps that anyone can
reach with ssh <app>@voxal.sh. You write a small JavaScript app against
@voxalsh/sdk; voxal deploy bundles it,
validates that it boots, and ships it. No shell is ever exposed: each SSH session is wired
to your sandboxed app.
Full documentation: docs.voxal.sh.
Install
npm install -g voxalshThis installs the voxal command (and a voxalsh alias). You can also run it without
installing: npx voxalsh login. Requires Node.js 20 or newer.
Quick start
voxal init myapp # connect/create a project, then scaffold ./myapp
cd myapp && npm i
voxal dev # preview locally, reload on save (Ctrl-C to stop)
voxal deploy # bundle, validate, and ship it
ssh [email protected] # reach your running appvoxal init runs an interactive menu to connect an existing project or create a new
one, writes the result into voxal.json, and scaffolds the app. If you are not logged in
yet, it offers to log you in inline and then continues. From then on voxal deploy is
non-interactive: it reads the linked project from voxal.json.
Commands
| Command | Description |
| --- | --- |
| voxal init [name] | Connect or create a project, then scaffold the app in ./<name> with the linked project written into voxal.json. |
| voxal dev [dir] | Run the app locally against your own terminal, with no server and no deploy. Reloads on save. Press q or Ctrl-C to stop. Needs a TTY. Runs the app inside an isolated-vm Isolate — the same sandbox as production — so a cloned/untrusted app can't touch your files, env, or keys. If isolated-vm can't load (no C++ toolchain) it falls back to running in-process and prints a loud warning. |
| voxal build [dir] [--out <file>] | Produce the exact production bundle deploy would upload, validate it boots, and write it to dist/<name>.js (or --out). Offline, no login. |
| voxal login [--no-browser] | Log in via the browser. --no-browser prints the URL instead of opening it, handy on headless boxes. |
| voxal logout | Log out and revoke this machine's token. |
| voxal whoami | Show the signed-in account, plan, this month's usage (apps used, active-hours against the plan budget, concurrent-connection ceiling), and your projects. |
| voxal deploy [dir] [--name <n>] | Resolve a project (from voxal.json or --name), bundle and validate the app, and deploy. Offers inline login if needed. |
| voxal env set KEY value | Set an encrypted app secret (the value is also accepted on stdin, e.g. echo "$KEY" \| voxal env set STRIPE_KEY). Read it in your app with env('KEY'). |
| voxal env ls | List a project's secret keys (values are write-only and never shown). |
| voxal env rm KEY | Delete a secret. |
| voxal projects [rm <name>] | List your projects, or delete one. |
Flags
| Flag | Meaning |
| --- | --- |
| --name <n> | Target project for deploy. |
| --out <file> | Output path for build. |
| --no-browser | Print the login link instead of opening a browser. |
| --token <t> | Authenticate a single command without an interactive login, for CI. Pair it with --name. Equivalent to the VOXAL_TOKEN environment variable. |
Configuration and security
- Your token is stored in
~/.voxal/config.jsonwith private (owner-only) permissions, so a leaked token is not world-readable. - The token is only ever sent over TLS to a trusted host. Dashboard/host/api URLs must be
https:unless they point at loopback (localhost/127.0.0.0/8/::1) for local dev — plainhttp:to any remote host is refused, so the bearer token can never go out in cleartext. If a resolved endpoint is neither the built-invoxal.shdefault nor loopback (e.g. a strayVOXAL_HOST/VOXAL_API/VOXAL_DASHBOARDenv var or a poisoned config), the CLI prints a one-time warning before sending the token.voxal loginpersists endpoint overrides only when you pass them as explicit flags, never values picked up from env vars or defaults. voxal loginshows a verification code. Confirm the code in your terminal matches the one on the/clipage before authorizing — this stops a phishing page from tricking you into authorizing someone else's login. The CLI also holds a secretverifierit proves on claim (PKCE-style), so even if the login URL'sstateleaks, only your terminal can claim the token.voxal logoutrevokes the token, so a stolen config cannot be reused.- App secrets (
voxal env) are end-to-end encrypted. Each value is sealed to the box's public key on your machine and only the ciphertext is uploaded — the dashboard stores it but can never read it, and it never appears in your bundle. For the production host the trusted key fingerprint is baked into the CLI, so the CLI refuses to seal if the served key doesn't match (no first-use window to exploit); self-hosted/local origins pin on first use (TOFU) instead.voxal env lsshows keys only; values can't be read back. voxal devsandboxes app code in anisolated-vmIsolate (see the command table); only the no-toolchain fallback runs it in-process, and that path warns first.- Every network call is bounded by a timeout, so a stalled server cannot hang the CLI.
- Every deploy is integrity-checked from build to boot, so the bytes that run are exactly the bytes you built.
- Bundles are capped at 5 MiB (warning past 4 MiB).
License
MIT
