CMK Prompt Concatenate
Two strings, one separator, no surprises
- prompt
Two string inputs, a separator, one string out. If you've used any concat node anywhere, you know this one already.
prompt1 and prompt2 are both marked as forced inputs - they must be wired, not typed into a widget, which is the pack telling you this node is meant to join two live prompt streams rather than to be a text box. separator is a normal widget defaulting to ", ".
Then the behaviour, in two lines of Python: strip each input, drop any that came back empty, join what's left with the separator. So an empty prompt2 leaves prompt1 untouched - no trailing comma, no dangling separator. And if both are empty you get an empty string rather than a separator with nothing around it.
That sounds trivial. It's also the correct behaviour, and it's the difference between a concat node you can leave permanently wired and one you have to keep disconnecting.
What it's for
The realistic use case is composing a prompt from parts that get decided in different places. A character or scene prompt arriving from one branch, a shared style or quality tail you apply to everything from another, and one node joining them so the CLIP encode downstream has a single string to work with. Change the style tail and every prompt in the workflow picks it up.
Because CMK's CMK_PIPE carries prompt_pos and prompt_neg as strings, there's a natural fit inside a CMK graph too: join a shared suffix onto the pipeline prompt before it goes back into the sampler's conditioning.
What it is not is a prompt engineering tool. It doesn't insert weights, doesn't parse (word:1.2) syntax, doesn't deduplicate, doesn't translate. Plain string join, that's all. If the two prompts have contradictory content, that's a prompt problem and no node will fix it - the model just gets both sets of tokens.
One thing worth internalising from the wider prompting world, since people reach for concat nodes hoping to solve it: on guidance-distilled models running near CFG 1, negative prompts do much less than they used to, and the fix is lexical - say the thing you want instead of concatenating another negative. Stacking more negative strings through a concat node is a common dead end there.
Where it sits in the pack
CMK/Internal is the category, and the name is honest: this is infrastructure the pack uses, not a headline feature. It doesn't appear in the Flow Browser - that catalogue only lists the guided CMK/Flow/ modules - so find it by searching CMK Prompt in the node menu.
No diagnostics, no log output, no caching oddities. It re-runs when its inputs change, like any other node.
Installing the pack
ComfyUI Manager → search CMK Flow → install the entry published by CMKFlow → restart. Registry package name is cmk-flow. The pack doesn't care what the install directory ends up being called, which is worth knowing because Manager sometimes normalises it.
Manually, from the folder that contains main.py:
git clone https://github.com/CMKFlow/cmk_nodes.git custom_nodes/cmk_nodes
python3 custom_nodes/cmk_nodes/scripts/install_cmk_requirements.py
You're looking for CMK dependency check: OK. That second command is mandatory, not decorative - a git clone never installs pip packages, and requirements.txt carries real weight: ultralytics, onnxruntime, insightface, segment-anything, opencv-python, imageio-ffmpeg, and a pinned nudenet==3.4.2 for the FaceSwap ContentGuard. The installer's job is to find the Python interpreter ComfyUI is genuinely running and install there, which matters most on ComfyUI Desktop where standalone-env and .venv can coexist. Since the pack imports all of its nodes in one graph, a failed import can cost you nodes far away from the actual missing library.
On updates, repeat both steps: git -C custom_nodes/cmk_nodes pull --ff-only, then the installer again.
Model weights are deliberately excluded from the Python package. If you want the bundled workflows to run, have the pack tell you precisely which files it expects:
python3 custom_nodes/cmk_nodes/scripts/check_cmk_resources.py --models-root "/path/to/ComfyUI-shared"
It reports each resource as FOUND or MISSING with the function it serves, and offers to download the ones with a verified public source - one confirmation per file, because several are multiple gigabytes.
Two settings the pack depends on: Vue Nodes / Nodes 2.0 enabled in ComfyUI, and Execution → Live preview method: auto if you want previews while samples render.
Short version
Wire it, forget it, and be glad it drops empty inputs instead of leaving a comma hanging. That's the whole review.
Inputs (3)
| Name | Type | Default | Description |
|---|---|---|---|
| prompt1 | STRING | — | |
| prompt2 | STRING | — | |
| separator | STRING | , | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| prompt | STRING | — |