Skip to main content

hugging-bay

Promise: Find open model files with recorded SHA-256 and licence labels; verify downloaded bytes locally.
Install: python -m pip install hugging-bay
MCP config: {"mcpServers":{"hugging-bay":{"url":"https://huggingbay.xyz/api/mcp"}}} (Cursor; public reads need no account).
First call: Client().resolve("Qwen/Qwen3-0.6B")
Ask: Missing a model, file, tool or feature? Ask with request_feature (MCP) or POST https://huggingbay.xyz/api/v1/requests. No account. You get an id and can check its status. What shipped: https://huggingbay.xyz/changelog
Changelog · API docs
Keywords: gguf, local-llm, huggingface-alternative, mcp

Usage

from hugging_bay import Client

client = Client()  # defaults to https://huggingbay.xyz
# Optional auth: Client(token="sk-...") sends Authorization: Bearer <token>.
# The token is never printed in repr()/str() and never logged.

0. Get an API key (self-serve, optional)

Public discovery — search, resolve, download-plan, and hosted downloads — needs no token. You only authenticate for account workflows (saves, collections, watchlists). Minting a reader token is self-serve, with no signup and no prior auth:

from hugging_bay import Client

issued = Client().create_reader_token(display_name="my app", purpose="serving models")
token = issued["apiKey"]["token"]      # shown once — store it securely
client = Client(token=token)
print(client.me()["role"])             # validate the token

The full walkthrough (curl, JS/TS, MCP) is the one-screen quickstart at https://huggingbay.xyz/quickstart. A 401/403 from any authorized endpoint returns next.href = /quickstart#get-a-key, so there is no dead-end.

1. Find a commercial-safe model for a rig

from hugging_bay import Client

client = Client()
result = client.find_model(
    task="coding",
    gpu="rtx4090-24",
    ctx=8192,
    device_family="nvidia",
    commercial=True,
    limit=3,
)
best = result["bestPick"]
print(best["repo"], "-> safe-to-run:", best["safety"]["verdict"])

2. Verify a source URL

from hugging_bay import Client, HuggingBayError

client = Client()
try:
    resolved = client.resolve("Qwen/Qwen3-0.6B")
    print("resolved artifact:", resolved.get("artifactId") or resolved)
except HuggingBayError as err:
    print("could not resolve:", err.status, err.error)

3. Pull plan, then verify the lock against local files

from hugging_bay import Client, verify_lock

client = Client()
artifact_id = "art_123"

# The hosted download plan (signed manifest + per-file hashes).
plan = client.download_plan(artifact_id)

# Stream one hosted file, verify its exact plan hash, and record the completed
# pull. This stops the Hugging Bay redirect, follows the short-lived signed GCS
# URL without forwarding the API bearer, and only returns after attestation.
file = next(row for row in plan["files"] if row["path"] == "model.gguf")
# Case-only filename twins are refused by default. Opt in to suffix names
# allocated from the sorted full plan; generated suffixes skip every planned
# basename. The destination you pass supplies the selected file's base name,
# and existing unrelated names may advance its suffix. `pathMapping` reports
# the actual local path.
result = client.download_file(
    artifact_id,
    file["path"],
    "./models/art_123/" + file["path"],
    sha256=file["sha256"],
    size_bytes=file["sizeBytes"],
    on_case_collision="suffix",
)
print(result.get("pathMapping"))

# Recompute local hashes and compare to the bay.lock document — pure stdlib,
# no network.
lock = client.lock(artifact_id)
report = verify_lock(lock, root_dir="./models/art_123")
if report["ok"]:
    print(f"verified {report['checked']} files")
else:
    for mismatch in report["mismatches"]:
        print("BAD:", mismatch["path"], mismatch["reason"])

4. Diagnose a failing run

from hugging_bay import Client

client = Client()
diagnosis = client.doctor(
    log_text="llama_model_load: error loading model: CUDA out of memory",
    runtime="llama.cpp",
)
if diagnosis["topFix"]:
    print("top fix:", diagnosis["topFix"])
for alt in diagnosis.get("smallerHostedAlternatives", []):
    print("smaller option:", alt)

Discovery → execution with Bay Run

BayRunClient runs the mirrored weights live on Bay Run (run.huggingbay.xyz, a separate origin). Take the next_call a catalog answer returns and run it — the client mints the anonymous $0 demo key for you and tolerates the edge's plain-text 429 "Rate exceeded.":

from hugging_bay import Client, BayRunClient

runnable = Client().find_runnable(task="embeddings", limit=1)
# hugging-bay.find-runnable.v1: the handoff lives at the top-level `next_call`
# (or under `recommendation.execution`); there is no `candidates` list.
next_call = runnable.get("next_call") or runnable["recommendation"]["execution"]

with BayRunClient() as run:            # mints a $0 demo key on first call
    out = run.run_next_call(next_call, input="text to embed")
    print(out)

# Or call the OpenAI-compatible surface directly:
with BayRunClient() as run:
    run.embeddings("BAAI/bge-small-en-v1.5", "hello world")
    run.rerank("BAAI/bge-reranker-base", query="q", documents=["a", "b"])
    run.run_pin("pin_abc123", input="...")

API surface

The new typed hosted methods require BayRunClient(enable_hosted_api=True). They are off by default. Existing execution methods keep their behavior. Use pins(), pin(id), mint_pin(request), instant_models(), instant_classify(request), instant_embed(request), instant_rerank(request), instant_chat(request), and coprocessor(request). Request and response types are in hugging_bay.bayrun_types.

