The download command finished. Which revision did it fetch? Did the filter match anything? Can the next run use the same file without going online?
Those are more useful questions than whether a progress bar reached the end. Hugging Face’s new CLI and Hub recap covers shared caches, download improvements and cloud tooling. I used that as a reason to build a much smaller workflow: a download that leaves a receipt. [1]
Original workflow diagram. The executed example downloaded only a model configuration, not weights.
Start with the smallest useful file 🧪
I used huggingface_hub 2.3.0 and the public SmolLM2-135M repository. The target is its config.json, pinned to a full commit identifier. That configuration is 704 bytes in this revision. It is enough to exercise selection, caching and identity without pulling a model into memory. [2, 3]
With uv installed, this is the CLI preflight:
uv run --with huggingface_hub==2.3.0 hf download HuggingFaceTB/SmolLM2-135M --revision 93efa2f097d58c2a74874c7e644dbc9b0cee75a2 --include config.json --dry-run
My run listed one matching file. A dry run is a plan based on the current repository metadata and cache state; it is not proof that the bytes are already present.
The distinction becomes important when an agent writes the command. A typo in an include pattern can leave you with no matching files and a workflow that still needs an explicit failure condition. “Nothing downloaded” can mean “already cached” or “nothing selected.” Those are very different outcomes. ⚠️
Turn the plan into a checked receipt
Save this as receipt.py:
import hashlib
import json
from pathlib import Path
from huggingface_hub import hf_hub_download, snapshot_download
repo = "HuggingFaceTB/SmolLM2-135M"
revision = "93efa2f097d58c2a74874c7e644dbc9b0cee75a2"
args = dict(repo_id=repo, revision=revision, token=False, cache_dir=".hf-receipt-cache")
plan = snapshot_download(**args, allow_patterns=["config.json"], dry_run=True)
if not plan:
raise RuntimeError("The include pattern selected no files")
if sum(item.file_size for item in plan) > 1_000_000:
raise RuntimeError("This example permits at most 1,000,000 selected bytes")
path = Path(hf_hub_download(**args, filename="config.json"))
receipt = {"repo": repo, "revision": revision, "filename": "config.json",
"bytes": path.stat().st_size,
"sha256": hashlib.sha256(path.read_bytes()).hexdigest()}
Path("receipt.json").write_text(json.dumps(receipt, indent=2) + "\n")
offline = Path(hf_hub_download(**args, filename="config.json", local_files_only=True))
assert offline.resolve() == path.resolve()
print(receipt["bytes"], json.loads(offline.read_text())["model_type"])
Run it in the same pinned package environment:
uv run --with huggingface_hub==2.3.0 python receipt.py
The checked output is:
704 llama
The byte limit is a deliberately small example policy. It counts the selected files’ advertised sizes, including files already cached. It is not a measured transfer budget or a limit on process memory.
Read the evidence in the right order ✅
In a fresh isolated cache, the preflight marked config.json as uncached and needing download. After the fetch, the same preflight marked it cached and no longer needing download. The local-only call then resolved to the same file. I also tried a nonexistent filename pattern; the SDK returned an empty plan, which is exactly why the guard belongs in the program.
The revision identifies the repository snapshot. The SHA-256 identifies the bytes received. The offline reread checks whether this file is available locally. Keeping all three makes debugging less mysterious: you can distinguish a changed upstream snapshot, different content and a missing cache entry.
Hugging Face’s shared-Xet-cache work addresses another layer: reusing identical large files across repositories. The platform recap describes that feature; this tiny JSON exercise does not measure cross-repository Xet deduplication, transfer speed or storage savings. [1]
For a larger download, I would keep the same contract and change the allowlist and budget deliberately. A successful receipt for configuration metadata still says nothing about whether model weights fit, whether a runtime supports the architecture, or whether inference works.
The progress bar gets the file onto the machine. The receipt gives the next run something concrete to check. 💡
References and credits
[1] Hugging Face: what’s new in the hf CLI and Hub library. A recap of recent changes, not a claim that every feature launched together.
[2] huggingface_hub 2.3.0 release.
[3] The pinned SmolLM2 configuration.
Diagram: original, created for this article.
AI disclosure
AI was used to draft the article.

Top comments (0)