π¨ Prompt Builder (CharacterSuite)
The Assembly Point That Turns Prompt Soup Into a Finished Prompt
- final_positive
- final_negative
In the comfyui-character-suite workflow, every other node funnels into this one. CharacterExpander hands you an expanded positive and negative; SegmentLoader hands you saved fragments; this node is where it all gets glued into a single final_positive and final_negative pair you can drop straight into a CLIPTextEncode. It's the plumbing that makes the character library usable, and it's the node you'll actually reach for to control where the pieces land.
One naming thing up front: the class is CS_PromptBuilder, not PromptBuilder, and the pack does that deliberately to avoid clashing with other suites' identically-named nodes. If you load a workflow and see "Prompt Builder (CharacterSuite)" in the Add Node menu, this is the one.
What it actually does
It takes a base prompt (usually the output of CharacterExpander), up to three optional segment strings, and merges them according to insert_mode:
append(default) - segments go after your base prompt.prepend- segments go before it.after_quality- the interesting one. It splits your base prompt on commas, finds the last tag that looks like a quality tag (masterpiece, best quality, high quality, ultra detailed, highres, absurdres - that list is hardcoded), and inserts the segments right after it. The idea is quality tags lead a prompt on the SDXL lineage, so the stuff that matters most should sit near the front; this gets you that without you doing the surgery by hand.
use_break swaps the , separator for BREAK. Here's the take worth remembering: on CLIP-encoded anime models - Illustrious, NoobAI, Pony, the whole SDXL lineage - BREAK is a real chunk boundary and earns its place when you want to separate scenes or subjects. On the newer LLM-encoded checkpoints, the KB's prompt-engineering material is blunt: BREAK is meaningless, there's no token-chunk boundary to break against. So toggle use_break based on what your checkpoint actually is, not habit.
Inputs worth knowing:
base_positive/base_negative- required; wire CharacterExpander's outputs here.segment_a/segment_b/segment_c- optional, any STRING; typicallycombined_promptfrom SegmentLoader. Empty ones are skipped automatically.extra_negative- an extra block tacked onto the negative. Handy for one-off negatives you don't want to save as a segment.
Outputs: final_positive and final_negative, both STRING, ready for the encoder.
Installing it
cd ComfyUI/custom_nodes/
git clone https://github.com/DrkSun81/comfyui-character-suite
Restart and look under CharacterSuite (or ComfyUI Manager β search "character suite"). No pip dependencies - the pack is stdlib-only. Python 3.9+.
Where people get tripped up
after_qualitywith no quality tag found inserts at the start. If your base prompt has no masterpiece-style tag, the heuristic falls back to the front of the prompt. Keep at least one quality tag in your base if you want predictable placement.- It's a text joiner, not a cleaner. Load the same segment into two slots and you get the tag twice. There's no dedup, no reordering of your base - that's deliberate, but it means garbage in, garbage out.
BREAKis not free. On CLIP models it genuinely changes conditioning; on LLM-encoded models it's literal punctuation. Default is off for a reason - flip it only when you know the model reads it.- If a workflow won't load, check the node name. Because of the
CS_prefix collision-avoidance, a workflow saved with a different pack'sPromptBuilderwon't map onto this one automatically. - The included example workflow needs two things you may not have. Its checkpoint defaults to a placeholder (
illustrious/absoluteTerritory_v3.safetensors) you must swap for one you own, and its Show Text nodes come from the separate pysssss / ComfyUI-Custom-Scripts pack - install that, or delete those nodes when ComfyUI reports them missing.
It's the least flashy node in the suite and the one that holds the whole thing together. Once your character tags and segments feed in and a clean pair comes out, the rest of the graph - sampler, encoder, the works - just works.
Inputs (8)
| Name | Type | Default | Description |
|---|---|---|---|
| base_positive | STRING | masterpiece, best quality | β |
| base_negative | STRING | worst quality, low quality, blurry | β |
| insert_mode | COMBO | append | 3 options: append, prepend, after_quality |
| use_break | BOOLEAN | false | β |
| segment_aopt | STRING | β | |
| segment_bopt | STRING | β | |
| segment_copt | STRING | β | |
| extra_negativeopt | STRING | β |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| final_positive | STRING | β |
| final_negative | STRING | β |