On this page

Download protocol

Resolve an artifact, read the hosted download plan, download with resumable byte ranges, verify SHA-256 locally, and post completion attestation.

How to download a hosted model file safely: find the artifact, read its download plan, follow the redirect, check the hash, and attest completion.

In short

  1. Search or resolve a repo to an artifact id.
  2. Read GET /api/v1/artifacts/{id}/download-plan. Trust serve.downloadReady and serveExplanation.serveVerdict — not the deprecated storage status.
  3. Pick one files[] row with a downloadUrl. Open the file's downloadUrl (/api/downloads): it re-checks and redirects to a signed link that lasts at most 300s (default 300, configurable shorter). Reopen for a fresh link. A URL is not permission.
  4. Download bytes (use Range to resume large files), verify sha256 locally, then POST to /api/download-completions/{id}/{path} with X-Hugging-Bay-Completion-Token from the redirect.

Public OpenAPI subset: /openapi-public.json. Full contract: /openapi.json.

Endpoint changes in this source candidate

Protocol revision 2026-10-20-candidate-1. Package publication and product releases are recorded separately in the changelog.

  • /api/v1/search: Optional snapshot query pins complete public search metadata; unpinned behavior is unchanged.
  • /api/v1/resolve: Optional snapshot query pins resolved public identity; missing/unsupported references retain 404/400.
  • /api/v1/artifacts/{id}/files: Optional snapshot query pins bounded public file inventory; partial/degraded reads are never frozen.
  • /api/v1/artifacts/{id}/download-plan: Existing snapshot pins remain; clients carry the same pin across discovery and plan selection.
  • /openapi-public.json: Public read profile projects canonical schemas and their referenced components from the full contract.
  • /api/downloads/{id}/{path}: No authority change: every redirect is fresh and the final bytes must match the selected plan hash/size.

Pin the whole metadata path with snapshot: search, resolve, files, finder and plan. Pins retain per-instance answers for about one hour. Check X-Hugging-Bay-Snapshot-State; an unfrozen answer, restart or different instance does not guarantee identical metadata. Byte authorization is checked again when obtaining a fresh redirect. Keep the selected hash and size when renewing a URL.

When something fails

  • HTTP 429 or 503 on plan/search/resolve Wait Retry-After (or retry_after_s in JSON), add jitter, then retry the same read.
  • HTTP 302 Location expires or returns 403 GET the same /api/downloads/{id}/{path} again without following redirects to mint a fresh signed URL (≤300s).
  • Partial download interrupted Resume with Range: bytes=<received>- on the signed URL until sizeBytes match the plan row.
  • serve.downloadReady is false or downloadUrl is missing Stop. Read serveExplanation.reason and reasonCodes; do not guess another path.
  • Local SHA-256 ≠ files[].sha256 Discard the file. Do not attest. Fetch a fresh copy from a new redirect.
  • POST /api/download-completions returns 200 Token already consumed; do not retry the POST.
More: schema fields, errors, and machine-readable spec

Top-level plan fields (generated from schema)

  • schemaVersion (required): object = "hugging-bay.artifact-download-plan.v1"
  • generatedAt (optional): string
  • artifactId (required): The one id key every surface uses (same as artifact.id).
  • artifact (required): object
  • status (optional deprecated): DEPRECATED for availability: the canonical STORAGE state (e.g. complete-bytes = bytes are stored) — NOT an obtainability, runnability or verification claim. It stays complete-bytes on a withheld artifact. Read `serve.downloadReady` / `serveExplanation.serveVerdict` instead.
  • serve (required): The single non-contradictory obtain contract (hugging-bay.serve-contract.nv5). Agrees with every per-file affordance below.
  • serveVerdict (optional): Top-level obtain verdict, same evaluation as serveExplanation.serveVerdict.
  • serveExplanation (required): The plain-words twin of `serve`, from the same evaluation (same serveEvaluationId).
  • serveEvaluatedAt (optional): string
  • serveEvaluationId (optional): string
  • files (required): Hosted file rows. A row is LISTED for inventory even when withheld; only a row with a non-false `url`/`downloadUrl` is downloadable now.
  • stats (optional): Counts over `files`: `files` = rows downloadable now, `listedFiles` = rows listed (including withheld), `withheldFiles` = listed minus downloadable.
  • manifest (optional): object
  • canonicalState (optional): object
  • completionAttestation (optional): object
  • fileIntegrity (optional): object
  • verify (optional): object
  • commands (optional): array
  • runCommands (optional): Recorded shell invocations for the selected exact file when run-command evidence is available. Each command names the tool (llama.cpp, Ollama, LM Studio), exact path, SHA-256, shell command and provenance (testedOn host, testedAt, runnerVersion). status is not-tested-yet when no sealed run kit matches.

