CMK Boundary Cache
Why Your Unchanged FaceSwap Branch Doesn't Run Twice
- MODEL (opt)
- IMAGE
- LOG
- diagnostic
- MODEL
- IMAGE
- LOG
- diagnostic
This is a developer node. If you load a CMK reference workflow you'll see it sitting after the FaceSwap module, quietly passing four things along, and you'll wonder why it exists at all. The answer is that it's the module's cache boundary - the thing that makes "run this branch again" cheap when nothing in the branch changed.
The problem it solves
ComfyUI's own caching works backwards from output nodes and re-executes anything it thinks might have changed. That's fine for a linear graph. It gets expensive and unpredictable when a subgraph is expanded lazily, when one module has both an enabled and a disabled path, and when a video-length swap costs minutes. CMK handles that with its own module boundaries: a node that deliberately materialises the whole module result once, fingerprints it, and reuses it inside the session.
CMK Boundary Cache is that boundary for the closed FaceSwap subgraph. Its own docstring is blunt about the contract: MODEL is read-only and never serialised, while IMAGE, LOG and the complete diagnostic payload are materialised together so every public module output and internal preview consumes the same authoritative result. No path gets a slightly different image because it asked the module at a different moment.
How it works
The node fingerprints the whole upstream chain - the prompt graph, node identity, its own schema version - and stores that fingerprint with the materialised result. That's why the cache is version-tagged (cmk_faceswap_boundary_v4): bump the schema and every stale entry is invalid, instead of a half-updated boundary handing out mismatched images.
Inputs are all lazy and all optional, which is the interesting part:
MODEL (opt)- pass-through only, never cached.IMAGE- the swapped result.LOG- the module's log blocks.diagnostic- the full payload.
Laziness is doing real work here. The node asks ComfyUI for only what it actually needs in a given state, so a disabled module doesn't drag the expensive swap path into existence just to hand it a placeholder.
Outputs mirror the inputs one-for-one: MODEL, IMAGE, LOG, diagnostic, all types the next CMK module or the Visualizer consumes.
What the cache does and doesn't survive
The cache files live under ComfyUI/temp/cmk/. The first run after a restart, a code change or a cache clear logs a MISS → STORED. Subsequent runs where nothing upstream moved should log a HIT and skip the expensive work. Parallel unchanged branches and completed module boundaries are the design case: one branch changes, its merge and boundary update, and its untouched siblings still come out of cache.
The honest caveat, straight from the pack's own docs: an image boundary cache does not survive a ComfyUI restart. Restart and you're back to a MISS. Caches here are accelerators, not a portable project format - don't build a two-day workflow that assumes yesterday's swapped frames are still on disk. Only CMK's video paths have a genuine cross-session resume contract.
How you'd use it
You mostly don't call it - it's already wired into the pack's own subgraphs. It becomes relevant the moment you build a CMK-style module of your own, or you're reading a flow and can't work out why a downstream merge keeps its HIT while a parallel detailer branch re-runs.
If you're debugging one of these flows, that's the tell. Branch caches carry revision markers, and the boundaries only accept a HIT when the dependency manifest matches the currently materialised branch revisions. So "changed one branch, everything downstream re-ran, siblings didn't" is the system working, not a bug.
Install
Manager: search CMK Flow, install the CMKFlow entry, 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
No model downloads are needed for this node - it holds data, it doesn't run inference. The resource checker still matters for the pack as a whole, because the FaceSwap module feeding it needs inswapper_128.onnx and buffalo_l in place:
python3 custom_nodes/cmk_nodes/scripts/check_cmk_resources.py --models-root "/path/to/ComfyUI-Shared"
And the pack needs ComfyUI's Nodes 2.0 / Vue setting enabled; without it the lazy-graph switching that these boundaries depend on doesn't get the frontend treatment the author designed around.
Where people get burned
Expecting persistence. If you want "resume a video swap where I left off", that lives in the video nodes' manifests under output/video/..., not in temp/cmk/.
Deleting the temp directory mid-session to free space is the other one. It works, and the next run silently pays full price - a MISS you'll only see in the log.
Inputs (4)
| Name | Type | Default | Description |
|---|---|---|---|
| MODEL (opt)opt | CMK_MODEL_PIPE | — | |
| IMAGEopt | IMAGE | — | |
| LOGopt | CMK_LOG_PIPE | — | |
| diagnosticopt | CMK_DIAGNOSTIC | — |
Outputs (4)
| Name | Type | Description |
|---|---|---|
| MODEL | CMK_MODEL_PIPE | — |
| IMAGE | IMAGE | — |
| LOG | CMK_LOG_PIPE | — |
| diagnostic | CMK_DIAGNOSTIC | — |