gemini-image
The maintained, machine-wide core for image generation and editing with
Google Gemini. One zero-dependency Python file — runs on any machine with
python, no per-project install. It is the canonical successor to the
gemini-client plugin (strict superset; that plugin is retired in its favour).
Quick start
GEM=~/.claude/skills/gemini-image/scripts/gemini_image.py
# Generate
python "$GEM" --image -o castle.png "A watercolor painting of a medieval castle"
# Pick a model / aspect ratio / resolution
python "$GEM" --image -o hero.png --model gemini-3-pro-image \
--aspect-ratio 2:3 --image-size 2K "Botanical oil painting of peonies"
# Edit or compose from reference image(s) — repeat -i (limits are per-model, see table below)
python "$GEM" --image -o staged.png -i room.png -i sofa.png \
"Place this sofa in this room with warm afternoon light"
# See which image models your key can use
python "$GEM" --list-models --images-only
Auth resolves in order: --api-key → GEMINI_API_KEY → GOOGLE_API_KEY →
.env (cwd, then next to the script). The key is sent as x-goog-api-key.
Models (verified against the live API, 2026-07)
| Model |
Marketing name |
Status |
Use for |
gemini-3-pro-image / -preview |
Nano Banana Pro |
GA / preview |
Auto-selected default — highest fidelity, accurate text rendering, 1K/2K/4K, up to 6 object + 5 character reference images. Mockups, design, data-viz. ~$0.134/1K–2K, $0.24/4K. |
gemini-3.1-flash-image / -preview |
Nano Banana 2 |
GA / preview |
Balanced, and the offline/error fallback floor. Extreme aspect ratios (1:4…8:1), the 512 size, 4K, up to 10 object / 4 character / 3 style reference images, video-to-image. ~$0.067/1K. |
gemini-3.1-flash-lite-image |
Nano Banana 2 Lite |
GA (2026-06-30) |
Cheapest and fastest (~$0.0336/image). 1K only — any other --image-size is a hard 400. Standard aspect ratios only; up to 14 object reference images, but no character-consistency or style references. High-volume drafts. |
gemini-2.5-flash-image |
Nano Banana |
GA — deprecated |
Shuts down 2026-10-02. Still callable, but migrate: Google's named replacement is gemini-3.1-flash-image. |
imagen-4.0-* |
Imagen 4 |
deprecated |
Shuts down 2026-08-17, and uses the separate :predict endpoint — not covered by this generateContent client. |
Aspect ratios: 1:1 2:3 3:2 3:4 4:3 4:5 5:4 9:16 16:9 21:9; gemini-3.1-flash-image
adds the extreme ratios 1:4 4:1 1:8 8:1.
Sizes are per-model, not universal — the CLI accepts the union and the API is
the arbiter. Measured 2026-07: only gemini-3-pro-image and
gemini-3.1-flash-image genuinely deliver 2K/4K. gemini-3.1-flash-lite-image
returns a 400 for anything but 1K, and gemini-2.5-flash-image accepts 2K
but silently returns a 1024×1024 image.
Default model: best available, auto-selected
Omit --model (CLI) or model= (library) and the skill resolves the best
image model your key can access — currently gemini-3-pro-image — instead of
a fixed id. It stays current automatically: a future GA Pro model (e.g.
gemini-4-pro-image) is adopted the day your key gains access, no code change.
A newer flash model never displaces a GA pro one (newer ≠ higher fidelity).
- Explicit always wins:
--model <id> / model="<id>" skips resolution
entirely (and the /models lookup).
- Pin a default:
GEMINI_IMAGE_DEFAULT=<id> hard-pins (e.g. a cost-sensitive
project pins gemini-3.1-flash-lite-image); explicit --model still overrides it.
- Cost/speed: the best model costs more and is slower than the floor
(~$0.134 vs ~$0.067/1K image, ~3× latency — Google list pricing, 2026-07). CLI use prints a one-line stderr notice
when a non-default model is auto-selected; library use stays silent.
- Never fails: the resolution is cached per key for 24h (a temp-file keyed by
a hash of the API key — the key itself is never written). If
/models is
unreachable it falls back to gemini-3.1-flash-image, so a network blip can
never break generation or cause a surprise bill.
- Why that floor and not the cheapest model: the floor has to be non-deprecated,
honour every
--image-size the CLI advertises, and stay well below pro pricing.
gemini-3.1-flash-lite-image is cheaper but 1K-only, so a fallback would have
turned a 2K request into a hard failure; gemini-2.5-flash-image is retiring on
2026-10-02. gemini-3.1-flash-image is the only current model that clears all three.
What it does beyond the old plugin
- Reference-image input (
-i/--input-image, repeatable) — image editing and
multi-image composition, which the plugin could not do.
- Multi-image output — when the model returns several images they are all
saved (
out.png, out-2.png, …) instead of overwriting one file.
- Safety-block diagnostics — a blocked/empty result reports the
blockReason / finishReason / safety ratings instead of a bare "no image".
- Verified model menu + exponential-backoff retry (429/5xx) + a
GeminiError exception contract so projects can vendor the file and build
thin wrappers (CLI exit 2 = image blocked, 1 = error, 0 = ok).
Importable
generate, generate_image, resolve_best_image_model, extract_text,
extract_images, extract_usage, list_models, and GeminiError are public.
generate_image() returns
{output_paths, output_path, model, mime_type, text, blocked, diagnostic, raw}.
Calling it from another language
Non-Python callers reuse this skill by shelling out and reading stdout JSON
(--json), rather than reimplementing the API shape. stderr carries human
notices; exit codes are 0 ok, 2 image blocked, 1 error.
python "$GEM" --image --json -o out.png "A watercolor castle"
# stdout: {"output_paths":[…], "output_path":"out.jpg", "model":"gemini-3-pro-image", …}
Two fields exist specifically for callers and are easy to get wrong:
output_path — read the saved path from here, never from your own -o
value. The models choose their own output format, so -o out.png routinely
comes back as out.jpg.
model — the id that actually ran, after resolution. On the default path
the model is chosen here, at call time, so a caller that records its own
hard-coded guess for provenance will drift silently the first time resolution
picks something else.
This is the right integration for build-time scripts and CLIs. A compiled
server or MCP runtime can't shell out to a CLI; those conform to the contract in
SPEC.md instead of sharing this code.
Notes
- Every generated image carries an invisible SynthID watermark (Google,
non-optional).
- The saved file's extension matches the model's actual output format (the
image models choose it —
gemini-3-pro-image returns JPEG). A .png request
that comes back as JPEG is saved as .jpg with a stderr note, so a file never
lies about its contents.
- The request uses
generationConfig.imageConfig — the shape proven across all
current production callers and accepted by the live API. The newer
responseFormat.image shape is tracked as a future migration in
SPEC.md, which is the canonical contract this skill and the
project-specific TypeScript callers (ShopForge, ShopSmith, shopforge_v4) all
conform to.
- Per-project business logic (brand denylists, print-spec validation, Sharp
compositing, pack rules) stays in those projects — this core only does correct
generation/editing.
1---2name: gemini-image3description: Generate and edit images with Google's Gemini models (Nano Banana, Gemini 3 Pro Image, 3.1 Flash Image) from a zero-dependency Python CLI. Use to create, edit, restyle, or compose an image with Gemini or Google AI, including image-to-image with reference images. Also handles text and model-listing. The maintained successor to the older `gemini-client` plugin.4---56# gemini-image78The maintained, machine-wide core for **image generation and editing with9Google Gemini**. One zero-dependency Python file — runs on any machine with10`python`, no per-project install. It is the canonical successor to the11`gemini-client` plugin (strict superset; that plugin is retired in its favour).1213## Quick start1415```bash16GEM=~/.claude/skills/gemini-image/scripts/gemini_image.py1718# Generate19python "$GEM" --image -o castle.png "A watercolor painting of a medieval castle"2021# Pick a model / aspect ratio / resolution22python "$GEM" --image -o hero.png --model gemini-3-pro-image \23 --aspect-ratio 2:3 --image-size 2K "Botanical oil painting of peonies"2425# Edit or compose from reference image(s) — repeat -i (limits are per-model, see table below)26python "$GEM" --image -o staged.png -i room.png -i sofa.png \27 "Place this sofa in this room with warm afternoon light"2829# See which image models your key can use30python "$GEM" --list-models --images-only31```3233Auth resolves in order: `--api-key` → `GEMINI_API_KEY` → `GOOGLE_API_KEY` →34`.env` (cwd, then next to the script). The key is sent as `x-goog-api-key`.3536## Models (verified against the live API, 2026-07)3738| Model | Marketing name | Status | Use for |39|---|---|---|---|40| `gemini-3-pro-image` / `-preview` | Nano Banana Pro | GA / preview | **Auto-selected default** — highest fidelity, accurate text rendering, 1K/2K/4K, up to 6 object + 5 character reference images. Mockups, design, data-viz. ~$0.134/1K–2K, $0.24/4K. |41| `gemini-3.1-flash-image` / `-preview` | Nano Banana 2 | GA / preview | Balanced, and the **offline/error fallback floor**. Extreme aspect ratios (1:4…8:1), the `512` size, 4K, up to 10 object / 4 character / 3 style reference images, video-to-image. ~$0.067/1K. |42| `gemini-3.1-flash-lite-image` | Nano Banana 2 Lite | GA (2026-06-30) | **Cheapest and fastest** (~$0.0336/image). **1K only** — any other `--image-size` is a hard 400. Standard aspect ratios only; up to 14 object reference images, but no character-consistency or style references. High-volume drafts. |43| `gemini-2.5-flash-image` | Nano Banana | GA — **deprecated** | Shuts down **2026-10-02**. Still callable, but migrate: Google's named replacement is `gemini-3.1-flash-image`. |44| `imagen-4.0-*` | Imagen 4 | **deprecated** | Shuts down **2026-08-17**, and uses the separate `:predict` endpoint — **not** covered by this `generateContent` client. |4546Aspect ratios: `1:1 2:3 3:2 3:4 4:3 4:5 5:4 9:16 16:9 21:9`; `gemini-3.1-flash-image`47adds the extreme ratios `1:4 4:1 1:8 8:1`.4849Sizes are **per-model, not universal** — the CLI accepts the union and the API is50the arbiter. Measured 2026-07: only `gemini-3-pro-image` and51`gemini-3.1-flash-image` genuinely deliver 2K/4K. `gemini-3.1-flash-lite-image`52returns a 400 for anything but `1K`, and `gemini-2.5-flash-image` *accepts* `2K`53but silently returns a 1024×1024 image.5455## Default model: best available, auto-selected5657Omit `--model` (CLI) or `model=` (library) and the skill resolves the **best58image model your key can access** — currently `gemini-3-pro-image` — instead of59a fixed id. It stays current automatically: a future GA Pro model (e.g.60`gemini-4-pro-image`) is adopted the day your key gains access, no code change.61A newer *flash* model never displaces a GA *pro* one (newer ≠ higher fidelity).6263- **Explicit always wins:** `--model <id>` / `model="<id>"` skips resolution64 entirely (and the `/models` lookup).65- **Pin a default:** `GEMINI_IMAGE_DEFAULT=<id>` hard-pins (e.g. a cost-sensitive66 project pins `gemini-3.1-flash-lite-image`); explicit `--model` still overrides it.67- **Cost/speed:** the best model costs more and is slower than the floor68 (~$0.134 vs ~$0.067/1K image, ~3× latency — Google list pricing, 2026-07). CLI use prints a one-line stderr notice69 when a non-default model is auto-selected; library use stays silent.70- **Never fails:** the resolution is cached per key for 24h (a temp-file keyed by71 a *hash* of the API key — the key itself is never written). If `/models` is72 unreachable it falls back to `gemini-3.1-flash-image`, so a network blip can73 never break generation or cause a surprise bill.74- **Why that floor and not the cheapest model:** the floor has to be non-deprecated,75 honour every `--image-size` the CLI advertises, and stay well below pro pricing.76 `gemini-3.1-flash-lite-image` is cheaper but 1K-only, so a fallback would have77 turned a 2K request into a hard failure; `gemini-2.5-flash-image` is retiring on78 2026-10-02. `gemini-3.1-flash-image` is the only current model that clears all three.7980## What it does beyond the old plugin81821. **Reference-image input** (`-i/--input-image`, repeatable) — image editing and83 multi-image composition, which the plugin could not do.842. **Multi-image output** — when the model returns several images they are all85 saved (`out.png`, `out-2.png`, …) instead of overwriting one file.863. **Safety-block diagnostics** — a blocked/empty result reports the87 `blockReason` / `finishReason` / safety ratings instead of a bare "no image".884. **Verified model menu** + **exponential-backoff retry** (429/5xx) + a89 **`GeminiError` exception** contract so projects can vendor the file and build90 thin wrappers (CLI exit 2 = image blocked, 1 = error, 0 = ok).9192## Importable9394`generate`, `generate_image`, `resolve_best_image_model`, `extract_text`,95`extract_images`, `extract_usage`, `list_models`, and `GeminiError` are public.96`generate_image()` returns97`{output_paths, output_path, model, mime_type, text, blocked, diagnostic, raw}`.9899## Calling it from another language100101Non-Python callers reuse this skill by shelling out and reading **stdout JSON**102(`--json`), rather than reimplementing the API shape. stderr carries human103notices; exit codes are `0` ok, `2` image blocked, `1` error.104105```bash106python "$GEM" --image --json -o out.png "A watercolor castle"107# stdout: {"output_paths":[…], "output_path":"out.jpg", "model":"gemini-3-pro-image", …}108```109110Two fields exist specifically for callers and are easy to get wrong:111112- **`output_path` — read the saved path from here, never from your own `-o`113 value.** The models choose their own output format, so `-o out.png` routinely114 comes back as `out.jpg`.115- **`model` — the id that actually ran, after resolution.** On the default path116 the model is chosen *here*, at call time, so a caller that records its own117 hard-coded guess for provenance will drift silently the first time resolution118 picks something else.119120This is the right integration for **build-time scripts and CLIs**. A compiled121server or MCP runtime can't shell out to a CLI; those conform to the contract in122[`SPEC.md`](SPEC.md) instead of sharing this code.123124## Notes125126- Every generated image carries an invisible **SynthID** watermark (Google,127 non-optional).128- The saved file's extension matches the model's **actual** output format (the129 image models choose it — `gemini-3-pro-image` returns JPEG). A `.png` request130 that comes back as JPEG is saved as `.jpg` with a stderr note, so a file never131 lies about its contents.132- The request uses `generationConfig.imageConfig` — the shape proven across all133 current production callers and accepted by the live API. The newer134 `responseFormat.image` shape is tracked as a future migration in135 [`SPEC.md`](SPEC.md), which is the canonical contract this skill and the136 project-specific TypeScript callers (ShopForge, ShopSmith, shopforge_v4) all137 conform to.138- Per-project business logic (brand denylists, print-spec validation, Sharp139 compositing, pack rules) stays in those projects — this core only does correct140 generation/editing.