Skip to content

Stasho CLI ​

The Stasho CLI runs the agent API calls as terminal commands, for people and for agents that have a shell. It works with an agent key that you, the owner, create in the dashboard under Settings. It reaches every kind of project the key does: the site commands run uploaded sites, and the project commands read, redeploy and roll back uploaded sites, repo projects and App VM apps.

Prompt for your agent

Copy this into Claude Code, Cursor or any agent that can run shell commands.

text
Read https://docs.stasho.xyz/reference/cli.md and follow it to manage my Stasho projects.
Run stasho with npx @stasho/cli. My agent key (stasho_ak_…) is in the STASHO_AGENT_KEY
environment variable: never ask me to paste it in chat, and never write it into a file, code or
a commit. For a key created with My agent signs, the signing key is in STASHO_SIGNING_KEY or
saved by a prior stasho login on this machine. After every create and publish, tell me the url (it changes per version) and offer a
custom domain for a stable address. For a repo project or an App VM app, run stasho projects
first (a one-project key: run stasho project instead) and use each project's kind: publish for upload, deploy for the others. Read every error
to me, and stop on exit codes 2 and 3 when the message names something I must do. Ask me before
every delete, domain remove and rollback, and pass --yes only after I say yes.

Install ​

bash
npx @stasho/cli --help
# or
npm i -g @stasho/cli

It needs Node 22 or later. The examples below use the installed stasho command; with npx, write npx @stasho/cli in its place.

Log in ​

bash
stasho login

login generates a signing key the first time and keeps it on every later run, including after a failed login. It prints the key's public half and its address:

Signing public key: 0x04…
Signing address: 0x…

Then it asks for your agent key (stasho_ak_…), or reads it from STASHO_AGENT_KEY without asking. Without a terminal it reads one line from stdin, and exits 1 when stdin is empty or closed: set STASHO_AGENT_KEY, or run stasho login in a terminal. A STASHO_SIGNING_KEY that does not parse stops login with exit 1 and saves nothing. There are two kinds of agent key:

  • My agent signs. You create the key in the dashboard (Settings > Authorizations > Create key), choose My agent signs and paste the public signing key. The CLI signs the site records itself.
  • An ordinary key. You create the key as usual. Stasho's delegate writes the site records and the CLI signs nothing.

The credentials are saved in $XDG_CONFIG_HOME/stasho/credentials.json, or ~/.config/stasho/credentials.json when that is not set. The file is mode 0600 in a 0700 directory. In CI, skip the file and set STASHO_AGENT_KEY (and STASHO_SIGNING_KEY for a My agent signs key); both override the file. stasho logout deletes the file.

Commands ​

