19 KiB
Workflow Scope Implementation Plan
Objective
Add a first-class Workflow scope next to the existing All, Input,
Output, and Custom scopes. The scope should let users browse, classify,
preview, load, save, and organize ComfyUI workflow JSON files with a card grid
similar to ComfyUI's official template browser.
Target UX:
Workflowtab in the Majoor panel.- Workflow cards with static or animated thumbnails.
- Filters for task/category (
T2I,I2I,I2V,T2V,Image Edit, etc.), model family (Qwen,Seedance,Flux,Wan, etc.), provider, local/API runtime, required custom nodes, and missing models. - Sort modes similar to templates: default, recent, name, model, task, usage.
- Actions: load workflow into ComfyUI, save current workflow, duplicate, rename, move/category assign, delete with write guard, open in folder, inspect nodes, and optionally add thumbnail.
Official ComfyUI Alignment Notes
Sources consulted before planning:
- ComfyUI server routes and comms docs: https://docs.comfy.org/development/comfyui-server/comms_overview
- ComfyUI routes docs: https://docs.comfy.org/development/comfyui-server/comms_routes
- ComfyUI built-in template docs: https://docs.comfy.org/interface/features/template
- Custom-node workflow template docs: https://docs.comfy.org/custom-nodes/workflow_templates
- Official workflow templates repository: https://github.com/Comfy-Org/workflow_templates
Important constraints from those sources:
- ComfyUI server routes are based on
PromptServer.instance.routesandaiohttp; Majoor routes must keep using that pattern. - ComfyUI already exposes workflow/template/user-data routes, including
/workflow_templates,/userdata,/v2/userdata,/prompt,/history,/object_info, and/models. - ComfyUI custom-node examples are expected under
example_workflowsor compatible folder names, JSON only, with optional same-name JPG thumbnails. - Core template browsing is for official/custom-node examples. Majoor's Workflow scope should manage the user's saved workflow library, not override the core template browser.
- Frontend host access must stay behind bridge modules such as
ui/app/comfyApiBridge.tsorui/app/hostAdapter.ts.
Current Repository Audit
Existing Scope Flow
Current grid scopes are wired through:
ui/features/panel/views/tabsView.tsui/features/panel/controllers/scopeController.tsui/features/panel/controllers/gridController.tsui/api/endpoints.tsmjr_am_backend/routes/search/listing_endpoint.pymjr_am_backend/routes/search/listing_scopes.py
The accepted frontend scopes are currently:
allinputoutput/outputscustomsimilar
The backend listing route rejects unknown scopes, so workflow needs explicit
support on both sides.
Existing Data Model
Current persistence is media-asset oriented:
assets.source:output,input,customassets.kind: currently classifies file media types like image/video/audio/3Dasset_metadata: stores workflow/generation data extracted from mediaassets.workflow_id,asset_metadata.workflow_hash,asset_metadata.workflow_type,asset_metadata.has_workflowalready support workflow metadata attached to generated files
This is not enough for saved workflow files as browsable entities. A saved workflow is not just metadata on an image; it needs its own library row, thumbnail relation, categories, required nodes/models, and load/save actions.
Existing UI Card Flow
Cards are rendered through:
ui/vue/components/grid/AssetCardInner.vueui/features/grid/AssetCardRenderer.tsui/vue/components/grid/AssetsGrid.vueui/vue/components/grid/VirtualAssetGridHost.vue
The current card assumes media-ish assets and computes thumbnail URLs with
buildAssetViewURL(). Workflow cards need a separate preview contract, because
JSON cannot be served through /view and may use:
- explicit thumbnail image
- animated thumbnail/video/webp preview
- first matching generated output linked by
workflow_id - generated graph-map screenshot fallback
- icon fallback when no thumbnail exists
Existing Backend Architecture
The repo architecture says:
- routes parse HTTP and call services
- features own business logic
- adapters isolate DB/filesystem/ComfyUI boundaries
- write/delete operations must use shared security and audit helpers
Workflow scope should follow that shape:
routes/handlers/workflows.pyfeatures/workflows/service.pyfeatures/workflows/indexer.pyfeatures/workflows/classifier.pyfeatures/workflows/models.pyadapters/comfy_user_data.pyor equivalent bridge for ComfyUI user data APIs- optional DB migration under
adapters/db/migrations
Recommended Design
Storage Strategy
Use a dedicated workflow-library domain instead of forcing workflow JSON rows
into the current media assets table.
Recommended tables:
-
workflowsidworkflow_idnamedescriptionfilepathsourcecategorytaskmodel_familyproviderruns_onthumbnail_pathanimated_thumbnail_pathworkflow_hashnode_countlink_countsubgraph_countrequired_nodes_jsonrequired_models_jsonmissing_nodes_jsonmissing_models_jsontags_jsonfavoriteusage_countlast_loaded_atmtimesizecreated_atupdated_at
-
workflow_categories(optional cache/index only; folder tree remains source of truth)idnameslugsort_order
-
optional
workflow_assets- links generated media assets to a workflow row by
workflow_idorworkflow_hash
- links generated media assets to a workflow row by
Reasoning:
- Avoids breaking code that assumes
assets.kindis media. - Keeps workflow-specific filters cheap and explicit.
- Allows thumbnails and model requirements without overloading
asset_metadata.metadata_raw. - Still allows a compatibility response shaped like grid assets.
Workflow Library Roots
Support these roots in priority order:
- ComfyUI user workflows via
/userdata//v2/userdatawhen available. - Local ComfyUI user folder fallback, usually
ComfyUI/user/<user>/workflows. - Custom-node
example_workflowsas read-only entries under a separate category in Workflow scope.
Do not write into arbitrary paths unless the existing write-access, CSRF, and path guard stack allows it.
API Surface
Add Majoor routes under /mjr/am/workflows/*:
GET /mjr/am/workflows- list workflows with filters, sorting, paging
GET /mjr/am/workflows/{id}- workflow detail, parsed metadata, nodes, model requirements
GET /mjr/am/workflows/{id}/content- safe JSON content fetch for load/inspect
POST /mjr/am/workflows/save-current- save a posted frontend workflow JSON into the workflow library
POST /mjr/am/workflows/import- import uploaded or referenced workflow JSON
POST /mjr/am/workflows/{id}/renamePOST /mjr/am/workflows/{id}/categorizePOST /mjr/am/workflows/{id}/thumbnailPOST /mjr/am/workflows/{id}/duplicateDELETE /mjr/am/workflows/{id}
Also extend existing list route:
GET /mjr/am/list?scope=workflow- returns workflow-card shaped items for the current grid
Frontend Host Bridge
Add workflow host operations behind ui/app/comfyApiBridge.ts or
ui/app/hostAdapter.ts:
- read current graph/workflow safely
- serialize current workflow
- load workflow into ComfyUI using feature-detected public APIs first
- fetch ComfyUI
/workflow_templatesand/userdataonly throughfetchComfyApi() - check
/object_infoand/modelsfor missing requirements
Vue components must receive data/actions through props or stores. They should
not call window.app, globalThis.app, LiteGraph, canvas, or graph objects
directly.
Card UX Contract
Workflow card fields should be normalized before Vue rendering:
idkind: "workflow"filenamedisplay_namedescriptionthumbnail_urlanimated_thumbnail_urltaskmodel_familyproviderruns_onnode_countsubgraph_countmissing_nodes_countmissing_models_counttagsmtimefavoriteusage_count
Card behavior:
- show image thumbnail by default
- if animated preview exists, play on hover or respect existing video autoplay grid setting
- show task/model/provider chips
- show missing dependency warning chip
- primary click opens detail/preview, not destructive load
- explicit action button loads workflow into ComfyUI, preferring a new workflow tab when host API allows it
Classification Heuristics
Use a deterministic classifier first, then allow user overrides.
Task detection:
T2I: text/prompt nodes + image save nodes, no image/video input dependencyI2I: image loader/input nodes feeding sampler/edit/upscale pipelinesI2V: image input plus video-generation/video-combine nodesT2V: prompt plus video-generation/video-combine nodesVideo Edit: video loader plus video outputImage Edit: inpaint/control/edit/provider API nodesUpscale: upscaler/model upscale nodesAudio: audio loader/output/tts/music nodes3D: mesh/3D/model loader/export nodes
Model family detection:
- inspect node class names, widget values, model filenames, and loader nodes
- include known families such as
Qwen,Flux,Wan,Seedance,LTX,SDXL,SD1.5,Hunyuan,Kling,Veo,Grok, etc. - keep classifier rules data-driven so new model families can be added without rewriting UI code
Dependency detection:
- node classes from workflow JSON vs
/object_info - model filenames from loader widgets vs
/models/{folder}where feasible - provider/API nodes marked separately from local model requirements
Subgraph requirement:
- When parsing workflow JSON, include native subgraphs:
- root graph from
app.rootGraph,app.graph.rootGraph,app.graph, orapp.canvas.graph rootGraph.subgraphsnode.subgraphwhennode.isSubgraphNode?.()ornode.subgraphexists- serialized
workflow.definitions.subgraphs
- root graph from
- Qualify node IDs by graph/subgraph identity because IDs are not globally unique across subgraphs.
Implementation Checklist
Phase 0 - Discovery Spike
- Fetch and inspect current ComfyUI
/workflow_templatespayload shape. - Fetch and inspect current ComfyUI
/v2/userdata?dir=workflowsbehavior on stable and nightly builds. - Confirm frontend load workflow public API names in current
ComfyUI_frontend. - Confirm whether saved workflows live under
user/<user>/workflowsin the target install and whether multi-user mode changes that path. - Inventory local workflow JSON examples and thumbnail conventions.
- Decide whether custom-node
example_workflowsshould appear read-only in the Workflow tab or stay delegated to ComfyUI Templates.
Phase 1 - Backend Domain
- Add DB migration for workflow library tables and indexes.
- Add
features/workflows/models.pyfor normalized workflow records. - Add
features/workflows/parser.pyfor workflow JSON shape parsing, including subgraph traversal. - Add
features/workflows/classifier.pyfor task/model/provider/runs-on classification. - Add
features/workflows/service.pyfor list/detail/import/save/update. - Add path guards for workflow JSON and thumbnail files.
- Add write operations behind existing CSRF/write-access/security gates.
- Add audit logging for save/import/rename/categorize/thumbnail/delete.
- Add rate limits for list, import, save, and delete operations.
- Add thumbnail serving route with JSON/media content-type hardening.
Phase 2 - Backend Routes
- Add
routes/handlers/workflows.py. - Register workflow routes in
routes/route_catalog.py. - Extend
mjr_am_backend/routes/search/listing_endpoint.pyto acceptscope=workflow. - Add
listing_workflow_scope.pyor equivalent scoped handler. - Normalize workflow list results into grid-compatible card payloads.
- Add filters:
workflow_task,workflow_model,workflow_provider,runs_on. - Add filters:
missing,favorite,tag. - Add sort keys:
workflow_default,name,mtime_desc,task,model_family,usage_count,last_loaded_at. - Add tests for invalid paths, bad JSON, missing thumbnail, and remote write denial.
Phase 3 - Frontend API Client
- Add workflow endpoints to
ui/api/endpoints.ts. - Add typed client methods in
ui/api/client.tsor a workflow-specific API module. - Add
buildWorkflowThumbnailURL()and avoid using ComfyUI/viewfor JSON files. - Add frontend fetch tests for query construction and error mapping.
Phase 4 - Scope Integration
- Add
tab.workflowandtooltip.tab.workflowi18n entries. - Add Workflow button in
ui/features/panel/views/tabsView.ts. - Extend allowed scopes in
scopeController.ts. - Update
panelStateBridgetracked state for workflow filters. - Ensure
gridController.tswritesmjrScope=workflowand workflow filter datasets before reload. - Disable execution stack grouping for
workflowscope unless explicitly needed. - Update status/summary text for workflow counts.
- Add tests for scope switching and stale custom-root state reset.
Phase 5 - Workflow Cards
- Add a dedicated
WorkflowCardInner.vueor branch safely insideAssetCardInner.vuewhenkind === "workflow". - Render static thumbnail, animated preview, graph-map fallback, or icon fallback.
- Render task/model/provider/runs-on chips.
- Render dependency warning state.
- Add card action buttons: load, inspect, favorite, menu.
- Keep card dimensions stable with existing virtual grid constraints.
- Add Vue tests for cards with image thumbnail, animated thumbnail, missing dependency warning, and no-thumbnail fallback.
Phase 6 - Workflow Load And Save
- Add bridge method to serialize the current ComfyUI workflow.
- Add bridge method to load a workflow into ComfyUI using feature detection.
- Add "Save current workflow" action in the Workflow tab toolbar/menu.
- Add "Load workflow" card action with confirmation if current graph is dirty and ComfyUI exposes a reliable dirty-state signal.
- Increment usage stats and
last_loaded_atafter successful load. - Add fallback path: download/open JSON if host load API is unavailable.
- Add tests with mocked ComfyUI app/API surfaces.
Phase 7 - Filters And Organization
- Add task filter menu with common buckets (
T2I,I2I,I2V,T2V,Image Edit,Video Edit,Upscale,Audio,3D). - Add model-family filter menu, populated from indexed workflows.
- Add runs-on filter (
local,api,cloud,unknown). - Add category editor and category sidebar/list if needed.
- Add drag/drop or menu action to move workflow between categories.
- Add tag support if workflow library should share existing tag UI.
- Add search over name, description, tags, model family, node classes, and raw model filenames.
Phase 8 - Thumbnails
- Detect same-name thumbnail files next to workflow JSON.
- Allow user to select existing media asset as thumbnail.
- Allow first linked output by
workflow_id/workflow_hashas suggested thumbnail. - Add optional animated preview support (
webp,gif,mp4) with existing grid autoplay setting. - Add fallback graph-map screenshot generation only if it can be done without heavy server-side rendering.
- Harden thumbnail serving to image/video extensions only.
Phase 9 - Validation And QA
- Python tests for parser/classifier/subgraph traversal.
- Python tests for DB migration and workflow route security.
- Python tests for
/mjr/am/list?scope=workflow. - JS tests for tab/scope integration.
- Vue tests for workflow cards and filters.
- Bridge tests for save/load with stable and nightly ComfyUI API mocks.
- Run
python scripts/run_changed_quality_gate.py. - Run
npm run lint:js. - Run targeted
vitestfiles. - Run
npm run buildand updatedist/. - Manual test in ComfyUI stable.
- Manual test in ComfyUI nightly.
Risks And Mitigations
-
ComfyUI frontend API drift
- Mitigation: all host calls go through
comfyApiBridge.ts/hostAdapter.ts, with feature detection and fallback download/open modes.
- Mitigation: all host calls go through
-
Workflow file location differs by user mode
- Mitigation: prefer
/userdata//v2/userdata; filesystem fallback only when safely resolved.
- Mitigation: prefer
-
Saved workflow JSON schemas vary
- Mitigation: parser accepts root workflow, API prompt shape, frontend graph
shape, and
definitions.subgraphs; unknown fields are preserved.
- Mitigation: parser accepts root workflow, API prompt shape, frontend graph
shape, and
-
Media grid assumptions break on JSON rows
- Mitigation: use dedicated workflow tables and normalize to card payloads,
instead of storing JSON as regular media
assets.
- Mitigation: use dedicated workflow tables and normalize to card payloads,
instead of storing JSON as regular media
-
Dependency checks become slow
- Mitigation: cache
/object_infoand/modelssnapshots with TTL; classify on index, not on every card render.
- Mitigation: cache
-
Delete/move can damage user workflow libraries
- Mitigation: keep existing write guard, CSRF, path root checks, audit log, and confirmation UI.
Open Decisions
- Should custom-node
example_workflowsbe shown in the Workflow tab, or only in ComfyUI's native Templates browser? Decision: show them in Workflow scope under a separate read-only category. - Should Majoor create a dedicated workflow library folder, or only use
ComfyUI
user/<user>/workflows? Decision: use ComfyUIuser/<user>/workflowsas the workflow library root. - Should categories be stored as folders, DB metadata, or both? Decision: categories are folder-based (filesystem source of truth).
- Should workflow cards share current rating/tags/collections, or use workflow-specific favorites/categories first? Decision: use workflow-specific favorites/categories first.
Implementation note: workflow favorites are now persisted via
POST /mjr/am/workflows/favorite and reflected in workflow card state.
- Should "load workflow" replace the current graph immediately, open a new ComfyUI workflow tab if available, or ask every time? Decision: open a new ComfyUI workflow tab when available; otherwise fallback to current-canvas import with confirmation when dirty-state is detectable.
- Should thumbnails be manually assigned only, or generated from graph-map /
first linked output automatically?
Decision: default thumbnail source is latest linked output by
workflow_id, with optional manual assignment and optional graph-map generation fallback.
First Implementation Slice
Recommended first slice:
- Add read-only
scope=workflowlisting from a configured workflow directory. - Parse workflow JSON and classify task/model family locally.
- Add Workflow tab and workflow cards with static thumbnail fallback.
- Add load workflow action through a bridge with safe fallback.
- Add save-current/import/delete only after the read-only browser is stable.
This slice proves the UX and parser without introducing destructive operations or a large migration at the same time.