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)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| hugging_bay-0.4.7.tar.gz | 65.7 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| 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.