Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
9bc0d2f
feat(website): add SEO model pages infrastructure
christian-byrne May 4, 2026
8fe2dee
fix(website): address review comments on model pages PR
christian-byrne May 4, 2026
8db4e46
[automated] Apply ESLint and Oxfmt fixes
actions-user May 4, 2026
213870a
refactor(website): fix model pages architecture and design token viol…
christian-byrne May 4, 2026
a94c75c
[automated] Apply ESLint and Oxfmt fixes
actions-user May 4, 2026
d6704a9
refactor(website): fix model pages architecture and design token viol…
christian-byrne May 4, 2026
2143f82
fix(website): fix knip violations, invalid variant, and update SKILL.md
christian-byrne May 4, 2026
32a3161
[automated] Apply ESLint and Oxfmt fixes
actions-user May 4, 2026
a492d32
fix(website): remove unused type exports from models.ts
christian-byrne May 4, 2026
c38736c
revert(knip): revert website entry point expansion
christian-byrne May 4, 2026
c52e398
fix(discovery): read existing slugs from generated-models.json not mo…
christian-byrne May 4, 2026
7e11c5a
feat(website): add model thumbnails via hub API; overhaul discovery w…
christian-byrne May 4, 2026
5acb517
[automated] Apply ESLint and Oxfmt fixes
actions-user May 4, 2026
6c9947c
fix(models): link primary CTA to /workflows/model/{slug} on comfy.org
christian-byrne May 4, 2026
ef8ec75
fix(skill): lowercase description and heading body
christian-byrne May 4, 2026
4467e67
feat(models): auto-extract docsUrl from workflow_templates index; exp…
christian-byrne May 4, 2026
9832571
chore: merge main into glary/seo-model-pages
christian-byrne May 4, 2026
448953d
[automated] Apply ESLint and Oxfmt fixes
actions-user May 4, 2026
924374f
feat(models): add hubSlug for verified hub pages; expand FAQ copy
christian-byrne May 4, 2026
3ce00a8
feat(models): populate thumbnails from workflow_templates webp files
christian-byrne May 4, 2026
2a81c2b
[automated] Apply ESLint and Oxfmt fixes
actions-user May 4, 2026
037ae5a
feat(models): richer per-type copy, slug validation, SKILL.md docs up…
christian-byrne May 4, 2026
b0986f1
[automated] Apply ESLint and Oxfmt fixes
actions-user May 4, 2026
5feefc7
feat(models): fallback CTAs when no hub model page exists
christian-byrne May 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
223 changes: 223 additions & 0 deletions .claude/skills/add-model-page/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
---
name: add-model-page
description: 'Add, update, or remove a model page entry in ComfyUI_frontend. Triggered by Glary-Bot Slack commands. Creates a PR to Comfy-Org/ComfyUI_frontend with the change and posts a Vercel preview link back to Slack.'
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
description: 'Add, update, or remove a model page entry in ComfyUI_frontend. Triggered by Glary-Bot Slack commands. Creates a PR to Comfy-Org/ComfyUI_frontend with the change and posts a Vercel preview link back to Slack.'
description: 'Add, update, or remove a model page entry on the comfy org website. Creates a PR to Comfy-Org/ComfyUI_frontend apps/website folder with the change and posts a Vercel preview link back to Slack.'

---

# add-model-page

Handle Glary-Bot Slack commands that add, update, or remove model pages in the ComfyUI website.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Handle Glary-Bot Slack commands that add, update, or remove model pages in the ComfyUI website.
add, update, or remove model pages in the ComfyUI website.


## Trigger phrases

- `@Glary-Bot Add a model page for <model-name>`
- `@Glary-Bot Update the model page for <model-name>`
- `@Glary-Bot Remove <model-name> from model pages`
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- `@Glary-Bot Add a model page for <model-name>`
- `@Glary-Bot Update the model page for <model-name>`
- `@Glary-Bot Remove <model-name> from model pages`
- `Add a model page for <model-name>`
- `Update the model page for <model-name>`
- `Remove <model-name> from model pages`


## Repos involved

- **comfy-router** (this repo): skill lives here, no code changes needed
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- **comfy-router** (this repo): skill lives here, no code changes needed

- **ComfyUI_frontend** (`Comfy-Org/ComfyUI_frontend`): all file edits happen here

Assume ComfyUI_frontend is checked out at a sibling path. Find it:

```bash
find ~ -maxdepth 5 -name "models.ts" -path "*/website/src/config/*" 2>/dev/null | head -1
```

Set `FRONTEND` to that repo root (parent four levels up from the found path).

