Extensions/comfy-ovum
ComfyUI Extension

comfy-ovum

An assorted reliquary of nodes: mismatched, stubborn, and deliberately indistinct; they do what is required; do not ask for particulars.

By sfinktah·Created 12 months ago·Updated 9 months ago· 6
sfinktah/comfy-ovum
Nodes309
On cloudLocal install
Categoryovum/loop, ovum/logic
Stars6
Updated9 months ago

Nodes (309)

Add Value to List (if boolean)

Conditionally append one value to a list, based on a boolean

ovum/loop
if AMD else if NVIDIA Ovum

One workflow that behaves differently on AMD and NVIDIA

ovum/logic
AssertOvum

Stop the workflow when a condition is wrong, then fail loudly

Logic
Batch Extend Ovum

Join two lists into one, without mutating either

ovum/lists/comfy
Batch Slice Ovum

Take a chunk out of a list, JavaScript-style

ovum/lists/comfy
Batch Splice Ovum

Cut items out of a list and insert new ones in the same move

ovum/lists/comfy
Big Knob

A big friendly dial for driving a numeric parameter

Widget
Burn Notice

Text that erases itself after it's been read

ovum/util
Cast Any To List

Tell ComfyUI 'this is a list now' and stop fighting the type system

ovum/data
Cast List To Any

Make a list connectable to anything, so it can reach a scalar input

Data
Combo Mirror Ovum

One dropdown to drive a dozen matching dropdowns

ovum
Compare Ovum

A boring, reliable 'is this bigger than that?' node for your branches

ovum/loop
Concat Batches Ovum

Wrap scalars into lists, never crash

ovum/lists/comfy
Concat Lists

JavaScript-style array concat, straight from the pack's list toolbox

ovum/lists/any
Concat Lists Ovum

Join two lists without the mutation headache

ovum/lists/python
Convert to Dict

Force any wired value into a Python dict

Conversion
Convert to List

Wrap anything into a Python list, mainly for loop nodes

Conversion
Convert to Set

Turn a wired value into a Python set

Conversion
Convert to Tuple

Build the tuple that loop nodes actually want

Conversion
Create Empty List

The seed every Ovum loop starts from

ovum/loop
Make/Create Tuple

Pack any two values into a Python tuple

ovum/loop
CUDNN Toggle Ovum

Toggle cuDNN around a single node

ovum
Folder Paths

Stop hard-coding ComfyUI's directories in your workflow

ovum/utils
Foreach List Begin Ovum

Loop over a list in ComfyUI without illegal graph cycles

ovum/loop
Foreach List End Ovum

The close bracket of ComfyUI's most misunderstood loop

ovum/loop
From Batch Type Node Ovum

Reshape a list into tuple, set, or dict

ovum/lists/comfy
From List Type Node

The deprecated converter you'll still hit in old workflows

ovum/lists/any
From List Type Node Ovum

The plain-Python list converter that isn't deprecated

ovum/lists/python
Get By Index

Pull any element out of a list or batch without the errors

ovum/lists/python
Get Environment Variable

Read machine settings from inside a workflow (without leaking secrets)

ovum
Get List Length

The safety check your list-handling workflows keep needing

ovum/loop
Get LocalStorage

The Ovum node the author himself tells you to avoid

ovum
Get Setting

Read ComfyUI's UI settings straight into your graph

ovum/utils
Get Value from List

Forgiving index lookup that returns None instead of crashing

ovum/loop
Ground Ovum (GND)

The sink node that forces your branches to actually run

ovum/util
Halt Toggle

A stop button for your workflow that can reset itself

ovum/control
If Else Ovum

The branch node that only evaluates the side you need

ovum/loop
IMAGE_EX Context (List)

Batch-edit image metadata without demuxing

ovum/image
IMAGE_EX Context

Override one field of an image record and keep the rest

ovum/image
Index Of

Find a value's spot in a list — but reach for the Ovum version instead

ovum/lists/any
Index Of Batch Ovum

IndexOf, the non-deprecated batch flavor — find where an item sits in a list

ovum/lists/comfy
Index Of Ovum

IndexOf Ovum — the Python-list flavor of 'where is this value in my list?'

ovum/lists/python
Return TRUE if a list is not empty

Return TRUE if a list is not empty — the tiny gate your loop was missing

ovum/loop
Join Batch Ovum

Join Batch Ovum — glue a list into one string, the Comfy-list way

ovum/lists/comfy
Join List

JoinList (Join List) – ComfyUI Node

ovum/lists/any
Join List Ovum

Join List Ovum — one string from a Python list, separator of your choosing

ovum/lists/python
List Extend

