HologramHologram

Reference

API reference

Every route the hub answers, grouped by what it is for, generated from the OpenAPI document.

Markdown

One base URL, no key for any read. Everything below is generated at build time from /openapi.json, the OpenAPI 3.1 document that describes the whole endpoint, so a route cannot appear here without being described there. The interactive rendering of the same document is at /docs.

https://gethologram.ai
Placeholder Meaning Example
{owner}/{name} a model id, as on Hugging Face hexgrad/Kokoro-82M
{revision} main, or the commit the hub indexed f3ff3571791e39611d31c381e3a41a3af07b4987
{path} a file inside the model; may contain slashes voices/af_heart.pt
{source} huggingface, modelscope or ipfs ipfs
{id} an object address blake3:3cc11e52…

Models

Find a model and read its files, in Hugging Face's shape. This is the dialect every Python client already speaks.

GET/api/models

Search the index.

Hugging Face's list shape, so HfApi.list_models works unchanged, plus a hologram block on every row carrying the facts Hugging Face has no field for: the index address of the model, how many files it has, how many bytes of weights, and which sources hold them. A search costs a few hundred bytes; reading the whole catalog object costs several hundred KB, so search here rather than there.

This route lists everything the hub holds, not only what is trending today. Rows for models on the current browse list carry the full facts — task, parameters, library, downloads, licence. Models the browse list has forgotten, but whose bytes this hub has published and still serves, appear as thin rows: the name, the index address, and hologram.listed: false. The facts a browse row carries were never published with the object, so a thin row says so rather than reporting zeros as if they were measurements. Filter on hologram.listed if you want one kind or the other.

Query parameters are checked rather than coerced: a limit outside 1–500 or one that is not a whole number, and a sort outside the enum, each refuse with 400 BadParameter and a sentence saying what is allowed.

ParameterInTypeDescription
search optionalquerystringCase-insensitive substring of the model id.
author optionalquerystringExact owner match.
pipeline_tag optionalquerystringExact task match.
library optionalquerystringExact library match.
filter optionalqueryarray of stringTag that must be present. Repeat the parameter, or comma-separate. Tags include the task, the library, the format, the architecture, license:<id> and languages.
sort optionalquerydownloads, likes, trendingScore, trending_score, createdAt, created_atSort key.
direction optionalquerystring1 sorts ascending. Anything else sorts descending.
limit optionalqueryintegerRows to return, 1 to 500.
StatusMeaning
200Matching rows, most relevant first by the chosen sort. application/json
400A parameter is outside what this operation accepts. application/json
405The hub endpoint is read-only: any method other than GET or HEAD on this path is refused. application/json

GET/api/models/{owner}/{name}

One model at the indexed revision.

Hugging Face's model-info shape. sha is the revision the hub pinned; siblings lists every file. For sizes and hashes ask for the tree instead.

ParameterInTypeDescription
ownerpathstringThe owning organisation or user, exactly as on Hugging Face.
namepathstringThe model name.
StatusMeaning
200The model. application/json
403The model is gated on Hugging Face. The hub serves public models only and will not proxy a gate. application/json
404Not in the index. The request is recorded and considered for the next index run. application/json

GET/api/models/{owner}/{name}/revision/{revision}

One model, asserting the revision.

The same answer as getModel, refused unless the revision you name is the one the hub indexed. Use it to fail loudly rather than silently receive a different revision.

ParameterInTypeDescription
ownerpathstringThe owning organisation or user, exactly as on Hugging Face.
namepathstringThe model name.
revisionpathstringmain, or a commit prefix of at least seven characters. The hub indexes one revision per model and refuses any other, so main is always the pinned revision.
StatusMeaning
200The model. application/json
404Either the model is not indexed, or it is indexed at another revision. application/json

GET/api/models/{owner}/{name}/refs

The branches the hub knows.

Always exactly one branch, main, pointing at the indexed revision. Clients call this before a download to turn main into a commit.

ParameterInTypeDescription
ownerpathstringThe owning organisation or user, exactly as on Hugging Face.
namepathstringThe model name.
StatusMeaning
200One branch, no tags. application/json
404Not in the index. application/json

GET/api/models/{owner}/{name}/tree/{revision}

Every file, with its size and its SHA-256.