Key files inside `$FRONTEND`:
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- **ComfyUI_frontend** (`Comfy-Org/ComfyUI_frontend`): all file edits happen here
Assume ComfyUI_frontend is checked out at a sibling path. Find it:
```bash
find ~ -maxdepth 5 -name "models.ts" -path "*/website/src/config/*" 2>/dev/null | head -1
```
Set `FRONTEND` to that repo root (parent four levels up from the found path).
Key files inside `$FRONTEND`:


| File | Purpose |
|------|---------|
| `apps/website/src/config/models.ts` | Model array |
| `apps/website/src/i18n/translations.ts` | i18n string map |
| `apps/website/scripts/generate-models.ts` | Derives model data from workflow templates |

---

## Phase 1 — Parse the request

Extract:
- **action**: `add` | `update` | `remove`
- **model-name**: raw string from Slack (e.g. `flux1-schnell`, `flux1_dev.safetensors`)

Normalize to a slug: lowercase, replace `_` and `.` with `-`, strip `.safetensors` suffix.
Example: `flux1_dev.safetensors` → `flux1-dev`

---

## Phase 2 — Gather model data (ADD / UPDATE)

Run the generator to find the model:

```bash
cd $FRONTEND
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
cd $FRONTEND
cd ComfyUI_frontend

pnpm tsx apps/website/scripts/generate-models.ts \
| jq '.[] | select(.name | ascii_downcase | contains("MODEL_NAME"))'
```

Replace `MODEL_NAME` with the normalized slug (use `-` as wildcard-friendly substring).

The output object contains:
- `name` — exact filename (e.g. `flux1_dev.safetensors`) or display name for partner nodes
- `url` — HuggingFace download URL → use as `huggingFaceUrl` (empty `''` for partner nodes)
- `directory` — model subdirectory (e.g. `diffusion_models`) or `partner_nodes` for API models
- `workflowCount` — integer
- `suggestedSlug` — use this as `slug` if reasonable
- `suggestedDisplayName` — use as seed for i18n `displayName`

If the generator returns no match and the model is a known API/partner model (e.g. Kling AI, Meshy AI, Nano Banana), add it manually as `directory: 'partner_nodes'` — no HuggingFace URL needed. Otherwise, tell the user the model was not found and stop.

---

## Phase 3 — Check for existing entry

```bash
grep -n "slug: '${SLUG}'" $FRONTEND/apps/website/src/config/models.ts
```
Comment thread
coderabbitai[bot] marked this conversation as resolved.

- Match found + action is `add` → switch to UPDATE flow automatically; inform the user
- No match + action is `update` → stop and tell the user

---

## Phase 4A — ADD: insert new entry

### 4A.1 Build the entry

```typescript
{
slug: 'MODEL-SLUG',
name: 'model_name.safetensors', // or display name for partner nodes
displayName: 'models.MODEL-SLUG.displayName' as TranslationKey,
description: 'models.MODEL-SLUG.description' as TranslationKey,
directory: 'diffusion_models', // from generate-models; or 'partner_nodes' for API models
huggingFaceUrl: 'https://huggingface.co/...', // from generate-models; use '' for partner nodes
docsUrl: 'https://docs.comfy.org/...', // optional: tutorial link on docs.comfy.org
blogUrl: 'https://blog.comfy.org/...', // optional: blog post link
ogImage: '/images/models/MODEL-SLUG-og.png',
thumbnail: '/images/models/MODEL-SLUG-thumb.webp',
featured: true,
workflowCount: N, // from generate-models output
tags: ['tag1', 'tag2'] as const, // derive from slug tokens
publishedDate: 'YYYY-MM-DD', // today
modifiedDate: 'YYYY-MM-DD', // today
}
```

Tags: split the slug on `-`, drop pure numeric tokens, keep meaningful words.

### 4A.2 Insert into models array

The array in `apps/website/src/config/models.ts` is sorted by `workflowCount` descending. Find the first entry whose `workflowCount` is less than the new entry's count and insert before it. If all are greater, append at the end.

### 4A.3 Add i18n keys

In `apps/website/src/i18n/translations.ts`, find the closing `}` of the `translations` object (the line before `} as const satisfies`). Insert before it:

```typescript
'models.MODEL-SLUG.displayName': {
en: 'Human Display Name',
'zh-CN': ''
},
'models.MODEL-SLUG.description': {
en: 'SEO description: one sentence explaining what this model does.',
'zh-CN': ''
},
```

Use `suggestedDisplayName` from generate-models for the English `displayName`. Write a concise one-sentence English `description` based on the model name and directory.

---

## Phase 4B — UPDATE: edit existing entry

