zenmux-image-generation
Turn the user's visual intent into an optimized prompt, confirm the prompt and parameters, then generate or edit images through ZenMux and report the saved files.
Defaults when the user does not specify them:
- Model:
openai/gpt-image-2 - Count:
4 - Size:
1024x1024 - Quality:
medium - Format:
png - Output directory:
skills/zenmux-image-generation/output/
Prompt history belongs to the current project, not this skill. Save it under
.context/prompts/zenmux-image-generation/ relative to the project root.
1. Prepare the runtime and refresh sources
Require Node.js 22 or newer. Install locked dependencies once per clone or after dependency changes:
npm ci --prefix skills/zenmux-image-generation
Generation requires ZENMUX_API_KEY. Never accept the key as a CLI argument
or print it:
export ZENMUX_API_KEY=...
At the beginning of every invocation, refresh the bundled documentation, prompt cookbooks, and offline model snapshot:
bash skills/zenmux-image-generation/scripts/refresh_references.sh --quiet
If the user named a model, preserve it. Otherwise, list current image models unless the simple default clearly applies:
bash skills/zenmux-image-generation/scripts/list_models.sh
# Machine-readable alternatives:
bash skills/zenmux-image-generation/scripts/list_models.sh --names-only
bash skills/zenmux-image-generation/scripts/list_models.sh --json
The model command queries ZenMux live first and falls back to
references/zenmux-image-models.json when offline. Never invent a model ID from
memory.
Use sources in this order:
references/zenmux-openai-image-generation.mdfor ZenMux OpenAI Images protocol and TypeScript examples.references/zenmux-create-image-edit.mdfor edit fields, masks, limits, and request shapes.references/openai-typescript-images-generate.mdorreferences/openai-typescript-images-edit.mdfor the current OpenAI SDK signature.references/zenmux-image-generation.mdfor the Gemini/Vertex-compatible protocol.references/zenmux-generate-images.mdfor the complete Vertex AIgenerateImages/editImageparameter map.references/google-gemini-image-generation.mdfor Google's latest native Interactions API and the explicit ZenMux compatibility boundary.- The
awesome-*files for prompt inspiration only, never API truth.
2. Resolve intent
Extract the following. Ask only for missing information that materially changes the result, with at most three focused questions.
| Field | Default |
|---|---|
| Subject and desired change | Required |
| Style, composition, lighting, mood | Infer from the request |
| Reference images | None |
| Model | openai/gpt-image-2 |
| Size | 1024x1024 |
| Quality | medium |
| Count | 4 |
| Output format | png |
| Exact text in image | None |
| Semantic filename prefix | Short English kebab-case summary |
Aspect shortcuts:
- Portrait, 竖版, phone wallpaper, story:
1024x1536 - Landscape, 横版, banner, widescreen:
1536x1024 - Square, 方形, logo, icon, social post:
1024x1024 - 4K for
gpt-image-2:3840x2160 - 2K/QHD for
gpt-image-2:2560x1440
Capture every reference path or URL in user-supplied order. Accept local paths,
file://, http(s)://, and base64 image data URLs. Number references as
[Image #1], [Image #2], and so on in both prompt metadata and prompt text.
The flag order must match this numbering.
3. Choose the current model and protocol
The live model catalog is authoritative. As of the bundled snapshot, useful choices include:
| Need | Suggested model |
|---|---|
| General/high-quality default | openai/gpt-image-2 |
| Lower-cost OpenAI alternative | openai/gpt-image-1.5 |
| General Nano Banana default | google/gemini-3.1-flash-image |
| Lowest-latency Nano Banana | google/gemini-3.1-flash-lite-image |
| Complex professional assets | google/gemini-3-pro-image |
| Chinese poster/product design | qwen/qwen-image-3.0-pro, bytedance/doubao-seedream-5.0-pro |
| Photoreal or flexible creative work | bfl/flux-2-max, bfl/flux-2-flex, bfl/flux-2-pro |
| Other current options | klingai/kling-v3, sapiens-ai/agnes-image-2.1-flash, tencent/hy-image-v3.0, z-ai/glm-image |
Route by protocol:
openai/gpt-image-*, baregpt-image-*, andchatgpt-image-latestusescripts/generate-openai.tsandhttps://zenmux.ai/api/v1by default.- Every other model uses
scripts/generate-gemini.tsandhttps://zenmux.ai/api/vertex-ai. - If the user explicitly requests Gemini protocol for an OpenAI model, honor it
with
generate-gemini.ts.
Google’s direct Gemini API now documents client.interactions.create as its
native image-generation surface. ZenMux has not documented that route. Through
ZenMux, continue using generateContent for Google Gemini image models and
generateImages / editImage for all other image models. Do not send an
Interactions API payload to ZenMux until ZenMux explicitly announces support.
The current @google/genai SDK warns that generateImages is deprecated and
will be removed in its next major release no earlier than 2027-01-01. Treat the
method as a ZenMux compatibility bridge and re-check ZenMux docs before a major
SDK upgrade.
For gpt-image-2, custom WIDTHxHEIGHT values must have both edges divisible
by 16, an aspect ratio between 1:3 and 3:1, and 655,360-8,294,400 total pixels.
Resolutions above 2560x1440 are experimental; maximum is 3840x2160.
Other OpenAI image models should use auto, 1024x1024, 1536x1024, or
1024x1536.
4. Follow OpenAI Create/Edit best practices
Use the Images API for one-shot generation or editing. Use Responses API only when the user's actual product needs conversational, multi-turn image state; the bundled helper intentionally uses Images API.
For generation:
- Call
client.images.generatethrough the TypeScript SDK. - GPT Image returns
b64_json; decode and save the bytes without transcoding. - Use
nfor multiple outputs in one request when the model permits it. transparentbackgrounds require PNG or WebP.gpt-image-2transparent PNG/WebP output is currently a preview capability. Request it withbackground=transparent; merely asking for PNG does not create an alpha channel.output_compressionapplies only to JPEG or WebP.
For editing:
- Call
client.images.editand convert local/remote/data-URL bytes with the SDK'stoFilehelper. - Supply at most 16 input images and preserve their order.
gpt-image-2always processes image inputs at high fidelity, so omitinput_fidelity. Useinput_fidelity=highonly for earlier supported GPT Image models when identity preservation matters.- A mask applies to the first input. It must be PNG, under 4 MB, and match the first image dimensions. Fully transparent mask areas indicate what to edit.
- State the requested change first, then explicitly list everything that must remain invariant.
The scripts accept URL output as a defensive fallback, verify returned image magic bytes, use timeouts/retries, and never overwrite an existing file.
5. Optimize and save the prompt
Search only the relevant cookbook entries; do not read either cookbook end to end:
rg -n '^### No\..*(poster|portrait|product|infographic)' \
skills/zenmux-image-generation/references/awesome-gpt-image-2.md
Use awesome-gpt-image-2.md for OpenAI-oriented examples and
awesome-nano-banana-pro-prompts.md for Gemini-oriented examples. Adapt their
structure, not their subject.
Prompt order:
- Scene/background and composition
- Main subject and action
- Materials, lighting, palette, lens/render style
- Exact quoted copy, when required
- Edit relationships between
[Image #N]inputs - Constraints and invariants
For an edit, write surgical instructions such as: "Change only X. Preserve identity, pose, geometry, camera angle, lighting, framing, background, and all unmentioned details." Repeat invariants on every follow-up edit.
Save the prompt as:
.context/prompts/zenmux-image-generation/<YYYYMMDD-HHMMSS>-<short-slug>.md
Use this format:
# Optimized prompt — <summary>
- **Model:** openai/gpt-image-2
- **Size:** 1024x1536
- **Quality:** medium
- **Count:** 4
- **Output format:** png
- **Filename prefix:** launch-poster
- **References:** none
- **Created:** 2026-08-31 14:30 (Asia/Singapore)
---
<optimized prompt body>
Show the optimized prompt and parameters to the user. Do not call the paid generation API until the user confirms. Edit the same prompt file if they ask for small changes.
6. Generate with TypeScript
OpenAI generation:
npm --prefix skills/zenmux-image-generation run generate:openai -- \
--model "openai/gpt-image-2" \
--prompt-file ".context/prompts/zenmux-image-generation/<file>.md" \
--filename-prefix "launch-poster" \
--n 4 --size "1024x1536" --quality "medium" --output-format "png"
OpenAI edit with ordered references:
npm --prefix skills/zenmux-image-generation run generate:openai -- \
--model "openai/gpt-image-2" \
--prompt-file ".context/prompts/zenmux-image-generation/<file>.md" \
--filename-prefix "outfit-edit" \
--n 4 --size "1024x1536" --quality "high" \
--reference-image "/absolute/path/person.png" \
--reference-image "https://example.com/jacket.webp"
Add --mask-image "/absolute/path/mask.png" for a masked edit. For an earlier
GPT Image model, add --input-fidelity high when supported. Add
--background transparent --output-format png for a lossless transparent
asset, or use WebP plus --compression 85 for a smaller transparent asset.
Gemini/Vertex-compatible model:
npm --prefix skills/zenmux-image-generation run generate:gemini -- \
--model "google/gemini-3.1-flash-image" \
--prompt-file ".context/prompts/zenmux-image-generation/<file>.md" \
--filename-prefix "campaign-poster" \
--n 4 --aspect-ratio "2:3" --image-size "1K"
The TypeScript Gemini helper covers both ZenMux protocol shapes:
- Google Gemini image models use
generateContentor--streamforgenerateContentStream. It always requestsTEXTandIMAGE, supports up to 14 ordered references, and uses--aspect-ratio/--image-sizeto buildimageConfig. - Non-Google models use
generateImages, oreditImagewhen references are present. Supported CLI mappings include--negative-prompt,--aspect-ratio,--image-size,--seed,--enhance-prompt,--person-generation,--safety-filter-level,--include-rai-reason,--add-watermark, and--guidance-scale. --sizeand--qualityare OpenAI passthrough fields when an OpenAI model is deliberately called through Gemini protocol.--image-sizebecomessampleImageSizefor othergenerateImagesproviders where supported.- ZenMux Vertex protocol does not map GPT Image's
backgroundfield. Usegenerate-openai.tsfor transparent GPT Image output. - Provider defaults vary when
--aspect-ratioand--image-sizeare omitted. Some providers may also return a different MIME type than requested; the helper detects PNG/JPEG/WebP magic bytes and saves the matching extension.
--output-dir is optional. Pass it only when the user requests a different
location.
7. Object-storage-safe filenames
Every saved image uses this deterministic shape:
<semantic-prefix>-<model-slug>-<utc-millisecond-timestamp>-<8-hex-run-id>-<index>.<ext>
Example:
launch-poster-openai-gpt-image-2-20260831t143012345z-a1b2c3d4-01.png
This is intentionally conservative for Supabase Storage, S3-compatible APIs, CDNs, and signed URLs:
- Lowercase ASCII only in the stem:
a-z,0-9, and- - One final
.beforepng,jpg, orwebp - No spaces, Unicode, slashes, backslashes, control characters, URL-reserved
punctuation, leading dots, or
..segments - UTC millisecond timestamp for lexical ordering
- Random run ID plus output index to prevent collisions during concurrent runs
- Exclusive file creation so a collision cannot overwrite an existing object
Always pass a concise semantic --filename-prefix. If omitted, the script
derives it from the prompt filename and sanitizes it with the same rules.
8. Report and iterate
On success, the scripts print SUCCESS, OUTPUT_DIR, IMAGE_PATHS, and a
single-line RESULT_JSON. Parse RESULT_JSON when another tool needs stable
machine-readable output. Return clickable absolute paths to the user.
For follow-up edits, preserve the selected image as [Image #1], save a new
prompt that restates invariants, confirm it, and run the appropriate edit path.
If generation fails:
- Missing dependency: run
npm ci --prefix skills/zenmux-image-generation. - Model unavailable: rerun
list_models.sh; use the exact live ID. - Invalid size: choose the nearest valid dimensions that preserve aspect ratio.
- Reference rejected: convert it to PNG/JPEG/WebP and keep it under the model's input limit.
- Provider rejects multiple outputs: loop calls with
--n 1and retain the same semantic prefix; each run ID keeps filenames unique.