openrouter-image-gen
Skill17 starsChanged 2 months agoMITView on GitHub
Use when an illustration, cover, thumbnail, or any generated image is needed and local diffusion is unavailable. Generates via OpenRouter API, cheap models, no GPU, with recurring-character guidance for consistent article series art.
- Reads credentials
In this repository18 other files it gives its agents.
- 3dprinterSkill
- ai-projectsSkill
- ciberjohn-no-slopSkill
- excalidrawSkill
- gymcoachSkill
- jevSkill
- joplin-brainSkill
- medium-storySkill
- openscad-cadSkill
- paperclip-creatorSkill
- proxmox-estateSkill
- short-videosSkill
- skill-writerSkill
- social-posterSkill
- t3mp3st-autonomous-securitySkill
- technical-trainerSkill
- transcribeSkill
- uk-business-consultantSkill
The file
We split this skill into the rules it gives an agent
3 rules. About 0 are common, 1 is distinctive, and 2 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈1
Distinctive · estimate
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 28
If OPENROUTER_API_KEY is not set, the scripts fall back to reading it from OPENROUTER_ENV_FILE (default ~/.hermes/.env), looking for a line …
- Very specific: line 103
Ask targeted questions: is the required text legible and correctly spelled?
- Distinctive: line 117
Never print keys to chat or commit them.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
OpenRouter Image Generation
Generate images through OpenRouter's standard chat-completions endpoint using image-capable models. No local GPU, no ComfyUI workflow, no Docker: the image comes back inside the API response JSON.
Configuration Variables
Set these in your environment before running the pipeline, or document them in
a .env file at your repo root:
| Variable | Description | Example |
OPENROUTER_API_KEY | (Required) OpenRouter API key for image generation | sk-or-v1-xxxxxxxx |
OPENROUTER_ENV_FILE | (Optional) Path to a .env file containing the key, when it is not set directly in the environment | ~/.hermes/.env |
If OPENROUTER_API_KEY is not set, the scripts fall back to reading it from
OPENROUTER_ENV_FILE (default ~/.hermes/.env), looking for a line of the
form OPENROUTER_API_KEY=....
When to Use
- User asks for an illustration, cover, thumbnail, or any generated image and OpenRouter is the stated or available path.
- Local diffusion (ComfyUI) is not available or the job is a one-off.
- Text must render inside the image (T-shirts, signs, posters): Gemini image models handle text well — spell the text exactly in the prompt, then verify.
Endpoint & Response Shape (the critical bit)
- POST
https://openrouter.ai/api/v1/chat/completionswith the normal chat payload:{"model": ..., "messages": [{"role":"user","content":"<prompt>"}], "n": 1}. - The image is returned embedded in the JSON as a
data:image/...;base64,....URL string. There is NO separate file download and NO image field you can trust to exist:message.contentcan benullwhile the image is buried somewhere else (e.g. nested content arrays,reasoning_details). - Always walk the whole response JSON recursively and collect every string
starting with
data:image(fallback:http(s)URLs matching image|png|jpe?g|webp). Decode the first hit. Seescripts/generate_image.py.
Model Selection
Discover image-capable models live:
curl -s https://openrouter.ai/api/v1/models -o /tmp/or_models.json
# filter: architecture.output_modalities contains "image"Cheap verified picks (re-check pricing via the API):
| Model | Prompt $/token | Notes |
google/gemini-3.1-flash-lite-image | ~$0.25/M | Nano Banana 2 Lite — default "nice cheap" pick |
google/gemini-2.5-flash-image | ~$0.30/M | Nano Banana; proven text quality |
google/gemini-3.1-flash-image | ~$0.50/M | Nano Banana 2; best quality |
openai/gpt-5-image | ~$10/M | premium, rarely needed |
Prompt guidance: state style ("editorial illustration", "slightly cartoonish"), composition ("wide 16:9"), and explicitly "no real logos, no brand names, no watermark".
The Recurring Series Character (recommended)
For article or blog illustrations, define ONE cartoon character and reuse it in every illustration so the series reads as a single body of work. Save the first good generation as the style anchor and include the full spec in every prompt.
Example spec (used by the author of this skill — customise freely):
- A cartoon person of your choosing (example used by the author: stout/bald man, short goatee, round glasses, warm smile, plain black T-shirt, optionally a tech joke in green text)
- Their workspace: cluttered desk with monitors (terminal text and/or data visuals), shelves with books and electronics, warm desk lamp, string lights, night window
- A recurring motif: sci-fi paraphernalia (model starship, poster) — describe generically, never ask for trademarked logos
- Palette: cool blues/teals/purples with warm amber accents; wide 16:9
- Editorial cartoon style, clean linework, cel shading; "no real logos, no brand names, no watermark"
Verification (always — the model can lie about what it drew)
The configured aux vision model may not accept images (e.g. a text-only
fallback → HTTP 400 "This model does not support image"). Workaround: send the
PNG to a cheap vision-capable model over OpenRouter as a data: URL in a
content array
[{type:"text",text:...},{type:"image_url",image_url:{url:"data:image/png;base64,..."}}].
A verified vision model: google/gemini-3.5-flash-lite (check the current
list — a gemini-3.1-flash without -image may not exist as a text model).
Ask targeted questions: is the required text legible and correctly spelled?
Are the requested elements present? See scripts/verify_image_vision.py.
Key Pitfall — stale API keys
- An invalid/rotated OpenRouter key returns HTTP 401
{"error":{"message":"User not found."}}. GET /modelsmay STILL return 200 with an invalid key (the models list is not a strong auth check). Confirm the key withGET /api/v1/credits, which 401s on a bad key.- In Hermes, keys may live in multiple
.envfiles and they can DIVERGE. The session environment may hold a stale key sourced earlier from the wrong file. Read the key fromOPENROUTER_API_KEYexplicitly (or theOPENROUTER_ENV_FILEpath) rather than trustingos.environalone. - Never print keys to chat or commit them.
Scripts
scripts/generate_image.py <out.png> "<prompt>" [model]— reads the key fromOPENROUTER_API_KEY(orOPENROUTER_ENV_FILE), calls the API, walks the JSON for the image, writes the PNG. Default modelgoogle/gemini-3.1-flash-lite-image.scripts/verify_image_vision.py <image.png> [model]— vision check of a PNG via OpenRouter (data URL), prints the model's description. Default modelgoogle/gemini-3.5-flash-lite.
Related
comfyui— local diffusion workflows (different path, no API cost).baoyu-article-illustrator— style/palette guidance for article images (pair with this skill for consistent series art).medium-story— article pipeline; drop the PNG in the story folder and reference it with a[*FILES*: name.png — description]placeholder.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

