How to Upload Decensored Models to Hugging Face Using Heretic
Heretic provides an interactive CLI workflow in src/heretic/main.py that authenticates via temporary tokens, constructs repository IDs, and pushes either LoRA adapters or fully merged decensored models to the Hugging Face Hub without persisting credentials to disk.
The p-e-w/heretic repository includes a built-in mechanism to upload decensored models to Hugging Face using Heretic's command-line interface. This workflow handles authentication, repository naming, visibility settings, and model card generation automatically, ensuring your decensored weights reach the Hub securely.
Interactive Upload Workflow in Heretic
The upload sequence is implemented in src/heretic/main.py (lines 777–951) and triggers after you select a trial from the interactive menu. The workflow proceeds through eight distinct stages, from token acquisition to model card attachment.
Authentication and Token Handling
Heretic prioritizes security by avoiding on-disk credential storage. The process begins at lines 777–782:
- First, the library invokes
huggingface_hub.get_token()to check for a cached token. - If none exists,
prompt_password(defined insrc/heretic/utils.py) interactively requests your personal access token. This prevents writing sensitive credentials to disk, which is critical when working on shared GPU servers.
Repository Configuration
Once authenticated, Heretic identifies your Hub identity and constructs the target repository:
huggingface_hub.whoami(token)retrieves your username and profile details (lines 783–889), confirming the account that will own the model.- The default repository ID follows the pattern
<username>/<model-name>-heretic, derived fromsettings.modelinsrc/heretic/config.py(lines 891–896). - You may override this default via an interactive prompt.
Visibility and Merge Strategy Selection
Before pushing, you configure visibility and artifact type:
- Visibility: The prompt at lines 898–904 lets you select Public or Private, mapping directly to the
privateboolean passed topush_to_hub. - Merge Strategy:
obtain_merge_strategy(settings)(lines 907–913) determines whether to upload a LoRA adapter (adapter) or a fully merged model (merged). This aligns with the strategy used for local saves.
Pushing to the Hub
The actual upload occurs at lines 910–924, branching based on the merge strategy:
For LoRA adapters:
model.model.push_to_hub(repo_id, private=private, token=token)
For merged models:
merged_model = model.get_merged_model()
merged_model.push_to_hub(repo_id, private=private, token=token)
model.tokenizer.push_to_hub(repo_id, private=private, token=token)
The merged path explicitly pushes both the model weights and the tokenizer to ensure the repository is complete.
Model Card Generation
Finally, Heretic attaches or creates a model card (lines 927–951):
- If
REPOCARD_NAME(typicallyREADME.md) exists in the local model directory, it loads viaModelCard.load. - Otherwise, it attempts to fetch the card from the original model on the Hub.
- If no metadata exists, it initializes a default
ModelCardDatainstance to ensure the Hub receives structured metadata.
The card is then pushed to the repository, completing the upload workflow.
Programmatic Upload Script
While the interactive CLI is the primary interface, you can replicate the upload logic programmatically. The following Python script mirrors the workflow in src/heretic/main.py, allowing you to upload decensored models without manual prompting:
from pathlib import Path
import huggingface_hub
from huggingface_hub import ModelCard, ModelCardData
# 1. Get a token (fallback to manual input)
token = huggingface_hub.get_token()
if not token:
import getpass
token = getpass.getpass("Hugging Face access token: ")
# 2. Identify the user
user = huggingface_hub.whoami(token)
repo_id = f"{user['name']}/my-model-heretic" # customize as needed
private = False # or True for a private repo
# 3. Load your decensored model
# Replace with your actual Heretic model instance
# model = HereticModel.from_pretrained(...)
# 4. Choose merge strategy
strategy = "merged" # or "adapter"
if strategy == "adapter":
model.model.push_to_hub(repo_id, private=private, token=token)
else:
merged = model.get_merged_model()
merged.push_to_hub(repo_id, private=private, token=token)
model.tokenizer.push_to_hub(repo_id, private=private, token=token)
# 5. Handle model card
model_path = Path("path/to/local/model")
card_path = model_path / huggingface_hub.constants.REPOCARD_NAME
if card_path.is_file():
card = ModelCard.load(card_path)
else:
try:
card = ModelCard.load(repo_id)
except Exception:
card = ModelCard()
if card.data is None:
card.data = ModelCardData()
card.push_to_hub(repo_id, token=token, private=private)
print(f"✅ Uploaded to https://huggingface.co/{repo_id}")
When run after you have already performed a Heretic trial (i.e., you have a model object with the decensored weights), this script reproduces the same behaviour as the CLI's "Upload the model to Hugging Face" option.
Key Source Files and Implementation Details
The upload functionality is distributed across four core modules in the p-e-w/heretic repository:
| File | Role | Key Components |
|---|---|---|
src/heretic/main.py |
Interactive CLI and upload orchestration | prompt_password, huggingface_hub.whoami, obtain_merge_strategy, push_to_hub calls (lines 777–951) |
src/heretic/config.py |
Configuration and settings | Settings model storing original model path (settings.model) used to derive default repository names |
src/heretic/model.py |
Model abstraction and merging | get_merged_model(), push_to_hub(), tokenizer handling |
src/heretic/utils.py |
User interaction utilities | prompt_text, prompt_password, prompt_select for interactive prompts |
These modules collectively implement the secure, credential-free upload pipeline that distinguishes Heretic's approach to sharing decensored models.
Summary
- Heretic's upload workflow is implemented in
src/heretic/main.py(lines 777–951) and provides an interactive, menu-driven interface for pushing decensored models to Hugging Face. - Security-first authentication uses
huggingface_hub.get_token()with a fallback toprompt_password, ensuring tokens remain in memory only and are never written to disk—critical for shared GPU environments. - Flexible artifact selection via
obtain_merge_strategylets you upload either a LoRA adapter or a fully merged model, with the latter including the tokenizer. - Automatic model card handling checks for local
README.mdfiles, falls back to remote cards, and ensures valid metadata viaModelCardDatabefore pushing.
Frequently Asked Questions
How does Heretic handle Hugging Face authentication without storing tokens on disk?
Heretic prioritizes security by first attempting to retrieve a cached token via huggingface_hub.get_token(). If no token exists, it invokes prompt_password (defined in src/heretic/utils.py) to request your personal access token interactively. This approach ensures the token remains in memory only and is never written to configuration files, which is essential when operating on shared GPU servers where filesystem credentials could be exposed.
Should I upload a LoRA adapter or a merged model to Hugging Face?
The choice depends on your distribution goals. Heretic's obtain_merge_strategy function (lines 907–913 in src/heretic/main.py) determines the upload artifact:
- LoRA adapter: Uploads only the adapter weights via
model.model.push_to_hub(). This creates a smaller repository and allows users to merge it with the base model locally. - Merged model: Creates a full merged copy using
model.get_merged_model(), then pushes both the merged weights and the tokenizer. This provides an immediately usable model but results in a larger repository.
Can I make my uploaded decensored model private on Hugging Face?
Yes. During the interactive upload workflow (lines 898–904 in src/heretic/main.py), Heretic prompts you to select repository visibility. Your choice maps directly to the private boolean parameter passed to push_to_hub(). Selecting Private creates a repository visible only to you and explicitly invited collaborators, while Public makes the model accessible to the entire Hugging Face community.
What happens if my local model doesn't have a README.md model card?
Heretic handles missing model cards gracefully. In src/heretic/main.py (lines 927–951), the code first checks for a local REPOCARD_NAME (typically README.md). If not found, it attempts to load an existing card from the remote Hub using the original model ID. If neither exists, it initializes a fresh ModelCard with a default ModelCardData instance to ensure the uploaded repository contains valid metadata. This guarantees that your decensored model appears correctly on the Hugging Face Hub regardless of the original card's presence.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →