One-sentence positioning: generate images using the Codex agent's built-in image generation capability; this Skill handles only five things — turning requirements into good prompts, getting the command to run, acceptance, compression, and putting them in the directory where the project expects them.
Image generationis not a CLI subcommand(there is no codex image;codex exec --image is attaching an image as input). It is the Codex agent's built-in tool image_genDo not search codex --help for a flag, and if you cannot find one, conclude "cannot generate images" — that conclusion is wrong. Describe the image you want and let the agent choose the method itself.
Startup command
mkdir -p <outdir> # 先建目录,提示词里写它的绝对路径
cat <outdir>/prompt.md | codex exec --skip-git-repo-check \
--config model_reasoning_effort="medium" \
--sandbox danger-full-access \
-C <outdir> -o <outdir>/final.md 2>/dev/null
| Key points | Description |
|---|---|
| Run in background | Bash in Bash's run_in_background: true; two images take about 2–3 minutes, and a full set takes longer; wait for the completion notification, do not poll.Note: must be called from the main thread (not a subagent)—a subagent uses run_in_background and then parks waiting for a notification, which the harness will judge as idle and terminate, so the notification can never be delivered |
--sandbox danger-full-access |
Image generation requires network access. Whether this flag needs confirmation depends on the current machine's authorization settings: if there is standing authorization, run it directly; if not, confirm once according to that machine's rules; either way, the startup line must state which sandbox was used |
-o <outdir>/final.md |
The final report is written to a file; read the path and method from there; stdout is progress noise, do not parse it |
2>/dev/null |
Suppress stderr's thought stream; only remove it when debugging Codex itself |
| effort | medium is enough; this is not a reasoning task |
Do not pass -m |
Use ~/.codex/config.toml 's default model; only override if the user names one |
| Where the original images are | Every Codex image_gen 's raw output lands in ~/.codex/generated_images/<session-id>/exec-*.png(0.7–1.5 MB per image); what is in the output directory is its post-processed version; go there to get the originals |
codex --version fails or exits at startup: first codex doctor, report truthfully, and do not blindly retry.
How to write the prompt
A prompt.md must contain six things; if one is missing, a class of problem will occur:
- Absolute path of the output directory(already
mkdir -p)。 - numbered one by one: exact filename + specific description + pixel dimensions/aspect ratio.
- Shared style block: art style, background,hex color palette, lighting, lens — a set of images relies on this to stay consistent.
No text, no letters, no logos, no watermarks.text generated by- Escape hatch:
If you genuinely cannot generate images, say so plainly. Do not substitute placeholders, ASCII art, solid rectangles, or images downloaded from the web. - Reporting requirements: each file's absolute path, actual pixels, byte count, whether it has alpha, and the method used (which tool/model, whether there was local post-processing).
For transparent images be sure to write true alpha, not a white/dark square— in practice Codex self-checks based on this sentence; the first version baked in a background color and then redid it on its own.
Then add a commonly used fallback:If the exact size is unsupported, generate the nearest aspect and resize locally (sips / PIL) to the exact pixels; keep alpha for transparent items.
Complete example (a two-image set: mascot + og:image)
Generate two images with your built-in image generation tool and save them to:
<outdir absolute path>/
Shared style: palette #2563EB (primary) #F59E0B (accent) #0F172A (ink) #F8FAFC (paper).
No text, no letters, no logos, no watermarks anywhere.
1. `mascot-logo.png` — 1024x1024, transparent background PNG (true alpha, not a white square).
A friendly round owl holding a tiny wrench. Flat vector style, bold clean shapes,
2-3 flat tones per element, no gradients, no drop shadows. Occupies 75-80% of the
frame, centered, exclude the wrench from that measure.
2. `og-image.png` — 1200x630 (1.91:1), opaque. Photorealistic editorial photo: a person
in their late twenties at a wooden desk in front of a laptop, soft window light from
the left, shallow depth of field, calm home office, mug and small plant. Eye-level,
subject on the left so the right third is clean negative space. Laptop screen is a
soft blurred blue-white glow, nothing readable.
Rules: if you genuinely cannot generate images, say so plainly — no placeholders, ASCII
art, solid rectangles, or web downloads. If the exact size is unsupported, generate the
nearest aspect and resize locally (sips / PIL); keep alpha for the mascot.
Report per file: absolute path, actual pixels, bytes, alpha yes/no, method used.
Templates by purpose
| Purpose | Size / format | Style block key points | Mandatory constraints |
|---|---|---|---|
| logo / favicon source image | 1024×1024 transparent PNG; subsequently sips -Z scale down to 512/192/180/32/16 |
flat vector, bold silhouette, 2–3 tones, no gradients | Subject occupies 75–80%;still recognizable at 16px(single shape, not reliant on detail); no text |
| Mascot | 1024×1024 transparent PNG; for a set, same prompt with multiple poses | Same as above + numeric features such as head-to-body ratio, eye diameter ÷ head width | Species, prop (only one allowed), and color scheme all hard-coded; prop does not count toward the proportion |
| og:image / share image | 1200×630, opaque; one independent image per page | Subject offset to one side, clean negative space on the other (title overlaid later) | Subject still discernible when scaled to 120px; no text;must not be shared site-wide |
| Inner-page illustration | 1600×900 or 4:3; JPEG/WebP | Consistent with the site color palette; same art style across the same site | Semantically related to that page's target terms (write the scene, not keywords) |
| User scenario / real-person image | 1600×1067 (3:2) or 1200×630 | photorealistic editorial, natural window light, shallow DoF, 35–50mm perspective | Write age range, action, environment, light direction, composition; screen content "blurred and glowing, no readable text"; do not write real people's names |
| Hand-drawn / crayon / watercolor illustration | 1600×1200 or square; opaque if with paper texture | crayon on textured paper / loose watercolor, visible strokes, limited palette | Write paper color and graininess; line thickness; whitespace ratio |
| Poster / cinematic image | 2:3 (1000×1500) vertical or 21:9 horizontal | cinematic, anamorphic, volumetric light, color grade written as two hex colors | Leave text area empty; state the subject position clearly (which cell of the rule of thirds) |
State the size ratio clearly; when the model can't give exact pixels, rely on local scaling, see "Compression and saving to disk".
Consistency of a set of images
- Produce a set from one prompt file, put the shared style block at the top and write only the differences per image; when running in batches, copy the same style block verbatim.
- Write the palette with hard-coded hex, not "blue-ish"; within the same set also write character proportions, line width, and paper texture as numbers.
- When adjectives hit a ceiling ("make it more Japanese-style"), switch to measurable parameters: head-to-body ratio, eye diameter ÷ head width, line width ÷ image width, HSV saturation range, whitespace ratio. Measure the reference set and the output with the same script, produce a "parameter | reference range | our value | verdict" table, and only then can feeling become a checklist that can be fixed item by item.
- You can write prompts in the target language by default (n=3 blind evaluation favored the target language, but not significantly), but what truly works is writing the visual constraints as numbers.
Acceptance: three checks, miss one and you miss a class of problems
Source:codex/references/image-experiments.md"Acceptance of a set of images", a record of 16 character images on 2026-08-22, where the three checks each caught different defects.
First use Read to open and look at each one, then discuss the three items below; images you haven't looked at are not allowed onto the page. All three are mandatory—skip one and you miss a whole class of problems.
- Contact sheet(catches composition imbalance): shrink them all to 120px and tile them into one horizontal strip—this is the real size of the results page/share card. An image that looks beautiful at full size but is reduced to just a chair in the thumbnail can only be exposed by this step.
sips -Z 120 in.png --out thumbs/in.png - alpha bounding box ratio(turns "is it big enough" into a number):
Measured a set of six: 41%–66%, none of them met the bar and they differed by 1.6x, yet side by side they just looked "a bit messy." In the prompt, besides writing the ratio you also need to stateprops don't count。from PIL import Image im = Image.open(f).convert('RGBA'); bb = im.getchannel('A').getbbox() frac = (bb[2]-bb[0])*(bb[3]-bb[1]) / (im.width*im.height) # 目标 0.75–0.80 - Independent blind review(catches style and rule compliance, the easiest thing to skip): shuffle the paired results into
pairN-A/B, put the comparison table outside the project directory, and assign an agent that wasn't involved in generation to evaluate, explicitly saying "can't tell the difference" is acceptable. Non-blind judgment was once reversed for an entire group by blind review; the mechanism was extra props.
Reference images / mood board
Style is not protected by copyright; feeding reference images is standard practice in the design industry.The control point is on the output side, not the input side:
- For reference images usea set(10+ images from different sources tiled into a mood board), not a single image—a single image is the most likely to end up looking like the original.
- Reference images only convey texture (linework, coloring, head-to-body ratio),the subject is hard-coded by us: species, props, pose, color scheme.
- After generating, do a similarity check side by side with the reference set: "would this be recognized as some existing character"—if it looks like one, change the subject features and regenerate, don't change the style.
- In the prompt,don't name copyright-protected characters or "in the style of X": the reference images have already conveyed the information; naming only adds risk without adding effect.
Compression and committing to disk
Original images are about 1 MB each as PNG,no compression, no entry into the repo。
sips -s format jpeg -s formatOptions 82 in.png --out out.jpg # 不透明图:JPEG,4 MB 一套压到 1 MB 内
cwebp -q 82 in.png -o out.webp # 页内用 WebP(透明也保留)
cwebp -q 82 -alpha_q 100 mascot.png -o mascot.webp # 透明主体,alpha 无损
sips -Z 512 logo.png --out icon-512.png # 等比缩最长边
sips -z 630 1200 og.png --out og.png # 精确到像素(先高后宽)
When transparency wasn't achieved, or the subject ratio doesn't meet the bar, use ImageMagick for a second pass (first which magick, if not available then brew install imagemagick):
magick in.png -fuzz 8% -transparent '#0F172A' out.png # 纯色底抠透明(换成实际底色 hex)
magick in.png -trim +repage -resize 800x800 -gravity center \
-background none -extent 1024x1024 out.png # 裁掉空边,主体缩到约 78% 再居中回 1024²
magick out.png -format 'alpha_min=%[fx:minima.a] colors=%k\n' info: # alpha_min 必须是 0 才算真透明
| Asset | Format to keep | Where it goes (example path) |
|---|---|---|
| logo / icon set | Transparent PNG source + SVG (if any); export 512/192/180/32/16 | <project>/public/brand/,manifest.json referenced for real one by one |
| og:image | PNG or JPEG(WhatsApp/FB preview crawlers are unstable with WebP;rankup/references/seo-experiences.md 2026-07-18) |
<project>/public/og/<page-slug>.png, one per page |
| In-page illustrations / scene images | WebP (same image 175 KB→56 KB),<img> write the real width/height |
<project>/public/images/<section>/ |
| Original generated artifacts and prompt.md | Archived as-is, not committed to public/ |
<project>/design/imagegen/<batch>/ |
- For multi-file loops and wait polling, always use
python3heredoc-driven: in Claude Code's Bash tool, barefor f in *.png; do …; doneanduntil [ -f x ]; do sleep 2; donemay reportparse error near 'done'(measured on 2026-09-02 in a macOS zsh environment); heredoc is the most reliable. - Light-background illustrations need to be darkened for dark themes:
filter: brightness(.84) saturate(.92)。 - After wiring up the page,
curl -I200 per image; after migrating the repo structure, favicon/og silently 404ing is a pitfall we've hit.
Relationship to rankup
rankup/SKILL.mdSection 3 (site building) hard rules and the "which section does a one-liner fall into" table both point to/imagegen: whenever the site needs any visual asset, come here and actually generate it.- Paragraph 3 red line:no page may contain placeholder images(gray blocks,
placeholder, template sample images), Google will judge it a spam site based on this and the whole site will be penalized together; Paragraph 4 hard rule:each page must have its own og:image and must have an image, ≥1200px wide, sharing one across the entire site does not pass. With both combined, without image generation capability the only option left is placeholders—so image generation is a fixed step in the site-building process, not optional beautification. - After the images are done, go back to rankup to go through the gate:
checklists.mdParagraph 3 "no-placeholder red line", Paragraph 4 "each page has its own title/description/og:image and has an image", and Gate 0 icon full set andmanifest.jsonreferences all real, markings verified at 16px. - og dual format:
og:image/twitter:imageuse PNG/JPEG in-page,<img>、JSON-LDimage, image-sitemap uses WebP.
Anti-patterns
- Flip through
codex --helpand if you can't find an image flag, declare "Codex can't generate images". - Run
codex execin the foreground and make the user wait; or tightly poll the background shell. - On a machine with standing authorization, still repeatedly ask for permission for
--sandbox danger-full-access—handle it once according to that machine's rules, and just disclose it in the startup line. - In the prompt, have the model draw text, slogans, or brand names.
- Without opening it with
Read, plug the image into the page; or commit the uncompressed multi-MB original image into the repository. - One image per page but the entire site shares the same og:image; or first stuff in a gray block to "replace later".
- Use a single work by someone else as reference and name the character in the prompt.
- Do only one or two acceptance checks and move on; write non-blind judgments directly into the conclusion.
- Shrink the batch or avoid regenerating to "save quota"—first check the current account's plan; when quota is sufficient, if the first version is a bit off, run it again; don't limit yourself with guessed quota limits.
- Inside a subagent, use
run_in_background: trueto runcodex exec—after the subagent parks, the harness considers it idle and terminates it, the completion notification can never be delivered, the image is generated but no one receives it.Must be run from the main threadcodex exec(Bash'srun_in_background: true) and the main thread can correctly receive the completion notification; or inside the subagent, switch to foreground synchronous waiting (but it will occupy the subagent context for several minutes). On 2026-09-11, the same batch of tasks was retried three times because of this.
Verified (2026-09-02, codex-cli 0.149.0)
- Chain: two images as one set (1024² transparent mascot + 1200×630 real-person scene og:image), the command is the template above,
-o final.mdget the final report. exit 0, no errors,total time 302 s(about 5 minutes). - Method used by Codex: built-in
image_gentool (gpt-image-1.5 / gpt-image-2 appear in the logs, Codex self-reports "specific model name not disclosed"); this round it was called 9 times in total,all original images landed in~/.codex/generated_images/<session-id>/exec-*.png, each 0.7–1.5 MB. The final files were post-processed by it using ImageMagick (magick, local machine 7.1.2): mascot resize →-remaplock the four hex values in the prompt → alpha extraction; the og image was slightly center-cropped and scaled to exactly 1200×630. If you want the original images that have not been post-processed, go togenerated_images/to get them. - Result:
og-image.png1200×630 RGB 757 KB, composition, lighting, and screen blur with no text all meet the requirements;mascot-logo.png1024×1024 RGBA 33 KB (four-color quantization),true transparency—57% of pixels have alpha=0, alpha extremes (0,255). - The transparent background had a detour: by around 3.5 minutes there was already a version in the directory
mascot-logo.png, with alpha all 255 and the dark blue background baked in; Codex itself ran two more rounds before producing true transparency at minute 5. Two lessons: ①final.md/ don't measure the image before the exit code comes out, intermediate states will cause misjudgment; ② in the prompt,true alpha, not a white/dark squarethis sentence must be written, it really relied on this sentence for self-checking. If it is still not transparent in the end, do a second pass with the ImageMagick background-removal command from "Compression and Saving to Disk", and do not write success. - One item that did not meet the standard: mascot alpha bounding box ratio 0.62, the prompt wrote 75–80% and it was still not enough (the same phenomenon as the 41%–66% batch on 2026-08-22). The fix is in "Compression and Saving to Disk":
-trimthen according to the target ratio-resizeagain-extentback to 1024². - Compression measured:og PNG 757 KB →
sipsJPEG q82 92 KB →cwebpq82 27 KB; the four-color quantized transparent PNG 33 KB → WebP is instead 48 KB,use the already quantized flat transparent PNG directly, do not convert to WebP。 - Contact sheet
sips -Z 120both images have a distinguishable subject; blind evaluation was not done this time (a single image has no comparison).