Documentation
¶
Overview ¶
Package vast is a Go client for the vast.ai GPU marketplace API (https://console.vast.ai/api/v0). It covers the four-verb lifecycle the cozy platform consumes — search offers, create instance, poll, destroy — plus account balance and a static GPU catalog bridging vast gpu_name strings to the compilecache SKU-slug space.
Index ¶
- Constants
- Variables
- func Bool(b bool) *bool
- func GPUNameForSlug(slug string) (string, bool)
- func GPUNames(specs []GPUSpec) []string
- func NormalizeGPUName(name string) string
- func SKUSlug(gpuName string) string
- type APIError
- type Client
- func (c *Client) Balance(ctx context.Context) (float64, error)
- func (c *Client) CreateInstance(ctx context.Context, offerID int64, req *CreateInstanceRequest) (*CreateInstanceResponse, error)
- func (c *Client) DestroyInstance(ctx context.Context, instanceID int64) error
- func (c *Client) GetCurrentUser(ctx context.Context) (*User, error)
- func (c *Client) GetInstance(ctx context.Context, instanceID int64) (*Instance, error)
- func (c *Client) ListInstances(ctx context.Context) ([]Instance, error)
- func (c *Client) SearchOffers(ctx context.Context, filter *OfferFilter) ([]Offer, error)
- func (c *Client) WaitForInstanceRunning(ctx context.Context, instanceID int64, pollInterval time.Duration) (*Instance, error)
- type ClientOption
- func WithBaseURL(baseURL string) ClientOption
- func WithDebug(debug bool) ClientOption
- func WithHTTPClient(httpClient *http.Client) ClientOption
- func WithLogger(logger Logger) ClientOption
- func WithMaxRetryAttempts(n int) ClientOption
- func WithRetryDelay(d time.Duration) ClientOption
- func WithTimeout(timeout time.Duration) ClientOption
- func WithUserAgent(ua string) ClientOption
- type CreateInstanceRequest
- type CreateInstanceResponse
- type GPUSpec
- type Instance
- type Logger
- type Offer
- type OfferFilter
- type OfferGoneError
- type User
- type ValidationError
Constants ¶
const ( // DefaultBaseURL is the vast.ai REST API base. Endpoints below it are // versioned per path (/api/v0/..., /api/v1/...). DefaultBaseURL = "https://console.vast.ai" // DefaultTimeout is the default HTTP client timeout. DefaultTimeout = 30 * time.Second // DefaultUserAgent identifies the SDK. DefaultUserAgent = "vast-ai-go/0.1.0" // DefaultMaxRetryAttempts is the default number of retries for // retryable failures (429, and 5xx on idempotent requests). DefaultMaxRetryAttempts = 3 // DefaultRetryDelay is the base delay for exponential backoff. DefaultRetryDelay = 1 * time.Second )
const ( // RunTypeSSH boots vast's init, runs Onstart, and provides SSH access. RunTypeSSH = "ssh" // RunTypeArgs runs the image's own ENTRYPOINT/CMD (headless container; // Onstart is not applied). The forge's producer images use this. RunTypeArgs = "args" // RunTypeJupyter boots a Jupyter server. RunTypeJupyter = "jupyter" )
Run types for CreateInstanceRequest.RunType.
const ( StatusLoading = "loading" StatusRunning = "running" StatusExited = "exited" StatusOffline = "offline" StatusUnknown = "unknown" )
Instance lifecycle states (Instance.ActualStatus). vast reports a created/loading instance with an empty or "loading" actual_status; "running" is the only ready state. Per vast docs: once actual_status is exited, offline, or unknown the instance will never reach running — destroy and re-rent.
const ( // OfferTypeOnDemand — fixed-price, exclusive until destroyed. OfferTypeOnDemand = "on-demand" // OfferTypeBid — interruptible: you bid, and the instance is PAUSED // (not destroyed) whenever outbid. Not for run-to-completion work. OfferTypeBid = "bid" // OfferTypeReserved — reserved-term pricing. OfferTypeReserved = "reserved" )
Offer types (pricing model) accepted by OfferFilter.Type.
Variables ¶
var ( // ErrNotFound matches 404 responses (unknown instance id, etc.). ErrNotFound = errors.New("vast: not found") ErrUnauthorized = errors.New("vast: unauthorized") // ErrRateLimited matches 429 responses. ErrRateLimited = errors.New("vast: rate limited") // ErrOfferGone matches instance-create failures where the offer was // already rented or withdrawn (404/410 from PUT /asks/{id}/, or a // no-longer-available error body). Marketplace offers expire fast — // callers should re-search and pick the next offer, not retry the id. ErrOfferGone = errors.New("vast: offer gone") // ErrInsufficientCredit matches create failures caused by account // balance (vast rejects rentals below a minimum credit threshold). // Retrying is pointless until the account is topped up. ErrInsufficientCredit = errors.New("vast: insufficient credit") )
Sentinel errors, matched via errors.Is against errors returned by any SDK method. This is the taxonomy tensorhub's backoff logic consumes.
Functions ¶
func GPUNameForSlug ¶
GPUNameForSlug returns the vast gpu_name for a compilecache SKU slug.
func GPUNames ¶
GPUNames extracts the vast gpu_name strings from specs — directly usable as OfferFilter.GPUNames.
func NormalizeGPUName ¶
NormalizeGPUName canonicalizes a vast gpu_name: underscores (the vast CLI convention "RTX_4090") become spaces, and whitespace is collapsed.
func SKUSlug ¶
SKUSlug is the canonical compilecache slugifier, byte-compatible with gen_worker.compile_cache.sku_slug and tensorhub compilecache.SKUSlug: "NVIDIA GeForce RTX 4090" -> "rtx-4090", "NVIDIA H100 80GB HBM3" -> "h100-80gb-hbm3".
Apply it to CUDA device names. For vast gpu_name strings prefer the catalog (GPUSpecByName(...).Slug): vast's abbreviations ("RTX 4070S", "H100 SXM") do not slugify to the device slug.
Types ¶
type APIError ¶
type APIError struct {
StatusCode int
// Code is vast's machine-readable error slug when present
// (e.g. "invalid_args", "insufficient_credit").
Code string
Message string
// RetryAfter is populated from the Retry-After header on 429 responses.
RetryAfter time.Duration
}
APIError is an error response from the vast.ai API. It matches the package sentinels via errors.Is according to StatusCode and Code.
func (*APIError) IsServerError ¶
IsServerError reports whether the response was a 5xx.
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client is the vast.ai API client. Construct with NewClient; safe for concurrent use.
func NewClient ¶
func NewClient(apiKey string, opts ...ClientOption) (*Client, error)
NewClient creates a vast.ai API client authenticated with apiKey.
func (*Client) Balance ¶
Balance returns the account's spendable funds in USD: prepaid balance plus deposited/awarded credit. Live fact (2026-07): credit-only accounts (billing_creditonly) carry ALL funds in `credit` with `balance` pinned at 0 — returning `balance` alone reads $0.00 on a funded account. The forge's spend guardrails poll this before opening a session.
func (*Client) CreateInstance ¶
func (c *Client) CreateInstance(ctx context.Context, offerID int64, req *CreateInstanceRequest) (*CreateInstanceResponse, error)
CreateInstance accepts offer offerID and boots req.Image on it (PUT /api/v0/asks/{id}/). On-demand unless req.BidPricePerHour is set.
Offer-gone failures (rented from under you, withdrawn, host offline) return an error matching ErrOfferGone: re-search and take the next offer. Balance failures match ErrInsufficientCredit. Never retried on 5xx — a replay could double-rent; callers own create-retry policy.
func (*Client) DestroyInstance ¶
DestroyInstance permanently destroys an instance and all its data (DELETE /api/v0/instances/{id}/). This is the ONLY call that stops billing: a merely stopped instance still bills storage. errors.Is(err, ErrNotFound) means it's already gone — callers usually treat that as success.
func (*Client) GetCurrentUser ¶
GetCurrentUser returns the account that owns the API key.
func (*Client) GetInstance ¶
GetInstance fetches one instance by id (GET /api/v0/instances/{id}/).
func (*Client) ListInstances ¶
ListInstances returns every instance owned by the account, walking the keyset-paginated GET /api/v1/instances/ endpoint (25/page, 2026-04 API change) until exhausted.
func (*Client) SearchOffers ¶
SearchOffers queries the marketplace for rentable offers matching filter, cheapest first by default. A nil filter returns the cheapest rentable offers of any kind. Read-only and free — safe to call aggressively.
func (*Client) WaitForInstanceRunning ¶
func (c *Client) WaitForInstanceRunning(ctx context.Context, instanceID int64, pollInterval time.Duration) (*Instance, error)
WaitForInstanceRunning polls GetInstance until the instance is running, reaches a terminal state (returned with a non-nil error matching the instance state), or ctx expires. pollInterval <= 0 defaults to 10s. The last-observed instance is returned even on error when available.
type ClientOption ¶
type ClientOption func(*Client)
ClientOption configures the client.
func WithBaseURL ¶
func WithBaseURL(baseURL string) ClientOption
WithBaseURL overrides the API base URL (e.g. an httptest server).
func WithDebug ¶
func WithDebug(debug bool) ClientOption
WithDebug enables request/response logging.
func WithHTTPClient ¶
func WithHTTPClient(httpClient *http.Client) ClientOption
WithHTTPClient sets a custom HTTP client.
func WithLogger ¶
func WithLogger(logger Logger) ClientOption
WithLogger sets a custom logger for debug output.
func WithMaxRetryAttempts ¶
func WithMaxRetryAttempts(n int) ClientOption
WithMaxRetryAttempts sets the maximum number of retry attempts.
func WithRetryDelay ¶
func WithRetryDelay(d time.Duration) ClientOption
WithRetryDelay sets the base delay for exponential backoff.
func WithTimeout ¶
func WithTimeout(timeout time.Duration) ClientOption
WithTimeout sets the HTTP client timeout.
func WithUserAgent ¶
func WithUserAgent(ua string) ClientOption
WithUserAgent sets the User-Agent header.
type CreateInstanceRequest ¶
type CreateInstanceRequest struct {
// Image is the docker image to run (required).
Image string
// Env sets container environment variables. Keys beginning with "-"
// are passed through as raw docker flags per vast convention
// (e.g. {"-p 8080:8080": "1"}); prefer Ports for port mappings.
Env map[string]string
// Ports adds docker -p mappings (e.g. "8080:8080", "70000:8000/udp").
Ports []string
// Onstart is a startup script run by vast's init (<= 4048 chars; gzip
// +base64 anything larger and decode in the script). Applied for
// RunTypeSSH/RunTypeJupyter; ignored by RunTypeArgs.
Onstart string
// RunType selects the launch mode; defaults to RunTypeArgs (headless:
// the image's own entrypoint runs) unless Onstart is set, in which
// case it defaults to RunTypeSSH so the script actually executes.
RunType string
// Args replaces the image CMD when RunType is RunTypeArgs.
Args []string
// DiskGB is the local disk allocation in GB (default 10). Storage is
// billed per GB-hour even while the instance is stopped.
DiskGB float64
// Label is a free-form tag shown in listings; use it to correlate
// instances with forge sessions.
Label string
// BidPricePerHour places an interruptible bid ($/hr) instead of an
// on-demand rental. Leave zero for on-demand.
BidPricePerHour float64
// TargetState is the state after provisioning ("running" default).
TargetState string
// ImageLogin is a docker registry login string for private images
// ("-u user -p pass registry.example.com").
ImageLogin string
// if the machine cannot start the instance right away, instead of
// queueing it.
CancelUnavail bool
}
CreateInstanceRequest configures the container launched on an accepted offer. Image is required; everything else has serviceable defaults.
SECURITY: the host machine has root over the container — anything in Env and Onstart is readable (and tamperable) by the host. Ship only single-use, short-TTL, narrowly-scoped credentials.
type CreateInstanceResponse ¶
type CreateInstanceResponse struct {
Success bool `json:"success"`
// InstanceID is the new instance (contract) id — vast calls it
// "new_contract". Use it with GetInstance/DestroyInstance.
InstanceID int64 `json:"new_contract"`
}
CreateInstanceResponse reports the accepted contract.
type GPUSpec ¶
type GPUSpec struct {
// GPUName is the vast.ai gpu_name as returned in offers and accepted by
// OfferFilter.GPUName (e.g. "RTX 4090").
GPUName string
// Slug is the canonical compilecache SKU slug for the device
// (e.g. "rtx-4090").
Slug string
// VRAMGB is the nominal per-GPU memory in GB. Some vast names cover
// multiple VRAM variants (A100 PCIE 40/80) — offers carry the exact
// gpu_ram; this is the common configuration.
VRAMGB int
// SMCapability is the CUDA compute capability x10 (86 = SM8.6,
// 120 = SM12.0) — matches Offer.ComputeCap.
SMCapability int
// Consumer is true for GeForce SKUs (no attestation, marketplace boxes).
Consumer bool
}
GPUSpec bridges a vast.ai gpu_name to the cozy platform's canonical SKU slug space (compilecache: python-gen-worker gen_worker.compile_cache sku_slug / tensorhub internal/orchestrator/compilecache.SKUSlug).
The slug is derived from the CUDA DEVICE name as torch reports it on the box ("NVIDIA GeForce RTX 4090" -> "rtx-4090"), NOT from vast's marketing name. For consumer cards the two coincide; for datacenter cards they do not (vast "H100 SXM" is device "NVIDIA H100 80GB HBM3" -> slug "h100-80gb-hbm3"), so every entry carries an explicit Slug. This mirrors runpod-go-sdk's GPUSpec catalog so the forge pins SKUs identically across providers.
func GPUCatalog ¶
func GPUCatalog() []GPUSpec
GPUCatalog returns a copy of the static SKU catalog in fallback preference order (cheaper/more-liquid SKUs first).
func GPUSpecByName ¶
GPUSpecByName looks up a catalog entry by vast gpu_name. Underscores are normalized to spaces ("RTX_4090" works) and matching is case-insensitive.
func GPUSpecBySlug ¶
GPUSpecBySlug looks up a catalog entry by canonical compilecache slug (e.g. "rtx-4090") — the reverse bridge used when a desired cell's SKU must be turned into a vast offer filter.
func GPUsWithAtLeast ¶
GPUsWithAtLeast returns catalog entries with >= minVRAMGB of VRAM and SM capability >= minSM (x10, e.g. 89), preserving fallback order. Pass zeros to skip either constraint.
type Instance ¶
type Instance struct {
ID int64 `json:"id"`
MachineID int64 `json:"machine_id"`
HostID int64 `json:"host_id"`
// ActualStatus is the observed state (see Status* constants).
ActualStatus string `json:"actual_status"`
// IntendedStatus is the desired state ("running"/"stopped").
IntendedStatus string `json:"intended_status"`
CurState string `json:"cur_state"`
NextState string `json:"next_state"`
// StatusMsg carries loading/error detail (image pull progress, docker
// errors); invaluable for diagnosing stuck instances.
StatusMsg string `json:"status_msg"`
Label string `json:"label"`
ImageUUID string `json:"image_uuid"`
GPUName string `json:"gpu_name"`
NumGPUs int `json:"num_gpus"`
GPURAMMB float64 `json:"gpu_ram"`
GPUUtil float64 `json:"gpu_util"`
// DPHTotal is the effective $/hr being billed for compute.
DPHTotal float64 `json:"dph_total"`
DPHBase float64 `json:"dph_base"`
StorageCost float64 `json:"storage_cost"`
DiskSpace float64 `json:"disk_space"`
PublicIPAddr string `json:"public_ipaddr"`
SSHHost string `json:"ssh_host"`
SSHPort int `json:"ssh_port"`
InetUpCost float64 `json:"inet_up_cost"`
InetDownCost float64 `json:"inet_down_cost"`
// StartDate is a unix timestamp (fractional seconds).
StartDate float64 `json:"start_date"`
Geolocation string `json:"geolocation"`
}
Instance is a rented machine as reported by GetInstance/ListInstances.
func (Instance) IsTerminal ¶
IsTerminal reports whether the instance can never reach running again (destroy and re-rent — vast documents exited/offline/unknown as dead ends).
type Logger ¶
type Logger interface {
Printf(format string, v ...interface{})
}
Logger is the minimal logging interface used for debug output.
type Offer ¶
type Offer struct {
ID int64 `json:"id"`
AskID int64 `json:"ask_contract_id"`
MachineID int64 `json:"machine_id"`
HostID int64 `json:"host_id"`
GPUName string `json:"gpu_name"`
NumGPUs int `json:"num_gpus"`
GPURAMMB float64 `json:"gpu_ram"` // per-GPU VRAM in MB
GPUArch string `json:"gpu_arch"`
ComputeCap int `json:"compute_cap"` // SM capability x10 (86, 89, 120)
// DPHTotal is the on-demand $/hr for the whole offer (all GPUs).
DPHTotal float64 `json:"dph_total"`
// MinBid is the current minimum bid $/hr for interruptible rental.
MinBid float64 `json:"min_bid"`
// StorageCost is $/GB/month for disk (billed even while stopped).
StorageCost float64 `json:"storage_cost"`
// InetUpCost / InetDownCost are $/GB for traffic in each direction.
InetUpCost float64 `json:"inet_up_cost"`
InetDownCost float64 `json:"inet_down_cost"`
// Reliability is the host uptime score in [0,1].
Reliability float64 `json:"reliability2"`
// Verification is vast's raw host-verification state ("verified",
// "unverified", "deverified"). Live fact (2026-07): offer rows carry
// this string — there is NO boolean `verified` key in responses (the
// boolean exists only as a server-side FILTER name).
Verification string `json:"verification"`
// Verified means the machine passed vast's automated verification
// (CUDA >= 12, >= 90% reliability). Derived from Verification by
// SearchOffers — not a wire field.
Verified bool `json:"-"`
// HostingType is vast's raw hosting class (0 = residential/individual,
// 1 = datacenter). Like Verification, the wire has no `datacenter`
// boolean on offer rows — only the filter name.
HostingType int `json:"hosting_type"`
// Datacenter is true for hosted datacenter machines (consumer cards are
// overwhelmingly non-datacenter boxes). Derived from HostingType by
// SearchOffers — not a wire field. NOTE: datacenter alone does NOT
// imply verified — dc hosts can be "deverified"; filter on both.
Datacenter bool `json:"-"`
Hostname string `json:"hostname"`
CUDAMaxGood float64 `json:"cuda_max_good"` // max CUDA version the driver supports
DriverVersion string `json:"driver_version"`
CPUCores float64 `json:"cpu_cores_effective"`
CPURAMMB float64 `json:"cpu_ram"`
DiskSpace float64 `json:"disk_space"` // GB available
DiskBW float64 `json:"disk_bw"`
InetUp float64 `json:"inet_up"` // Mbps
InetDown float64 `json:"inet_down"` // Mbps
Geolocation string `json:"geolocation"`
DLPerf float64 `json:"dlperf"`
Rentable bool `json:"rentable"`
Rented bool `json:"rented"`
}
Offer is one rentable machine configuration returned by SearchOffers. The offer ID is the "ask" accepted by CreateInstance. Offers are a live marketplace view: an id can be rented out from under you at any moment (ErrOfferGone), so treat the list as immediately perishable.
type OfferFilter ¶
type OfferFilter struct {
// GPUName filters on the vast gpu_name (e.g. "RTX 4090"; underscores
// are normalized to spaces, so "RTX_4090" also works). Mutually
// exclusive with GPUNames.
GPUName string
// GPUNames filters on a set of acceptable gpu_names.
GPUNames []string
// NumGPUs requires exactly this many GPUs (most forge work wants 1).
NumGPUs int
// MinGPURAMGB requires at least this much per-GPU VRAM.
MinGPURAMGB int
// MinReliability requires host reliability >= this ([0,1], e.g. 0.98).
MinReliability float64
// MaxDPHTotal caps the on-demand $/hr for the whole offer.
MaxDPHTotal float64
// Verified, when non-nil, requires (or excludes) vast-verified machines.
Verified *bool
// Datacenter, when non-nil, requires (or excludes) datacenter hosts.
Datacenter *bool
// MinDiskGB requires at least this much rentable disk.
MinDiskGB float64
// MinCUDA requires cuda_max_good >= this (e.g. 12.4).
MinCUDA float64
// MinInetDownMbps / MinInetUpMbps set network floors.
MinInetDownMbps float64
MinInetUpMbps float64
// MinComputeCap requires SM capability x10 >= this (86, 89, 120).
MinComputeCap int
// MinCPUCores requires at least this many EFFECTIVE vCPUs allocated to
// the rental (wire field cpu_cores_effective — the slice this offer
// actually gets, not the whole machine).
MinCPUCores float64
// MinCPURAMGB requires at least this much host RAM in GB (wire field
// cpu_ram is MB; the SDK converts).
MinCPURAMGB float64
// Geolocation restricts to two-letter country codes (e.g. "US", "DE").
Geolocation []string
// Type is the pricing model: OfferTypeOnDemand (default), OfferTypeBid,
// or OfferTypeReserved.
Type string
// OrderBy is a list of [field, direction] pairs; default sorts by
// dph_total ascending (cheapest first).
OrderBy [][2]string
// Limit caps the number of offers returned (default 64).
Limit int
// External, when non-nil, includes/excludes offers outside vast's
// standard pool. Defaults to false (exclude) like the vast CLI.
External *bool
}
OfferFilter selects offers. Zero values mean "no constraint" except where noted. The SDK always constrains to rentable, un-rented offers.
type OfferGoneError ¶
OfferGoneError wraps an instance-create failure classified as the offer being gone. errors.Is(err, ErrOfferGone) is true; the underlying APIError is reachable via errors.As.
func (*OfferGoneError) Error ¶
func (e *OfferGoneError) Error() string
func (*OfferGoneError) Is ¶
func (e *OfferGoneError) Is(target error) bool
func (*OfferGoneError) Unwrap ¶
func (e *OfferGoneError) Unwrap() error
type User ¶
type User struct {
ID int64 `json:"id"`
Email string `json:"email"`
// Balance is the current prepaid credit in USD.
Balance float64 `json:"balance"`
// Credit is promotional/awarded credit in USD, when present.
Credit float64 `json:"credit"`
}
User is the authenticated account (GET /api/v0/users/current/).
type ValidationError ¶
ValidationError is a client-side input validation failure; no request was sent to the API.
func (*ValidationError) Error ¶
func (e *ValidationError) Error() string