Each files[] row (generated from schema)

  • path (required): string
  • sizeBytes (required): integer
  • sha256 (required): The full published SHA-256 of the exact bytes; verify locally with `sha256sum <file>` (older Mac: `shasum -a 256 <file>`).
  • url (optional deprecated): Legacy alias of downloadUrl; false/null when withheld.
  • downloadUrl (optional): Canonical byte-download URL. Responds HTTP 302 to signed storage; follow redirects.
  • canonicalUrlField (optional): One canonical byte URL per row. = "downloadUrl"
  • downloadUrlResponse (optional): object
  • verifiedDownloadUrl (optional): Server-stream-verified lane, when available.
  • completionAttestationUrl (optional): POST here after a full download + local SHA-256 match, with the X-Hugging-Bay-Completion-Token from the redirect.
  • contentType (optional): string
  • role (optional): string

Error codes

codeHTTPmeaning / retry
invalid_query400A query parameter is missing, malformed, or outside its documented enum or numeric range. Carries field and (for enums) allowed. Rejected at the edge before the database.
artifact_not_found404No public artifact has that id (anonymous caller). next.command searches the catalog for it.
file_withheld404The file lane refused bytes because the live file admission or artifact obtain verdict withheld them (410 for withdrawn bytes or reason_code artifact_obtain_not_ready). Files withheld — not faked; next.command reads the download-plan, whose serveExplanation says why. Artifact-verdict denials include obtainReady, serveVerdict, reasonCodes, reason, serveEvaluatedAt and serveEvaluationId. reason_code carries the lane code.
rate_limited429Too many requests in the current window. Wait retry_after_s seconds (also in Retry-After), then retry. See x-rate-limit.
service_unavailable503A bounded authority read failed closed or capacity was saturated. The document is never fabricated; wait retry_after_s seconds (always in the body), then retry.
completion_token_invalid403Re-open the download URL (do not follow the 302) for a fresh X-Hugging-Bay-Completion-Token, then POST again.
digest_mismatch409Do not retry the POST with the same bytes; re-download and re-hash locally.
signed_url_expired403GET the plan downloadUrl again; signed storage links last at most 300s.
range_not_satisfiable416Fix the Range header against sizeBytes from the plan row.

Agent-readable spec (plain text)

Hugging Bay download protocol
schemaVersion: hugging-bay.artifact-download-plan.v1
generatedFrom: openapi-developer-contract DOWNLOAD_PLAN_SCHEMA
digest: sha256:4e0ac3abf17f6c1cd5977a02d493f2e8321a4ec6f7a061e3bac4840dfdaf6803

Summary
- Find an artifact (search or resolve), read its download-plan, download only rows with downloadUrl when serve says READY.
- Open the file's downloadUrl (/api/downloads): it re-checks and redirects to a signed link that lasts at most 300s (default 300, configurable shorter). Reopen for a fresh link. A URL is not permission.
- Verify SHA-256 locally, then POST completion with the redirect token.

