Source profileQuality 85/100

pulumi/docs/.claude/commands/blog-feature-image/SKILL.md

blog-feature-image

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 buil

Source repository stars
178
Declared platforms
0
Static risk flags
2
Last source update
2026-08-04
Source checked
2026-08-04

Decision brief

What it does—and where it fits

Formerly /blog-meta-image. This skill now produces only the feature image. The 1200×628 OpenGraph/social card is generated at build time by scripts/meta-images/blog.mjs (via scripts/generate-meta-images.mjs) from the post title and this feature image — do not composite or commit…

Best for

    Not for

    • Tasks that require unconfirmed production actions or broad system permissions.
    • Environments where the pinned source and install steps cannot be inspected.

    Compatibility matrix

    Platform support, with evidence labels

    PlatformStatusEvidenceWhat to check
    CodexNot declaredNo explicit evidencePortability before use
    Claude CodeNot declaredNo explicit evidencePortability before use
    CursorNot declaredNo explicit evidencePortability before use
    Gemini CLINot declaredNo explicit evidencePortability before use
    Open the compatibility checker

    Installation

    Inspect first. Install second.

    The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.

    Source-detected install commandSource
    npx skills add https://github.com/pulumi/docs --skill ".claude/commands/blog-feature-image"
    Safe inspection promptEditorial

    Inspect the Agent Skill "blog-feature-image" from https://github.com/pulumi/docs/blob/c6501a9070af13d99cce54d64afe2e760fa9b040/.claude/commands/blog-feature-image/SKILL.md at commit c6501a9070af13d99cce54d64afe2e760fa9b040. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.

    Workflow

    What the source asks the agent to do

    1. 01

      [Step 1/4] Find the Blog Post

      Locate the blog post that needs a feature image:

      If $ARGUMENTS contains a file path, use that directly.Otherwise, run git status and git diff --name-only to find modified/untracked content/blog//index.md files.If multiple blog posts are found, use AskUserQuestion to ask which one.
    2. 02

      [Step 2/4] Parse Blog Content & User Requests

      If a feature.png already exists in the blog post's directory, skip all interactive questions — just make sure featureimage: feature.png is set in frontmatter (Step 4) and report. (New posts scaffold with a blank featureimage and no image file, so any feature.png present is a rea…

      Title: the title: field from YAML frontmatter (used to choose an on-theme template)Tags: the tags: array from frontmatterTopics: 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, platf…
    3. 03

      [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.

      First, check whether feature.png already 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.
    4. 04

      Environment Setup (first time only)

      Before rendering, ensure uv is installed:

      Before rendering, ensure uv is installed:If not found, install it: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.
    5. 05

      [Step 4/4] Confirm & Update Frontmatter

      1. Verify feature.png was created at its expected path (a template render, or the designer-supplied file the user handed you — never an AI-generated image) 2. Update the blog post's frontmatter — add or update the feature image field only:

      Verify feature.png was 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:Report to the user:

    Permission review

    Static risk signals and limitations

    Reads files

    low · line 28

    The documentation asks the agent to read local files, directories, or repositories.

    Read the full blog post file (frontmatter + body).

    Network access

    medium · line 154

    The documentation includes network, browsing, or remote request actions.

    curl -fsSL "https://raw.githubusercontent.com/phosphor-icons/core/main/assets/fill/<name>-fill.svg" \

    Network access

    medium · line 292

    The documentation includes network, browsing, or remote request actions.

    curl -LsSf https://astral.sh/uv/install.sh | sh

    Evidence record

    Why each signal appears

    EvidenceSourceComputedTestedEditorial
    SignalValueEvidence typeMeaning
    Quality score85/100ComputedDocumentation, specificity, maintenance, and trust rules
    Repository stars178SourceRepository attention, not individual Skill quality
    Compatibility0 platformsSourceDeclared in the catalog source record
    Usage guideautomated source guideEditorialGenerated or reviewed according to the visible evidence level

    Pinned source

    Provenance and original SKILL.md

    Repository
    pulumi/docs
    Skill path
    .claude/commands/blog-feature-image/SKILL.md
    Commit
    c6501a9070af13d99cce54d64afe2e760fa9b040
    License
    Apache-2.0
    Collected
    2026-08-04
    Default branch
    master
    View the original SKILL.md

    /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 by scripts/meta-images/blog.mjs (via scripts/generate-meta-images.mjs) from the post title and this feature image — do not composite or commit a meta.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.png may be produced, and no others:

    1. compose_meta_image.py renders one of the built-in templates in assets/templates/ (the normal path — Steps 2–3).
    2. 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:

    1. If $ARGUMENTS contains a file path, use that directly.
    2. Otherwise, run git status and git diff --name-only to find modified/untracked content/blog/*/index.md files.
    3. If multiple blog posts are found, use AskUserQuestion to ask which one.
    4. 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 feature.png already exists in the blog post's directory, skip all interactive questions — just make sure feature_image: feature.png is set in frontmatter (Step 4) and report. (New posts scaffold with a blank feature_image and no image file, so any feature.png present is a real one.)

    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:

    1. First, check whether feature.png already 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.
    2. 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"
      
    3. 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:

    1. Try simple-icons first — clean vector SVGs for 3000+ brands. Download from https://raw.githubusercontent.com/simple-icons/simple-icons/develop/icons/{slug}.svg and add a fill attribute with the brand color to <path> elements.
    2. Otherwise use WebSearch to find the official SVG ("<technology> logo SVG site:github.com")
    3. Use WebFetch to download the SVG content
    4. Save it to .claude/commands/blog-feature-image/assets/logos/<name>.svg

    Template Resolution

    SelectionFeature Template
    Neotemplates/feature-neo.png
    Platformtemplates/feature-platform.png
    Rockettemplates/feature-rocket.png
    Shieldtemplates/feature-shield.png
    Lightbulbtemplates/feature-lightbulb.png
    1 logotemplates/feature-logo-1.png
    2 logostemplates/feature-logo-2.png
    3 logostemplates/feature-logo-3.png
    Shape: circletemplates/feature-shape-circle.png
    Shape: squaretemplates/feature-shape-square.png
    Shape: diamondtemplates/feature-shape-diamond.png
    Shape: hexagontemplates/feature-shape-hexagon.png
    Shape: locktemplates/feature-shape-lock.png
    Shape: shieldtemplates/feature-shape-shield.png
    Shape: speech bubbletemplates/feature-shape-speech-bubble.png
    Shape: sync diamondtemplates/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.

    1. Determine the blog post directory (e.g., content/blog/my-post/) and use its name as <slug>
    2. Write the feature JSON config to /tmp/feature-<slug>.json
    3. 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

    1. Verify feature.png was created at its expected path (a template render, or the designer-supplied file the user handed you — never an AI-generated image)
    2. Update the blog post's frontmatter — add or update the feature image field only:
      feature_image: feature.png
      
      Do not add a meta_image field — the social/OpenGraph card is generated at build time from the title + this feature image.
    3. Report to the user:
      • Which blog post was used
      • What feature template was selected and why
      • What logos were placed (if any)
      • Where feature.png was saved
      • That the OpenGraph social card is generated at build time (preview it with make meta-images then check assets/images/generated/blog/<slug>/index.png)
      • Remind them to preview feature.png to make sure it looks good

    Error Handling

    • If compose_meta_image.py fails, 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

    Alternatives

    Compare before choosing

    Computed 10023,781

    alirezarezvani/claude-skills

    app-store-optimization

    App Store Optimization (ASO) toolkit for researching keywords, analyzing competitor rankings, generating metadata suggestions, and improving app visibility on Apple App Store and Google Play Store. Use when the user asks about ASO, app store rankings, app metadata, app titles and descriptions, app store listings, app visibility, or mobile app marketing on iOS or Android. Supports keyword research and scoring, competitor keyword analysis, metadata optimization, A/B test planning, launch checklist

    Computed 982,504

    aaron-he-zhu/aaron-marketing-skills

    reactivation-specialist

    Use when the user asks to "build a win-back campaign", "re-engage lapsed subscribers", "run a re-permission / re-consent sweep", or "sunset my dead list"; produces a closed-loop reactivation program — a lapsed-cohort definition, a staged offer ladder, a re-consent (re-permission) capture step, and a sunset-confirm / suppression rule. Owns none of the SEND-N sub-item notes: engagement-decay / sunset is email-sequence-designer's and preference-center / frequency options is preference-frequency-man

    Computed 9828

    MoizIbnYousaf/marketing-cli

    higgsfield-generate

    Use when the user wants to generate an image or video via Higgsfield AI. Covers 30+ models: Soul V2, Seedance 2.0, Kling 3.0, Veo 3.1, GPT Image 2, Nano Banana 2. Also covers Marketing Studio — branded ad video/image with avatars and products. Use whenever: "generate an image", "make a video", "animate this photo", "image-to-video", "img2vid", "edit this image with AI", "produce a clip", "create an ad", "make a UGC video", "marketing video", "brand video", "TV spot", "import product from URL", "

    Computed 9728

    MoizIbnYousaf/marketing-cli

    create-skill

    Create new marketing skills for the mktg playbook. Use when the agent needs to add a new capability, someone says 'create a skill', 'new skill', 'add a marketing skill', 'extend the playbook', 'I need a skill for X', 'build a skill', 'make a skill for Y', or 'add capability for Z'. Also use when someone wants to capture a marketing workflow they just did into a reusable skill, or when they say 'turn this into a skill'. Reads the skill contract, generates SKILL.md with correct frontmatter and str