CLI#

The dormo CLI is a thin layer over the REST API. Everything it does, you can do with the API.

Install and log in#

Install script#

Available once the first CLI release is tagged. The script installs a prebuilt binary for Linux or macOS (amd64 or arm64); run curl -fsSL https://dormo.dev/install.sh | sh in a terminal.

It detects your OS and architecture, downloads the matching archive from the project's GitHub Releases, verifies its SHA-256 against the release's checksums.txt and installs dormo to ~/.local/bin (or /usr/local/bin when run as root). Optional environment variables:

Variable Effect
DORMO_VERSION Install a specific version, e.g. DORMO_VERSION=0.2.0. Default: the latest stable release.
DORMO_INSTALL_DIR Install somewhere else, e.g. DORMO_INSTALL_DIR=$HOME/bin.

Each release also ships a signed checksum file and SBOMs; the release notes list the cosign and gh attestation verify commands.

Build from source#

Until the first release, and during the private beta, the CLI is built from source (Go 1.27.3+, standard library only); beta participants get access to the source repository:

cd cli && go build -o dormo . && sudo mv dormo /usr/local/bin/

Log in#

dormo login                              # prompts for an API key (opens the dashboard to create one)
dormo login --key-stdin < key.txt        # non-interactive (CI)
dormo whoami

Coming soon: an npm wrapper (npm install -g @dormo/cli) and browser-based login. Until then, dormo login asks you to paste a key created in the dashboard.

Credentials are stored in ~/.config/dormo/config.json. The DORMO_API_KEY environment variable takes precedence.

Global flags: --json (machine-readable output; on automatically when stdout is not a TTY), --api-key <key>, --api-url <url>, --quiet.

Cheat sheet#

dormo create --template base --size default --name dev   # prints the sandbox ID
dormo list                                               # your sandboxes (deleted ones hidden)
dormo exec <id> -- npm test                              # exit code = command's exit code
dormo shell <id>                                         # PTY session: prints its WebSocket URL
dormo ssh <id>                                           # SSH through the gateway
dormo cp ./app <id>:/home/user/app -r                    # upload a directory
dormo port expose <id> 3000 --public                     # https://<short_id>-3000.dormo.host
dormo pause <id>                                         # $0 compute while paused
dormo fork <id> --name dev-copy                          # copy with memory
dormo fork <id> --count 5 -q                             # 5 copies, all or nothing; prints 5 IDs
dormo desktop <id> --ttl 10m --read-only --open          # open the desktop in a browser
dormo screenshot <id> -o screen.png
dormo input <id> '[{"action":"left_click","coordinate":[640,412]}]' -o after.png
dormo delete <id> --yes

Commands#

Sandboxes#

Command Description API
create [flags] Create a sandbox. Flags: --template <name>, --snapshot <snap_id>, --image <ref>, --size small\|default\|large, --name, --label k=v (repeatable), --env K=V (repeatable), --idle-timeout 5m, --no-auto-pause, --always-on, --batch, --region auto\|eu-de\|eu-fi, --ttl 2h, --disk 100, --port 3000[:public] (repeatable), --no-wait POST /sandboxes
list [--state s] [--label k=v] [--all] List sandboxes. Sandboxes in state deleted are hidden unless you pass --all or --state deleted; --all shows them only if the API still returns them. A guaranteed "recently deleted" view is coming soon. GET /sandboxes
get <id> Show a sandbox GET /sandboxes/{id}
update <id> [flags] --name, --label k=v, --idle-timeout 15m, --no-auto-pause, --always-on, --no-always-on, --ttl PATCH /sandboxes/{id}
pause <id> Pause (RAM + disk snapshot) POST /sandboxes/{id}/pause
resume <id> Resume POST /sandboxes/{id}/resume
fork <id> [--count N] [--name] [--label] Fork with memory. --count (-n) 1–50 creates N forks in one call, all or nothing; prints a table (-q: one ID per line, --json: array of sandboxes) POST /sandboxes/{id}/fork
delete <id> [--yes] Delete permanently DELETE /sandboxes/{id}

Exec and terminals#

