Hub Python Library documentation
Create a CLI extension
Create a CLI extension
The hf CLI supports extensions, custom commands provided by the community that integrate seamlessly
into the CLI. Extensions are hosted as public GitHub repositories and can be installed with a single command.
Once installed, they appear as top-level hf commands just like built-in ones.
This system is inspired by GitHub CLI extensions. In this guide, you will learn how to create your own extension, publish it, and make it discoverable.
For user-facing documentation on installing and managing extensions, see the CLI reference for
hf extensions.
Overview
There are two types of extensions:
- Shell script extensions: a single executable file (bash script, compiled binary, etc.) placed at the root of the repository.
- Python extensions: a standard Python package with a
pyproject.toml. Installed in an isolated virtual environment so dependencies don’t conflict with the user’s system.
Both types share the same conventions:
- The GitHub repository must be named
hf-<name>(e.g.,hf-claude,hf-mem). - Once installed, users run the extension with
hf <name>(e.g.,hf claude). - The extension is listed in
hf --helpunder “Extension commands”.
When a user runs hf extensions install [OWNER/]hf-<name>, the system first looks for a binary/script file
named hf-<name> at the repository root. If found, it installs as a shell script extension. Otherwise, it
falls back to installing the repo as a Python package.
Create a shell script extension
A shell script extension is the simplest type. You only need a GitHub repository with an executable file
named hf-<name> at the root.
Minimal example
Create a repository named hf-hello on GitHub with a single file:
hf-hello (at the repository root):
#!/usr/bin/env bash
set -euo pipefail
echo "Hello from hf-hello extension!"
echo "Arguments: $@"That’s it! Users can now install and run it:
>>> hf extensions install <your-username>/hf-hello >>> hf hello Hello from hf-hello extension! Arguments:
Tips for shell script extensions
- Always start with a shebang (
#!/usr/bin/env bash) andset -euo pipefailfor safety. - The script receives all extra arguments passed by the user. For example,
hf hello --name worldpasses--name worldto the script. - You can access the user’s Hugging Face token via the
HF_TOKENenvironment variable if they are logged in. - Add a
manifest.jsonat the repository root to provide a description (see Add a description). - External dependencies (e.g.,
fzf,jq, etc.) are not installed automatically with your extension. Check for required tools at the start of your script and fail gracefully with a helpful error message if they are missing.
For a real-world example, see hanouticelina/hf-claude — a shell script extension that launches Claude Code with HF Inference Providers.
Create a Python extension
Python extensions are full Python packages installed in an isolated virtual environment. This is the best choice when your extension has Python dependencies or more complex logic.
Minimal example
Create a repository named hf-hello on GitHub with this structure:
hf-hello/
├── pyproject.toml
└── src/
└── hf_hello/
├── __init__.py
└── cli.pypyproject.toml:
[build-system]
requires = ["setuptools>=64"]
build-backend = "setuptools.backends._legacy:_Backend"
[project]
name = "hf-hello"
version = "0.1.0"
description = "A hello-world hf CLI extension"
requires-python = ">=3.10"
[project.scripts]
hf-hello = "hf_hello.cli:main"src/hf_hello/cli.py:
import sys
def main():
print("Hello from hf-hello extension!")
print(f"Arguments: {sys.argv[1:]}")
if __name__ == "__main__":
main()The critical part is the [project.scripts] entry point: it must be named hf-<name> (here, hf-hello).
This is how the hf CLI discovers and executes your extension.
Users install and run it the same way:
>>> hf extensions install <your-username>/hf-hello >>> hf hello Hello from hf-hello extension! Arguments: []
How Python extensions are installed
When a user installs a Python extension, the following happens:
- A virtual environment is created at
~/.local/share/hf/extensions/hf-<name>/venv/. - Your package is installed via
pip installfrom the GitHub repo archive. - The system verifies that a
hf-<name>console script was created in the venv.
This means your extension’s dependencies are fully isolated — they won’t conflict with the user’s other Python packages.
For a real-world example, see alvarobartt/hf-mem — a Python extension that estimates inference memory requirements for HF models.
Add a description
A description helps users understand what your extension does. It appears in hf extensions list
and in hf --help.
The system looks for a description in the following order:
manifest.jsonat the repository root:
{
"description": "A short description of what your extension does"
}pyproject.tomldescriptionfield (for Python extensions):
[project]
description = "A short description of what your extension does"- GitHub repository description (the “About” field on the repo page).
For Python extensions, setting description in pyproject.toml is the most natural approach.
For shell script extensions, use a manifest.json file or set the GitHub repository description.
Make your extension discoverable
To help users find your extension, add the hf-extension topic to your GitHub repository:
- Go to your repository on GitHub.
- Click the gear icon next to “About” on the right sidebar.
- Under “Topics”, add
hf-extension.
This is a community convention that makes it easy to browse all available extensions on the hf-extension topic page.
Users can then discover your extension directly from the CLI with hf extensions search, which lists
all GitHub repositories tagged with the hf-extension topic, sorted by stars:
>>> hf extensions search
NAME REPO STARS DESCRIPTION INSTALLED
------ ----------------------- ----- ----------------------------------- ---------
claude hanouticelina/hf-claude 2 Extension for `hf` CLI to launch... yes
agents hanouticelina/hf-agents HF extension to run local coding...The INSTALLED column shows which extensions are already installed locally. From there, users can
install any listed extension with hf extensions install <repo>.
Test your extension
During development, you can install your extension directly from your GitHub repository:
# Install from your repo
>>> hf extensions install <your-username>/hf-<name>
# Run it
>>> hf <name>
# Reinstall after making changes (push to GitHub first)
>>> hf extensions install <your-username>/hf-<name> --force
# List installed extensions
>>> hf extensions list
# Remove when done
>>> hf extensions remove <name>Use
--forceto overwrite a previously installed version when testing updates.
Naming rules
Extension names must follow these rules:
- The GitHub repository must be named
hf-<name>. <name>must start with a letter or digit.<name>can contain letters, digits,.,_, and-.<name>cannot conflict with a built-inhfcommand (e.g.,download,upload,auth).
When installing, users can either specify the full OWNER/hf-<name> or just hf-<name> (which
defaults to the huggingface organization).
Existing extensions
Here are some community extensions you can use as reference:
| Extension | Type | Description |
|---|---|---|
| hanouticelina/hf-claude | Shell script | Launch Claude Code with HF Inference Providers |
| alvarobartt/hf-mem | Python | Estimate inference memory requirements for HF models |