Technique
How to write prompts when nothing rewrites them
When nothing screens or rewrites your prompt, the text you submit is the text that renders, so your wording is the only variable you have and the only thing there is to debug. That makes prompting a discipline rather than a bag of tricks: describe the frame and the light instead of stacking adjectives, move one thing at a time so you can attribute the difference, and treat the negative prompt as a per-model field rather than a habit: some models declare one, most do not.
What the request actually contains
A generation request carries a model id, a prompt, and the options that model accepts: a size for images; a resolution, a length and on some models an aspect ratio for video; plus the addresses of any reference pictures. That is the whole surface, listed endpoint by endpoint in the API reference. Nothing sits between your text and the render: no rewriting stage, no guidance dial, no step count. Seed and negative prompt are open on some models and not on most; the catalog endpoint and each model page say which. Where a model ships a prompt expander as a vendor setting, it is sent switched off.
That missing middle layer is why most prompt tricks exist elsewhere. OpenAI's image generation documentation says the model "will automatically revise your prompt for improved performance", hands the rewritten text back in a revised_prompt field, and documents no way to switch it off. Prompt-hacking is what negotiating with a rewriter looks like, and here there is nobody to negotiate with; generating without a filter takes that layer apart.
Keys the endpoint does not define are simply not read. Add a cfg value or a step count to the JSON and nothing happens and nothing errors. seed and negative_prompt are the exception: they are read on the models that declare them, and a model that does not declare one returns 400 rather than swallowing the field. That is worth knowing before you spend an afternoon tuning a field that was never delivered.
Move one thing, and learn your noise floor
A comparison is readable only when a single thing moved. Change the wording and the size in one run and you have two explanations for the difference and no way to separate them, so the run taught you nothing except that something happened.
There is a second source of variation and it is not yours. Omit the seed and the adapter draws a fresh one on every request, and on models that declare no seed there is no field to pin at all, so one prompt submitted twice does not come back as one picture; choosing resolution and length has the mechanism and why a bigger re-run is a fresh draw rather than an enlargement. Measure it before you read anything into an edit. Run your baseline twice, look at how far apart the two land, and treat that distance as the smallest difference a wording change has to beat. Do it on the cheapest option the model offers, since every attempt spends credits and the pricing page lists what each one charges.
You do not need a notebook for this. The prompt is stored verbatim beside the generation and comes back on every record from the generations endpoint, so your history is already the experiment log. Copy a working sentence out of it rather than retyping it: retyping is an edit you did not mean to make.
Describe the frame, not the mood
A stack of adjectives hands the composition back to the model. Moody, ethereal, hyperdetailed name no subject, no placement and no light direction; they are a wish about the result rather than a description of a picture. The Hugging Face Diffusers prompting guide states the rule directly, listing subject, style and context and then telling you to "use these elements as a structured narrative, not a keyword list", because current models read language rather than match keywords.
Long lists also fail in a documented way. In Attend-and-Excite (Chefer et al., SIGGRAPH 2023) the authors assess "catastrophic neglect, where the model fails to generate one or more of the subjects from the input prompt", and report that it also "fails to correctly bind attributes (e.g., colors) to their corresponding subjects". That starts at two subjects and two colours, not at ten.
So write decisions. What is in the frame and where it sits, where the light comes from and how hard it is, what the lens does to the background. Each one is checkable against the render: you can see whether the light came from the left. You cannot see whether it was ethereal, so that word can never tell you your edit worked.
A negative prompt is not on every model
Reaching for a negative prompt is muscle memory from local pipelines, and it was never a way of writing. It is a separate argument to the sampling loop. The Diffusers reference defines negative_prompt as "the prompt or prompts not to guide the image generation" and notes it is "ignored when not using guidance", so the field exists because there is a guidance step with an unconditional branch to steer away from.
A negative prompt exists here only on the models that declare one, and everywhere else anything you type is description. "No watermark, no text" is a sentence that names a watermark and text. State the positive instead: rather than no hat, say what is on the head; rather than not blurry, say what is sharp and how quickly the background falls away.
When an unwanted element survives several attempts, stop re-rolling. Hand the frame you have to an editing model as a reference and describe the change against it, which is a shorter argument and a different kind of request. The catalog marks which models read references, and keeping a character consistent covers what an attachment holds that a sentence cannot.
What wording cannot buy
Video wants more from the same field. A clip is rendered as one take, so your sentence has to carry motion and camera as well as the frame, and the camera is the part people leave out: omitting it picks one for you. From a still to a video is that handoff, and calling the API from your code is the same loop driven from a script.
What no phrasing buys is a way past the prohibited categories. A request that hits one is refused before the run starts, so it costs nothing, but these are categories rather than a reading of your tone, and rephrasing does not move a request out of one. What is allowed and what is blocked sets out the line.
Frequently asked questions
Does anything change my prompt before the model sees it?
No. There is no rewriting stage, and where a model ships a prompt expander as a vendor setting it is sent switched off. The text stored beside your generation is the text that rendered, so a sentence copied back out of your history behaves the way it did the first time.
Where do I put a negative prompt?
In the negative_prompt field on the models that declare one; each model page and the catalog endpoint say which do. Send it to a model that does not declare it and the request returns 400 rather than swallowing it. Where there is no field, write the positive statement, or send the picture back through an editing model and describe the fix against it.
Why does the same prompt give me a different picture twice?
Omit the seed and the adapter draws a fresh one on every request, and models that declare no seed give you nothing to pin. Measure it rather than fight it: run your baseline twice and treat the gap between them as the smallest difference a wording change has to beat.
