Quivvo CLI
quivvo is the command-line client for Quivvo machines. It needs Node.js 22 or later and has no dependencies.
command -v quivvo >/dev/null || npm i -g quivvo@latest
npx quivvo@latest works without installing, but leaves nothing on your PATH, so every later command has to start with it too.
Credentials live in ~/.config/quivvo/credentials.json (mode 0600). QUIVVO_API_KEY and QUIVVO_API_URL override them. The default API URL is https://tryquivvo.com. The CLI talks to that and, for ssh, cp, push and port-forward, directly to the machine at *.fly.dev, so a restricted network has to allow both.
How do scripts and agents use it?
--jsonon any command prints one JSON document on stdout, errors included, and nothing on stderr. Warnings go inside the document. Following a stream (exec --stream,jobs logs -f) prints one JSON document per line instead.- Errors under
--jsonhavecode,message,retryable,retry_after_seconds,status,exit_code,hint,docs_url,request_idandowner_action. Errors lists the codes. Ifhintnames a step you may take, take it first, such as suspending a machine to make room.owner_actionis what only the workspace's owner can do, so pass that on when nothing else works. - Remote exit codes pass through.
exec,run,ssh,jobs waitandjobs logs -fexit with the remote command's code, which can be 2, 3 or 75 too. Under--json, look for theerrorkey rather than going by the code alone. The one difference:jobs waitkeeps 124 for "still running", so a job that hit its own timeout exits 1 there and 124 fromjobs logs -f. - No terminal.
shopens no shell and waits for nobody: with no key it exits 3 and namesquivvo login --agent --no-wait --json, and with a key it gets the machine running and prints the nextexec.quivvo sh dev -- uname -aruns that command and exits with its code.sshdoes the same, on a machine that exists. - Tool timeouts.
execprints output as it's produced, so what ran before a kill is already on stdout, but the kill stops the command. Under--jsonwithout--stream, or with--tail-bytes, nothing prints until the end, so get it back withquivvo historyand thenquivvo output. If it might outlast your tool's timeout (often 120 seconds), use--background.runwaits for the whole command too:run --no-waitstarts a job instead. - Safe retries. A
createthat fails leaves nothing behind, with one exception: when--wait-setupfails, the machine is there, running and billing, so you can read the script's log. Delete it withquivvo rm.--idempotency-keygets the first answer back within 24 hours, and a different request with the same key is aconflict.--if-not-existsuses the machine if it's already there, andcreatedunder--jsonsays which. It won't run a setup script a second time. Repeatingrmorsnapshot rmsucceeds.forklists partial failures infailedand exits with the first failure's code, so a 5 doesn't mean nothing was made:machineslists the copies it did make, which are running and billing, andhintsays how to delete them. - Limits. A command that waits for its result stops at 280 seconds, which is also its default. With
--background, the default is 3600 and the most is 86400. See recipes. - The queue.
quivvo queueprints your place, how many have joined from your link, and the link. While a workspace is waiting,whoamishows the same, and whatever creates a machine exits 5 with the codequeued. Pass the link to the owner and stop: retrying won't help. - Keys.
quivvo logingets a key that drives machines.keysandclaimalso needkeys:write, which you tick when you approve the sign-in. It's off by default because anyone can start a sign-in and send you the link. A key with onlymachines:readcancpa single file off a running machine and nothing else of what opens a connection: copying a directory or uploading,push,sshandport-forwardneedmachines:write. - Secrets. A bare
--env KEYforwards your local value, and it stays out of history. The command text doesn't. - stdin. A command gets none unless you pass
--stdin, even from a pipe, because a stdin that never closes would hang it. When a pipe or file was given without it, the CLI warns that it was ignored.--stdintakes up to 1 MB. - Binary data.
execis for text. Its plain stdout and--stdincarry binary bytes unchanged, but--jsonand--tail-bytescan't, and say so inwarnings. Usecpandpushfor files. pushandcpdiffer.pushsends what git tracks and new files, with no.gitand none of what usually holds a credential, tracked or not:.envand its variants such as.env.*andprod.env,.ssh,.aws,*.pem,.netrc,*.tfvars,.mcp.json, cloud service-account files, and the logins in.claudeand.codex. That's a list of names, so it can't catch everything. It says what it left out, and--includesends it.cpsends everything you point it at, and copying into an existing directory nests, likecp. Bringing a directory back from a machine leaves out.git/hooks, because an agent had root there and the nextgit commiton your computer would run them..git/config,.envrcand.vscode/tasks.jsoncan run commands too, so read what you bring back before you work in it.
Exit codes
| Code | Meaning |
|---|---|
0 |
ok |
1 |
something else went wrong |
2 |
the command line or a request was wrong |
3 |
not signed in, or this key isn't allowed to |
4 |
no such machine, job, snapshot or file |
5 |
a plan limit, or out of credit: the error says who can fix it |
75 |
nothing changed and it may work later: run it again |
76 |
login: the code expired; run it again for a new one |
77 |
login: the workspace's owner denied it |
124 |
a wait or the command's timeout ran out |
125 |
exec or run itself failed, so the command's result is unknown |
| otherwise | exec, run, ssh, jobs wait and jobs logs -f exit with the remote code |
Environment
| Variable | Meaning |
|---|---|
QUIVVO_API_KEY |
Use this key instead of the saved credentials |
QUIVVO_API_URL |
API to talk to (default https://tryquivvo.com) |
QUIVVO_DEBUG |
Log every request to stderr |
NO_COLOR |
Plain output |
Commands
<m> is a machine's name or id. Every command also takes --json and --help. Run quivvo <command> --help for what each flag does, or quivvo help --json for all of it as data.
quivvo sh [name] [--template T] [--size S] [--region R] [-- cmd...]
Sign in if needed, create or resume a machine (default "dev"), open a shell
quivvo init [--client claude|codex|cursor ...] [--yes] [--dry-run] [--project] [--inline-key] [--no-skill] [--no-mcp]
Set up the skill and the MCP server for the AI tools on this computer (shows a checklist first)
quivvo login [--agent] [--name N] [--scope S ...] [--no-wait] [--no-browser]
Sign in with a device code (opens the browser unless --agent)
quivvo logout [--revoke]
Remove the saved credentials
quivvo whoami
Show the workspace, plan limits, and what this key may do
quivvo queue
Show your place in the queue and your invite link
quivvo create [--name N] [--template T] [--size S | --vcpus N --mem-mib M] [--disk G] [--region R] [--snapshot S] [--setup-file PATH] [--env K[=V] ...] [--auto-suspend MIN] [--delete-after MIN] [--if-not-exists] [--idempotency-key KEY] [--wait-setup] [--no-wait]
Create a machine (waits until it's running)
quivvo ls [--all] [--state S]
List machines
quivvo get <m>
Show a machine (with its daemon's status when it's running)
quivvo exec <m> [--stream] [--background] [--cwd D] [--env K[=V] ...] [--timeout SEC] [--tail-bytes N] [--stdin] [--] <cmd...>
Run a command and print its output; exits with the command's exit code
quivvo run [--push DIR] [--timeout SEC] [--keep] [--no-wait] [--cwd D] [--env K[=V] ...] [--template T] [--size S] [--region R] [--name N] [--] <cmd...>
also: --include PATTERN, --exclude PATTERN
One command on a throwaway machine: create, optionally push, run, delete
quivvo ssh <m> [--print] [--cwd D] [-- cmd...]
Interactive shell on the machine; --print shows an OpenSSH command
quivvo ssh-proxy <m> [--port N]
Pipe stdin/stdout to the machine's port 22 (an OpenSSH ProxyCommand)
quivvo cp <src> <dst> [--exclude PATTERN ...]
Copy files or directories to or from a machine (`m:/path` marks the machine side)
quivvo push <local-dir> <m>[:path] [--exclude PATTERN ...] [--include PATTERN ...]
Upload a directory, honouring .gitignore (default: ~/<its name> on the machine)
quivvo jobs ls <m>
List a machine's jobs, newest first
quivvo jobs logs <m> <job> [-f] [--tail N] [--offset BYTES]
Print a job's output (stdout and stderr interleaved)
quivvo jobs wait <m> <job> [--timeout SEC]
Wait for a job to end; exits with its exit code
quivvo jobs kill <m> <job> [--signal TERM|KILL|INT]
Signal a job's process group (default TERM)
quivvo ps <m>
List processes on a machine
quivvo history <m> [--limit N]
Commands run with exec, newest first (works while stopped)
quivvo output <m> <exec-id>
Print a past exec's output (the first 16 KiB and last 48 KiB of each stream)
quivvo logs <m> [--lines N]
Boot and daemon log; of a machine that isn't running, its state, error and the provider's events
quivvo status <m>
The machine daemon's status: uptime, idle time, sessions, memory, disk
quivvo suspend <m> [--no-wait]
Suspend a machine (keeps memory and processes when it can; otherwise it stops)
quivvo resume <m> [--no-wait]
Resume a suspended machine
quivvo stop <m> [--no-wait]
Stop a machine (the disk is kept)
quivvo start <m> [--no-wait]
Start a stopped machine
quivvo restart <m> [--no-wait]
Power-cycle a machine
quivvo rm <m> [--yes]
Delete a machine and its disk (asks first)
quivvo snapshot save <m> --name N [--no-wait]
Save a machine's disk as a snapshot
quivvo snapshot ls
List snapshots
quivvo snapshot rm <name> [--yes]
Delete a snapshot (by name or id)
quivvo restore <m> --snapshot N [--yes] [--no-wait]
Replace a machine's disk with a snapshot's (same id, name and URL). What's on /data now is lost, and anything installed outside /data may be too
quivvo fork <m> [--count N] [--name N] [--no-wait]
Copy a machine's disk into new ones
quivvo port publish <m> <port> [--private]
Serve a port on the machine's URL
quivvo port unpublish <m> <port>
Stop serving a port
quivvo port ls <m>
List published ports
quivvo port-forward <m> <remote-port>[:<local-port>]
Forward a local port to a port inside the machine (private, no publishing)
quivvo desktop <m> [--stop] [--no-browser]
Start a machine's desktop and open it in the dashboard (--stop stops it)
quivvo auto-suspend <m> <minutes>
Suspend after this many idle minutes (0 turns it off)
quivvo resize <m> [--vcpus N --mem-mib M] [--disk G]
Change CPU and memory (while stopped) or grow the disk (any time)
quivvo usage
This period's cost, credit balance and per-machine usage
quivvo catalog
Templates, sizes and regions you can create machines with
quivvo keys ls
List API keys
quivvo keys create --name N [--scope S ...]
Create an API key (the secret is printed once)
quivvo keys rm <id>
Revoke an API key
quivvo feedback <message...> [--machine M] [--context TEXT]
Tell us something went wrong or could be better
quivvo claim <CODE> [--yes] [--deny] [--scope S ...]
Approve (or --deny) a sign-in code shown by `quivvo login --agent`
quivvo mcp init claude|cursor|codex [--project] [--inline-key]
Write the hosted MCP server into an AI tool's config, referring to $QUIVVO_API_KEY
quivvo mcp start
A stdio MCP server that forwards to the hosted one
quivvo agent prompt <m> [--provider claude|codex] [--cwd D] [--env K[=V] ...] [--model M] [--continue RUN] [--name KEY] [--timeout SEC] [--budget USD] [--] <text>
Start a run; prints its id
quivvo agent wait <m> <run> [--timeout SEC]
Wait for a run: 0 done, 1 the agent failed, 124 still running
quivvo agent result <m> <run> [--diff]
Print what a run came back with; exits like `agent wait`
quivvo version
Print the CLI version
Updated 8 November 2026
Give your agent a computer
npx quivvo@latest sh