Obtain authority
- serve.downloadReady and serveExplanation.serveVerdict (READY / BLOCKED / PENDING / UNKNOWN)
- Legacy top-level status is storage-only: DEPRECATED for availability: the canonical STORAGE state (e.

Plan fields (from schema)
schemaVersion (required): object = "hugging-bay.artifact-download-plan.v1"
generatedAt (optional): string
artifactId (required): The one id key every surface uses (same as artifact.id).
artifact (required): object
status (optional deprecated): DEPRECATED for availability: the canonical STORAGE state (e.g. complete-bytes = bytes are stored) — NOT an obtainability, runnability or verification claim. It stays complete-bytes on a withheld artifact. Read `serve.downloadReady` / `serveExplanation.serveVerdict` instead.
serve (required): The single non-contradictory obtain contract (hugging-bay.serve-contract.nv5). Agrees with every per-file affordance below.
serveVerdict (optional): Top-level obtain verdict, same evaluation as serveExplanation.serveVerdict.
serveExplanation (required): The plain-words twin of `serve`, from the same evaluation (same serveEvaluationId).
serveEvaluatedAt (optional): string
serveEvaluationId (optional): string
files (required): Hosted file rows. A row is LISTED for inventory even when withheld; only a row with a non-false `url`/`downloadUrl` is downloadable now.
stats (optional): Counts over `files`: `files` = rows downloadable now, `listedFiles` = rows listed (including withheld), `withheldFiles` = listed minus downloadable.
manifest (optional): object
canonicalState (optional): object
completionAttestation (optional): object
fileIntegrity (optional): object
verify (optional): object
commands (optional): array
runCommands (optional): Recorded shell invocations for the selected exact file when run-command evidence is available. Each command names the tool (llama.cpp, Ollama, LM Studio), exact path, SHA-256, shell command and provenance (testedOn host, testedAt, runnerVersion). status is not-tested-yet when no sealed run kit matches.

Per-file row (from schema)
  path (required): string
  sizeBytes (required): integer
  sha256 (required): The full published SHA-256 of the exact bytes; verify locally with `sha256sum <file>` (older Mac: `shasum -a 256 <file>`).
  url (optional deprecated): Legacy alias of downloadUrl; false/null when withheld.
  downloadUrl (optional): Canonical byte-download URL. Responds HTTP 302 to signed storage; follow redirects.
  canonicalUrlField (optional): One canonical byte URL per row. = "downloadUrl"
  downloadUrlResponse (optional): object
  verifiedDownloadUrl (optional): Server-stream-verified lane, when available.
  completionAttestationUrl (optional): POST here after a full download + local SHA-256 match, with the X-Hugging-Bay-Completion-Token from the redirect.
  contentType (optional): string
  role (optional): string

Serve verdicts
READY, BLOCKED, PENDING, UNKNOWN

Snapshot scope: search, resolve, file inventory, finder and plan accept snapshot. Pins freeze metadata per instance, not signed URLs or byte authority. Check X-Hugging-Bay-Snapshot-State; unfrozen is not an immutable answer. Restart or another instance can miss a prior answer. A 410 requires restarting the metadata chain with a fresh pin. Download bytes must still match the selected plan hash and size.

Endpoint changes in this source candidate (publication is separate)
- /api/v1/search: Optional snapshot query pins complete public search metadata; unpinned behavior is unchanged.
- /api/v1/resolve: Optional snapshot query pins resolved public identity; missing/unsupported references retain 404/400.
- /api/v1/artifacts/{id}/files: Optional snapshot query pins bounded public file inventory; partial/degraded reads are never frozen.
- /api/v1/artifacts/{id}/download-plan: Existing snapshot pins remain; clients carry the same pin across discovery and plan selection.
- /openapi-public.json: Public read profile projects canonical schemas and their referenced components from the full contract.
- /api/downloads/{id}/{path}: No authority change: every redirect is fresh and the final bytes must match the selected plan hash/size.

Retry rules
- HTTP 429 or 503 on plan/search/resolve: Wait Retry-After (or retry_after_s in JSON), add jitter, then retry the same read.
- HTTP 302 Location expires or returns 403: GET the same /api/downloads/{id}/{path} again without following redirects to mint a fresh signed URL (≤300s).
- Partial download interrupted: Resume with Range: bytes=<received>- on the signed URL until sizeBytes match the plan row.
- serve.downloadReady is false or downloadUrl is missing: Stop. Read serveExplanation.reason and reasonCodes; do not guess another path.
- Local SHA-256 ≠ files[].sha256: Discard the file. Do not attest. Fetch a fresh copy from a new redirect.
- POST /api/download-completions returns 200: Token already consumed; do not retry the POST.

Error codes (download path)
- invalid_query (400): A query parameter is missing, malformed, or outside its documented enum or numeric range. Carries field and (for enums) allowed. Rejected at the edge before the database.
- artifact_not_found (404): No public artifact has that id (anonymous caller). next.command searches the catalog for it.
- file_withheld (404): The file lane refused bytes because the live file admission or artifact obtain verdict withheld them (410 for withdrawn bytes or reason_code artifact_obtain_not_ready). Files withheld — not faked; next.command reads the download-plan, whose serveExplanation says why. Artifact-verdict denials include obtainReady, serveVerdict, reasonCodes, reason, serveEvaluatedAt and serveEvaluationId. reason_code carries the lane code.
- rate_limited (429): Too many requests in the current window. Wait retry_after_s seconds (also in Retry-After), then retry. See x-rate-limit.
- service_unavailable (503): A bounded authority read failed closed or capacity was saturated. The document is never fabricated; wait retry_after_s seconds (always in the body), then retry.
- completion_token_invalid (403): Re-open the download URL (do not follow the 302) for a fresh X-Hugging-Bay-Completion-Token, then POST again.
- digest_mismatch (409): Do not retry the POST with the same bytes; re-download and re-hash locally.
- signed_url_expired (403): GET the plan downloadUrl again; signed storage links last at most 300s.
- range_not_satisfiable (416): Fix the Range header against sizeBytes from the plan row.

# Worked example: resolve → plan → download (resume) → verify → attest
# Requires curl, jq and either sha256sum (Linux) or shasum (Mac). Choose a repo and an exact path from its plan.
set -eu
BASE='https://huggingbay.xyz'
REPO='Qwen/Qwen2.5-0.5B-Instruct-GGUF'
WORK=$(mktemp -d)
trap 'rm -rf "$WORK"' EXIT
PIN=$(curl -fsS "$BASE/api/v1/snapshot" | jq -er '.snapshotId')
curl -fsS --get --data-urlencode "repo=$REPO" --data-urlencode "snapshot=$PIN" "$BASE/api/v1/resolve" > "$WORK/resolve.json"
ARTIFACT=$(jq -er '.artifactId' "$WORK/resolve.json")
curl -fsS --get --data-urlencode "snapshot=$PIN" "$BASE/api/v1/artifacts/$ARTIFACT/download-plan" > "$WORK/plan.json"
jq -e '.serve.downloadReady == true' "$WORK/plan.json" > /dev/null
# Inspect files[] and choose FILE explicitly; this example chooses the first READY GGUF.
jq -e '[.files[] | select(.downloadUrl != null and (.path | endswith(".gguf")))][0] | select(. != null)' "$WORK/plan.json" > "$WORK/file.json"
HASH=$(jq -er '.sha256 | sub("^sha256:"; "") | ascii_downcase | select(test("^[0-9a-f]{64}$"))' "$WORK/file.json")
BYTES=$(jq -er '.sizeBytes | select(type == "number" and . >= 0 and floor == .)' "$WORK/file.json")
DOWNLOAD=$(jq -er '.downloadUrl' "$WORK/file.json")
case "$DOWNLOAD" in "$BASE/api/downloads/$ARTIFACT/"*) ;; *) exit 1 ;; esac
# The signed redirect and capability are fresh, never snapshot-cached. Do not log them.
curl -fsS -D "$WORK/headers" -o /dev/null "$DOWNLOAD"
TOKEN=$(awk 'tolower($1)=="x-hugging-bay-completion-token:" {gsub("\r", "", $2); print $2}' "$WORK/headers")
LOC=$(awk 'tolower($1)=="location:" {gsub("\r", "", $2); print $2}' "$WORK/headers")
test -n "$TOKEN" && test -n "$LOC"
# Re-run this transfer with a fresh redirect if its signed URL expires. Keep HASH and BYTES.
curl -fsSL -C - -o model.gguf.part "$LOC"
test "$(wc -c < model.gguf.part | tr -d ' ')" = "$BYTES"
if command -v sha256sum > /dev/null 2>&1; then
  printf '%s  model.gguf.part\n' "$HASH" | sha256sum -c -
