---
name: cloudgpu-compute
description: >
  Find GPU compute on CloudGPU, estimate what a task will cost, and, with the
  user's approval, rent a GPU with a server-enforced budget and time limit, run
  code on it, collect the results and shut it down. Use when a task needs CUDA
  or a GPU that the local machine does not have: model training or fine-tuning,
  inference, image or video generation, or batch processing.
---

# CloudGPU compute

CloudGPU (https://cloudgpu.app) rents GPUs billed per minute from a prepaid USD
balance. Discovery and quotes need no account. Running anything needs an API key
in the `CLOUDGPU_API_KEY` environment variable; without one, ask the user to
approve you through a connect link (below). Full guide:
https://cloudgpu.app/docs/agents · OpenAPI: https://cloudgpu.app/openapi.json

## When to use it

- The task needs a GPU (CUDA, more VRAM than the local machine, or faster runs).
- The user has agreed to pay for GPU time, or you are only checking prices.

## Workflow

1. **Discover.** `GET https://cloudgpu.app/v1/public/gpu-catalog` lists GPU
   models, `vram_gb`, `price_per_gpu_hour_usd`, `availability`, billing rules,
   `disk_options` and `templates`. No key needed.
2. **Quote.** `POST https://cloudgpu.app/v1/quotes` with
   `{"requirements": {"min_vram_gb": N, "gpu_count": 1}, "estimated_duration_seconds": S, "max_budget_usd": "X"}`.
   Send the API key too, if you have one, to get `can_start_with_balance`.
3. **Ask the user.** Show the chosen candidate's `estimated_total_cost` and
   `required_starting_balance`, and get an explicit yes before spending money.
   `within_budget: true` does not mean the balance can start the instance.
4. **Run a job** when the work is one command, on a candidate with
   `supports_jobs: true`. `POST https://cloudgpu.app/v1/jobs`
   with the key, an `Idempotency-Key` header (a new UUID per job),
   `{"quote_id": "...", "command": "...", "max_minutes": N, "max_spend_usd": X}`.
   CloudGPU starts the GPU, runs the command and destroys the GPU. The disk is
   erased at the end, so the command must upload its results to storage the
   user named, or print them.
5. **Watch.** `GET https://cloudgpu.app/v1/jobs/{id}` about once a minute until
   `status` is `succeeded`, `failed` or `cancelled`. `GET .../logs` has the last
   ~4 KB of output. Then report `cost_usd` to the user.

For interactive work, rent an instance instead: `POST /v1/gpu/instances` with
`quote_id`, `max_minutes` and `max_spend_usd`; poll `GET /v1/gpu/instances/{id}`
until `running`; work over SSH; download results; then
`POST /v1/gpu/instances/{id}/destroy`.

If the client has the CloudGPU MCP server (`npx -y cloudgpu-mcp`), prefer its
tools: `run_job`, `get_job`, `cancel_job` for jobs, and `create_instance`,
`upload`, `run_command`, `tail_logs`, `download`, `stop_instance` for instances.

## No API key: connect link

1. `POST https://cloudgpu.app/v1/agent/connect` with
   `{"agent_name": "<who you are>", "spend_limit_usd": <what the user wants>, "max_concurrent": 1}`.
2. Show the user `verification_uri_complete` and ask them to open it, sign in
   and approve. They may lower the limits.
3. Every `interval` seconds, `POST https://cloudgpu.app/v1/agent/connect/token`
   with `{"device_code": "..."}` until it returns `api_key` (once). Store it
   where the user wants; never print it.

That key cannot spend more than its limit or run more than `max_concurrent`
jobs or instances at once, and the user can revoke it at any time.

## Safety rules

- Never start a paid instance without the user's explicit approval of a quote.
- Never exceed the budget the user gave. Set `max_spend_usd` to it.
- When you retry a job, send the same `Idempotency-Key`; never invent a new key
  for a retry.
- Never print, log or commit the API key.
- Do not change passwords, SSH settings, the firewall or the platform's
  monitoring agent on the instance.
- If anything fails, download what exists and destroy the instance rather than
  leave it running.

## Errors and retries

| Response | What to do |
|---|---|
| `409 quote_expired` | Request a new quote, show it to the user again, then retry |
| `409 gpu_unavailable` | Pick another GPU from a new quote |
| `409 price_changed` | Request a new quote and check it against the user's budget again |
| `409 quote_mismatch` | Make `gpu_count`, `template` and `disk_gb` match the quote, or quote the new configuration |
| `402 insufficient_balance` | Ask the user to top up; do not retry until the balance covers `required_starting_balance` |
| `401` | The key is missing or invalid; ask the user for a valid key |
| `429` | Wait and retry later; do not loop quickly |
| Job create times out | Send the same request with the same `Idempotency-Key`; you get the same job back |
| `409 idempotency_key_reused` | That key belongs to another job; use a new key for a new job |
| `403 key_budget_exceeded`, `429 key_concurrency_exceeded` | This key's limits; lower `max_spend_usd`, wait for a job to finish, or ask the user |
| `401 credential_revoked` | The user revoked or let the key expire; connect again |
| Job `status` is `needs_attention` | CloudGPU stopped it to check by hand; tell the user and do not resubmit |
| Instance create times out | **Do not retry blindly**: instance creates take no idempotency key. List `GET /v1/gpu/instances` for one created in the last few minutes with the same GPU model; if you find an extra one, destroy it |
| Instance `status` becomes `failed` | Nothing is running; you may quote and try another GPU |

## Billing

Per minute, rounded up, with a 1-minute minimum. One hour is pre-authorised
while an instance runs, and unused minutes go back to your balance when you
destroy the instance. There is no subscription and no minimum term.

## Files

CloudGPU does not keep files. A job's or instance's disk is erased when it
ends.
