vastai-sdk — Claude Code skill: Vast.ai GPU instances from Python
A skill that gives the agent a reference for the Vast.ai Python SDK: GPU instances, volumes and serverless endpoints. Useful when you rent GPUs and script the setup.
npx skills add vast-ai/vast-cli --skill vastai-sdk -a claude-code
npx skills add vast-ai/vast-cli --skill vastai_sdk -a claude-codeWhat vastai-sdk does
The skill hands the agent a map of the vastai package. The high-level VastAI class covers instances, volumes, templates and invoices; SyncClient and AsyncClient give typed access to offers and instances; Serverless handles inference endpoints. Examples walk through searching offers, creating an instance, start/stop/reboot/destroy, labels, SSH and scp strings, and copying data between instances, volumes and cloud services.
You need Python 3.9+ and an API key. The SDK reads it from ~/.vast_api_key or takes it as an argument. Serverless work needs pip install "vastai[serverless]". The older vastai_sdk import still works as a shim that re-exports vastai.
One spot where money leaks quietly: a search with type='bid' exposes min_bid, but create_instance without bid_price rents at the on-demand dph_total. So after any interruptible search, pass bid_price. When someone outbids you the instance goes to stopped and storage keeps billing; raise the bid with change_bid to resume.
Volume copy only targets other volumes, instances or cloud services, never your local machine. And do not use /root or / as the destination directory — it breaks ssh permissions on the instance and later copies fail.
What it helps with
- find GPU offers by filters and rent an instance
- spin up a training instance with Jupyter and a direct connection
- copy a dataset from your machine to an instance
- grab the SSH string for an instance
- deploy a serverless inference endpoint
Example prompts for the agent
- search offers with gpu_name=RTX_4090 and num_gpus>=4, then create an instance from the best one
- create an instance with jupyter and direct, image pytorch/pytorch:latest
- copy ./data/ to instance 12345 at /workspace/data/
How to install vastai-sdk
1Skills CLI (Vercel)
npx skills add vast-ai/vast-cli --skill vastai-sdk -a claude-codenpx skills add vast-ai/vast-cli --skill vastai_sdk -a claude-code2Manually: put the files in place
~/.claude/skills/vastai_sdk/SKILL.mdCopy the whole skill folder; for one project use .claude/skills/vastai_sdk/
1Skills CLI (Vercel)
npx skills add vast-ai/vast-cli --skill vastai_sdk -a codex2Manually: put the files in place
.agents/skills/vastai_sdk/SKILL.mdFor all projects use ~/.agents/skills/
1Skills CLI (Vercel)
npx skills add vast-ai/vast-cli --skill vastai_sdk -a cursor2Manually: put the files in place
.cursor/skills/vastai_sdk/SKILL.mdCursor also reads .agents/skills/ and .claude/skills/
1GitHub CLI
gh skill install vast-ai/vast-cli vastai_sdk2Manually: put the files in place
.github/skills/vastai_sdk/SKILL.md1Skills CLI (Vercel)
npx skills add vast-ai/vast-cli --skill vastai_sdk -a gemini-cli2Platform CLI
gemini skills install https://github.com/vast-ai/vast-cli --path vastai_sdkManually: put the files in place
.devin/skills/vastai_sdk/SKILL.mdThe legacy .windsurf/skills/ path still works
Skills CLI (Vercel)
npx skills add vast-ai/vast-cli --skill vastai_sdk -a opencodeClaude.ai
Zip the folder and upload it in Settings → Capabilities → Skills
Step by step, with commands for each platform: How to install skills in Claude Code: five ways
Questions about vastai-sdk
How do I install vastai-sdk in Claude?
Run npx skills add vast-ai/vast-cli --skill vastai-sdk -a claude-code, then npx skills add vast-ai/vast-cli --skill vastai_sdk -a claude-code if you need the second name. The skill lands in ~/.claude/skills/vastai_sdk/SKILL.md.
What does vastai-sdk do?
It is a reference for the Vast.ai Python SDK: GPU instances, volumes, templates, invoices and serverless endpoints. The agent uses it to write code with VastAI, SyncClient, AsyncClient and Serverless.
Do I need an API key?
Yes. The SDK reads the key from ~/.vast_api_key, or you pass it to the constructor. You get the key from the Vast.ai console.
Source text
SKILL.md · MIT
---
name: vastai-sdk
description: Vast.ai Python SDK — high-level API for GPU instances, volumes, serverless endpoints, and billing.
allowed-tools: Python(vastai:*)
compatibility: Python 3.9+
metadata:
author: vast-ai
---
# Vast.ai Python SDK (`vastai` / `vastai_sdk`)
The `vastai` package provides a Python SDK for managing GPU instances, volumes, serverless endpoints, and billing on Vast.ai. The `vastai_sdk` package is a backward-compatibility shim that re-exports `vastai`.
## Installation
```bash
pip install vastai
```
For serverless and async support:
```bash
pip install "vastai[serverless]"
```
## Authentication
The SDK reads the API key from `~/.vast_api_key` by default. You can also pass it explicitly:
```python
from vastai import VastAI
vast = VastAI() # reads ~/.vast_api_key
vast = VastAI(api_key="YOUR_API_KEY") # explicit key
```
Get your API key from https://console.vast.ai/manage-keys/
## Backward Compatibility
The old `vastai_sdk` import still works:
```python
from vastai_sdk import VastAI # equivalent to: from vastai import VastAI
```
## VastAI Class (High-Level SDK)
```python
from vastai import VastAI
vast = VastAI(api_key=None, server_url=None, retry=3, raw=False, quiet=False)
```
### Instance Management
```python
# List all your instances
instances = vast.show_instances()
# Get a single instance
instance = vast.show_instance(id=12345)
# Search GPU offers
offers = vast.search_offers(query='gpu_name=RTX_4090 num_gpus>=4 reliability>0.99')
# Create an instance from an offer
result = vast.create_instance(id=<offer_id>, image="pytorch/pytorch:latest", disk=50)
# ...as a jupyter instance on a direct connection
result = vast.create_instance(id=<offer_id>, image="pytorch/pytorch:latest", disk=50,
jupyter=True, direct=True, jupyter_lab=True)
# Lifecycle
vast.start_instance(id=12345)
vast.stop_instance(id=12345)
vast.reboot_instance(id=12345)
vast.destroy_instance(id=12345)
# Label an instance
vast.label_instance(id=12345, label="my-training-run")
# Get SSH connection string
ssh_url = vast.ssh_url(id=12345) # returns "ssh -p PORT user@host"
scp_url = vast.scp_url(id=12345) # returns scp-compatible URL
```
### Interruptible (spot) rentals
Interruptible (spot) instances are priced below on-demand instances, but can be interrupted at any time by another user with a lower bid. Note: `vast.search_offers(type='bid', ...)` exposes `min_bid`, but `vast.create_instance(...)` defaults to **on-demand at `dph_total`** unless you pass `bid_price=<floor>`. Always pass `bid_price` after a `type='bid'` search, otherwise the instance will be rented as an on-demand instance/price instead of as an interruptible.
When outbid, the instance moves to `stopped` (not destroyed) and storage charges continue. Resume by raising the bid via `vast.change_bid(id=..., price=...)`.
### Search
```python
# Search GPU offers (use help(vast.search_offers) for full query syntax)
offers = vast.search_offers(query='gpu_name=RTX_3090 num_gpus>=2')
# Search volume offers
volumes = vast.search_volumes(query='...')
# Search network volumes
net_vols = vast.search_network_volumes()
# Search templates
templates = vast.search_templates()
# Search invoices
invoices = vast.search_invoices()
```
### Data Transfer
```python
# copy() takes vast URLs: "[C.|V.]id:path", "cloud_service[.id]:path", or "local:path"
vast.copy("local:./data/", "C.12345:/workspace/data/") # Local → instance
vast.copy("C.12345:/workspace/results/", "local:./out/") # Instance → local
vast.copy("12345:/workspace/", "67890:/workspace/") # Instance → instance (legacy format)
vast.copy("s3.101:/data/", "C.12345:/workspace/") # Cloud service → instance
vast.copy("V.1234:/file", "C.5678:/workspace/") # Volume → instance
vast.copy("V.1234:/file", "s3.101:/workspace/") # Volume → cloud service
vast.cancel_copy(dst_id=12345) # Cancel an in-progress copy
# Cloud sync via a saved cloud connection (see the UI settings page for connection IDs)
vast.cloud_copy(src="./data", dst="s3://bucket/path", instance=12345,
connection=<conn_id>, transfer="Instance To Cloud")
vast.cancel_sync(dst_id=12345)
```
Volume copy is currently only supported for copying to other volumes, instances, or cloud services, not local. Do not use `/root` or `/` as a destination directory — it breaks ssh permissions on the instance and future copies fail. See https://vast.ai/docs/gpu-instances/data-movement#constraints.
### Serverless Deployments
```python
# List all deployments
deployments = vast.show_deployments()
# Get a deployment
deployment = vast.show_deployment(id=42)
# Delete a deployment
vast.delete_deployment(id=42)
```
### Machine Management (Hosting)
```python
machines = vast.show_machines()
machine = vast.show_machine(id=10)
vast.list_machine(id=10, price_gpu=0.30)
vast.unlist_machine(id=10)
```
### SSH Keys
```python
keys = vast.show_ssh_keys()
vast.create_ssh_key(ssh_key="ssh-rsa AAAA...")
vast.delete_ssh_key(id=5)
```
### Team Management
```python
members = vast.show_members()
vast.invite_member(email="[email protected]", role="developer")
vast.remove_member(id=7)
```
## SyncClient (Low-Level Sync)
`SyncClient` provides typed, synchronous access to GPU offers and instances.
```python
from vastai import SyncClient
client = SyncClient(api_key="YOUR_API_KEY") # or reads ~/.vast_api_key
# Search offers with structured filters
offers = client.search(
num_gpus=2,
gpu_name="RTX_4090",
min_reliability=0.99,
max_dph_total=2.0,
)
# Create an instance (SyncClient takes an InstanceConfig, not loose kwargs)
from vastai.data.instance import InstanceConfig
instance = client.create_instance(
offer_id=<id>,
config=InstanceConfig(image="pytorch/pytorch:latest", disk=50),
)
# List your instances
instances = client.show_instances() # returns list[SyncInstance]
# Destroy an instance
client.destroy_instance(instance_or_id=12345)
```
## AsyncClient (Low-Level Async)
`AsyncClient` provides async access to GPU offers and instances. Use as an async context manager.
```python
import asyncio
from vastai import AsyncClient
from vastai.data.instance import InstanceConfig
async def main():
async with AsyncClient(api_key="YOUR_API_KEY") as client:
# Search offers
offers = await client.search(num_gpus=1, gpu_name="A100")
# Create instance
instance = await client.create_instance(
offer_id=<id>, config=InstanceConfig(image="ubuntu:22.04"))
# List instances
instances = await client.show_instances() # returns list[AsyncInstance]
# Destroy instance
await client.destroy_instance(instance_or_id=instance.id)
asyncio.run(main())
```
## Serverless Client
For inference endpoints (requires `pip install "vastai[serverless]"`):
```python
import asyncio
from vastai import Serverless
async def main():
serverless = Serverless() # reads ~/.vast_api_key
# Get an endpoint
endpoint = await serverless.get_endpoint("my-endpoint")
# Make a request
response = await serverless.request("/v1/completions", {
"model": "Qwen/Qwen3-8B",
"prompt": "Who are you?",
"max_tokens": 100,
"temperature": 0.7,
})
text = response["response"]["choices"][0]["text"]
print(text)
asyncio.run(main())
```
## Common Patterns
```python
# Find cheapest 4x RTX 4090 and launch a job
from vastai import VastAI
vast = VastAI()
offers = vast.search_offers(query='gpu_name=RTX_4090 num_gpus=4 reliability>0.99')
cheapest = min(offers, key=lambda o: o['dph_total'])
result = vast.create_instance(id=cheapest['id'], image="pytorch/pytorch:latest", disk=100)
print(f"Launched instance: {result['new_contract']}")
# Use help() to explore method signatures
help(vast.search_offers)
help(vast.create_instance)
```
© vast-ai · MIT · vast-ai/vast-cli