Find the entry by slug. Apply only the fields the user explicitly requested changing. Update `modifiedDate` to today. Leave all other fields unchanged.

---

## Phase 4C — REMOVE: delete entry

1. Remove the entire object literal (including trailing comma) from the `models` array.
2. Remove the two translation keys (`displayName` and `description`) from `translations.ts`.
3. Note in the PR description why the model was removed (quote the Slack request).

---

## Phase 5 — Verify TypeScript

```bash
cd $FRONTEND
pnpm typecheck 2>&1 | grep -E "error|warning" | head -20
```

Fix any type errors before proceeding. Common issues:
- Missing `as TranslationKey` cast on `displayName`/`description`
- New translation key not yet present in `translations` when models.ts references it (add key first)

---

## Phase 6 — Create PR

```bash
cd $FRONTEND
BRANCH="glary/add-model-page-MODEL-SLUG" # or update- / remove-
git checkout -b $BRANCH
git add apps/website/src/config/models.ts apps/website/src/i18n/translations.ts
git commit -m "feat(models): add model page for MODEL-SLUG"
git push -u origin $BRANCH
gh pr create \
--title "Add model page: MODEL-SLUG" \
--body "$(cat <<'EOF'
Adds a new model page entry for MODEL-SLUG.

Triggered by Glary-Bot from Slack: "<paste original Slack message>"

## Changes
- `models.ts`: new entry with workflowCount N, directory DIRECTORY
- `translations.ts`: placeholder i18n keys (zh-CN needs translation)

## Images needed
- `/images/models/MODEL-SLUG-og.png` (1200×630)
- `/images/models/MODEL-SLUG-thumb.webp`

cc @design-team for images
EOF
)"
```

For UPDATE use branch `glary/update-model-page-MODEL-SLUG`. For REMOVE use `glary/remove-model-page-MODEL-SLUG` and remove the images note.

---

## Phase 7 — Post Vercel preview to Slack

After the PR is created, fetch the Vercel preview URL:

```bash
# Wait ~60s for Vercel bot to comment, then:
gh pr view $BRANCH --json comments \
--jq '.comments[].body | select(contains("vercel.app"))' | grep -o 'https://[^ )]*vercel.app[^ )]*' | head -1
```

Post back to the original Slack thread:

> PR created: <PR_URL>
> Preview: <VERCEL_PREVIEW_URL>/models/MODEL-SLUG
> Please review and approve. Once merged, the page will be live at comfy.org/models/MODEL-SLUG.
> Note: OG image and thumbnail still needed — tagged design team in the PR.

If the Vercel URL is not available within 2 minutes, post the PR URL alone and note the preview is pending.

---

## Error states

| Situation | Response |
|-----------|----------|
| Model not in workflow templates | "I couldn't find MODEL-NAME in the workflow templates. Check the spelling or ask an engineer to add it to `workflow_templates/templates/`." |
| Slug already exists (add) | Automatically switch to update flow; tell the user. |
| Slug not found (update/remove) | "There's no model page for MODEL-SLUG yet. Did you mean to add one?" |
| Typecheck fails | Fix the error, do not push a broken PR. |
| `generate-models.ts` errors | Share the error output in Slack and stop. |
142 changes: 142 additions & 0 deletions .github/workflows/model-page-discovery.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
name: Model Page Discovery

on:
schedule:
- cron: '0 9 * * 1' # Every Monday at 9am UTC
workflow_dispatch:

jobs:
discover:
runs-on: ubuntu-latest
permissions:
contents: read
issues: write

steps:
- name: Checkout ComfyUI_frontend
uses: actions/checkout@v4

Check failure on line 17 in .github/workflows/model-page-discovery.yml

View workflow job for this annotation

GitHub Actions / validate-pins

pinact error

uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
path: ComfyUI_frontend

- name: Checkout workflow_templates
uses: actions/checkout@v4

Check failure on line 22 in .github/workflows/model-page-discovery.yml

View workflow job for this annotation

GitHub Actions / validate-pins

pinact error

uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
repository: Comfy-Org/workflow_templates
path: workflow_templates

- name: Setup Node 20
uses: actions/setup-node@v4

Check failure on line 28 in .github/workflows/model-page-discovery.yml

View workflow job for this annotation

GitHub Actions / validate-pins

pinact error

uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: '20'

- name: Setup pnpm
uses: pnpm/action-setup@v4

Check failure on line 33 in .github/workflows/model-page-discovery.yml

View workflow job for this annotation

GitHub Actions / validate-pins

pinact error

uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4.3.0
with:
version: latest
run_install: false

- name: Get pnpm store directory
id: pnpm-cache
shell: bash
run: echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
working-directory: ComfyUI_frontend

