ComfyUI Node

Save Custom Metadata Rules

Save the scanner's output before your ruleset becomes a memory

By xxmjskxx·Created about a year ago·Updated about a month ago· 25
Save Custom Metadata Rules
    • status
    rules_json_string
    save_modeoverwrite
    backup_before_savetrue
    restore_backup_setnone
    replace_conflictsfalse
    rebuild_python_rulestrue
    limit_backup_sets20

    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 from Metadata Rule Scanner. The tooltip documents the schema: keep the top-level nodes and samplers keys, keep rule keys like field_name|fields|prefix|selector|validate|format, and don't rename metafield constants. status keys from the scanner are ignored, so don't panic if they look odd.
    • save_mode - overwrite replaces your existing user JSON wholesale; append_new only adds missing metafields and sampler roles. append_new is the one you want most days - it keeps your hand-tweaked rules intact while folding in the new stuff.
    • replace_conflicts - append_new mode 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. With limit_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 but none, every other input except rebuild_python_rules is ignored. That's the "oh no" button, and it works.
    • rebuild_python_rules (default True) - regenerates defs/ext/generated_user_rules.py from 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

    1. Metadata Rule ScannerSave Custom Metadata Rules (rules_json_string).
    2. Run once, read the status, tweak save_mode / replace_conflicts as needed.
    3. Confirm with Show generated_user_rules.py; hand-edit if you want (then use Save generated_user_rules.py to write edits back).
    4. 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.

    CategorySaveImageWithMetaDataUniversal/rules

    Inputs (7)

    NameTypeDefaultDescription
    rules_json_stringSTRINGPaste 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_modeoptCOMBOoverwriteoverwrite: replace existing user JSON with provided content (legacy). append_new: add only missing metafields / sampler roles.
    backup_before_saveoptBOOLEANtrueCreate a timestamped backup set before applying changes.
    restore_backup_setoptCOMBOnoneRestore a previous backup set. If not 'none', other inputs (except rebuild_python_rules) are ignored.
    replace_conflictsoptBOOLEANfalseappend_new mode only. If True, conflicting metafields / sampler roles are replaced by incoming definitions; otherwise they are kept and counted as skipped.
    rebuild_python_rulesoptBOOLEANtrueGenerate defs/ext/generated_user_rules.py reflecting the resulting JSON. Disable to only adjust JSON (faster when iterating).
    limit_backup_setsoptINT200–500Retention for timestamped backup sets. 0 = no pruning. After creating a new backup, oldest sets beyond this count are deleted.

    Outputs (1)

    NameTypeDescription
    statusSTRING