List Extend — glue two lists together (and don't use the deprecated one)

ovum/lists/any
List Extend Ovum

List Extend Ovum — merge two lists without mutating either

ovum/lists/python
List Keys

List Keys — pull the keys out of a dict (or indices out of a list)

ovum/loop
List Slice

Pull a contiguous chunk out of any ComfyUI list

ovum/lists/any
List Slice Ovum

List Slice Ovum — cut a sub-list out, JavaScript-style, without touching the original

ovum/lists/python
List Splice

List Splice — edit a list in place, delete-and-insert style (deprecated, mind)

ovum/lists/any
List Splice Ovum

List Splice Ovum — the maintained in-place list surgeon

ovum/lists/python
List Values

List Values — the sibling to List Keys that fetches a dict's values

ovum/loop
LiveCrop

LiveCrop — crop, expand, and rotate with interactive guides right in the node

ovum
LMStudio Prompt Chain Ovum

LM Studio Prompt Chain Ovum — keep the conversation going across nodes

Ovum/LLM
LMStudio Prompt Ovum

LM Studio Prompt Ovum — a local LLM in your ComfyUI graph, no API keys

Ovum/LLM
LMStudio Unload Ovum

LM Studio Unload Ovum — force the local model out of VRAM when you're done with it

Ovum/LLM
Load Image From Output Subdirectory With Workflow Ovum

Load From An Output Subdirectory With Workflow Ovum — grab a saved image from a subfolder, recipe included

ovum/image
Load Image From Output With Workflow Ovum

Load Image From Output With Workflow Ovum — bring a saved image back with its recipe

ovum/image
Load images list (regex/custom filter + callback)

Load images list (regex/custom filter + callback) — a batch image loader with an opinionated filter

ovum/image
Load Image With Workflow Ovum

Load an image and get its workflow back — metadata round-tripping made easy

ovum/image
Make Flat Image List

Flatten every flavor of image collection into one list Comfy can iterate

ovum/lists/python
Make Flat String List

Strings, numbers, and lists of both — flattened into one text list

ovum/lists/python
Map End Ovum

Where your map loop's results actually land — Map End Ovum

ovum/loop
Map Start Ovum

The loop node that also collects the results — Map Start Ovum explained

ovum/loop
math Int Operation

The Ovum integer calculator that doesn't overthink it

ovum/loop
Convert any to INT and subtract 1

Convert anything to an int, then knock one off — the off-by-one fixer

ovum/loop
New Multi-type Dictionary

Build a dict by renaming input labels — the dictionary node that respects your naming

ovum
Next Video Filename Ovum

Know VHS VideoCombine's next filename before it saves — no file guessing

ovum/workflow
Open output via shell

Auto-open your finished render in VLC — securely, no shell injection

ovum
Combine Paths

Gather a pile of paths into one flat list — Combine Paths

ovum/path
Ovum Length

How long is that list? Length with a passthrough

ovum/lists/python
os.path.abspath

Os.path.abspath as a node — turn relative paths into absolute ones

ovum/path/os.path
os.path.basename

Grab the filename off a full path — os.path.basename as a node

ovum/path/os.path
os.path.commonpath

Find the shared folder of a set of paths — os.path.commonpath

ovum/path/os.path
os.path.commonprefix

Os.path.commonprefix — the naive sibling that finds shared characters

ovum/path/os.path
os.path.dirname

Strip the filename, keep the folder — os.path.dirname as a node

ovum/path/os.path
os.path.exists

Does that path actually exist? A boolean check for your graph

ovum/path/os.path
os.path.expanduser

Turn ~ into your real home folder — os.path.expanduser as a node

ovum/path/os.path
os.path.expandvars

Resolve $VAR and ${VAR} inside your paths — os.path.expandvars

ovum/path/os.path
os.path.getatime

When was this file last touched? getatime as a node

ovum/path/os.path
os.path.getctime

Watching for files that just got written

ovum/path/os.path
os.path.getmtime

The timestamp that actually means 'when was this edited'

ovum/path/os.path
os.path.getsize

The file-size check that keeps broken runs from passing

ovum/path/os.path
os.path.isabs

'is this path absolute?' depends on where you're standing

ovum/path/os.path
os.path.isdir

'is this a real folder?' before you write into it

ovum/path/os.path
os.path.isfile

The 'does my output actually exist' check every automation graph needs

ovum/path/os.path
os.path.islink

Spotting the symlinks in your model directory

ovum/path/os.path
os.path.ismount

'is this where my NAS is mounted?'

ovum/path/os.path
os.path.join

The path-builder you'll actually use every single day

ovum/path/os.path
os.path.lexists

The 'does the link exist' question isfile gets wrong

ovum/path/os.path
os.path.normcase

Making 'c:\Models' and 'C:\models' compare equal

ovum/path/os.path
os.path.normpath

The path-cleaner that fixes 'a//b/../c' nonsense

ovum/path/os.path
os.path.realpath

Cutting through symlinks to find the real file

ovum/path/os.path
os.path.relpath

'how do I get from here to there?' as a string

ovum/path/os.path
os.path.samefile

The 'are these two paths the same file?' truth-teller

ovum/path/os.path
os.path.split

One node instead of dirname+basename

ovum/path/os.path
os.path.split (all)

The whole path, broken into every piece

ovum/path/os.path
os.path.splitdrive

Separating the drive letter from the path

ovum/path/os.path
os.path.splitext

The node that separates your filename from its extension

ovum/path/os.path
Backslashes → Forward

The Windows-path converter your cross-platform workflow needs

ovum/path
STRING to PATHLIKE (PurePath)

Turn a path string into a pathlib.PurePath for type-safe wiring

ovum/path
re.escape (Regex Escape)

Stop regex metacharacters from hijacking your literal text

ovum/regex
re.findall (Regex FindAll)

Pull every match out of a string as plain text — great for tags, numbers, and filenames

ovum/regex
re.finditer (Regex FindIter)

Get every match as a real match object — the workhorse for structured extraction

ovum/regex
re.compile flags (Regex Flags)

The Regex Flags node is the one setting every Ovum regex node shares — here's what each toggle actually does

ovum/regex
re.fullmatch (Regex FullMatch)

The strictest regex check in the pack — validate whole strings, not fragments

ovum/regex
re.match (Regex Match)

Check whether a string starts with your pattern (and the difference from search, settled)

ovum/regex
re.Match.expand (Regex Match Expand)

Rebuild text from a match's groups with a template

ovum/regex
re.Match.group (Regex Match Group Selector)

The extraction node — pull captured groups out of any match object

ovum/regex
re.Match (Regex Match Result)

Introspect any match object — the debugging eyes of the regex suite

ovum/regex
re.Match[index] (Regex Match Select)

Pick one match out of a finditer list by index

ovum/regex
re.Match.span/start/end (Regex Match Span)

Get the exact character positions of a match

ovum/regex
re.Match.__repr__ (Regex Match View)

One node to actually see what your regex matched

ovum/regex
re.search (Regex Search)

Find text anywhere in a string and feed the match to other nodes

ovum/regex
re.split (Regex Split)

Slice strings on any regex — smarter than a simple delimiter split

ovum/regex
re.sub (Regex Sub)

Find-and-replace with regex power — the node that cleans up half your text problems

ovum/regex
re.subn (Regex SubN)

The same find-and-replace as re.sub, but the count is the point

ovum/regex
Escapable Wildcard Processor 🥚

Dynamic prompts in ComfyUI — wildcard files, random choices, and date stamps

ovum/text
Passthru Input And Output Is List Ovum

The spy node that keeps lists as lists

ovum/debug
Passthru Input Is List Ovum

See exactly what a node handed you — and force list-unwrap semantics

ovum/debug
Passthru Output Is List Ovum

The 'trust me, this is a batch' debug node

ovum/debug
Passthru Ovum

The do-nothing node that actually tells you what's flowing

ovum/debug
Convert any to INT and add 1

Turn anything into an INT and bump it by 1

ovum/loop
Python String Format

The most useful text node in comfy-ovum

ovum
Reinterpret As List Cast

Present any value as a batch, don't convert it

Data
Reinterpret Cast

Connect incompatible sockets without changing a byte

Data
Repeat Item

Stamp out N copies of one value

ovum/lists/any
Repeat Item Batch Ovum

Stamp out a fan-out batch from a single value

ovum/lists/comfy
Repeat Item Ovum

N copies of one value, the list-utility way

ovum/lists/python
Reverse Batch Ovum

Flip a ComfyUI batch's order, safely and non-mutating

ovum/lists/comfy
Reverse List

Flip a batch's order (and why the deprecated tag matters)

ovum/lists/any
Reverse List Ovum

Flip a real list object, not a graph batch

ovum/lists/python
Set Environment Variable

A global variable bus for your whole ComfyUI session

ovum
Set LocalStorage

Persist little strings across sessions, in your browser not your server

ovum
String Batch Editor Ovum

Type a batch, one string per line

ovum/lists/comfy
String List Editor

Type a list, or drag files into it

ovum/lists/any
String List Editor Ovum

Type a list that stays a list object

ovum/lists/python
Sync Sink Ovum

The node that does nothing so your whole graph finishes

ovum/KJNodes
Text Ovary

Captions, watermarks and credits stamped straight onto images

image/text
Timer 🥚

A workflow stopwatch that tells you where the time actually went

ovum
Uncachable List Copy (immutable)

The node that breaks Comfy's cache so your loop re-runs

ovum/loop
_.all

Does every element in your list pass the test?

ovum/underscore
_.any

Does anything in your list pass the test?

ovum/underscore
_.castArray

Guarantee a value is an array, no matter what it is

ovum/underscore
_.chain

The front door to the whole ovum/underscore suite

ovum/underscore
_.chunk

Slice one big list into batches of N

ovum/underscore
_.clone

A copy you can mutate without breaking the original

ovum/underscore
_.collect

The legacy name for “map each item”

ovum/underscore
_.compact

Quietly delete the junk from a list

ovum/underscore
_.constant

A factory for “always return this exact value”

ovum/underscore
_.contains

Ask a list “does this value live in here?”

ovum/underscore
_.countBy

Histogram your list, no spreadsheet required

ovum/underscore
_.curry

Build a specialized function from a general one

ovum/underscore
_.defaults

Fill in missing keys, keep the ones you have

ovum/underscore
_.detect

The alias for “find the first match”

ovum/underscore
_.difference

Everything in list A that isn't in list B

ovum/underscore
_.each

Visit every element, and pass the list through

ovum/underscore
_.escape

Make user text safe for HTML

ovum/underscore
_.every

“is this true for ALL of them?”

ovum/underscore
underscore function

Hand the whole library to rgthree's Power Puter

ovum/underscore
_.extend

Merge dicts, later wins

ovum/underscore
_.extendDeep

The merge that reaches all the way down

ovum/underscore
_.filter

Keep the values that pass the test

ovum/underscore
_.filterObject

Filter a dict's values, not a list's

ovum/underscore
_.find

_.find hands you the item, not the index

ovum/underscore
_.findIndex

When you want the position, not the item

ovum/underscore
_.findKey

Find the key, not the value

ovum/underscore
_.findLastIndex

_.findLastIndex finds the match nearest the end

ovum/underscore
_.findWhere

_.findWhere and its properties shorthand

ovum/underscore
_.first

_.first, with or without n

ovum/underscore
_.firstOr

_.firstOr returns a fallback

ovum/underscore
_.flatten

_.flatten turns lists of lists into one flat list

ovum/underscore
_.foldl

_.foldl is reduce, and it has a memo trap

ovum/underscore
_.foldr

_.foldr and why direction matters

ovum/underscore
_.forEach

_.forEach, and what it's actually for

ovum/underscore
_.fromPairs

_.fromPairs builds your object

ovum/underscore
_.functions

_.functions

ovum/underscore
_.get

_.get, and the deep-path claim to be wary of

ovum/underscore
_.getmanyattr

_.getmanyattr

ovum/underscore
_.groupBy

_.groupBy is the genuinely useful one

ovum/underscore
_.grouper

_.grouper

ovum/underscore
_.has

Does the object have that key? _.has, and the dict gotcha

ovum/underscore
_.hasCallable

Is that property actually a function? _.hasCallable

ovum/underscore
_.head

First-with-n, and the one-element list quirk

ovum/underscore
_.identity

The node that hands your data right back

ovum/underscore
_.include

The 'is this value in this list?' check that feeds your if/else

ovum/underscore
_.indexBy

Turn a list of records into a dict you can look up by key

ovum/underscore
_.indexOf

Find where a value sits in a list, without crashing when it's missing

ovum/underscore
_.initial

Everything in the list except the last one

ovum/underscore
_.inject

Reduce by its old name, and the WIP edge you'll notice immediately

ovum/underscore
_.intersection

What's in every one of these lists?

ovum/underscore
_.invert

Flip a dict's keys and values for reverse lookups

ovum/underscore
_.invoke

Run a method on every item in a collection, in the graph

ovum/underscore
_.isBool

'is it a boolean?' — and the reason it doesn't output a boolean

ovum/underscore
_.isBoolean

The properly-typed 'is this a bool?' check

ovum/underscore
_.isBuiltinFunction

'is this a built-in like len() or print()?'

ovum/underscore
_.isBuiltinMethod

'is this a built-in method like str.upper?'

ovum/underscore
_.isCallable

The one Python type-check in this family that's actually broadly useful

ovum/underscore
_.isClass

'is this value a class/type?'

ovum/underscore
_.isCode

'is this a compiled code object?'

ovum/underscore
_.isComplex

'is this value a complex number?'

ovum/underscore
_.isDict

'is this value a Python dict?' — the type-check you'll actually reach for

ovum/underscore
_.isDictlike

The duck-typed 'does this behave like a dict?' check

ovum/underscore
_.isElement

The node that can only ever say 'no'

ovum/underscore
_.isEllipsis

A check for the literal dot-dot-dot singleton

ovum/underscore
_.isEmpty

One check for empty strings, lists, dicts, and nothing at all

ovum/underscore
_.isEqual

Deep-compare two values to detect change or duplication

ovum/underscore
_.isFile

A type-theory check that returns False for actual files

ovum/underscore
_.isFloat

An exact-type float check that numpy will trip over

ovum/underscore
_.isFrame

A stack-frame check that belongs to the debugger, not your graph

ovum/underscore
_.isFunction

The callback spotter that gets a proper BOOLEAN output

ovum/underscore
_.isGenerator

A correctly-checked type test you'll rarely need

ovum/underscore
_.isGetSetDescriptor

Introspection-only, and you will never need it

ovum/underscore
_.isInt

An exact-type integer check with a numpy gotcha

ovum/underscore
_.isIntegral

The loose 'whole number' check that includes bools

ovum/underscore
_.isIntString

The safe 'string is a plain integer' check before you convert

ovum/underscore
_.isLambda

The misnomer that agrees with isFunction on everything

ovum/underscore
_.isList

An exact-type check so you know whether to fan out or not

ovum/underscore
_.isListlike

The pragmatic 'can I iterate this' test, without exact-type pedantry

ovum/underscore
_.isMemberDescriptor

A second CPython descriptor check, also never needed

ovum/underscore
_.isMethod

A bound-method spotter for a world that never sends them

ovum/underscore
_.isModule

The check that only fires if someone wires in an imported module

ovum/underscore
_.isNone

Checking for nothing in ComfyUI

ovum/underscore
_.isNotImplemented

The check for Python's 'I can't do that' singleton

ovum/underscore
_.isNumeric

So, is that widget value actually a number? Ask this node.

ovum/underscore
_.isSlice

Yes, it checks for Python slice objects. No, you probably never needed that.

ovum/underscore
_.isString

Tell text from everything else before your format node eats it.

ovum/underscore
_.isTraceback

Checking for Python tracebacks inside ComfyUI. Really.

ovum/underscore
_.isTuple

Tuple or list? This is how you tell them apart without guessing.

ovum/underscore
_.isType

Is it the type itself, like the class? The obscure cousin of the is-family.

ovum/underscore
_.isUnicode

Same as _.isString — because in Python 3, everything is unicode.

ovum/underscore
_.iteratee

The quiet engine behind map, filter and max — a callback factory in node form.

ovum/underscore
_.join

Turn a list into one string, JavaScript style — glue included.

ovum/underscore
_.keys

Pull the keys out of a dict — and get a free index list for lists.

ovum/underscore
_.last

Grab the last item in a list — and mind the n-elements twist.

ovum/underscore
_.lastIndexOf

Find the LAST match in a list — and fix that fromIndex default first.

ovum/underscore
_.map

The one underscore node you'll actually want — map every element through a transform.

ovum/underscore
_.mapDeep

Recursive map over nested data — in theory. The schema forgot the function.

ovum/underscore
_.mapObject

Map, but for dicts — transform every value, or rename keys while you're at it.

ovum/underscore
_.matcher

Build a predicate that says 'got these attributes?' — the filter's best friend.

ovum/underscore
_.max

The biggest value in a list — with an iteratee for 'biggest by some criterion'.

ovum/underscore
_.maxBy

Max by a key — and why you'll probably use _.max instead.

ovum/underscore
_.methods

List every callable on an object — the introspection node nobody knew they wanted.

ovum/underscore
_.min

The smallest value in a list — mirror image of _.max, same quirks.

ovum/underscore
_.minBy

The _.minBy That Wants a Callable It Can't Be Given

ovum/underscore
_.mixin

Give the Underscore Object Your Own Functions

ovum/underscore
_.most

Did Most of These Pass? Only Sort Of

ovum/underscore
_.now

Seconds Since Epoch, Not Milliseconds

ovum/underscore
_.object

Turn Two Lists Into a Dictionary (or One List of Pairs)

ovum/underscore
_.omit

Strip the Junk Keys Out of a Dictionary

ovum/underscore
_.only

Values for Lists, Keys for Dicts

ovum/underscore
_.pairs

Flatten a Dictionary Into [key, value] Pairs

ovum/underscore
_.partition

Split a List Into the Passers and the Failers

ovum/underscore
_.pick

Whitelist a Dictionary Down to the Keys You Care About

ovum/underscore
_.pluck

Pull One Field Out of Every Item in a List

ovum/underscore
_.pluckAsObject

The Underscore Node Whose Author Left a Question Mark

ovum/underscore
_.property

A Factory That Makes a Property-Getter Function

ovum/underscore
_.random

A Random Integer With an Off-by-One You Should Know About

ovum/underscore
_.range

Generate a List of Integers Without Typing Them Out

ovum/underscore
_.reduce

Fold a List Into One Value — but Bring Your Own Memo

ovum/underscore
_.reduceRight

Reduce, From the Right, With a Different Function Signature

ovum/underscore
_.re_findall

Pull Every Regex Match Out of a String

ovum/underscore
_.reject

Keep Everything That Fails

ovum/underscore
_.remove

The Remove Node That's Missing Its Predicate

ovum/underscore
_.rest

Everything after the first item, without the ceremony

ovum/underscore
_.result

Read a property, or call it if it's a function

ovum/underscore
_.reverse

Flip your list, but keep the original intact

ovum/underscore
_.same

The fastest way to ask 'is this list all one value?'

ovum/underscore
_.sampleSize

Grab n random items, re-rolled every run

ovum/underscore
_.select

Filtering's confusing twin — know what you're getting

ovum/underscore
_.shuffle

Randomize a list, Fisher-Yates style, without touching the original

ovum/underscore
_.size

The length of anything, as an integer you can use

ovum/underscore
_.some

'does anything in this list pass the test?' — with a short circuit

ovum/underscore
_.sort

Sort the values, keep the keys out of it

ovum/underscore
_.sortBy

Sort a list by a property, a length, or a custom key

ovum/underscore
_.sortedIndex

Where would this value slot into a sorted list?

ovum/underscore
_.sortObjectBy

Sort a dict's values, with a reverse switch

ovum/underscore
_.sum

Add up the values in a list, literally

ovum/underscore
_.symmetric_difference

The elements that live in exactly one list

ovum/underscore
_.tail

Drop the first item, keep the rest

ovum/underscore
_.take

The first element — or the first n, with a surprising twist

ovum/underscore
_.tap

Poke at the data mid-chain, then hand it back unchanged

ovum/underscore
_.times

Run a function n times — if you can supply the function

ovum/underscore
_.toArray

Make sure it's actually a list before something else chokes

ovum/underscore
_.toPairs

Turn a dict into a list of key/value pairs, the easy way

ovum/underscore
_.unescape

Clean HTML entities out of your prompt text

ovum/underscore
_.union

Merge several tag lists into one, duplicates gone

ovum/underscore
_.uniq

Dedupe a list and keep the first occurrence

ovum/underscore
_.uniq_mutate

Dedupe in place, and it deletes the wrong copy

ovum/underscore
_.unique

The alias that is uniq, minus the fancy options

ovum/underscore
_.uniqueId

A counter that hands out unique integers

ovum/underscore
_.value

The terminal node that unwraps an underscore chain

ovum/underscore
_.values

Pull the values out of a dict, in order

ovum/underscore
_.where

Filter a list of objects like a mini database query

ovum/underscore
_.without

Strip unwanted values out of a list

ovum/underscore
_.zip

Merge parallel lists into pairs, like Python's zip

ovum/underscore
_.zipObject

Build a dict from two parallel lists

ovum/underscore
Unique Batch Ovum

Dedupe a batch, order preserved

ovum/lists/comfy
Unique List

The dedupe node that got renamed, then deprecated

ovum/lists/any
Unique List Ovum

The dependable Python-list dedupe

ovum/lists/python
VHS PNG deleter

Clean up the frame dump after Video Helper Suite renders

ovum/workflow
Widget To Boolean Ovum

Read any node's widget as true/false

ovum/KJNodes
Widget To Float Ovum

Grab any widget value as a float

ovum/KJNodes
Widget To Int Ovum

Read any node's widget as a clean integer

ovum/KJNodes
Widget To String Ovum

Read any node's widget as text — without hardcoding it twice

ovum/KJNodes
Workflow Widget To Any Ovum

Pull a widget out of a workflow blob and keep its real type

ovum/workflow
XRange Node

The counter that ticks one step on every run

Data
Readme

Ovum

Some custom nodes for Comfy that I just couldn't live without. Some have come from other packages that were annoyingly hard to find, some have been improved from other peoples' work who don't accept PR requests, some have been made by me, and one has been made entirely by AI (but basically had to be rewritten afterwards).

Twin Connectors: SetTwinNodes and GetTwinNodes

Twin Connectors: Set/Get screenshot

A pair of graph-cleaning utility nodes designed to “tunnel” connections and reduce visual clutter without sacrificing clarity or type-safety.

Effortless to type one-handed: enter SETTW or GETTW to locate these nodes fast—so your right hand can stay on the mouse (because where else would your right hand be?)

All the functionality of Kijai's Set/Get nodes, easier to use than easyUse SetNodes, twice as many connections, and unbelievably more automated.

  • SetTwinNodes accepts an arbitrary number (two... more coming soon) of inputs and exposes matching outputs, letting you collect and forward values by meaningful constant names rather than raw wires.
  • GetTwinNodes presents matching outputs, selected via lightweight “constant” widgets. You pick the names you care about; the node provides outputs of the corresponding types.

What makes them useful:

  • They work in subgraphs!
  • ~Clean labels over raw types: when a link is attached, constants and slots can inherit human-friendly labels from the connected endpoints; titles are built from the chosen constants.~
  • ~Provisional naming: when a Get node learns a name from a downstream connection that does not yet exist on any Set, it marks the constant with an asterisk to signal “choose a valid source later.” When the matching Set appears, the names reconcile automatically.~
  • Works in either order: you can drop a Get first and wire it to a consumer; later, when a Set of the right type appears, the system can adopt the better name and update labels across the link.
  • Sensible colorization: nodes can colorize based on the first two connected, typed slots to give fast visual feedback while keeping the graph readable.
  • Serialization-safe: saved widget values and output types are respected on load; no surprise re-labelling. (Mostly)
  • ~Ergonomic pairing: when you pick one constant and the system recognizes an associated partner, it can suggest or create the companion slot automatically; if it can’t, it still creates a second empty selector so you can complete the pair manually.~
  • Tunneling without surprises: instant graphic feedback warns of setters with no getters.

How to use:

  1. Drop a SetTwinNodes near your sources and connect any values you want to “publish.” Give each constant a clear name (e.g., width, height, start_image). The node mirrors types to its outputs and propagates names to matching Gets.
  2. Drop a GetTwinNodes near your consumers and pick the same constant names to “subscribe.” If you connect the Get to a consumer before a matching Set exists, it will note your intent and reconcile once a suitable Set appears.
  3. Rename safely: titles and labels follow your constants (sometimes); if a label equals its raw type (a “lame name”), later Set connections can adopt a better name from a compatible Get to keep the graph readable.
  4. Toggle “Show connections” from the node menu to visualize virtual links between Sets and Gets without adding extra wires.

These nodes are meant to keep large graphs navigable while preserving intent through names, not just types. They are deliberately forgiving when you work top-down or bottom-up, and they do their best to stay out of your way once you’ve chosen the labels that make sense in your workflow.

Python String Format

Turn multiple inputs into a single, neatly formatted string using Python’s str.format syntax. This node is ideal for building prompts, captions, file names, or any text that needs values injected at runtime.

What it does:

  • Accepts a format template (fmt) and inserts values into placeholders like {arg0}, {arg1}, etc.
  • Produces a single STRING output.
  • Uses Python’s standard formatting rules, so you get powerful control over numbers, padding, alignment, and more.

Placeholders:

  • Use {arg0} for the first input, {arg1} for the second, and so on.
  • You can apply format specs: {arg0:.2f}, {arg1:03d}, {arg2:^20}, {arg3!r}.
  • To show a literal curly brace, escape it: {{ or }}.

New lines:

  • Press Enter in the fmt field to insert real line breaks; the output will contain those line breaks exactly.
  • You can also embed newline escapes: use \n for a single new line, or \n\n to insert a blank line.
  • Mix placeholders and text across lines to build readable multi-line prompts or file names.

Examples:

  • Multiline prompt with escape sequences:
    • fmt: Positive: {arg0}\nNegative: {arg1}\nSteps: {arg2}
    • Inputs: arg0 = "cozy cabin", arg1 = "low quality, blurry", arg2 = 30
    • Output: Positive: cozy cabin Negative: low quality, blurry Steps: 30
  • Multiline using literal line breaks:
    • fmt: Title: {arg0}

      {arg1}
      Tags: {arg2}, {arg3}
      
    • Inputs: arg0 = "Autumn Forest", arg1 = "golden hour, volumetric light", arg2 = "forest", arg3 = "sunset"

    • Output: Title: Autumn Forest

      golden hour, volumetric light
      Tags: forest, sunset
      

Common recipes:

  • Basic substitution:
    • fmt: Prompt: {arg0}. Steps: {arg1}
    • Inputs: arg0 = "A cozy cabin at night", arg1 = 30
    • Output: Prompt: A cozy cabin at night. Steps: 30
  • Float precision:
    • fmt: Score: {arg0:.2f}
    • Inputs: arg0 = 0.98765
    • Output: Score: 0.99
  • Zero-padded integers:
    • fmt: Image_{arg0:04d}
    • Inputs: arg0 = 7
    • Output: Image_0007
  • Alignment and width:
    • fmt: [{arg0:^10}]
    • Inputs: arg0 = "OK"
    • Output: [ OK ]
  • Literal braces:
    • fmt: Config: {{enabled: {arg0}}}
    • Inputs: arg0 = true
    • Output: Config: {enabled: true}

Tips:

  • Missing or empty inputs are gracefully replaced with the literal string "None" at format time, so your workflow keeps running even if something disconnects or a generator yields no value. This is a dramatic improvement over other formatting nodes that can kill your workflow right when it’s about to finish saving that super‑long video.
  • Another bonus: non‑scalar inputs (lists, dictionaries, tuples, and custom objects) are kept as real Python objects rather than being flattened to JSON. That means you can index or key into them right in the format string.
  • Robust error handling: if formatting fails (e.g., invalid format spec, out-of-range index, missing key/attribute), the node prints the error to the console and returns the error text as the output string instead of crashing your run.
  • Numbers respect format specs; use them to avoid manual rounding or string tricks.
  • If you need default values, provide them upstream (e.g., via a constant/text node) and wire them in.

Structured data (lists, dicts, tuples):

  • Lists:
    • fmt: Top tags: {arg0[0]}, {arg0[1]}, count={arg0[2]:02d}
    • Inputs: arg0 = ["hdr", "sunset", 7]
    • Output: Top tags: hdr, sunset, count=07
  • Dictionaries:
    • fmt: User: {arg0[name]} (id={arg0[id]})
    • Inputs: arg0 = {"name": "Riley", "id": 42}
    • Output: User: Riley (id=42)
  • Tuples (or list-like sizes):
    • fmt: Size: {arg0[0]}x{arg0[1]}
    • Inputs: arg0 = (1024, 576)
    • Output: Size: 1024x576
  • You can combine indexing with format specs:
    • fmt: Mean: {arg0[1]:.2f}
    • Inputs: arg0 = ["loss", 0.123456]
    • Output: Mean: 0.12

Use cases:

  • Build dynamic prompts from multiple upstream nodes.
  • Compose file names with counters, dates, or padded indices.
  • Generate human-readable summaries that include numeric metrics.

Timer

How long does the workflow spend in each node?

Somewhat rough around the edges with a number of confusing buttons and inputs (thankfully you can ignore them all), but a useful tool for timing and debugging.

Timer: screenshot

Live Crop (interactive)

Visually crop, expand, and rotate an image with interactive guides rendered directly in the node.

  • Inputs:
    • crop_top, crop_bottom, crop_left, crop_right (FLOAT [-1..1]):
      • Negative: crops that fraction of the original dimension from that side (e.g., -0.1 removes 10% from that edge).
    • image (IMAGE, optional), mask (MASK, optional): both are processed with the same operations; masks use white=255 for padding.
  • Outputs: IMAGE, MASK
  • UI: The node shows a preview of the incoming image(s) with red lines indicating where the crop will occur. Adjust the sliders or drag the guides (think: Photoshop rulers) to update.

Notes:

  • When no image is connected, the node returns None; when connected, the preview is downscaled for responsiveness.
  • Multiple images/batches supported, allowing you crop as you go: adjust the cropping for the second image, which will be the first image by the time the next workflow executes.

Environment Bridge: Set Environment Variable and Get Environment Variable

Browser Local Storage: Set LocalStorage and Get LocalStorage

Persist small strings in the browser between sessions without touching the server environment.

  • Set LocalStorage: Writes a key/value into the browser's localStorage (strings only). Includes an optional passthrough to help enforce execution order. If overwrite=false and the key exists in localStorage, the value is left unchanged.
  • Get LocalStorage: Reads a key from the browser's localStorage with a default fallback. Returns (value, exists).

Notes:

  • Backend nodes cannot directly access the browser; the Set node triggers a frontend action to store the value using ComfyUI's UI-return channel. The Get node returns the provided default at execution time but is useful for coordinating UI state; use environment variables if you need true backend-readable values.
  • Keys and values are stored as strings. If you need structures, encode/decode to JSON in the graph.

Publish and subscribe values anywhere in your workflow (and even across workflows) using the process environment as a lightweight, global message bus.

What they do:

  • “Set Environment Variable” writes key/value pairs to the process environment. You can optionally thread a passthrough input/output to enforce execution order without altering data flow.
  • “Get Environment Variable” reads a key from the environment with a fallback default. It is change-aware and will re-evaluate when the targeted variable changes.
  • Together they enable out‑of‑band data routing without extra wires, allowing one‑to‑many fan‑out, late binding, and cross‑graph coordination.

Why it’s special:

  • Global scope within the process: values are visible to all workflows running in the same Comfy session.
  • “Virtual wires” without clutter: connect distant parts of a large graph through names, not links.
  • Change detection: readers can refresh only when a variable’s value or existence actually changes, keeping runs fast and deterministic.
  • Execution ordering: use the passthrough to place setting/getting in precise positions of your pipeline without affecting the payload being processed.

Patterns you can build:

  • Publish/Subscribe hub:
    • Upstream nodes “publish” dimensions, models, seeds, or file paths with “Set Environment Variable.”
    • Downstream consumers “subscribe” with “Get Environment Variable” wherever they need the same value.
  • Cross‑workflow handoff (inter‑workflow):
    • Use a stable variable name (e.g., PROJECT_PREFIX, ACTIVE_CHECKPOINT) so separate workflows launched in the same session share configuration.
  • Pseudo‑feedback loops (intra‑workflow):
    • Emulate feedback by writing a value early and reading it later in the same run to condition subsequent steps, without creating illegal graph cycles.
  • State and toggles:
    • Flip feature flags (e.g., USE_HIRES_FIX=true) to drive conditional branches or tool selection across multiple, otherwise unconnected nodes.
  • Secrets and tokens:
    • Inject API keys, model licenses, or service endpoints at runtime; consumers read them on demand.
  • One‑to‑many routing:
    • Publish once, consume everywhere—useful for common output directories, date stamps, or version tags.

Common recipes:

  • Share a counter between runs:
    • Read COUNT with “Get Environment Variable” (default 0) → increment in your logic → write back with “Set Environment Variable” for the next run.
  • Centralize paths:
    • Use “Set Environment Variable” with name=OUTPUT_DIR, value=/data/renders → multiple savers read OUTPUT_DIR to stay in sync.
  • Switch models/tools globally:
    • Use “Set Environment Variable” with name=ACTIVE_MODEL, value=SDXL → routers or conditionals pick the right branch downstream.

Tips and caveats:

  • Scope: values live only for the current process and its children; they do not persist after a restart.
  • Collisions: environment space is shared; pick distinctive names or prefixes (e.g., OVUM_) to avoid clashes.
  • Security: avoid printing secrets; prefer generic names and keep sensitive values out of saved screenshots or public logs.
  • Consistency: environment variables are strings; encode complex data (e.g., JSON) explicitly if needed and decode where you read it.
  • Ordering: use the passthrough to ensure “set before get” along your execution path; visual proximity doesn’t influence execution—connections do.

In short, “Set Environment Variable” and “Get Environment Variable” act like SetNode/GetNode with super powers: they can tunnel values across the graph, coordinate multiple consumers, and enable inter‑ and intra‑workflow value transfer—while staying simple, explicit, and robust.

Halt Toggle Node

The Halt Toggle node is a versatile control node designed to bring simplified workflow execution halts to your projects.

Key Features:

  • Flexible Halting: Easily pause workflow execution when the stop_now condition is met.
  • Auto-Reset Capability: The node can automatically reset itself after halting, allowing seamless continuation of the workflow in subsequent runs without manual intervention.
  • Delay Support: Introduce a configurable delay (in milliseconds) before halting the workflow.
  • Passthrough Convenience: The node forwards inputs, keeping graph wiring intuitive and maintaining data flow consistency when used as part of a larger workflow.
  • Detailed Feedback: Provides outputs to indicate whether a stop was applied and if an auto-reset was triggered.

How It Works:

When the stop_now input is set to true, the Halt Toggle node halts the workflow execution. However, if the reset_after_stop option is enabled, the halt will auto-disable for the next run, ensuring the workflow proceeds smoothly without requiring manual toggle adjustments.

Use Case Example:

If you have a workflow that requires pausing at specific stages or debugging steps, the Halt Toggle node provides an elegant solution to stop execution conditionally and resume it dynamically in subsequent runs.

Enhance your workflow control with the Halt Toggle node, empowering you to build more robust and interactive systems effortlessly.

Pystructure Data Nodes (complementary to ComfyUI-LogicUtils)

These nodes are complementary to the excellent collection at https://github.com/aria1th/ComfyUI-LogicUtils. They focus on list manipulation and small data utilities that pair well with logic/structure nodes from that set.

  • List Slice

    • What it does: Returns a slice of an input list using JavaScript-like slice semantics.
    • Inputs:
      • py_list (LIST): The source list.
      • start (INT): Start index. Negative values count from the end. Clamped to bounds; default 0 if empty.
      • end (INT): End index (non-inclusive). Negative values count from the end. Clamped to bounds; defaults to list length if empty.
    • Output:
      • LIST: A new list containing the requested slice. If start >= end after normalization, returns an empty list.
    • Notes: Behavior mirrors JS slice for negative indices and boundary clamping; does not mutate the input list.
  • List Splice

    • What it does: Splices into a list using JavaScript-like splice semantics: remove delete_count items starting at start and insert items from insert_list.
    • Inputs:
      • py_list (LIST): The target list (will be modified in place).
      • start (INT): Start index. Negative values count from the end. Clamped to valid positions.
      • delete_count (INT): Number of items to remove (clamped to remaining length; negatives treated as 0).
      • insert_list (LIST): Items to insert at the splice position (can be empty to perform pure deletion).
    • Outputs:
      • LIST (modified_list): The same list instance after splicing.
      • LIST (removed_elements): A list of the elements that were removed.
    • Notes: Mirrors JS semantics for start and delete_count; performs in-place mutation of py_list.
  • Repeat Item

    • What it does: Produces a list containing the given item repeated count times.
    • Inputs:
      • item (any): Any value to repeat.
      • count (INT): Number of repetitions. Minimum 0; negatives are treated as 0.
    • Output:
      • LIST: [item, item, ..., item] repeated count times.
    • Notes: Non-mutating; useful for building lists of constants, seeds, file paths, or objects for batch operations.
  • Reverse List

    • What it does: Returns a new list in reverse order.
    • Inputs:
      • py_list (LIST): The source list.
    • Output:
      • LIST: A new list with elements reversed.
    • Notes: Non-mutating; the input list is not modified.
  • List Concat

    • What it does: Concatenates two lists similar to JS Array.concat.
    • Inputs:
      • list_a (LIST): First list.
      • list_b (LIST): Second list (optional; blank treated as empty).
    • Output:
      • LIST: New list of elements of list_a followed by elements of list_b.
    • Notes: Non-mutating.
  • List IndexOf

    • What it does: Finds the first index of a value in a list like JS indexOf.
    • Inputs:
      • py_list (LIST): The list to search.
      • search_element (any): Value to find.
      • start (INT): Optional fromIndex; negative values count from end; blank -> 0.
    • Output:
      • INT: Index of the match; -1 if not found.
  • List Join

    • What it does: Joins elements into a string like JS join.
    • Inputs:
      • py_list (LIST): Elements to join.
      • separator (STRING): Optional separator; blank/unspecified -> comma, empty string -> no separator.
    • Output:
      • STRING: Joined string.
  • XRange

    • What it does: Python-like xrange/range iterator without generators. Outputs current value, full list, and a boolean flag for exhausted/looped.
    • Inputs:
      • stop (INT): End (exclusive). Required.
      • start (INT): Optional start; blank -> 0.
      • step (INT): Optional step; blank -> 1; cannot be 0; can be negative.
      • repeat (BOOLEAN): If true, wraps to the start (or end for negative step) when reaching the end; the flag output is true on the wrap iteration.
      • cursor (INT): Current index into the range; you can set/reset this manually to control which value is output.
      • advance (BOOLEAN): If true (default), increases cursor by 1 each evaluation so you can tick through values using Repeat/Trigger.
    • Outputs:
      • INT: current value at the cursor.
      • LIST: the full expanded list of values (range(start, stop, step)).
      • BOOLEAN: exhausted_or_looped — true when the range is exhausted (with repeat disabled) or when it loops (with repeat enabled).
    • Notes:
      • Negative steps are supported exactly like Python range. If the computed range is empty, the list is empty and the flag is true; current value returns 0.

Open Output via Shell (secure)

When your video has finished generating, have VLC (or your default media player) open it automatically.

Text Ovary (overlay text on images)

Text Ovary is a polished, in-house merge of the excellent TextOverlay node (sfinktah/comfyui-textoverlay) adapted for Ovum.

Why you’ll like it:

  • Super simple: plug in an IMAGE and a STRING, pick a font, done.
  • Looks great: fill + stroke with independent opacity to keep captions readable over any background.
  • Precise placement: left/center/right, top/middle/bottom, with padding and x/y nudges.
  • Multiline aware: sensible line spacing and alignment across lines.
  • Batch-friendly: renders the same text across a whole batch efficiently.

Inputs:

  • image (IMAGE)
  • text (STRING, multiline)
  • font_size (INT)
  • font (choice from bundled fonts)
  • fill_color_hex (STRING, e.g. #ffffff)
  • stroke_color_hex (STRING)
  • stroke_thickness (FLOAT, relative to font size)
  • padding (INT)
  • horizontal_alignment (left|center|right)
  • vertical_alignment (top|middle|bottom)
  • x_shift, y_shift (INT)
  • line_spacing (FLOAT)
  • stroke_opacity (FLOAT)

Output:

  • IMAGE with the text composited

Tip: Pair with Python String Format to build captions dynamically from metadata or prompts.

Safely open your rendered media with the system’s default app—no fragile shell strings, no workflow‑stopping errors.

Why you’ll like it:

  • Validates the path exists and is a regular file before trying to open it.
  • Accepts only image/video types (via MIME detection) to avoid launching arbitrary files.
  • Uses platform‑appropriate launchers:
    • Windows: start " <file> (handles spaces and the window‑title quirk).
    • macOS: open <file>
    • Linux: xdg-open <file>
  • Secure by design: runs without a shell so spaces/quotes can’t break or inject commands.
  • Non‑fatal: any failure returns an “[ERROR] …” string; your workflow keeps going.

Inputs:

  • input (any, optional passthrough): helps enforce execution order; doesn’t alter your data.
  • filename (STRING): full path to the image or video you want to open.

Output:

  • STRING: a success message or an “[ERROR] …” detail you can log, display, or ignore.

Tips:

  • Wire filename from your saver node to auto‑open the latest result.
  • Works well with format/concat nodes to build paths dynamically.
  • On headless systems, the open command may be unavailable; you’ll get a clear error message instead of a crash.

Regex Nodes (ovum/regex)

A compact suite of regex utilities that mirror Python’s re API while being graph-friendly. They accept plain strings or lists and return structured results without crashing your run when there are no matches.

Highlights:

  • Builders and matchers: re.compile flags, search, match, fullmatch, findall, finditer, split, sub, subn
  • Match inspectors: view, span/start/end, group/groups/groupdict, select index, expand templates
  • Escape helper: re.escape for safe literal matching

These nodes keep outputs list-aware to make it easy to fan out results downstream.

CUDNN Toggle Ovum

Temporarily flip torch.backends.cudnn.enabled (and benchmark) on/off around a section of your graph. Useful for cases where disabling cuDNN speeds up certain ops (e.g., VAE Encode/Decode under ZLUDA). Returns the previous state so you can restore it later.

Image List Loader + Folder Paths

Load a batch of images from a folder or an explicit list with optional regex/custom filtering, recursion, and sorting. Outputs images, masks, normalized file paths, callback payloads, embedded prompt/workflow info, and an ‘exhausted’ flag.

  • Folder Paths: utility to retrieve common ComfyUI directories as normalized strings for wiring into other nodes.

BigKnob (Widget)

A simple numeric knob with min/max clamping and precision rounding. Great as a human-friendly dial to drive parameters.

LM Studio Prompt (Ovum/LLM)

Connect to an LM Studio server to generate text (optionally with an image for vision models). Supports prompt modes, wildcard expansion, dynamic model discovery, and optional auto-unload after inactivity.

Workflow Helpers (Widgets to values)

  • Widget To String (KJNodes): Read a widget from any node in your workflow and return its value as STRING (with smart float formatting).
  • Workflow Widget To Any: Same idea, but returns the native type from a PROMPT&WORKFLOW input.
  • Sync Sink (KJNodes): A no-op sink that forces upstream branches to complete before proceeding; handy for synchronizing flows.

VHS Helper: Next Video Filename

Predict the next auto-numbered output base path that VHS VideoCombine will use (without writing files), so you can plan downstream file operations deterministically.

Wildcard Processor (Escapable)

Powerful prompt preprocessor that supports wildcard files, date stamping, simple random ranges, and safe comment/markup stripping. Designed to play nicely with other Ovum text utilities.

Does Kijai SetNode exist?

Checks your current workflow to see if a Kijai SetNode exists for a given Constant and is actually wired at input 0. Useful for conditionally enabling branches tied to KJNodes Set/Get patterns.

Folder, Range, and Sequence Utilities

  • XRange: A range-like tick node that outputs current value, full list, and an overflow/loop flag with optional repeat and reset behavior. Useful for counters and iteration control.

Ovum

Some custom nodes for Comfy that I just couldn't live without. Some have come from other packages that were annoyingly hard to find, some have been improved from other peoples' work who don't accept PR requests, some have been made by me, and one has been made entirely by AI (but basically had to be rewritten afterwards).

Twin Connectors: SetTwinNodes and GetTwinNodes

Twin Connectors: Set/Get screenshot

A pair of graph-cleaning utility nodes designed to “tunnel” connections and reduce visual clutter without sacrificing clarity or type-safety.

Effortless to type one-handed: enter SETTW or GETTW to locate these nodes fast—so your right hand can stay on the mouse (because where else would your right hand be?)

All the functionality of Kijai's Set/Get nodes, easier to use than easyUse SetNodes, twice as many connections, and unbelievably more automated.

  • SetTwinNodes accepts an arbitrary number (two... more coming soon) of inputs and exposes matching outputs, letting you collect and forward values by meaningful constant names rather than raw wires.
  • GetTwinNodes presents matching outputs, selected via lightweight “constant” widgets. You pick the names you care about; the node provides outputs of the corresponding types.

What makes them useful:

  • They work in subgraphs!
  • ~Clean labels over raw types: when a link is attached, constants and slots can inherit human-friendly labels from the connected endpoints; titles are built from the chosen constants.~
  • ~Provisional naming: when a Get node learns a name from a downstream connection that does not yet exist on any Set, it marks the constant with an asterisk to signal “choose a valid source later.” When the matching Set appears, the names reconcile automatically.~
  • Works in either order: you can drop a Get first and wire it to a consumer; later, when a Set of the right type appears, the system can adopt the better name and update labels across the link.
  • Sensible colorization: nodes can colorize based on the first two connected, typed slots to give fast visual feedback while keeping the graph readable.
  • Serialization-safe: saved widget values and output types are respected on load; no surprise re-labelling. (Mostly)
  • ~Ergonomic pairing: when you pick one constant and the system recognizes an associated partner, it can suggest or create the companion slot automatically; if it can’t, it still creates a second empty selector so you can complete the pair manually.~
  • Tunneling without surprises: instant graphic feedback warns of setters with no getters.

How to use:

  1. Drop a SetTwinNodes near your sources and connect any values you want to “publish.” Give each constant a clear name (e.g., width, height, start_image). The node mirrors types to its outputs and propagates names to matching Gets.
  2. Drop a GetTwinNodes near your consumers and pick the same constant names to “subscribe.” If you connect the Get to a consumer before a matching Set exists, it will note your intent and reconcile once a suitable Set appears.
  3. Rename safely: titles and labels follow your constants (sometimes); if a label equals its raw type (a “lame name”), later Set connections can adopt a better name from a compatible Get to keep the graph readable.
  4. Toggle “Show connections” from the node menu to visualize virtual links between Sets and Gets without adding extra wires.

These nodes are meant to keep large graphs navigable while preserving intent through names, not just types. They are deliberately forgiving when you work top-down or bottom-up, and they do their best to stay out of your way once you’ve chosen the labels that make sense in your workflow.

Python String Format

Turn multiple inputs into a single, neatly formatted string using Python’s str.format syntax. This node is ideal for building prompts, captions, file names, or any text that needs values injected at runtime.

What it does:

  • Accepts a format template (fmt) and inserts values into placeholders like {arg0}, {arg1}, etc.
  • Produces a single STRING output.
  • Uses Python’s standard formatting rules, so you get powerful control over numbers, padding, alignment, and more.

Placeholders:

  • Use {arg0} for the first input, {arg1} for the second, and so on.
  • You can apply format specs: {arg0:.2f}, {arg1:03d}, {arg2:^20}, {arg3!r}.
  • To show a literal curly brace, escape it: {{ or }}.

New lines:

  • Press Enter in the fmt field to insert real line breaks; the output will contain those line breaks exactly.
  • You can also embed newline escapes: use \n for a single new line, or \n\n to insert a blank line.
  • Mix placeholders and text across lines to build readable multi-line prompts or file names.

Examples:

  • Multiline prompt with escape sequences:
    • fmt: Positive: {arg0}\nNegative: {arg1}\nSteps: {arg2}
    • Inputs: arg0 = "cozy cabin", arg1 = "low quality, blurry", arg2 = 30
    • Output: Positive: cozy cabin Negative: low quality, blurry Steps: 30
  • Multiline using literal line breaks:
    • fmt: Title: {arg0}

      {arg1}
      Tags: {arg2}, {arg3}
      
    • Inputs: arg0 = "Autumn Forest", arg1 = "golden hour, volumetric light", arg2 = "forest", arg3 = "sunset"

    • Output: Title: Autumn Forest

      golden hour, volumetric light
      Tags: forest, sunset
      

Common recipes:

  • Basic substitution:
    • fmt: Prompt: {arg0}. Steps: {arg1}
    • Inputs: arg0 = "A cozy cabin at night", arg1 = 30
    • Output: Prompt: A cozy cabin at night. Steps: 30
  • Float precision:
    • fmt: Score: {arg0:.2f}
    • Inputs: arg0 = 0.98765
    • Output: Score: 0.99
  • Zero-padded integers:
    • fmt: Image_{arg0:04d}
    • Inputs: arg0 = 7
    • Output: Image_0007
  • Alignment and width:
    • fmt: [{arg0:^10}]
    • Inputs: arg0 = "OK"
    • Output: [ OK ]
  • Literal braces:
    • fmt: Config: {{enabled: {arg0}}}
    • Inputs: arg0 = true
    • Output: Config: {enabled: true}

Tips:

  • Missing or empty inputs are gracefully replaced with the literal string "None" at format time, so your workflow keeps running even if something disconnects or a generator yields no value. This is a dramatic improvement over other formatting nodes that can kill your workflow right when it’s about to finish saving that super‑long video.
  • Another bonus: non‑scalar inputs (lists, dictionaries, tuples, and custom objects) are kept as real Python objects rather than being flattened to JSON. That means you can index or key into them right in the format string.
  • Robust error handling: if formatting fails (e.g., invalid format spec, out-of-range index, missing key/attribute), the node prints the error to the console and returns the error text as the output string instead of crashing your run.
  • Numbers respect format specs; use them to avoid manual rounding or string tricks.
  • If you need default values, provide them upstream (e.g., via a constant/text node) and wire them in.

Structured data (lists, dicts, tuples):

  • Lists:
    • fmt: Top tags: {arg0[0]}, {arg0[1]}, count={arg0[2]:02d}
    • Inputs: arg0 = ["hdr", "sunset", 7]
    • Output: Top tags: hdr, sunset, count=07
  • Dictionaries:
    • fmt: User: {arg0[name]} (id={arg0[id]})
    • Inputs: arg0 = {"name": "Riley", "id": 42}
    • Output: User: Riley (id=42)
  • Tuples (or list-like sizes):
    • fmt: Size: {arg0[0]}x{arg0[1]}
    • Inputs: arg0 = (1024, 576)
    • Output: Size: 1024x576
  • You can combine indexing with format specs:
    • fmt: Mean: {arg0[1]:.2f}
    • Inputs: arg0 = ["loss", 0.123456]
    • Output: Mean: 0.12

Use cases:

  • Build dynamic prompts from multiple upstream nodes.
  • Compose file names with counters, dates, or padded indices.
  • Generate human-readable summaries that include numeric metrics.

Timer

How long does the workflow spend in each node?

Somewhat rough around the edges with a number of confusing buttons and inputs (thankfully you can ignore them all), but a useful tool for timing and debugging.

Timer: screenshot

Live Crop (interactive)

Visually crop, expand, and rotate an image with interactive guides rendered directly in the node.

  • Inputs:
    • crop_top, crop_bottom, crop_left, crop_right (FLOAT [-1..1]):
      • Negative: crops that fraction of the original dimension from that side (e.g., -0.1 removes 10% from that edge).
    • image (IMAGE, optional), mask (MASK, optional): both are processed with the same operations; masks use white=255 for padding.
  • Outputs: IMAGE, MASK
  • UI: The node shows a preview of the incoming image(s) with red lines indicating where the crop will occur. Adjust the sliders or drag the guides (think: Photoshop rulers) to update.

Notes:

  • When no image is connected, the node returns None; when connected, the preview is downscaled for responsiveness.
  • Multiple images/batches supported, allowing you crop as you go: adjust the cropping for the second image, which will be the first image by the time the next workflow executes.

Environment Bridge: Set Environment Variable and Get Environment Variable

Browser Local Storage: Set LocalStorage and Get LocalStorage

Persist small strings in the browser between sessions without touching the server environment.

  • Set LocalStorage: Writes a key/value into the browser's localStorage (strings only). Includes an optional passthrough to help enforce execution order. If overwrite=false and the key exists in localStorage, the value is left unchanged.
  • Get LocalStorage: Reads a key from the browser's localStorage with a default fallback. Returns (value, exists).

Notes:

  • Backend nodes cannot directly access the browser; the Set node triggers a frontend action to store the value using ComfyUI's UI-return channel. The Get node returns the provided default at execution time but is useful for coordinating UI state; use environment variables if you need true backend-readable values.
  • Keys and values are stored as strings. If you need structures, encode/decode to JSON in the graph.

Publish and subscribe values anywhere in your workflow (and even across workflows) using the process environment as a lightweight, global message bus.

What they do:

  • “Set Environment Variable” writes key/value pairs to the process environment. You can optionally thread a passthrough input/output to enforce execution order without altering data flow.
  • “Get Environment Variable” reads a key from the environment with a fallback default. It is change-aware and will re-evaluate when the targeted variable changes.
  • Together they enable out‑of‑band data routing without extra wires, allowing one‑to‑many fan‑out, late binding, and cross‑graph coordination.

Why it’s special:

  • Global scope within the process: values are visible to all workflows running in the same Comfy session.
  • “Virtual wires” without clutter: connect distant parts of a large graph through names, not links.
  • Change detection: readers can refresh only when a variable’s value or existence actually changes, keeping runs fast and deterministic.
  • Execution ordering: use the passthrough to place setting/getting in precise positions of your pipeline without affecting the payload being processed.

Patterns you can build:

  • Publish/Subscribe hub:
    • Upstream nodes “publish” dimensions, models, seeds, or file paths with “Set Environment Variable.”
    • Downstream consumers “subscribe” with “Get Environment Variable” wherever they need the same value.
  • Cross‑workflow handoff (inter‑workflow):
    • Use a stable variable name (e.g., PROJECT_PREFIX, ACTIVE_CHECKPOINT) so separate workflows launched in the same session share configuration.
  • Pseudo‑feedback loops (intra‑workflow):
    • Emulate feedback by writing a value early and reading it later in the same run to condition subsequent steps, without creating illegal graph cycles.
  • State and toggles:
    • Flip feature flags (e.g., USE_HIRES_FIX=true) to drive conditional branches or tool selection across multiple, otherwise unconnected nodes.
  • Secrets and tokens:
    • Inject API keys, model licenses, or service endpoints at runtime; consumers read them on demand.
  • One‑to‑many routing:
    • Publish once, consume everywhere—useful for common output directories, date stamps, or version tags.

Common recipes:

  • Share a counter between runs:
    • Read COUNT with “Get Environment Variable” (default 0) → increment in your logic → write back with “Set Environment Variable” for the next run.
  • Centralize paths:
    • Use “Set Environment Variable” with name=OUTPUT_DIR, value=/data/renders → multiple savers read OUTPUT_DIR to stay in sync.
  • Switch models/tools globally:
    • Use “Set Environment Variable” with name=ACTIVE_MODEL, value=SDXL → routers or conditionals pick the right branch downstream.

Tips and caveats:

  • Scope: values live only for the current process and its children; they do not persist after a restart.
  • Collisions: environment space is shared; pick distinctive names or prefixes (e.g., OVUM_) to avoid clashes.
  • Security: avoid printing secrets; prefer generic names and keep sensitive values out of saved screenshots or public logs.
  • Consistency: environment variables are strings; encode complex data (e.g., JSON) explicitly if needed and decode where you read it.
  • Ordering: use the passthrough to ensure “set before get” along your execution path; visual proximity doesn’t influence execution—connections do.

In short, “Set Environment Variable” and “Get Environment Variable” act like SetNode/GetNode with super powers: they can tunnel values across the graph, coordinate multiple consumers, and enable inter‑ and intra‑workflow value transfer—while staying simple, explicit, and robust.

Halt Toggle Node

The Halt Toggle node is a versatile control node designed to bring simplified workflow execution halts to your projects.

Key Features:

  • Flexible Halting: Easily pause workflow execution when the stop_now condition is met.
  • Auto-Reset Capability: The node can automatically reset itself after halting, allowing seamless continuation of the workflow in subsequent runs without manual intervention.
  • Delay Support: Introduce a configurable delay (in milliseconds) before halting the workflow.
  • Passthrough Convenience: The node forwards inputs, keeping graph wiring intuitive and maintaining data flow consistency when used as part of a larger workflow.
  • Detailed Feedback: Provides outputs to indicate whether a stop was applied and if an auto-reset was triggered.

How It Works:

When the stop_now input is set to true, the Halt Toggle node halts the workflow execution. However, if the reset_after_stop option is enabled, the halt will auto-disable for the next run, ensuring the workflow proceeds smoothly without requiring manual toggle adjustments.

Use Case Example:

If you have a workflow that requires pausing at specific stages or debugging steps, the Halt Toggle node provides an elegant solution to stop execution conditionally and resume it dynamically in subsequent runs.

Enhance your workflow control with the Halt Toggle node, empowering you to build more robust and interactive systems effortlessly.

Pystructure Data Nodes (complementary to ComfyUI-LogicUtils)

These nodes are complementary to the excellent collection at https://github.com/aria1th/ComfyUI-LogicUtils. They focus on list manipulation and small data utilities that pair well with logic/structure nodes from that set.

  • List Slice

    • What it does: Returns a slice of an input list using JavaScript-like slice semantics.
    • Inputs:
      • py_list (LIST): The source list.
      • start (INT): Start index. Negative values count from the end. Clamped to bounds; default 0 if empty.
      • end (INT): End index (non-inclusive). Negative values count from the end. Clamped to bounds; defaults to list length if empty.
    • Output:
      • LIST: A new list containing the requested slice. If start >= end after normalization, returns an empty list.
    • Notes: Behavior mirrors JS slice for negative indices and boundary clamping; does not mutate the input list.
  • List Splice

    • What it does: Splices into a list using JavaScript-like splice semantics: remove delete_count items starting at start and insert items from insert_list.
    • Inputs:
      • py_list (LIST): The target list (will be modified in place).
      • start (INT): Start index. Negative values count from the end. Clamped to valid positions.
      • delete_count (INT): Number of items to remove (clamped to remaining length; negatives treated as 0).
      • insert_list (LIST): Items to insert at the splice position (can be empty to perform pure deletion).
    • Outputs:
      • LIST (modified_list): The same list instance after splicing.
      • LIST (removed_elements): A list of the elements that were removed.
    • Notes: Mirrors JS semantics for start and delete_count; performs in-place mutation of py_list.
  • Repeat Item

    • What it does: Produces a list containing the given item repeated count times.
    • Inputs:
      • item (any): Any value to repeat.
      • count (INT): Number of repetitions. Minimum 0; negatives are treated as 0.
    • Output:
      • LIST: [item, item, ..., item] repeated count times.
    • Notes: Non-mutating; useful for building lists of constants, seeds, file paths, or objects for batch operations.
  • Reverse List

    • What it does: Returns a new list in reverse order.
    • Inputs:
      • py_list (LIST): The source list.
    • Output:
      • LIST: A new list with elements reversed.
    • Notes: Non-mutating; the input list is not modified.
  • List Concat

    • What it does: Concatenates two lists similar to JS Array.concat.
    • Inputs:
      • list_a (LIST): First list.
      • list_b (LIST): Second list (optional; blank treated as empty).
    • Output:
      • LIST: New list of elements of list_a followed by elements of list_b.
    • Notes: Non-mutating.
  • List IndexOf

    • What it does: Finds the first index of a value in a list like JS indexOf.
    • Inputs:
      • py_list (LIST): The list to search.
      • search_element (any): Value to find.
      • start (INT): Optional fromIndex; negative values count from end; blank -> 0.
    • Output:
      • INT: Index of the match; -1 if not found.
  • List Join

    • What it does: Joins elements into a string like JS join.
    • Inputs:
      • py_list (LIST): Elements to join.
      • separator (STRING): Optional separator; blank/unspecified -> comma, empty string -> no separator.
    • Output:
      • STRING: Joined string.
  • XRange

    • What it does: Python-like xrange/range iterator without generators. Outputs current value, full list, and a boolean flag for exhausted/looped.
    • Inputs:
      • stop (INT): End (exclusive). Required.
      • start (INT): Optional start; blank -> 0.
      • step (INT): Optional step; blank -> 1; cannot be 0; can be negative.
      • repeat (BOOLEAN): If true, wraps to the start (or end for negative step) when reaching the end; the flag output is true on the wrap iteration.
      • cursor (INT): Current index into the range; you can set/reset this manually to control which value is output.
      • advance (BOOLEAN): If true (default), increases cursor by 1 each evaluation so you can tick through values using Repeat/Trigger.
    • Outputs:
      • INT: current value at the cursor.
      • LIST: the full expanded list of values (range(start, stop, step)).
      • BOOLEAN: exhausted_or_looped — true when the range is exhausted (with repeat disabled) or when it loops (with repeat enabled).
    • Notes:
      • Negative steps are supported exactly like Python range. If the computed range is empty, the list is empty and the flag is true; current value returns 0.

Open Output via Shell (secure)

When your video has finished generating, have VLC (or your default media player) open it automatically.

Text Ovary (overlay text on images)

Text Ovary is a polished, in-house merge of the excellent TextOverlay node (sfinktah/comfyui-textoverlay) adapted for Ovum.

Why you’ll like it:

  • Super simple: plug in an IMAGE and a STRING, pick a font, done.
  • Looks great: fill + stroke with independent opacity to keep captions readable over any background.
  • Precise placement: left/center/right, top/middle/bottom, with padding and x/y nudges.
  • Multiline aware: sensible line spacing and alignment across lines.
  • Batch-friendly: renders the same text across a whole batch efficiently.

Inputs:

  • image (IMAGE)
  • text (STRING, multiline)
  • font_size (INT)
  • font (choice from bundled fonts)
  • fill_color_hex (STRING, e.g. #ffffff)
  • stroke_color_hex (STRING)
  • stroke_thickness (FLOAT, relative to font size)
  • padding (INT)
  • horizontal_alignment (left|center|right)
  • vertical_alignment (top|middle|bottom)
  • x_shift, y_shift (INT)
  • line_spacing (FLOAT)
  • stroke_opacity (FLOAT)

Output:

  • IMAGE with the text composited

Tip: Pair with Python String Format to build captions dynamically from metadata or prompts.

Safely open your rendered media with the system’s default app—no fragile shell strings, no workflow‑stopping errors.

Why you’ll like it:

  • Validates the path exists and is a regular file before trying to open it.
  • Accepts only image/video types (via MIME detection) to avoid launching arbitrary files.
  • Uses platform‑appropriate launchers:
    • Windows: start " <file> (handles spaces and the window‑title quirk).
    • macOS: open <file>
    • Linux: xdg-open <file>
  • Secure by design: runs without a shell so spaces/quotes can’t break or inject commands.
  • Non‑fatal: any failure returns an “[ERROR] …” string; your workflow keeps going.

Inputs:

  • input (any, optional passthrough): helps enforce execution order; doesn’t alter your data.
  • filename (STRING): full path to the image or video you want to open.

Output:

  • STRING: a success message or an “[ERROR] …” detail you can log, display, or ignore.

Tips:

  • Wire filename from your saver node to auto‑open the latest result.
  • Works well with format/concat nodes to build paths dynamically.
  • On headless systems, the open command may be unavailable; you’ll get a clear error message instead of a crash.

Regex Nodes (ovum/regex)

A compact suite of regex utilities that mirror Python’s re API while being graph-friendly. They accept plain strings or lists and return structured results without crashing your run when there are no matches.

Highlights:

  • Builders and matchers: re.compile flags, search, match, fullmatch, findall, finditer, split, sub, subn
  • Match inspectors: view, span/start/end, group/groups/groupdict, select index, expand templates
  • Escape helper: re.escape for safe literal matching

These nodes keep outputs list-aware to make it easy to fan out results downstream.

CUDNN Toggle Ovum

Temporarily flip torch.backends.cudnn.enabled (and benchmark) on/off around a section of your graph. Useful for cases where disabling cuDNN speeds up certain ops (e.g., VAE Encode/Decode under ZLUDA). Returns the previous state so you can restore it later.

Image List Loader + Folder Paths

Load a batch of images from a folder or an explicit list with optional regex/custom filtering, recursion, and sorting. Outputs images, masks, normalized file paths, callback payloads, embedded prompt/workflow info, and an ‘exhausted’ flag.

  • Folder Paths: utility to retrieve common ComfyUI directories as normalized strings for wiring into other nodes.

BigKnob (Widget)

A simple numeric knob with min/max clamping and precision rounding. Great as a human-friendly dial to drive parameters. Totally untested.

LM Studio Prompt (Ovum/LLM)

Connect to an LM Studio server to generate text (optionally with an image for vision models). Supports prompt modes, wildcard expansion, dynamic model discovery, and optional auto-unload after inactivity. NOTE: Since LM Studio does not actually support unloading models on request, this node requires you install the the LM Studio model "liquid/lfm2-1.2b" and set your automatic model unloading to the shortest possible period (60 seconds).

LM Studio Unload (Ovum/LLM)

Force an immediate unload of the LM Studio model when an auto-unload timer is pending. This node cancels the repository’s shared unload timer (scheduled by LM Studio Prompt nodes) and triggers a tiny model switch on the LM Studio server to free VRAM sooner.

What it does:

  • Cancels any pending auto-unload timer shared by all LM Studio nodes in this package.
  • If a timer was active, it sends a minimal request to switch to the tiny model "liquid/lfm2-1.2b" so VRAM is released quickly.
  • If no timer was active, it does nothing (and tells you so).
  • Always passes its first input through unchanged so you can wire it inline without breaking your graph.

Inputs:

  • any_input (ANY, passthrough)
  • server_address (STRING, default: localhost)
  • server_port (INT, default: 1234)

Outputs:

  • any_output (ANY, passthrough of any_input)
  • status (STRING) — human-readable summary: unloaded now, attempted but failed, or nothing to do.

Notes:

  • Install the LM Studio model "liquid/lfm2-1.2b" for unloading to work as designed.
  • All LM Studio requests from these nodes are serialized; the unload timer is suspended during requests and restarted after completion.

Workflow Helpers (Widgets to values)

  • Widget To String (KJNodes): Read a widget from any node in your workflow (works inside subgraphs, unlike KJNODE) and returns its value as a STRING
  • Workflow Widget To Any: Same idea, but returns the native type from a PROMPT&WORKFLOW input.
  • Sync Sink (KJNodes): A no-op sink that forces upstream branches to complete before proceeding; handy for synchronizing flows.

VHS Helper: Next Video Filename

Predict the next auto-numbered output base path that VHS VideoCombine will use (without writing files), so you can plan downstream file operations deterministically.

Wildcard Processor (Escapable)

Powerful prompt preprocessor that supports wildcard files, date stamping, simple random ranges, and safe comment/markup stripping. Designed to play nicely with other Ovum text utilities.

Does Kijai SetNode exist?

Checks your current workflow to see if a Kijai SetNode exists for a given Constant and is actually wired at input 0. Useful for conditionally enabling branches tied to KJNodes Set/Get patterns.

Folder, Range, and Sequence Utilities

  • XRange: A range-like tick node that outputs current value, full list, and an overflow/loop flag with optional repeat and reset behavior. Useful for counters and iteration control.

Additional nodes and utilities (not previously documented)

The following nodes are available in the root Python modules but were not yet described above. This section adds short, practical explanations so you can use them immediately.

OS Path Utilities (ovum/path and ovum/path/os.path)

A set of small path helpers and thin wrappers over Python’s os.path functions.

  • STRING to PATHLIKE (PurePath): Convert a path string to a pathlib.PurePath object for type-safe wiring.
  • Backslashes → Forward: Convert Windows backslashes to forward slashes.
  • os.path.abspath / expanduser / basename / dirname / split / splitext / join / exists / isfile / isdir …: Each node mirrors the corresponding os.path function and returns a normalized string. Many accept an optional path input jack so you can provide the value either as a widget or as a link.
  • Most nodes include a forward_slashes option to normalize separators in the output.

Casting helpers (ovum/data)

Lightweight type adapters that help you connect otherwise incompatible sockets.

  • Blind Cast: Reinterpret any value as any type (passes value through unchanged). Exists in a single and list variant.
  • Cast Pyobjects/List to Any: Treat a LIST as any type (*) while keeping list outputs list-shaped.
  • Cast Any to Pyobjects/List: Accept any value and expose it explicitly as LIST (strings become [string]).

More List utilities (Data)

Complements the Pystructure section with additional practical nodes.

  • Unique List / Unique Batch: Remove duplicates while preserving order. Works with hashable and unhashable elements.
  • String List Editor / String Batch Editor: Quickly build a list by typing one item per line in a multiline text box (blank lines ignored).
  • From List Type / From Batch Type: Convert a LIST to tuple, set, dict (index→value), or dict from key/value pairs.
  • List Extend / Batch Extend: Non‑mutating concatenation of two Python lists.

Passthrough shapers (ovum)

A family of “do nothing” nodes that are useful for wiring and debugging.

  • Passthru (single/multi/list variants): Forwards inputs unchanged while letting you explicitly control whether the input and/or output is treated as a list by the graph engine. Helpful when you need to satisfy list/non‑list expectations without changing your data.
  • Pretty/Compact preview: Some variants include compact pretty‑printing of complex values in the UI to make debugging easier (no side effects on the data).

Underscore.js method nodes (ovum/underscore)

NOTE: These are an absolute disaster to use in production. They are a WORK IN PROGRESS and are not recommended for use in workflows. Graph wrappers for underscore3 (a Python port of Underscore.js). They let you chain collection utilities in Comfy.

  • _.CHAIN and _.VALUE: Start a chain with an object (list/dict/etc.) and extract the final value.
  • Method nodes: One node per Underscore method (map, filter, reduce, keys, values, uniq, flatten, zip, range, …). Each has two outputs: the updated chain and the immediate result of that method.
  • Iteratee support: For iteratee‑style methods (e.g., map), you can either provide a simple function via UI inputs or supply an iteratee node class name to build a tiny subgraph automatically that runs per item and collects its chosen output.

Load Image with Workflow + IMAGE_EX Context

File loader and context nodes that expose embedded prompt/workflow metadata along with images.

  • Load Image with Workflow: Like core Load Image, but also extracts embedded prompt/workflow where present. Useful for round‑tripping images with their provenance.
  • Load Image from Output with Workflow: Fetch a previously saved output image and parse its embedded metadata.
  • IMAGE_EX Context: Pass through a single IMAGE_EX dict while optionally overriding image, mask, filepath, prompt, workflow, or edits.
  • IMAGE_EX Context (List): Same as above but for lists. All provided list inputs must be the same length; outputs are lists of images/masks/paths/prompts/workflows/edits.

Loop/Logic nodes (ovum/loop)

Tools for structured iteration and simple branching without illegal graph cycles.

  • ForeachListBeginOvum + ForeachListEndOvum: I think I just stole these from easyUse to learn how they worked!
  • MapStartOvum + MapEndOvum: Like Foreach but auto‑merges each per‑iteration result into an accumulator (typically a list) for you.

Logic helpers (ovum/loop)

Small building blocks used with the loop nodes.

  • IfElseOvum: Simple branch select; returns on_true or on_false based on a BOOLEAN input. Supports lazy inputs so only the chosen branch is evaluated.
  • CompareOvum: Compare two values using ==, !=, <, <=, >, >= and return BOOLEAN.
  • Convert any to INT and add 1 / subtract 1: Utility nodes (PlusOne / MinusOne) that coerce a value to INT and adjust by ±1.
  • Uncachable List Copy (immutable): Forces a fresh copy of a list or the values of a dict every run so that Comfy treats it as changed (useful in loops).

ComboMirror

Mirror the options from any combobox input and drive multiple targets with a single selection.

  • What it does: Connect ComboMirror to a node input that uses a combo-box and it automatically adopts that list of options. Then feed ComboMirror’s output into any number of compatible combo inputs so they all share the same chosen value.
  • Why it’s helpful: Keep several nodes in sync with one picker and reduce repetitive clicking.
  • Outputs: COMBO (the selected value) and LIST (all available option strings mirrored from the target).
  • How to select:
    • Manual: Pick from the mirrored options in the ComboMirror widget (default).
    • choice_index: Provide a non-negative index to force selection by index and disable manual picking.
    • choice_regex: Provide a string/regex to auto-pick. Matching order is:
      1. Regex search (re.search)
      2. Exact match (case-sensitive)
      3. Exact match (case-insensitive)
      4. Substring contains (case-insensitive)
    • If none of the above applies, the current widget value is used.
  • How to use:
    1. Place ComboMirror near a node that has a combobox input (e.g., model, scheduler, sampler).
    2. Connect ComboMirror’s output to that input; the options will be mirrored into the ComboMirror widget.
    3. Pick a value once (or drive via choice_index/choice_regex) and wire the COMBO output to other matching combo inputs to keep them synchronized.

Notes:

  • For advanced workflows the frontend also passes the raw options as a hidden string; the node returns those as the LIST output for inspection or debugging.

VHS PNG deleter (VhsPngDeletingOvum)

Remove intermediate PNG frames produced by Video Helper Suite (VHS) from both your list of filenames and from disk.

  • Category: ovum/workflow
  • Display name: "VHS PNG deleter"
  • Class name: VhsPngDeletingOvum

Inputs

  • filenames (STRING)
    • Accepts a STRING, a list of STRINGs, or a tuple shaped like (BOOLEAN, LIST[STRING]) as produced by some VHS nodes.
    • If a list or tuple is provided, the node will treat the inner list as a list of file paths.

Outputs

  • filenames (STRING)
    • Mirrors the input structure:
      • If input was a list, returns a filtered list with .png items removed.
      • If input was a tuple (flag, list), returns (flag, filtered_list) with the same flag preserved.
      • Otherwise returns the input unchanged.

Behavior

  • For list inputs (or the list inside a supported tuple):
    • Removes any entries that end with the .png extension (case-insensitive).
    • Attempts to delete those .png files from the filesystem (silently ignores errors if a file cannot be removed).
    • Returns the remaining non-.png filenames.
  • For non-list inputs, simply returns the input unchanged.

Example

(True,
  ['C:\\zluda\\comfyui-n\\output\\WanVideo2_2_T2V_VHS_01102.png',
   'C:\\zluda\\comfyui-n\\output\\WanVideo2_2_T2V_VHS_01102.mp4'])

becomes

(True,
  ['C:\\zluda\\comfyui-n\\output\\WanVideo2_2_T2V_VHS_01102.mp4'])

Notes

  • This is useful after VHS video assembly steps when you want to clean up temporary PNG frames.

Burn Notice

A small utility node for ephemeral text that should be consumed once and then disappear. It exposes a multiline STRING input and immediately returns it on execution, but the UI clears the field afterward. Optionally, the node can auto‑mute itself so it won’t execute again until you unmute it.

  • Category: ovum/util
  • Display name: "Burn Notice"
  • Class name: BurnNoticeOvum

Inputs

  • value (STRING, multiline)
    • Arbitrary text. This is returned as the output on execution. After execution completes, the UI clears this field so it doesn’t persist into the next run.
  • mute_after (BOOLEAN, default: false)
    • When enabled, the frontend mutes the node after it runs (equivalent to LiteGraph mode = 2). This prevents the node from executing again until you manually unmute it from the node’s context menu.

Outputs

  • value (STRING)
    • Exactly the text that was provided at execution time.

Behavior and notes

  • The backend simply returns the provided string; all “erase after read” behavior is handled in the frontend extension.
  • After onExecuted, the UI:
    • Sets the "value" widget to an empty string.
    • If mute_after is true, sets node.mode = 2 (mute) and marks the canvas dirty so the UI updates immediately.
  • Practical uses: one‑shot messages, tokens, secrets, ad‑hoc parameters, or any text you intend to consume once and then remove from the workflow state.

Colorize Graph

A frontend-only utility node that recolors all nodes in the current graph based on the type of the first input (if any), else the first output. It uses the same color mapping SetTwinNodes, which is an extended version of Kijai's SetNode coloring scheme.

  • Category: ovum
  • Display name: "Colorize Graph"
  • Node type: ColorizeGraph (frontend)

Buttons

  • Apply Colors: Recolors every node according to the type heuristic described above.
  • Undo: Restores all nodes to their original colors from before the last Apply Colors.

Notes

  • Skips recoloring itself.
  • Works entirely in the browser; no backend execution is involved.
  • If you click Apply Colors multiple times, Undo restores the colors as they were before the first apply in that session.

Get Setting (Ovum/Utils)

A lightweight utility node that reads a value from the workflow "settings" snapshot shared by the frontend. It lets you reference run-time settings (like user preferences or UI-level parameters) inside your graph without extra wiring.

  • Category: ovum/utils
  • Display name: "Get Setting"
  • Python class: GetSettingOvum

What it does

  • Exposes a COMBO selector of available setting keys (populated by the frontend).
  • Returns the current value for the selected key (type is "*" to allow any type).
  • Mirrors the resolved value into a read-only STRING field (value_out) for quick inspection.

Inputs

  • setting (COMBO, required): The setting key to read. The options are populated by the frontend.

Optional/Hidden

  • value_out (STRING, optional, readonly): Text view of the resolved value.
  • extra_pnginfo (hidden): Provided by Comfy; used to obtain the workflow settings snapshot.

Output

  • value (*): The actual setting value from the workflow settings object. If the key doesn’t exist, the node returns None. The type of this output will change to match the type of the setting key.

Notes

  • Prefers workflow.settings when present; otherwise falls back to workflow.extra.settings in the PNG workflow blob.
  • The node does not mutate any data; it only reads.

New Multi-type Dictionary

New Multi-type Dictionary example

Build a Python DICT from multiple dynamic inputs whose keys come from the input labels you set in the graph. Each input can accept any type, so you can mix simple scalars and complex objects in a single dictionary.

What it does

  • Creates inputs named key-value-1, key-value-2, ... as you connect them. You can rename the visible label of each input; that label becomes the dictionary key.
  • Supports any ComfyUI type on the value side (images, lists, dicts, numbers, strings, etc.). The node returns a single DICT containing one entry per connected input.
  • Preserves your custom labels: once you change an input label away from its default, it won’t be auto‑overwritten by dynamic input maintenance.
  • Works reliably with API runs: the frontend stores a mapping of input names to labels in the workflow extras so the Python backend knows your chosen keys at execution time.

How it works

  • UI side (JS): The node manages dynamic inputs with the pattern key-value-n. When the last input becomes linked, a new empty input is added; when you disconnect, extra trailing empty inputs are trimmed. During graphToPrompt, the UI writes an array of [inputName, label] pairs into workflow.extra under the key ovum.multi.dict:(<nodeId>).
  • Backend (Python): At run time, the node reads that mapping from extra_pnginfo and builds the dictionary using the labels as keys and the connected input values as values. If a label is missing, it falls back to the input name.

Example (screenshot above)

  • The top-left Get Setting outputs a complex DICT (type: HIDDEN in settings, displayed as JSON). Its link goes into the New Multi‑type Dictionary input whose label is set to disabledExtensions. That key stores the entire dict object under "disabledExtensions".
  • The bottom-left Get Setting outputs a COMBO value (effectively an INT with value 2). Its link goes into the input labeled linkRenderMode. That key stores the integer 2 under "linkRenderMode".
  • The resulting dictionary has two entries: {"disabledExtensions": <DICT>, "linkRenderMode": 2}.

Inputs

  • key-value-n (*): Dynamic inputs that accept any type. Change the input label to set the dictionary key. The default label matches the input name (e.g., key-value-1) until you customize it.
  • unique_id, extra_pnginfo, prompt (hidden): Standard Comfy plumbing; extra_pnginfo carries the label mapping from the UI.

Output

  • dict (DICT): A dictionary with one entry per connected input using your labels as keys.

Tips

  • Use meaningful labels like seed, strength, disabledExtensions to make the resulting dict self‑documenting.
  • You can wire in non‑scalar values (lists, dicts, images); the node keeps their native types.

Index of Node Classes

Below is an index of Python class names for nodes in this repository. Each entry links to the section in this README where the node or its family is documented; entries marked as "undocumented" currently have no dedicated section.

  • AmdNvidiaIfElseOvum — undocumented
  • AssertOvum — undocumented
  • BigKnob — see BigKnob (Widget): #bigknob-widget
  • BurnNoticeOvum — see Burn Notice: #burn-notice
  • CUDNNToggleOvum — see CUDNN Toggle Ovum: #cudnn-toggle-ovum
  • CastAnyToList — see Casting helpers: #casting-helpers-ovumdata
  • CastListToAny — see Casting helpers: #casting-helpers-ovumdata
  • ColorizeGraph — see Colorize Graph: #colorize-graph
  • ComboMirrorOvum — see ComboMirror: #combomirror
  • CommandExecNode — undocumented
  • ConcatBatchesOvum — undocumented
  • ConcatLists — see Pystructure Data Nodes: #pystructure-data-nodes-complementary-to-comfyui-logicutils
  • ConcatListsOvum — see More List utilities (Data): #more-list-utilities-data
  • ConvertAny2Dict — undocumented
  • ConvertAny2List — undocumented
  • ConvertAny2Set — undocumented
  • ConvertAny2Tuple — undocumented
  • CreateEmptyList — undocumented
  • FolderPathsNode — see Image List Loader + Folder Paths: #image-list-loader--folder-paths
  • ForeachListBeginOvum — see Loop/Logic nodes: #looplogic-nodes-ovumloop
  • ForeachListEndOvum — see Loop/Logic nodes: #looplogic-nodes-ovumloop
  • FromBatchTypeNodeOvum — undocumented
  • FromListTypeNode — see Pystructure Data Nodes: #pystructure-data-nodes-complementary-to-comfyui-logicutils
  • FromListTypeNodeOvum — see More List utilities (Data): #more-list-utilities-data
  • GetByIndex — see More List utilities (Data): #more-list-utilities-data
  • GetEnvVar — see Environment Bridge: #environment-bridge-set-environment-variable-and-get-environment-variable
  • GetListLength — undocumented
  • GetLocalStorage — see Browser Local Storage: #browser-local-storage-set-localstorage-and-get-localstorage
  • GetSettingOvum — see Get Setting: #get-setting-ovumutils
  • Ground — undocumented
  • IfElseOvum — see Logic helpers: #logic-helpers-ovumloop
  • ImageExContextListOvum — see Load Image with Workflow + IMAGE_EX Context: #load-image-with-workflow--image_ex-context
  • ImageExContextOvum — see Load Image with Workflow + IMAGE_EX Context: #load-image-with-workflow--image_ex-context
  • IndexOf — see Pystructure Data Nodes: #pystructure-data-nodes-complementary-to-comfyui-logicutils
  • IndexOfBatchOvum — undocumented
  • IndexOfOvum — see More List utilities (Data): #more-list-utilities-data
  • JoinBatchOvum — undocumented
  • JoinList — see Pystructure Data Nodes: #pystructure-data-nodes-complementary-to-comfyui-logicutils
  • JoinListOvum — see More List utilities (Data): #more-list-utilities-data
  • LMStudioPromptOvum — see LM Studio Prompt (Ovum/LLM): #lm-studio-prompt-ovumllm
  • LMStudioUnloadOvum — see LM Studio Unload (Ovum/LLM): #lm-studio-unload-ovumllm
  • ListExtend — see Pystructure Data Nodes: #pystructure-data-nodes-complementary-to-comfyui-logicutils
  • ListExtendOvum — see More List utilities (Data): #more-list-utilities-data
  • ListSlice — see Pystructure Data Nodes: #pystructure-data-nodes-complementary-to-comfyui-logicutils
  • ListSliceOvum — see More List utilities (Data): #more-list-utilities-data
  • ListSplice — see Pystructure Data Nodes: #pystructure-data-nodes-complementary-to-comfyui-logicutils
  • ListSpliceOvum — see More List utilities (Data): #more-list-utilities-data
  • LiveCrop — see Live Crop (interactive): #live-crop-interactive
  • LoadImageFromOutputWithWorkflowOvum — see Load Image with Workflow + IMAGE_EX Context: #load-image-with-workflow--image_ex-context
  • LoadImageWithWorkflowOvum — see Load Image with Workflow + IMAGE_EX Context: #load-image-with-workflow--image_ex-context
  • LoadImagesListWithCallback — see Image List Loader + Folder Paths: #image-list-loader--folder-paths
  • MakeFlatImageList — see More List utilities (Data): #more-list-utilities-data
  • MakeFlatStringList — see More List utilities (Data): #more-list-utilities-data
  • MapEndOvum — see Loop/Logic nodes: #looplogic-nodes-ovumloop
  • MapStartOvum — see Loop/Logic nodes: #looplogic-nodes-ovumloop
  • MinusOne — see Logic helpers: #logic-helpers-ovumloop
  • NewMultiDictionaryOvum — see New Multi‑type Dictionary: #new-multi‑type-dictionary
  • NextVideoFilenameOvum — see VHS Helper: Next Video Filename: #vhs-helper-next-video-filename
  • OpenOutputViaShell — see Open Output via Shell (secure): #open-output-via-shell-secure
  • OvumCombinePaths — see OS Path Utilities: #os-path-utilities-ovumpath-and-ovumpathospath
  • OvumOsPathAbspath — see OS Path Utilities: #os-path-utilities-ovumpath-and-ovumpathospath
  • OvumOsPathBasename — see OS Path Utilities: #os-path-utilities-ovumpath-and-ovumpathospath
  • OvumOsPathCommonPath — see OS Path Utilities: #os-path-utilities-ovumpath-and-ovumpathospath
  • OvumOsPathCommonPrefix — see OS Path Utilities: #os-path-utilities-ovumpath-and-ovumpathospath
  • OvumOsPathDirname — see OS Path Utilities: #os-path-utilities-ovumpath-and-ovumpathospath
  • OvumOsPathExists — see OS Path Utilities: #os-path-utilities-ovumpath-and-ovumpathospath
  • OvumOsPathExpanduser — see OS Path Utilities: #os-path-utilities-ovumpath-and-ovumpathospath
  • OvumOsPathExpandvars — see OS Path Utilities: #os-path-utilities-ovumpath-and-ovumpathospath
  • OvumOsPathGetAtime — see OS Path Utilities: #os-path-utilities-ovumpath-and-ovumpathospath
  • OvumOsPathGetCtime — see OS Path Utilities: #os-path-utilities-ovumpath-and-ovumpathospath
  • OvumOsPathGetMtime — see OS Path Utilities: #os-path-utilities-ovumpath-and-ovumpathospath
  • OvumOsPathGetSize — see OS Path Utilities: #os-path-utilities-ovumpath-and-ovumpathospath
  • OvumOsPathIsAbs — see OS Path Utilities: #os-path-utilities-ovumpath-and-ovumpathospath
  • OvumOsPathIsdir — see OS Path Utilities: #os-path-utilities-ovumpath-and-ovumpathospath
  • OvumOsPathIsfile — see OS Path Utilities: #os-path-utilities-ovumpath-and-ovumpathospath
  • OvumOsPathIslink — see OS Path Utilities: #os-path-utilities-ovumpath-and-ovumpathospath
  • OvumOsPathIsmount — see OS Path Utilities: #os-path-utilities-ovumpath-and-ovumpathospath
  • OvumOsPathJoin — see OS Path Utilities: #os-path-utilities-ovumpath-and-ovumpathospath
  • OvumOsPathLexists — see OS Path Utilities: #os-path-utilities-ovumpath-and-ovumpathospath
  • OvumOsPathNormCase — see OS Path Utilities: #os-path-utilities-ovumpath-and-ovumpathospath
  • OvumOsPathNormPath — see OS Path Utilities: #os-path-utilities-ovumpath-and-ovumpathospath
  • OvumOsPathRealpath — see OS Path Utilities: #os-path-utilities-ovumpath-and-ovumpathospath
  • OvumOsPathRelpath — see OS Path Utilities: #os-path-utilities-ovumpath-and-ovumpathospath
  • OvumOsPathSamefile — see OS Path Utilities: #os-path-utilities-ovumpath-and-ovumpathospath
  • OvumOsPathSplit — see OS Path Utilities: #os-path-utilities-ovumpath-and-ovumpathospath
  • OvumOsPathSplitAll — see OS Path Utilities: #os-path-utilities-ovumpath-and-ovumpathospath
  • OvumOsPathSplitdrive — see OS Path Utilities: #os-path-utilities-ovumpath-and-ovumpathospath
  • OvumOsPathSplitext — see OS Path Utilities: #os-path-utilities-ovumpath-and-ovumpathospath
  • OvumPathBackToForward — see OS Path Utilities: #os-path-utilities-ovumpath-and-ovumpathospath
  • OvumPathToPathLike — see OS Path Utilities: #os-path-utilities-ovumpath-and-ovumpathospath
  • OvumReEscape — see Regex Nodes: #regex-nodes-ovumregex
  • OvumReFindAll — see Regex Nodes: #regex-nodes-ovumregex
  • OvumReFindIter — see Regex Nodes: #regex-nodes-ovumregex
  • OvumReFlags — see Regex Nodes: #regex-nodes-ovumregex
  • OvumReFullMatch — see Regex Nodes: #regex-nodes-ovumregex
  • OvumReMatch — see Regex Nodes: #regex-nodes-ovumregex
  • OvumReMatchExpand — see Regex Nodes: #regex-nodes-ovumregex
  • OvumReMatchGroup — see Regex Nodes: #regex-nodes-ovumregex
  • OvumReMatchInfo — see Regex Nodes: #regex-nodes-ovumregex
  • OvumReMatchSelect — see Regex Nodes: #regex-nodes-ovumregex
  • OvumReMatchSpan — see Regex Nodes: #regex-nodes-ovumregex
  • OvumReMatchView — see Regex Nodes: #regex-nodes-ovumregex
  • OvumReSearch — see Regex Nodes: #regex-nodes-ovumregex
  • OvumReSplit — see Regex Nodes: #regex-nodes-ovumregex
  • OvumReSub — see Regex Nodes: #regex-nodes-ovumregex
  • OvumReSubN — see Regex Nodes: #regex-nodes-ovumregex
  • OvumWildcardProcessor — see Wildcard Processor (Escapable): #wildcard-processor-escapable
  • PassthruInputAndOutputIsListOvum — see Passthrough shapers: #passthrough-shapers-ovum
  • PassthruInputIsListOvum — see Passthrough shapers: #passthrough-shapers-ovum
  • PassthruOutputIsListOvum — see Passthrough shapers: #passthrough-shapers-ovum
  • PassthruOvum — see Passthrough shapers: #passthrough-shapers-ovum
  • PlusOne — see Logic helpers: #logic-helpers-ovumloop
  • PythonStringFormat — see Python String Format: #python-string-format
  • RepeatItem — see Pystructure Data Nodes: #pystructure-data-nodes-complementary-to-comfyui-logicutils
  • RepeatItemBatchOvum — undocumented
  • RepeatItemOvum — see More List utilities (Data): #more-list-utilities-data
  • ReverseBatchOvum — undocumented
  • ReverseList — see Pystructure Data Nodes: #pystructure-data-nodes-complementary-to-comfyui-logicutils
  • ReverseListOvum — see More List utilities (Data): #more-list-utilities-data
  • SetEnvVar — see Environment Bridge: #environment-bridge-set-environment-variable-and-get-environment-variable
  • SetLocalStorage — see Browser Local Storage: #browser-local-storage-set-localstorage-and-get-localstorage
  • StringListEditor — see Pystructure Data Nodes: #pystructure-data-nodes-complementary-to-comfyui-logicutils
  • StringListEditorOvum — see More List utilities (Data): #more-list-utilities-data
  • SyncSinkOvum — see Workflow Helpers: #workflow-helpers-widgets-to-values
  • TextOvary — see Text Ovary (overlay text on images): #text-ovary-overlay-text-on-images
  • Timer — see Timer: #timer
  • UniqueList — see Pystructure Data Nodes: #pystructure-data-nodes-complementary-to-comfyui-logicutils
  • UniqueListOvum — see More List utilities (Data): #more-list-utilities-data
  • VhsPngDeletingOvum — see VHS PNG deleter: #vhs-png-deleter-vhspngdeletingovum
  • WidgetToBooleanOvum — see Workflow Helpers: #workflow-helpers-widgets-to-values
  • WidgetToFloatOvum — see Workflow Helpers: #workflow-helpers-widgets-to-values
  • WidgetToIntOvum — see Workflow Helpers: #workflow-helpers-widgets-to-values
  • WidgetToStringOvum — see Workflow Helpers: #workflow-helpers-widgets-to-values
  • WorkflowWidgetToAnyOvum — see Workflow Helpers: #workflow-helpers-widgets-to-values
  • XRangeNode — see Folder, Range, and Sequence Utilities: #folder-range-and-sequence-utilities