Minimal CLI for generating images with Google's Gemini API or OpenAI's gpt-image-2, with style reference support and parallel batch generation.
Built to help maintain a consistent personal style for AI-generated images, so that you don't end up with the same generic style as everyone else.
# Install as a global CLI tool
uv tool install git+https://github.com/ryanbbrown/stylegenOr clone the repo if you want the included reference images as a starting point:
git clone https://github.com/ryanbbrown/stylegen
cd stylegen
uv tool install .Output directories are created automatically wherever you run sgen.
- Get a Gemini API key from Google AI Studio
- Set the environment variable:
Or create a
export GEMINI_API_KEY=your_api_key_here.envfile in your working directory.
To use -m gpt, also set an OpenAI API key as OPENAI_API_KEY. Each key is only required for the models that use it, so you can run with just one.
# Basic generation
sgen "a cozy cabin in the woods"
# With your style reference
sgen "a cozy cabin in the woods" -r my-style.png
# Multiple references for stronger style matching
sgen "a cozy cabin in the woods" -r style1.png -r style2.png
# Generate 5 variations to pick the best one
sgen "a cozy cabin in the woods" -r my-style.png -c 5
# Different aspect ratios and sizes
sgen "a cozy cabin in the woods" -a 16:9 -s 2K
# Use flash model (7x cheaper, lower quality)
sgen "a cozy cabin in the woods" -m flash
# Use OpenAI's gpt-image-2 instead of Gemini
sgen "a cozy cabin in the woods" -m gpt -r my-style.png
# Lower temperature for more consistent results
sgen "a cozy cabin in the woods" -t 0.5
# Prompt from file (for longer/reusable prompts)
sgen prompts/my-style.md -r style.png# Edit an image (aspect ratio auto-detected)
sgen edit photo.png "make the sky more dramatic"
# Override aspect ratio
sgen edit photo.png "add a rainbow" -a 16:9| Flag | Description | Default |
|---|---|---|
-r, --reference |
Reference image for style matching (repeatable) | None |
-c, --count |
Number of images to generate in parallel | 1 |
-a, --aspect |
Aspect ratio (1:1, 16:9, 9:16, 4:3, 3:4, etc.) | 1:1 (auto-detect in edit mode) |
-s, --size |
Image size: 1K, 2K, or 4K (ignored by flash; 2K/4K experimental on gpt) | 1K |
-m, --model |
Model: pro, flash, or gpt | pro |
-t, --temperature |
Temperature 0.0-2.0 (lower = more consistent; Gemini models only) | 1.0 |
-n, --name |
Filename prefix | sgen |
-o, --output |
Output directory | output |
Pricing: pro ~$0.13/image (1K/2K), ~$0.24 (4K) | flash ~$0.02/image | gpt ~$0.12-0.21/image (1K)
-m |
Model | Provider |
|---|---|---|
pro |
gemini-3-pro-image-preview |
|
flash |
gemini-2.5-flash-image |
|
gpt |
gpt-image-2 |
OpenAI |
Every flag except -t works the same on all three. Two differences are worth knowing about -m gpt:
- No temperature. OpenAI's Images API has no temperature parameter. Passing
-tprints a warning and is ignored rather than silently dropped. - Quality is pinned to
high. OpenAI's default (auto) can picklow, which defeats the point of style matching. Quality is the single biggest cost lever on that model, so it is fixed rather than exposed as a flag.
Under the hood, -a and -s are mapped to a literal pixel size, since gpt-image-2 takes dimensions rather than an aspect ratio. All ten aspect ratios and all three size tiers work; requests are kept inside OpenAI's limits (edges a multiple of 16, at most 3840px, under 8.29M pixels total). Reference images and edit go through OpenAI's edits endpoint, because its generate endpoint accepts no images. Up to 16 references.
This repo includes pixel art reference images to demonstrate the workflow:
sgen "A cute friendly robot with a round head and expressive eyes, sitting at a cozy desk in a recording studio, reading from an open book into a desk microphone. The robot wears headphones. Floating books and music notes surround the scene. Warm lighting, simple clean background. Cartoon illustration style, bold outlines, flat colors, whimsical and playful mood." -r references/pixel1.png -a 3:2Generated metadata:
{
"command": "sgen \"A cute friendly robot...\" -r references/pixel1.png -a 3:2",
"prompt": "A cute friendly robot with a round head and expressive eyes...",
"aspect_ratio": "3:2",
"size": "1K",
"model": "pro",
"provider": "gemini",
"temperature": 1.0,
"reference": ["references/pixel1.png"],
"job_timestamp": "2026-01-24T15-54-27",
"generated_at": "2026-01-24T15:54:41.590988",
"image_tokens": 1120,
"cost": 0.1344
}A few more examples using the same style reference:
![]() |
![]() |
![]() |
![]() |
Images and rich metadata are saved separately:
output/
├── images/
│ ├── 2026-01-24T15-30-00-sgen-1.png
│ ├── 2026-01-24T15-30-00-sgen-2.png
│ └── ...
└── metadata/
├── 2026-01-24T15-30-00-sgen-1.json
├── 2026-01-24T15-30-00-sgen-2.json
└── ...
Why separate JSON metadata instead of embedding in PNG?
Easier to search, parse, and use programmatically. You can grep through your metadata, pipe it to jq, or let a coding agent read it and re-run the command.
Why parallel generation?
AI image generation has natural variation. Generating 3-5 images at once and picking the best is faster than generating one, deciding it's not quite right, and regenerating.
Why no built-in prompt management?
Prompts can be passed as text or as a file path (if the path exists, its contents are used). Beyond that, prompt management is left to you and your tools. Store prompts in version-controlled files, use templates, or let a coding agent manage them—whatever fits your workflow.
Inspired by gemimg and imagemage. Built for use with coding agents like Claude Code.