oid is the SHA-256 of the file's bytes, which is the value you check a download against. This is the only place the expected hashes come from: never take a hash from the source that serves the bytes.

ParameterInTypeDescription
ownerpathstringThe owning organisation or user, exactly as on Hugging Face.
namepathstringThe model name.
revisionpathstringmain, or a commit prefix of at least seven characters. The hub indexes one revision per model and refuses any other, so main is always the pinned revision.
StatusMeaning
200One entry per file. application/json
404Not in the index, or indexed at another revision. application/json

GET/api/models/{owner}/{name}/tree/{revision}/{prefix}

The files under one directory.

The same entries, filtered to one directory prefix.

ParameterInTypeDescription
ownerpathstringThe owning organisation or user, exactly as on Hugging Face.
namepathstringThe model name.
revisionpathstringmain, or a commit prefix of at least seven characters. The hub indexes one revision per model and refuses any other, so main is always the pinned revision.
prefixpathstringDirectory prefix, with or without a trailing slash.
StatusMeaning
200One entry per file under the prefix; empty if nothing matches. application/json
404Not in the index, or indexed at another revision. application/json

GET/api/models/{owner}/{name}/xet-read-token/{revision}

Hand a Xet client back to Hugging Face.

huggingface_hub follows the hub's redirect, meets Hugging Face's Xet headers there, then asks this endpoint for a Xet read token. That token is Hugging Face's to give, so the hub sends the client there and issues nothing itself.

ParameterInTypeDescription
ownerpathstringThe owning organisation or user, exactly as on Hugging Face.
namepathstringThe model name.
revisionpathstringmain, or a commit prefix of at least seven characters. The hub indexes one revision per model and refuses any other, so main is always the pinned revision.
StatusMeaning
307Redirect to the same path on huggingface.co.
405The hub endpoint is read-only: any method other than GET or HEAD on this path is refused. application/json

Files

Turn a model file into a URL that is up right now, together with the SHA-256 it must have.

GET/{owner}/{name}/resolve/{revision}/{path}

A URL for one file, at a source that is up.

The route every download goes through. The hub answers 302 to the first source in its preference order that passed the last probe, and puts the expected SHA-256 in ETag and X-Linked-Etag and the serving source in X-Hub-Source. No weight byte passes through the hub.

Ask for the path SHA256SUMS and the hub synthesises the checksum file for the whole model instead, so a download can be checked with sha256sum -c and no tool of ours.

ParameterInTypeDescription
ownerpathstringThe owning organisation or user, exactly as on Hugging Face.
namepathstringThe model name.
revisionpathstringmain, or a commit prefix of at least seven characters. The hub indexes one revision per model and refuses any other, so main is always the pinned revision.
pathpathstringThe file path inside the repository. It may contain slashes; do not encode them. The literal path SHA256SUMS is synthesised by the hub and is not a file of the repository.
StatusMeaning
200Only for the synthesised SHA256SUMS path: the checksum file itself. text/plain
302Follow Location for the bytes, then check them against ETag.
404The model is not indexed, the revision is not the indexed one, or the file is not in it. application/json

GET/via/{source}/{owner}/{name}/resolve/{revision}/{path}

A URL for one file, from the source you name.

The caller states the policy and the hub executes it: /via/ipfs/... serves from IPFS even when Hugging Face is up. The prefix works in front of any Models or Files route, not only this one.

A pin is a constraint, not a hint. If the named source does not hold the file this refuses with 404 SourceHasNotGotIt, naming the sources that do; an unrecognised source name refuses with 404 UnknownSource. It does not quietly serve you something else. That matters most for the obvious use of a pin — fetching the same file through two sources and comparing them — which is worthless if one fetch can silently come from the other's host.

X-Hub-Source still names who served, and on this route it will always equal the source you asked for. Drop the prefix to let the hub choose by health and order.

