{ "$schema": "http://json-schema.org/draft-07/schema#", "$id": "https://dsh.local/schemas/workflow-manifest.schema.json", "title": "Workflow Manifest", "description": "一份「工作流绑定契约」:把一个抽象 capability 绑定到一条具体 ComfyUI 工作流(数据,非代码)。", "type": "object", "required": [ "id", "version", "capability", "graph", "params" ], "additionalProperties": true, "properties": { "id": { "type": "string", "pattern": "^[a-z0-9][a-z0-9._-]*$" }, "version": { "type": "integer", "minimum": 1 }, "capability": { "type": "string", "enum": [ "image.text2image", "image.image2image", "video.text2video", "video.image2video", "video.reference2video", "audio.tts", "audio.music" ] }, "runner": { "type": "string", "enum": [ "comfyui" ], "default": "comfyui" }, "displayName": { "type": "string" }, "description": { "type": "string" }, "modelNode": { "type": "string", "description": "基础模型输出节点 id($model 哨兵的来源;缺省 '1')" }, "output": { "type": "object", "properties": { "mediaType": { "type": "string", "enum": [ "image", "video", "audio" ] }, "hasAudio": { "type": "boolean" } } }, "assets": { "type": "object", "additionalProperties": { "type": "object", "required": [ "default" ], "properties": { "kind": { "type": "string", "enum": [ "checkpoint", "clip", "vae", "lora", "other" ] }, "default": { "type": "string" }, "env": { "type": "string", "description": "可覆盖文件名的环境变量名" }, "label": { "type": "string" } } } }, "graph": { "type": "object", "description": "ComfyUI API 格式图模板 {nodeId: {class_type, inputs}}。可变字段留 null,由 params 注入;模型资产用 \"$assets.\";模型连线用 [\"$model\", 0]。", "additionalProperties": { "type": "object", "required": [ "class_type" ], "properties": { "class_type": { "type": "string" }, "inputs": { "type": "object", "additionalProperties": true } } } }, "params": { "type": "object", "description": "注入点:任务输入 → 图字段。", "additionalProperties": { "oneOf": [ { "type": "object", "required": [ "inject", "to" ], "properties": { "inject": { "type": "string", "const": "scalar" }, "to": { "$ref": "#/definitions/targets" }, "default": {} } }, { "type": "object", "required": [ "inject", "via", "to" ], "properties": { "inject": { "type": "string", "const": "image" }, "via": { "type": "string", "enum": [ "field", "node" ] }, "to": { "$ref": "#/definitions/target" }, "node": { "type": "string", "description": "via=node 时的 LoadImage 类节点类名,默认 LoadImage" }, "preprocess": { "type": "array", "items": { "type": "object", "required": [ "class_type" ], "properties": { "class_type": { "type": "string" }, "inputs": { "type": "object", "additionalProperties": true }, "imageInput": { "type": "string", "description": "接收上一节点输出连线的输入字段,默认 image" } } } }, "max": { "type": "integer", "minimum": 1 } } } ] } }, "priority": { "type": "number", "description": "同能力候选的确定性排序权重(降序,缺省 0;相同则按 id 升序)。该顺序决定 preferred 为空时的隐式默认档:写负数可让清单永不被选为默认(适合实验性、依赖自定义节点或成本高出一个量级的加速变体)。" }, "tier": { "type": "string", "enum": [ "fast", "balanced", "quality" ], "description": "档位(受控枚举,锁定三档)。一个清单只服务一个档位;声明了才参与档位解析。契约见 docs/tier-strategy-design.md。" }, "group": { "type": "string", "description": "组名(唯一的分组依据,不从文件名猜):同 group 的清单聚合成一组,配置页显示为「displayName(档位列表)」。缺省以自身 id 成组。" }, "accel": { "type": "string", "description": "加速实现标注(如 sol),仅用于 UI 标注与「有加速/无加速」策略投影,不参与档位解析。" }, "requiresNodes": { "type": "array", "items": { "type": "string" }, "description": "该实现必需的 ComfyUI 节点 class_type(预检依据)。缺失 → 显式不可用并报错,本插件不会静默替换用户选定的实现。" }, "estSeconds": { "type": "number", "exclusiveMinimum": 0, "description": "实测耗时(秒),口径:16:9 · 124 帧 · 该档长边。内置清单由生成器从 benchmark 数据填入;用户上传留空 → UI 显示「耗时未知」。" }, "note": { "type": "string", "description": "UI 上给用户看的一行事实(如「Sol-Attn 加速 · 1344×768 实测 1.27× · 480p 无收益」)。" }, "internal": { "type": "boolean", "description": "诊断/调试清单:true 时永不参与档位解析,也不出现在 UI 与技能选项里(只能显式 workflow= 调用)。" }, "modes": { "type": "object", "additionalProperties": { "type": "object", "properties": { "steps": { "type": "integer", "minimum": 1 }, "longSide": { "type": "integer" }, "loras": { "type": "array", "items": { "type": "object", "required": [ "asset" ], "properties": { "asset": { "type": "string", "description": "assets 里的 key(lora 资产)" }, "strength": { "type": "number", "default": 1.0 } } } } } } }, "resolution": { "type": "object", "properties": { "policy": { "type": "string", "enum": [ "explicit", "aspect-ratio" ] }, "snap": { "type": "integer", "minimum": 1 }, "default": { "oneOf": [ { "type": "array", "items": { "type": "integer" }, "minItems": 2, "maxItems": 2 }, { "type": "object", "additionalProperties": { "type": "array", "items": { "type": "integer" }, "minItems": 2, "maxItems": 2 } } ] } } }, "constraints": { "type": "object", "properties": { "aspectRatios": { "type": "array", "items": { "type": "string" } }, "maxDurationFrames": { "type": "integer", "minimum": 1 }, "supportsSubtitles": { "type": "boolean" } } }, "chain": { "type": "object", "description": "链式续接声明:本实现消费「上一镜」的产物(服务端 latent)以延续画面与音频,专用于同场景续接镜。不声明=不参与链式续接。契约见 docs/shot-chain-continuity.md。", "properties": { "source": { "enum": [ "clip-latent" ], "description": "上一镜的来源形态:clip-latent = 上一镜渲染时落盘的服务端 latent(画质无损、无需上传)" }, "sampleExtra": { "type": "integer", "minimum": 0, "description": "为继承而多采的帧数:请求 N 帧 → 实际按 N+sampleExtra 采样,交付前裁掉(起链时不加)" }, "lengthGrid": { "type": "array", "items": { "type": "integer" }, "minItems": 2, "maxItems": 2, "description": "[步长, 偏移]:模型合法的采样帧数(如 17k+5)" }, "indexParam": { "type": "string", "description": "载入序号注入的参数名(默认 context_clip_index)" }, "saveIndexParam": { "type": "string", "description": "落盘序号注入的参数名(默认 save_clip_index)" } }, "required": [ "source", "sampleExtra" ] } }, "definitions": { "target": { "type": "object", "required": [ "node", "field" ], "properties": { "node": { "type": "string" }, "field": { "type": "string", "description": "字段名;支持 ${i} 索引占位与 dotted 字段(如 ref_images.ref_image_${i})" } } }, "targets": { "oneOf": [ { "$ref": "#/definitions/target" }, { "type": "array", "items": { "$ref": "#/definitions/target" }, "minItems": 1 } ] } } }