else
  printf '%s  model.gguf.part\n' "$HASH" | shasum -a 256 -c -
fi
# Completion route follows the plan-selected file, not a guessed filename.
COMPLETION=$(printf '%s' "$DOWNLOAD" | sed 's#/api/downloads/#/api/download-completions/#')
jq -n --arg sha256 "$HASH" --argjson sizeBytes "$BYTES" --arg completionToken "$TOKEN" '{sha256:$sha256,sizeBytes:$sizeBytes,completionToken:$completionToken}' > "$WORK/completion.json"
curl -fsS -X POST -H 'content-type: application/json' --data-binary @"$WORK/completion.json" "$COMPLETION"
mv model.gguf.part model.gguf
Quick answer: compatibility and sources

How do I use Download protocol?

It depends on your client and setup. Resolve an artifact, read the hosted download plan, download with resumable byte ranges, verify SHA-256 locally, and post completion attestation. Check the current file record before downloading. Metadata access, file hosting and a tested runtime are separate things.

Model weights are learned parameters; a runtime is the software that loads them. RAM is working memory, separate from disk space for downloaded files.

Page-copy provenance: the revision record names apps/web/server.mjs, apps/web/lib/aeo-page.mjs, apps/web/lib/api-status-contract.mjs, apps/web/lib/agent-readable.mjs, apps/web/lib/docs-hub-model.mjs, apps/web/lib/compare-pages.mjs and commit 8871bab84e1cf80aea1686a944ec335078a6c036. This identifies the text source; it is not a model test receipt. A SHA-256 checksum fingerprints file bytes, not safety or answer quality. See what file verification checks. Run receipts, when present, belong to a specific model file and setup; this page asserts no model test.

