# Tutorial 503: Publish to HuggingFace Hub

## Prerequisites

- [Weights Management](https://tinker-docs.thinkingmachines.ai/tutorials/core-concepts/weights/)

Run it interactively [source](https://github.com/thinking-machines-lab/tinker-cookbook/blob/main/tutorials/503_publish_hub.py)

```
curl -O https://raw.githubusercontent.com/thinking-machines-lab/tinker-cookbook/main/tutorials/503_publish_hub.py && marimo edit 503_publish_hub.py
```

Once you have a merged model or PEFT adapter on disk, you can upload it to HuggingFace Hub for sharing, deployment, or version control.

**The publish workflow:**

1. Build your model (merged via `build_hf_model` or adapter via `build_lora_adapter`)
2. Optionally configure a model card with training metadata
3. Push to Hub with `publish_to_hf_hub`

You need a HuggingFace token with write access. Set it via `HF_TOKEN` environment variable or `huggingface-cli login`.

## Basic publish

The simplest case -- push a model directory to a Hub repository. Repositories are created as **private** by default.

```
from tinker_cookbook import weights

url = weights.publish_to_hf_hub(
    model_path="./merged_model",
    repo_id="my-org/my-finetuned-qwen3",
)
print(f"Published to: {url}")
# -> Published to: https://huggingface.co/my-org/my-finetuned-qwen3
```

## Custom model card

Use `ModelCardConfig` to auto-generate a README.md with HuggingFace metadata (base model, datasets, tags, license). The model card is created during upload.

```
from tinker_cookbook.weights import ModelCardConfig

card_config = ModelCardConfig(
    base_model="Qwen/Qwen3.5-4B",
    datasets=["my-org/my-sft-dataset"],
    tags=["sft", "chat"],
    license="apache-2.0",
    language=["en"],
)

print("Model card config:")
print(f"  base_model: {card_config.base_model}")
print(f"  tags:       {card_config.tags}")
print(f"  license:    {card_config.license}")
```

**Output**  
```
Model card config:
  base_model: Qwen/Qwen3.5-4B
  tags:       ['sft', 'chat']
  license:    apache-2.0
```

## Preview the model card

You can preview the generated model card without publishing by calling `generate_model_card` directly.

```
from tinker_cookbook.weights import generate_model_card

_card = generate_model_card(
    config=card_config,
    repo_id="my-org/my-finetuned-qwen3",
)
print(str(_card))
```

**Output**
````
---
base_model: Qwen/Qwen3.5-4B
datasets:
- my-org/my-sft-dataset
language:
- en
library_name: transformers
license: apache-2.0
pipeline_tag: text-generation
tags:
- tinker
- tinker-cookbook
- sft
- chat
---

# my-org/my-finetuned-qwen3

This model was fine-tuned from [Qwen/Qwen3.5-4B](https://huggingface.co/Qwen/Qwen3.5-4B) using [Tinker](/content/tinker/index.html) and [tinker-cookbook](https://github.com/thinking-machines-lab/tinker-cookbook).

## Model details

- **Base model:** [Qwen/Qwen3.5-4B](https://huggingface.co/Qwen/Qwen3.5-4B)
- **Format:** Merged model

## Usage

```python
from transformers import AutoModelForCausalLM

model = AutoModelForCausalLM.from_pretrained("my-org/my-finetuned-qwen3")
```

## Framework versions

- tinker-cookbook: 0.4.2.dev30+gba719c09e
- transformers: 5.5.3
- torch: 2.12.0
  ```

## Publishing with a model card

Pass the config to `publish_to_hf_hub` and the model card is created automatically:

```
url = weights.publish_to_hf_hub(
    model_path="./merged_model",
    repo_id="my-org/my-finetuned-qwen3",
    model_card=card_config,
)
# -> Published to: https://huggingface.co/my-org/my-finetuned-qwen3
```

## Publishing a PEFT adapter

The same `publish_to_hf_hub` works for adapter directories too. When `model_path` contains `adapter_config.json`, the model card auto-detects the format.

```
adapter_card = ModelCardConfig(
    base_model="Qwen/Qwen3.5-4B",
    tags=["sft"],
    license="apache-2.0",
)

url = weights.publish_to_hf_hub(
    model_path="./peft_adapter",
    repo_id="my-org/my-qwen3-lora",
    model_card=adapter_card,
    private=False,  # make public
)
# -> Published to: https://huggingface.co/my-org/my-qwen3-lora
```

## CLI alternative

You can also publish from the command line with the `tinker` CLI:

```
# Push a merged model
tinker checkpoint push-hf \
    --model-path ./merged_model \
    --repo-id my-org/my-finetuned-qwen3

# Push a PEFT adapter
tinker checkpoint push-hf \
    --model-path ./peft_adapter \
    --repo-id my-org/my-qwen3-lora \
    --public
```

The CLI supports the same options as the Python API (model card fields, privacy settings, custom HF tokens).

## Next steps

- **[Export a Merged HuggingFace Model](https://tinker-docs.thinkingmachines.ai/tutorials/deployment/export-hf/)** 
- **[Build a PEFT LoRA Adapter](https://tinker-docs.thinkingmachines.ai/tutorials/deployment/lora-adapter/)**
