Prompt Manager (+/-)
Stop wiring two text encoders for every idea you're testing
- clip
- positive
- negative
- positive_text
- negative_text
Two CLIPTextEncode nodes, one wired to the sampler's positive, one to the negative. It's the most common pattern in ComfyUI and it has a specific failure mode: you nudge the negative, forget which encoder you edited, and spend a run wondering why nothing changed. Close the tab and that pairing is gone - the graph remembers both strings, but nothing remembers that these two belong together.
Prompt Manager (+/-) is the one-box version. One node, both editors, and - this is the part that earns it a slot - the pair gets saved as a named recipe you can pull back later by selecting it, not by re-dragging a PNG and squinting at which node was the negative.
What it does under the hood
It subclasses the Focused node, so storage is the same SQLite prompt database. The encoder call is where it diverges, and the divergence is small enough to state exactly:
- Positive gets the full treatment:
prepend_text+ your maintext+append_textare joined, then LoRA trigger words are injected if that integration is enabled, then encoded. - Negative is encoded as typed. No composition, no trigger injection. The output tooltip even calls it "the unchanged negative text."
Both go through clip.encode_from_tokens_scheduled(), same path as the core encoder, so your conditioning is unchanged. Then it writes the pair tables: a prompt row per component plus a combination row pointing at both. Components are immutable while referenced - edit either text and you get a new combination, not a silent overwrite, which is why the library fills with variants sharing one positive and differing only in the negative.
Images get linked to the positive prompt, traced through the queue graph rather than guessed. Cached runs still count, because the run counter hooks the queue's dequeue event instead of the node execution - which matters, since a repeat run with identical text is exactly the case that gets cached, and exactly the case where you'd otherwise be told you never used that prompt.
The inputs and outputs
Required: text (positive), negative_text, and clip. Only one CLIP input for both sides, which is the point.
Optional: category and tags describe the pair as a whole, with the same autocomplete as Focused. prepend_text and append_text are forceInput here too - sockets, not text boxes, meant for wiring a trigger string. search_text is the library query box again; the backend accepts it and does nothing with it.
Four outputs:
positive→ sampler positive, the composed text with prepend/append and LoRA triggers applied.negative→ sampler negative.positive_text→ the effective string that was actually encoded, useful for filename templates or a note node.negative_text→ the negative as typed, unchanged.
The node UI has its own Save pair button, and it's disabled when either text field is fed by a connection - connected values are authoritative, so the save has to happen by running the node instead.
Install
Manager, search ComfyUI_PromptManager. Or:
cd ComfyUI/custom_nodes
git clone https://github.com/ComfyAssets/ComfyUI_PromptManager
cd ComfyUI_PromptManager
pip install -r requirements.txt
Two runtime dependencies, watchdog and Pillow. That's it. Restart ComfyUI; the node is under ComfyAssets → Prompts. First run creates prompts.db in the extension folder - on Docker, set an absolute database.default_path in config.json before you build a library you care about, because that folder may not survive a container rebuild.
Should you care, and where it bites
Whether the negative half is worth having depends on what you run. On the SDXL lineage - Illustrious, NoobAI, Pony, WAI - the negative prompt is still load-bearing, and pairing it with its positive is a real organisational win. On guidance-distilled models at CFG 1 the negative conditioning does nothing at all. If you only run Flux and Z-Image, you're buying a two-box node to fill in one box.
The traps, specifically:
Empty negative is a value, not an absence. The tooltip says so outright, and "same positive, no negative" is a legitimate stored variant, not a bug.
Editing text makes a new recipe. You cannot rewrite a saved component in place. That is correct behaviour for keeping history honest, and it will look like the library is growing duplicate-ish entries until you understand why.
The save button isn't a save when fields are connected. Covered above - run the node.
The pair UI is newer than the rest of the node. Storage and prompt IDs have been deliberately kept stable; the layout around them has been moving fast through late 2026. If you're reading this a few versions later, trust the changelog over this page.
For the "same three ideas, small tweaks" workflow, this is the node I'd reach for - not because the encoding differs but because the diffing does.
Inputs (8)
| Name | Type | Default | Description |
|---|---|---|---|
| text | STRING | The text prompt to be encoded and saved to database. | |
| negative_text | STRING | — | |
| clip | CLIP | The CLIP model used for encoding the text. | |
| categoryopt | STRING | Optional category for organizing prompts (e.g., 'landscapes', 'portraits') | |
| tagsopt | STRING | Comma-separated tags for the prompt (e.g., 'anime, detailed, sunset') | |
| search_textopt | STRING | Search past prompts by text; add tag:name (or tag:"two words") to filter by tag | |
| prepend_textopt | STRING | Text to prepend to the main prompt (connected STRING nodes will be added before the main text) | |
| append_textopt | STRING | Text to append to the main prompt (connected STRING nodes will be added after the main text) |
Outputs (4)
| Name | Type | Description |
|---|---|---|
| positive | CONDITIONING | Positive conditioning with composition and optional LoRA trigger words. |
| negative | CONDITIONING | Negative conditioning from the negative editor, including empty text. |
| positive_text | STRING | The effective positive text that was encoded. |
| negative_text | STRING | The unchanged negative text that was encoded. |