provenance_keys() reads published Ed25519 keys. verify_receipt(receipt) checks a receipt locally with those keys. Unknown signers fail closed. Pin keys can differ from published provenance keys, so Pin verification may need an explicit trusted key document. Never use a receipt's embedded key as trust. The standalone hugging_bay.verify_receipt(receipt, keys) works offline. Verification authenticates signed claims. It does not prove model quality or the unsigned decision. For raw-result binding, set omit_raw_result=False when calling and pass result=... to verification.

With hosted methods enabled, the client retries 429 and 503 lane_cold once unless the server marks the error retriable: false. It accepts Retry-After seconds or HTTP dates and preserves the same body and idempotency key. A cold lane without a delay gets a one second retry. Delays above max_retry_after_seconds (default 120) raise BayRunError with the full .retry_after delay. Set honor_retry_after=False to let your application schedule retries. When the hosted flag is off, existing methods retain their 429/503 retry policy and 120 second cap.

See the hosted API guide and five examples.

Method Endpoint
create_reader_token(display_name, purpose) POST /api/account/reader-token (self-serve, no auth)
me() GET /api/me
find_model(task, gpu, ctx, device_family, commercial, limit) GET /api/agents/find-model
artifact(id) GET /api/v1/artifacts/{id}
safety(id) GET /api/v1/artifacts/{id}/safety
bundle(id) GET /api/v1/artifacts/{id}/bundle
passport(id) GET /api/v1/artifacts/{id}/passport
resolve(repo_or_url) GET /api/v1/resolve?repo=
download_plan(id) GET /api/v1/artifacts/{id}/download-plan
download_file(id, path, destination, sha256, size_bytes, on_case_collision="error") GCS redirect + streamed SHA-256 verification + completion attestation; refuses case-folded path collisions by default, or returns deterministic .caseN destinations in pathMapping with on_case_collision="suffix"
lock(id) GET /api/v1/artifacts/{id}/lock
doctor(log_text, runtime) POST /api/doctor
find_runnable(task, limit, commercial, **filters) GET /api/agents/find-runnable
recipes() / recipe(slug) GET /api/recipes[/{slug}]
verify_lock(lock_dict, root_dir) offline, stdlib only
BayRunClient.free_key() POST /v1/keys/free (Bay Run)
BayRunClient.models() GET /v1/models (Bay Run)
BayRunClient.run_pin(pin_id, ...) POST /v1/run/{pin_id} (Bay Run)
BayRunClient.embeddings / rerank / classify / chat(...) OpenAI-compatible (Bay Run)
BayRunClient.run_next_call(next_call, input) executes a catalog next_call

Errors

Every Hugging Bay error is the same typed envelope on every surface: {error, code, status, message, requestId, cause?, next}. Any response with status >= 400 raises HuggingBayError, which surfaces those fields directly — .error/.code (machine code), .message, .status, .request_id, .next (the {action, href} recovery step), and the raw .body. On a 503 with a Retry-After header the client waits once and retries a single time.

resolve() follows status-based error handling: a well-formed reference with no catalog match raises status 404; malformed/unsupported input raises 400 (invalid_query). Bay Run errors raise BayRunError, which is tolerant of the edge's non-JSON bodies and exposes .retry_after.

License

MIT

Public response note

Hugging Bay responses include a download note in note.summary. Current clients should read note, downloadable, and downloadStatus. Older clients that still need the previous response shape can opt in to it for one release; see the API reference.

Downloadable doesn't mean tested: this record says whether the exact file can be downloaded now, not that the model is complete or that it runs.

Release dependency

The request-and-status sentence above is approved copy held on the c29 AEO-72/AEO-73 deployment gate. Verify the deployed request_feature, get_request, and public changelog/status path before package publication or directory copy uses it.

Generated task client and resume

client.api exposes OpenAPI-generated task methods and typed dictionaries. client.search, client.artifact, client.find_runnable, client.deployment_plan and client.download_plan use these generated wire types. Deployment plans use GET /api/agents/deployment-plan?artifact=id; download plans keep their existing route.

Pass resume=True to client.download_file to retain interrupted bytes beside the destination. Retry the same call to continue. The SDK hashes the prefix again, validates the exact storage range, and checks the full SHA-256 before completion attestation and publication. A 200 response restarts the transfer. A crashed process can leave a lock; remove it only when no download is using it.

Run python examples/read_only.py for live GET-only reads. It never downloads model bytes or attests completion. See the SDK workflow for generation, drift checks and local packaging commands.

Metadata

Release files for hugging-bay 0.4.7

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for hugging-bay 0.4.7
File Size Uploaded Provenance
hugging_bay-0.4.7.tar.gz 65.7 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for hugging-bay 0.4.7
File Interpreter ABI Platform
hugging_bay-0.4.7-py3-none-any.whl Python 3 none any Details

Total release size: 109.3 kB

Release files / hugging_bay-0.4.7.tar.gz

Download URL hugging_bay-0.4.7.tar.gz
Size 65.7 kB
Tags Source
SHA-256 checksum
How to use checksums
dc34c546beab500e275a1ebc3e916112c230eb9f51441eb26759564b2d303b5e
BLAKE2b-256 checksum
How to use checksums
c645ad53c7779bd9d7193f34a007b66daee33a1e6c146b68b450fd9c8ff28df7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.3

Release files / hugging_bay-0.4.7-py3-none-any.whl

Download URL hugging_bay-0.4.7-py3-none-any.whl
Size 43.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
8ee2378654c331e26b69c99b75e07fb51afbe0eb228b7ee2e76bcab65c0d6e51
BLAKE2b-256 checksum
How to use checksums
79943b0b653a8b87827a48aa01e6020a2472f4de4bc5f44f5589dc65eab0bbe2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.3

Security for hugging-bay 0.4.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page