diff --git a/runpodctl/overview.mdx b/runpodctl/overview.mdx index 3db0f7b73..d003b2341 100644 --- a/runpodctl/overview.mdx +++ b/runpodctl/overview.mdx @@ -203,6 +203,69 @@ Learn more about a particular command by running: runpodctl [command] --help ``` +## Output format + +Successful command output goes to standard output as JSON by default, which makes runpodctl scriptable and agent-friendly. Use the `--output` flag to switch to a human-readable table or YAML: + +```bash +runpodctl pod list # json (default) +runpodctl pod list --output=table # table +runpodctl pod list --output=yaml # yaml +``` + +`template search` and `hub search` emit `[]` on standard output when nothing matches, instead of a prose message, so a caller piping the output into a JSON parser gets a valid empty list on the no-match case. + +### Error format + +When a command fails, runpodctl writes a single flat JSON object to standard error and exits with a non-zero status. Branch on the `code` field, never on the message text: + +```json +{"error":"failed to get endpoint: endpoint not found","code":"not_found","status":404} +``` + +| Field | Description | +| --- | --- | +| `error` | Human-readable message, unwrapped (never a nested JSON blob). | +| `code` | Stable, lowercase identifier for the failure class. Present on every error from the resource commands. | +| `status` | HTTP status code. Only present when the failure came back from a REST call. Absent when the API answered `200` with an empty result (GraphQL reports missing resources this way), so branch on `code` rather than `status`. | + +Codes runpodctl generates: + +| Code | Meaning | +| --- | --- | +| `usage_error` | The invocation was wrong: unknown command or flag, bad or missing arguments, missing required flags. Usage text is printed after the JSON object. | +| `not_found` | The resource does not exist. | +| `bad_request`, `unauthorized`, `forbidden`, `conflict`, `rate_limited`, `server_error`, `api_error` | Derived from the REST status returned by the API. | +| `graphql_error` | GraphQL returned an errors array (HTTP 200). | +| `no_credentials` | No API key is configured. Run `runpodctl doctor` or set `RUNPOD_API_KEY`. | +| `network_error` | The API could not be reached (DNS failure, connection refused, TLS error, timeout). This is the only code that means "transient, retry." | +| `cli_error` | Any other local failure: validation, config, bad input, malformed `RUNPOD_API_URL`. | + +The API can also return its own code, which is passed through in lowercase. Treat the list above as the set the CLI generates rather than an exhaustive one. + +### Exit codes + +Every documented resource command exits non-zero on failure, including `model`, `update`, `send`, and `receive` (which previously exited `0` on some failure paths). Do not rely on stdout being empty to detect failure. Check the exit code and parse the JSON error object on stderr. + +A few legacy surfaces still print plain-text errors and do not carry a `code`: + +- The legacy pod verbs (`get pod`, `create pod`, `remove pod`, `start pod`, `stop pod`, `create pods`, `remove pods`) and `get cloud` print `Error: ` via cobra and exit `1`. +- `exec` prints plain text and exits `1`. +- `project` prints to standard output and exits `0` on failure (tracked upstream). + +Parsers should tolerate a non-JSON line on stderr from those commands, and should not rely on the exit code for `project` until the upstream fix lands. + +### Environment variables + +| Variable | Default | Description | +| --- | --- | --- | +| `RUNPOD_API_KEY` | — | API key. Also settable via `runpodctl doctor` or `~/.runpod/config.toml`. | +| `RUNPOD_API_URL` | `https://rest.runpod.io/v1` | REST control plane (config key `restApiUrl`). | +| `RUNPOD_GRAPHQL_URL` | `https://api.runpod.io/graphql` | GraphQL control plane (config key `apiUrl`). | +| `RUNPOD_INVOKE_URL` | `https://api.runpod.ai/v2` | Base URL used to build the Serverless invoke URLs reported by `serverless create/get/list` (config key `invokeUrl`). | + +Invoke is a separate service from the control plane. Pointing `RUNPOD_API_URL` or `RUNPOD_GRAPHQL_URL` at a non-production host does not move the invoke URLs; override `RUNPOD_INVOKE_URL` explicitly when you need that. + ## Shell completion Enable tab completion for your shell to make working with `runpodctl` easier: diff --git a/runpodctl/reference/runpodctl-gpu.mdx b/runpodctl/reference/runpodctl-gpu.mdx index 584fcae97..12bd35ae5 100644 --- a/runpodctl/reference/runpodctl-gpu.mdx +++ b/runpodctl/reference/runpodctl-gpu.mdx @@ -35,29 +35,66 @@ Include GPUs that are currently unavailable. ## Example output +Each GPU entry includes on-demand pricing and a per-data-center stock breakdown alongside the best overall `stockStatus`: + ```json [ { "available": true, "communityCloud": true, + "communityPricePerHr": 0.34, + "dataCenterAvailability": [ + { "dataCenterId": "US-CA-2", "stockStatus": "High" }, + { "dataCenterId": "EU-RO-1", "stockStatus": "Low" }, + { "dataCenterId": "US-KS-2", "stockStatus": "none" } + ], "displayName": "RTX 4090", "gpuId": "NVIDIA GeForce RTX 4090", "memoryInGb": 24, "secureCloud": true, + "securePricePerHr": 0.44, "stockStatus": "High" }, { "available": true, - "communityCloud": true, + "communityCloud": false, + "communityPricePerHr": null, + "dataCenterAvailability": [ + { "dataCenterId": "US-CA-2", "stockStatus": "High" }, + { "dataCenterId": "EU-RO-1", "stockStatus": "Medium" } + ], "displayName": "A100 PCIe", "gpuId": "NVIDIA A100 80GB PCIe", "memoryInGb": 80, "secureCloud": true, + "securePricePerHr": 1.39, "stockStatus": "High" } ] ``` +### Output fields + + +On-demand price per hour in USD on Secure Cloud. Explicitly `null` when the GPU is not offered on Secure Cloud (distinguishable from a real `0`). + + + +On-demand price per hour in USD on Community Cloud. Explicitly `null` when the GPU is not offered on Community Cloud. + + + +Best availability across all data centers that offer this GPU. Typical values are `High`, `Medium`, `Low`, and `none`. + + + +Per-data-center availability breakdown. Every data center that offers the GPU is listed; a data center with no reported stock is included with `stockStatus: "none"` so you can tell "offered here, out of stock" apart from "not offered here." + + + +`true` when at least one data center reports real stock. Derived from `stockStatus`, so `available: true` implies `stockStatus` is not `none`. + + ## Using GPU IDs When creating Pods or Serverless endpoints, use the GPU ID from the list with the `--gpu-id` flag: diff --git a/runpodctl/reference/runpodctl-serverless.mdx b/runpodctl/reference/runpodctl-serverless.mdx index a80cd6f13..2f54f3460 100644 --- a/runpodctl/reference/runpodctl-serverless.mdx +++ b/runpodctl/reference/runpodctl-serverless.mdx @@ -243,6 +243,24 @@ Access your Serverless endpoint using these URL patterns: | Health check | `https://api.runpod.ai/v2//health` | | Job status | `https://api.runpod.ai/v2//status/` | +### Invoke URLs in command output + +`serverless create`, `serverless get`, and `serverless list` include a `urls` object on each endpoint so you can invoke a freshly deployed endpoint without a second lookup: + +```json +{ + "id": "abc123", + "name": "my-vllm", + "urls": { + "run": "https://api.runpod.ai/v2/abc123/run", + "runsync": "https://api.runpod.ai/v2/abc123/runsync", + "health": "https://api.runpod.ai/v2/abc123/health" + } +} +``` + +The URLs are computed client-side from the endpoint ID. Invoke is a separate service from the control plane, so `RUNPOD_API_URL` and `RUNPOD_GRAPHQL_URL` do not move them. Set `RUNPOD_INVOKE_URL` (or the `invokeUrl` key in `~/.runpod/config.toml`) when you need to target a non-production invoke host; the default is `https://api.runpod.ai/v2`. + ## Related commands - [`runpodctl hub`](/runpodctl/reference/runpodctl-hub)