ParameterInTypeDescription
sourcepathhuggingface, modelscope, ipfsPin one byte source instead of letting the hub choose.
ownerpathstringThe owning organisation or user, exactly as on Hugging Face.
namepathstringThe model name.
revisionpathstringmain, or a commit prefix of at least seven characters. The hub indexes one revision per model and refuses any other, so main is always the pinned revision.
pathpathstringThe file path inside the repository. It may contain slashes; do not encode them. The literal path SHA256SUMS is synthesised by the hub and is not a file of the repository.
StatusMeaning
200Only for the synthesised SHA256SUMS path, which the prefix reaches like any other. text/plain
302Redirect to a source. Check X-Hub-Source: it names who actually served, which is not always the source you asked for.
404Unknown model, revision or file; SourceHasNotGotIt when the named source does not hold this file, naming the ones that do; or UnknownSource when the source name is not one this hub knows. A malformed source segment, such as one with capitals, is refused by the edge as a bare 404 with an empty body rather than in this shape. application/json
405The hub endpoint is read-only: any method other than GET or HEAD on this path is refused. application/json

GET/via/{source}/api/models

Search with a source pinned for what follows.

The same rows as listModels. The prefix is accepted on every read route so a client can be configured once, with HF_ENDPOINT=https://gethologram.ai/via/ipfs, and never choose again.

ParameterInTypeDescription
sourcepathhuggingface, modelscope, ipfsPin one byte source instead of letting the hub choose.
StatusMeaning
200Matching rows. application/json
405The hub endpoint is read-only: any method other than GET or HEAD on this path is refused. application/json

Registry

The OCI distribution dialect: Ollama pulls, CNCF ModelPack artifacts, and the hub's own daily index. Reads are anonymous; a write is refused at the edge unless it carries the registry token that docker login sends, and writes are not described here because only the hub publishes.

GET/v2/

The OCI distribution entry point.

200 {} means version 2 of the distribution API is supported and reads are anonymous. docker login is needed only to push.

StatusMeaning
200The registry speaks the v2 API. application/json
401A write was attempted without a registry token. Reads never need one. text/plain

GET/v2/_catalog

The repositories the hub's own registry holds.

The hub's registry namespace only, model-hub/index among them. Model repositories are answered from the index and do not appear here; ask for a model's tags directly.

StatusMeaning
200Repository names. application/json
401A write was attempted without a registry token. Reads never need one. text/plain

GET/v2/{owner}/{name}/tags/list

The tags a model can be pulled by.

latest always, plus one tag per single-file GGUF quantisation, which is what ollama pull …:Q4_K_M asks for. Owner and name must be lowercase: OCI references are case-sensitive and lowercase-only.

ParameterInTypeDescription
ownerpathstringThe owning organisation or user, exactly as on Hugging Face.
namepathstringThe model name.
StatusMeaning
200The tag list. application/json
404Not in the index. application/json

GET/v2/{owner}/{name}/manifests/{reference}

A model as an OCI artifact.

One route, two answers, chosen by Accept. Send the OCI manifest type and the hub answers a CNCF ModelPack artifact whose layers are the model's files, each layer digest being that file's SHA-256, which oras, modctl, skopeo and crane all verify for you. Send the Docker manifest type, which is what Ollama sends, and the hub answers a GGUF model manifest; models with no GGUF file refuse it.

ParameterInTypeDescription
ownerpathstringThe owning organisation or user, exactly as on Hugging Face.
namepathstringThe model name.
referencepathstringA tag, or a manifest digest asked for again.
Accept optionalheaderstringapplication/vnd.oci.image.manifest.v1+json for ModelPack, application/vnd.docker.distribution.manifest.v2+json for Ollama.
StatusMeaning
200The manifest. Every layer digest is the SHA-256 of one file of the model. application/vnd.oci.image.manifest.v1+json, application/vnd.docker.distribution.manifest.v2+json
404Not in the index, or asked for a GGUF manifest of a model that has none. application/json

GET/v2/{owner}/{name}/blobs/{digest}

One layer of a model artifact.

Small layers (config, chat template, parameters) are answered directly, each checked against its digest before the hub keeps it. Weight layers are a redirect to a live source; the client verifies the digest, as every OCI client already does. HEAD answers 200 with the size directly, because newer Ollama refuses a cross-host redirect on HEAD.

ParameterInTypeDescription
ownerpathstringThe owning organisation or user, exactly as on Hugging Face.
namepathstringThe model name.
digestpathstringsha256:<64 hex>, the SHA-256 of the file's bytes.
StatusMeaning
200A small layer, in full. application/octet-stream
307A weight layer: follow Location, then verify the digest.
404No such blob in this model at the indexed revision. application/json

