Skip to content

Add Runcrate catalog provider - #280

Open
heydryft wants to merge 1 commit into
dstackai:mainfrom
heydryft:pr_add_runcrate_provider
Open

heydryft wants to merge 1 commit into
dstackai:mainfrom
heydryft:pr_add_runcrate_provider

Conversation

@heydryft

Copy link
Copy Markdown

Summary

Adds Runcrate as an online catalog provider.

  • Runcrate rents on-demand GPU and CPU VMs. Its offer list, GET https://www.runcrate.ai/api/v1/instances/types (docs), needs an API key, so this is an online provider like seeweb and hotaisle: RuncrateProvider.from_env() reads RUNCRATE_API_KEY through get_creds_env, and default_catalog() skips the provider when the variable is not set.
  • The endpoint returns every offer that can be launched right now in one unpaginated response ({"data": [...], "meta": {"total": N}}). One CatalogItem per offer:
    • instance_name is the offer id, which the create instance API takes as instance_type_id, so a future dstack backend can launch straight from the offer. Ids change as capacity changes, so they are meant to be used shortly after the query, which is how online providers are used anyway.
    • location is region as the API returns it (the same string the create API accepts), price is hourly_rate for the whole VM, cpu, memory and disk_size are cpu_cores, memory_gb and storage_gb. spot is always False.
    • provider_data carries the Runcrate gpu_type, which the create API also accepts together with gpu_count and region.
  • gpu_type is mapped to KNOWN_NVIDIA_GPUS names and memory through an explicit GPU_MAP, as daytona does: A100_80G to A100 80 GB, A100 to A100 40 GB, V100_32G to V100 32 GB, V100 to V100 16 GB, RTXPro6000 to RTXPRO6000, and the other 15 types by the same name (B300 uses the registered 270 GB). All 20 GPU types Runcrate lists today (https://www.runcrate.ai/api/gpu-pricing) are covered. An unknown type is skipped with a warning, and the integrity tests warn about unknown types in the live response (like test_real_world_lium_gpu_models).
  • GH200 offers get cpu_arch=arm through is_nvidia_superchip, as vultr does.
  • CPU-only offers (gpu_type: "CPU", gpu_count: 0) are published with no GPU fields.
  • Errors follow the sibling providers: an HTTP error (for example a 401 for a bad key) propagates through raise_for_status(), an unexpected response shape raises ValueError, and a malformed or incomplete offer is skipped with a warning.
  • Registered in ONLINE_PROVIDERS, ONLINE_PROVIDER_MODULES, the CLI (python -m gpuhunt runcrate), the README and the catalogs workflow (a test-runcrate integrity job using a RUNCRATE_API_KEY secret, like test-seeweb).

The structure follows the two most recent provider PRs: #259 (Lium: online provider, unit tests against a recorded response, integrity tests that warn about unmapped GPU names, workflow job) and #263 (Daytona: explicit GPU map, API key read from the environment, test_default.py update), plus #246 (Seeweb) for the authenticated from_env.

Testing

All run on this branch on 2026-10-25, Python 3.14, uv sync --all-extras:

  • uv run pytest src/tests: 356 passed (47 new in src/tests/providers/test_runcrate.py, run against a response recorded from the live API on 2026-10-25 and trimmed to nine offers, with offer ids replaced by placeholders; no network)
  • uv run pytest --doctest-modules src/gpuhunt: 4 passed
  • uv run pytest src/integrity_tests/test_runcrate.py with RUNCRATE_API_KEY set: 11 passed against the live API, no unknown-GPU warnings
  • uv run pyright: 0 errors
  • pre-commit run --all-files (ruff, ruff-format): passed
  • python -m gpuhunt runcrate --output runcrate.csv: 155 offers
  • gpuhunt.query(provider=["runcrate"]) with RUNCRATE_API_KEY set: 155 offers (111 GPU, 44 CPU) across 41 regions and 19 GPU types; gpuhunt.query(provider=["runcrate"], gpu_name=["A100"], min_gpu_memory=80, max_gpu_count=1) returns only 80 GB A100 offers

The new integrity job needs a RUNCRATE_API_KEY repository secret. Reading offers does not need a balance on the account; I can provide a key for it.

Gaps

These matter for a dstack backend more than for the catalog, but to be clear up front:

  • Terminate only: Runcrate instances cannot be stopped and started again.
  • No spot or interruptible capacity: every offer is on-demand, so the provider never emits spot=True.
  • Single-node: no multi-node clusters with private networking between instances yet.

AI assistance

This PR was prepared with AI assistance (Claude) and tested end to end against the live Runcrate API: the unit tests, the live integrity tests, the CLI dump and gpuhunt.query results above all come from real runs. I work on Runcrate and will maintain the provider; happy to adjust anything to your conventions.

Runcrate is an online provider: offers are queried live from
GET https://www.runcrate.ai/api/v1/instances/types with RUNCRATE_API_KEY.
Each offer is a fixed on-demand VM shape in one region; instance_name is
the offer id the create instance API takes as instance_type_id.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant