Skip to main content

SDK Usage

Everything the CLI does is available in Python. Import the client and helpers from the top-level substratecloud package.

The client

from substratecloud import SubstrateCloud

client = SubstrateCloud() # token/base_url from env or config
client = SubstrateCloud(profile="staging") # named profile

The client exposes three resource managers — client.inventory, client.instances, and client.ssh_keys — plus high-level helpers.

Use it as a context manager so the underlying HTTP connection is always closed:

with SubstrateCloud() as client:
items = client.inventory.list(gpu_type="A100")

Imperative lifecycle

# 1. Find capacity
item = client.inventory.find_cheapest(gpu_type="A100")

# 2. Launch (billing starts here)
instance = client.instances.create(inventory_gpu_id=item.id, name="exp-1")

# 3. Wait until it's ready
client.instances.wait_until_active(instance.id, timeout=600)

# 4. Use it — SSH in via instance.ip_address ...

# 5. Stop billing
client.instances.delete(instance.id)
SDK ↔ CLI naming

The SDK methods instances.create() / instances.delete() map to the CLI verbs substratecloud instance launch / substratecloud instance terminate (the CLI has no create/delete subcommands).

Useful manager methods:

  • inventory.list(gpu_type=, location=, gpu_count=, max_price=)
  • inventory.find_cheapest(gpu_type=, location=, min_count=, max_price=)
  • inventory.find_with_fallback([{...}, ...]) — try regions in order
  • instances.list(), instances.get(id), instances.find_by_name(name), instances.find_by_tag(tag)
  • instances.wait_until_active(id, timeout=)
  • instances.delete(id), instances.delete_many([ids])
  • ssh_keys.list(), ssh_keys.find_by_name(name)

client.run() — find + launch + wait in one call

from substratecloud import SubstrateCloud, DockerWorkload, Secret

client = SubstrateCloud()

wl = DockerWorkload(
image="vllm/vllm-openai:latest",
args=["--model", "mistralai/Mistral-7B-v0.1"],
env={"HF_TOKEN": Secret.from_env("HF_TOKEN")},
ports={8000: 8000},
)

inst = client.run(
workload=wl,
gpu="A100",
name="vllm-mistral",
region_preference=["Stockholm", "US East"],
max_price_per_hour=3.0,
ssh_key="my-laptop", # name or UUID
tags=["team:platform"],
wait=True, # block until active (default)
wait_timeout=600.0,
)
print(f"ssh {inst.ssh_user}@{inst.ip_address} -p {inst.ssh_port}")

Every run() is auto-tagged with actor:<user> and trace:<id> for audit. Passing budget_limit= adds a budget:N tag — an audit tag only; it does not auto-terminate the instance. See Cost Safety.

Fluent builder

Each builder call returns a fresh, immutable Launch you can chain and then plan() / apply():

launch = (
client.gpu("H100", count=1, max_price=4.0, regions=["Stockholm"])
.docker("nginx:latest", ports={80: 80})
)
plan = client.plan(launch) # dry-run
inst = client.apply(launch) # launch

Workloads

Importable from the top-level package:

from substratecloud import DockerWorkload, BootScript, HealthCheck, InferenceServer

Docker

DockerWorkload(
image="vllm/vllm-openai:latest",
args=["--model", "mistralai/Mistral-7B-v0.1"],
env={"HF_TOKEN": Secret.from_env("HF_TOKEN")},
ports={8000: 8000}, # container: host
)

Boot script (preview)

Run shell steps on a bare VM, including cloning a repo at boot:

bs = BootScript(ports=[8080]).git_clone(
"https://github.com/your-org/your-repo.git", dest="/opt/app"
)

For private repos, supply a token via a secret (Secret.from_env("GIT_TOKEN") in Python, or {from_env: GIT_TOKEN} in YAML) — resolved at submit time.

InferenceServer is a convenience preset for serving models. Runnable recipes for each workload type live in the SDK repo under examples/python/.

Secrets

The Secret type is a sentinel. It never appears in repr(), is resolved at the moment the API request is built, and is redacted from structured logs.

from substratecloud import Secret

Secret.from_env("HF_TOKEN") # read from the environment at submit time
Secret.from_callable(read_hf_token, label="hf") # any callable provider (Vault / AWS SM / GCP SM)
Secret.literal("hf_xxx") # tests/dev only — emits a warning

Declarative manifests

Describe an instance in YAML and manage it with plan / apply / destroy (CLI) or client.plan() / client.apply() / client.destroy() (SDK).

# minimal-docker.yaml
name: web-1
gpu:
type: A4000
count: 1
workload:
type: docker
image: nginx:latest
ports: { 80: 80 }
lifecycle:
budget_limit_usd: "25" # required unless you pass --no-safety-net
substratecloud plan    minimal-docker.yaml
substratecloud apply minimal-docker.yaml
substratecloud destroy web-1

apply is idempotent: it looks for an existing instance tagged with the manifest name and reuses it, so re-running is safe. Ready-made manifests live in the SDK repo under examples/manifests/.