Releases: huggingface/huggingface_hub
Release list
[v1.32.0] Shared blob store, sandbox security hardening and faster imports
📂 [Cache] Shared blob store: deduplicate Xet files across repos
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
- [Cache] Add cross-repo shared blob store by @hanouticelina in #4498
💻 [Jobs] Ship config inside UV scripts
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
🛡️ [Sandbox] security hardening
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
- [sandbox audit] Make the sandbox security contract match the implementation by @Wauplin in #4831
- [sandbox audit] Use each pooled sandbox's own capability token by @Wauplin in #4832
- [sandbox audit] Validate a pool host before sending it a credential by @Wauplin in #4834
- [sandbox audit] Bind the sandbox pool cache to the endpoint, credential and namespace that wrote it by @Wauplin in #4838
- [sandbox audit] Bound what a transfer or a command's output costs the client by @Wauplin in #4839
- [sandbox audit] Decide host teardown per host, and report it honestly by @Wauplin in #4840
- [sandbox audit] Address background processes by their server-assigned id by @Wauplin in #4836
- [sandbox audit] Pin the sandbox server binary by digest and verify it before running it by @Wauplin in #4837
- [sandbox audit] Keep secret values out of argv in the CLI and fix the env/secrets docs by @Wauplin in #4835
🔒 Security hardening for serialization and validation
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.
- [Serialization] Harden torch checkpoint deserialization by @Wauplin in #4877
- [Core] Reject path traversal via embedded ".." segments in path_in_repo by @bodapatisaikrishna in #4884
- [Core] Restrict repo_id validation regex to ASCII word characters by @bodapatisaikrishna in #4892
🧰 Smarter cache management
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
- [CLI] Support file URIs in hf cache rm by @hanouticelina in #4847
- [Cache] Support kernel repos in
hf cachecommands by @hanouticelina in #4905
🚀 Faster imports
huggingface_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.
🖥️ CLI
- [CLI] Make --format human override agent auto-detection by @hanouticelina in #4878
- [CLI] Add
hf --skillsas an alias forhf skills previewby @Wauplin in #4906
🤖 Inference
- Add
--container-registry-{username,password}by @alvarobartt in #4854 — docs
📊 Jobs
- [Jobs] Scope network groups to the namespace and resource group by @co42 in #4855
- [Jobs] Expose the network group on JobInfo by @co42 in #4862
🔧 Other QoL Improvements
- [Download] Send X-HF-Download-Counter header on download calls by @Wauplin in #4613
- [Buckets] Send mtime when copying files by @Wauplin in #4920
🐛 Bug and typo fixes
- fix(serialization): save_torch_state_dict cleanup regex silently matches/deletes unrelated files by @g0rdonL in #4857
- [Sandbox] Preserve terminal command results by @evalstate in #4851
- [Http] Fix race in
get_session()creating multiple clients by @hanouticelina in #4868 - [RepoCard] Fix AttributeError when model-index has source: null by @Saniyagupte in #4870
- [Spaces] Fix AttributeError in SpaceRuntime when hardware is null by @Saniyagupte in #4873
- [Buckets] Fix file metadata size on redirects by @davanstrien in #4874
- [CLI] Fix card data serialization by @davanstrien in #4882
- Fix doubled colon in snapshot download transfer bar description by @sandeepb2013 in #4890
- [Download] Fix silently disabled tree cache on long Windows paths by @askalf in #4896
- [Safetensors] Recognize proposed U3 metadata by @7dsolv in #4898
- [Serialization] Sync
_get_dtype_sizewith safetensors by @Wauplin in #4902
📖 Documentation
- [Community] Fix docstring for DiscussionComment.last_edited_by by @Saniyagupte in #4864
- [Docs] Fix hf discussions info options that do not exist by @rishabhsai in #4886
🏗️ Internal
- [CI] Make CI less flaky and stop 6h hung jobs by @Wauplin in #4830
- Bump the actions group with 4 updates by @dependabot[bot] in #4848
- Post-release: bump version to 1.32.0.dev0 by @huggingface-hub-bot[bot] in #4856
- Key the doc build concurrency group on the pull request number by @albertvillanova in #4876
[v1.31.0] Custom labels for Sandboxes, More resilient downloads and more
🏷️ Custom labels for Sandboxes
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-infra📥 More resilient downloads
A 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_downloadnow writes therefs/cache file atomically, reusing the logic already used byhf_hub_download. This fixes a long-standing race when many concurrentsnapshot_downloadcalls 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_downloadby @Wauplin in #4829 -
[Download] Prevent cached file copies during local-dir dry runs by @wakamex in #4817
🔌 httpx re-exported for library integrators
huggingface_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
🔒 Security
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.
🖥️ CLI
- [CLI] Fix
hf buckets rm --recursivedeleting lexical siblings of the prefix: removinglogs/no longer toucheslogs_root.txtby @Wauplin in #4804 - [CLI] Don't let
hf updateself-upgrade a pip install on Windows: it now prints thepip install -Ucommand to run instead of leaving a broken install by @Wauplin in #4823 - [CLI] Raise explicit error for shell-script extensions on Windows by @hanouticelina in #4846
- [CLI] Fix truncated command descriptions in the CLI reference by @hanouticelina in #4849
🐛 Bug and typo fixes
- [hf_api] Make
CommitInfocopy-able and pickle-able by @Wauplin in #4822 - [LFS] Fix
SliceFileObj.__iter__yielding only the first 4MB chunk by @BenYang12 in #4844 - Fix dotenv parser truncating unquoted values containing
#(used byhf jobs --env-file) by @BenYang12 in #4842 - Keep single-quoted values verbatim in
load_dotenvby @AnishPatel526 in #4827
📖 Documentation
- [Docs] Clarify Jobs argument forwarding with
--and align examples by @davanstrien in #4809
🏗️ Internal
- Bump the actions group across 1 directory with 5 updates by @dependabot[bot] in #4798
- Post-release: bump version to 1.31.0.dev0 by @huggingface-hub-bot[bot] in #4806
[v1.30.0] Scheduled job filters, repo-aware revision pinning and more
🖥️ hf jobs scheduled ls can now filter by status, label and name
You 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
- Align
hf jobs scheduled lsfiltering withhf jobs ls(--status/--label/--name) by @moon-bot-app[bot] in #4773
🔖 ResolvedRevision now pins the repo it was resolved for
ResolvedRevision 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
🤖 Inference
- Do not require the
conversationaltag for chat-completion on hf-inference: any model with pipeline tagtext-generationorimage-text-to-textcan now be served, mirroring the updated provider-side rules by @hanouticelina in #4784
🐛 Bug and typo fixes
- [Download] Follow redirects between Hub hosts when resolving files, instead of failing with a misleading connection error (redirects to CDNs are still not followed, so LFS metadata is preserved and
Authorizationis never forwarded off-Hub) by @hanouticelina in #4739
📖 Documentation
- [Sandbox] Mark the Sandbox API as experimental across docstrings, guides, package reference and CLI help, and clarify that shared sandboxes are intended for workloads within the same trust boundary by @Wauplin in #4783
🏗️ Internal
- [Release] Refresh OpenCode model cache (
opencode models --refresh) before validatingRELEASE_NOTES_MODEL, fixing release CI failures on cold runners by @Wauplin in #4761 - [Release] Consolidate the HF CLI skill sync into the release workflow, removing the duplicate standalone sync workflow that opened two PRs on
huggingface/skillsper release by @hanouticelina in #4765 - [CI] The close-unscoped-community-prs workflow stays available for manual runs only: enforcement was enabled and then disabled again within this release by @hanouticelina and @Wauplin in #4766, #4800
- [CI] Fix torch_1.11 case-arm label to match the renamed matrix entry, restoring torch installation on that lane by @MohammedAlkindi in #4776
- Post-release: bump version to 1.30.0.dev0 by @huggingface-hub-bot[bot] in #4763
[v1.29.0] Fix Xet downloads rate limits, bucket visibility updates, and security fixes
⚡ Xet downloads no longer make one API call per file
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.
- [Xet] Cache connection info to avoid one token request per file by @hanouticelina in #4732
🪣 Change bucket visibility after creation
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
- [Buckets] Add support for updating bucket visibility by @hanouticelina in #4715
🔒 Security fixes
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.
- [Buckets] Validate remote paths in bucket sync to prevent path traversal by @hanouticelina in #4731
- Fix extension-confusion fallback to pickle in load_state_dict_from_file (add
_is_safetensors) by @moon-bot-app[bot] in #4737
🤖 Inference
- [Inference Providers] Send LoRA weights for fal-ai text-to-video by @moon-bot-app[bot] in #4706
- Hint at
stream=Truewhen a non-streaming inference call fails with 504 by @moon-bot-app[bot] in #4744
🖥️ CLI
- [CLI] Installer: point at shadowed newer Python on macOS by @hanouticelina in #4758
- [CLI] Fix hf-mount install instructions in hf-cli skill by @Wauplin in #4747
🔧 Other QoL Improvements
- [MCP] Set upper bound mcp<2.0 for optional extra dependency
huggingface_hub[mcp]by @Wauplin in #4735 - Remove leftover deprecated
labels/tagsfrom docstrings and signature by @Wauplin in #4745
🐛 Bug and typo fixes
- [CLI] Fix upload when local_path is a wildcard by @shoutoutuoadi325 in #4711
- [CLI] Fix argument help rendering with click 8.5 by @Wauplin in #4759
📖 Documentation
- Docs: mark Sandboxes as experimental and drop the "HF token never enters the sandbox" claim by @moon-bot-app[bot] in #4734
🏗️ Internal
- [Release] Refresh OpenCode model cache before validating RELEASE_NOTES_MODEL by @Wauplin in #4761
- [Tests] Fix expand property tests after server-side error message change by @Wauplin in #4746
- [CI] Auto-close community PRs without a maintainer-scoped issue by @hanouticelina in #4695
- Post-release: bump version to 1.29.0.dev0 by @huggingface-hub-bot[bot] in #4702
- Bump the actions group with 4 updates by @dependabot[bot] in #4704
[v1.28.0] Hardware discovery and managed engine images for Inference Endpoints and more
🔎 Discover deployable hardware with hf endpoints hardware
Deploying 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 available- [Inference Endpoints] Add
hf endpoints hardwareto list available instances by @hanouticelina in #4672
🚀 Managed engine images and multi-accelerator parallelism for Inference Endpoints
custom_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.
- [Inference Endpoints] Support managed engine images in
custom_imageby @hanouticelina in #4671 - [CLI] Add --tensor-parallel-size / --data-parallel-size to
hf endpoints deployandupdateby @moon-bot-app[bot] in #4661
🤖 Inference
- [Inference Providers] deepinfra: add text-to-speech support by @ovuruska in #4559
- [Inference Providers] deepinfra: add feature-extraction support by @ovuruska in #4656
🖥️ CLI
- [CLI] Keep
hf extensionsoff the metered GitHub REST API by @hanouticelina in #4659
🐛 Bug and typo fixes
- [CLI] Fix scheduled upload of a single file in a subfolder by @dfedoryshchev in #4619
- [Download] Fix tqdm_class ignored by the Xet transfer bar by @bharadwaj-pendyala in #4647
- [CLI] Fix duplicated GPU rows in hf jobs stats by @dfedoryshchev in #4660
- Don't report a 429 as a window rate limit when the window isn't exhausted by @moon-bot-app[bot] in #4662
- [Download] Fix ResolvedRevision string value after pickle/copy by @hanouticelina in #4692
- Do not use a redirect's Content-Length as file size in get_hf_file_metadata by @assafvayner in #4699
- [Inference Endpoints] Omit
model.taskinstead of sending null on create by @hanouticelina in #4701
📖 Documentation
- Fix import path in parse_hf_mount doc example by @davidpavlovschi in #4621
- Improve wording in cache limitations documentation by @aaravxsingh15 in #4622
- [Docs] Normalize malformed docstring parameter entries by @4ktLuffy in #4623
- [Docs] Remove obsolete Repository API from German guides by @OllieinCanada in #4679
🏗️ Internal
- Post-release: bump version to 1.28.0.dev0 by @huggingface-hub-bot[bot] in #4643
- Bump the actions group with 4 updates by @dependabot[bot] in #4652
[v1.27.0] Automatic `hf-cli` skill install, engine flags for Inference Endpoints & more
🤖 The hf-cli skill installs itself and stays in sync
The 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)⚙️ Engine flags for Inference Endpoints, at deploy time and after
--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 ""- [Inference Endpoints] Allow container command/args without custom image + support them in update by @gary149 in #4628
🚀 Baseten joins the inference providers
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)🔧 Other QoL Improvements
- [HfApi] Add
regiontoExpandSpaceProperty_Tby @hanouticelina in #4641 — the Hub addedregionas an expandable property for Spaces; it is now accepted byspace_info/list_spacesand typed onSpaceInfoasLiteral["us", "eu"] | None— docs - [Xet] Bump minimum hf-xet to 1.5.2 by @hanouticelina in #4640 — 1.5.2 fixes possible hangs on poor networks, but the floor was still 1.5.1, so fresh installs could land on the buggy version
- Serialize
modelfirst 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 changes
🐛 Bug and typo fixes
- [HfFileSystem] Fix bucket prefix collisions by @lewtun in #4630 — the Buckets API applies
prefixlexically, so in a bucket holdinglogs_existing/but nologs/,exists(".../logs/new.txt")raisedKeyErrorandls(".../logs")could return the unrelated sibling. Listings are now filtered on path-component boundaries - [Cache] Stop deleting snapshot files twice when deleting a revision by @hanouticelina in #4639 — snapshot files that aren't symlinks into
blobs/(Windows copies, or files created by the user inside a snapshot dir) were deleted a second time as blobs, logging aFileNotFoundErrortraceback each. Reported freed size is unchanged, and per-path delete lines moved todebug - [Download] Don't retain caller frames when falling back to cache after a failed HEAD call by @Wauplin in #4614 — the swallowed HEAD exception kept its traceback, and with it the whole caller stack, alive until the next
gc.collect(); vLLM had to monkey-patch this. Also fixes a v1.0 regression wherehttp_backoffretried on an httpx client already closed by a previousConnectError
🏗️ Internal
v1.26.1
[v1.26.0] Resolve revisions only once, security hardening, and resource groups for Jobs & Collections
📌 Pin a revision once with resolve_revision
Libraries 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)
🔒 Security hardening for downloads and sandboxes
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.
- [Download] Reject absolute/UNC/traversal filenames on local_dir & cache paths by @Wauplin in #4540
- [Sandbox] Don't send the HF token to sandbox jobs by @Wauplin in #4583
🗂️ Resource groups for Jobs and Collections
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
- Support resource groups for collections by @moon-bot-app[bot] in #4575
- feat(jobs): support resource group at Job creation by @moon-bot-app[bot] in #4576
📊 Job names, front and center in the CLI
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
📖 Documentation
- Added Odia (
or) translation of the index, installation and quick-start pages by @indrajeetapache in #4454 - [Docs] Fix Odia (or) docs build, register it in CI, rename tm -> ta by @Wauplin in #4589 — note: Tamil docs URLs move from
/tm/to/ta/(correct ISO 639-1 code) - [Docs] Fix HF_XET_SHARD_CACHE_SIZE_LIMIT default (4GB → 16GB) by @rajatarya in #4593 — docs
- docs(jobs): mention cost attribution/spending-limit in resource_group_id docs by @Pierrci in #4597 — docs
🐛 Bug and typo fixes
- [Download] Reject redacted Xet hashes from tree cache by @seanses in #4595 — fixes xet downloads failing with
Unable to parse string as hex hash valueon gated repos without content access - [Safetensors] Fix truncated header on 100kb boundary by @Wauplin in #4603 — headers of 99994–100000 bytes were silently truncated and failed with
header is not json-encoded string - Reject
token=Falseincreate_inference_endpoint_from_cataloginstead of silently ignoring it by @ckarnell in #4605 - [CLI] Don't crash when stdout can't encode non-ASCII output by @Wauplin in #4610 — fixes
UnicodeEncodeErroron Windows when output is redirected or piped - [Core] Fix tilde expansion in CommitOperationAdd by @Saniyagupte in #4612 — paths like
~/model.binno longer raiseFileNotFoundErroron upload
🏗️ Internal
- [Bot] Update hardware flavor enums and docs by @huggingface-hub-bot[bot] in #4577
- Post-release: bump version to 1.26.0.dev0 by @huggingface-hub-bot[bot] in #4584
- [CI] [Release] Make notify-prs best-effort with a retry by @Wauplin in #4585
- [Release] [CI] Update slack message generation by @Wauplin in #4587
- [Release] [CI] Fix slack message generation follow-ups by @Wauplin in #4588
- [CI] Unpin pytest-rerunfailures to fix cascading fixture setup errors by @Wauplin in #4590
v1.25.1
[v1.25.0] Auto-named Jobs, smarter progress bars & cache diagnostics
🏷️ Auto-named Jobs on creation
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
🔧 Other QoL Improvements
- Add timeout parameter to safetensors metadata methods by @go-bai in #4378
- [Download] [Fix] Update file-count progress bar on completion by @Wauplin in #4560
- [Cache] Warn on inconsistency in cache by @Wauplin in #4551 — docs
📖 Documentation
- Document the 150-character limit on collection descriptions by @davanstrien in #4553 — docs
- [Docs] Fix compromised DO_NOT_TRACK URL by @Wauplin in #4545
- Add SECURITY.md file by @Wauplin in #4541
🐛 Bug and typo fixes
- [Repocard] Fix catastrophic backtracking (ReDoS) in REGEX_YAML_BLOCK by @sohumt123 in #4526
- Fix Windows crash when downloading into a deep local_dir by @askalf in #4546
- [Fix] Do not fail on create space if exists_ok=True and 402 Payment required error by @Wauplin in #4539
- [Repocard] Preserve order of appended keys in CardData.to_yaml by @rahulrshetty45 in #4561
- [HfFileSystem] Raise FileNotFoundError when streaming a missing file by @rahulrshetty45 in #4562
- [Upload] Forward token in _final_commit_info repo_info lookup by @Wauplin in #4572