MCP

The Model Context Protocol server, for agents that bind to tools rather than to routes.

POST/mcp

The Model Context Protocol server.

Streamable HTTP, stateless, anonymous, POST only. Protocol versions 2026-07-28, 2025-11-25, 2025-06-18 and 2025-03-26 are accepted. Three tools: search_models finds one, get_model lists its files with sizes and hashes, resolve_file gives a URL, the SHA-256 it must have, and the command that hands the file to an engine.

Weight bytes never travel in a tool result: the tool returns the instruction, the agent's shell or engine does the download.

get_model returns at most 200 files. When a model has more it keeps every config, tokenizer and other small text file first, fills the remainder with the largest weights, and sets files_truncated and files_truncated_note; files_total always counts the whole model. It truncates by usefulness rather than alphabetically, because the tail of a model directory is where the tokenizer lives and a caller cannot proceed without it. For the complete list use listModelFiles.

Body: application/json — A JSON-RPC 2.0 request.

StatusMeaning
200A JSON-RPC 2.0 response. A tool that fails answers 200 with result.isError set, as the protocol requires. application/json
405GET and DELETE are refused: the server keeps no session, so there is no stream to open or close. application/json

Objects

The content-addressed floor under every dialect. An object is named by the BLAKE3 of its bytes, so its answer can be cached forever.

GET/api/v1/capabilities

What this server can do.

Every operation the server exposes, which modules are loaded, and the hard limits. maximum_message_bytes is 32 MiB: anything larger is published as chunks.

StatusMeaning
200The capability manifest. application/json
404The edge routes only GET and HEAD to this path; anything else falls through to the catch-all. text/plain

GET/api/v1/modules

The modules that are loaded.

One entry per module, with the operations it owns and whether it is ready.

StatusMeaning
200Success. application/json
404The edge routes only GET and HEAD to this path; anything else falls through to the catch-all. text/plain

GET/api/v1/objects

List stored objects.

Needs a publisher token. Reading a known address needs none. There is no anonymous listing, on purpose: the catalog is the public index and it is one object away.

Auth: publisherToken

StatusMeaning
200Success. application/json
401No publisher token. text/plain

POST/api/v1/objects

Publish an object.

The body is the bytes; the response id is their BLAKE3 address. Up to 8 MiB per request at the edge, 32 MiB at the server. Larger payloads are published as chunks and joined by a source record.

Auth: publisherToken

ParameterInTypeDescription
content-type optionalheaderstring,nullStored media type
x-hologram-kind optionalheaderstring,nullObject kind; defaults to file
x-hologram-filename optionalheaderstring,nullOriginal filename

Body: application/octet-stream — The object's bytes.

StatusMeaning
201Success. application/json
401No publisher token. text/plain

GET/api/v1/objects/{id}

One object, by the hash of its bytes.

The content-addressed floor. The answer for an address never changes, so it is served immutable with a one-year lifetime and may be cached forever. The server does not verify on read: hash what arrives and keep it only if the BLAKE3 equals the address you asked for.

ParameterInTypeDescription
idpathstringblake3:<64 hex>, the hash of the object's bytes.
StatusMeaning
200The object's bytes, served under the media type they were published with. The hub publishes application/vnd.hologram.model-hub.catalog.v1+json for a catalog, …model.v1+json for one model revision and …source.v1+json for one place its bytes can be fetched; anything else published here keeps its own type, and an object stored without one is served as opaque bytes. Match on the address, not on the media type. application/vnd.hologram.model-hub.catalog.v1+json, application/vnd.hologram.model-hub.model.v1+json, application/vnd.hologram.model-hub.source.v1+json, application/octet-stream
400The path is not an address. An address is blake3: followed by 64 hexadecimal characters; anything else under this prefix is refused at the edge rather than passed to the server. application/json
404No object at that address. application/json

Account

The only surface that needs a person. Everything else on this endpoint is anonymous, and signing in adds nothing to it: an account exists so that a saved list, an attributed model request and a recorded interest in publishing have somewhere to live. Signing in grants no read that anonymous callers do not already have, and publishing access is an operator's decision, not a form's.

GET/api/account/health

Is sign-in available.

The one account route that needs no token. configured: false means this hub has no sign-in keys, which changes nothing for anonymous callers.

