---
name: quivvo
description: Create and drive cloud Linux machines for AI agents with Quivvo. Use when you need a full computer away from the user's laptop to run untrusted or long-running code, use Docker, start servers with a public URL, or try several attempts in parallel. Triggers on quivvo, cloud machine, cloud VM, remote sandbox, and running something "somewhere safe".
---

# Quivvo

Quivvo gives you a Linux machine in the cloud: a Firecracker microVM with root and a persistent disk at `/data` (home is `/data/home`). Machines suspend when idle and wake on the next command.

## Install and sign in

```bash
command -v quivvo >/dev/null || npm i -g quivvo@latest
quivvo whoami --json
```

If that exits 3 you aren't signed in. This never blocks:

```bash
quivvo login --agent --no-wait --json
```

Send your owner `message_for_owner` and end your turn: nothing exists until they approve. Run the same command again later. It checks once and exits 0 approved, 75 still pending, 76 expired (run it again for a new code), or 77 denied. The run that issues the code exits 0 too, so read `status`.

New accounts wait in a queue for now. Run `quivvo whoami --json`: if `queue.waiting` is true, tell your owner `queue.position` and `queue.invite_url`, and stop.

## Use a machine

```bash
quivvo create --name work --if-not-exists      # 2 vCPU, 4 GiB, Docker, Node, Python, Go, gh, Claude Code, Codex
quivvo exec work -- "cd /data/home && npm test"
quivvo push ./api work                         # what git tracks, no .git, no .env
quivvo cp work:/data/home/report.txt .
quivvo port publish work 3000                  # prints an HTTPS URL
quivvo snapshot save work --name base          # copies /data, nothing else
quivvo fork work --name attempt-2              # the same; on Free, suspend work first
quivvo rm work --yes                           # leaves its snapshots
quivvo snapshot rm base --yes
```

A command gets no stdin unless you pass `--stdin`, even from a pipe: `cat patch.diff | quivvo exec work --stdin -- patch -p1`. `exec` is for text: under `--json` binary output gets changed, and `warnings` says so. Move binary data with `quivvo cp` and `quivvo push`.

Add `--json` to any command: one document on stdout, errors included. With no terminal, `quivvo ssh work` opens no shell: use `exec`.

## Long work

A command that waits for its result stops at 280 seconds, and if your tool's timeout (often 120 seconds) kills `exec` first, the command stops too. Start anything that might outlast either as a job. It takes up to 86400 seconds (an hour by default) and goes on if you disconnect:

```bash
JOB=$(quivvo exec work --background --timeout 1800 -- "npm test")
quivvo jobs wait work "$JOB" --timeout 100     # 124: still running, run it again
quivvo jobs logs work "$JOB" --tail 50
```

A job ends as `exited`, `killed` or `lost`: its process went away, usually because the machine restarted.

## One command on a throwaway machine

```bash
quivvo run --push . -- "npm ci && npm test"
```

It creates a machine, runs the command, deletes the machine and exits with its code. It waits throughout, so it's for work shorter than your tool's timeout. Add `--no-wait --timeout 1800` for anything longer: it starts a job and prints the machine and the job. If `run` gets SIGKILL, the machine stays and bills until the server deletes it, at the timeout plus 30 minutes: `quivvo ls`, then `quivvo rm <m> --yes`.

## Secrets

Pass them with `--env`. Command text is kept in history, and environment variables aren't. A bare `--env KEY` forwards your local value:

```bash
quivvo exec work --env GITHUB_TOKEN -- "gh repo clone acme/api"
```

## Hand a task to Claude Code or Codex

```bash
RUN=$(quivvo agent prompt work --env ANTHROPIC_API_KEY --cwd api --name fix-test -- "fix the failing test")
quivvo agent wait work "$RUN" --timeout 100    # 124: still running
quivvo agent result work "$RUN" --diff
```

Use `--provider codex --env CODEX_API_KEY` for Codex, or `--env CLAUDE_CODE_OAUTH_TOKEN` with a token from `claude setup-token`. Everything the agent runs can read these keys, as root, so only use code you trust with them.

## Exit codes

`0` ok. `2` bad command line or request. `3` not signed in, or this key isn't allowed. `4` not found. `5` a plan limit or out of credit: do what `hint` says if you can, and otherwise pass on `owner_action`. `75` nothing changed, run it again. `124` a wait or timeout ran out. `125` `exec` itself failed, so the command's result is unknown. A remote command can exit with these too, so under `--json` look for the `error` key.

## Rules of thumb

- Keep work under `/data`; it survives stops and restarts. Snapshots and forks copy only `/data`, so what `apt-get` installed isn't on the copy.
- Suspend keeps memory and processes when it can, and otherwise stops the machine, which keeps only the disk. `suspend_outcome` and `resume_outcome` under `--json` say which happened.
- A machine's URL serves one port, the last published, and doesn't wake a suspended machine.
- `quivvo port-forward` runs until it's killed, so start it in the background. With `--json` it prints the port at once.
- A running job keeps a machine awake and billing, so kill jobs you no longer need. A server started as a job ends at its `--timeout`, a day at most.
- Reading files or jobs wakes a stopped machine, and its bill. `ls`, `get`, `logs` and `ps` don't.
- Exit 137 with `oom_killed: true` means it ran out of memory: use a bigger size.
- The Free plan runs 1 machine at a time and keeps 3.
- Delete machines you're done with. `--delete-after MIN` on `create` makes that certain.

## More

- Recipes: https://tryquivvo.com/docs/recipes.md
- Every error code: https://tryquivvo.com/docs/errors.md
- All docs in one file: https://tryquivvo.com/llms-full.txt
- API: https://tryquivvo.com/api/v1/openapi.json
- Sizes and prices, without a key: https://tryquivvo.com/api/v1/catalog
- Something wrong? `quivvo feedback "what happened"`