- name: Cache pnpm store
uses: actions/cache@v4

Check failure on line 45 in .github/workflows/model-page-discovery.yml

View workflow job for this annotation

GitHub Actions / validate-pins

pinact error

uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('ComfyUI_frontend/**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-

- name: Install dependencies
run: pnpm install --frozen-lockfile
working-directory: ComfyUI_frontend

- name: Run model discovery script
run: pnpm tsx apps/website/scripts/generate-models.ts out.json
working-directory: ComfyUI_frontend
env:
WORKFLOW_TEMPLATES_PATH: ${{ github.workspace }}/workflow_templates

- name: Compare against existing models config
id: compare
shell: bash
run: |
set -euo pipefail
cd ComfyUI_frontend

# Extract slugs from the generated out.json
NEW_SLUGS=$(node -e "
const fs = require('fs');
const models = JSON.parse(fs.readFileSync('out.json', 'utf8'));
const arr = Array.isArray(models) ? models : Object.values(models);
const slugs = arr.map(m => m.slug).filter(Boolean);
console.log(JSON.stringify(slugs));
")

# Extract slugs from existing models.ts config
EXISTING_SLUGS=$(node -e "
const fs = require('fs');
const content = fs.readFileSync('apps/website/src/config/models.ts', 'utf8');
// Match slug: 'value' or slug: \"value\" patterns
const matches = [...content.matchAll(/slug\s*:\s*['\"]([^'\"]+)['\"]/g)];
const slugs = matches.map(m => m[1]);
console.log(JSON.stringify(slugs));
" 2>/dev/null || echo '[]')

# Find new slugs not in existing config
ADDED_SLUGS=$(node -e "
const newSlugs = $NEW_SLUGS;
const existing = $EXISTING_SLUGS;
const existingSet = new Set(existing);
const added = newSlugs.filter(s => !existingSet.has(s));
console.log(JSON.stringify(added));
")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Read the generated slug field here.

generate-models.ts serializes each entry as suggestedSlug, so m.slug is always undefined and this scan will never report new models.

Proposed fix
-            const slugs = arr.map(m => m.slug).filter(Boolean);
+            const slugs = arr.map(m => m.suggestedSlug ?? m.slug).filter(Boolean);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/model-page-discovery.yml around lines 69 - 95, The script
that builds NEW_SLUGS reads model objects' slug property (m.slug) but
generate-models.ts serializes each entry as suggestedSlug, so m.slug is
undefined; update the NEW_SLUGS node snippet to read the correct property
(suggestedSlug) instead of slug (or fall back to suggestedSlug when slug is
absent) so the extracted slugs reflect the generated out.json entries; modify
the map callback in the NEW_SLUGS extraction to use m.suggestedSlug (or
m.suggestedSlug || m.slug) and keep the rest of the JSON.stringify flow
unchanged.


COUNT=$(node -e "console.log($ADDED_SLUGS.length)")
echo "new_count=$COUNT" >> $GITHUB_OUTPUT
echo "new_slugs=$ADDED_SLUGS" >> $GITHUB_OUTPUT

if [ "$COUNT" -eq 0 ]; then
echo "No new models found."
else
echo "Found $COUNT new model(s): $ADDED_SLUGS"
fi

- name: Open GitHub issue for new models
if: steps.compare.outputs.new_count != '0'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NEW_SLUGS: ${{ steps.compare.outputs.new_slugs }}
NEW_COUNT: ${{ steps.compare.outputs.new_count }}
shell: bash
run: |
SLUG_LIST=$(node -e "
const slugs = $NEW_SLUGS;
console.log(slugs.map(s => '- \`' + s + '\`').join('\n'));
")

gh issue create \
--repo "$GITHUB_REPOSITORY" \
--title "New models detected — add to model pages" \
--body "## $NEW_COUNT new model(s) found in workflow_templates

The weekly model discovery scan found models present in \`workflow_templates\` that are not yet in \`apps/website/src/config/models.ts\`.

### New slugs ($NEW_COUNT)

$SLUG_LIST

### Next steps

1. Review which of these warrant an SEO model page
2. Run \`pnpm tsx apps/website/scripts/generate-models.ts\` locally for full details
3. Add entries to \`apps/website/src/config/models.ts\` via PR (or use Glary-Bot via Slack)

---
*Generated by the [model-page-discovery workflow](https://github.com/$GITHUB_REPOSITORY/actions/workflows/model-page-discovery.yml)*"

- name: No new models found
if: steps.compare.outputs.new_count == '0'
run: echo "No new models found — nothing to do."
Loading
Loading