Workflow Discriminator
Reconstruct the exact prompt behind every image in a grid
- objs_0
- objs_1
- list_a
- list_b
- list_c
- list_d
- jsonpaths
Every ComfyUI image you save carries the whole workflow in its metadata - but here's the kicker: if you generated a grid, that metadata holds the workflow for the entire grid, not the individual image. So a month later, staring at grid cell (2, 4), you can't tell which prompt made it. Workflow Discriminator is the niche-but-neat answer: you feed it the workflows from several images that share one origin, and it diffs them to figure out which values actually varied, returning those differing values as output lists.
The mechanism is honest and straightforward: it treats the first object as a baseline, runs DeepDiff against every other one, and counts which JSON paths change most often across the set. The top-changing paths get promoted to output lists - list_a through list_d - and the paths themselves come out as the jsonpaths output. So if your 9-image grid varied subject, style, and seed, you get one list per varying value, plus the JSONPaths telling you where in the workflow each lived. ignore_jsonpaths lets you exclude paths (say, the ever-random seed) so you can chain discriminators and peel off one axis at a time.
The inputs
- objs_0 and more_objs - one or more workflow objects (or lists of them); they're concatenated. In practice you feed these from a metadata loader.
- ignore_jsonpaths - optional list of JSONPaths to skip.
The catch: images don't carry metadata in the tensor
This is the one thing that trips everyone up. ComfyUI's IMAGE tensor has no workflow metadata attached - you can't just connect the image output of a loader and hope. You must load images through a specialized image+metadata loader and connect its metadata here. The pack suggests:
- Load Any File.metadata → JSON OutputList with
jsonpath=$.["PNG:Prompt"]→ this node. - Crystools "Load image with metadata" → Metadata extractor.
- Simple_Readable_Metadata "Simple Readable Metadata-SG.metadata_raw".
Each of those gives you the JSON you need. This node is genuinely narrow - you only reach for it when you need provenance from saved grid images, or when you're building the "Baking Values Into Workflow" pattern that stores each cell's exact prompt back into metadata. It's the last 10% of the pack, but it's the piece that makes "which cell was this?" answerable.
Installing
Search "OutputLists Combiner" in ComfyUI Manager, or:
cd ComfyUI/custom_nodes
git clone https://github.com/geroldmeisinger/ComfyUI-outputlists-combiner
cd ComfyUI-outputlists-combiner
uv pip install -r requirements.txt
Restart after. It pulls in deepdiff and jsonpath_ng from the pack's requirements - no models, no binaries. If your lists come back empty, the usual cause is feeding it strings that aren't JSON: make sure the metadata loader actually produced workflow JSON before it hit this node.
Inputs (3)
| Name | Type | Default | Description |
|---|---|---|---|
| objs_0opt | * | (optional) A single object (or a list of objects), usually of a workflow. `objs_0` and `more_objs` will be concateneted together and exist for convinience, if you only want to compare two objects. | |
| objs_1opt | * | (optional) Another object (or a list of objects), usually of a workflow. `objs_0` and `more_objs` will be concateneted together and exist for convinience, if you only want to compare two objects. | |
| ignore_jsonpathsopt | STRING | (optional) A list of JSONPaths to ignore in case you want to chain multiple discriminators together. |
Outputs (5)
| Name | Type | Description |
|---|---|---|
| list_a | * | — |
| list_b | * | — |
| list_c | * | — |
| list_d | * | — |
| jsonpaths | STRING | — |