---
name: comfyui_export_skill_template
kind: function
lang: py
domain: ml
version: "1.0.0"
purity: impure
signature: "def export_skill_template(slug: str, *, ui_graph: bool = False, port: int = 9222, library_dir: str = '~/ComfyUI/skills_library', ui_workflows_dir: str = '~/ComfyUI/user/default/workflows', subject_placeholder: str = '{subject}', seed: int = 0, server_url_substr: str = '8188', timeout_s: float = 20.0) -> dict"
description: "Exporta una skill (receta comfyui-skill) a artefactos cargables como GRAFO en ComfyUI. Compila la receta con comfyui_build_skill_workflow (subject placeholder) y escribe el template en API format en exports/<slug>.template.json. Con ui_graph=True carga ese workflow en la UI del navegador via CDP (comfyui_load_workflow_ui -> litegraph auto-posiciona), extrae el UI graph serializado (comfyui_export_workflow_ui api_format=False) y lo guarda en la carpeta nativa ~/ComfyUI/user/default/workflows/<slug>.json (aparece en el menu Workflows del navegador y se abre como grafo visual) + copia en exports/<slug>.ui.json. Si el navegador/CDP no esta disponible no falla: deja el template API y devuelve error explicando el fallback. Skill sin recipe.json -> ok False."
tags: [comfyui, comfyui-skill, ml, workflow, template, browser, cdp, stable-diffusion]
uses_functions:
  - comfyui_build_skill_workflow_py_ml
  - comfyui_load_workflow_ui_py_browser
  - comfyui_export_workflow_ui_py_browser
uses_types: []
returns: []
returns_optional: false
error_type: "error_go_core"
imports: []
params:
  - name: slug
    desc: "Slug de la skill: carpeta <library_dir>/<slug>/ que contiene recipe.json."
  - name: ui_graph
    desc: "Si True, ademas del template API carga el workflow en la UI de ComfyUI via CDP, extrae el UI graph posicionado (app.graph.serialize) y lo guarda en la carpeta nativa de la UI (cargable desde el menu Workflows del navegador). Requiere una pestana de ComfyUI abierta. Default False."
  - name: port
    desc: "Puerto de remote debugging del Chrome diario (solo si ui_graph=True). Default 9222."
  - name: library_dir
    desc: "Raiz de la libreria de skills. Default ~/ComfyUI/skills_library."
  - name: ui_workflows_dir
    desc: "Carpeta nativa de workflows de la UI de ComfyUI. Default ~/ComfyUI/user/default/workflows."
  - name: subject_placeholder
    desc: "Texto que sustituye {subject} en el scaffold del prompt del template. Default '{subject}' (literal, editable por el usuario)."
  - name: seed
    desc: "Semilla fijada en el template. Default 0."
  - name: server_url_substr
    desc: "Substring de la URL de la pestana de ComfyUI para identificarla entre las abiertas. Default '8188'."
  - name: timeout_s
    desc: "Timeout de la conexion CDP en segundos. Default 20.0."
output: "dict {ok, template_path, ui_workflow_path, error}. Campo extra ui_export_path (copia del UI graph en exports/). ok True si el template API se escribio; con ui_graph=True y CDP no disponible ok sigue True (template escrito), ui_workflow_path None y error explica el fallback. Skill sin recipe.json -> ok False."
tested: true
tests: ["golden: skill txt2img+facedetailer (sin ui_graph) -> ok True, template.json escrito con API format valido (class_type/inputs) y subject placeholder presente", "edge: respeta export_template_path de la receta", "error: slug inexistente (sin recipe.json) -> ok False", "error: receta con base_workflow desconocido -> ok False"]
test_file_path: "python/functions/ml/tests/test_comfyui_export_skill_template.py"
file_path: "python/functions/ml/comfyui_export_skill_template.py"
---

## Ejemplo

```python
import sys, os
sys.path.insert(0, os.path.join(os.environ["HOME"], "fn_registry", "python", "functions"))
from ml.comfyui_export_skill_template import export_skill_template

# Solo template API (sin navegador): rápido, headless.
out = export_skill_template("portrait_cinematic_sd15")
print(out["ok"], out["template_path"])
# -> True  ~/ComfyUI/skills_library/portrait_cinematic_sd15/exports/portrait_cinematic_sd15.template.json

# Template + GRAFO cargable en el navegador (requiere pestaña ComfyUI abierta en CDP 9222):
out = export_skill_template("portrait_cinematic_sd15", ui_graph=True, port=9222)
print(out["ui_workflow_path"])
# -> ~/ComfyUI/user/default/workflows/portrait_cinematic_sd15.json  (aparece en el menú Workflows)
```

Lanzable directo: `./fn run comfyui_export_skill_template portrait_cinematic_sd15 --ui-graph`

## Cuando usarla

- Cuando quieras **congelar una skill como grafo reproducible**: tras afinar una receta del grupo
  `comfyui-skill`, exportarla a un node-template (API format) versionable junto a la skill.
- Cuando quieras **ver/editar la skill como GRAFO visual** en el navegador: con `ui_graph=True`
  el workflow aparece en el menú Workflows de ComfyUI y se abre como grafo posicionado, listo
  para retocar a mano antes de generar.
- Es el paso "receta → grafo cargable" del flujo del grupo `comfyui-skill`:
  `load_skill` → `build_skill_workflow` → **`export_skill_template`** → abrir en la UI.

## Gotchas

- **`ui_graph=True` necesita el navegador**: una pestaña de ComfyUI abierta en el Chrome diario
  con CDP en el puerto `port` (9222). Sin ella, la función NO falla — escribe el template API y
  devuelve `error` con el fallback (arrastrar el `.json` a la UI o usar `comfyui_load_workflow_ui`).
- **La carpeta nativa de la UI solo acepta UI graph format** (`nodes`/`links`/`pos`), no API
  format. Por eso la copia a `~/ComfyUI/user/default/workflows/<slug>.json` solo ocurre con
  `ui_graph=True` (el UI graph se genera vía CDP). El template API de `exports/` se carga con
  `app.loadApiJson` / `comfyui_load_workflow_ui`, no desde el menú Workflows.
- **Reemplaza el grafo in-memory de la pestaña**: `ui_graph=True` carga el workflow sobre el grafo
  actual de la UI. Si hay trabajo sin guardar en esa pestaña (título con `*`), haz backup antes
  con `comfyui_export_workflow_ui(api_format=True, save_path=...)`.
- **No valida modelos**: hereda de `comfyui_build_skill_workflow` — no comprueba que el
  checkpoint/LoRA existan en el servidor; eso lo valida ComfyUI al enviar el grafo.
- **Bases solo de texto**: `base_workflow` ∈ {txt2img, flux, sdxl_refiner}. Las bases con imagen
  de entrada lanzan error en el build → `ok` False.
