6.6 KiB
ComfyUI Workflow Format — Agent Guide
Guide for receiving a ComfyUI workflow file (e.g. via Telegram attachment), understanding it, adding the required metadata, and saving it as an image generation provider.
JSON API Format Structure
When exporting a workflow from ComfyUI with "Save (API Format)", the result is a JSON where every numeric key is a pipeline node:
{
"3": { "class_type": "KSampler", "inputs": { "steps": 20, "cfg": 7, "seed": 42, ... } },
"4": { "class_type": "CheckpointLoaderSimple", "inputs": { "ckpt_name": "v1-5-pruned.safetensors" } },
"6": { "class_type": "CLIPTextEncode", "inputs": { "text": "", "clip": ["4", 1] } },
"7": { "class_type": "CLIPTextEncode", "inputs": { "text": "", "clip": ["4", 1] } },
"8": { "class_type": "EmptyLatentImage", "inputs": { "width": 512, "height": 512, "batch_size": 1 } },
"9": { "class_type": "SaveImage", "inputs": { "filename_prefix": "ComfyUI", "images": ["10", 0] } },
"10": { "class_type": "VAEDecode", "inputs": { "samples": ["3", 0], "vae": ["4", 2] } }
}
Key rules:
- Numeric keys are node IDs. They need not be consecutive.
- Non-numeric keys (e.g.
_personal_agent) are ignored by ComfyUI and used only by the plugin. - Array values in
inputs(e.g.["4", 1]) are links to other nodes:[node_id, output_slot].
Relevant Nodes
class_type |
Field to modify | Description |
|---|---|---|
CLIPTextEncode |
inputs.text |
Text prompt (positive or negative) |
CLIPTextEncodeSD3 |
inputs.clip_l, inputs.clip_g, inputs.t5xxl |
SD3.5 text prompt — all three fields must be populated |
KSampler |
inputs.steps |
Number of diffusion steps |
KSampler |
inputs.cfg |
CFG scale (creativity vs. prompt adherence) |
KSampler |
inputs.seed |
Seed for reproducibility |
EmptyLatentImage |
inputs.width |
Image width in pixels |
EmptyLatentImage |
inputs.height |
Image height in pixels |
CheckpointLoaderSimple |
inputs.ckpt_name |
SD model name to use |
LoraLoader |
inputs.lora_name |
LoRA to apply |
SaveImage |
inputs.filename_prefix |
Output filename prefix |
The _personal_agent Block
Add this as a non-numeric key to the JSON to configure the provider.
Full Schema
"_personal_agent": {
"name": "Workflow Name",
"description": "Description for the agent: style, format, ideal use cases.",
"prompt_node": "6",
"negative_prompt_node": "7",
"prompt_field": "clip_l",
"prompt_field_extra": ["clip_g", "t5xxl"],
"negative_prompt_field": "clip_l",
"negative_prompt_field_extra": ["clip_g", "t5xxl"],
"extra_params": {
"width_node": "8",
"height_node": "8",
"steps_node": "3"
}
}
| Field | Required | Notes |
|---|---|---|
name |
✓ | Name shown in the provider listing |
description |
— | Free text for the agent: style, default dimensions, use cases |
prompt_node |
✓ | ID of the node for the positive prompt (CLIPTextEncode or CLIPTextEncodeSD3) |
negative_prompt_node |
— | ID of the node for the negative prompt |
prompt_field |
— | Input field to inject the prompt into. Default: "text". For SD3.5: "clip_l" |
prompt_field_extra |
— | Additional input fields to copy the prompt into. For SD3.5: ["clip_g", "t5xxl"] |
negative_prompt_field |
— | Input field for the negative prompt. Default: "text" |
negative_prompt_field_extra |
— | Additional input fields for the negative prompt |
extra_params.width_node |
— | ID of the node with inputs.width (usually EmptyLatentImage) |
extra_params.height_node |
— | ID of the node with inputs.height |
extra_params.steps_node |
— | ID of the node with inputs.steps (usually KSampler) |
If prompt_node is omitted, the plugin heuristically picks the first
CLIPTextEncode or CLIPTextEncodeSD3 node found (ascending numeric ID order).
Identifying the Correct Nodes
To find the right node IDs by reading the JSON:
-
Positive prompt — find nodes with
"class_type": "CLIPTextEncode"or"CLIPTextEncodeSD3". There are usually two: one for the positive prompt (empty or descriptive text) and one for the negative. Conventionally the positive one has the lower ID. -
Dimensions — find
"class_type": "EmptyLatentImage". Readinputs.widthandinputs.heightto know the workflow's default dimensions. -
Steps — find
"class_type": "KSampler". Theinputs.stepsfield is the number of diffusion steps.
Example: reading defaults for extra_params_schema
Given the node:
"8": { "class_type": "EmptyLatentImage", "inputs": { "width": 768, "height": 1024 } }
The plugin will automatically generate:
"extra_params_schema": {
"properties": {
"width": { "type": "integer", "default": 768 },
"height": { "type": "integer", "default": 1024 }
}
}
Recommended Editing Workflow
-
Receive the file — Telegram attachment, web upload, or local path.
-
Read the JSON and identify:
- The
CLIPTextEncodenode for the positive prompt (lowest ID among those present). - The
CLIPTextEncodenode for the negative prompt (if present). - The
EmptyLatentImagenode for dimensions. - The
KSamplernode for steps.
- The
-
Add
_personal_agentwith the discovered node IDs and a meaningful description. Example for a landscape 1024×512 workflow:"_personal_agent": { "name": "Landscape XL", "description": "Landscapes and horizontal scenes. Default 1024x512. Great for backgrounds and scenery.", "prompt_node": "6", "negative_prompt_node": "7", "extra_params": { "width_node": "8", "height_node": "8", "steps_node": "3" } } -
Save to
data/comfyui/workflows/<name>.json. The filename becomes the provider ID:landscape-xl.json→ providercomfyui-landscape-xl. -
The watcher detects the file within 5 s and registers the provider. Verifiable by calling
image_generate_providers_list.
Notes on Workflows Without _personal_agent
If the file does not contain a _personal_agent block, the plugin:
- Uses the filename as the provider name.
- Heuristically searches for the first
CLIPTextEncodeorCLIPTextEncodeSD3node for the prompt. - Registers the provider without
descriptionorextra_params_schema. - If no
CLIPTextEncodeorCLIPTextEncodeSD3node is found, skips the file with a warning.
Adding _personal_agent is always preferred to give the agent the context
needed to pick the right provider.