NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
PyPI · #122 most downloaded on PyPI
Client library to download and publish models, datasets and other repos on the huggingface.co hub
Last release 3 days ago
01 Oct 2026
Ships on a steady schedule
a new release about every 2 weeks
Nearly every release is documented
notes for 56 of the last 60 stable releases
8 versions withdrawn
withdrawn after publishing
6 years old
331 releases · first in 2020
One column per quarter.
[CLI] Rename 'hf spaces zero-gpu-quota' to 'hf spaces zero-gpu quota'- #5055
[CLI] Rename 'hf spaces zero-gpu-quota' to 'hf spaces zero-gpu quota'- #5055
Full Changelog: v2.1.0...v2.1.1
…cannot reach new sandboxes (documented, accepted breaking change). The sandbox concepts and guides have been updated to describe the strict behavior,…
Hugging Face Jobs get a batch of quality-of-life improvements this release. Jobs can now retry automatically on failure with the new attempts parameter, and you can start a fresh Job from an existing Job's saved spec (including secrets and hardware settings) with rerun_job / hf jobs rerun. Scheduled Jobs can be rescheduled — change the cron expression or preset without recreating the Job — via update_scheduled_job_schedule / hf jobs scheduled reschedule. Finally, you can now expose ports on Jobs: use expose for token-protected access and expose_public for unauthenticated access, both at creation time and on a running Job with update_job_expose / hf jobs expose.
# Retry a job up to 2 times on failure, and rerun it later from its saved spec
>>> hf jobs run --attempts 3 --detach python:3.12 python train.py
>>> hf jobs rerun <job_id>
# Reschedule a scheduled job to run every day at 9:00
>>> hf jobs scheduled reschedule <scheduled_job_id> "0 9 * * 1"
# Expose ports on a running Job (8000 token-protected, 9000 public)
>>> hf jobs expose <job_id> 8000 --public 9000📚 Documentation: Jobs guide
The Hub now exposes a ZeroGPU quota endpoint, and huggingface_hub wraps it with a new HfApi.get_zero_gpu_quota() method returning a ZeroGpuQuota dataclass (values in GPU-seconds). This is particularly useful for apps, MCP servers and agents built on top of ZeroGPU Spaces: check how much quota is left and when it resets, and warn your users before they hit the daily limit. The same information is available from the CLI with hf spaces zero-gpu-quota, which also prints a hint to purchase credits when the quota is running low.
>>> from huggingface_hub import get_zero_gpu_quota
>>> quota = get_zero_gpu_quota()
ZeroGpuQuota(base=2400, remaining=1810, resets_at=datetime.datetime(2026, 9, 30, 9, 12, 3, tzinfo=datetime.timezone.utc), overquota_used=0)>>> hf spaces zero-gpu quota
✓ ZeroGPU quota (in GPU-seconds)
remaining: 1810
base: 2400
resets_at: 2026-09-30T18:12:03+00:00
overquota_used: 0📚 Documentation: Manage your Space guide
HfFileSystem.get_file downloads Xet files with hf_xetHfFileSystem.get_file now downloads Xet-backed files through hf_xet (the same code path as hf_hub_download) when writing to a local path, letting hf_xet write directly to disk instead of going through Python. It reuses the Xet hash already returned by info() (part of the tree listing), so no extra HTTP call is needed. This mostly benefits non-streaming datasets loads from hf://buckets/... paths: benchmarks on HF Jobs show get_file dropping from ~120s to ~7s on a 2 GB parquet file, and load_dataset("hf://buckets/...") from ~130s to ~17s. The classic HTTP path is still used for non-Xet files, when hf_xet is not installed, or when writing to a file-like object. As a side effect, a missing remote file no longer leaves an empty local file behind.
The catalog methods now use the new /api/v1/catalog API. list_inference_catalog returns InferenceCatalogModel dataclasses with their tested deployment recipes (hardware + engine combinations), and takes server-side filters (accelerator, engine, license, task, search, limit). create_inference_endpoint_from_catalog can deploy an exact recipe with the new recipe_id and gguf_file arguments. The CLI follows suit: hf endpoints catalog ls prints one row per recipe and supports the filters, while hf endpoints catalog deploy gains --recipe and --gguf-file.
>>> hf endpoints catalog ls --engine vllm --task text-generation --search llama --limit 10
REPO_ID TASK LICENSE ACCELERATOR ENGINE GGUF_FILE RECIPE_ID
----------------------------------- ------------------ ---------- ----------- -------- ----------------------------- -------------------------
meta-llama/Llama-3.1-8B-Instruct text-generation Llama 3.1 gpu vllm sizzling-biryani-g4xsi1ac
bartowski/QwQ-32B-Preview-GGUF text-generation Apache 2.0 gpu llamacpp QwQ-32B-Preview-Q8_0.gguf baked-orange-m863gx7d📚 Documentation: Inference Endpoints guide
Sandbox security is tightened in this release. Pooled sandboxes with missing, empty or malformed capability tokens are now refused instead of silently substituting the host-management credential, and the client is pinned to sbx-server 0.7.0, which removes host-token acceptance on per-sandbox routes entirely. Older pool hosts that do not provide scoped tokens must be upgraded/recycled: new clients cannot reach legacy hosts and legacy clients cannot reach new sandboxes (documented, accepted breaking change). The sandbox concepts and guides have been updated to describe the strict behavior, including how to safely use proxy_headers with external HTTP clients (disable redirects!).
Note
The Inference Endpoints catalog migration (#4928) and the Sandbox credential changes (#4782, #5028) are breaking changes detailed in their highlight sections above.
hf auth login when hf auth whoami fails by @moon-bot-app[bot] in #5033hf auth whoami not-logged-in message with hf auth token by @Wauplin in #5034hf upload help text by @davanstrien in #5046visibility to create_bucket by @hanouticelina in #5053[v2.1.0] Better Jobs tooling, ZeroGPU quota tracking, and revamped Model Catalog Latest
Latest
Compare
Nothing published for this version
💔 Breaking Change: HTTP stack moves to httpx2
See MIGRATION GUIDE in docs.
httpx2See migration plan in #4802 .
huggingface_hub v2.0 replaces its HTTP dependency with httpx2: clients and transport exceptions now come from httpx2/httpcore2 instead of httpx/httpcore. Custom client factories (via set_client_factory / set_async_client_factory) and any except clauses catching transport errors must use httpx2 types. For code that must support both v1.x (starting with v1.30.0) and v2.x, import the HTTP module from huggingface_hub.utils:
from huggingface_hub.utils import get_session, httpx
try:
response = get_session().get("https://huggingface.co/api/models/gpt2")
response.raise_for_status()
except httpx.HTTPError:
...Note that httpx2 uses the operating system's certificate trust store by default (custom CA bundles via SSL_CERT_FILE / SSL_CERT_DIR still work), logging configuration should target the httpx2 and httpcore2 loggers, and the oauth extra now requires authlib>=1.8.0.
This release also removes all APIs deprecated in 1.x:
upload_large_folder / HfApi.upload_large_folder → use upload_folderduplicate_space → use duplicate_reporequest_space_storage / delete_space_storage → use the volume APIs (set_space_volumes, delete_space_volumes)repo_type_and_id_from_hf_id → use parse_hf_uriInferenceEndpointType.PROTECTED → use AUTHENTICATED (create_inference_endpoint(type="protected") now raises ValueError)list_models(model_name=...) → use list_models(search=...)create_repo / duplicate_repo(space_storage=...) → use space_volumestext_generation(stop_sequences=...) → use stopInferenceClient(token=...) → pass a token string or NoneOn the CLI side, the following entry points and options are gone: huggingface-cli (use hf), hf repo and hf repo-files delete (use hf repos and hf repos delete-files), hf upload-large-folder (use hf upload), hf repos create/duplicate --storage (use --volume), hf jobs ps and hf jobs scheduled ps -f/--filter (use --status/--label), and hf skills add/update --claude (Claude Code installation is now automatic).
A migration guide covering all of this is available at https://github.com/huggingface/huggingface_hub/blob/main/docs/source/en/concepts/migration_v2.md.
Nothing published for this version
…from .agents/skills . The --claude flag is deprecated: it still works as a no-op but prints a warning, and --dest keeps installing only to the directo…
Very large Xet uploads used to sit silently between "Uploading" and "Committing" while shards were being finalized, which could take a long time with no feedback. The upload live display now shows a dedicated Validating bar — reported as a percentage instead of opaque internal validation-entry counts — both in the upload_folder display and in XetUploadProgressReporter (used by upload_file, create_commit and bucket uploads). This requires hf-xet>=1.6.0.
hf skills add no longer requires a special flag for Claude Code. The skill is now always installed to .agents/skills (or ~/.agents/skills with -g) and symlinked into .claude/skills (honoring CLAUDE_CONFIG_DIR when set), so a single command covers Claude Code, Codex, Cursor, OpenCode, Pi and any other agent that loads skills from .agents/skills. The --claude flag is deprecated: it still works as a no-op but prints a warning, and --dest keeps installing only to the directory you provide. hf skills update refreshes both roots the same way. Along the way, CLAUDE_CONFIG_DIR is now properly honored everywhere (it was previously ignored, which left skills invisible to relocated Claude Code installs).
# works with Claude Code, Codex, Cursor, OpenCode, Pi and any agent that loads skills from `.agents/skills`
hf skills addCLAUDE_CONFIG_DIR in hf skills add -g --claude by @hanouticelina in #4957📚 Documentation: CLI guide
privateService.accountId and privateService.region. Use the new private_link_account_id and private_link_region parameters (the region is required when the account ID is set, and is independent of the compute region). The legacy account_id keyword still exists but is ignored and emits a FutureWarning; it is no longer included as a top-level payload field.hf jobs run, hf jobs uv run and their scheduled variants (--format became the script path, -q became the image name). They are now consumed wherever they appear; use -- when your script needs them.bucket as a watched item type in hf webhooks create --watch by @davanstrien in #4958 — docsscan_cache_dir ref names on Windows by @gokay-ai in #4925format_timesince showing "60 seconds ago" / "60 minutes ago" / "24 hours ago" instead of rolling over by @Sreekant13 in #4943BucketBatchError when a batch reports failed operations by @hanouticelina in #4954 — docshf package's python_requires with huggingface_hub by @sharziki in #4959re.match by @Wauplin in #4939[v1.33.0] Better UX on large uploads and simpler skills installs
Compare
v1.33.0.rc1 pre-release
v1.33.0.rc1 pre-release
v1.33.0.rc0 pre-release
v1.33.0.rc0 pre-release
Torch checkpoint deserialization was hardened across 11 reported vulnerabilities: load_state_dict_from_file now defaults to safe=True (always using th…
The cache now deduplicates Xet files across repos. A Xet file downloaded through hf_xet is stored once at <CACHE_DIR>/blobs/<prefix>/<xet_hash> and every repo that needs it gets a relative symlink instead of a download: no bytes are transferred and no extra space is used, even across different repos — or after the repo that first downloaded the file was deleted. The per-repo snapshot layout is unchanged, older clients keep reading and downloading normally, and any failure to share silently falls back to regular repo-local storage. Set HF_HUB_DISABLE_SHARED_BLOBS=1 to opt out entirely. Shared files carry a <xet_hash>.refs manifest listing the repo blobs referencing them, which hf cache rm consults on deletion and hf cache prune sweeps to reclaim payloads that no cached repo uses anymore.
📚 Documentation: Manage your cache
A UV script that only runs correctly on a specific runtime can now carry that runtime with it. An optional [tool.hf-jobs] table in the script's PEP 723 header accepts image, flavor, python, timeout, name, namespace, env, secrets, labels, volumes, network_group and network_aliases, and hf jobs uv run reads it at submit time. CLI flags always win, and env/secrets/labels/volumes merge entry by entry instead of being replaced, so -e/-v add to what the script declares. Typos and unknown keys are rejected with the list of valid options, secrets are passed by name only (values come from your environment), and every run prints a config summary with script-sourced values marked and secrets redacted. Note that the table is read by the CLI only: run_uv_job() and create_scheduled_uv_job() ignore it.
# /// script
# requires-python = ">=3.11"
# dependencies = ["vllm", "datasets"]
#
# [tool.hf-jobs]
# image = "vllm/vllm-openai:unlimited-ocr"
# flavor = "l4x1"
# python = "/usr/bin/python3"
# secrets = ["HF_TOKEN"]
# ///📚 Documentation: Run and manage Jobs
An internal security review of the Sandbox API resulted in a 9-PR hardening series. Pooled sandboxes now use their own per-sandbox capability token instead of the host-wide credential, pool hosts are fully validated (initiator, namespace, image, flavor, command, URL) before any credential is sent to them, the sbx-server binary is pinned by digest and verified before being run as PID 1, and the local pool cache is bound to the endpoint, credential and namespace that wrote it. Secret values no longer end up in argv when using hf sandbox exec --secrets, background processes are addressed by their server-assigned id (so kill() actually stops them and reports honestly), transfers and command output are bounded to avoid unbounded memory usage in the client, and pool ownership is decided per host so a with SandboxPool(...) block never again tears down a colleague's discovered host. The security documentation was also rewritten to state precisely what the sandbox contract is — and what it is not — including a new "Known limitations" section.
📚 Documentation: Sandboxes
Three changes make the library safer against malicious or malformed inputs, with a stricter behavior worth noting. Torch checkpoint deserialization was hardened across 11 reported vulnerabilities: load_state_dict_from_file now defaults to safe=True (always using the safetensors loader), the pickle path defaults to weights_only=True, and unsafe combinations raise explicit errors instead of silently falling through. Path validation now rejects .. segments anywhere in path_in_repo (previously only a leading one was caught), so uploads like "a/../../etc/passwd" are refused. Finally, repo_id validation is restricted to ASCII word characters as documented, so non-ASCII ids like café are rejected client-side instead of failing later on the Hub.
hf cache rm accepts hf:// file URIs, so you can remove a single cached file — typically one GGUF quantization — without deleting the whole repo. The file is removed from every cached revision, and its blob is deleted only if no other cached file still references it. hf cache commands also support kernel repos: scan_cache_dir() used to treat kernels--* folders as corrupted and skip them, but kernel repos now show up in hf cache ls, rm and prune, and --repo-type kernel works for hf download and hf cache verify.
hf cache rm hf://models/unsloth/gemma-3-27b-it-GGUF/gemma-3-27b-it-Q4_K_M.gguf --dry-run
hf download kernels-community/activation README.md --repo-type kernel📚 Documentation: Manage your cache
hf cache commands by @hanouticelina in #4905huggingface_hub now imports much faster: huggingface_hub.utils is lazy like the root package, heavy HfApi implementation imports and optional Torch/TensorBoard/NumPy/FastAPI/Starlette dependencies are deferred until used, and CLI commands are registered lazily while hf --help still renders the same complete output. Benchmark medians on Python 3.10: from huggingface_hub import * drops from 2.36s to 0.39s (626.8 → 49.6 MiB peak RSS), hf version from 0.37s to 0.17s, and hf env from 0.40s to 0.24s.
hf --skills as an alias for hf skills preview by @Wauplin in #4906--container-registry-{username,password} by @alvarobartt in #4854 — docsget_session() creating multiple clients by @hanouticelina in #4868_get_dtype_size with safetensors by @Wauplin in #4902[v1.32.0] Shared blob store, sandbox security hardening and faster imports
Compare
v1.32.0.rc0 pre-release
v1.32.0.rc0 pre-release
Dedicated sandboxes now accept custom labels, attached to the underlying Job. This is useful for cost attribution, bookkeeping, or finding and reconne
Dedicated sandboxes now accept custom labels, attached to the underlying Job. This is useful for cost attribution, bookkeeping, or finding and reconnecting to the sandboxes created by a given controller run. Labels use the same -l / --label KEY=VALUE syntax as hf jobs run. They are merged with the labels the SDK uses internally, and invalid or reserved labels are rejected before a billable Job is started. Pool-based sandboxes are unchanged: custom labels are only accepted for dedicated sandboxes.
>>> from huggingface_hub import Sandbox
>>> sandbox = Sandbox.create(image="python:3.12", labels={"controller-run": "run-42"})hf sandbox create --label controller-run=run-42 --label team=data-infraA batch of fixes makes downloads more robust to unusual server responses, network hiccups and concurrent usage:
A timeout while waiting for the response headers of a streamed download is now retried and resumed like a body read failure, instead of escaping http_get() while retries remain.
Regular HTTP downloads no longer fail when the HEAD response has no Content-Length. The file size is validated against the GET response when available.
snapshot_download now writes the refs/ cache file atomically, reusing the logic already used by hf_hub_download. This fixes a long-standing race when many concurrent snapshot_download calls target the same repo (seen in vLLM / llm-compressor).
hf download --dry-run --local-dir ... no longer copies files from the Hub cache into the destination. On large files and slow disks this looked like a hang and could leave an incomplete file behind.
[Download] Share retry handling for stream entry and body failures by @Wauplin in #4826
[Download] Tolerate missing HEAD Content-Length by @Wauplin in #4805
[Download] Write cache ref file atomically in snapshot_download by @Wauplin in #4829
[Download] Prevent cached file copies during local-dir dry runs by @wakamex in #4817
httpx re-exported for library integratorshuggingface_hub now re-exports the HTTP library it uses as huggingface_hub.utils.httpx. Libraries built on top of huggingface_hub that need httpx types or exceptions (typically to catch errors) should import it from there rather than importing httpx directly. v1.x is built on httpx, and v2.x will move to its successor httpx2, so importing through huggingface_hub.utils keeps your code compatible with both. This is only for types and exceptions: to make requests to the Hub, keep using get_session().
from huggingface_hub.utils import httpx
try:
...
except httpx.HTTPError:
...📚 Documentation: Utilities — The httpx module
HfFileSystem.get() now validates remote filenames before writing anything locally. A server-side filename such as folder/..\..\outside.txt could previously escape the destination directory on Windows during a recursive download. The same check already protected hf_hub_download, snapshot_download and bucket sync. Unsafe filenames now raise ValueError on all platforms, including when downloading to an explicitly named file or a file object.
hf buckets rm --recursive deleting lexical siblings of the prefix: removing logs/ no longer touches logs_root.txt by @Wauplin in #4804hf update self-upgrade a pip install on Windows: it now prints the pip install -U command to run instead of leaving a broken install by @Wauplin in #4823CommitInfo copy-able and pickle-able by @Wauplin in #4822SliceFileObj.__iter__ yielding only the first 4MB chunk by @BenYang12 in #4844# (used by hf jobs --env-file) by @BenYang12 in #4842load_dotenv by @AnishPatel526 in #4827-- and align examples by @davanstrien in #4809[v1.31.0] Custom labels for Sandboxes, More resilient downloads and more
Compare
v1.31.0.rc1 pre-release
v1.31.0.rc1 pre-release
v1.31.0.rc0 pre-release
v1.31.0.rc0 pre-release
Warning -f / --filter on hf jobs scheduled ls is deprecated and no longer applied: it is accepted but ignored, with a warning pointing to the new flag…
hf jobs scheduled ls can now filter by status, label and nameYou can now filter scheduled jobs with --status (active/suspended), repeatable -l/--label key=value and --name (a shortcut for --label name=NAME), matching the flags hf jobs ls already had. On the Python side, HfApi.list_scheduled_jobs gains a labels argument.
Warning
-f/--filter on hf jobs scheduled ls is deprecated and no longer applied: it is accepted but ignored, with a warning pointing to the new flags. Migrate as shown below. The option itself will be removed in a future release.
hf jobs scheduled ls --all
hf jobs scheduled ls --status suspended
hf jobs scheduled ls --name hourly-task --label env=prod| before | after |
|---|---|
-f name=daily-report |
--name daily-report |
-f env=prod |
--label env=prod |
-f suspend!=true |
(default, or --status active) |
-f suspend=true |
--status suspended |
📚 Documentation: Jobs guide
hf jobs scheduled ls filtering with hf jobs ls (--status/--label/--name) by @moon-bot-app[bot] in #4773ResolvedRevision now pins the repo it was resolved forResolvedRevision didn't record which repo a commit hash was resolved against, so resolving "main" on two different repos returned the same commit oid. It now remembers its repo_id and repo_type: passed back for the same repo it is returned as is, for a different repo the requested revision is resolved again.
>>> from huggingface_hub import resolve_revision
>>> revision = resolve_revision("openai-community/gpt2")
# Same repo => returned as is
>>> resolve_revision("openai-community/gpt2", revision=revision) is revision
True
# Another repo => "main" is resolved again for that repo
>>> resolve_revision("openai-community/gpt2-medium", revision=revision).resolved
'6dcaa7a952f72f9298047fd5137cd6e4f05f41da'📚 Documentation: Manage cache — Pin a revision
conversational tag for chat-completion on hf-inference: any model with pipeline tag text-generation or image-text-to-text can now be served, mirroring the updated provider-side rules by @hanouticelina in #4784Authorization is never forwarded off-Hub) by @hanouticelina in #4739opencode models --refresh) before validating RELEASE_NOTES_MODEL, fixing release CI failures on cold runners by @Wauplin in #4761huggingface/skills per release by @hanouticelina in #4765[v1.30.0] Scheduled job filters, repo-aware revision pinning and more
Compare
v1.30.0.rc0 pre-release
v1.30.0.rc0 pre-release
Two security-relevant fixes land in this release. First, the path-traversal guard introduced earlier for CVE-2026-15717 is now extended to hf buckets…
Since v1.19.0, downloading a repository with hf_xet eagerly requested a xet read token for every single file, because each download group was built without cached connection info. On repos with many files this quickly added up — a 77k-file repo made ~1,500 Hub API calls per minute — and eventually hit the rate limiter, leaving snapshot_download appearing stalled for minutes before failing with a 429 Too Many Requests. This release restores the Python-side connection info cache so the endpoint and token are reused across download groups, skipping the eager per-file token request entirely. Large downloads are both faster and far less likely to be rate-limited.
Bucket visibility used to be a create-time-only setting: once a bucket existed, there was no way to flip it between private and public. You can now update it with the new HfApi.update_bucket_settings() method (also exported as update_bucket_settings) or from the CLI with hf buckets settings, which takes either --private or --public.
>>> from huggingface_hub import update_bucket_settings
# Make a bucket private
>>> update_bucket_settings("username/my-bucket", private=True)
# Make it public again
>>> update_bucket_settings("username/my-bucket", private=False)# Make a bucket private
>>> hf buckets settings username/my-bucket --private
✓ Bucket settings updated
bucket_id: username/my-bucket
private: True
# Make it public again
>>> hf buckets settings username/my-bucket --public📚 Documentation: Buckets guide
Two security-relevant fixes land in this release. First, the path-traversal guard introduced earlier for CVE-2026-15717 is now extended to hf buckets sync / sync_bucket(): when downloading from a bucket, server-supplied file keys were joined straight onto the local destination without validation, so a malicious or compromised bucket could return anchored or traversing keys (/etc/cron.d/evil, ../../../../etc/passwd, Windows drive-absolute or UNC paths) that escape the chosen directory and write arbitrary files. Remote paths are now validated the same way as in the original fix. Second, load_state_dict_from_file could fall back to pickle deserialization for a shard named exactly .safetensors: Path.suffix returns an empty string for extension-only filenames, so a file that passed sharded-checkpoint validation (which uses str.endswith) was still routed to torch.load(weights_only=False). A shared _is_safetensors() helper now guarantees both code paths use the same matching semantics, so an index-declared "safetensors" checkpoint can never be loaded with pickle.
_is_safetensors) by @moon-bot-app[bot] in #4737stream=True when a non-streaming inference call fails with 504 by @moon-bot-app[bot] in #4744huggingface_hub[mcp] by @Wauplin in #4735labels/tags from docstrings and signature by @Wauplin in #4745[v1.29.0] Fix Xet downloads rate limits, bucket visibility updates, and security fixes
Compare
v1.29.0.rc1 pre-release
v1.29.0.rc1 pre-release
💔 Breaking change: huggingface_hub.constants.INFERENCE_ENDPOINT_IMAGE_KEYS is removed. It was never exported at the package root nor documented, but c…
hf endpoints hardwareDeploying an Inference Endpoint requires five hardware flags (--vendor, --region, --accelerator, --instance-type, --instance-size) whose valid values depend on each other, and until now there was no way to learn them from the CLI. The new hf endpoints hardware command lists the valid combinations along with the price per replica per hour and your namespace's accelerator quota, filtered by default to the hardware you can deploy on right now. The same data is available in the SDK via list_inference_endpoints_hardware(), which flattens the API response into InferenceEndpointHardware objects you can filter programmatically.
>>> hf endpoints hardware --vendor aws --region eu-west-1
VENDOR REGION ACCELERATOR INSTANCE_TYPE INSTANCE_SIZE MEMORY_GB GPU_MEMORY_GB PRICE_PER_HOUR QUOTA STATUS
------ --------- ----------- ------------- ------------- --------- ------------- -------------- ----- ---------
aws eu-west-1 cpu intel-spr x1 2.0 0.033 0/60 available
aws eu-west-1 cpu intel-spr x2 4.0 0.067 0/60 available
aws eu-west-1 gpu nvidia-a10g x1 30.0 24 1.0 0/16 available
aws eu-west-1 gpu nvidia-t4 x1 15.0 16 0.5 1/30 availablehf endpoints hardware to list available instances by @hanouticelina in #4672custom_image now accepts the engine-specific container types supported by the API: key the dictionary with the engine name (vLLM, sGLang, tgi, tei, llamacpp, hfServe, ...) instead of leaving it flat, and each engine takes the usual container fields plus its own tuning options. Any dict without a top-level url is forwarded to the API untouched, so engines added to the API later will work without upgrading huggingface_hub, and update_inference_endpoint now handles the same payload shapes as create_inference_endpoint. On the CLI, hf endpoints deploy and hf endpoints update gain --engine, --tensor-parallel-size and --data-parallel-size, and update also accepts --custom-image, --health-route and --port. This matters because vLLM and SGLang default to a single accelerator while an endpoint is allocated every accelerator of its instance — the API now rejects that misconfiguration, and these flags are how you set things right.
$ hf endpoints deploy gpt-oss-120b-vllm --repo openai/gpt-oss-120b --framework custom \
--accelerator gpu --instance-size x8 --instance-type nvidia-h200 --region us-east-1 --vendor aws \
--engine vllm --custom-image vllm/vllm-openai:v0.23.0 --tensor-parallel-size 8
# Retune a running endpoint
$ hf endpoints update gpt-oss-120b-vllm --tensor-parallel-size 4 --data-parallel-size 2💔 Breaking change: huggingface_hub.constants.INFERENCE_ENDPOINT_IMAGE_KEYS is removed. It was never exported at the package root nor documented, but code reading it directly will now get an AttributeError.
custom_image by @hanouticelina in #4671hf endpoints deploy and update by @moon-bot-app[bot] in #4661hf extensions off the metered GitHub REST API by @hanouticelina in #4659model.task instead of sending null on create by @hanouticelina in #4701[v1.28.0] Hardware discovery and managed engine images for Inference Endpoints and more
Compare
v1.28.0.rc0 pre-release
v1.28.0.rc0 pre-release
🤖 The hf-cli skill installs itself and stays in sync
hf-cli skill installs itself and stays in syncThe hf-cli skill teaches AI agents how to use the hf CLI, but until now you had to know it existed and install it by hand. The standalone installers (bash and PowerShell) now install it globally by default, pass --exclude-skill / -ExcludeSkill to skip — and hf update refreshes it afterwards, without ever bringing it back if you opted out or removed it. Any hf command also hints, at most once a day, when the skill is missing or was generated by another hf version. The hint is purely local, never installs anything on its own, and is silenced by HF_HUB_DISABLE_UPDATE_CHECK=1.
# The installer sets up the skill for you...
>>> curl -LsSf https://hf.co/cli/install.sh | bash -s
[INFO] Installing the hf-cli skill for AI agents...
Installed 'hf-cli' to central location: ~/.agents/skills/hf-cli
[INFO] Pass --exclude-skill to skip it.
# ...or skip it entirely
>>> curl -LsSf https://hf.co/cli/install.sh | bash -s -- --exclude-skill
[INFO] Skipping the hf-cli skill (--exclude-skill)--container-command / --container-args no longer require --custom-image. That gate was conservative CLI scoping, not an API constraint: model.command and model.args are top-level fields of the endpoint payload and apply to managed engine images too, which is how the vLLM engine docs recommend passing engine flags. They can now also be changed after deploy — hf endpoints update gained both flags, and HfApi.update_inference_endpoint / InferenceEndpoint.update the matching container_command / container_args parameters. Values replace rather than append: pass an empty string to reset to the image default, or omit the flag to leave it untouched. --health-route and --port still require --custom-image, since they only exist on the custom image payload.
# Engine flags at deploy time, no custom image required anymore
>>> hf endpoints deploy my-endpoint --repo gpt2 --framework pytorch \
--accelerator cpu --instance-size x2 --instance-type intel-icl \
--region us-east-1 --vendor aws \
--container-args "--max-model-len 8192"
# Change engine flags on an existing endpoint (previously UI / raw API only)
>>> hf endpoints update my-endpoint --container-args "--enable-auto-tool-choice --tool-call-parser lfm2"
# Reset to the image defaults
>>> hf endpoints update my-endpoint --container-args ""Baseten is now supported for the conversational task. It serves an OpenAI-compatible chat completions API, so there are no provider-specific quirks: target it with provider="baseten" and your own key, or let auto-routing pick it for any model already mapped on the Hub.
>>> from huggingface_hub import InferenceClient
>>> client = InferenceClient(provider="baseten", api_key="<BASETEN_API_KEY>")
>>> out = client.chat_completion(
... model="zai-org/GLM-5.2",
... messages=[{"role": "user", "content": "Hello!"}],
... )
>>> print(out.choices[0].message.content)region to ExpandSpaceProperty_T by @hanouticelina in #4641 — the Hub added region as an expandable property for Spaces; it is now accepted by space_info / list_spaces and typed on SpaceInfo as Literal["us", "eu"] | None — docsmodel first in conversational payloads by @moon-bot-app[bot] in #4618 — routers can now resolve the provider from a small prefix instead of buffering a whole payload of base64 images. The resulting dicts are equal, only the key order changesprefix lexically, so in a bucket holding logs_existing/ but no logs/, exists(".../logs/new.txt") raised KeyError and ls(".../logs") could return the unrelated sibling. Listings are now filtered on path-component boundariesblobs/ (Windows copies, or files created by the user inside a snapshot dir) were deleted a second time as blobs, logging a FileNotFoundError traceback each. Reported freed size is unchanged, and per-path delete lines moved to debuggc.collect(); vLLM had to monkey-patch this. Also fixes a v1.0 regression where http_backoff retried on an httpx client already closed by a previous ConnectError[v1.27.0] Automatic hf-cli skill install, engine flags for Inference Endpoints & more
Compare
v1.27.0.rc0 pre-release
v1.27.0.rc0 pre-release
Full Changelog : v1.26.0...v1.26.1
Full Changelog: v1.26.0...v1.26.1
-traversal filenames on all platforms, interpreting each name under both POSIX and Windows rules (refs CVE-2026-15717). Previously only a Windows-only…
resolve_revisionLibraries that download many files one by one (config, weights, tokenizer, processor, ...) had to resolve revision="main" into a commit hash on every call — costing one HTTP request per file and risking two calls landing on two different commits if the repo is updated in between. The new HfApi.resolve_revision resolves the revision once and returns a ResolvedRevision: a str subclass whose value stays the user-facing revision (so error messages keep saying "main") while its .resolved attribute holds the commit hash. Download helpers (hf_hub_download, snapshot_download, get_cached_repo_tree) detect it and use the commit hash directly, guaranteeing every file comes from the same commit. The mapping is also written to the refs/ folder of the cache, so later runs in offline mode transparently fall back to the cached value.
>>> from huggingface_hub import resolve_revision, hf_hub_download
>>> revision = resolve_revision("openai-community/gpt2")
>>> revision
ResolvedRevision(initial=None, resolved='607a30d783dfa663caf39e06633721c8d4cfcd7e')
>>> revision == "main" # readable error messages
True
>>> config = hf_hub_download("openai-community/gpt2", "config.json", revision=revision)
>>> weights = hf_hub_download("openai-community/gpt2", "model.safetensors", revision=revision)📚 Documentation: Manage the cache — Pin a revision (advanced)
This release ships two security fixes. First, downloading or uploading to a --local-dir now rejects absolute, drive-relative, root-relative, UNC and ..-traversal filenames on all platforms, interpreting each name under both POSIX and Windows rules (refs CVE-2026-15717). Previously only a Windows-only ..\ check existed, so a malicious repo could write files outside the target directory on Windows clients — and even leak a NetNTLMv2 hash via UNC paths. Legitimate repo filenames never contain such segments, so real downloads are unaffected; note that exotic names like folder/..\..\..\file, previously tolerated on Linux, are now rejected everywhere. Second, Sandbox.create no longer injects your HF token into the job environment to download the sbx-server binary: the bucket is public, so the bootstrap now downloads it anonymously and no HF credential ever lands in the sandbox unless you explicitly opt in with forward_hf_token=True.
Organization resource groups are now supported across the client. For collections, create_collection accepts an optional resource_group_id, and the new update_collection_resource_group method wraps the dedicated Hub endpoint to assign a collection to a resource group afterwards (passing None removes it). For Jobs, run_job, run_uv_job and create_scheduled_job accept a resource_group_id parameter, mirrored by a --resource-group-id option on the hf jobs run, hf jobs uv run and hf jobs scheduled run commands. Beyond access control within an organization, resource groups are also used for cost attribution and per-group spending limits.
hf jobs run --resource-group-id <group-id> python:3.12 python train.py📚 Documentation: Collections reference, CLI reference
Job names are now much easier to work with from the terminal. hf jobs ls (and hf jobs scheduled ls) display a dedicated NAME column, and a new --name filter acts as a shortcut for --label name=NAME. The name is also surfaced as a top-level field in hf jobs inspect and in command results, instead of only living inside labels — where it remains for compatibility.
$ hf jobs ls -a --name training-v2
JOB_ID NAME IMAGE/SPACE COMMAND CREATED STATUS RUNTIME
----------- ------------ ----------- ------------ ------------ --------- -------
6a60b190... training-v2 python:3.12 python -c... 2026-07-2... COMPLETED 0s📚 Documentation: Run and manage Jobs
or) translation of the index, installation and quick-start pages by @indrajeetapache in #4454/tm/ to /ta/ (correct ISO 639-1 code)Unable to parse string as hex hash value on gated repos without content accessheader is not json-encoded stringtoken=False in create_inference_endpoint_from_catalog instead of silently ignoring it by @ckarnell in #4605UnicodeEncodeError on Windows when output is redirected or piped~/model.bin no longer raise FileNotFoundError on upload[v1.26.0] Resolve revisions only once, security hardening, and resource groups for Jobs & Collections
Compare
v1.26.0.rc2 pre-release
v1.26.0.rc2 pre-release
v1.26.0.rc1 pre-release
v1.26.0.rc1 pre-release
v1.26.0.rc0 pre-release
v1.26.0.rc0 pre-release
v1.25.1 Compare # Choose a tag to compare
v1.25.1
Compare
Jobs now get an automatic name when you don't provide one explicitly, derived from the Docker image (or UV script) plus a short hash of the command li
Jobs now get an automatic name when you don't provide one explicitly, derived from the Docker image (or UV script) plus a short hash of the command line. This means reruns of the same command share a consistent name, while different commands get distinct names — making it much easier to find and group related jobs in the UI or CLI. Names follow the server-side character rules: :, / and . in image tags are replaced with - so python:3.12 foo --truc becomes python-3-12-7c6db949. Explicit --name still takes precedence.
>>> hf jobs run --detach python:3.12 foo --truc
id: 6a60b85c13e6ef894d54b949
Hint: Job auto-named 'python-3-12-7c6db949'. Pass `--name` or run `hf jobs labels <id> --name` to rename.
📚 Documentation: Jobs guide, CLI guide
[v1.25.0] Auto-named Jobs, smarter progress bars & cache diagnostics
Compare
Nothing published for this version
Jobs on the Hub now support an optional --name flag on the CLI and a name parameter on the Python API (run_job, run_uv_job, create_scheduled_job, crea
Jobs on the Hub now support an optional --name flag on the CLI and a name parameter on the Python API (run_job, run_uv_job, create_scheduled_job, create_scheduled_uv_job). Names are stored as the name label and make Jobs easier to find and identify in the UI. You can also name an existing Job using hf jobs labels <job_id> --name my-job. Names are optional and do not need to be unique.
# Create a named Job
hf jobs run --name training-v2 python:3.12 python train.py
# Name an existing Job
hf jobs labels <job_id> --name training-v2
# Named scheduled Job
hf jobs scheduled run @hourly --name hourly-task python:3.12 python -c 'print("This runs every hour!")'
📚 Documentation: CLI guide, Jobs guide
The README has been completely refreshed to put the hf CLI first. The standalone installer (curl/PowerShell) and a terminal quick start — covering auth login, models ls, download, upload, and jobs run — now appear before the Python library section. A new For AI agents section introduces hf skills add for Codex, Cursor, OpenCode, Claude Code, and other AI tools. The Python content remains intact under the renamed Use the Python library heading, with refreshed example models and a corrected tagline ("The official CLI and Python client for the Hugging Face Hub").
[v1.24.0] Name your Jobs! (and download fixes)
Compare
Nothing published for this version
Nothing published for this version
Nothing published for this version
You can now seed a new Space from one of the official Hub templates (JupyterLab, a Gradio chatbot, a Streamlit app, etc.) instead of starting from an
You can now seed a new Space from one of the official Hub templates (JupyterLab, a Gradio chatbot, a Streamlit app, etc.) instead of starting from an empty repo. List what's available with the new list_space_templates() API or the hf spaces templates CLI command, then pass a template's repo_id (or its short name) to create_repo(..., space_template=...) or hf repos create --type space --template. The Space SDK is inferred from the template, and templates recommended as private (like JupyterLab) are created privately by default unless you explicitly choose a visibility.
# List available templates
$ hf spaces templates
NAME REPO_ID SDK PREFERRED_PRIVATE
----------- ----------------------------------- ------- -----------------
Streamlit streamlit/streamlit-template-space docker
JupyterLab SpacesExamples/jupyterlab docker ✔
# Create a Space from a template
$ hf repos create my-jupyterlab --type space --template jupyterlab
✓ Repo created
repo_id: Wauplin/my-jupyterlab
url: https://huggingface.co/spaces/Wauplin/my-jupyterlab
>>> from huggingface_hub import create_repo
>>> create_repo("my-jupyterlab", repo_type="space", space_template="jupyterlab")
A new hf extensions update command brings your installed CLI extensions to their latest published version on GitHub. Pass a name to update a single extension, or run it with no argument to check every installed extension and update the ones that are behind. Updates are applied in place — Python extensions reuse their existing venv and binary extensions are overwritten — so a failed update no longer leaves the extension uninstalled, and extensions that are already up to date are simply skipped.
# Update a single extension (accepts <name>, hf-<name> or OWNER/hf-<name>)
hf extensions update hf-claude
# Check every installed extension and update the outdated ones
hf extensions update
hf extensions update command by @Wauplin in #4496Xet downloads now show two progress bars so you can tell a transfer is alive even on a slow connection. The transfer bar advances as bytes arrive over the network, while the reconstruction bar tracks real progress as buffered chunks are written to disk — previously the single bar could sit at 0% for a long time while data was actually arriving. The dual bars are wired into single-file downloads (hf_hub_download), snapshot_download (where parallel file downloads feed the repo-level transfer and reconstruction bars), the hf download CLI, and bucket downloads.
big.bin: downloading bytes: | 52.4MB 1.2MB/s
big.bin: reconstructing file: | 52.4MB / 105MB 800kB/s
hf-cli skillhf skills add and hf skills update now generate the built-in hf-cli skill locally from your installed CLI version instead of downloading it from the marketplace bucket. The installed SKILL.md is therefore always in sync with the CLI you're running, and installing or updating the hf-cli skill works fully offline — the marketplace is only contacted when you install another managed skill. As defense-in-depth against path traversal, skill names coming from the marketplace payload are now validated before any filesystem work.
# Works fully offline, and always matches your installed CLI version
$ HF_HUB_OFFLINE=1 hf skills add --dest ./skills
Installed 'hf-cli' to ./skills/hf-cli
hf models ls by inference provider by @moon-bot-app[bot] in #4497 — docsget_cached_repo_tree utility by @Wauplin in #4513 — docssnapshot_download silently skipped files on Windows[v1.23.0] Space templates, CLI extension updates & smoother Xet downloads
Compare
Nothing published for this version
[Upload] Deprecate upload_large_folder (API + CLI) by @Wauplin in #4414 — upload_large_folder and hf upload-large-folder are now deprecated in favor o…
Sandboxes are isolated cloud machines you can spin up in seconds, run commands in with live-streamed output, and move files in and out of — all from Python or the CLI. They are built entirely on top of Jobs: under the hood a sandbox is just a Job running a tiny static server, so any Docker image with /bin/sh works and it inherits Jobs' billing, hardware flavors, and namespace permissions for free. Two flavors are available: Sandbox.create for a dedicated VM (GPU workloads, untrusted code, full isolation) and SandboxPool to pack many cheap CPU sandboxes into a few shared host VMs for fan-out workloads like RL rollouts. This release also adds background processes (sbx.run(..., background=True) / hf sandbox spawn) and a port proxy (Sandbox.proxy_url_for) so you can reach a server running inside a sandbox from the outside over HTTP or WebSocket.
from huggingface_hub import Sandbox
with Sandbox.create(image="python:3.12") as sbx: # ready in ~6s
sbx.files.write("/app/main.py", "print(40 + 2)")
print(sbx.run("python /app/main.py").stdout) # 42
# Create, run, copy files, and terminate from the terminal
hf sandbox create
hf sandbox exec <id> -- python -c "print('hi')"
hf sandbox cp data.csv <id>:/data/data.csv
hf sandbox kill <id>
hf sandbox CLI on top of Jobs by @Wauplin in #4350📚 Documentation: Sandboxes guide, Sandbox reference
snapshot_download now caches a repository's file listing on disk under a new trees/ folder, so re-downloading a commit that's already cached costs a single network call — resolving the branch or tag to a commit hash — instead of one metadata request per file. The listing is immutable per commit and shared by both snapshot_download and hf_hub_download; for Xet-enabled files it also skips the per-file HEAD /resolve request entirely, rebuilding the metadata from the cached listing. As a deliberate side effect of the completeness check, when the Hub can't be reached and the local snapshot is missing requested files, snapshot_download now raises IncompleteSnapshotError instead of silently returning a partial folder.
📚 Documentation: Manage your cache
The entire hf CLI now runs on a small in-house layer over Click 8.x instead of Typer, which had vendored Click in a way that broke the CLI's custom help rendering, error enrichment, and shell completion — and forced capping typer<0.26. The migration preserves existing behavior: --help output is byte-identical, the generated cli.md reference is unchanged apart from a header comment, and shell completion now uses Click's native completion. The public typer_factory helper is kept so downstream libraries like transformers that register their own commands keep working.
upload_large_folder and hf upload-large-folder are now deprecated in favor of upload_folder / hf upload, which handle very large and resumable uploads out of the box.allow_patterns/ignore_patterns now match case-sensitively on every OS (aligned with case-sensitive Hub paths). On Windows this is a behavior change: patterns like *.PDF no longer match file.pdf.black-forest-labs, clarifai, hyperbolic, nebius, nvidia, sambanova) — docshf discussions edit by @Wauplin in #4415 — docshf cache ls now flags leftover .incomplete files and hf cache prune removes them automatically — docsout singleton publicly + add out.log method by @Wauplin in #4471jobs-artifacts bucket and mount it; -v accepts local directories in hf jobs run/uv run (and scheduled variants) — docshf jobs scheduled trigger ... to trigger scheduled jobs on demand by @Wauplin in #4459 — docshttp_backoff now honors the standard Retry-After header (delay-seconds form); HF rate-limit headers still take precedence when present.base_model=False to get_dataset_leaderboard to include fine-tuned/derivative repos that declare a parent model.hf cache ls --filter thresholds like size>1GB now parse instead of raising.__init__.py).[v1.22.0] Sandboxes, faster downloads, and a rebuilt CLI
Compare
Nothing published for this version
-f/--filter in hf jobs ls is deprecated. Use --status and --label instead. Glob patterns (data-*), negation (key!=value), and filtering by id/image/co…
ls instead of psThe Jobs listing API and CLI have been overhauled with server-side filtering, proper pagination, and a CLI rename that aligns with the rest of hf. list_jobs() now accepts status and labels parameters that push filtering to the server, and returns a lazy iterator (matching list_models, list_datasets, etc.) so large result sets are fetched page by page. On the CLI side, hf jobs ps has been renamed to hf jobs ls for consistency with hf repos ls, hf models ls, and friends — ps and list still work as aliases.
⚠️ Breaking changes:
list_jobs() now returns an Iterable[JobInfo] instead of list[JobInfo]. If you indexed the result (jobs[0]), wrap it with list(...).-f/--filter in hf jobs ls is deprecated. Use --status and --label instead. Glob patterns (data-*), negation (key!=value), and filtering by id/image/command are no longer supported.from huggingface_hub import list_jobs
# Filter by status and labels
list_jobs(status=["RUNNING", "SCHEDULING"], labels={"env": "prod"})
# Iterate lazily
for job in list_jobs():
print(job.id)
# Materialize all results
all_jobs = list(list_jobs())
# Filter by status and labels
hf jobs ls --status running,scheduling --label env=prod --label team=ml
# Paginate with --limit
hf jobs ls -a --limit 500
hf jobs ls -a --limit 0 # no limit
hf jobs ps by @Wauplin in #4403📚 Documentation: CLI guide, Jobs guide
from huggingface_hub import loginA regression introduced in v1.20.0 caused from huggingface_hub import login to raise an ImportError on a fresh interpreter, due to a circular dependency between _oauth_device and utils._http. The fix moves _oauth_device.py into the utils layer so all imports resolve downward, eliminating the cycle. No lazy imports or workarounds required.
from huggingface_hub import login by @hanouticelina in #4385hf jobs uv run flags before the script for consistency by @davanstrien in #4396Nothing published for this version
Full Changelog: https://github.com/huggingface/huggingface_hub/compare/v1.20.0...v1.20.1
Full Changelog: https://github.com/huggingface/huggingface_hub/compare/v1.20.0...v1.20.1
> 🚨🚨 Breaking change: With the upload_folder and hf upload revamp, uploading a folder might result in multiple commits. It is also not possible to ope…
hf auth login now defaults to a browser-based OAuth Device Code flow instead of asking you to copy-paste a token. The command prints a URL and a short code, you authorize in the browser, and the CLI retrieves and saves the token for you. The same applies to login() in Python. In an interactive terminal you still get a gh-style arrow-key menu to pick between browser login and pasting a token, and --token works exactly as before.
OAuth tokens expire after 30 days, but they come with a refresh token: get_token() transparently refreshes them when less than a day of validity remains, so long-running setups keep working without re-authenticating. hf auth list now shows the expiry date for OAuth tokens.
> hf auth login
? How would you like to log in? Log in with your browser
Open this URL in your browser:
https://hf.co/oauth/device
And enter the code: 52AT-FLYZ
Waiting for authorization.
When the command is run by an AI agent, it never prompts. Instead it streams structured events so the agent can surface the URL and code to its user, then blocks until a terminal auth_success / auth_error event:
$ hf auth login --format json
{"event": "device_code", "verification_uri": "https://hf.co/oauth/device", "user_code": "52AT-FLYZ", "verification_uri_complete": "https://hf.co/oauth/device", "expires_in": 300, "interval": 5}
{"event": "auth_success", "user": "celinah", "token_name": "oauth-celinah"}
hf auth list surfaces the new expiry column:
$ hf auth list
name token expires
- ------------- ----------- -------------------
my-token hf_****5678
* oauth-user hf_****1234 2026-07-09
oauth-old hf_****9999 2026-06-09 (expired)
Finally, notebook_login() now renders the link and code with plain IPython.display.HTML, dropping the ipywidgets dependency.
hf upload for large foldershf upload and the underlying upload_folder have been revamped to be faster and far more robust on large folders. When hf_xet is installed (the default), uploads now run through a streamed, multi-commit pipeline built on the XetSession API: the folder is scanned and fed into a background Xet upload while previous batches are committed in parallel, and files are hashed in a single read pass while they are chunked (the old flow read every large file twice). Nothing changes in how you call it:
hf upload <repo-id> <path/to/folder>
This is a drop-in replacement for experimental hf upload-large-folder used until today, which will be deprecated in a future release.
🚨🚨 Breaking change: With the
upload_folderandhf uploadrevamp, uploading a folder might result in multiple commits. It is also not possible to open a PR against a specific revision while usingupload_folder. If you passcreate_pr=True, it will necessarily create a PR against main. It will open the PR no matter if some changes have been committed (previously an empty commit was resulting in no PR opened at all).
What you get on large folders:
(part N) suffix.Found 301 files to upload
Preparing ████████████████████ 301 / 301 ✓
Uploading █████████████████░░░ 255 / 300 files 25.5MB · 1.86MB/s
Committing ░░░░░░░░░░░░░░░░░░░░ 0 / 301
upload_large_folder/hf upload-large-folderare intentionally left untouched in this release; their deprecation will follow oncehf uploadhas fully absorbed the use case.
wait, SSH access, and cleaner error messagesThis release adds three major capabilities to Hugging Face Jobs.
Wait for completion. HfApi.wait_for_job() and hf jobs wait block until one or more Jobs reach a terminal stage, which makes it easy to chain commands in CI scripts. wait_for_job accepts a single id or a list, returns the final JobInfo even on failure (check job.status.stage), and only raises TimeoutError on timeout. The CLI exits 0 only if all waited-on Jobs ended COMPLETED.
# Wait on a single job, then run the next step only if it succeeded
hf jobs wait <job_id> && next-step
# Wait on a batch, with a timeout
hf jobs wait <id1> <id2> --timeout 10m
⚠️ Breaking change: non-detached
hf jobs run/hf jobs uv runnow exit with the Job's outcome (exit code1if the Job errored) instead of always exiting0. We consider this a bugfix — scripts relying on the old behavior were being silently misled — but it is called out here in case you depend on the previous exit code.
SSH access. With --ssh at launch and an SSH key registered on huggingface.co/settings/keys, you can connect straight into a running Job's container with hf jobs ssh <job_id>. Thanks to wait_for_job, hf jobs ssh now waits for the Job to reach RUNNING before connecting (with a status spinner) instead of failing immediately while it is still scheduling.
$ hf jobs run --ssh --detach python:3.12 sleep infinity
✓ Job started
id: 6a33ba2aef9220ea67d98a03
url: https://huggingface.co/jobs/Wauplin/6a33ba2aef9220ea67d98a03
Hint: Use `hf jobs ssh Wauplin/6a33ba2aef9220ea67d98a03` to open an SSH session into the job.
$ hf jobs ssh Wauplin/6a33ba2aef9220ea67d98a03
Job is running.
Running `ssh 6a33ba2aef9220ea67d98a03@ssh.hf.jobs`
root@j-wauplin-6a33ba2aef9220ea67d98a03-do4bduvn-5f153-458k4:/#
Readable errors. A new JobNotFoundError and the switch from response.raise_for_status to hf_raise_for_status turn raw httpx tracebacks into clean, actionable messages. Per-command try/except blocks were removed in favor of the global CLI error handling.
$ hf jobs inspect 000
Error: 404 Client Error. (Request ID: Root=1-6a316470-...)
Job Not Found for url: https://huggingface.co/api/jobs/Wauplin/000.
Please make sure you specified the correct job ID and namespace.
Set HF_DEBUG=1 as environment variable for full traceback.
hf jobs wait and HfApi.wait_for_job by @Wauplin in #4345hf jobs ssh wait for job to be running by @Wauplin in #4379hf endpoints deploy can now deploy custom Docker containers end-to-end, no more hand-writing JSON and POSTing the raw endpoints API. New flags wire up the image and its runtime: --custom-image, --health-route, --port, --command, and --container-args. Environment variables and secrets can be injected with --env/--env-file and --secrets/--secrets-file. On the SDK side, create_inference_endpoint gains container_command and container_args parameters.
hf endpoints deploy nex-n2-pro \
--repo nex-agi/Nex-N2-Pro \
--framework custom \
--accelerator gpu --vendor aws --region us-east-1 \
--instance-type nvidia-h200 --instance-size x8 \
--custom-image nexagi/sglang:v0.5.12 \
--health-route /health --port 30000 \
--container-args "--reasoning-parser qwen3 --tool-call-parser qwen3_coder --mamba-scheduler-strategy extra_buffer --tp 8" \
--env MODEL_ID=/repository \
--type authenticated
The type parameter now defaults to authenticated instead of the deprecated protected (passing protected emits a FutureWarning). The custom-container flags raise a clean error if used without --custom-image.
wait_for_space and hf spaces waitMirroring the new wait_for_job primitive, HfApi.wait_for_space() and hf spaces wait block until a Space leaves an intermediate stage (BUILDING, APP_STARTING, …) and settles on a final state. The CLI exits 0 if the Space is RUNNING, non-zero otherwise. hf spaces ssh and hf spaces dev-mode were refactored to use wait_for_space internally instead of the old CLI-only helper.
# Wait after a restart
hf spaces restart username/my-space && hf spaces wait username/my-space
# With a timeout
hf spaces wait username/my-space --timeout 5m
>>> from huggingface_hub import restart_space, wait_for_space
>>> restart_space("username/my-space")
>>> runtime = wait_for_space("username/my-space")
>>> runtime.stage
'RUNNING'
📚 Documentation: CLI guide — wait for a Space · Space runtime reference
wait_for_space API and hf spaces wait CLI by @Wauplin in #4380🚨🚨 With the upload_folder and hf upload revamp, uploading a folder might result in multiple commits.
It is also not possible to open a PR against a specific revision while using upload_folder. If you pass create_pr=True, it will necessarily create a PR against main. It will open the PR no matter if some changes have been committed (previously an empty commit was resulting in no PR opened at all).
RepoUrl now rejects canonical single-segment repo IDs like "gpt2" or "datasets/squad" (use "user/gpt2" or "datasets/user/squad" instead). repo_type_and_id_from_hf_id is softly deprecated. parse_hf_uri gains an endpoint argument to parse URLs from self-hosted Hub instances.
parse_hf_uri in RepoUrl + soft-deprecate repo_type_and_id_from_hf_id by @Wauplin in #4324Non-detached hf jobs run / hf jobs uv run now exit with the Job's outcome (exit 1 on Job error) instead of always exiting 0
create command instead of just reporting the 404.408 Request Timeout is now part of the default retry status set, alongside the existing 5xx codes.error_description in HTTP error messages by @coyotte508 in #4341 — failed OIDC exchanges now surface the server's error_description, making misconfigured Trusted Publishers far easier to debug.RemoteProtocolError in http_get by @Wauplin in #4351 — transient connection drops mid-download are now retried instead of failing the download.desktop.ini and similar Windows metadata files no longer trip up scan-cache.inference pytest marker to filter inference tests by @Wauplin in #4338--prerelease=allow injection for sentence-transformers by @hanouticelina in #4366[v1.20.0] Browser-based OAuth login, multi-commit folder uploads, and more
Compare
Nothing published for this version
CI workflows can now authenticate to the Hub without storing an HF_TOKEN secret, using Trusted Publishers. Set HF_OIDC_RESOURCE to the repo (or userna
CI workflows can now authenticate to the Hub without storing an HF_TOKEN secret, using Trusted Publishers. Set HF_OIDC_RESOURCE to the repo (or username) you want to scope the token to, and huggingface_hub performs the OIDC exchange under the hood — no token, no setup code. GitHub Actions is supported out of the box (with permissions: id-token: write), and other providers can pass a pre-minted ID token via HF_OIDC_ID_TOKEN. Exchanged tokens are short-lived (1 hour), repo-scoped, and cached locally with automatic refresh.
# Publish a model without storing any HF_TOKEN secret
- name: Push the model
env:
HF_OIDC_RESOURCE: acme/awesome-model
run: hf upload acme/awesome-model ./model .
📚 Documentation: Trusted Publishers
hf upload and hf download now accept an hf:// URI in place of the positional repo ID. The URI encodes repo type, revision, and file path in a single string following the grammar hf://[<TYPE>/]<ID>[@<REVISION>][/<PATH>], so you no longer need separate --repo-type and --revision flags. When a URI is provided, it is the single source of truth — passing --repo-type or --revision on top of it raises an error, and a path in the URI cannot be combined with positional filenames (download) or path_in_repo (upload).
# Download a single file from a dataset at a given revision
hf download hf://datasets/HuggingFaceM4/FineVision@refs/pr/1/data/train.parquet
# Download an entire repo
hf download hf://datasets/google/fleurs
# Upload a file to a dataset on a specific branch
hf upload hf://datasets/Wauplin/my-cool-dataset@my-branch/data/train.csv ./train.csv
hf upload and hf download by @Wauplin in #4297📚 Documentation: CLI guide — hf:// URIs · Download guide · Upload guide
Jobs can now expose container ports through the public jobs proxy using --expose <port> (CLI) or expose=[8000] (Python API). Each exposed port is reachable at https://<job_id>--<port>.hf.jobs and requires an HF token with read access to the job's namespace. This works on hf jobs run, hf jobs uv run, and their scheduled variants. Job responses now surface expose_urls on JobStatus.
# Expose a web server running on port 8000
> hf jobs run --expose 8000 python:3.12 python -m http.server 8000
✓ Job started
id: 6a2aa7cec4f53f9fc5aa4cff
url: https://huggingface.co/jobs/Wauplin/6a2aa7cec4f53f9fc5aa4cff
Hint: Exposed ports are reachable at (requires an HF token with read access to the job):
https://6a2aa7cec4f53f9fc5aa4cff--8000.hf.jobs
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
from huggingface_hub import run_job
run_job(image="python:3.12", command=["python", "-m", "http.server", "8000"], expose=[8000])
📚 Documentation: Jobs guide
All Xet upload and download code has been migrated from the old function-based hf_xet API to the new session-based XetSession API (hf-xet >= 1.5.0). A global singleton get_xet_session() provides fork-safe, thread-safe, and SIGINT-safe session reuse across all call sites — repo commits, hf_hub_download, bucket uploads/downloads, and snapshot_download all share the same underlying Tokio runtime. Token refresh is now handled through a centralized xet_connection_info_refresh_url() builder, and progress reporting follows the new (group_report, item_reports) contract.
get_token() now checks HF_TOKEN/HUGGING_FACE_HUB_TOKEN and the on-disk token file before the Colab secrets vault, so an explicit login() or env variable always wins over the notebook's stored secret.GET /api/agent-harnesses instead of using a hardcoded list, with a 24-hour on-disk cache and in-process caching for hot paths._MISSING_TYPE import from dataclasses module by @xsuchy in #4322 — fixes ImportError on Python 3.15 where dataclasses._MISSING_TYPE was removed upstream."have being" to "have been" in hf download warning output.test_get_hf_file_metadata_from_a_lfs_file by accepting cdn.hf.co in addition to xethub.hf.co in the redirect URL check.Nothing published for this version
Nothing published for this version
…correctness no longer depends on it. This is a breaking change: resuming a previously failed partial download is no longer possible. However, file res…
hf cp commandA single hf cp command now handles all file-copy workflows (upload a local file, download from the Hub, or copy between two remote locations) with consistent hf:// URI syntax for both repositories and buckets. It is also available as hf repos cp and hf buckets cp; all three aliases are identical, so you can use whichever reads best for your workflow. You can stream from stdin (-) or to stdout (-), and a trailing / on the source path gives you rsync-style semantics (copy the folder contents, not the folder itself). Note that remote-to-remote copies only work within the same storage region, and bucket-to-repo is not yet supported.
# Upload a local file to a repo
hf cp ./model.safetensors hf://username/my-model/model.safetensors
# Download a file to stdout
hf cp hf://username/my-model/config.json - | jq .
# Copy between two Hub repos
hf cp hf://username/source-model/config.json hf://username/dest-model/config.json
📚 Documentation: CLI guide — Copy files
hf cp command (aliased as hf repos cp and hf buckets cp) by @Wauplin in #4295<img width="2282" height="832" alt="image" src="https://github.com/user-attachments/assets/fa4047b2-c62e-4e92-b556-ae18db8c98a8" />
hf repos ls by @Wauplin in #4287parse_hf_uri now accepts Hugging Face web URLs so you can paste a link straight into the CLI or the library and it "just works".
# Copy-paste a URL from the website
hf cp https://huggingface.co/nvidia/LocateAnything-3B/blob/main/config.json - | jq '.architectures'
📚 Documentation: HF URIs — Web URLs
parse_hf_uri + add HfUri.to_url by @Wauplin in #4296On Lustre, GPFS, and some NFS mounts, flock(2) silently succeeds for every caller, which means filelock provides no mutual exclusion. When multiple hf_hub_download calls race for the same file, they can append to the same .incomplete file and silently corrupt the blob cache. This release fixes that by always downloading to a fresh temporary file instead of resuming an incomplete one, making the download path safe even when file locking is broken. filelock is still used as a "best-effort" hint to avoid unnecessary duplicate downloads, but correctness no longer depends on it. This is a breaking change: resuming a previously failed partial download is no longer possible. However, file resumability was already a niche use case only applicable when hf_xet is disabled.
Nothing published for this version
You can now copy files or entire folders between different repositories on the Hub — model to model, model to dataset, any combination — without downl
You can now copy files or entire folders between different repositories on the Hub — model to model, model to dataset, any combination — without downloading or re-uploading data. CommitOperationCopy accepts src_repo_id and src_repo_type for cross-repo sources, and LFS blobs are deduplicated server-side via the /lfs-files/duplicate endpoint. Non-LFS files are fetched from the source repo and committed as regular payloads. copy_files and hf buckets cp now support repo-to-repo in addition to the existing bucket destinations.
>>> from huggingface_hub import copy_files
# Copy an entire folder
>>> copy_files(
... "hf://datasets/username/source-dataset/data/",
... "hf://datasets/username/target-dataset/data/",
... )
📚 Documentation: Upload guide — Copy files between repositories
hf spaces sshA new hf spaces ssh command opens an SSH session directly into a Space's Dev Mode container. If Dev Mode is not enabled yet, the CLI prompts you to enable it. You can also use --dry-run to print the SSH command without running it, or -i to forward a specific key. Your SSH public key must be registered in your HF user settings.
# SSH into a Space
$ hf spaces ssh username/my-space
# Print the SSH command without running it
$ hf spaces ssh username/my-space --dry-run
hf spaces ssh by @gary149 in #4241📚 Documentation: CLI guide — SSH into a Space | Spaces guide — SSH into a Space
hf repos lsA new hf repos ls command lists all your repositories — models, datasets, spaces, and buckets — with storage size and percentage of namespace total, sorted by storage usage. It supports --type, --search, --namespace, and --limit (default 30, --limit 0 for all), plus the standard --format family.
# List all your repos
$ hf repos ls
# List all datasets under org with JSON output
$ hf repos ls --namespace my-org --type dataset --limit 0 --format json | jq '.[].id'
hf repos ls command by @Wauplin in #4283📚 Documentation: CLI guide — List repos | Repository guide — List your repositories
Human-mode CLI tables now use a column-aware algorithm that computes per-column width caps from the actual terminal width, shrinking only the widest columns when needed. Non-TTY output keeps the legacy fixed cap, and --no-truncate bypasses truncation entirely. Numeric columns (all int/float values) are automatically right-aligned.
# Tables adapt to your terminal width
$ hf models ls --search qwen3
# Force full values regardless of width
$ hf models ls --no-truncate
📚 Documentation: CLI guide — Output formatting
Jobs now have their own JobHardware enum, independent of SpaceHardware, so the two catalogs can diverge as needed. The old JobHardware dataclass (return type of list_jobs_hardware()) has been renamed to JobHardwareInfo. CLI --flavor / --hardware flags use a new SoftChoice type that shows known values for autocomplete but accepts any string — older CLI versions won't reject new server-side flavors. A daily CI workflow (update-hardware-flavors.yaml) runs utils/check_hardware_flavors.py to sync both enums from the live Hub API and opens a bot PR when something changes.
# Unknown flavors pass through instead of raising a validation error
$ hf jobs run --flavor future-gpu-x99 python:3.12 echo "works with unknown flavors"
📚 Documentation: Jobs guide
hf jobs to out singleton by @hanouticelina in #4254Note: The second item changes
hf jobs psandhf jobs scheduled psto use--format auto|human|agent|json|quiet(removing--format tableand-q). JSON output forhf jobs psnow flattenscommandto a string andstatusto a stage string.
extensions, lfs-enable-largefiles, version to out singleton by @hanouticelina in #4284📚 Documentation: Jobs guide — Update labels | Jobs guide — Hardware
click as an explicit dependency (typer 0.26.0 fix) by @hanouticelina in #4270local_files_only grammar by @hunterhogan in #4255_cli_utils.py by @hanouticelina in #4285Nothing published for this version
[CI] Cap typer below 0.26.0 (CLI incompatibility) #4272
[CI] Cap typer below 0.26.0 (CLI incompatibility) #4272
[CI] Add click as explicit dependency #4270
Full Changelog: https://github.com/huggingface/huggingface_hub/compare/v1.16.1...v1.16.4
Nothing published for this version
[Hot-fix] [Inference] Remove Together ASR task to drop urllib3 dependency by @Wauplin in #4248
Full Changelog: https://github.com/huggingface/huggingface_hub/compare/v1.16.0...v1.16.1
This migration includes several breaking changes: BucketUrl.handle has been renamed to BucketUrl.uri (type changed from str to HfUri, use .to_uri() fo…
Together now supports five additional task types beyond chat and text-to-image on Inference Providers:
feature_extractiontext_to_speechautomatic_speech_recognition~ EDIT: hot-fix v1.16.1 removed this task (see https://github.com/huggingface/huggingface_hub/pull/4248) to fix a dependency issue. We will add it back in a future release.image_to_imagetext_to_videofrom huggingface_hub import InferenceClient
client = InferenceClient(provider="together")
# Embeddings
embeddings = client.feature_extraction("Hello world", model="intfloat/multilingual-e5-large-instruct")
# Text-to-speech
audio = client.text_to_speech("Hello world", model="hexgrad/Kokoro-82M", extra_body={'voice': 'af_heart'})
# Text-to-video
video = client.text_to_video("A cat on the moon", model="Wan-AI/Wan2.2-T2V-A14B")
📚 Documentation: Inference guide
hf:// URI parsingAll scattered ad-hoc hf:// URI parsers throughout the codebase have been consolidated onto the new parse_hf_uri/parse_hf_mount helpers. This brings consistent parsing behavior, a new is_hf_uri public helper for validating URIs, and proper handling of @ in filenames (now treated as literal). The CLI error handler now catches HfUriError and displays a clean message instead of a raw traceback.
This migration includes several breaking changes: BucketUrl.handle has been renamed to BucketUrl.uri (type changed from str to HfUri, use .to_uri() for the string form), Volume.to_hf_handle() has been renamed to Volume.to_uri(), single-segment repo IDs (e.g. gpt2) are no longer supported in HfFileSystem paths or CLI -v flags — you must use the namespace/name format instead.
📚 Documentation: CLI guide | Buckets guide
--no-truncate flag for CLI tablesA new --no-truncate global formatting flag disables the ... shortening of scalar values in human-mode tables, letting you see full IDs, names, and other long text at a glance. List- and dict-valued columns (e.g. tags) remain shortened in human mode since they can be arbitrarily long; use --format json for those. When any cell is truncated, human tables now print a one-line hint at the bottom pointing you to the right flag.
# Show full scalar values in table output
hf models ls --no-truncate
--no-truncate flag for human tables by @hanouticelina in #4229📚 Documentation: CLI guide
initiator field on jobs API responses by @davanstrien in #4212Token files written by huggingface_hub (~/.cache/huggingface/token and ~/.cache/huggingface/stored_tokens) were previously created with Python's default modes, leaving them world-readable on most systems. This PR sets file permissions to 0o600 and parent directory permissions to 0o700 after every write, bringing huggingface_hub in line with industry-standard tools like GitHub CLI, AWS CLI, and Google Cloud SDK. Pre-existing installations will converge to safe permissions on the next token save. The chmod calls are wrapped in try/except for Windows, which doesn't support POSIX modes.
ephemeral_storage field to JobHardware by @Wauplin in #4233ty invalid-type-form on WebhooksServer annotations by @hanouticelina in #4242Nothing published for this version
Make HF_HUB_ENABLE_HF_TRANSFER deprecation warning visible to users by @Adithya191101 in #4220
create_bucket and create_repo now accept an optional region argument ("us" or "eu") so you can pin a new bucket or repo to a specific cloud region at creation time. The same option is exposed on the CLI via a --region flag on hf buckets create and hf repos create.
>>> from huggingface_hub import create_bucket, create_repo
>>> create_bucket("my-bucket", region="us")
>>> create_repo("my-model", region="eu")
$ hf buckets create my-bucket --region us
$ hf repos create username/my-model --region eu
hf skills listA new hf skills list (alias ls) command lists every skill available in the Hugging Face marketplace and shows whether each one is already installed in the four supported locations (project, global, project Claude, global Claude). Handy when you want to check what's installable and what you've already got before running hf skills add.
$ hf skills ls
NAME DESCRIPTION PROJECT PROJECT (CLAUDE) GLOBAL GLOBAL (CLAUDE)
--------------------------- ----------------------------------- ------- ---------------- ------ ---------------
hf-cli Execute Hugging Face Hub operati... yes yes yes yes
hf skills list command by @Wauplin in #4180--help output with ANSI stylinghf --help and every subcommand now render with underlined section headings and bold option/command names, making the help screens much easier to scan in a terminal. The new styling is automatically disabled when NO_COLOR is set or when the CLI detects it's running under an AI agent, so script and agent output stays clean.
--help with ANSI styling by @Wauplin in #4192hf update no longer suggests a version that isn't on brew yet for Homebrew installs.HF_DEBUG=1 for the full stack).Nothing published for this version
Update unit test warnings check to ignore unrelated deprecation warnings by @seanses in #4188
You can now manage Space secrets and environment variables directly from the command line with two new hf spaces subgroups: secrets and variables. Use hf spaces secrets to add, list, and delete write-only secrets, and hf spaces variables to add, list, and delete readable environment variables. Both add commands support multiple -s/-e flags and --secrets-file/-env-file for loading from dotenv files. On the Python side, HfApi.get_space_secrets() returns secret metadata (key, description, updated timestamp) without ever revealing values.
# List secrets (values are write-only — only keys and timestamps are shown)
$ hf spaces secrets ls username/my-space
# Add secrets
$ hf spaces secrets add username/my-space -s OPENAI_API_KEY=sk-...
$ hf spaces secrets add username/my-space --secrets-file .env.secrets
# Delete a secret (confirmation prompt, use --yes to skip)
$ hf spaces secrets delete username/my-space OPENAI_API_KEY --yes
# List, add, and delete variables (values are readable)
$ hf spaces variables ls username/my-space
$ hf spaces variables add username/my-space -e MODEL_ID=gpt2 -e MAX_TOKENS=512
$ hf spaces variables delete username/my-space MAX_TOKENS --yes
📚 Documentation: CLI guide · Manage your Space
hf buckets cp now supports rsync-style trailing slash semantics when copying folders. A trailing / on the source path copies only the folder's contents to the destination, while omitting it nests the folder itself — matching the behavior you'd expect from rsync. This makes it possible to flatten directory structures during copies, which was not possible before. Additionally, copy_files now raises an explicit EntryNotFoundError when the source path resolves to no files, instead of silently succeeding with zero operations.
# Without trailing slash: "logs" dir is nested => dst/logs/...
$ hf buckets cp hf://buckets/username/src-bucket/logs hf://buckets/username/dst/
# With trailing slash: only contents of "logs" are copied => dst/...
$ hf buckets cp hf://buckets/username/src-bucket/logs/ hf://buckets/username/dst/
📚 Documentation: Buckets guide · CLI guide
hf skills upgrade -> hf skills update by @hanouticelina in #4176 — hf skills upgrade no longer exists; use hf skills update instead.out.status() by @hanouticelina in #4171 — status updates (spinners/progress) on hf extensions install and hf spaces dev-mode are now suppressed when using --format json, --quiet, or --format agent.hf datasets leaderboard by @Wauplin in #4174hf update when already on latest version by @julien-c in #4177hf skills to bucket by @hanouticelina in #4175Nothing published for this version
This release adds three new CLI capabilities for exploring Hub content. hf models card, hf datasets card, and hf spaces card fetch the README of any r
This release adds three new CLI capabilities for exploring Hub content. hf models card, hf datasets card, and hf spaces card fetch the README of any repo and print it to stdout, with --metadata (YAML frontmatter as JSON) and --text (prose only) flags for splitting the card into its structured and unstructured parts. Calling hf models ls <repo_id>, hf datasets ls <repo_id>, or hf spaces ls <repo_id> now switches from listing repos to listing files inside that repo, with --tree, -R, -h, and --revision options mirroring the existing hf buckets ls behavior. And hf datasets leaderboard <dataset_id> surfaces model scores submitted to a benchmark dataset, making it easy to compare models by score from the terminal.
# Get model card metadata as JSON
hf models card google/gemma-4-31B-it --metadata --format json
# List files in a model repo (tree view with sizes)
hf models ls meta-llama/Llama-3.2-1B-Instruct --tree -h
# Show top 5 models on SWE-bench
hf datasets leaderboard SWE-bench/SWE-bench_Verified --limit 5
📚 Documentation: CLI guide
hf datasets leaderboard by @hanouticelina in #4154Three new hf spaces subcommands bring full lifecycle control to the terminal. hf spaces pause and hf spaces restart stop or rebuild a Space (with --factory-reboot for a clean rebuild), and hf spaces settings lets you configure sleep time and hardware in one call. A companion hf spaces hardware command lists all available hardware flavors with pricing, so you can discover options before changing settings. Pause and restart include a confirmation prompt (-y to skip) since they tear down the running container.
# Pause a Space when not in use (not billed while paused)
hf spaces pause username/my-space
# Restart with a GPU
hf spaces settings username/my-space --hardware t4-medium --sleep-time 3600
# List available hardware options
hf spaces hardware
📚 Documentation: CLI guide — Spaces
hf spaces hardware command by @Wauplin in #4169--hardware flag to hf spaces settings by @davanstrien in #4163hf update replaces the auto-update promptThe blocking interactive Y/n auto-update prompt at CLI startup is gone. It was catching too many non-interactive contexts (CI runners, Homebrew post-install hooks, Jupyter notebooks) and hanging automation. In its place, a single yellow stderr warning suggests running hf update — a new command that detects how hf was installed (Homebrew, standalone installer, or pip) and runs the right upgrade command. Set HF_HUB_DISABLE_UPDATE_CHECK=1 to silence the startup check entirely, for example in offline CI.
hf update
📚 Documentation: CLI guide — Updating
hf update + drop interactive update prompt by @Wauplin in #4131The --format, --json, and -q / --quiet flags are now handled globally by the CLI framework instead of being declared individually on each command. This means every hf command automatically accepts them — no more per-command --format boilerplate, and the flags are properly documented in a dedicated "Formatting options" section in every --help page. --format auto (the default) picks human for interactive terminals and agent when invoked by an AI agent, making CLI output automatically suitable for both people and tools.
# JSON output for scripting
hf models ls --search bert --limit 2 --json | jq '.[].id'
# IDs only, one per line
hf collections ls --owner nvidia -q
📚 Documentation: CLI guide — Output formatting
hf:// URI parsingA new parse_hf_uri function and HfUri dataclass provide a single source of truth for parsing hf://... strings across the library. Whether you reference a model, dataset, space, bucket, or file inside a repo, the parser handles all valid URI shapes — type prefixes, revisions, and paths — and rejects invalid ones with clear error messages. A companion parse_hf_mount / HfMount handles volume mount specifications (hf://...:/mnt:ro). Both are pure string parsers (no network calls) and round-trippable via .to_uri().
from huggingface_hub import parse_hf_uri, parse_hf_mount
parse_hf_uri("hf://datasets/namespace/my-dataset@refs/pr/3/train.json")
# HfUri(type='dataset', id='namespace/my-dataset', revision='refs/pr/3', path_in_repo='train.json')
parse_hf_mount("hf://buckets/my-org/my-bucket/sub/dir:/mnt:ro")
# HfMount(source=HfUri(type='bucket', id='my-org/my-bucket', ...), mount_path='/mnt', read_only=True)
📚 Documentation: HF URIs reference
Local scripts uploaded by hf jobs uv run are now stored in a {namespace}/jobs-artifacts bucket and mounted into the job container at /data instead of being base64-encoded into an environment variable. The old bash -c + xargs + base64 -d pipeline was fragile and required manual shell quoting. Bucket transport is simpler, easier to debug, and supports write-back: jobs can persist output artifacts to /data/ since the mount is read-write. The base64 transport path has been fully removed with no fallback.
Nothing published for this version
Your coding agent can read these notes before it upgrades. Set up the MCP server →