Official Python SDK and CLI for KeyNode — AI compute on distributed GPUs
Project description
KeyNode Python SDK & CLI
Official Python SDK and CLI for KeyNode — the AI compute platform that connects your workloads to underutilized GPUs from distributed providers. Run training jobs and inference cheaper and faster than traditional cloud.
Requirements
- Python 3.10+
Installation
pip install keynode
Or install from source:
git clone <repo_url>
cd keynode-python
pip install .
# Development (editable) install
pip install -e .
Authentication
Option 1 — CLI login (recommended)
keynode auth login
This prompts for your API key and saves it to ~/.keynode/config.json.
Option 2 — Environment variables
export KEYNODE_API_KEY="kn_xxx"
export KEYNODE_BASE_URL="https://api.keynode.es" # optional, this is the default
Option 3 — Direct SDK initialization
from keynode import KeyNodeClient
client = KeyNodeClient(api_key="kn_xxx", base_url="https://api.keynode.es")
CLI Usage
Auth
keynode auth login # Save API key to config
keynode auth whoami # Verify authentication
GPU Catalog
keynode gpu list # List all available GPUs
keynode gpu list --min-vram 24 # Filter by minimum VRAM
keynode gpu list --max-price 1.5 --region eu-west # Filter by price and region
keynode gpu list --model "RTX 4090" # Search by model name
keynode gpu stats # Platform-wide GPU stats
keynode gpu detail "NVIDIA A100" --vram 80 # Detailed info for a GPU SKU
Runs
keynode run list # List all runs
keynode run get <run_id> # Get run details
keynode run create -f payload.json # Create run from JSON file
keynode run cancel <run_id> # Cancel a run
keynode run retry <run_id> # Retry a run immediately
keynode run clone-retry <run_id> # Clone and retry a run
keynode run resume <run_id> # Resume a paused run
keynode run wait <run_id> # Block until run finishes
keynode run wait <run_id> --timeout 3600 # Wait with timeout (seconds)
keynode run metrics <run_id> # GPU/CPU metrics time-series
keynode run manifest <run_id> # Show run manifest
keynode run download-manifest <run_id> -o out.json # Download manifest as JSON
keynode run artifacts <run_id> # List artifacts
keynode run download-artifacts <run_id> -o out.tar.gz # Download artifacts tarball
Backups
keynode backup list # List all backups
keynode backup list --run-id 365 # Filter by run
keynode backup list --status completed # Filter by status
keynode backup delete <backup_id> # Delete a backup
Datasets
keynode dataset list # List datasets
keynode dataset upload ./train.csv --name my-train # Upload a dataset
keynode dataset download <dataset_id> -o data.csv # Download a dataset
keynode dataset delete <dataset_id> # Delete a dataset
Sources
keynode source list # List sources
keynode source upload ./my_code.tar.gz # Upload a source archive
keynode source delete <source_id> # Delete a source
Secrets
keynode secret list # List secrets
keynode secret create --name HF_TOKEN # Create a secret (prompts for value)
keynode secret delete <secret_id> # Delete a secret
API Keys
keynode apikey list # List your API keys
keynode apikey create --name "ci-pipeline" # Create a new API key
keynode apikey create --name "tmp" --expires-in-days 30 # Key with expiry
keynode apikey revoke <api_key_id> # Revoke an API key
Python SDK Usage
Initialize the client
from keynode import KeyNodeClient
# From environment variables or ~/.keynode/config.json
client = KeyNodeClient.from_env()
# Or explicitly
client = KeyNodeClient(api_key="kn_xxx", base_url="https://api.keynode.es")
Browse the GPU catalog
with KeyNodeClient.from_env() as client:
# List available GPUs
gpus = client.gpu.list(min_vram=24, max_price=2.0)
for g in gpus:
print(f"{g['model']} {g['vram_gb']}GB — €{g['min_price_per_hour']:.3f}/hr ({g['units_available']} available)")
# Platform stats
stats = client.gpu.stats()
print(f"{stats['gpus_available']} GPUs available across {stats['regions_active']} regions")
# Detailed SKU info
detail = client.gpu.detail("NVIDIA A100", vram_gb=80)
print(detail["region_breakdown"])
Create a training run and wait for completion
from keynode import KeyNodeClient
payload = {
"name": "my-training-job",
"image": "registry.keynode.es/keynode-jupyter-scipy-ssh:v1",
"cmd": "python train.py",
"cpus": 4,
"memory_gb": 16,
"gpu_count": 1,
}
with KeyNodeClient.from_env() as client:
run = client.runs.create(payload)
run_id = run["run_id"]
# Block until finished (polls every 5s)
result = client.runs.wait(run_id, timeout=7200)
print(f"Status: {result['status']}")
# Download results
client.runs.download_artifacts(run_id, output_path="./results.tar.gz")
List runs
with KeyNodeClient.from_env() as client:
runs = client.runs.list()
print(runs)
Get GPU/CPU metrics for a run
with KeyNodeClient.from_env() as client:
metrics = client.runs.metrics(run_id=365, step_s=10)
for point in metrics["items"]:
print(f"{point['ts']} GPU {point['gpu_util']}% VRAM {point['gpu_mem_mb']}MB")
Work with backups
with KeyNodeClient.from_env() as client:
# List all backups
backups = client.backups.list()
# Filter by run
run_backups = client.backups.list(run_id=365, status="completed")
# Delete a backup
client.backups.delete(backups[0]["id"])
Work with datasets
with KeyNodeClient.from_env() as client:
# Upload
dataset = client.datasets.upload("./data/train.csv", dataset_name="train-v1")
# Download
client.datasets.download(dataset["id"], output_path="./train_downloaded.csv")
# Delete
client.datasets.delete(dataset["id"])
Manage API keys
with KeyNodeClient.from_env() as client:
# Create a new key (raw key shown only once)
result = client.api_keys.create(name="ci-pipeline", expires_in_days=90)
print(result["api_key"]) # save this immediately
# List existing keys
keys = client.api_keys.list()
# Revoke a key
client.api_keys.revoke(keys[0]["api_key_id"])
Manage secrets
with KeyNodeClient.from_env() as client:
client.secrets.create(name="HF_TOKEN", value="hf_xxx", description="HuggingFace token")
secrets = client.secrets.list()
client.secrets.delete(secrets[0]["id"])
Download run artifacts
with KeyNodeClient.from_env() as client:
# List artifacts
artifacts = client.runs.artifacts(run_id=365)
# Download as tarball
client.runs.download_artifacts(run_id=365, output_path="./results.tar.gz")
# Download manifest
client.runs.download_manifest(run_id=365, output_path="./manifest.json")
Error handling
from keynode import KeyNodeClient
from keynode.exceptions import KeynodeAuthError, KeynodeApiError
try:
with KeyNodeClient.from_env() as client:
run = client.runs.get(999)
except KeynodeAuthError:
print("Invalid or missing API key")
except KeynodeApiError as e:
print(f"API error {e.status_code}: {e.message}")
Package Structure
keynode → Python SDK (client, resources, config, exceptions)
keynode_cli → CLI application
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file keynode-0.1.1.tar.gz.
File metadata
- Download URL: keynode-0.1.1.tar.gz
- Upload date:
- Size: 22.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ad82bb2cb969ed75ca149a9711636e4e8596b9353aebe9f44e386f3095fad576
|
|
| MD5 |
8794d9696812f6ac75b2c942f71819ad
|
|
| BLAKE2b-256 |
d43ee7df1257ab49931c13a42b84ab7f643b060a0ef07a956ab05c23eef06b08
|
File details
Details for the file keynode-0.1.1-py3-none-any.whl.
File metadata
- Download URL: keynode-0.1.1-py3-none-any.whl
- Upload date:
- Size: 25.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
47c15dfad7e40a3f44c5a016bd41ffefcf92de04abd2e070c73a478eded43e4c
|
|
| MD5 |
ef2d1c0c4ae50d54717e742a2690d9f2
|
|
| BLAKE2b-256 |
7418198926985de21a9bb3bffeed092405adf4965c344358e1b71b615b646864
|