Metadata Rule Scanner
Point this at your node jungle and get capture rules back
- suggested_rules_json
- diff_report
The "universal" in this pack's name is doing a lot of work. The save node captures metadata by reading the input values of whatever nodes ran in your graph - but for a node it has never seen, what to read is a guess. The pack ships built-in heuristics for the usual suspects, but you've got 200 custom node packs installed, and half of them are obscure. That's where Metadata Rule Scanner comes in: it walks every node class ComfyUI has loaded, applies heuristics to figure out which inputs are prompts, seeds, models, LoRAs, samplers, and so on, and emits a JSON ruleset you can save and hand back to the save node.
It's the discovery half of the recommended first-run workflow: scan, save the rules, then use the save node with your custom capture ruleset. And the README is blunt that this isn't a one-and-done - you should re-run the scanner whenever you update the pack or install new nodes you want captured.
The inputs
exclude_keywords- a comma-separated blacklist of substrings matched against class names, defaulting to a long list (mask,find,resize,rotate,detailer,bus,...). This is how you keep the scanner from drowning in noise nodes it would never capture from. If the scanner "isn't finding" a node you care about, check whether it's in here first - the class name matching is case-insensitive substring.mode-new_only(only brand-new fields, plus all fields for brand-new nodes),all(full suggestions), orexisting_only(only nodes already in the baseline).new_onlyis the default because it keeps the diff small.include_existing- default False. When False you get the "missing-only lens": the scanner filters out metafields and sampler roles the baseline already captures, so you only see gaps. Flip it True to see everything merged.force_include_metafields- always suggest specific MetaField names (likeMODEL_HASH,LORA_MODEL_HASH) even when they're already captured.force_include_node_class- exact class names (comma or newline separated) that get included no matter what the keyword filter or mode says. This is the escape hatch when a node's class name collides with your exclude list. You can find the exact class name by exporting the workflow JSON and reading theclass_type, or via the node's type in the UI.
The outputs
suggested_rules_json- the JSON ruleset. This is what you feed intoSave Custom Metadata Rules.diff_report- a human-readable diff summary showing what's new vs. already captured, including aBaselineCache=hit:X|miss:Yline. Cache hits are cheap; the baseline is cached across scans using file mtimes, so iterate fast.
How to read the output
The scanner output is a suggestion, not gospel. The README says it plainly: treat it as a starting point, check the diff_report, and expect some nodes to need manual mapping of inputs to metadata fields. A forced node showing up as an empty {} isn't a bug - it means the scanner guarantees the class is present as an anchor even though no heuristic matched yet, so you can hand-write its rules. Wire diff_report into a Show Text (UniMeta) node and you can eyeball everything on canvas.
Wiring it up
The intended flow (there's a simple example workflow in the repo, plus an advanced one where you edit the JSON between scan and save):
Metadata Rule Scanner→Save Custom Metadata Rules(rules_json_string).- Run, check the status output, and confirm with
Show generated_user_rules.py. - Back in your normal workflow,
Save Image w/ Metadata Universalpicks the merged rules up automatically.
One gotcha that bites after updates: saved rules carry a RULES_VERSION matching the pack, and the save node logs a [Metadata Loader] warning if yours are stale or missing. That warning is the scanner's cue - re-run it, re-save, move on. It's annoying the first time, but it's exactly the right failure mode for "I added a node and the metadata went quiet."
Inputs (5)
| Name | Type | Default | Description |
|---|---|---|---|
| exclude_keywords | STRING | mask,find,resize,rotate,detailer,bus,scale,vision,text to,crop,xy,plot,controlnet,save,trainlora,postshot | Comma-separated keywords to exclude nodes whose class names contain any of them. |
| include_existingopt | BOOLEAN | false | Include existing metafields / sampler roles from baseline (defaults+ext+user). Set False for 'missing-only lens' (only fields/roles not yet captured). Mode interactions when include_existing=False (lens ON): new_only: unchanged (only new fields by definition) all: global missing-only filter existing_only: only baseline nodes, but only their missing fields |
| modeopt | COMBO | new_only | new_only: only new fields for existing nodes all: full suggestions existing_only: only nodes already captured. |
| force_include_metafieldsopt | STRING | Comma-separated MetaField names to always include even if already present (e.g. MODEL_HASH,LORA_MODEL_HASH). | |
| force_include_node_classopt | STRING | Exact node class names (comma or newline separated) always to include in scan output, even if excluded by keywords or mode. |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| suggested_rules_json | STRING | — |
| diff_report | STRING | — |