StatusMeaning
200Whether the account service is up and configured. application/json
404Any other path under /api/account that is not a route answers 404 once the caller is signed in. application/json

GET/api/account/me

The signed-in account.

What the hub holds for this person: nothing but a saved list, the models they asked for, and a wallet address they chose to report.

Auth: privyToken

StatusMeaning
200The account. application/json
401Not signed in, or the token is not this hub's to accept. application/json
429Too many requests from this account. application/json
503Sign-in is not configured on this hub. Every anonymous surface still works. application/json

PATCH/api/account/me

Record or clear a wallet address.

The address is Privy's to mint and the page's to report. It is recorded and never trusted for anything.

Auth: privyToken

Body: application/json

StatusMeaning
200The address as it now stands. application/json
400Not an address. application/json
401Not signed in, or the token is not this hub's to accept. application/json
429Too many requests from this account. application/json
503Sign-in is not configured on this hub. Every anonymous surface still works. application/json

POST/api/account/saved

Save a model to this account.

A list the person keeps, nothing more. It is not a download, a pin or a claim on anything.

Auth: privyToken

Body: application/json

StatusMeaning
200The saved list. application/json
400Not a model id. application/json
401Not signed in, or the token is not this hub's to accept. application/json
409The saved list is full. application/json
429Too many requests from this account. application/json
503Sign-in is not configured on this hub. Every anonymous surface still works. application/json

DELETE/api/account/saved/{model}

Remove a model from the saved list.

Removing something that is not there is not an error.

Auth: privyToken

ParameterInTypeDescription
modelpathstringThe model id, URL-encoded (the slash included).
StatusMeaning
200The saved list as it now stands. application/json
401Not signed in, or the token is not this hub's to accept. application/json
429Too many requests from this account. application/json
503Sign-in is not configured on this hub. Every anonymous surface still works. application/json

POST/api/account/request

Ask for a model to be indexed.

The anonymous version of this already happens: the endpoint records every model it is asked for and does not have. Signing in only adds attribution, so the operator can tell one person asking ten times from ten people asking once.

Auth: privyToken

Body: application/json

StatusMeaning
200Recorded. application/json
400Not a model id. application/json
401Not signed in, or the token is not this hub's to accept. application/json
409This account has asked for enough for now. application/json
429Too many requests from this account. application/json
503Sign-in is not configured on this hub. Every anonymous surface still works. application/json

POST/api/account/publisher-request

Record an interest in publishing.

It issues nothing and grants nothing. Who may write to this registry is an operator's decision, and a decision is not something a web form gets to make.

Auth: privyToken

Body: application/json

StatusMeaning
202Recorded, and nothing was issued. application/json
401Not signed in, or the token is not this hub's to accept. application/json
429Too many requests from this account. application/json
503Sign-in is not configured on this hub. Every anonymous surface still works. application/json

Health

Is the endpoint up, and which byte sources are up behind it.

GET/healthz

Is the endpoint up.

The Hologram Server behind the object routes. status: ready means the object plane answers; it says nothing about byte sources, which have their own probe.

StatusMeaning
200The server is up. application/json
404The edge routes only GET and HEAD to this path; anything else falls through to the catch-all. text/plain

GET/api/hub/health

Which byte sources are up, as seen from the hub.

The result of the hub's own periodic probe of every source it can redirect to, and the order it prefers them in. A file request is sent to the first source in order that is ok.

This is measured from the hub, not from you. A source reported ok here can still be unreachable from the network you are on — ipfs.filebase.io in particular is blocked or TLS-terminated on some networks while the hub reaches it fine. Read this as the hub's routing preference, not as a promise about your own failover. If failover matters to you, test a /via/{source} fetch from where your code will actually run.

StatusMeaning
200Per-source liveness and the preference order. application/json
405The hub endpoint is read-only: any method other than GET or HEAD on this path is refused. application/json

Discovery

What this endpoint is, in a form a machine can bind to without reading prose.

GET/

The hub, answered three ways.

One URL, three readers, chosen by Accept.

A browser sends text/html and gets the website. A caller that asks for application/json by name gets the descriptor, which points at today's catalog address and at everything else here. Anything else — */*, which is what curl, node's fetch and python's requests all send, and therefore what an arriving agent actually asks — gets agent.md: the whole hub on one screen, in the imperative, ending in a check it can run itself.

