comfy-conditionals

v2026.09.24

ComfyUI predicate/boolean nodes: compare, AND/OR/XOR/NOT, ternary, null/empty/type probes, ExecutionBlocker. Use when forming the boolean that drives a workflow switch or blocker.

GitHub
Install command
npx skhub add laurigates/comfy-conditionals
Markdown
SKILL.md

ComfyUI conditionals

Predicates → boolean → branch. How the decision is formed, not where the signal goes after.

Four packs contribute predicate primitives. The split:

PackPrimary niche
comfyui-easy-useeasy ifElse, easy compare, easy blocker, and the easy is* probes — the broadest, most-used predicate kit
comfyui-impact-packImpactCompare + ImpactConditionalBranch (lazy) + ImpactIfNone + ImpactConditionalStopIteration (Impact-iterator loop control)
comfyui_essentialsSimpleCondition (ternary), SimpleComparison (typed, epsilon-aware), SimpleMathCondition (boolean from math)
comfyui-logicutilsBit-banging + regex-on-strings logic gates: AContainsB, bitwise And/Or/Xor/Not/Shift, generic Invert

When to Use This Skill

Use this skill when...Use instead when...
Forming the boolean/predicate that drives a switch or blocker in a workflowRouting the signal after the decision is made -> comfy-flow-control
Comparing values, combining booleans, detecting null/emptyComputing a numeric (non-boolean) value -> comfy-math-strings

Sources of truth

  • custom_nodes/comfyui-easy-use/py/nodes/logic.py — ifElse, compare, blocker, is* probes
  • custom_nodes/comfyui-impact-pack/modules/impact/special_samplers.py — ImpactCompare, ImpactConditionalBranch
  • custom_nodes/comfyui_essentials/misc.py — SimpleMath / SimpleCondition / SimpleComparison
  • custom_nodes/comfyui-logicutils/logic_gates.py — logic gate nodes

Which compare node?

NeedBest nodeWhy
Compare two ANY values, any op (==, !=, <, >, <=, >=)easy compareMulti-op switcher widget, no type lock
Compare two INT/FLOAT, return BOOLEANImpactCompareOp picker (a=b, a<>b, a>b, a<b, a>=b, a<=b, tt/ff constants)
Compare two FLOAT with epsilon toleranceSimpleComparison (essentials)Floats are unsafe under == — epsilon-aware
Compare a string against a regex / substringLogicGateCompareString / AContainsB (logicutils)The only regex-on-string predicate available
Quick math → boolean (e.g. (a+b) > c)SimpleMathConditionComputes the expression and returns BOOLEAN in one node
Detect null / unwired inputeasy isNone or ImpactIfNoneReturns BOOLEAN + passes value through
Detect empty mask (all zeros)easy isMaskEmptySpecifically tests MASK type
Detect SDXL vs SD1 modeleasy isSDXLProbes CLIP / pipe and identifies arch
Detect file path exists on diskeasy isFileExistFor input-validation gates

Type coercion footgun

ImpactConditionalBranch.cond is BOOLEAN. Don't feed it:

  • SimpleMathCondition output → that's FLOAT (0.0 / 1.0) — convert via comparator first
  • easy compare output → that IS BOOLEAN, fine
  • LogicGateCompare output → BOOLEAN, fine
  • A raw INT from a math node → not BOOLEAN; pass through ImpactCompare (a > 0) or convert

When in doubt, route through easy compare and pick the comparison operator that yields the boolean you want.

Boolean algebra

For combining multiple predicates into one branch input:

OperatorNode
AND / OR / XORImpactLogicalOperators (op picker)
NOTImpactNeg
Bit-wise AND / OR / XOR / NOT / shiftlogicutils LogicGateBitwiseAnd etc. (work on INT, not BOOLEAN)
Generic invert (works on any truthy/falsy)LogicGateInvertBasic
isMaskEmpty(face_mask) ──┐
                         ▼
                ImpactNeg (NOT)  ──┐
                                   ▼
            ImpactLogicalOperators (AND) ──→ ImpactConditionalBranch
                                   ▲
isFileExist(reference.png) ────────┘

