A visual prompt engineering toolkit for ComfyUI. Chain prompts together, see what fires, lock what works.
Complex prompts with randomization become unreadable fast:
{warrior|mage|rogue}, {iron|steel|mythril} {sword|axe|staff},
{{fire|ice|lightning} enchantment|no enchantment}, {dragon|demon|undead} slayer
Now nest a few levels deeper. Add 20 options per group. Good luck debugging which path fired.
PromptChain makes the hierarchy spatial. Instead of parsing nested braces in your head, you see the decision tree as connected nodes:
Each node shows exactly what it can output. Chain them together, see the whole prompt path at a glance.
cd ComfyUI/custom_nodes
git clone https://github.com/mobcat40/ComfyUI-PromptChain.gitRestart ComfyUI. No external dependencies required.
- Dual prompt support — Handle both positive and negative prompts in a single chain
- Inline wildcards — Write
red | blue | greendirectly in nodes. No external files required. - Comments — Use
//or/* */to annotate your prompts without affecting output - Syntax highlighting — Operators and comments are color-coded for easy reading
- Visual chaining — Connect nodes to build rich, meaningful structures
- Dynamic inputs — Inputs auto-expand as you connect more nodes
- Live preview — See what fired, when it fired, in real-time
- Lock system — Freeze outputs with upstream propagation
- Disable system — Mute entire branches with one click
- Import/Export — Convert to/from Dynamic Prompt syntax
- Tag deduplication — Automatic duplicate removal
- Three modes:
🎲 Roll— Pick one random path from connected inputs➕ Combine— Merge all paths with intelligent interleaving🟢 Switch— Manually select which input to pass through (shows selected option name)
The core node for all prompt processing, combining, and randomization.
| Output | UI Label | Description |
|---|---|---|
chain |
out |
Bundle containing both positive and negative prompts (for chaining to other PromptChain nodes) |
positive |
positive |
Plain positive prompt text (connect to CLIP positive) |
negative |
negative |
Plain negative prompt text (connect to CLIP negative) |
The menubar at the top of each node provides quick access to all controls:
| Control | Description |
|---|---|
| 🔒/🔓 Lock | Freeze output (orange when active). Label shows when node is wide enough. |
| ⛔ Disable | Mute node (red when active). Label shows when node is wide enough. |
| ℹ️ Preview | Show live output preview. Label shows when node is wide enough. |
+ checkbox |
Show/hide positive prompt text field (blue) |
- checkbox |
Show/hide negative prompt text field (red) |
Below the menubar is a mode dropdown that controls how inputs are processed:
| Mode | Description |
|---|---|
| 🎲 Roll | Pick one random input (shows winning input name after execution) |
| ➕ Combine | Merge all inputs with breadth-first interleaving |
| 🟢 [name] | Switch mode — manually select which input to use (shows selected input's name) |
The dropdown shows "No Inputs" when no inputs are connected.
Inspector node for debugging text flowing through your prompt chain.
Purpose: Logs the text reaching your CLIP/KSampler nodes to help debug complex chains.
Inputs:
text— Text to inspectlabel— Optional label for the debug output (default: "positive")
Output:
text— Passes through input unchanged
Usage: Insert between any connection to see what's actually being passed. Check debug.log in the extension folder (custom_nodes/ComfyUI-PromptChain/debug.log) for output.
PromptChain handles both positive and negative prompts in a single unified chain.
Each PromptChain node has two text fields:
- Positive prompt (dark background) — Your main prompt content
- Negative prompt (subtle red-tinted background) — Things to avoid
Both prompts flow through the chain together via the chain output. At the end of your chain, use the separate positive and negative outputs to connect to your CLIP nodes.
Use the + and - checkboxes in the menubar to show/hide each prompt field:
+— Toggle positive prompt visibility-— Toggle negative prompt visibility
This helps reduce clutter when you only need one prompt type in a particular node.
[Style Node] [Subject Node] [Final Node]
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ + cinematic | │ │ + warrior | mage │ │ │──→ positive → CLIP
│ dramatic │──chain──→ │ │──chain──→ │ │
│ - blurry | ugly │ │ - deformed │ │ │──→ negative → CLIP
└──────────────────┘ └──────────────────┘ └──────────────────┘
Picks ONE random input from all connected inputs.
- The node's text field is prepended to the selected input
- Use for branching logic where you want one path chosen randomly
- Each execution may select a different input
Merges ALL inputs using breadth-first interleaving.
Tags round-robin across branches so no single branch dominates the token budget:
Input branches: ["a, b, c, d", "X, Y"]
Output: "a, X, b, Y, c, d"
Not "a, b, c, d, X, Y" — the interleaving ensures balanced representation.
Manually select which connected input to pass through.
- A dropdown appears showing all connected inputs by their source node names
- Click the dropdown or use arrow keys to cycle through inputs
- The node's text field is prepended to the selected input
- Perfect for A/B testing or debugging specific paths
Write wildcards directly in text fields — no external files needed.
| Symbol | Meaning | Example | Result |
|---|---|---|---|
| |
OR (pick one) | red | blue | green |
blue |
, |
AND (include both groups) | red | blue, dress | skirt |
blue, dress |
Lines ending with | continue the OR group:
warrior |
mage |
rogue
Equivalent to warrior | mage | rogue — picks one randomly.
Comma separates independent wildcard groups:
red | blue | green, large | small, fluffy | smooth
This picks one from each group and combines them: "blue, small, fluffy"
Add notes to your prompts without affecting the output. Great for documenting complex prompts or temporarily disabling tags.
Use // to comment until end of line:
photorealistic, // main style
1girl, // character
detailed background // setting
Output: photorealistic, 1girl, detailed background
Use /* */ for multi-line comments:
cinematic lighting,
/* TODO: experiment with these later
golden hour,
rim lighting,
*/
soft shadows
Output: cinematic lighting, soft shadows
- Documentation — Explain why certain tags are included
- Quick disable — Comment out tags instead of deleting them
- Notes to self — Leave reminders for future editing
- Version history — Keep old variations as comments
All text fields feature live syntax highlighting with a Monokai-inspired color scheme:
| Element | Color | Example |
|---|---|---|
Operators (|, ,) |
Pink, bold | red | blue |
Comments (//, /* */) |
Gray, italic | // note |
| Regular text | Light gray | portrait of a warrior |
The highlighting updates in real-time as you type, making it easy to:
- Spot structure — Instantly see where your wildcards and groups are
- Find comments — Gray italic text stands out from active prompts
- Identify operators — Bold pink pipes and commas show decision points
The preview panel also uses syntax highlighting, with the "Prompt result:" label displayed in gray bold to distinguish metadata from actual prompt content.
Click the lock icon (🔒/🔓) to freeze the current output. (For when you need to lock in that sweet Mythril Ice Enchanted Sword!)
- Node returns cached output instead of re-processing
- Randomization results preserved across executions
- Perfect for keeping a roll you like
| State | Appearance |
|---|---|
| Locked | 🔒 Orange icon + bold yellow "Lock" text + gold background with diagonal stripes |
| Unlocked | 🔓 Dim gray icon and text |
Locking a node also locks all its input nodes (the entire upstream chain). This ensures your complete prompt path stays frozen — from source nodes all the way to the locked node.
Lock state and cached output save with your workflow.
Click ⛔ Disable in the menubar to temporarily exclude a node from the prompt chain.
- Node outputs an empty string
- Downstream nodes ignore this input entirely
- The node and its upstream chain are visually marked
| State | Appearance |
|---|---|
| Disabled | ⛔ Red icon + bold red "Disable" text + dark red background with diagonal stripes |
| Enabled | ⛔ Dim gray icon and text |
Disabling a node also disables all its input nodes (the entire upstream chain). This lets you mute an entire branch with one click.
- A/B testing different branches without rewiring
- Temporarily muting parts of complex prompt trees
- Quick toggling of optional modifiers
Disabled state saves with your workflow.
Toggle the Preview button (ℹ️) in the menubar to see real-time output.
- Last run timestamp — Shows elapsed time since execution (e.g., "20 mins ago"), updates in real-time
- Execution time — Shows how long the workflow took to execute (in milliseconds)
- Word count — Shows word count for positive and negative prompts (e.g., "15 words / 8 neg")
- Selected wildcards — See exactly which options fired
- Full output — The complete processed result for both positive and negative prompts
- "Awaiting first run..." — Shown until node executes for the first time
Right-click any PromptChain node → Import or Export
Paste existing prompts and auto-generate clean node structures:
| Format | Example | Result |
|---|---|---|
| Plain tags | red, blue, green |
Converts to red | blue | green |
| Dynamic Prompts | {warrior|mage}, {sword|staff} |
Creates connected node tree |
| Nested braces | {a|{b|c}} |
Recursively expanded into node hierarchy |
| Top-level OR | option A | option B |
Creates separate input nodes |
Convert your node tree back to Dynamic Prompt format:
- Traverses all connected upstream nodes
- Converts wildcards to brace syntax
- Respects modes: Randomize →
{a|b}, Combine → comma-joined - Opens dialog with exportable string ready to copy
Duplicates are automatically removed. First occurrence wins:
Input: "red, blue, RED, green, Blue"
Output: "red, blue, green"
- Case-insensitive matching
- Special tags like
[BREAK]are always preserved - Early nodes = intentional placement; later duplicates from merges get removed
Input slots automatically expand as you connect more nodes:
- Connect a node → new empty slot appears
- Disconnect → empty slots are cleaned up (keeps at least one)
- Input labels show connected node titles for easy identification
- No manual slot management needed
Node 1 (Randomize): Node 2 (Randomize): Node 3 (Combine):
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ warrior | │ │ steel | mythril │ │ fire enchant, │
│ mage | rogue │──────────→│ sword | staff │──────────→│ dragon slayer │
└─────────────────┘ └─────────────────┘ └─────────────────┘
Possible output: "warrior, mythril staff, fire enchant, dragon slayer"
[Style] [Subject] [Output]
┌────────────────┐ ┌────────────────┐ ┌────────────────┐
│ + cinematic | │ │ + portrait of │ │ │→ positive
│ moody | soft │──chain────→│ a warrior │──chain────→│ │
│ - cartoon │ │ - bad anatomy │ │ │→ negative
└────────────────┘ └────────────────┘ └────────────────┘
positive: "cinematic, portrait of a warrior"
negative: "cartoon, bad anatomy"
[Option A]─────┐
│
[Option B]─────┼──→ [Switch Node] ──→ Output
│ (manually select)
[Option C]─────┘
Use the dropdown to instantly swap between options without rewiring.
Wire Randomize nodes in a mesh instead of a tree for combinatorial trait mixing:
[Fur Type]──┐ ┌──[Randomize]──┐
├────→┤ ├────→[Combine]──→ Final
[Fur Color]─┤ └──[Randomize]──┤
│ │
[Creature]──┴─────[Randomize]─────┘
Each Randomize node acts as selection pressure. Cross-wire your trait pools and every run produces a unique combination — like breeding.
Example pools:
Shiny Fur | Matted FurSilver | Black | RedWerewolf | Bear
Natural output: "Red, Shiny Fur, Werewolf" — emergent behavior from simple primitives.
Use Switch mode to build a reusable prompt control panel:
How it works:
- Create a Switch node for each category (Style, Pose, Character, Outfit, etc.)
- Connect pre-built prompt options to each Switch
- Use the dropdown or arrow keys to flip between presets
- All Switches feed into a final Combine node
Why this pattern is powerful:
- Instant iteration — Change any category without rewiring
- Saved presets — Your options persist with the workflow
- Mix and match — Combine any style with any pose with any character
- Quick comparison — Flip through options to find what works
Build your prompt palette once, reuse it forever. Each workflow becomes a custom prompt mixer tailored to your subject.
Disconnected PromptChain nodes act as prompt storage:
- Drop a node, paste your prompt, leave it unwired
- Sits on your canvas as a visual "sticky note"
- Saves with your workflow
- Connect when you want to use it, disconnect to deactivate
Build a library of prompt fragments right in your workflow. Zero config, just nodes.
| Pain Point | Dynamic Prompts | PromptChain |
|---|---|---|
| Nested syntax | {a|{b|{c|d}}} |
Visual node tree |
| Debugging | Read the string | See what lit up |
| Positive + negative | Separate handling | Unified chain |
| External files | Required | None |
| Migration | — | One-click import |
-
Use Lock for iteration — Find a random combination you like? Lock it before further experiments.
-
Disable for comparison — Instead of deleting nodes, disable them to quickly compare with/without.
-
Hide unused prompts — Use
+/-toggles to hide prompt fields you're not using in a node. -
Preview everything — Enable preview on your final node to see the complete output.
-
Chain outputs — Use
chainoutput when connecting to other PromptChain nodes; usepositive/negativeonly at the end for CLIP. -
Debug complex chains — Insert a PromptChain Debug node to log what's actually flowing through a connection.
-
Comment out experiments — Use
//to disable tags without deleting them:// golden hour, soft lighting
MIT License — free to use forever!



