- name
- codex-image-gen
- description
- Generate or edit raster images from a text prompt by driving the codex CLI's built-in image tool, and save them to a given path. Use when asked to generate, create, make, draw, render, illustrate, or edit an image, picture, photo, illustration, texture, sprite, icon art, mockup, poster, cover art, thumbnail, logo concept, or transparent cutout; when a variant of an existing image is wanted ("make the sky purple", "same but wider"); or when a build step needs a placeholder or asset image. Also use whenever image generation is requested and no other image backend has been specified.
- license
- MIT
# Image Generation via the codex CLI
## Overview
The `codex` CLI carries its own ChatGPT authentication and ships a built-in image
tool, so any agent on this machine can generate images through it with no
`OPENAI_API_KEY` and no other image service.
`codex exec` has no "write the image to this path" flag: it saves what it
generates to `$CODEX_HOME/generated_images/<session id>/` and embeds it in the
session transcript. `scripts/codex_image.py` handles that round trip — it runs
one non-interactive turn, recovers the image, and writes it where you asked.
**Always go through the script.** A hand-rolled `codex exec "draw me a cat"` very
often returns prose or an ImageMagick drawing instead of a generated image, and
leaves you to find the output yourself.
**Never fall back to the OpenAI API.** This skill has no API-key fallback path,
and none should be added or used. Do not call the OpenAI SDK, an `OPENAI_API_KEY`,
or any script that bills a metered OpenAI API account for image generation — not
even when `codex exec` fails or is out of quota. If `codex_image.py` fails, report
the failure (see Failure modes) and stop; do not silently switch to a paid API
path.
## Requirements
- `codex` on `PATH` and logged in (`codex login`). Set `CODEX_BIN` to point at a
different binary.
- Python 3.9+. Standard library only, except `--fit`, which needs Pillow.
- Image generation consumes the codex account's quota. When it is exhausted the
script fails with a clear message and writes nothing; report that to the user
rather than retrying in a loop.
## Quick start
Run from this skill directory, or give the script's absolute path:
```bash
python3 scripts/codex_image.py \
--prompt "a lone red bicycle leaning against a wet stone wall at dusk, cinematic photograph" \
--output ~/Desktop/bike.png
```
A run takes roughly 30–60 seconds. On success the script prints each path it
wrote; on failure it exits non-zero and writes nothing.
## Common invocations
| Goal | Command |
|---|---|
| Basic generation | `codex_image.py -p "<prompt>" -o out.png` |
| Portrait / landscape / square | `codex_image.py -p "..." -o out.png --aspect 9:16` |
| Use a reference image | `codex_image.py -p "..." -o out.png -r ref.png` |
| Edit an existing image | `codex_image.py --edit v1.png -p "make the sky purple" -o v2.png` |
| Several options to choose from | `codex_image.py -p "..." -o opt.png -n 3` |
| Exact pixel dimensions | `codex_image.py -p "..." -o cover.png --aspect 9:16 --fit 1080x1920` |
| Long prompt from a file | `codex_image.py --prompt-file prompt.md -o out.png` |
| Machine-readable result | `codex_image.py -p "..." -o out.png --quiet --json` |
Key flags:
- `--aspect` is a hint passed to the model (`16:9`, `9:16`, `1:1`, `4:5`, …). It
shapes the generated image but does not guarantee exact dimensions.
- `--fit WxH` guarantees them, after the fact: letterbox-pads by default
(`--fit-mode pad`, colour via `--fit-background`) or `--fit-mode crop` to
center-crop instead. Pair it with a matching `--aspect` so there is little to
pad or crop.
- `-n/--variants N` asks for N takes in one run. The first lands at `-o`, the
rest beside it as `<name>-2.png`, `<name>-3.png`. The model does not always
honour the count; the script saves whatever it actually produced.
- `--edit` attaches the image as the edit target and instructs the model to
change only what the prompt asks for. Write the prompt as the *change*
("remove the lamp post"), not as a fresh description of the whole picture.
- `--sandbox` defaults to `read-only`, which is all image generation needs. Use
`--sandbox bypass` only where the nested codex sandbox cannot start at all
(a container without user namespaces, for instance).
- `--reasoning` defaults to `high` because lower effort makes the model skip the
image tool and answer in text.
- `--print-prompt` shows the fully assembled prompt without spending quota — use
it to check what the model will actually receive.
- `--verbatim` sends codex nothing but the `$imagegen` trigger and your prompt,
word for word: no wrapper, no reference note. Use it when the caller owns an
exact prompt. It cannot be combined with `--edit`, `--aspect` or `--variants`.
## Writing the prompt
The script adds the scaffolding that forces a real image-tool call; the
`--prompt` text should be purely about the picture. Beyond that, codex's own
image skill responds well to a short labelled spec:
```
Subject: a lone red bicycle, paint worn to bare metal at the edges
Scene: leaning on a wet stone harbour wall, town lights beyond
Style: cinematic photograph, shallow depth of field
Lighting: dusk, low warm sun, reflections on wet stone
Composition: subject slightly left of centre, room above for a headline
Text (verbatim): "NO SPARE"
Avoid: people, watermarks, extra bicycles
```
Guidance that pays off:
- Quote any text that must appear in the image verbatim, and keep it short —
long strings come back misspelled.
- List what must *not* appear; negative constraints work.
- For a transparent cutout, ask for a transparent background explicitly and save
as `.png`.
- When editing, name the invariants: "change only the sky; keep the bicycle,
framing and lighting identical."
- Iterate one change at a time, feeding the previous output back through
`--edit`. Several changes in one prompt tend to redraw the whole image.
An `--edit` is a re-generation from the attached image, not a pixel-level patch:
framing, crop and fine detail drift even when the prompt says to keep them. Two
things reduce the drift — restating the original description alongside the
change, and keeping the chain short, since every pass compounds it. When a
detail must survive untouched, composite it back in afterwards rather than
trusting the model to preserve it.
## After generating
Look at the result before handing it over — `Read` the file, since the model
sometimes gets text, counts, or a specific requested detail wrong. If it misses,
re-run with a sharpened prompt or refine it with `--edit`.
## Failure modes
- **"the codex run produced no image"** — the model answered in text instead of
calling its image tool. Re-run; make the prompt more explicitly a picture
request, or raise `--reasoning`. Nothing was written, so nothing is stale.
- **"the codex account is out of quota"** — wait for the reset time codex prints,
or use another account. Do not retry in a loop. Do not switch to the OpenAI
API as a substitute.
- **"codex CLI not found on PATH"** — install codex and run `codex login`, or set
`CODEX_BIN`.
- **Wrong dimensions** — `--aspect` alone is only a hint; add `--fit WxH`.
View on GitHub