Every command takes --json, which prints one JSON object on stdout. Progress lines go to stderr, so stdout stays parseable in a pipe. publish, domain and delete take --site <id> (the site's projectId), or read STASHO_SITE_ID when the flag is absent; site takes the id as its argument. project, deployments, deploy and rollback take --project <id> instead, or read STASHO_PROJECT_ID; projects takes no id. An empty --site is refused rather than falling back to STASHO_SITE_ID, and a command refuses any argument it does not take, before it sends a request or asks a question.

Create a site ​

bash
stasho create ./dist --name "Launch page"

Zips the directory (index.html at its root) and creates a site. Prints projectId, deploymentId, url, cid and name. The url is the gateway URL of this version and changes with every version; a custom domain is the stable address. This is the create call, scope create.

create and publish leave .git out and refuse a folder with a .env or .env.* file at any depth, naming the file so you can move it out; every other dotfile, .well-known included, is published. The API holds any zip to the same rule, whichever tool made it.

If create exits 3 saying the site was created but its first version was not recorded, publish to the site id it names instead of creating again.

Publish a new version ​

bash
stasho publish ./dist --site <id>

Prints deploymentId, url, cid and domains. This is the publish call, scope publish.

List sites ​

bash
stasho sites

Prints one line per site: its id, its latest version's status and its url. This is the list call, scope publish, all-sites key only.

Read a site ​

bash
stasho site <id>

Prints the site's projectId, url, latest version status and each domain with its status. This is the read call, scope publish.

Attach a custom domain ​

bash
stasho domain add www.example.com --site <id>

Prints the DNS records to set, one per line. This is the attach call, scope domains.

A host must be a hostname like www.example.com. The CLI lowercases it and drops a trailing dot, and refuses anything else before sending a request.

Check a domain's DNS ​

bash
stasho domain check www.example.com --site <id>

Prints ok, or one missing: line per record that is wrong, each with its meaning. This is the check call, scope domains. It exits 0 and lists what is missing until the DNS is right, so read its output rather than its exit code.

Detach a domain ​

bash
stasho domain remove www.example.com --site <id>

Detaches the domain. On a terminal the CLI asks [y/N]; without one it refuses and needs --yes. This is the detach call, scope domains.

Delete a site ​

bash
stasho delete --site <id>

Deletes the site, with the same [y/N] question on a terminal and --yes otherwise. This is the delete call, scope delete.

List projects ​

bash
stasho projects

Prints one line per project: its id, its kind (upload, repo or app) and its url, with - where a value is absent. This is the list call, scope read, all-projects key only. A key for one project answers exit 3; use stasho project.

Read a project ​

bash
stasho project --project <id>

Prints projectId, kind, url and currentDeploymentId (the rollback in force, - when none is), then one domain: line per domain with its host and status (- for an App VM's domains, whose state lives on the VM). This is the read call, scope read. The kind says which verb ships a version: publish for upload, deploy for repo and app.

List deployments ​

bash
stasho deployments --project <id>

Prints one line per deployment, newest first: its id, status, live on the one serving (else -), run <runId> and its url. The runId is how you find the deployment that your stasho deploy made. This is the deployments call, scope read. With --json, the whole response.

Redeploy a project ​

bash
stasho deploy --project <id>

Builds and publishes the latest commit on the project's production branch, for a repo project or an App VM app. Prints projectId and runId (null when GitHub returned no run details) as soon as the workflow is dispatched; the build finishes later, so run stasho deployments --project <id> until the entry with that runId reads live. After about 15 minutes, stop and tell the owner the build has not finished, not that it failed: a slow build can still go live. A run that dies before its first report creates no deployment, and awaiting_resign (the owner must re-authorize) or, on an App VM app, pinned (waiting for the VM) will not become live on their own. An uploaded site exits 3 with use_publish: use stasho publish. This is the redeploy call, scope deploy. It spends one of the key's daily deploys. It never opens a pull request or writes to the repo: an unfinished setup exits 3 with setup_required, and a repo Stasho cannot reach with repo_unreachable, both for the owner to fix in the dashboard.

Roll back ​

bash
stasho rollback <deploymentId> --project <id>

Makes an earlier deployment live, without a rebuild. The deployment must have status: "live" and a stored build, from stasho deployments, and be one with live: false (rolling back to the serving build is charged and pins it, so a build already running then does not serve); any other exits 3 with not_rollbackable. Prints projectId and currentDeploymentId. This is the rollback call, scope rollback, and it spends one of the key's daily deploys (a refused one spends nothing). On an App VM project the key must be an All sites key created with My agent signs; any other key exits 3 with app_rollback_needs_signer, and the owner rolls back in the dashboard instead.

Undo a rollback ​

bash
stasho rollback undo --project <id>

Clears the pin, so the newest live version serves again. Prints projectId and currentDeploymentId (null). A project with no stored pin exits 3 with not_pinned. A pin a newer build has superseded reads as - in stasho project and is still stored, so an undo clears it and is charged as usual. The scope, budget and App VM rule are the rollback's. This is the undo call.

Signing ​

On a My agent signs key, create, domain add, domain remove, delete, rollback and rollback undo each answer with a message to sign. The CLI checks the message before it signs: that it is to be signed by the key it expects, that it writes exactly one project record (the one you named, for domain, delete and rollback; a new site has no id to name yet), and that the text it signs is the hash of that message. For a rollback it also checks the pin: the record must set currentDeploymentId to the deployment you named, and an undo must clear it. A record that pins anything else stops with exit code 2. Any mismatch stops with exit code 2 and nothing is signed. The CLI checks which site a signature writes; it does not judge the record's contents.

Your agent signs its own site records. Stasho still publishes the files and marks versions live, as it does from the dashboard, and gains no new permission over your sites.

The loop itself is described in Sign your own records.

Exit codes ​

codemeaning
0done
1usage, credentials or a refused input (including a destructive command without a yes)
2the CLI refused to sign: the message did not match
3the server refused: the message says what to change
4the server or the network is unavailable: retry later

Environment ​

variableuse
STASHO_AGENT_KEYyour agent key; overrides the credentials file
STASHO_SIGNING_KEYyour signing private key; overrides the credentials file
STASHO_SITE_IDthe site used when --site is not given
STASHO_PROJECT_IDthe project used when --project is not given
STASHO_API_URLoverrides the API base URL (--api does too)
XDG_CONFIG_HOMEwhere the credentials directory lives

Never pass a key as an argument: it would show in ps, shell history and CI logs.

Limits ​

The CLI is subject to the same limits as the key; see the Limits table.