Command Description API
exec <id> [--cwd] [--env K=V] [--user] [--timeout 300] [--background] -- <cmd...> Run a command; streams output; exits with its exit code. --background prints the command ID. POST /sandboxes/{id}/exec
commands list <id> Recent commands GET /sandboxes/{id}/commands
commands logs <id> <cmd_id> [--follow] Output of a command: replays earlier output, then follows until the command exits (the API has one replay-and-follow stream, so --follow currently changes nothing). Alias: dormo logs. GET .../commands/{cmd_id}/stream
commands kill <id> <cmd_id> [--signal SIGKILL] Signal a command POST .../commands/{cmd_id}/kill
shell <id> [--user] [--cwd] Creates a PTY session and prints its websocket_url (valid 60 s until first connect). A built-in interactive terminal is coming soon; use dormo ssh meanwhile. POST /sandboxes/{id}/pty
ssh <id> [--key file.pub] [--ttl 1h] [--user u] [--print] [-- ssh args] SSH via ssh.dormo.host. Sends your local public key (default ~/.ssh/id_ed25519.pub, id_ecdsa.pub or id_rsa.pub) as a temporary key for this sandbox; nothing is stored on your account. --print only prints the command. POST /sandboxes/{id}/ssh

Files#

Command Description API
cp <src> <dst> [-r] Copy local ↔ sandbox. Sandbox paths are <id>:/path. /files/upload, /files/content, /files/download
files ls <id> <path> [-R] List GET /sandboxes/{id}/files
files cat <id> <path> Print a file GET .../files/content
files rm <id> <path> [-r] Delete DELETE /sandboxes/{id}/files
files watch <id> <path> Print change events GET .../files/watch

Networking and desktop#

Command Description API
port expose <id> <port> [--public] Public HTTPS URL POST /sandboxes/{id}/ports
port ls <id> / port rm <id> <port> List / remove GET, DELETE .../ports
token create <id> [--ttl 1h] [--port 3000] Access token for private ports POST .../access-tokens
ssh-key add <file.pub> / ssh-key ls / ssh-key rm <id> Account SSH keys /ssh-keys
desktop <id> [--ttl 10m] [--read-only] [--single-use] [--open] Desktop stream URL POST /sandboxes/{id}/desktop
screenshot <id> [-o shot.png] [--scale 0.5] [--format png\|jpeg] [--region x0,y0,x1,y1] Save a screenshot GET .../screenshot
input <id> '<actions JSON>' [-o after.png] [--coordinate-scale 0.5] Send mouse and keyboard actions: a JSON array of input actions (a single object also works; - reads stdin). -o saves a screenshot taken after the last action. POST .../input

Snapshots and templates#

Command Description API
snapshot create <id> [--name] [--no-memory] Named snapshot POST /sandboxes/{id}/snapshots
snapshot ls [--sandbox <id>] / snapshot rm <snap_id> List / delete /snapshots
template create --name <n> (--image <ref> \| --snapshot <snap_id>) [--start-command] [--ready-check <cmd>] [--desktop] Create a template POST /templates
template ls / template logs <name> [--follow] / template rm <name> Manage templates /templates

Account#

Command Description API
key create --name <n> (--preset ci \| --scope exec ...) [--label k=v] [--sandbox <id>] [--expires 30d] Create an API key POST /api-keys
key ls / key rotate <id> / key revoke <id> Manage keys /api-keys
webhook create --url <url> --event sandbox.ready [--event ...] Create a webhook POST /webhooks
webhook ls / rm / rotate / test Manage webhooks /webhooks
usage [--group-by none\|sandbox\|day\|size\|label\|template] [--label-key customer] [--from] [--to] Usage and cost GET /usage
limits Plan, concurrency, rate limits GET /limits
spend-limit set <usd> [--on-limit pause_running\|block_new] / spend-limit clear Spend limit PUT /account/spend-limit
mcp [--read-only] [--tools a,b] Run the local MCP server on stdio (starts npx -y @dormo/mcp; needs Node.js and the published @dormo/mcp package, coming soon to npm) see MCP

CI example#

dormo login --key-stdin <<< "$SANDBOX_API_KEY"
id=$(dormo create --template base --size large --batch --ttl 1h --json | jq -r .id)
trap 'dormo delete "$id" --yes' EXIT
dormo cp . "$id":/home/user/repo -r
dormo exec "$id" --cwd /home/user/repo --timeout 600 -- npm ci '&&' npm test

--batch halves the compute price; the sandbox may wait briefly in queued, and exec waits for it to start.