CMK Mask Detailer Flow Gate
The Switch That Decides Whether Your Detail Pass Runs At All
- MODEL BYPASS
- PROCESS BYPASS
- IMAGE BYPASS
- LOG BYPASS
- VISUAL BYPASS
- MODEL ACTIVE
- PROCESS ACTIVE
- IMAGE ACTIVE
- LOG ACTIVE
- VISUAL ACTIVE
- MODEL
- MASK DETAILER PROCESS
- IMAGE
- LOG
- VISUAL
A gate is the least glamorous node in any workflow, and the one you'll end up cursing the least. This one sits between "I have a painted mask, detail it" and "I don't have a mask yet, just give me my image back," and it decides which of those two graphs gets evaluated.
CMK Mask Detailer Flow Gate is a CMK/Developer/Internal node - you'll see it inside CMK's shipped workflows and in the Flow Browser, but you won't find it by browsing the node menu with a beginner's eyes.
How the switching actually works
One required widget: enabled, default true.
The clever part is READY. That optional input is fed by Mask Detailer · Intake, which only sets it true once a locked snapshot and a non-empty painted mask both exist. So the gate is doing:
active = enabled AND READY
If both are true, it routes the five * ACTIVE inputs to the outputs. Otherwise it routes the five * BYPASS inputs - the untouched image, the original model, the original log, and a visual provider registered with status="disabled" or "waiting" so the Visualizer shows you a labelled pass-through rather than nothing at all.
That means an unpainted mask doesn't fail. It quietly passes your image through, which is exactly the behaviour you want at 2am and exactly the behaviour that makes you stare at a result wondering why nothing changed.
Why it's built on lazy evaluation
Every one of those ten optional inputs is declared lazy: True, and the gate implements check_lazy_status to request only the branch it's about to use. This is not decoration. It's the mechanism that makes the freeze real: when the gate picks the bypass branch, the detailer branch's upstream nodes are never evaluated, so no sampling happens and no cache gets dirtied. ComfyUI's engine supports this - a node tells the executor which inputs it needs before they're computed - and it's the reason gates like this one exist in packs that care about not burning GPU time.
The _pending_connected_visual helper is a nice detail: if VISUAL BYPASS is wired but hasn't produced a value, the gate explicitly asks for it before finishing, so the Visualizer doesn't end up with a stale panel from the previous run.
Inputs and outputs at a glance
Required: enabled (BOOLEAN, default true).
Optional, bypass side: READY, MODEL BYPASS, PROCESS BYPASS, IMAGE BYPASS, LOG BYPASS, VISUAL BYPASS.
Optional, active side: MODEL ACTIVE, PROCESS ACTIVE, IMAGE ACTIVE, LOG ACTIVE, VISUAL ACTIVE.
Outputs, in this order: MODEL (CMK_MODEL_PIPE), MASK DETAILER PROCESS (CMK_MASK_DETAILER_PROCESS), IMAGE, LOG (CMK_LOG_PIPE), VISUAL (CMK_VISUAL_PIPE).
The bypass path still manufactures a valid process object - it takes the incoming process metadata and stamps mask_detailer_bypassed: true with a reason of either "disabled" or "snapshot not ready". That reason string is your debugging breadcrumb.
Install
Part of the pack: ComfyUI Manager → search CMK Flow → install from CMKFlow → restart. Manual:
git clone https://github.com/CMKFlow/cmk_nodes.git custom_nodes/cmk_nodes
python3 custom_nodes/cmk_nodes/scripts/install_cmk_requirements.py
CMK dependency check: OK means you're done.
Traps
It raises if a connected branch input is missing. Feed it IMAGE ACTIVE but forget MODEL ACTIVE, and it errors with a comma-separated list rather than guessing. That's intentional and it's a better failure than a silent fallback.
enabled off does not mean "no wires needed." Turning the gate off still requires the bypass inputs to be connected, because the bypass path is a real path through the graph, not a skip.
Two enable levels exist in this pack, and they're not the same thing. The architecture docs distinguish a GLOBAL enable (does this module participate) from a LOCAL enable (does this particular parallel instance run). Effective activation is the AND of the two. If you're hunting a module that refuses to run, check both.
Inputs (12)
| Name | Type | Default | Description |
|---|---|---|---|
| enabled | BOOLEAN | true | — |
| READYopt | BOOLEAN | — | |
| MODEL BYPASSopt | CMK_MODEL_PIPE | — | |
| PROCESS BYPASSopt | * | — | |
| IMAGE BYPASSopt | IMAGE | — | |
| LOG BYPASSopt | CMK_LOG_PIPE | — | |
| VISUAL BYPASSopt | CMK_VISUAL_PIPE | — | |
| MODEL ACTIVEopt | CMK_MODEL_PIPE | — | |
| PROCESS ACTIVEopt | CMK_MASK_DETAILER_PROCESS | — | |
| IMAGE ACTIVEopt | IMAGE | — | |
| LOG ACTIVEopt | CMK_LOG_PIPE | — | |
| VISUAL ACTIVEopt | CMK_VISUAL_PIPE | — |
Outputs (5)
| Name | Type | Description |
|---|---|---|
| MODEL | CMK_MODEL_PIPE | — |
| MASK DETAILER PROCESS | CMK_MASK_DETAILER_PROCESS | — |
| IMAGE | IMAGE | — |
| LOG | CMK_LOG_PIPE | — |
| VISUAL | CMK_VISUAL_PIPE | — |