Synthèse automatique
Sélectionne un modèle de visuel parmi ceux fournis et génère l'image de héros 1884×1256 d'un article de blog, puis renseigne le champ feature_image dans le frontmatter.
Points forts
- Choisit automatiquement un modèle adapté au titre, aux tags et au contenu de l'article (neo, platform, rocket, shield, lightbulb, variantes de logos, modèles de formes avec icône Phosphor).
- Met à jour le frontmatter (feature_image) après le rendu, ce qui évite les oublis manuels.
- Prend en charge des arguments explicites (nom de modèle, logos, icône Phosphor) pour forcer un rendu précis.
- Interdit formellement la génération d'images par IA et n'accepte que les modèles intégrés ou un fichier fourni par un designer.
Limites
- Fortement couplé au dépôt Pulumi : dépend de compose_meta_image.py et du dossier assets/templates/.
- Ne produit plus la carte OpenGraph/social 1200×628, désormais générée au build par scripts/meta-images/blog.mjs.
- N'accepte aucune image originale : si aucun modèle ne convient, il faut choisir le plus proche ou solliciter l'utilisateur.
À utiliser lorsqu'un article de blog Pulumi a besoin d'une image de héros créée ou régénérée à partir des modèles existants.
À éviter pour produire une illustration originale, une image générée par IA, ou pour travailler sur un dépôt dépourvu des scripts et modèles requis.
Analyse de sécurité
SûrThe skill instructs benign file operations (copying a user-supplied image, running a repository-internal template rendering script) and git status/diff to locate posts. It explicitly forbids AI image generation and destructive actions. No exfiltration, obfuscation, or unsafe commands are present.
Aucun point d'attention détecté
Comment cette analyse est faiteExemples
/blog-feature-image content/blog/esc-secrets-best-practices/index.md/blog-feature-image content/blog/platform-engineering-idp/index.md rocketRegenerate the hero image for my latest blog post using shape-sync-diamond with a git-branch icon.name: blog-feature-image description: "Render the feature image (1884x1256) for a blog post — the in-body hero art. Reads the blog post, selects a feature template (neo, platform, rocket, shield, lightbulb, a 1-3 logo variant, or a shape template — circle, square, diamond, hexagon, lock, shield, speech-bubble, sync-diamond — with a centered solid phosphor icon or single small logo), renders feature.png, and sets feature_image in frontmatter. The OpenGraph/social meta image is no longer produced here — it is generated on-brand at build time from the title + feature image (scripts/meta-images/blog.mjs). Use when the user types /blog-feature-image (formerly /blog-meta-image) or asks to create, generate, or regenerate a blog post's feature image, hero image, or social card. Accepts optional arguments like a feature template name, logo names, or a phosphor icon name."
/blog-feature-image — Render a Blog Feature Image
Formerly
/blog-meta-image. This skill now produces only the feature image. The 1200×628 OpenGraph/social card is generated at build time byscripts/meta-images/blog.mjs(viascripts/generate-meta-images.mjs) from the post title and this feature image — do not composite or commit ameta.png.
You are rendering the feature image (1884×1256) for a Pulumi blog post — the hero art shown at the top of the post and in the blog listing. Follow these steps precisely.
⛔ Hard rule: never create the image yourself
There are exactly two valid ways
feature.pngmay be produced, and no others:
compose_meta_image.pyrenders one of the built-in templates inassets/templates/(the normal path — Steps 2–3).- You copy a file the user explicitly gave you a path to, and that file is a human/designer-supplied image (e.g. from the design team,
needs-design).You must NEVER create, draw, paint, illustrate, synthesize, or otherwise author original image content for
feature.png, and you must NEVER use any image-generation tool/model (or ask another agent to) to produce it. An AI-generated image is never an acceptable feature image — no matter how well it fits the post, how much better it might look, or how the "custom image" option is phrased below. If no template fits and no designer-supplied file exists, pick the closest template or stop and ask the user — do not invent one.
Skill directory: .claude/commands/blog-feature-image/ — all paths below are relative to the project root unless noted.
[Step 1/4] Find the Blog Post
Locate the blog post that needs a feature image:
- If
$ARGUMENTScontains a file path, use that directly. - Otherwise, run
git statusandgit diff --name-onlyto find modified/untrackedcontent/blog/*/index.mdfiles. - If multiple blog posts are found, use
AskUserQuestionto ask which one. - If no blog post is found, ask the user to specify a path.
Read the full blog post file (frontmatter + body).
[Step 2/4] Parse Blog Content & User Requests
From the blog post, extract:
- Title: the
title:field from YAML frontmatter (used to choose an on-theme template) - Tags: the
tags:array from frontmatter - Topics: scan the body for key signals — cloud providers (AWS, Azure, GCP), languages (Go, Python, TypeScript), technologies (Kubernetes, Terraform, Docker), features (ESC, secrets, OIDC, policy), concepts (AI, ML, platform engineering, IDP)
From $ARGUMENTS, parse user preferences:
- Feature template: name of a feature template (e.g., "neo", "platform", "rocket", "shield", "lightbulb"), a shape template (e.g., "shape-lock", "shape-circle"), or logo names like "aws kubernetes"
- Phosphor icon: an icon name for a shape template's centerpiece (e.g., "shape-sync-diamond git-branch")
Fast-path: existing feature image
If a real feature.png already exists in the blog post's directory (not a placeholder), skip all interactive questions — just make sure feature_image: feature.png is set in frontmatter (Step 4) and report.
If $ARGUMENTS fully specifies the feature template (e.g., /blog-feature-image rocket), skip the interactive question and go straight to Step 3's rendering. If partially specified, only ask about the unspecified parts.
[Step 3/4] Select Feature Template & Render
Read the asset catalog reference at .claude/commands/blog-feature-image/references/asset-catalog.md for the full template list and logo inventory.
Interactive Selection
Ask questions progressively (one at a time) using AskUserQuestion. Skip any question already answered via $ARGUMENTS.
Question 1: Custom or template?
header: "Feature Image Source"
question: "Use a designer-supplied custom image, or a built-in template? (To request a custom image from the design team, label your PR with `needs-design`. If you can't get one fast enough, continue with templates.)"
options:
- label: "I have a designer-supplied image"
description: "Provide a path to a human/designer-made feature image file (never an AI-generated one)"
- label: "Use a template"
description: "Choose from the built-in Pulumi feature image templates"
The "custom image" option is only for a designer-supplied file (a designer, the needs-design team, or the author) — never an AI-generated stand-in. If the user doesn't already have one, use a template instead.
If I have a designer-supplied image is selected:
- First, check whether
feature.pngalready exists in the blog post's directory.- If it does, use that file without asking — skip straight to Step 4.
- If it does not exist, ask the user for the file path to their designer-supplied image.
- If a path was provided, copy it into the blog post directory and rename it to
feature.png:cp "<provided-path>" "<blog-dir>/feature.png" - Skip straight to Step 4.
Question 2: Feature template
header: "Feature Image"
question: "Choose a feature template for this blog post:"
options:
- label: "Platform"
description: "Default, platform engineering, DevOps, Pulumi news and events"
- label: "Neo"
description: "For usage on Neo specific posts only"
- label: "Rocket"
description: "Releases, new features, and announcements"
- label: "Shield"
description: "Security, secrets, compliance, and policy"
- label: "Lightbulb"
description: "Tutorials, how-tos, best practices, and guest posts"
- label: "Logo variant (1-3 logos)"
description: "Cloud provider or technology-specific content — places provider/tech logos in circular placeholders"
- label: "Shape + icon or single logo"
description: "Outline shape (circle, square, diamond, hexagon, lock, shield, speech bubble, sync diamond) with a centered solid phosphor icon or a single small logo"
If Shape + icon or single logo is selected, go to Question 2a. If Logo variant is selected, ask which logos (Question 3):
Question 2a: Which shape?
Only ask if the shape family was chosen. Recommend a shape based on the post's topic.
header: "Shape Template"
question: "Which shape template?"
options:
- label: "Lock"
description: "Security, secrets, encryption, access control"
- label: "Shield"
description: "Security posture, compliance, policy, protection"
- label: "Speech bubble"
description: "Community, Q&A, announcements, AI chat and agents"
- label: "Sync diamond"
description: "CI/CD, automation, deployments, drift detection"
- label: "Hexagon"
description: "Kubernetes-adjacent, modules, packages, components"
- label: "Circle / Square / Diamond"
description: "General-purpose abstract — pick by icon silhouette fit"
(Present at most 4 options per AskUserQuestion call — lead with the topical best fits for this post; the free-form "Other" covers the rest.)
Question 2b: Icon or logo in the center?
header: "Shape Centerpiece"
question: "What goes in the center of the shape?"
options:
- label: "Phosphor icon (recommended)"
description: "A solid (fill-weight) Phosphor icon, tinted violet (#C3BDFF)"
- label: "Single logo"
description: "One product/technology logo, rendered small"
If Phosphor icon: suggest 3–4 topical icon names from Phosphor Icons based on the post content (e.g. rocket-launch, shield-check, database, git-branch, robot, stack), then fetch per the icon-lookup rule below. Pick an icon whose silhouette complements the shape (e.g. a wide icon fights the tall lock).
If Single logo: continue with Question 3 (exactly 1 logo) and Question 4 as usual — the monochrome-preferred overlay rule applies unchanged.
Icon lookup (phosphor): Check assets/icons/<name>-fill.svg first. If missing, download the fill weight from phosphor-icons/core and cache it in the skill assets (commit it — the cache grows like the logo library):
curl -fsSL "https://raw.githubusercontent.com/phosphor-icons/core/main/assets/fill/<name>-fill.svg" \
-o .claude/commands/blog-feature-image/assets/icons/<name>-fill.svg
On a 404, the slug is wrong — search phosphoricons.com for the correct kebab-case name and retry. Always use the fill weight (solid), never regular/bold/duotone.
Question 3: Which logos?
header: "Logos"
question: "Which product/technology logos? (select 1-3)"
multiSelect: true
Based on technologies detected in the blog post (AWS, Kubernetes, TypeScript, Docker, etc.), present up to 4 relevant logos from the catalog. Example:
- "AWS" —
logos/aws.svg - "Kubernetes" —
logos/kubernetes.svg - "Docker" —
logos/docker.svg - "TypeScript" —
logos/typescript.svg
The number of selected logos (1, 2, or 3) determines which template to use (feature-logo-1, feature-logo-2, or feature-logo-3). If more than 3 are selected, ask the user to narrow down to 3.
Question 4: Logo tint style
Only ask if logos were selected in Question 3.
Recommend Overlay almost every time. It's the default and the right choice for the vast majority of posts — it keeps the logos on-brand in Pulumi's lavender and reads cleanest against the template background. This is especially true when a monochrome variant of the logo is available (see the mandatory-monochrome rule below), since a clean single-color cutout tints perfectly.
Color is a backup for when overlay doesn't work — not a stylistic preference. Reach for it only when a flat lavender tint destroys the logo's legibility: specifically when the logo is a solid filled shape with no internal cutouts, so overlay collapses it into a featureless lavender blob and the recognizable shape is lost. In that case Color preserves the internal brightness contrast that keeps the mark readable. When the logo has cutouts/negative space that survive a flat tint (most icons and monochrome variants do), stay on Overlay. When in doubt, render Overlay first and only switch to Color if the shape is genuinely unreadable.
header: "Logo Tint Style"
question: "How should the tint color be applied to the logos?"
options:
- label: "Overlay (default)"
description: "Replace all logo colors with a flat tint — best for single-color cutout logos."
- label: "Color"
description: "Backup for when overlay flattens a solid, cutout-less logo into an unreadable blob — recolors in light-purple while preserving internal brightness contrast to keep the shape legible."
Set logo_tint_mode in the feature config to "overlay" or "color" accordingly. Default is "overlay".
⚠️ Overlay tint MUST use the monochrome variant when one exists. For overlay mode, always prefer a <name>-monochrome.svg over the plain <name>.svg — check assets/logos/ for a monochrome-suffixed version of each selected logo and use it if present (e.g. kubernetes-monochrome.svg, not kubernetes.svg). The flat tint reads cleanest off a clean single-color cutout; multicolor source SVGs can produce muddy or uneven fills. Only fall back to the plain SVG when no monochrome variant exists. (For color mode, use the plain full-color SVG.)
Logo lookup: Check assets/logos/ first. If tint style is Overlay and there is a version of the logo suffixed with monochrome, use that (see the overlay rule above — monochrome is mandatory when available). If a needed logo isn't found locally:
- Try simple-icons first — clean vector SVGs for 3000+ brands. Download from
https://raw.githubusercontent.com/simple-icons/simple-icons/develop/icons/{slug}.svgand add afillattribute with the brand color to<path>elements. - Otherwise use
WebSearchto find the official SVG ("<technology> logo SVG site:github.com") - Use
WebFetchto download the SVG content - Save it to
.claude/commands/blog-feature-image/assets/logos/<name>.svg
Template Resolution
| Selection | Feature Template |
|-----------|-----------------|
| Neo | templates/feature-neo.png |
| Platform | templates/feature-platform.png |
| Rocket | templates/feature-rocket.png |
| Shield | templates/feature-shield.png |
| Lightbulb | templates/feature-lightbulb.png |
| 1 logo | templates/feature-logo-1.png |
| 2 logos | templates/feature-logo-2.png |
| 3 logos | templates/feature-logo-3.png |
| Shape: circle | templates/feature-shape-circle.png |
| Shape: square | templates/feature-shape-square.png |
| Shape: diamond | templates/feature-shape-diamond.png |
| Shape: hexagon | templates/feature-shape-hexagon.png |
| Shape: lock | templates/feature-shape-lock.png |
| Shape: shield | templates/feature-shape-shield.png |
| Shape: speech bubble | templates/feature-shape-speech-bubble.png |
| Shape: sync diamond | templates/feature-shape-sync-diamond.png |
| Custom | (provided path, skip feature render) |
Build Composition Config
Build one JSON config for feature.png (1884×1256).
Feature config — for static templates (no logos):
{
"template": "templates/feature-neo.png",
"logos": []
}
Feature config — for logo variants (logos composited onto circular placeholders):
{
"template": "templates/feature-logo-2.png",
"logos": [
"logos/aws.svg",
"logos/kubernetes.svg"
],
"logo_tint_mode": "overlay"
}
Feature config — for a shape template with a phosphor icon centerpiece (icon is always flat-tinted #C3BDFF, rendered at ~85% of the clear space):
{
"template": "templates/feature-shape-lock.png",
"icon": "icons/shield-check-fill.svg"
}
Feature config — for a shape template with a single small logo (same logo rules as the logo variants, including the monochrome-preferred overlay rule):
{
"template": "templates/feature-shape-circle.png",
"logos": ["logos/aws.svg"],
"logo_tint_mode": "overlay"
}
icon and logos are mutually exclusive — set one or the other.
Important: All paths in the config are relative to --assets-dir.
Environment Setup (first time only)
Before rendering, ensure uv is installed:
which uv
If not found, install it:
curl -LsSf https://astral.sh/uv/install.sh | sh
No uv sync is needed — the script has inline PEP 723 metadata declaring its own dependencies (cairosvg, pillow, pyyaml), so uv run handles installation automatically.
cairosvg rasterizes the logo SVGs and needs the native libcairo library (a system package, not a pip dep). The script auto-locates Homebrew's copy on macOS, so a plain uv run normally just works. If you still see no library called "cairo" was found, install it:
brew install cairo # macOS
# apt-get install libcairo2 # Debian/Ubuntu
Rendering
Render the feature image. Skip if the user provided a custom image.
- Determine the blog post directory (e.g.,
content/blog/my-post/) and use its name as<slug> - Write the feature JSON config to
/tmp/feature-<slug>.json - Run:
uv run .claude/commands/blog-feature-image/scripts/compose_meta_image.py \ --config /tmp/feature-<slug>.json \ --assets-dir .claude/commands/blog-feature-image/assets \ --output <blog-dir>/feature.png
[Step 4/4] Confirm & Update Frontmatter
- Verify
feature.pngwas created at its expected path (a template render, or the designer-supplied file the user handed you — never an AI-generated image) - Update the blog post's frontmatter — add or update the feature image field only:
Do not add afeature_image: feature.pngmeta_imagefield — the social/OpenGraph card is generated at build time from the title + this feature image. - Report to the user:
- Which blog post was used
- What feature template was selected and why
- What logos were placed (if any)
- Where
feature.pngwas saved - That the OpenGraph social card is generated at build time (preview it with
make meta-imagesthen checkassets/images/generated/blog/<slug>/index.png) - Remind them to preview
feature.pngto make sure it looks good
Error Handling
- If
compose_meta_image.pyfails, read the error output and try to fix the config (common issues: invalid SVG path, missing template file) - If a requested logo name doesn't match anything in the catalog, suggest the closest matches and ask the user
- If the blog post has no title, ask the user for one
Du fichier au premier essai
Le téléchargement contient exactement le contenu affiché sur cette fiche. Cette copie peut différer de la dernière version du dépôt source.
Consulter la source et ses fichiers annexesCe téléchargement contient uniquement SKILL.md. Les scripts, références, modèles et dépendances éventuels ne sont pas inclus. Récupérez les fichiers nécessaires depuis la source en conservant leur arborescence avant de poursuivre.
1. Télécharger le fichier
Télécharger SKILL.mdDepuis la racine d’un projet de test, enregistrez le fichier sous .skill-downloads/blog-feature-image-generation-ms8gxn4b/SKILL.md, ou utilisez la commande suivante. Ce dossier sert à examiner la skill avant son installation.
Commande pour macOS/Linux ou WSL : un shell POSIX et curl sont nécessaires. Sous Windows sans WSL, utilisez le bouton de téléchargement et créez le dossier manuellement.
mkdir -p '.skill-downloads/blog-feature-image-generation-ms8gxn4b' && curl --fail --show-error --location 'https://skills-guides.com/api/skills/blog-feature-image-generation-ms8gxn4b/download' --output '.skill-downloads/blog-feature-image-generation-ms8gxn4b/SKILL.md.part' && mv '.skill-downloads/blog-feature-image-generation-ms8gxn4b/SKILL.md.part' '.skill-downloads/blog-feature-image-generation-ms8gxn4b/SKILL.md'2. Vérifier les prérequis
Lisez SKILL.md avant de l’utiliser. Si le fichier cite des scripts ou services externes, examinez-les et préparez les accès nécessaires dans votre environnement de test.
Aucune section de prérequis reconnue dans ce fichier. Cela ne signifie pas qu’il est autonome : les bibliothèques, outils et accès peuvent être cités ailleurs dans le contenu ou dans le dépôt source.
Les plateformes de la fiche sont des indications du catalogue. Les chemins ci-dessous suivent la documentation des outils ; ils ne prouvent pas que cette skill y a été exécutée. Aucune version minimale de ces outils n’est attestée pour cette fiche.
3. Charger la skill
Après vérification, copiez le dossier complet dans le projet avec l’une des commandes ci-dessous, puis ouvrez une nouvelle session de l’outil. La commande s’arrête si un dossier du même nom existe déjà : comparez les fichiers avant de le remplacer.
Claude Code
test -f '.skill-downloads/blog-feature-image-generation-ms8gxn4b/SKILL.md' && test -s '.skill-downloads/blog-feature-image-generation-ms8gxn4b/SKILL.md' && mkdir -p '.claude/skills' && test ! -e '.claude/skills/blog-feature-image' && cp -R '.skill-downloads/blog-feature-image-generation-ms8gxn4b' '.claude/skills/blog-feature-image'OpenSkills
OpenSkills doit déjà être installé. La procédure locale install/read est contrôlée avec OpenSkills 1.5.0, qui exige Node.js ≥ 20.6.0. Aucun slug du catalogue n’est résolu automatiquement.
Installation officielle d’OpenSkillsopenskills install './.skill-downloads/blog-feature-image-generation-ms8gxn4b'openskills read 'blog-feature-image-generation-ms8gxn4b'La lecture doit afficher le contenu du fichier installé et son dossier de base. Elle ne lance ni la skill ni ses dépendances.
Pour un agent qui lit AGENTS.md, synchronisez ensuite l’index. Cette commande modifie AGENTS.md : relisez le diff avant de l’utiliser.
openskills syncMode manuel ou autre outil : joignez SKILL.md à une conversation, ou ouvrez-le dans un agent capable de lire les fichiers. Ajoutez les ressources annexes nécessaires. Il n’existe pas de dossier universel reconnu par tous les outils.
4. Faire un premier essai
Utilisez une entrée courte et fictive : un endpoint d’API, un petit document ou un brief d’interface. Dans une nouvelle conversation, joignez le fichier ou donnez son chemin à l’agent, puis adaptez cette demande :
Lis .skill-downloads/blog-feature-image-generation-ms8gxn4b/SKILL.md et applique ses instructions à cet exemple : [décrire une entrée de test]. Indique les fichiers, dépendances ou accès qui manquent. Produis le résultat demandé par la skill sans inventer de données ni exécuter de script non examiné.Résultat attendu : une sortie correspondant aux instructions de la skill, ou une liste précise des prérequis manquants. Une simple confirmation de lecture ne valide pas le premier usage. Si une ressource externe est indisponible, ce parcours reste à tester.
Fragments d'écriture
Contenu
Extrayez des fragments d'écriture bruts via un entretien intensif, sans imposer de structure. Capturez idées, citations et mots porteurs pour une utilisation ultérieure.
Rédaction UI et audit
Contenu
Rédigez ou auditez les textes d'interface (boutons, erreurs, états vides, infobulles) dans le monorepo, en suivant la source de vérité du design system.
Extraction MIDI/score
Contenu
Extrait le MIDI ou la partition d'une production musicale existante via l'outil MCP CogMusic et confirme la disponibilité du fichier.