This combination says: "face mask is non-empty AND reference image exists on disk → run the detailer branch".

Branching

Lazy if-then-else (skips the discarded branch)

NodeBehavior
easy ifElseBOOLEAN selector, on_true / on_false inputs; only the chosen one is evaluated upstream
ImpactConditionalBranchBOOLEAN cond; lazy tt_value / ff_value inputs
ImpactConditionalBranchSelModeSame, but selection happens at execution time rather than prompt-queue time — needed when cond depends on something computed earlier in the same queue

These are predicate-side nodes that ALSO act as switches — they form the boolean and route in one step. If your predicate is simple (one comparison) and the branches are large (samplers, models), ImpactConditionalBranch is the cleanest single-node solution.

If the predicate is complex (multi-criteria), form it explicitly in this skill's primitives, then pass the resulting BOOLEAN to a switch from comfy-flow-control.

Ternary (compute, don't route)

SimpleCondition (essentials) — given condition, returns value_if_true or value_if_false. Both inputs are computed (eager), so it's a value picker, not an execution gate. Use it for selecting between two constants or already-computed scalars; never for selecting between sampler chains.

ExecutionBlocker — the kill-path primitive

easy blocker is the canonical "kill this path" node. Behavior:

  • Input: any value + continue BOOLEAN.
  • If continue=True: pass the value through unchanged.
  • If continue=False: returns an ExecutionBlocker sentinel.

The sentinel propagates downstream: any node that receives an ExecutionBlocker on any input is silently skipped (its execute() is never called). The skip cascades through the rest of the graph downstream of the blocker.

LoadImage ── easy compare (size > 1024) ─┐
                                         ▼
LoadImage ──────────────► easy blocker ───► ResizeImage ─► KSampler ─► SaveImage
                            ▲ continue

When the loaded image is smaller than 1024px, the blocker fires; ResizeImage / KSampler / SaveImage are all skipped without errors.

ExecutionBlocker gotchas

  • Preview Bridge swallows the sentinel — see comfy-flow-control gotchas. The blocker fires, but a Preview Bridge tee downstream reports nothing visibly, and fails to propagate the abort. Use FastPreview (kjnodes) downstream of a blocker if you need visual confirmation.
  • Cannot be visualized — there's no "is this currently blocked?" light. Add an easy showAnything on the BOOLEAN that drives the blocker to confirm at queue time.
  • No partial recovery — once a path is blocked, every downstream node in that chain is skipped, period. To preserve a parallel path through the same upstream value, tee BEFORE the blocker, not after.

Null / empty / type probes

ProbeReturns BOOLEAN when
easy isNoneInput is None / unwired / a placeholder
ImpactIfNoneSame, plus passes the non-None value through (combines probe + pass-through)
easy isMaskEmptyAll mask pixels are zero (no positive area)
easy isFileExistFilesystem path resolves to a real file
easy isSDXLThe CLIP / pipe / model identifies as SDXL architecture

Use cases:

  • Detector pipelines: isMaskEmpty(face_mask) → blocker to skip detailer when no face is found.
  • Optional reference image: isFileExist(ref_path) → switch between "use reference" and "no reference" branches.
  • Multi-architecture workflows that need different sampler defaults: isSDXL(pipe) → switch sampler configuration.

Logicutils — strings, bits, regex

comfyui-logicutils is the sole source for:

  • Regex / substring on strings — LogicGateCompareString (also registered as AContainsB). Pass a regex pattern in b, a string in a, get BOOLEAN.
  • Bitwise integer ops — for flags packed into a single INT. Niche; mostly useful when interfacing with external systems that send flag bitmasks.
  • LogicGateInvertBasic — generic invert that handles any truthy/falsy input (more lenient than ImpactNeg, which expects strict BOOLEAN).

Iterator stop

ImpactConditionalStopIteration — only useful inside an Impact detector→detailer iterator loop. Takes a BOOLEAN; when True, halts the iterator's next round. The iterator must support stop signals (detector-pipeline variants do; non-iterating Impact paths ignore it).

Recipes

Skip face-detailer when no face detected

LoadImage ──► BBoxDetector ──► IMAGE/MASK output
                                    │
                                    ▼
                            easy isMaskEmpty ──► (BOOLEAN)
                                                    │
                                                    ▼ (invert: empty → skip)
                                              ImpactNeg
                                                    │
                                                    ▼
                            ┌───────► easy blocker ◄────── (the image+mask payload)
                            │           continue
                            ▼
                  (downstream FaceDetailer chain, silently skipped on empty)

isMaskEmpty → True when no face found → ImpactNeg flips it → False → blocker fires → FaceDetailer + SaveImage chain is skipped without error.

Multi-criteria gate

"Run the high-quality upscale path only if the image is large AND the reference exists AND we're not in SDXL mode":

GetImageSize&Count(image) ──► width  ──► easy compare (> 1024) ──┐ (BOOL)
                                                                  │
easy isFileExist(ref_path) ──► (BOOL) ───────────────────────────┤
                                                                  │
easy isSDXL(pipe) ──► ImpactNeg (NOT SDXL) ──► (BOOL) ───────────┤
                                                                  ▼
                                              ImpactLogicalOperators (AND of 3)
                                                                  │
                                                                  ▼
                                                  ImpactConditionalBranch
                                                  tt = upscale chain
                                                  ff = passthrough

Three independent predicates combined with AND. The downstream branch is fully lazy: when any predicate is False, none of the upscale chain runs.

Distinguish "first run" from "rerun" via file existence

Useful for caching: if an output file already exists, skip regeneration.

easy isFileExist("output/cached_step1.png") ──► (BOOL)
                                                  │
                                                  ▼
                                  ImpactConditionalBranch
                                  tt = LoadImage from cache
                                  ff = run full pipeline + SaveImage

Gotchas

  • Floats and equality: easy compare with == on FLOATs is a trap. Use SimpleComparison (epsilon-aware) or easy compare with < / > instead. 1.0 + 2.0 == 3.0 is True, but 0.1 + 0.2 == 0.3 is False.
  • Lazy branch + ComfyExecutionBlocker: lazy nodes (easy ifElse, ImpactConditionalBranch) won't evaluate the unselected branch, but they pass through whatever node-graph value the selected branch produces — including an ExecutionBlocker sentinel. If both branches can emit blockers, plan the merge carefully.
  • SimpleMathCondition returns FLOAT (1.0 / 0.0), not BOOLEAN. Pass through ImpactCompare (> 0.5) before feeding a switch that wants BOOLEAN.
  • easy isNone on a pipe: pipes (PIPE_LINE) are tuples — isNone returns False on an empty pipe (the tuple exists, just with None fields). To detect missing pipe content, unpack with pipeOut and probe individual fields.
  • AContainsB is regex, not substring: special characters need escaping. To do a plain substring check, escape with \Q...\E or use Python regex-special escapes manually.

Cross-refs

  • comfy-flow-control — once the boolean is formed, this skill points at the switches that consume it (typed switches, ExecutionBlocker propagation, broadcast routing).
  • comfy-math-strings — math primitives that feed comparisons (constants, sliders, SimpleMath expressions, GetImageSize&Count outputs).
  • comfy-debug-preview — ShowAnything / ShowText for inspecting the BOOLEAN being passed to a branch at queue time.

Things this skill does NOT cover

  • Switching / routing AFTER the decision — that's comfy-flow-control.
  • Numerical computation that doesn't yield a BOOLEAN — arithmetic, math expressions, string formatting → comfy-math-strings.
  • Image / mask manipulation upstream of the probe — getting a mask in the first place via segmentation, detection, etc. is model-inference work, not utility.
  • Sampler-time conditionals — model_sampling, CFG scheduling, step gating within the diffusion loop is sampler/model territory, not workflow logic.
Discovery
Tags

No tags published for this skill.

Version
Latest version metadata

Version

v2026.09.24

Published

Sep 24, 2026

Category

Uncategorized

License

MIT

Source path

comfyui-plugin/skills/comfy-conditionals

Default branch

main

Latest commit

1668324

Tree SHA

b2d4cc3