POML Processor
Render Microsoft's structured prompt markup into an actual LLM prompt, right inside ComfyUI
- rendered_prompt
- metadata
First, the thing that trips everyone up: this node does not make a Stable Diffusion prompt. Feed its output to a CLIP Text Encode and you'll get gibberish. The POML Processor produces a prompt for an LLM - the kind you hand to an OpenRouter, Ollama, or local chat-model node. ComfyUI has quietly become a general workflow engine, and if your graph already calls a language model, this node is how you stop hand-editing giant prompt strings in a text widget.
POML stands for Prompt Orchestration Markup Language, and it's a real Microsoft project, not a community invention - there's a paper (arXiv 2508.13948) and the official Python SDK lives at github.com/microsoft/poml. The idea is that your prompt stops being one blob of prose and becomes structured, XML-ish markup:
<poml>
<role>You are an AI assistant specialized in {{ domain }}.</role>
<task>Help the user understand {{ topic }} in simple terms.</task>
<output-format>Use clear explanations with examples.</output-format>
</poml>
The Processor parses that markup, substitutes the {{ variable }} placeholders, and renders it back out as a plain-text prompt. The same "structure beats syntax" logic the community rediscovered for LLM-encoded image models applies here tenfold - a role separated from a task separated from an output format is much easier for a language model to follow than a wall of text.
How it works
The node tries the official poml SDK first. If it's not installed, it quietly falls back to a built-in XML parser, and it degrades feature by feature from there - no pandas means tables render as plain text, no PyPDF2 means PDFs fail gracefully. This is a genuinely thoughtful design, and the metadata output is the window into it.
It parses your markup into components (role, task, examples, documents, tables, images, output format), runs the variable substitution, then renders. The render_mode changes the shape:
- standard - clean natural-language prompt
- optimized - labeled sections (
Role:,Task:,Examples:,Output Format:) - debug - numbered parts under a
=== DEBUG MODE ===banner
Inputs that actually matter
- poml_template - your POML markup. Multiline, and there's a sensible starter template preloaded, so the node works before you write a single tag.
- render_mode - start with
standard, switch todebugwhen something's off. - variables_json - a JSON object whose keys fill your
{{ placeholders }}. Mismatched names are the #1 beginner mistake. - max_length - truncates the output (0 = no limit). Handy for token budgets; truncation appends
....
Outputs
- rendered_prompt - wire this into your LLM node's text input.
- metadata - a JSON blob with
sdk_used,components_found,variables_used,prompt_length, and a fulldependencies_statusreport. Run it into a text display node and it doubles as a health check.
Install
This is a small pack, no model downloads, no API keys, no GPU work - it's pure local string processing. Install via ComfyUI Manager (search "Zenkai-POML" or DJZ-POML), or:
cd ComfyUI/custom_nodes
git clone https://github.com/MushroomFleet/ComfyUI-DJZ-POML
cd ComfyUI-DJZ-POML
pip install -r requirements.txt
Then restart ComfyUI. The requirements pull in poml, pandas, openpyxl, PyPDF2, Pillow, requests, and jsonschema - pandas and PyPDF2 are the heavy-ish ones. If you skip the install and only have poml, the node still runs; you just lose table and PDF features. Portable-install users get a handy install-portable.bat.
Where people get burned
- Bad JSON in
variables_jsonproduces an error string as your prompt, with the real error inmetadata. Check metadata first, not the prompt. - A syntax error in your markup doesn't crash - the parser falls back to a generic "Assistant / Help the user" prompt and tucks the error into
metadata. You can get silent garbage out of a node that looks healthy. Usedebugmode and readmetadata.error. - Unsubstituted placeholders like a literal
{{ topic }}in the output mean your variable name doesn't match the template. The parser leaves unknown placeholders alone rather than raising. - Wrong downstream - again, this feeds an LLM, not an image sampler. The README's canonical graph is
POML Processor → OpenRouter.
Fair warning: this is a brand-new pack from a single-commit repo (MushroomFleet), and it's an early take on a niche idea. The graceful degradation and the metadata plumbing are more polished than most first releases, but treat it as a promising toy until it has community mileage.
Inputs (4)
| Name | Type | Default | Description |
|---|---|---|---|
| poml_template | STRING | <poml> <role>You are a helpful AI assistant.</role> <task>Assist the user with their request in a clear and helpful manner.</task> <output-format>Provide a well-structured, informative response.</output-format> </poml> | — |
| render_mode | COMBO | standard | 3 options: standard, optimized, debug |
| variables_jsonopt | STRING | {"user_name": "User", "topic": "AI"} | JSON object with template variables |
| max_lengthopt | INT | 00–8000 | — |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| rendered_prompt | STRING | — |
| metadata | STRING | — |