Page sources and update history

Updated · Page-copy source revision 8871bab84e1cf80aea1686a944ec335078a6c036 · Source files: apps/web/server.mjs, apps/web/lib/aeo-page.mjs, apps/web/lib/api-status-contract.mjs, apps/web/lib/agent-readable.mjs, apps/web/lib/docs-hub-model.mjs, apps/web/lib/compare-pages.mjs · Full revision record

Key facts

Catalog vs runtime
Metadata access, file hosting and a tested load are separate checks.
Checksum
SHA-256 confirms file identity, not license permission or answer quality.
Receipts
Run evidence is scoped to one file and setup; it does not transfer to other files.

Evidence you can inspect (plain text)

  • GET /openapi.json lists request and response shapes for public API reads.
  • GET /api/agent-discovery lists agent-facing interfaces when enabled.
  • Open /artifact/hf-model-qwen-qwen3-8b/files for model exact filenames, availability and any recorded SHA-256.
  • Open /evidence/artifacts/hf-model-qwen-qwen3-8b for run-readiness evidence tied to that record; absent receipts stay unmeasured.
  • Open /api/artifacts/hf-model-qwen-qwen3-8b/card.md for machine-readable source facts (not a runtime test).
  • These documents describe interfaces and catalog reads; they do not execute or score models.

Unmeasured states are stated explicitly; this page does not invent run scores or compatibility guarantees.

Which date applies to which fact

  • Committed page-copy sources:
  • Upstream model metadata: Dates on artifact records when shown; not implied by page-copy revision
  • Run receipts: Only on /evidence pages when recorded; otherwise unmeasured

Page-copy revision (Updated line above) identifies committed text sources, not upstream model edits or test outcomes.