⚠️ VISION PROTOCOL
CRITICAL: For general chat inquiries ("what is this?", "describe this image", "extract text"), DO NOT USE the describe command.
- PRIORITY: Use your native multimodal (vision) capabilities. It is faster and preserves context.
- EXCEPTION: ONLY use the
describecommand if you need structured JSON analysis or specific identity-lock metadata required for a subsequent tool call.
Image Generation & Editing
Multi-provider image CLI. Default provider is xAI (Grok) at $0.02/image flat rate. OpenAI available via --provider openai.
Providers
| Provider | Default Model | Pricing | Key Env Var |
|---|---|---|---|
| xAI Pro (default) | grok-imagine-image-quality |
$0.07/image flat | XAI_API_KEY |
| xAI Standard | grok-imagine-image |
$0.02/image flat | XAI_API_KEY |
| OpenAI | gpt-image-2 |
$0.009-$0.200/image (quality-dependent) | OPENAI_API_KEY |
Both providers use the OpenAI SDK under the hood. The --provider flag switches the API endpoint and default model. Quality defaults to high.
Both providers support: generate, edit, style-transfer, restore, thumbnail, batch. All commands work with xAI by default.
xAI advantages: flat pricing, more permissive content policy, fewer refusals on real people/public figures, stronger photorealism for human faces.
xAI watch-outs: defaults to cinematic/dramatic/oversaturated aesthetic. Requires --prefix steering for editorial or restrained styles. See Taming xAI's Aesthetic Bias.
OpenAI advantages: neutral aesthetic defaults, transparent backgrounds, masks, multi-image edit (multiple input files), fine-grained quality/compression control, describe command (vision), better prompt adherence for non-cinematic styles, better text rendering.
describe always uses OpenAI (xAI has no vision endpoint). Requires OPENAI_API_KEY even when xAI is the default provider.
API Keys
Both keys live in ~/.secrets (sourced by shell profile). Run source ~/.secrets if they're not in your environment.
| Key | Where to get it | Env var |
|---|---|---|
| xAI (default provider) | console.x.ai > API Keys | XAI_API_KEY |
| OpenAI (describe, fallback) | platform.openai.com/api-keys | OPENAI_API_KEY |
Quick Start
- Confirm your API key is set:
source ~/.secrets echo $XAI_API_KEY | head -c 10 # xAI (default) echo $OPENAI_API_KEY | head -c 10 # needed for describe, or --provider openai - Install the SDK if needed:
pip install openai - Generate an image:
omni-image generate "A watercolor painting of a sunset over Mos Eisley" --output sunset.png
Commands
Generate
Create images from a text prompt.
# Basic generation (uses xAI by default, quality high)
omni-image generate "your prompt" --output result.png
# Specific size
omni-image generate "your prompt" --size 1536x1024 -o landscape.png
# Use OpenAI instead
omni-image --provider openai generate "your prompt" -o result.png
# xAI Pro model
omni-image generate "your prompt" --model grok-imagine-image-quality -o result.png
# Transparent background (OpenAI only, PNG)
omni-image --provider openai generate "a logo on transparent background" --background transparent -o logo.png
# Multiple images at once
omni-image generate "your prompt" -n 4 --output-dir ./variants/
# Compressed JPEG output
omni-image generate "your prompt" --format jpeg --compression 80 -o photo.jpg
Edit
CRITICAL: xAI (Grok) fully supports image editing / image-to-image generation. Do NOT refuse to edit an image because you think xAI lacks this feature.
Modify existing images with a text prompt. Optionally supply a mask to constrain edits.
# Edit a single image
omni-image edit "make the sky dramatic and stormy" -i photo.jpg -o dramatic.png
# Edit with a mask (transparent areas in the mask = regions to change)
omni-image edit "replace with a garden" -i room.jpg --mask mask.png -o garden_room.png
# Combine multiple images
omni-image edit "merge these into a collage with consistent lighting" -i img1.jpg img2.jpg img3.jpg -o collage.png
# High input fidelity (preserves more of the original style)
omni-image edit "add a hat" -i portrait.jpg --input-fidelity high -o hat.png
When to Use Input Fidelity
The --input-fidelity flag controls how much the output preserves the source image's structure:
- Use
highwhen you want to preserve the spatial layout of the source: walls, windows, furniture placement, body poses. Good for stylizing a venue photo while keeping the architecture intact, or retouching a portrait without changing the pose. - Omit it (or use
low) when the source is a loose reference: you want the AI to use the shape or composition as a starting point but reimagine the contents freely. Good for filling an empty glass with a different liquid, or using a product shot as a structural anchor.
Rule of thumb: if the edit prompt describes changing what's in the image, omit fidelity. If it describes changing how the image looks, use high.
Exception: When the image contains a person whose likeness must be preserved, always use high regardless of the edit type. See Preserving Likeness.
Reference-Based Generation
The most powerful edit pattern is using a photo as a structural anchor while completely reimagining its contents. Feed a product photo to edit not to modify the product, but to let the AI use its shape and proportions as a scaffold for something new.
# Use an empty coupe glass photo as a structural reference, reimagine the contents
omni-image edit \
"Fill this coupe glass with a bright blue butterfly pea tea cocktail, violet-shifting ice cubes, condensation on the glass" \
-i ref_empty_coupe.jpg --quality high -o cocktail_blue.png
# Use a rocks glass photo as a shape anchor for a completely different drink
omni-image edit \
"Golden amber old fashioned with a large ice sphere, orange peel garnish, smoke wisps" \
-i ref_rocks_glass.jpg --quality high -o cocktail_amber.png
# Use a venue photo as a layout reference for a different setting
omni-image edit \
"Transform this space into a 1920s speakeasy with warm Edison bulbs, dark wood, and brass fixtures" \
-i venue_photo.jpg --input-fidelity high -o speakeasy.png
Notice: the first two examples omit --input-fidelity because the glass shape is a loose reference. The third uses --input-fidelity high because the wall/window layout should be preserved.
Describe
Analyze images using GPT-4o vision. Returns alt text, captions, tags, or structured analysis.
# Generate alt text for web accessibility (default)
omni-image describe photo.jpg
# Get a natural language caption
omni-image describe photo.jpg --mode caption
# Detailed multi-paragraph description
omni-image describe photo.jpg --mode detailed
# Keyword tags
omni-image describe photo.jpg --mode tags
# Structured JSON (alt_text, caption, tags, colors, objects, scene)
omni-image describe photo.jpg --mode json
# Custom analysis
omni-image describe photo.jpg --custom "what fonts and colors are used in this design?"
# Multiple images
omni-image describe img1.jpg img2.png img3.webp
# Use the full gpt-4o model for better accuracy
omni-image describe photo.jpg --model gpt-4o
Background Remove
Remove background to transparent PNG.
omni-image bg-remove product.jpg -o product-nobg.png
Style Transfer
Apply an art style to an image. 10 built-in presets plus custom.
Warning: Style transfer stylizes the entire image including faces. It will not preserve a person's likeness. If the user wants to stylize a photo of a person while keeping their face recognizable, use edit with the Identity Preservation Framework instead. For example, use edit with the 3-layer identity lock and a style directive like "Style: watercolor painting. Real textures." rather than style-transfer.
# Built-in styles: watercolor, oil-painting, pixel-art, pencil-sketch,
# anime, pop-art, art-deco, minimalist, cyberpunk, stained-glass
omni-image style-transfer photo.jpg --style watercolor -o watercolor.png
omni-image style-transfer photo.jpg --style pixel-art -o pixel.png
# Custom style
omni-image style-transfer photo.jpg --style custom --custom-style "1920s art nouveau poster" -o nouveau.png
Color Palette Control
Important: The built-in style presets apply technique only, not color palette. The watercolor preset produces cool, washed-out lavender tones by default. If you are building a cohesive page where style-transferred photos need to match AI-generated illustrations, the color mismatch will be visible.
Two fixes:
1. Steer color with --prefix (works with any preset):
# Warm watercolor instead of the default cool tones
omni-image --prefix "Warm golden amber and coral tones. Rich saturated palette." \
style-transfer venue.jpg --style watercolor -o venue_warm.png
# Apply the same color direction across a batch for consistency
PREFIX="Warm watercolor in golden amber, coral, and cream tones. Saturated, not washed out."
omni-image --prefix "$PREFIX" style-transfer photo1.jpg --style watercolor -o art1.png
omni-image --prefix "$PREFIX" style-transfer photo2.jpg --style watercolor -o art2.png
omni-image --prefix "$PREFIX" style-transfer photo3.jpg --style watercolor -o art3.png
2. Use --style custom for full control when presets aren't enough:
omni-image style-transfer venue.jpg \
--style custom \
--custom-style "Warm watercolor illustration. Golden amber, coral, and cream palette. Visible brush strokes, soft washes of color, paper texture. Rich saturated tones, not cool or washed out." \
-o venue_watercolor.png
When building cohesive visual pages, always use --prefix or --style custom with explicit color direction. The bare presets are fine for one-off transformations but produce inconsistent palettes across a series.
Restore
Restore damaged, faded, or degraded photographs. Uses high input fidelity by default.
omni-image restore old_photo.jpg -o restored.png
Thumbnail
Generate web-optimized thumbnails (JPEG at 80% compression by default).
# From a text prompt
omni-image thumbnail "a cozy coffee shop interior" -o thumb.jpg
# From an existing image
omni-image thumbnail "clean product shot" --from-image product.jpg -o thumb.jpg
Batch
Process multiple image jobs from a JSON manifest. Each job can generate or edit independently, sharing a common style prefix and defaults.
omni-image --retries 3 batch drinks.json --output-dir ./public/images/
Manifest format (drinks.json):
{
"style_prefix": "Vivid, hyper-real 1920s cinematic movie still. Rich jewel tones, warm golden lighting, film grain.",
"defaults": {
"quality": "high",
"size": "1024x1024",
"model": "gpt-image-2",
"format": "png"
},
"jobs": [
{
"name": "cold_open",
"input": "ref_coupe.jpg",
"prompt": "Blue butterfly pea tea cocktail with violet-shifting ice cubes, condensation on glass",
"output": "drink_cold_open.png"
},
{
"name": "smoking_gun",
"input": "ref_rocks.jpg",
"prompt": "Golden amber with smoke cloche, large ice sphere, orange peel",
"output": "drink_smoking_gun.png"
},
{
"name": "hero_banner",
"prompt": "Elegant bar counter with three cocktails backlit by warm Edison bulbs",
"output": "hero_banner.png",
"size": "1536x1024"
}
]
}
Each job inherits from defaults and can override any field. Jobs with input use the edit API (reference-based generation); jobs without input use generate. The style_prefix is prepended to every job's prompt.
Batch also generates an index.html gallery in the output directory with thumbnails and job info. Open it in a browser to review all results at a glance.
Output is a summary JSON with per-job status:
{
"status": "success",
"message": "Batch complete: 3/3 succeeded",
"results": [
{"name": "cold_open", "status": "success", "path": "/abs/path/drink_cold_open.png"},
{"name": "smoking_gun", "status": "success", "path": "/abs/path/drink_smoking_gun.png"},
{"name": "hero_banner", "status": "success", "path": "/abs/path/hero_banner.png"}
]
}
Parameters Reference
Global flags
These flags go before the subcommand name:
| Flag | Values | Default | Notes |
|---|---|---|---|
--provider |
xai, openai |
xai |
API provider. Switches endpoint, default model, and API key env var. |
--retries |
0-10 |
0 |
Retry transient API errors with exponential backoff (1s, 2s, 4s... capped at 30s) |
--prefix |
string | none | Style preamble prepended to prompts in generate, edit, and style-transfer |
--preset |
draft, balanced, final |
none | Quality preset. xAI: draft/balanced = grok-imagine-image, final = grok-imagine-image-quality. OpenAI: draft = mini/low, balanced = 1.5/medium, final = 1.5/high. |
--dry-run |
flag | off | Estimate cost in USD without making API calls. Works with all commands and batch. |
# Example: retry up to 3 times with a style prefix
omni-image --retries 3 --prefix "Photorealistic, 8K, shallow depth of field." generate "a cup of coffee" -o coffee.png
# Use a preset for quick iteration
omni-image --preset draft generate "concept sketch of a robot" -o robot_draft.png
# Estimate cost before running
omni-image --preset final --dry-run generate "hero image" -n 4
# Dry-run a whole batch manifest
omni-image --dry-run batch drinks.json
Presets
Presets map to model + quality combinations. Use them to switch between iteration and production without remembering flag combos:
| Preset | Model | Quality | Approx. Cost (square) |
|---|---|---|---|
draft |
gpt-image-1-mini |
low |
$0.005 |
balanced |
gpt-image-2 |
medium |
$0.034 |
final |
gpt-image-2 |
high |
$0.133 |
If you pass --model or --quality explicitly, those override the preset values.
Dry Run
--dry-run calculates the estimated cost without calling the API. The output is JSON:
{
"status": "dry_run",
"estimated_cost_usd": 0.532,
"breakdown": [
{"model": "gpt-image-2", "quality": "high", "size": "1024x1024", "n": 1, "cost_usd": 0.133}
]
}
For batch manifests, the breakdown includes each job by name. When --quality is auto, the estimate uses medium pricing as a reasonable midpoint.
Generation & Editing flags
| Flag | Values | Default | Notes |
|---|---|---|---|
--model |
xAI: grok-imagine-image-quality, grok-imagine-image. OpenAI: gpt-image-2, gpt-image-1, gpt-image-1-mini |
provider-specific | Set by --provider. xAI default: grok-imagine-image-quality. OpenAI default: gpt-image-2. |
--size |
auto, 1024x1024, 1536x1024, 1024x1536, 4096x4096 |
auto |
xAI maps these to aspect ratios (1:1, 3:2, 2:3). OpenAI supports up to 4K. |
--quality |
auto, low, medium, high |
high |
Controls rendering fidelity on both providers. xAI pricing stays flat regardless of quality level. |
--resolution |
auto, 1k, 2k |
auto |
xAI only. Output pixel dimensions. 2k gives sharper detail at no extra cost. OpenAI ignores this. |
--format |
png, jpeg, webp |
png |
Controls output file format. Both providers save as this format. |
--compression |
0-100 |
none | JPEG/WebP quality (OpenAI only; xAI ignores) |
--background |
auto, transparent, opaque |
auto |
OpenAI only; xAI ignores. Transparent requires PNG or WebP. |
-n |
1-10 |
1 |
Number of images |
-o / --output |
file path | auto-named | Single image explicit path |
--output-dir |
directory | . |
Where auto-named files go |
--input-fidelity |
low, high |
low |
Edit only, OpenAI only. xAI edit works without this flag. high preserves source layout; low uses source as loose reference. |
Describe flags
| Flag | Values | Default | Notes |
|---|---|---|---|
--mode |
alt-text, caption, detailed, tags, json |
alt-text |
Output format for vision analysis |
--custom |
string | none | Freeform analysis prompt (overrides --mode) |
--model |
gpt-4o, gpt-4o-mini |
gpt-4o-mini |
Vision model; mini is cheaper, 4o is more accurate |
Style transfer flags
| Flag | Values | Default |
|---|---|---|
--style |
watercolor, oil-painting, pixel-art, pencil-sketch, anime, pop-art, art-deco, minimalist, cyberpunk, stained-glass, custom |
required |
--custom-style |
string | none (required when --style custom) |
Thumbnail flags
| Flag | Values | Default |
|---|---|---|
--from-image |
file path | none (generates from prompt if omitted) |
--format |
png, jpeg, webp |
jpeg |
--compression |
0-100 |
80 |
Batch flags
| Flag | Values | Default | Notes |
|---|---|---|---|
manifest (positional) |
file path | required | Path to JSON manifest |
--output-dir |
directory | . |
Base directory for output files |
Manifest fields: style_prefix (string), defaults (object with model/quality/size/format/compression/background/input_fidelity), jobs (array of objects with name/prompt/input/output and optional per-job overrides).
Resolution Expectations
Output dimensions vary by model, quality, and --size. This table shows what to expect:
| Provider | Model | Quality Levels | Available Sizes / Aspect Ratios | Notes |
|---|---|---|---|---|
| xAI | grok-imagine-image |
low, medium, high |
1:1, 16:9, 9:16, 4:3, 3:4, 3:2, 2:3, 2:1, 1:2 | Default. $0.02/image flat. Use --resolution 2k for sharper output. |
| xAI | grok-imagine-image-quality |
low, medium, high |
same as above | $0.07/image flat. Best with --resolution 2k. Wins ~79% vs standard in head-to-head. |
| OpenAI | gpt-image-2 |
low, medium, high, auto |
1024x1024, 1536x1024, 1024x1536, auto |
Best OpenAI model |
| OpenAI | gpt-image-1-mini |
low, medium, high, auto |
1024x1024, 1536x1024, 1024x1536, auto |
Budget option |
When --size auto (the default), the API picks the best size for the prompt. For xAI, --size values are mapped to aspect ratios (e.g., 1536x1024 becomes 3:2). For predictable output, set size explicitly. Use 1536x1024 for landscape backgrounds and hero images, 1024x1024 for product shots and thumbnails, 1024x1536 for portrait/mobile.
Cost Guidance
Per-image costs in USD (verified April 2026).
xAI (default provider) -- flat rate regardless of quality/resolution/size:
| Model | Cost/image | Notes |
|---|---|---|
grok-imagine-image |
$0.02 | Default. 300 RPM. Supports quality and resolution params at no extra cost. |
grok-imagine-image-quality |
$0.07 | Higher fidelity, better prompt adherence, sharper at 2K resolution. 30 RPM. |
OpenAI (--provider openai) -- quality-dependent:
| Model | Quality | Square (1024x1024) | Landscape/Portrait (1536x) |
|---|---|---|---|
gpt-image-2 |
low |
$0.009 | $0.013 |
gpt-image-2 |
medium |
$0.034 | $0.050 |
gpt-image-2 |
high |
$0.133 | $0.200 |
gpt-image-1-mini |
low |
$0.005 | $0.006 |
gpt-image-1-mini |
medium |
$0.011 | $0.015 |
gpt-image-1-mini |
high |
$0.036 | $0.052 |
Cost-aware usage for agents:
- xAI is the default for a reason. At $0.07/image (Pro), it undercuts OpenAI high ($0.133) by half. Generate, edit, style-transfer, restore, thumbnail, and batch all work on xAI.
- Switch to OpenAI only when needed. Transparent backgrounds, mask-based inpainting, multi-image edit (multiple input files),
describe(vision), and--input-fidelitycontrol are OpenAI-only features. Use--provider openaifor those. - Batch math: A 10-image batch on xAI costs $0.20. The same batch on OpenAI at high quality landscape costs $2.00. That is a 10x difference.
- Describe is nearly free.
gpt-4o-minivision calls cost fractions of a cent per image. Usedescribe --mode jsonfreely for analysis, alt text, and tagging. Always uses OpenAI regardless of--provider. - Edit costs the same as generate on both providers. Using a reference photo does not add cost but dramatically improves quality. Always prefer edit with a reference photo over blind generation.
Photo-First: Edit Over Generate
The single most important principle in this skill: always prefer editing a real photo over generating from scratch. No text prompt, no matter how detailed, can capture what a photograph captures -- the specific geometry of a building, the exact way light falls across a bar counter, the grain of a wood table, or the proportions of a person's face. A photo grounds the generation in reality. Without one, the model hallucinates every detail.
This applies to:
- Real places -- venues, buildings, landscapes, interiors, storefronts
- Real products -- bottles, packaging, dishes, glassware, merchandise
- Real people -- portraits, headshots, action figures, stylized likenesses
- Real events -- setups, table arrangements, stage configurations
Why this matters
generate creates from nothing. The model invents proportions, invents lighting, invents spatial relationships. Even with a perfect prompt, the result is a plausible fiction. edit and style-transfer start from truth -- the actual photo -- and transform it. The difference is visible immediately and becomes critical when the output represents something real that people will recognize.
Edit costs the same as generate. There is zero cost penalty for using a reference photo. The only cost is asking the user for one.
Decision tree
Does a real-world photo of the subject exist (or could the user take one)?
YES → Use edit or style-transfer with the photo as input
Is the goal to apply a uniform art style to the whole image?
YES → style-transfer (watercolor, pixel-art, oil-painting, etc.)
NO → edit with a descriptive prompt
Does the image contain a person whose face must be recognizable?
YES → edit with identity lock (see Preserving Likeness section)
NO → edit with appropriate --input-fidelity
NO → Use generate with a detailed prompt (Prompt Spec Scaffold below)
Common scenarios
Illustrations of a real venue or place:
# WRONG: generates a generic bar that looks nothing like the real one
omni-image generate "watercolor illustration of The Lavender Farms cocktail bar" -o bar.png
# RIGHT: transforms the actual venue into a watercolor
omni-image style-transfer venue_photo.jpg --style watercolor -o bar_watercolor.png
# RIGHT: more control over the transformation
omni-image edit \
"Transform into a warm watercolor illustration. Preserve the room layout, bar position, and window placement. Soft washes of color, visible brush strokes, paper texture." \
-i venue_photo.jpg --input-fidelity high --quality high -o bar_watercolor.png
Product photography in a new context:
# WRONG: generates a generic bottle shape
omni-image generate "artisanal hot sauce bottle on marble counter" -o product.png
# RIGHT: uses the actual bottle with its real label, shape, and proportions
omni-image edit \
"Place on a white marble counter. Soft diffused studio lighting from above. Subtle shadow beneath. Clean white background." \
-i real_bottle_photo.jpg --quality high -o product_styled.png
Menu art from real dishes:
# Style-transfer for uniform illustration style across a menu
omni-image style-transfer risotto_photo.jpg --style watercolor -o menu_risotto.png
omni-image style-transfer steak_photo.jpg --style watercolor -o menu_steak.png
# Or edit for more photographic polish
omni-image edit \
"Fine dining food photography. Enhance plating, adjust lighting to warm directional from 10 o'clock. Deepen background blur." \
-i dish_photo.jpg --input-fidelity high --quality high -o menu_hero.png
Real building in a different context:
# Preserve architecture, change the surroundings
omni-image edit \
"Cover in fresh snow. Overcast winter sky. Warm light glowing from the windows. Footprints in the snow leading to the front door." \
-i storefront_summer.jpg --input-fidelity high --quality high -o storefront_winter.png
When you genuinely need generate
Use generate only when no reference photo exists or could exist:
- Fictional subjects (fantasy creatures, imagined places, concept art)
- Abstract visuals (textures, patterns, backgrounds, gradients)
- Icons and UI elements (app icons, empty states, illustrations)
- Subjects the user cannot photograph (historical scenes, future concepts)
Even then, consider whether a similar photo could serve as a structural anchor via edit.
Finding reference photos
When the user doesn't have a photo, the agent can search for one. Real places, landmarks, products, and public buildings all have photos available online. Use web search or image search to find a reference, download it, and feed it into edit or style-transfer.
# Search for a reference photo of a real place
firecrawl search "The Alamo San Antonio exterior photo" --sources images -o .firecrawl/alamo-ref.json --json
# Download the best result
curl -sL "$IMAGE_URL" -o ref_alamo.jpg
# Now use it as a reference for the illustration
omni-image style-transfer ref_alamo.jpg --style watercolor -o alamo_watercolor.png
This works for:
- Landmarks and buildings -- search by name, download exterior/interior shots
- Products -- search for the brand/product name, use official product photos
- Dishes and food -- search for the dish name, use a well-shot example as a base
- Venues -- search the business name, pull from their website or review photos
The downloaded reference does not need to be perfect. Even a mediocre photo of the right subject gives the model more to work with than the best text prompt describing it from scratch.
Agent behavior
When the user asks for an image of something real:
- Ask if they have a photo. A phone snapshot is enough.
- If they don't, search for one. Use web/image search to find a reference photo of the subject. Download it and use as input.
- If they provide a photo (or you found one), choose between
style-transfer(uniform art style) andedit(selective control). - If the photo contains a person whose likeness matters, follow the Preserving Likeness protocol.
- Only use
generatefrom scratch as a last resort -- when no reference photo exists, can be taken, or can be found online.
Prompt Engineering
The GPT image models respond well to detailed, specific prompts. A few things that help:
- Be specific about style: "oil painting", "3D render", "pixel art", "watercolor", "photorealistic"
- Describe composition: "close-up", "aerial view", "centered", "rule of thirds"
- Mention lighting: "golden hour", "dramatic shadows", "soft diffused light"
- Include context: "on a white background", "in a forest setting", "floating in space"
For edits, describe the full desired result rather than just the change. "A portrait of a person wearing a red hat in a garden" works better than "add a hat".
Prompt Spec Scaffold
When building prompts for image generation, use this structured template. Fill in each segment that applies, skip the rest. The agent should compose the final prompt by concatenating the filled segments into a single string.
[SUBJECT] What is the main focus? e.g. "A Bengal cat sitting on a stack of old books"
[STYLE] Art style or medium. e.g. "Hyper-real photograph" or "Ukiyo-e woodblock print"
[COMPOSITION] Camera angle and framing. e.g. "Close-up, shallow depth of field, rule of thirds"
[LIGHTING] Light source and quality. e.g. "Warm golden hour side-lighting, long shadows"
[COLOR] Palette or mood. e.g. "Muted earth tones with a pop of teal"
[BACKGROUND] Setting and context. e.g. "In a dimly lit library with leather-bound volumes"
[CONSTRAINTS] Technical limits. e.g. "No text, no watermarks, transparent background"
Example assembled prompt:
A Bengal cat sitting on a stack of old books. Hyper-real photograph. Close-up, shallow depth of field, rule of thirds. Warm golden hour side-lighting, long shadows. Muted earth tones with a pop of teal. In a dimly lit library with leather-bound volumes. No text, no watermarks.
The agent should auto-enhance user prompts by filling in missing segments. If the user says "make me a picture of a cat", the agent adds style, composition, lighting, and color based on context. No API call needed for prompt enhancement -- the agent does it.
See references/sample-prompts.md for curated examples by category.
Taming xAI's Aesthetic Bias
xAI's image models (built on the Aurora architecture, evolved from FLUX.1) have a strong default toward cinematic drama: high saturation, volumetric lighting, atmospheric depth, and glossy surfaces. This is by design -- xAI markets the models as "especially strong at cinematic instructions." But for editorial, travel, product, or documentary photography, this default produces oversaturated, ornamental results that read as obviously AI-generated.
The xAI API provides no style parameter. All aesthetic steering must happen through the prompt itself (and --prefix). Negative prompts do not work. You cannot say "no oversaturation" -- you must describe what you do want.
The 5-Part Prompt Formula (xAI)
xAI responds better to natural-language scene descriptions than to comma-separated keyword lists. Structure prompts with these five components:
[SCENE] What is happening. Write it like a short film direction.
[STYLE] Visual aesthetic anchor. Be specific: "editorial travel magazine" not "beautiful".
[MOOD] Emotional direction: "understated", "contemplative", "clean", "warm".
[LIGHTING] Use precise references: "3 PM October sunlight", "overcast diffused", "window light from camera left".
[CAMERA] Camera body + lens implies color science, grain, and DOF without listing each:
"shot on Fujifilm X-T4, 35mm f/1.4" or "Hasselblad medium format, natural film grain".
Camera references are the single most powerful shorthand. "Shot on Fujifilm XT4" bundles film-like color science, natural grain, and warm tones into three words. Other effective references:
- Fujifilm X-T4 -- warm, filmic, slightly desaturated. Great for travel and lifestyle.
- Leica M10 -- contrasty, sharp, classic documentary feel.
- Hasselblad 500C -- medium format film look, creamy bokeh, natural skin tones.
- Canon EOS R5, 85mm f/1.2 -- clean, sharp, shallow DOF. Good for portraits and products.
- 35mm Kodak Portra 400 -- warm, slightly overexposed, golden-hour travel aesthetic.
Steering Prefixes by Content Type
Use --prefix to apply consistent aesthetic direction across multiple images. These are tested prefixes that counteract xAI's dramatic defaults:
Editorial travel photography:
--prefix "Clean editorial travel photography. Shot on Fujifilm X-T4, 35mm lens. Natural lighting, muted warm tones. Documentary feel, not dramatic. Soft grain, gentle vignette."
Product photography:
--prefix "Clean commercial product photography. Soft diffused studio lighting. Neutral white background. Sharp focus, natural colors. No dramatic shadows or atmospheric effects."
Real estate and interiors:
--prefix "Architectural photography. Shot on Canon EOS R5 with tilt-shift lens. Even natural lighting, true-to-life colors. Clean, unprocessed look. No HDR, no dramatic contrast."
Editorial food photography:
--prefix "Editorial food photography. Shot on Hasselblad, 80mm lens. Warm directional light from 10 o'clock. Shallow depth of field. Natural colors, no oversaturation."
Modern Industrial Luxury (The 'NJOY' Aesthetic):
--prefix "Ultra-sharp modern commercial product photography isolated on a pure, deep black void. High-contrast, stark, sculptural studio lighting. Deep rich true blacks, bright pristine highlights. Sleek, premium, sterile yet luxurious aesthetic. Shot on Canon EOS R5. No film grain. No vintage retro grading."
Note on Modern Industrial Luxury: This aesthetic works by treating mundane, utilitarian objects (like a plastic ethernet connector, a rubber cable, or a basic bracket) with the exact same reverence and dramatic lighting used for high-end consumer electronics or luxury watches. It is about the treatment (pure black background, stark sculptural lighting, ultra-sharp focus), not just the material.
Portraits and headshots:
--prefix "Natural portrait photography. Shot on Canon 85mm f/1.2. Window light, soft and diffused. True skin tones, no airbrushing. Documentary, not glamour."
Landscape and nature:
--prefix "Shot on Kodak Portra 400 film. Muted earth tones, soft grain. Natural, understated. No HDR, no oversaturation, no volumetric god rays."
What NOT to Do with xAI Prompts
- Do not use negative phrasing. "No oversaturation" or "not dramatic" gets ignored or misinterpreted. Instead, describe the positive: "muted earth tones", "natural lighting", "documentary feel".
- Do not stack more than 2 style cues. Saying "impressionistic, cyberpunk, art deco, photorealistic" causes the model to default to a generic "safe" style. Pick one or two complementary directions.
- Do not rely on single adjectives. "Beautiful" and "high quality" are noise. Use specific descriptors: lens, film stock, lighting angle, color temperature.
- Front-load the important words. xAI weights the first 20-30 words most heavily. Put the subject and critical style direction first, details second.
Typography and Text in xAI (Grok)
Grok struggles more with text rendering and typography layout than OpenAI. If you simply ask for "A poster that says X", Grok will often garble the text or lose the structural layout. To get high-quality text out of Grok:
- Treat text as a physical, structural prop. Do not just ask for text; describe where the text lives in the physical space of the image. (e.g., "A crinkled diner receipt unspooling across the frame. The itemized charges feature the exact text:" or "A massive fight card list dominates the center. The exact text reads:")
- Always use
--resolution 2k(or thegrok-imagine-image-qualitymodel). The higher resolution is strictly necessary for the text rendering engine to resolve smaller letters clearly. - Use ALL CAPS. Grok renders uppercase block lettering significantly better than lowercase or cursive scripts.
- Use exact quotes. Say
The exact text reads: 'HELLO WORLD'rather thanIt should say hello world. - Isolate each text element in its own sentence. Separate position, font style, and content:
At the top, bold condensed sans-serif text reads "ARIZONA". Below the illustration, smaller italic serif text reads "Land of the Sun". - Keep strings under ~25 characters per element. Longer strings increase substitution errors. Break long text into two lines in the prompt.
Grok Aurora Architecture: Why It Prompts Differently
Aurora (the engine behind grok-imagine-image) is an autoregressive mixture-of-experts network, not a diffusion model. It generates images patch by patch the way a language model generates tokens. This has direct prompting implications:
- Natural language over keyword stacks. Coherent sentences work better than comma-separated tags. "A neon hot dog glowing in a purple sky above lavender fields" beats "neon, hot dog, purple sky, lavender, glowing".
- Text rendering is architecturally stronger than diffusion models because text and visual tokens share the same pipeline. Still not perfect, but Grok renders poster text better than Stable Diffusion or Midjourney.
- Follows composition literally. Diffusion models interpret artistically; Aurora tends toward literal execution. If you say "explosion in the background," you get an explosion in the background, not a stylistic interpretation.
- Earlier tokens matter more. Front-load the subject and critical style direction in the first 20-30 words. Details come second.
- Supports ~1,000 characters without degradation. Density helps. Short prompts produce flat, stock-photo results. Pack in specific visual details.
The Grok Poster Principle
For text-heavy graphics (posters, lineups, menus, cards), Grok works best with:
One killer visual + crisp text + loaded atmosphere.
Do NOT try to illustrate every element. The festival lineup poster that worked had ONE dominant visual (neon hot dog sun over lavender fields) and let the TEXT carry the lineup. The five genre re-skins that looked generic each tried to cram 9 competing vignettes into the frame.
Recipe:
- One clear visual metaphor (anchors the whole image)
- Text elements specified individually with position and font
- Atmospheric details (lighting, color, mood) woven as natural language
- Style anchor (one or two references, not a tag stack)
Named Artist/Style References
Aurora responds to named references because of its broad training data. Use these as shorthand:
- Photorealism: "National Geographic style", "Platon portrait lighting"
- Illustration: "Greg Rutkowski", "Simon Stalenhag environmental feel"
- Landscape: "Albert Bierstadt tonality", "Hiroshi Sugimoto long exposure"
- Anime: "Makoto Shinkai atmospheric haze", "MAPPA character design"
- Retro/vintage: "WPA poster aesthetic", "Saul Bass graphic design"
Agentic Workflow: Prompt Iteration
When tasked with generating a highly specific image (like a poster with text, or a complex visual concept), do not expect to get it right on the first try. You must learn how to prompt by iterating.
At $0.02-0.07/image on Grok, you should iterate freely. The standard agent workflow for complex image requests is:
- Draft: Generate a V1 using a best-guess prompt based on the 5-Part Formula and isolation patterns for text.
- Review: Look at the result (using the
describecommand, or by asking the user for qualitative feedback like "what went wrong with V1?"). - Isolate the Failure: Identify the specific weakness. Did the text garble? Was the lighting too dramatic? Did the subject drift?
- Refine ONE Variable: Change exactly one element at a time between regenerations (e.g., adjust only the lighting description, or only the font layout). Changing the lighting, background, and mood simultaneously makes it impossible to identify what caused improvement or regression.
- Re-generate: Fire the new prompt and repeat until the output matches the user's intent perfectly.
Grok Visual Content Policy (Tested April 2026)
Grok's image generation API has minimal visual content filtering. Empirical results from systematic testing:
Renders without refusal:
- Silhouettes of sexual positions (oral, from behind) against gradient backgrounds
- Nudity in "classical art" framing (Renaissance paintings, marble sculptures)
- Boudoir/lingerie photography
- Nude couples in shower scenes (steam partially obscuring)
- Pin-up illustrat
…(truncated)