Save Custom Metadata Rules
Save the scanner's output before your ruleset becomes a memory
- status
Metadata Rule Scanner generates the JSON that tells the save node what to capture. But a JSON blob sitting on a node output isn't a configuration - it's a suggestion until something writes it down. Save Custom Metadata Rules is the thing that writes it down: it takes the scanner's output, validates it, merges it into your user rules, and rebuilds the Python module the save node actually loads at runtime.
If you're coming from the one-click world of ComfyUI-Image-Saver, this two-step dance (scan, then save) feels like ceremony. It's the price of the "universal" approach: because the rules are generated dynamically per-install from your node list, somebody has to persist them. This node is that step, and it's designed to make the ceremony survivable.
The inputs
rules_json_string- paste the output fromMetadata Rule Scanner. The tooltip documents the schema: keep the top-levelnodesandsamplerskeys, keep rule keys likefield_name|fields|prefix|selector|validate|format, and don't rename metafield constants.statuskeys from the scanner are ignored, so don't panic if they look odd.save_mode-overwritereplaces your existing user JSON wholesale;append_newonly adds missing metafields and sampler roles.append_newis the one you want most days - it keeps your hand-tweaked rules intact while folding in the new stuff.replace_conflicts-append_newmode only. True means incoming definitions replace conflicting ones; False keeps the existing and counts them as skipped.backup_before_save(default True) - writes a timestamped backup set before touching anything. Withlimit_backup_sets(default 20, max 500) controlling how many backups are retained. This is the node's safety net, and it's genuinely good.restore_backup_set- a dropdown to roll back to a previous backup. When it's set to anything butnone, every other input exceptrebuild_python_rulesis ignored. That's the "oh no" button, and it works.rebuild_python_rules(default True) - regeneratesdefs/ext/generated_user_rules.pyfrom the merged JSON. Toggle it off when you're iterating fast and only want the JSON adjusted.
What it does under the hood
On save, the node merges your JSON with the built-in defaults and extension rules, validates it, and writes the deterministic generated_user_rules.py that embeds a RULES_VERSION matching the installed pack. That version stamp is what lets the save node warn you when your rules are stale after a pack update - you'll see a [Metadata Loader] warning and know it's time to re-scan and re-save. The generated module is what actually runs, so after a successful save your rules are live for every future save.
The single status string output tells you what happened - how many rules added, skipped, conflicts, backups created. It's an output node, so it runs at the end of the chain; wire it to a Show Text (UniMeta) if you want it on canvas.
The workflow, end to end
Metadata Rule Scanner→Save Custom Metadata Rules(rules_json_string).- Run once, read the status, tweak
save_mode/replace_conflictsas needed. - Confirm with
Show generated_user_rules.py; hand-edit if you want (then useSave generated_user_rules.pyto write edits back). - Re-run the pair after every pack update or new node install.
The one trap worth naming: overwrite mode will happily replace a ruleset you spent an afternoon hand-tuning with whatever the scanner just emitted. If you've customized, use append_new and keep backup_before_save on. The scanner is smart, but it doesn't know about the one weird input you mapped by hand.
Inputs (7)
| Name | Type | Default | Description |
|---|---|---|---|
| rules_json_string | STRING | Paste JSON from 'Metadata Rule Scanner'. Keep top-level keys: 'nodes' and 'samplers'. Nodes: { 'NodeClass': { 'MetaFieldName': { rule... } } } Rule keys: field_name|fields|prefix|selector|validate|format (ignore 'status'). Samplers: { 'SamplerNode': { 'role': 'input_name' } }. Don't rename metafield constants. | |
| save_modeopt | COMBO | overwrite | overwrite: replace existing user JSON with provided content (legacy). append_new: add only missing metafields / sampler roles. |
| backup_before_saveopt | BOOLEAN | true | Create a timestamped backup set before applying changes. |
| restore_backup_setopt | COMBO | none | Restore a previous backup set. If not 'none', other inputs (except rebuild_python_rules) are ignored. |
| replace_conflictsopt | BOOLEAN | false | append_new mode only. If True, conflicting metafields / sampler roles are replaced by incoming definitions; otherwise they are kept and counted as skipped. |
| rebuild_python_rulesopt | BOOLEAN | true | Generate defs/ext/generated_user_rules.py reflecting the resulting JSON. Disable to only adjust JSON (faster when iterating). |
| limit_backup_setsopt | INT | 200–500 | Retention for timestamped backup sets. 0 = no pruning. After creating a new backup, oldest sets beyond this count are deleted. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| status | STRING | — |