Nodes/CWK Prompt Composer/CWK Prompt Composer
ComfyUI Node

CWK Prompt Composer

Pills, autocomplete, and a CLIP encoder in one node — CWK Prompt Composer

By cowneko·Created 6 months ago·Updated 6 months ago· 1
CWK Prompt Composer
  • clip
  • positive_prompt
  • negative_prompt
  • positive_cond
  • negative_cond
positive_prompt
negative_prompt
parsercomfy
flux_guidance3.5
zero_out_negativefalse

If your prompts are danbooru-tag soup - which they are, if you run anything in the SD 1.5/SDXL/Illustrious/Pony line - CWK Prompt Composer is the closest thing to an IDE for writing them. It's a prompt text editor that turns your positive and negative prompts into colored, draggable pills, gives you autocomplete for every tag and embedding you own, throws in wildcard loading and server-side presets, and then also encodes the result to conditioning. One node replaces the usual "three text boxes + two CLIP Text Encode nodes" blob in the middle of your graph.

The honest framing up front: this is a quality-of-life pack aimed squarely at tag-style prompting. Its tag library is literally the danbooru list (99k+ tags, downloaded into tags/main.txt). If your workflow is a single sentence into Flux 2 or Anima - where your prompt is read as an instruction by an LLM text encoder and (word:1.3) is silently discarded - most of what makes this node fun does nothing for you. Keep it for the CLIP-era models it was built around.

How it works

Almost all the magic is on the front end. The Python node itself is small: it takes your two strings, and if you've wired a clip model in, encodes them. Everything else - pill canvas, category-colored syntax highlighting, tag pickers, wildcards, presets, the export dialog - is JavaScript living in the pack's web/ directory, talking to a few /cwk/* API endpoints the pack registers with ComfyUI's server.

The clever bit is the built-in encoding. Two parsers, selectable via the parser dropdown:

  • comfy (default) - the standard ComfyUI path: clip.tokenize() + encode_from_tokens(). Weights behave exactly like any CLIP Text Encode node.
  • A1111 - a fully self-contained reimplementation of Automatic1111's parse_prompt_attention, supporting (word:1.3), ((word)), [word], and BREAK, with per-token emphasis and mean normalization. It doesn't need ComfyUI_smZNodes or any other pack; it's right there in nodes.py. If you migrated from A1111 and never got comfortable with ComfyUI's weighting, this makes the syntax you already know work.

The inputs that matter

The two required inputs are just positive_prompt and negative_prompt - multiline strings, and the ones you'll spend your time in. Then the optional ones:

  • clip - wire a CLIP model here if you want conditioning outputs. Leave it empty and the node degrades to a string formatter: it returns the prompts and empty lists for the conds.
  • parser - comfy or A1111, as above.
  • flux_guidance - default 3.5. If you change it from the default, it injects that guidance value into the positive conditioning, exactly like the FluxGuidance node. You want this on Flux. On non-Flux models changing it does nothing useful.
  • zero_out_negative - zeroes the negative conditioning tensors, mirroring ConditioningZeroOut. Reach for it on distilled-guidance / CFG 1 style workflows where the negative is ignored anyway.

Outputs are positive_prompt, negative_prompt (both STRING), and positive_cond / negative_cond (both CONDITIONING). The conds plug straight into a KSampler; the strings feed anything else you want to preview or log.

Installing it

Either ComfyUI Manager (search "CWK Prompt Composer") or:

cd ComfyUI/custom_nodes
git clone https://github.com/cowneko/CWK_Prompt_Composer.git

Then restart ComfyUI. There's no requirements.txt and no heavy dependency - it uses only torch and aiohttp, which ComfyUI already ships. One thing to know: if tags/main.txt is missing, the pack fetches the danbooru tag list from a remote gist on first use, so the very first run needs network. It ships a 99k-line main.txt, so you usually won't see it.

Gotchas worth knowing

The A1111 parser is a faithful port, but remember what it is: CLIP-era syntax for CLIP-era models. Feed ((word:1.4)) through it into an LLM-encoded model and you're just writing literal punctuation into an instruction. That's not a bug in this node - it's the new text encoders dropping support for weighting.

The 75-token counter in each panel header is there for a reason: it shows a chunk indicator when you blow past the CLIP chunk boundary, so you can see where BREAK would actually help. And if you're coming from A1111, the pill-mode right-click menu hides a genuinely useful option: "Add to Tag List", which saves a tag to the right tags/*.txt file in alphabetical order - effectively building your own personal tag library that persists across sessions.

It's a niche pack - essentially zero search presence - so if something's weird, your first stop is the GitHub issues. But for the tag-prompting crowd, this is the rare case where the fanciest feature, the built-in encoding, is also what de-clutters your workflow the most.

CategoryCWK

Inputs (6)

NameTypeDefaultDescription
positive_promptSTRING
negative_promptSTRING
clipoptCLIP
parseroptCOMBOcomfy2 options: comfy, A1111
flux_guidanceoptFLOAT3.50–100
zero_out_negativeoptBOOLEANfalse

Outputs (4)

NameTypeDescription
positive_promptSTRING
negative_promptSTRING
positive_condCONDITIONING
negative_condCONDITIONING