So curl gethologram.ai is the shortest useful thing an agent can be told about this service.

ParameterInTypeDescription
Accept optionalheaderstringtext/html for the site, application/json for the descriptor, anything else for the brief.
StatusMeaning
200The website, the descriptor or the brief, depending on what was asked for. application/json, text/markdown, text/html
405The hub endpoint is read-only: any method other than GET or HEAD on this path is refused. application/json

GET/.well-known/model-hub.json

The hub descriptor at its well-known path.

The same bytes as GET / with Accept: application/json. Start here if you were given nothing but the host name.

StatusMeaning
200The descriptor. application/json
404This document describes a deployment that serves this path; a hub that has not been updated to it answers 404 here. Fall back to /llms.txt, which every deployment serves. text/plain

GET/openapi.json

This document.

The whole endpoint, every dialect, in one OpenAPI 3.1 document. /docs renders it. Both paths serve the same bytes; the well-known one exists because that is where an agent looks first.

StatusMeaning
200This document. application/json
404This document describes a deployment that serves this path; a hub that has not been updated to it answers 404 here. Fall back to /llms.txt, which every deployment serves. text/plain

GET/.well-known/openapi.json

This document.

The whole endpoint, every dialect, in one OpenAPI 3.1 document. /docs renders it. Both paths serve the same bytes; the well-known one exists because that is where an agent looks first.

StatusMeaning
200This document. application/json
404This document describes a deployment that serves this path; a hub that has not been updated to it answers 404 here. Fall back to /llms.txt, which every deployment serves. text/plain

GET/.well-known/agent-card.json

An agent card for this endpoint.

The hub described as a set of skills, for frameworks that discover services through an agent card rather than an OpenAPI document.

StatusMeaning
200The agent card. application/json
404This document describes a deployment that serves this path; a hub that has not been updated to it answers 404 here. Fall back to /llms.txt, which every deployment serves. text/plain

GET/agent.md

The whole hub, for the agent that just arrived.

One screen of plain markdown: what this is, the one line that switches an existing tool over, the three requests that use it directly, and the rule that makes the bytes safe. It is what GET / answers to anything that is not a browser, and it ends with a check the reader can run to confirm the rest. The last line is a canary: a fetcher that summarises drops it, and an agent that cannot see it knows to fetch this path again verbatim.

StatusMeaning
200Markdown, a few hundred lines at most. text/markdown, text/plain
404This document describes a deployment that serves this path; a hub that has not been updated to it answers 404 here. Fall back to /llms.txt, which every deployment serves. text/plain

GET/models

The models section, answered two ways.

The site shows this address beside the models heading — the same tag on every section, so one shape covers all five. A browser gets the section's page; anything else gets a brief covering finding a model, proving it and fetching it: the few requests that do the job, in the order you would make them, with the rule that makes the bytes safe. Ask for application/json and the same address answers a section descriptor: one fixed shape, the same on all five sections, naming how to enumerate this section, how to reach one item, how to fetch its bytes and how to check them. Where the section has a snapshot, catalog.address is a content address holding the whole of it, so the entire section is one verifiable fetch. Where it has none the field is null and list carries a live route instead; no section borrows a catalogue it does not have. It adds no API — every route the descriptor names is already in this document. What was missing was an address that gathers them, which the site was already advertising. The trailing slash works either way, and a page below the section, such as a single model or one docs page, is untouched.

StatusMeaning
200The section descriptor to a caller that asked for JSON, the section brief to any other non-browser, and the section's page to a browser. application/json, text/markdown, text/html
404This document describes a deployment that serves this path; a hub that has not been updated to it answers 404 here. Fall back to /llms.txt, which every deployment serves. text/plain

GET/registry

The registry section, answered two ways.

The site shows this address beside the registry heading — the same tag on every section, so one shape covers all five. A browser gets the section's page; anything else gets a brief covering pulling the same models as OCI artifacts: the few requests that do the job, in the order you would make them, with the rule that makes the bytes safe. Ask for application/json and the same address answers a section descriptor: one fixed shape, the same on all five sections, naming how to enumerate this section, how to reach one item, how to fetch its bytes and how to check them. Where the section has a snapshot, catalog.address is a content address holding the whole of it, so the entire section is one verifiable fetch. Where it has none the field is null and list carries a live route instead; no section borrows a catalogue it does not have. It adds no API — every route the descriptor names is already in this document. What was missing was an address that gathers them, which the site was already advertising. The trailing slash works either way, and a page below the section, such as a single model or one docs page, is untouched.

/v2/ itself is deliberately left alone: it is a protocol endpoint and OCI clients depend on exactly what it returns.

StatusMeaning
200The section descriptor to a caller that asked for JSON, the section brief to any other non-browser, and the section's page to a browser. application/json, text/markdown, text/html
404This document describes a deployment that serves this path; a hub that has not been updated to it answers 404 here. Fall back to /llms.txt, which every deployment serves. text/plain

GET/spaces

The spaces section, answered two ways.

The site shows this address beside the spaces heading — the same tag on every section, so one shape covers all five. A browser gets the section's page; anything else gets a brief covering browser-only apps, each sealed under one root digest, and how to read one from the registry: the few requests that do the job, in the order you would make them, with the rule that makes the bytes safe. Ask for application/json and the same address answers a section descriptor: one fixed shape, the same on all five sections, naming how to enumerate this section, how to reach one item, how to fetch its bytes and how to check them. Where the section has a snapshot, catalog.address is a content address holding the whole of it, so the entire section is one verifiable fetch. Where it has none the field is null and list carries a live route instead; no section borrows a catalogue it does not have. It adds no API — every route the descriptor names is already in this document. What was missing was an address that gathers them, which the site was already advertising. The trailing slash works either way, and a page below the section, such as a single model or one docs page, is untouched.

StatusMeaning
200The section descriptor to a caller that asked for JSON, the section brief to any other non-browser, and the section's page to a browser. application/json, text/markdown, text/html
404This document describes a deployment that serves this path; a hub that has not been updated to it answers 404 here. Fall back to /llms.txt, which every deployment serves. text/plain

GET/buckets

The buckets section, answered two ways.

The site shows this address beside the buckets heading — the same tag on every section, so one shape covers all five. A browser gets the section's page; anything else gets a brief covering walking a bucket as an OCI index tree and checking every block against its address: the few requests that do the job, in the order you would make them, with the rule that makes the bytes safe. Ask for application/json and the same address answers a section descriptor: one fixed shape, the same on all five sections, naming how to enumerate this section, how to reach one item, how to fetch its bytes and how to check them. Where the section has a snapshot, catalog.address is a content address holding the whole of it, so the entire section is one verifiable fetch. Where it has none the field is null and list carries a live route instead; no section borrows a catalogue it does not have. It adds no API — every route the descriptor names is already in this document. What was missing was an address that gathers them, which the site was already advertising. The trailing slash works either way, and a page below the section, such as a single model or one docs page, is untouched.

StatusMeaning
200The section descriptor to a caller that asked for JSON, the section brief to any other non-browser, and the section's page to a browser. application/json, text/markdown, text/html
404This document describes a deployment that serves this path; a hub that has not been updated to it answers 404 here. Fall back to /llms.txt, which every deployment serves. text/plain

GET/models/

The models, browsed.

The browse page: every model the hub lists, with its files, sizes and addresses. For people; anything that is not a browser gets the section brief instead of 236 KB of markup. A page below this one, such as a single model, is untouched by that and always answers HTML.

StatusMeaning
200The page to a browser; to anything else the section brief, the same bytes as /models. text/html, text/markdown
404This document describes a deployment that serves this path; a hub that has not been updated to it answers 404 here. Fall back to /llms.txt, which every deployment serves. text/plain

GET/docs

This document, rendered.

A reference page for people, built from /openapi.json at load time. It is the same contract as the document; nothing is written twice.

StatusMeaning
200An HTML page. text/html
404This document describes a deployment that serves this path; a hub that has not been updated to it answers 404 here. Fall back to /llms.txt, which every deployment serves. text/plain

GET/docs/

The documentation.

Overview, quickstart, the concepts, one page per dialect, and a reference generated from this document. Every page has a Markdown twin at /docs/{page}.md, and /llms.txt lists them all.

