Nodes/ComfyUI-MOSS-Image-Studio-Lite-SatoDive/MOSS Prompt Enhancer Lite (SatoDive)
ComfyUI Node

MOSS Prompt Enhancer Lite (SatoDive)

Your own 9B rewrites the prompt, and you get a veto

By SatoDive·Created 3 days ago·Updated 2 days ago· 4
MOSS Prompt Enhancer Lite (SatoDive)
  • clip
  • prompt
  • width
  • height
  • report
  • layout
◄text►
◄enhancefalse►
◄outputauto (official choice)►
◄detailofficial (220-500 words)►
◄creativity0.25►
◄variation0►
◄width1024►
◄height1024►
◄layout►

The free lunch hiding in your model folder

Every prompt enhancer you've seen either calls an API or makes you download a second language model and budget VRAM for two networks. This one doesn't. MOSS-Image's text encoder is Qwen3.5-9B - a full chat model - so the enhancer reuses the exact file your render already loads. No key, no Ollama, no extra download.

That's the joke of the thing: the model writes its own prompt.

The catch: "prompt enhancer" is a category with two classic failure modes, both from the LLM being a chat model rather than a function. It emits scaffolding - "Here is your enhanced prompt:", fences, thinking blocks - into your conditioning. And it drifts, adding people and objects you never asked for. Most of the engineering here is those two problems being answered.

How it works

The node runs the encoder's own generation path: tokenize with a system prompt, thinking off, then sample with temperature 0.2 + 0.8 × creativity (so 0.4 at the default 0.25), top-k 64, top-p 0.95, min-p 0.05, a 1.05 repetition penalty, and variation as the seed. Same machinery as ComfyUI's Generate Text node, using the LLM already resident.

The system prompt isn't improvised: it's ported from OpenMOSS's own moss-image-prompt-enhancer skill and Comfy-Org's template upsampler - caption-versus-layout rules, the eight facets, and a strict rule keeping your visible wording verbatim in quotes. detail sets the target lengths (220–320 words, 320–500 for posters); creativity is the honesty dial.

Then the important half: the LLM only writes; Python does the parsing. A layout answer gets its first JSON object pulled out, repaired where the repair is unambiguous (label aliases folded, xywh/yxyx converted, inverted boxes fixed, boxes clipped or rescaled), then compiled to the official abs_centralized / yxyx layout string. If it still can't be read you fall back to a caption, and if that fails too your own text goes through untouched with a note in the report. Nothing here can kill a render.

Feed it a layout with boxes and it switches to per-box rewriting: each description is rewritten separately, and its strict strength maps to a freedom label - 1.0 is locked (returned character for character whatever the model says), then low, medium, high. Places, box types and the literal words never move, because the program keeps them.

The inputs and outputs that matter

clip is the MOSS text encoder - wire the same CLIPLoader you feed the render, so it loads once. text is your idea in plain words, any language; words that must appear in the image go in quotes. enhance is off by default, and off means genuinely off: no tokenizer, no LLM, your text passes through. output is auto / caption / layout - leave it on auto unless you know you want boxes. variation is your reroll button.

width and height aren't metadata: layout boxes are placed on that canvas, and both come back out as outputs so you can wire them into the render. Do that.

Outputs are prompt (what goes downstream), width, height, report, and layout - your boxes with their rewritten descriptions. Nothing generates until you click: ✨ Enhance in the Generate node runs it as a separate small job and shows before/after with an Apply.

Install

Same pack, same steps, nothing extra for this node.

cd ComfyUI/custom_nodes
git clone https://github.com/SatoDive/ComfyUI-MOSS-Image-Studio-Lite-SatoDive
# restart ComfyUI

You'll still need ComfyUI v0.42+ for MOSS-Image support and the moss_image_sft_*, qwen3.5_9b_* and flux2-vae files. Wiring: CLIPLoader (type moss_image) → clip here and on MOSS Generate Lite; prompt → Generate's prompt; layout → Generate's layout; width/height → Generate's, if there's no source image. It isn't an output node, so it runs only when something downstream does.

Where people get burned

The first ON run is slow - a 9B model writing several hundred words, on the card that's about to render. Normal. After that it's cached and a plain re-run never calls the LLM; for a new rewrite, change variation, not your sampler seed.

Generate at a different resolution than the enhancer's width/height and boxes land in the wrong place. That's why those values are outputs.

Then the two "it did nothing" cases, which the report explains: boxes at strict 1.0 are locked and never change, and every answer is a rewrite of what you wrote - a vague brief comes back concrete, not different. When it says the answer was unusable it prints the raw text, so you can see whether the model refused or rambled; your original prompt went to the render either way.

Last thing: this writes long, detailed captions because MOSS-Image's guide asks for them. Don't carry that habit to another model - a 400-word caption in an encoder trained on short prompts is how you get drift. Here it's the house style.

CategorySatoDive/MOSS-Image Lite

Inputs (10)

NameTypeDefaultDescription
clipCLIPThe MOSS text encoder (CLIPLoader, type moss_image) - the same file your render uses, so it loads only once.
textSTRINGYour idea in plain words, any language. Put words that must appear in the image in quotes.
enhanceBOOLEANfalseOFF: your text goes to the render unchanged and the LLM never runs. ON: the rewrite runs once and is reused until you change the text or a setting.
outputCOMBOauto (official choice)auto: the official rule - a caption for ordinary images, a Layout (boxes) for posters / exact text placement. caption / layout: force one.
detailCOMBOofficial (220-500 words)official = the MOSS guide's lengths (220-320 words, 320-500 for posters).
creativityFLOAT0.250–10 = strict (only what you wrote, made concrete), 1 = free. Temperature 0.2 + 0.8 x this.
variationINT00–4294967295Change it to get another rewrite of the same text (the rewrite is cached otherwise, so a normal re-run never waits for the LLM).
widthINT1024256–4096Picture size: Layout boxes are placed on it. Also given as an output - wire it to the render so both always match.
heightINT1024256–4096—
layoutoptSTRINGLayout boxes JSON (from MOSS Generate Lite). With boxes, each box's description is rewritten on its own (its strict strength sets how freely) and the global text becomes the summary; places, types and words never change.

Outputs (5)

NameTypeDescription
promptSTRINGExactly what goes to the render (your text when OFF).
widthINT—
heightINT—
reportSTRING—
layoutSTRINGThe boxes with their rewritten descriptions (your layout when OFF / no boxes).