HuggingFace compatible OCI Model Relay
4
stars
116
commits
Go
primary language
Sep 14, 2026
updated
Push Hugging Face models straight into your OCI registry. Shpiel
speaks the Hugging Face Hub API — read, write, and Xet — so
push_to_hub() lands weights as versioned, content-addressed OCI
artifacts in the registry your cluster already runs, ready for image
volumes and P2P distribution. (Filesystem and S3-compatible object
storage backends ship too.) Every existing HF tool works unchanged by
setting one environment variable:
export HF_ENDPOINT=https://shpiel.internal
hf download, push_to_hub(), vLLM --model org/name, SGLang, TGI — no
new tools, no new auth universe, no workflow breakage.
The ML world standardized on two incompatible planes. Researchers live on
the Hugging Face API: every training script ends in push_to_hub(), every
inference engine starts with from_pretrained(). Clusters want weights as
versioned, content-addressed, P2P-distributable artifacts — that's where
cold-start time, egress cost, and reliability are actually won.
Today the bridge between those planes is shell scripts, or a heavyweight self-hosted hub with its own database and auth universe. Shpiel is the bridge as one boring binary: no database, one YAML file, runs identically on a laptop and in Kubernetes.
The killer scenario is autoscaled GPU fleets: with node auto-provisioning, time-to-first-token is dominated by pulling hundreds of gigabytes of weights from the public internet onto a node that didn't exist a minute ago. Shpiel turns that into a LAN-speed pull from in-cluster infrastructure — and, paired with Spegel, into a peer-to-peer pull from neighboring nodes. See the Spegel deployment guide.
researchers ── HF API (read / write / Xet) ──▶ Shpiel ──▶ backends
inference engines ◀── HF API (reads, ranges) ──┘ │ ├─ OCI registry (Zot, Harbor)
│ ├─ filesystem / NFS / PVC
│ └─ S3 / GCS / MinIO / R2
huggingface.co (pull-through / mirror)
huggingface_hub 1.x uploads through the Xet
protocol with no LFS fallback; Shpiel implements the CAS API (the first
open-source server that does), so current clients push and pull
chunk-level with zero client-side flags — including the global
chunk-deduplication probe, so identical content pushed to different
repos skips the re-upload.tar-layers format is a standard mountable image —
Kubernetes image volumes and Spegel work out of the box.huggingface_hub
cache: mount the volume, set HF_HUB_OFFLINE=1, and from_pretrained
reads it directly.xet.store_backend), so chunk-level storage needs no local disk.# Container image
docker run -p 8080:8080 ghcr.io/loewenthal-corp/shpiel:latest \
serve --local --listen-api :8080
# Helm chart
helm install shpiel oci://ghcr.io/loewenthal-corp/charts/shpiel
# Binaries (linux/darwin, amd64/arm64) on every release
# https://github.com/loewenthal-corp/shpiel/releases
# From source
go install github.com/loewenthal-corp/shpiel/cmd/shpiel@latest
# Laptop mode: localhost bind, filesystem store in ~/.shpiel,
# pull-through from huggingface.co, Xet on.
shpiel serve --local
# Point any HF tool at it:
export HF_ENDPOINT=http://127.0.0.1:8080
hf download Qwen/Qwen3-0.6B # first pull: cached through Shpiel
hf download Qwen/Qwen3-0.6B # second pull: served locally
hf upload my-org/my-model ./model # pushes work too
Beyond laptop mode, everything is one YAML file — config.example.yaml documents every knob:
shpiel config validate config.yaml
shpiel serve --config config.yaml
The Helm chart uses the same mental model: its config value is
config.yaml, rendered verbatim into a ConfigMap.
| Client | Reads | Writes |
|---|---|---|
huggingface_hub / hf CLI 1.x | ✅ (HTTP or chunk-level Xet) | ✅ via Xet (enable xet in config) |
huggingface_hub / hf CLI 0.x | ✅ | ✅ via git-LFS |
vLLM, SGLang, TGI, from_pretrained | ✅ incl. Range/lazy loading | — |
HF_HUB_OFFLINE=1 on a shared volume | ✅ (fs backend) | — |
The compatibility surface is enforced by an executable conformance suite
that runs against every serving configuration, and by end-to-end tests
that drive a real Python huggingface_hub/hf_xet client against the
real binary. If it regresses, CI fails.
v0.1.0 is out. The read path, write path, Xet server, OCI, filesystem, and S3 backends, pull-through, replication, and the ops surface described above are all shipped and covered by conformance + e2e tests.
On the roadmap: global chunk-level dedup queries, dataset repos, mintable local tokens and OIDC for air-gapped auth, and published Spegel benchmark numbers. The spec tracks the details.
MatrixHub-style self-hosted hubs. Full hub replacements: a database, a web UI, their own user/org/auth universe to administer. Shpiel deliberately isn't a hub — huggingface.co stays the social layer (cards, browsing, discussions) while Shpiel handles bytes. No database, no UI, stateless between requests, and your weights live in a standard registry instead of an app-specific store.
Dragonfly. P2P distribution for registries — it accelerates pulls but doesn't get models into a registry, so you still need the HF-to-OCI bridge. Shpiel is that bridge, and the two compose: point Shpiel's OCI backend at a Dragonfly-fronted registry and pulls fan out P2P. (Spegel plays the same role with zero extra infrastructure, which is why it's the flagship pairing — see docs/spegel.md.)
ModelExpress. GPU-to-GPU weight transfer between running processes — a layer above storage. It needs a seed node to have the weights in the first place; Shpiel is how the seed node gets them at LAN speed.
Shell scripts (hf download && modctl build && modctl push). Work
until they meet a moving branch, a resume, a fine-tune push, or a
researcher who wasn't told about them. Shpiel keeps the researcher
workflow byte-identical and makes the pipeline a server instead of a
cron job.
Development setup, the Tilt environment, testing philosophy, and the release process live in DEVELOPMENT.md. Agent-oriented notes live in AGENTS.md.
Apache-2.0
81 commits
23 commits
10 commits
1 commits
Go
93.6%
TypeScript
2.1%
Python
1.7%
CSS
1.3%
HuggingFace compatible OCI Model Relay
4
stars
116
commits
Go
primary language
Sep 14, 2026
updated
Push Hugging Face models straight into your OCI registry. Shpiel
speaks the Hugging Face Hub API — read, write, and Xet — so
push_to_hub() lands weights as versioned, content-addressed OCI
artifacts in the registry your cluster already runs, ready for image
volumes and P2P distribution. (Filesystem and S3-compatible object
storage backends ship too.) Every existing HF tool works unchanged by
setting one environment variable:
export HF_ENDPOINT=https://shpiel.internal
hf download, push_to_hub(), vLLM --model org/name, SGLang, TGI — no
new tools, no new auth universe, no workflow breakage.
The ML world standardized on two incompatible planes. Researchers live on
the Hugging Face API: every training script ends in push_to_hub(), every
inference engine starts with from_pretrained(). Clusters want weights as
versioned, content-addressed, P2P-distributable artifacts — that's where
cold-start time, egress cost, and reliability are actually won.
Today the bridge between those planes is shell scripts, or a heavyweight self-hosted hub with its own database and auth universe. Shpiel is the bridge as one boring binary: no database, one YAML file, runs identically on a laptop and in Kubernetes.
The killer scenario is autoscaled GPU fleets: with node auto-provisioning, time-to-first-token is dominated by pulling hundreds of gigabytes of weights from the public internet onto a node that didn't exist a minute ago. Shpiel turns that into a LAN-speed pull from in-cluster infrastructure — and, paired with Spegel, into a peer-to-peer pull from neighboring nodes. See the Spegel deployment guide.
researchers ── HF API (read / write / Xet) ──▶ Shpiel ──▶ backends
inference engines ◀── HF API (reads, ranges) ──┘ │ ├─ OCI registry (Zot, Harbor)
│ ├─ filesystem / NFS / PVC
│ └─ S3 / GCS / MinIO / R2
huggingface.co (pull-through / mirror)
huggingface_hub 1.x uploads through the Xet
protocol with no LFS fallback; Shpiel implements the CAS API (the first
open-source server that does), so current clients push and pull
chunk-level with zero client-side flags — including the global
chunk-deduplication probe, so identical content pushed to different
repos skips the re-upload.tar-layers format is a standard mountable image —
Kubernetes image volumes and Spegel work out of the box.huggingface_hub
cache: mount the volume, set HF_HUB_OFFLINE=1, and from_pretrained
reads it directly.xet.store_backend), so chunk-level storage needs no local disk.# Container image
docker run -p 8080:8080 ghcr.io/loewenthal-corp/shpiel:latest \
serve --local --listen-api :8080
# Helm chart
helm install shpiel oci://ghcr.io/loewenthal-corp/charts/shpiel
# Binaries (linux/darwin, amd64/arm64) on every release
# https://github.com/loewenthal-corp/shpiel/releases
# From source
go install github.com/loewenthal-corp/shpiel/cmd/shpiel@latest
# Laptop mode: localhost bind, filesystem store in ~/.shpiel,
# pull-through from huggingface.co, Xet on.
shpiel serve --local
# Point any HF tool at it:
export HF_ENDPOINT=http://127.0.0.1:8080
hf download Qwen/Qwen3-0.6B # first pull: cached through Shpiel
hf download Qwen/Qwen3-0.6B # second pull: served locally
hf upload my-org/my-model ./model # pushes work too
Beyond laptop mode, everything is one YAML file — config.example.yaml documents every knob:
shpiel config validate config.yaml
shpiel serve --config config.yaml
The Helm chart uses the same mental model: its config value is
config.yaml, rendered verbatim into a ConfigMap.
| Client | Reads | Writes |
|---|---|---|
huggingface_hub / hf CLI 1.x | ✅ (HTTP or chunk-level Xet) | ✅ via Xet (enable xet in config) |
huggingface_hub / hf CLI 0.x | ✅ | ✅ via git-LFS |
vLLM, SGLang, TGI, from_pretrained | ✅ incl. Range/lazy loading | — |
HF_HUB_OFFLINE=1 on a shared volume | ✅ (fs backend) | — |
The compatibility surface is enforced by an executable conformance suite
that runs against every serving configuration, and by end-to-end tests
that drive a real Python huggingface_hub/hf_xet client against the
real binary. If it regresses, CI fails.
v0.1.0 is out. The read path, write path, Xet server, OCI, filesystem, and S3 backends, pull-through, replication, and the ops surface described above are all shipped and covered by conformance + e2e tests.
On the roadmap: global chunk-level dedup queries, dataset repos, mintable local tokens and OIDC for air-gapped auth, and published Spegel benchmark numbers. The spec tracks the details.
MatrixHub-style self-hosted hubs. Full hub replacements: a database, a web UI, their own user/org/auth universe to administer. Shpiel deliberately isn't a hub — huggingface.co stays the social layer (cards, browsing, discussions) while Shpiel handles bytes. No database, no UI, stateless between requests, and your weights live in a standard registry instead of an app-specific store.
Dragonfly. P2P distribution for registries — it accelerates pulls but doesn't get models into a registry, so you still need the HF-to-OCI bridge. Shpiel is that bridge, and the two compose: point Shpiel's OCI backend at a Dragonfly-fronted registry and pulls fan out P2P. (Spegel plays the same role with zero extra infrastructure, which is why it's the flagship pairing — see docs/spegel.md.)
ModelExpress. GPU-to-GPU weight transfer between running processes — a layer above storage. It needs a seed node to have the weights in the first place; Shpiel is how the seed node gets them at LAN speed.
Shell scripts (hf download && modctl build && modctl push). Work
until they meet a moving branch, a resume, a fine-tune push, or a
researcher who wasn't told about them. Shpiel keeps the researcher
workflow byte-identical and makes the pipeline a server instead of a
cron job.
Development setup, the Tilt environment, testing philosophy, and the release process live in DEVELOPMENT.md. Agent-oriented notes live in AGENTS.md.
Apache-2.0
81 commits
23 commits
10 commits
1 commits
Go
93.6%
TypeScript
2.1%
Python
1.7%
CSS
1.3%