This is also the address the site shows beside the Docs heading, the same tag every section carries. A browser gets this index; anything else gets the section brief, which lists every page and the address of its twin, generated from the pages themselves. The slash is load-bearing: /docs without one is the server's own API reference, on a different upstream.

StatusMeaning
200The descriptor to a caller that asked for JSON, the section brief to any other non-browser, the index to a browser. application/json, text/html, text/markdown
404This document describes a deployment that serves this path; a hub that has not been updated to it answers 404 here. Fall back to /llms.txt, which every deployment serves. text/plain

GET/docs/{page}/

One documentation page.

The page named by its slug: quickstart, verification, addresses, sources, huggingface, ollama, oci, mcp, objects, api, errors, limits.

ParameterInTypeDescription
pagepathstringThe page slug, as listed in /llms.txt.
StatusMeaning
200An HTML page. text/html
404No page has that slug. text/html

GET/docs/{page}.md

One documentation page, as Markdown.

The same page as /docs/{page}/, from the same source, with every link resolved to an absolute Markdown twin. index.md is the overview.

ParameterInTypeDescription
pagepathstringThe page slug, as listed in /llms.txt.
StatusMeaning
200Markdown. text/markdown
404No page has that slug. text/plain

GET/registry/

The hub's own registry, browsed.

A page over /v2/: every repository and tag the hub's registry holds, each layer verified in the browser against its digest. For people; a client uses /v2/ directly, and anything that is not a browser gets the section brief instead of the markup.

StatusMeaning
200The page to a browser; to anything else the section brief, the same bytes as /registry. text/html, text/markdown
404This document describes a deployment that serves this path; a hub that has not been updated to it answers 404 here. Fall back to /llms.txt, which every deployment serves. text/plain

GET/spaces/

Apps that run entirely in the browser, each in its own sealed frame.

Five demo Apps (speech, image, chat, vision, depth). Every file of an App is sealed under one root digest, its model bytes are accepted only when they re-derive to the digest the model index names, and nothing runs on a server. An App published to the registry lives at /v2/spaces/<id> as an OCI artifact of type application/vnd.hologram.space.v1+json.

StatusMeaning
200An HTML page. text/html
404This document describes a deployment that serves this path; a hub that has not been updated to it answers 404 here. Fall back to /llms.txt, which every deployment serves. text/plain

GET/spaces/spaces.json

The Apps catalog: id, sealed root, files, models and their sizes.

{ format: "hologram.spaces.catalog/v1", spaces: [{ id, name, task, tagline, root, bytes, files, models, modelHost, modelBytes, source, requires, entry }] }. root is SHA-256 over the App's file map; entry is the page to open.

StatusMeaning
200JSON. application/json
404This document describes a deployment that serves this path; a hub that has not been updated to it answers 404 here. Fall back to /llms.txt, which every deployment serves. text/plain

GET/llms.txt

The endpoint explained for an agent, shortest path first.

Prose, not a schema: what to do, in order, with the tools an agent already has. Read this when you would otherwise guess.

StatusMeaning
200Plain text. text/plain
404This document describes a deployment that serves this path; a hub that has not been updated to it answers 404 here. Fall back to /llms.txt, which every deployment serves. text/plain

GET/archive.json

Every day the hub has indexed.

One row per day: the index address, its IPFS CID, how many models and files it held, and the previous day. The chain lets anyone replay the hub's history and check each step.

StatusMeaning
200The archive ledger. application/json
404This document describes a deployment that serves this path; a hub that has not been updated to it answers 404 here. Fall back to /llms.txt, which every deployment serves. text/plain

GET/pins.json

Which models are pinned on IPFS.

The models whose weights the hub can still serve when Hugging Face and ModelScope are both unreachable, with the IPFS root of each and the gateway to read it through.

StatusMeaning
200The pin set. application/json
404This document describes a deployment that serves this path; a hub that has not been updated to it answers 404 here. Fall back to /llms.txt, which every deployment serves. text/plain

GET/robots.txt

Crawling policy.

Allows the website, the discovery paths and this document; asks crawlers to leave redirect and blob routes alone, because they cost a byte source real traffic.

StatusMeaning
200Plain text. text/plain
404This document describes a deployment that serves this path; a hub that has not been updated to it answers 404 here. Fall back to /llms.txt, which every deployment serves. text/plain