huggingface/sync-models
Sync chat-ui's model config with the HuggingFace router — add descriptions for new models, flag reasoning-capable ones, enable artifacts for models with 32B+ parameters, and prune deprecated models the router no longer serves. Use when models are released or removed on the router and prod.yaml/dev.yaml need syncing. Triggers on requests like "add new model descriptions", "update models from router", "sync models", "remove deprecated models", "prune models no longer on the router", or when explicitly invoking /sync-models.
npx skills add https://github.com/huggingface/chat-ui --skill sync-models
Add descriptions for new models available in the HuggingFace router to chat-ui's prod.yaml and dev.yaml. Also flag models that support the OpenAI-compatible reasoning_effort parameter so chat-ui shows the thinking-effort selector for them, and enable artifacts for models with 32B or more total parameters. Finally, prune deprecated models — entries in the config whose ids the router no longer returns.
The comparison runs in two directions:
Both directions share the same source of truth: whatever https://router.huggingface.co/v1/models returns _right now_.
WebFetch https://router.huggingface.co/v1/models
Extract all model IDs from the response.
chart/env/prod.yaml (and chart/env/dev.yaml — the two share the same model set)MODELS JSON array in envVarsCompare the router list against the config in both directions:
Compute both sets with a script so the diff is exact rather than eyeballed — the list is long and near-duplicate ids (GLM-4.7 vs GLM-4.7-FP8, -Instruct vs -Thinking) are easy to miss:
python3 - <<'EOF'
import json, re, subprocess
raw = subprocess.check_output(["curl","-sS","https://router.huggingface.co/v1/models"]).decode()
router = {m["id"] for m in json.loads(raw)["data"]}
txt = open("chart/env/prod.yaml").read()
block = re.search(r"MODELS:\s*>\s*\n(.*?)\n\S", txt, re.S).group(1)
ids = [e["id"] for e in json.loads(block)]
keep = {"omni"} # never treat the router alias (PUBLIC_LLM_ROUTER_ALIAS_ID) as deprecated
print("MISSING (add): ", sorted(router - set(ids)))
print("DEPRECATED (rm): ", [i for i in ids if i not in router and i not in keep])
EOF
Only operate on the missing set for the add/research steps (4–8). Never edit, re-flag, or re-describe entries that already exist in prod.yaml / dev.yaml — even if you think their reasoning capability or description could be improved. Existing entries are intentionally curated and may have been hand-tuned for known quirks. Out of scope unless the user explicitly asks for a re-audit.
Exclude the router alias from the deprecated set. The omni entry (whatever PUBLIC_LLM_ROUTER_ALIAS_ID is set to) is a synthetic alias, not a router model, so it never appears in /v1/models. Never remove it. The same goes for any other intentionally-synthetic id that isn't meant to come from the router.
For each missing model, search the web for its specifications:
A model is "reasoning-capable" for chat-ui purposes if it accepts the OpenAI-style reasoning_effort: low|medium|high parameter via the HF router and _meaningfully changes its chain-of-thought depth_ in response. Whether that holds depends on both the model and the providers serving it — the router is a transparent proxy, so behavior comes from each provider's implementation. Don't decide from the name alone.
Heuristic shortlist (candidates worth verifying):
gpt-oss, -Thinking, -thinking, -Reasoning, -reasoning, QwQ, R1, MiniMax-M, Kimi-K2-Thinking, cogito-<think>...</think> examplesSkip without further checking:
Qwen3-235B-A22B-Instruct-2507 ≠ Qwen3-235B-A22B-Thinking-2507).Verify each candidate via provider docs before flagging:
For each model on the heuristic shortlist, look up its live providers in the /v1/models payload, then check those providers' chat-completions documentation for reasoning_effort, reasoning_content, enable_thinking, or a thinking parameter. If at least one live provider documents it for this model (or for the model family in general), flag it as reasoning-capable. The HF router will proxy the parameter to whichever provider it picks.
Provider docs to consult (use WebFetch / WebSearch):
If none of the live providers document reasoning support for the model, don't flag it — even if the name pattern-matches. If documentation is ambiguous, lean toward not flagging and mention it in the commit so it can be revisited.
Enable artifacts for any new model with 32B or more total parameters by appending "supportsArtifacts": true to its entry. This makes chat-ui instruct the model to emit <artifact> blocks rendered in the side panel.
35B-A3B MoE qualifies (35B total ≥ 32B) even though only 3B are active.Qwen3.6-27B, 550B-A55B). When it isn't, use the parameter count found while researching the model in step 4.Match existing style:
Examples:
"Flagship GLM MoE for coding, reasoning, and agentic tool use.""MoE agent model with multilingual coding and fast outputs.""Vision-language Qwen for documents, GUI agents, and visual reasoning.""Mobile agent for multilingual Android device automation."Add new models at the TOP of the MODELS array in:
chart/env/prod.yamlchart/env/dev.yamlBase format:
{ "id": "org/model-name", "description": "Description here." }
Append "supportsReasoning": true for reasoning-capable models (step 5) and "supportsArtifacts": true for 32B+ models (step 6). A model can carry both:
{
"id": "org/model-name",
"description": "Description here.",
"supportsReasoning": true,
"supportsArtifacts": true
}
supportsReasoning is what makes chat-ui render the Thinking-effort dropdown in the chat footer for that model and forward reasoning_effort to the router. supportsArtifacts enables the artifacts side panel for the model.
Delete the full entry line for every id in the deprecated set (step 3) from both chart/env/prod.yaml and chart/env/dev.yaml. Match on the exact "id" value so near-duplicate ids aren't removed by accident, and keep the removal symmetric — the two files must end with the same model set.
Removing a deprecated entry is safe and low-risk: MODELS is an overrides map, not the model list. src/lib/server/models.ts builds the catalog from the router's /v1/models response and only applies a MODELS entry when its id is present in that response (it maps over the router models and looks each up in the override map). An entry whose id the router no longer serves is a dead override — it never renders in the UI — so pruning it changes nothing at runtime; it just keeps the config honest and readable.
After editing, re-parse the MODELS block in each file as JSON to confirm it's still valid and that no deprecated id remains (reuse the script from step 3 — the deprecated set should now be empty).
Do not touch models that are merely referenced by env vars but still present in the router (e.g. TASK_MODEL, LLM_ROUTER_TOOLS_MODEL, LLM_ROUTER_MULTIMODAL_MODEL). If a deprecated id _is_ referenced by one of those env vars, stop and flag it to the user instead of silently removing it — that indicates a config that needs a replacement model, not just a pruned line.
10. Commit changes
In the commit message, mention how many models were added (and how many of those are reasoning-capable / get artifacts) and how many deprecated models were removed, so it's easy to review.
git add chart/env/prod.yaml chart/env/dev.yaml
git commit -m "feat: sync models from router (+N added, M reasoning-capable, K artifacts, -D removed)"
GLM-4.7 and GLM-4.7-FP8, or -Instruct and -Thinking, as independent ids — presence of one says nothing about the other. Trust the script's diff, not the family name.supportsArtifacts too.Qwen3-VL-*-Thinking) — judge by the same rules.Take huggingface/sync-models from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.