blog-image-gen
Skill2 starsChanged 4 months agoMITView on GitHub
Generate hero images for blog posts using the blog repo's OpenAI image-generation scripts after verifying current official API docs for model names, tool syntax, size/quality options, and pricing. Use when the user asks to create, generate, regenerate, or batch produce hero/header images for blog posts in priv/content/posts. Also use to ingest manually-downloaded images from the art/ folder into the served location and wire them to the blog.
- Reads credentials
- Installs packages
In this repository15 other files it gives its agents.
- AGENTS.mdAGENTS.md
- agent-coordinationSkill
- bogdan-baciu-designSkill
- chat-analysisSkill
- deep-decideSkill
- deep-research-agentsSkill
- grill-meSkill
- handoffSkill
- insight-lockSkill
- parallel-dispatchSkill
- quiz-meSkill
- skill-drift-scannerSkill
- table-system-migrationSkill
- weekly-updateSkill
- x-signal-researchSkill
The file
We split this skill into the rules it gives an agent
12 rules. About 0 are common, 9 are distinctive, and 3 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈9
Distinctive · estimate
This author's own choices. Worth a look.
3
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 30
If either script is missing, stop and locate it with:
- Distinctive: line 38
Verify current OpenAI image-generation model names, tool syntax, pricing, size limits, and quality options from official OpenAI docs before …
- Very specific: line 95
Check Bogdan.Content.Post.detect_hero/1 — it reads via :code.priv_dir(:bogdan), which requires a recompile after adding files (touch …
- Distinctive: line 102
Before accepting a generated image:
- Distinctive: line 119
If a thumbnail needs revision, keep the prior image until the replacement is generated and reviewed.
- Distinctive: line 143
When editing prompt parsing or review workflow text in this skill, run:
- Very specific: line 156
Pre-written: if blog-image-prompts.md has a section ## N.
- Distinctive: line 167
Verify current allowed values in official OpenAI docs before changing these.
- Distinctive: line 201
Does not edit blog post frontmatter — hero detection is automatic via filename.
- Distinctive: line 202
Does not push images to a CDN — they ship in the Phoenix release artifact.
- Distinctive: line 203
Does not retry failed API calls inline — re-run the command to retry skipped slugs.
- Very specific: line 204
Does not write prompts for you when a pre-written one is desired.
≈ “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
Blog Image Generation
Generate editorial hero images for posts on bogdanbaciu.com via the blog repo's
image-generation scripts. Images land at
priv/static/images/posts/<slug>/hero.png and are auto-rendered on the post
page by Bogdan.Content.Post.detect_hero/1 (no frontmatter changes needed).
When to use
- "Generate the image for
<slug>." - "Generate images for every post that's missing one."
- "I dumped some PNGs into
art/— wire them up." - "Show me what's done and what's still pending."
Required setup (verify once per session)
- Work from the blog repo root. On this machine the expected repo is:
/Users/danb/Desktop/bogdanbaciu-dot-com. - Confirm the project scripts exist before invoking anything:
test -f scripts/gen_blog_image.py && test -f scripts/ingest_art.pyIf either script is missing, stop and locate it with:
rg --files /Users/danb/Desktop | rg '(^|/)gen_blog_image\.py$|(^|/)ingest_art\.py$'OPENAI_API_KEYis set in the shell that will run the script.pip show openaireturns a version (install withpip install --upgrade openaiif not).- Verify current OpenAI image-generation model names, tool syntax, pricing, size limits, and quality options from official OpenAI docs before quoting or relying on them. Do not treat model names or per-image costs in this skill as evergreen.
- Confirm estimated batch cost with the user before any
--allrun. ChatGPT subscriptions do not imply API credits.
Workflow
Step 1 — Check what's pending
python3 scripts/gen_blog_image.py --listThis prints one line per post showing whether it's already done (and where) or PENDING. Posts are considered done if EITHER of these exists:
priv/static/images/posts/<slug>/hero.png(script output, served)art/<slug-no-hyphens>.png(manual download — needs ingest)
Step 2 — If the user has manual downloads in art/, ingest first
python3 scripts/ingest_art.py --dry-run # preview
python3 scripts/ingest_art.py # do itThis copies art/<compact>.png → priv/static/images/posts/<slug>/hero.png
by matching the compact (no-hyphen) filename to a real post slug. Orphans
(filenames that don't map to a slug) are reported but left alone.
Step 3 — Smoke-test on one post (dry run, then real)
python3 scripts/gen_blog_image.py <slug> --dry-run # prints final prompt
python3 scripts/gen_blog_image.py <slug> # one real call (~$0.30)Open the generated priv/static/images/posts/<slug>/hero.png and confirm
quality before any batch run.
Step 4 — Batch the rest
python3 scripts/gen_blog_image.py --allSequential, with SLEEP_BETWEEN_CALLS_SEC = 3 between calls. Already-done
slugs are skipped automatically. Failures are logged but don't halt the loop —
re-run to retry.
Step 5 — Verify rendering
Boot the server (mix phx.server) and visit /thoughts/<slug>. The hero
should appear between the title and the lede. If it doesn't:
- Check
Bogdan.Content.Post.detect_hero/1— it reads via:code.priv_dir(:bogdan), which requires a recompile after adding files (touchlib/bogdan/content.exor restart the server). - Confirm the file is at the exact path
priv/static/images/posts/<slug>/hero.png.
Step 6 — Prompt-quality and thumbnail review
Before accepting a generated image:
- The image matches the post's concrete subject, not just its mood.
- It is editorial and specific, not generic stock imagery.
- It has no fake screenshots, fake UI, fake charts, unreadable text, distorted hands/faces, or accidental brand/logo claims.
- It works as a crop at article-card size and as a full hero.
- It is visually distinct from nearby posts in the image inventory.
- The prompt mentions the one or two actual concepts the article is about and avoids stuffing in every paragraph of the post.
Output a compact review table:
| Slug | Thumbnail path | Pass/Revise | Reason | Follow-up |
<slug> | priv/static/images/posts/<slug>/hero.png | Pass | Specific to the article; clean crop | None |
If a thumbnail needs revision, keep the prior image until the replacement is generated and reviewed.
For batch review, build a local contact sheet from the blog repo root:
python3 /Users/danb/src/skills/blog-image-gen/scripts/thumbnail_contact_sheet.py --repo .Open priv/static/images/posts/contact-sheet.html and scan for duplicate visual
ideas, awkward crops, distorted text, and subject drift before accepting a batch.
Step 7 — Commit
git add priv/static/images/posts/
git commit -m "blog: add hero images for <N> posts"The PNGs are committed to the repo (Fly.io builds the release from this tree;
priv/static/ ships in the artifact).
Skill maintenance evals
When editing prompt parsing or review workflow text in this skill, run:
PYTHONDONTWRITEBYTECODE=1 python3 /Users/danb/src/skills/blog-image-gen/evals/prompt_fixture_eval.pyThe fixture locks the contract that --dry-run output must expose the final
prompt as a fenced FINAL PROMPT block before any real API call is made.
Prompt sourcing
scripts/gen_blog_image.py resolves the prompt for each slug in this order:
- Pre-written: if
blog-image-prompts.mdhas a section## N. <slug> — ...with a fenced code block, that exact prompt is used. - Auto-generated: otherwise the script prepends the house-style preamble
to a one-liner derived from the post title + description (or first ~300
words of body if no description). The auto path is fine for batch but
pre-written prompts produce noticeably better results — encourage the user
to draft one in
blog-image-prompts.mdfor any post they care strongly about before running.
Tunable knobs (top of scripts/gen_blog_image.py)
Verify current allowed values in official OpenAI docs before changing these.
| Constant | Default | Notes |
MODEL | script-defined | Verify current image-generation model name |
SIZE | script-defined | Verify current allowed sizes and aspect limits |
QUALITY | script-defined | Verify current quality options |
OUTPUT_FORMAT | "png" | png / jpeg / webp (jpeg is faster) |
MODERATION | "auto" | auto / low |
SLEEP_BETWEEN_CALLS_SEC | 3 | Polite throttle for batch runs |
On "thinking" / reasoning mode
The script may use the Responses API with an image-generation tool and a separate planning model. Verify the current OpenAI API surface before editing this path; model names, tool payloads, and reasoning options are time-sensitive.
client.responses.create(
model="<current-planning-model>",
input=prompt,
tools=[{"type": "image_generation", "model": "<current-image-model>",
"size": "<verified-size>", "quality": "<verified-quality>",
"output_format": "webp", "moderation": "auto"}],
reasoning={"effort": "<verified-effort>"},
)Image bytes come back as a base64 string on the image-generation output item. Do not downgrade to another API path without checking the project script and the current official docs.
What this skill does NOT do
- Does not edit blog post frontmatter — hero detection is automatic via filename.
- Does not push images to a CDN — they ship in the Phoenix release artifact.
- Does not retry failed API calls inline — re-run the command to retry skipped slugs.
- Does not write prompts for you when a pre-written one is desired; draft those in
blog-image-prompts.mdfirst.
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.

