# Создание расширения CLI

CLI `hf` поддерживает расширения — пользовательские команды, предоставляемые сообществом и бесшовно интегрируемые в CLI. Расширения размещаются в публичных репозиториях GitHub и устанавливаются одной командой. После установки они отображаются как команды верхнего уровня `hf`, аналогично встроенным.

Эта система вдохновлена [расширениями GitHub CLI](https://docs.github.com/en/github-cli/github-cli/creating-github-cli-extensions). В этом руководстве вы узнаете, как создать собственное расширение, опубликовать его и сделать доступным для поиска.

> [!TIP]
> См. [справочник CLI для `hf extensions`](../package_reference/cli#hf-extensions) для пользовательской документации по установке и управлению расширениями.

## Обзор

Существует два типа расширений:

1. **Расширения для shell-скриптов**: один исполняемый файл (bash-скрипт, скомпилированный бинарный файл и т. д.), размещённый в корне репозитория.
2. **Расширения Python**: стандартный пакет Python с файлом `pyproject.toml`. Устанавливается в изолированную виртуальную среду, чтобы зависимости не конфликтовали с системными.

Оба типа используют одни и те же соглашения:

- Репозиторий GitHub **должен** называться `hf-<name>` (например, `hf-claude`, `hf-mem`).
- После установки пользователи запускают расширение с помощью `hf <name>` (например, `hf claude`).
- Расширение перечислено в `hf --help` в разделе «Extension commands».

Когда пользователь выполняет `hf extensions install [OWNER/]hf-<name>`, система сначала ищет файл бинарного/скриптового типа с именем `hf-<name>` в корне репозитория. Если файл найден, он устанавливается как расширение в виде shell-скрипта. В противном случае система переходит к установке репозитория как Python-пакета.

## Создание расширения для shell-скрипта

Расширение в виде shell-скрипта — самый простой тип. Достаточно иметь репозиторий на GitHub с исполняемым файлом `hf-<name>` в корне.

> [!WARNING]
> Расширения на языке Shell не поддерживаются в Windows. Если ваше расширение должно работать в Windows, используйте вместо него [расширение на Python](#create-a-python-extension).

### Минимальный пример

Создайте репозиторий с именем `hf-hello` на GitHub с одним файлом:

**`hf-hello`** (в корне репозитория):

```bash
#!/usr/bin/env bash
set -euo pipefail

echo "Hello from hf-hello extension!"
echo "Arguments: $@"
```

Всё готово! Теперь пользователи могут установить и запустить его:

```bash
>>> hf extensions install <your-username>/hf-hello
>>> hf hello
Hello from hf-hello extension!
Arguments:
```

### Советы по расширениям для скриптов оболочки

- Всегда начинайте с shebang (`#!/usr/bin/env bash`) и `set -euo pipefail` для безопасности.
- Скрипт получает все дополнительные аргументы, переданные пользователем. Например, `hf hello --name world` передаёт `--name world` в скрипт.
- Если пользователь выполнен вошёл в систему, то его токен Hugging Face можно получить через переменную окружения `HF_TOKEN`.
- Добавьте `manifest.json` в корень репозитория, чтобы предоставить описание (см. [Добавление описания](#add-a-description)).
- Внешние зависимости (например, `fzf`, `jq` и т. д.) **не** устанавливаются автоматически вместе с вашим расширением. Проверяйте наличие необходимых инструментов в начале скрипта и при их отсутствии корректно завершайте работу с понятным сообщением об ошибке.

> [!TIP]
> В качестве примера из реальной практики см. [hanouticelina/hf-claude](https://github.com/hanouticelina/hf-claude) — расширение для shell-скрипта, которое запускает Claude Code с HF Inference Providers.

## Создание расширения Python

Расширения на Python — это полноценные пакеты Python, устанавливаемые в изолированную виртуальную среду. Это лучший вариант, если ваше расширение имеет зависимости на Python или более сложную логику.

### Минимальный пример

Создайте репозиторий с именем `hf-hello` на GitHub со следующей структурой:

```
hf-hello/
├── pyproject.toml
└── src/
    └── hf_hello/
        ├── __init__.py
        └── cli.py
```

**`pyproject.toml`**:

```toml
[build-system]
requires = ["setuptools>=64"]
build-backend = "setuptools.build_meta"

[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`**:

```python
import sys

def main():
    print("Hello from hf-hello extension!")
    print(f"Arguments: {sys.argv[1:]}")

if __name__ == "__main__":
    main()
```

Критически важной частью является точка входа `[project.scripts]`: она **должна** называться `hf-<name>` (в данном случае `hf-hello`). Именно так CLI `hf` находит и выполняет ваше расширение.

Пользователи устанавливают и запускают его так же:

```bash
>>> hf extensions install <your-username>/hf-hello
>>> hf hello
Hello from hf-hello extension!
Arguments: []
```

### Как устанавливаются расширения Python

Когда пользователь устанавливает расширение Python, происходит следующее:

1. Виртуальное окружение создаётся в `~/.local/share/hf/extensions/hf-<name>/venv/`.
2. Ваш пакет устанавливается с помощью `pip install` из архива репозитория GitHub.
3. Система проверяет, что в venv был создан консольный скрипт `hf-<name>`.

Это означает, что зависимости вашего расширения полностью изолированы — они не будут конфликтовать с другими пакетами Python пользователя.

> [!TIP]
> В качестве примера из реальной практики см. [alvarobartt/hf-mem](https://github.com/alvarobartt/hf-mem) — расширение на Python, которое оценивает требования к памяти при инференсе для моделей HF.

## Добавьте описание

Описание помогает пользователям понять, что делает ваше расширение. Оно отображается в `hf extensions list` и в `hf --help`.

Система ищет описание в следующем порядке:

1. **`manifest.json`** в корне репозитория:

```json
{
    "description": "A short description of what your extension does"
}
```

2. **`pyproject.toml`** поле `description` (для расширений Python):

```toml
[project]
description = "A short description of what your extension does"
```

3. Описание репозитория на **GitHub** (поле «About» на странице репозитория).

Для расширений на Python наиболее естественным подходом является указание `description` в `pyproject.toml`. Для расширений на shell-скриптах используйте файл `manifest.json` или задайте описание репозитория GitHub.

## Сделайте ваше расширение доступным для поиска

Чтобы пользователи могли найти ваше расширение, добавьте тему **`hf-extension`** в ваш репозиторий GitHub:

1. Перейдите в ваш репозиторий на GitHub.
2. Нажмите на значок шестеренки рядом с «О» на правой боковой панели.
3. В разделе «Темы» добавьте `hf-extension`.

Это общепринятая в сообществе практика, которая упрощает просмотр всех доступных расширений на [странице темы hf-extension](https://github.com/topics/hf-extension).

После этого пользователи смогут найти ваше расширение прямо из CLI с помощью `hf extensions search`, которое выводит список всех репозиториев GitHub с тегом `hf-extension`, отсортированных по числу звёзд:

```bash
>>> 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...
```

Колонка `INSTALLED` показывает, какие расширения уже установлены локально. Оттуда пользователи могут установить любое из перечисленных расширений с помощью `hf extensions install <repo>`.

## Проверьте ваше расширение

В процессе разработки вы можете установить своё расширение непосредственно из вашего репозитория на GitHub:

```bash
# 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

# Update to the latest version (only if a newer commit is available)
>>> hf extensions update <name>

# List installed extensions
>>> hf extensions list

# Remove when done
>>> hf extensions remove <name>
```

> [!TIP]
> Используйте `--force` для перезаписи ранее установленной версии при тестировании обновлений.

## Обновление установленных расширений

После установки расширения вы можете обновить его до последней версии, опубликованной на GitHub:

```bash
# 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` обновляет только уже установленные расширения. Если расширение не установлено, возникает ошибка. Расширения, которые уже актуальны, пропускаются.

Версия расширения — это коммит, из которого оно было установлено, отображаемый в виде короткого SHA в столбце `VERSION` команды `hf extensions list`. Столбец `LATEST` проверяется, когда на GitHub недоступен более новый коммит, а при запуске устаревшего расширения выводится подсказка с предложением выполнить `hf extensions update <name>`. Чтобы не превышать лимиты GitHub для неавторизованных запросов, `hf` запрашивает последний коммит каждого расширения не чаще одного раза в день. Чтобы отключить эти проверки, установите `HF_HUB_DISABLE_UPDATE_CHECK=1`.

Если расширение Python перестаёт работать, потому что интерпретатор Python, с которым оно было установлено, был удалён (например, после обновления Homebrew), `hf extensions update <name>` пересоздаёт его виртуальное окружение.

## Правила именования

Имена расширений должны соответствовать следующим правилам:

- Репозиторий GitHub должен называться `hf-<name>`.
- `<name>` должен начинаться с буквы или цифры.
- `<name>` может содержать буквы, цифры, `.`, `_` и `-`.
- `<name>` не может конфликтовать с встроенной командой `hf` (например, `download`, `upload`, `auth`).

При установке пользователь может указать полное имя `OWNER/hf-<name>` или только `hf-<name>` (по умолчанию используется организация `huggingface`).

## Существующие расширения

Вот несколько расширений сообщества, которые можно использовать в качестве примера:

| Расширение | Тип | Описание |
|-----------|------|-------------|
| [hanouticelina/hf-claude](https://github.com/hanouticelina/hf-claude) | Shell-скрипт | Запуск Claude Code с провайдерами инференса HF |
| [alvarobartt/hf-mem](https://github.com/alvarobartt/hf-mem) | Python | Оценка требований к памяти при инференсе для моделей HF |

