Skip to content

Add content-create-hero-image and content-write-blog local skills#7975

Open
ankur-arch wants to merge 3 commits into
mainfrom
skills/blog-content-skills
Open

Add content-create-hero-image and content-write-blog local skills#7975
ankur-arch wants to merge 3 commits into
mainfrom
skills/blog-content-skills

Conversation

@ankur-arch

@ankur-arch ankur-arch commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Moves the Prisma blog-imagery and blog-writing skills into this repo as local skills under .claude/skills/, per Ty's suggestion: the context you need to write a post and produce its cover should live in the repo where the blog PR is actually raised, so the skills and the standards they conform to can't drift apart.

Both skills originate from the prisma/ignite skills library. (Cover-imagery skill history: ignite PR #147 → merged in #148.)

Skills added

content-create-hero-image — generates a hero (SVG) + meta (Open Graph PNG) image for a blog post in the Eclipse house style. Bundles:

  • the Eclipse design system + machine-readable tokens.json and a content-module catalog (comparison card, code card, pipeline/flow, terminal, data/log panel);
  • brand fonts (Mona Sans, Inter, Geist Mono), official logos, a parameterized template;
  • a font-embed + headless-Chrome render pipeline so the PNG is pixel-identical to the SVG (real Mona Sans, not a fallback sans);
  • a worked example gallery (five covers) and a structured design-review loop;
  • it discovers the blog's current image conventions (directory, filenames, frontmatter fields) from recent posts rather than hardcoding them — e.g. it will pick up apps/blog/public/<slug>/imgs/ and whatever hero/meta naming the latest posts use.

content-write-blog — scaffolds a blog-post skeleton (frontmatter + section stubs) grounded in Prisma positioning. It produces content only; it doesn't branch/commit/push. assets/positioning.md is now a bundled file (in ignite it was a symlink into docs/prisma/, which doesn't resolve here).

Notes

  • Purely additive — new files only, all under .claude/skills/.
  • Output sizes are well within budget: hero SVGs ~23–26 KB (subset-embedded fonts), meta PNGs ~212–248 KB (largest ~24% of the 1 MB cap), all 1200×630.
  • content-write-tweet intentionally stays in ignite — it isn't blog-specific and doesn't depend on anything defined in this repo.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Documentation
    • Added guides for generating Prisma blog hero and meta images, including a design-system reference, structured design review workflow, and output/naming conventions
    • Added optional Figma refresh/source documentation for keeping artwork up to date
    • Added blog post skeleton skill documentation plus positioning guidelines
    • Documented bundled font and reusable logo assets, including centralized visual tokens
  • New Features
    • Added tooling to embed Prisma brand fonts into hero SVGs and export pixel-exact PNGs for social/OG images

Move the Prisma blog-imagery and blog-writing skills into the web repo as local
skills under .claude/skills/, so the context needed to write a post and produce
its cover lives in the repo where the blog PR is raised.

- content-create-hero-image: generates hero (SVG) + meta (OG PNG) blog images in
  the Eclipse house style. Bundles the design system, brand tokens, fonts, logos,
  a font-embed + headless-Chrome render pipeline, a worked example gallery, and a
  design-review loop. Discovers the blog's current image conventions rather than
  hardcoding them.
- content-write-blog: scaffolds a blog post skeleton grounded in Prisma
  positioning. positioning.md is now a bundled file (it was a symlink into the
  ignite repo, which does not resolve here).

Both originate from the prisma/ignite skills library.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Jun 23, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
blog Building Building Preview, Comment Jun 24, 2026 7:59am
docs Building Building Preview, Comment Jun 24, 2026 7:59am
eclipse Building Building Preview, Comment Jun 24, 2026 7:59am
site Building Building Preview, Comment Jun 24, 2026 7:59am

Request Review

@coderabbitai

coderabbitai Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: d8f3f9c9-40ab-4847-a97f-42d2f23ccd98

📥 Commits

Reviewing files that changed from the base of the PR and between b16adb9 and b804034.

📒 Files selected for processing (3)
  • .claude/skills/content-create-hero-image/SKILL.md
  • .claude/skills/content-create-hero-image/references/design-system.md
  • .claude/skills/content-create-hero-image/scripts/export-png.sh
🚧 Files skipped from review as they are similar to previous changes (3)
  • .claude/skills/content-create-hero-image/references/design-system.md
  • .claude/skills/content-create-hero-image/scripts/export-png.sh
  • .claude/skills/content-create-hero-image/SKILL.md

Walkthrough

Two new Claude skill definitions are added under .claude/skills/. The content-create-hero-image skill provides a complete pipeline for generating Prisma blog SVG hero and PNG meta images, including design tokens, logo/font assets, Figma reference docs, a design-review rubric, a font-embedding Python script, and a headless-Chrome PNG-export Bash script. The content-write-blog skill defines a blog skeleton workflow backed by a Prisma positioning document.

Changes

content-create-hero-image skill

Layer / File(s) Summary
Design tokens and bundled static assets
.claude/skills/content-create-hero-image/assets/tokens.json, .claude/skills/content-create-hero-image/assets/fonts/README.md, .claude/skills/content-create-hero-image/assets/logos/README.md, .claude/skills/content-create-hero-image/assets/figma/board-meta.json
tokens.json defines the single-source-of-truth color/font/layout/product/format token set; fonts/README.md and logos/README.md document bundled Mona Sans/Inter/Geist Mono WOFF2 files and SVG logo inventory with usage rules; board-meta.json commits the Figma board snapshot.
Design system and Figma reference docs
.claude/skills/content-create-hero-image/references/design-system.md, .claude/skills/content-create-hero-image/references/figma-source.md, .claude/skills/content-create-hero-image/references/figma-mcp.md
design-system.md codifies the canonical visual language (aurora surface, typography rules, layout anatomy, content module catalog, output formats); figma-source.md documents the offline SOCIALS.fig extraction process; figma-mcp.md describes the optional live-Figma token/logo refresh workflow with read-only guardrails.
Cover-art design review workflow
.claude/skills/content-create-hero-image/references/design-review.md
Defines the A–F critique rubric across ten categories, three laws, explicit AI-slop auto-fail list, worst-first fix loop with magick-based bounding-box alignment verification, and a Report template.
Font-embedding and PNG-export scripts
.claude/skills/content-create-hero-image/scripts/embed-fonts.py, .claude/skills/content-create-hero-image/scripts/export-png.sh
embed-fonts.py is an idempotent Python script that base64-encodes WOFF2 @font-face rules into SVG <defs> with optional fontTools subsetting; export-png.sh resolves brand fonts into a temporary fontconfig, renders via headless Chrome with retry/supersampling, and falls back to rsvg-convert/magick/inkscape.
SKILL.md execution contract and README
.claude/skills/content-create-hero-image/SKILL.md, .claude/skills/content-create-hero-image/README.md
SKILL.md defines the full 10-step workflow (discover conventions → gather brief → choose direction → select assets → generate SVG → embed fonts → export PNG → wire frontmatter → design-review loop → return paths), output contract, validation checklist, and anti-patterns; README.md documents invocation modes, iteration loop, output path conventions, and sample modules.

content-write-blog skill

Layer / File(s) Summary
Prisma positioning asset
.claude/skills/content-write-blog/assets/positioning.md
Defines Prisma's full messaging system: strategic frame, five personas, problem/solution narrative, homepage hero template, competitive landscape, JTBD four-force analysis, platform feature descriptions, and three-level product benefits.
content-write-blog SKILL.md execution contract
.claude/skills/content-write-blog/SKILL.md
Defines the blog-writing workflow: pitch intake, positioning grounding, repo checkout verification, convention survey, author resolution/scaffolding, slug/frontmatter proposal-and-confirmation, skeleton writing with lint, link enrichment with numbered inventory output format, quality-bar rule, hand-off summary, and anti-patterns list.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the primary change: adding two local skills (content-create-hero-image and content-write-blog) to the repository, which is reflected throughout the changeset with new directories, files, and documentation for both skills.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands.

@argos-ci

argos-ci Bot commented Jun 23, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Argos notifications ↗︎

Awaiting the start of a new Argos build…

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (4)
.claude/skills/content-write-blog/SKILL.md (2)

94-114: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Clarify how to discover Prisma docs structure when it's not co-located with the blog checkout.

Step 8 instructs the skill to add documentation links (lines 100–104) and mentions discovering them from the blog checkout or "if the operator can point to a docs checkout" (line 106). This fallback is mentioned but not integrated into the decision tree. If blog posts commonly link to prisma.io/docs, the skill should explicitly ask the operator upfront (as part of Step 3 checkout discovery, or as an optional input) whether they have a docs checkout available, and if not, clarify that the skill will construct links based on Prisma's known site structure (prisma.io/docs/[path]) rather than discovering them offline. This prevents uncertainty and wasted effort in Step 8.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.claude/skills/content-write-blog/SKILL.md around lines 94 - 114, The
documentation link discovery process in Step 8 under the "Documentation"
subsection is unclear when a docs checkout isn't available alongside the blog
repository. Modify Step 3 to explicitly ask the operator upfront whether they
have a docs checkout available as part of the checkout discovery process. Then,
in Step 8's documentation linking guidance, add a clear decision tree that
states: if a docs checkout is available, use it to discover links; if not,
construct links using Prisma's known site structure pattern
(prisma.io/docs/[path]) rather than leaving this as an ambiguous fallback
option.

49-59: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Step 4 should explicitly discover whether title appears in H1 or frontmatter only.

Line 54 extracts "title casing" but Step 7 (line 85) references the decision "some setups derive the title from frontmatter only — match what recent posts do." This convention should be discovered in Step 4 alongside other frontmatter decisions, not left to be inferred at writing time. Add a bullet point to Step 4 that explicitly asks: does the title appear as an H1 in the post body, or is it frontmatter-only?

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.claude/skills/content-write-blog/SKILL.md around lines 49 - 59, Step 4
currently extracts title casing but does not explicitly discover whether titles
appear as H1 headings in the post body or are frontmatter-only. Add a new bullet
point to the numbered list in Step 4 that explicitly asks the operator to check
recent blog posts and determine if the title appears as an H1 element in the
post content or exists only in the frontmatter. This convention should be
discovered alongside the other frontmatter and formatting decisions in Step 4,
not inferred later during writing in Step 7.
.claude/skills/content-create-hero-image/scripts/embed-fonts.py (1)

58-64: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Simplify the redundant import logic.

The script imports fontTools and brotli in the try block (line 59), then re-imports fontTools again in the else block (line 64). This redundancy is harmless but confusing. The intent is to conditionally enable subsetting if both packages are available; a clearer pattern:

try:
    from fontTools import subset
    import brotli  # noqa: F401
    can_subset = True
except ImportError:
    can_subset = False

Then use if can_subset: instead of if subset: (which currently works but relies on the side effect of the if/else structure).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.claude/skills/content-create-hero-image/scripts/embed-fonts.py around lines
58 - 64, Remove the redundant import of fontTools in the else block of the
try/except statement. Instead, introduce a boolean flag (can_subset) that is set
to True in the try block when both fontTools and brotli are successfully
imported, and set to False in the except block when ImportError occurs. Then
locate any conditional checks that currently use `if subset:` and replace them
with `if can_subset:` to make the intent explicit and eliminate the reliance on
the side effect of the redundant import structure.
.claude/skills/content-create-hero-image/scripts/export-png.sh (1)

83-87: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Strengthen the @font-face check before Chrome render.

Line 84 checks for embedded fonts with grep -q "@font-face", but this is too broad — it could match @font-face inside comments or SVG metadata, giving a false positive. A more precise check would look for @font-face within a <style> block or deduplicate font names in the SVG source. However, for the typical cover workflow (single <style> block at the top), the current check is acceptable.

As written, it's a defensive warning, not a blocker — if fonts are not actually embedded, Chrome will still render, but with fallback fonts. This is correct behavior, but the warning could be clearer:

💬 Proposed refinement
-  if ! grep -q "`@font-face`" "$IN"; then
+  if ! grep -q '<style[^>]*>' "$IN" || ! grep -q '`@font-face`' "$IN"; then
-    echo "warning: $IN has no embedded `@font-face` — run embed-fonts.py first or the browser render will use fallback fonts." >&2
+    echo "warning: $IN has no embedded fonts — run embed-fonts.py first or the PNG will use fallback fonts (likely not Mona Sans/Inter/Geist Mono)." >&2

Alternatively, if you want to be strict, fail the script and require embedding before export. The current warning is appropriate; the refinement above just makes it clearer.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.claude/skills/content-create-hero-image/scripts/export-png.sh around lines
83 - 87, The grep check for `@font-face` in the conditional at line 84 is too
broad and could match `@font-face` in comments or SVG metadata, causing false
positives. Refine the check to specifically look for `@font-face` declarations
within <style> blocks (e.g., grep for a pattern that matches `@font-face` only
within style tags) to avoid false positives and give more accurate warnings
about embedded fonts. Alternatively, improve the warning message in the echo
statement to be more explicit about the consequence: that Chrome will render
with fallback fonts if fonts are not properly embedded in the style block.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.claude/skills/content-create-hero-image/references/figma-mcp.md:
- Around line 55-78: Replace the non-existent Figma Plugin API methods in both
code snippets. The first snippet uses `.query()`, `.values()`, and `.first()`
which don't exist in the Figma API—replace the entire chain with
`figma.currentPage.findAll()` using a callback function that checks node type
and name patterns to return an array of matching frames with their name, width,
and height properties. The second snippet at the logo export section uses
`.query()` and `.first()` which should be replaced with
`figma.currentPage.findOne()` using a callback function that matches nodes by
exact name or name pattern instead, maintaining the error handling and export
logic that follows.

In @.claude/skills/content-create-hero-image/scripts/embed-fonts.py:
- Around line 76-89: Add a file existence check immediately after the font_path
assignment in the font loading loop to verify that the font file exists before
attempting to process it. If the font file does not exist at the resolved
font_path, raise an error with a clear message that identifies the specific
missing font filename (fname) and its expected location (fonts directory), so
users understand exactly which bundled font file is missing and where it should
be located.

---

Nitpick comments:
In @.claude/skills/content-create-hero-image/scripts/embed-fonts.py:
- Around line 58-64: Remove the redundant import of fontTools in the else block
of the try/except statement. Instead, introduce a boolean flag (can_subset) that
is set to True in the try block when both fontTools and brotli are successfully
imported, and set to False in the except block when ImportError occurs. Then
locate any conditional checks that currently use `if subset:` and replace them
with `if can_subset:` to make the intent explicit and eliminate the reliance on
the side effect of the redundant import structure.

In @.claude/skills/content-create-hero-image/scripts/export-png.sh:
- Around line 83-87: The grep check for `@font-face` in the conditional at line 84
is too broad and could match `@font-face` in comments or SVG metadata, causing
false positives. Refine the check to specifically look for `@font-face`
declarations within <style> blocks (e.g., grep for a pattern that matches
`@font-face` only within style tags) to avoid false positives and give more
accurate warnings about embedded fonts. Alternatively, improve the warning
message in the echo statement to be more explicit about the consequence: that
Chrome will render with fallback fonts if fonts are not properly embedded in the
style block.

In @.claude/skills/content-write-blog/SKILL.md:
- Around line 94-114: The documentation link discovery process in Step 8 under
the "Documentation" subsection is unclear when a docs checkout isn't available
alongside the blog repository. Modify Step 3 to explicitly ask the operator
upfront whether they have a docs checkout available as part of the checkout
discovery process. Then, in Step 8's documentation linking guidance, add a clear
decision tree that states: if a docs checkout is available, use it to discover
links; if not, construct links using Prisma's known site structure pattern
(prisma.io/docs/[path]) rather than leaving this as an ambiguous fallback
option.
- Around line 49-59: Step 4 currently extracts title casing but does not
explicitly discover whether titles appear as H1 headings in the post body or are
frontmatter-only. Add a new bullet point to the numbered list in Step 4 that
explicitly asks the operator to check recent blog posts and determine if the
title appears as an H1 element in the post content or exists only in the
frontmatter. This convention should be discovered alongside the other
frontmatter and formatting decisions in Step 4, not inferred later during
writing in Step 7.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: b48aa6a9-4e9a-4370-93e0-276286381152

📥 Commits

Reviewing files that changed from the base of the PR and between aff9dcf and b16adb9.

⛔ Files ignored due to path filters (30)
  • .claude/skills/content-create-hero-image/assets/examples/building-open-chat/hero.svg is excluded by !**/*.svg
  • .claude/skills/content-create-hero-image/assets/examples/building-open-chat/meta.png is excluded by !**/*.png
  • .claude/skills/content-create-hero-image/assets/examples/create-prisma-deploy-prisma-compute/hero.svg is excluded by !**/*.svg
  • .claude/skills/content-create-hero-image/assets/examples/create-prisma-deploy-prisma-compute/meta.png is excluded by !**/*.png
  • .claude/skills/content-create-hero-image/assets/examples/image-transformations-with-bun-on-prisma-compute/hero.svg is excluded by !**/*.svg
  • .claude/skills/content-create-hero-image/assets/examples/image-transformations-with-bun-on-prisma-compute/meta.png is excluded by !**/*.png
  • .claude/skills/content-create-hero-image/assets/examples/prisma-compute-config-file/hero.svg is excluded by !**/*.svg
  • .claude/skills/content-create-hero-image/assets/examples/prisma-compute-config-file/meta.png is excluded by !**/*.png
  • .claude/skills/content-create-hero-image/assets/examples/prisma-next-benchmark/hero.svg is excluded by !**/*.svg
  • .claude/skills/content-create-hero-image/assets/examples/prisma-next-benchmark/meta.png is excluded by !**/*.png
  • .claude/skills/content-create-hero-image/assets/figma/board-thumbnail.png is excluded by !**/*.png
  • .claude/skills/content-create-hero-image/assets/figma/examples/prisma-next-announcement.svg is excluded by !**/*.svg
  • .claude/skills/content-create-hero-image/assets/fonts/GeistMono.woff2 is excluded by !**/*.woff2
  • .claude/skills/content-create-hero-image/assets/fonts/Inter-Regular.woff2 is excluded by !**/*.woff2
  • .claude/skills/content-create-hero-image/assets/fonts/MonaSans.woff2 is excluded by !**/*.woff2
  • .claude/skills/content-create-hero-image/assets/hero1.svg is excluded by !**/*.svg
  • .claude/skills/content-create-hero-image/assets/hero2.svg is excluded by !**/*.svg
  • .claude/skills/content-create-hero-image/assets/hero3.svg is excluded by !**/*.svg
  • .claude/skills/content-create-hero-image/assets/hero4.svg is excluded by !**/*.svg
  • .claude/skills/content-create-hero-image/assets/logos/prisma-compute-icon.svg is excluded by !**/*.svg
  • .claude/skills/content-create-hero-image/assets/logos/prisma-logo-dark.svg is excluded by !**/*.svg
  • .claude/skills/content-create-hero-image/assets/logos/prisma-logo-indigo.svg is excluded by !**/*.svg
  • .claude/skills/content-create-hero-image/assets/logos/prisma-logo-white.svg is excluded by !**/*.svg
  • .claude/skills/content-create-hero-image/assets/logos/prisma-next-logo.svg is excluded by !**/*.svg
  • .claude/skills/content-create-hero-image/assets/logos/prisma-next-mark-dark.svg is excluded by !**/*.svg
  • .claude/skills/content-create-hero-image/assets/logos/prisma-next-mark-white.svg is excluded by !**/*.svg
  • .claude/skills/content-create-hero-image/assets/logos/prisma-postgres-icon.svg is excluded by !**/*.svg
  • .claude/skills/content-create-hero-image/assets/logos/prisma-symbol-indigo.svg is excluded by !**/*.svg
  • .claude/skills/content-create-hero-image/assets/logos/prisma-symbol-white.svg is excluded by !**/*.svg
  • .claude/skills/content-create-hero-image/assets/templates/cover.svg is excluded by !**/*.svg
📒 Files selected for processing (14)
  • .claude/skills/content-create-hero-image/README.md
  • .claude/skills/content-create-hero-image/SKILL.md
  • .claude/skills/content-create-hero-image/assets/figma/board-meta.json
  • .claude/skills/content-create-hero-image/assets/fonts/README.md
  • .claude/skills/content-create-hero-image/assets/logos/README.md
  • .claude/skills/content-create-hero-image/assets/tokens.json
  • .claude/skills/content-create-hero-image/references/design-review.md
  • .claude/skills/content-create-hero-image/references/design-system.md
  • .claude/skills/content-create-hero-image/references/figma-mcp.md
  • .claude/skills/content-create-hero-image/references/figma-source.md
  • .claude/skills/content-create-hero-image/scripts/embed-fonts.py
  • .claude/skills/content-create-hero-image/scripts/export-png.sh
  • .claude/skills/content-write-blog/SKILL.md
  • .claude/skills/content-write-blog/assets/positioning.md

Comment thread .claude/skills/content-create-hero-image/references/figma-mcp.md
Comment on lines +76 to +89
font_path = fonts / fname
if subset:
opts = subset.Options()
opts.flavor = "woff2"
opts.desubroutinize = True
font = subset.load_font(str(font_path), opts)
ss = subset.Subsetter(options=opts)
ss.populate(text=text)
ss.subset(font)
buf = io.BytesIO()
subset.save_font(font, buf, opts)
font_bytes = buf.getvalue()
else:
font_bytes = font_path.read_bytes()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Add error handling for missing font files.

If a bundled font file is missing (e.g., MonaSans.woff2 not found in assets/fonts/), line 76 will crash with a bare FileNotFoundError, making it unclear which font is missing and why. Add a check:

🛡️ Proposed error handling
     for family, weight, fname in FACES:
         font_path = fonts / fname
+        if not font_path.is_file():
+            sys.exit(f"error: font not found: {font_path}")
         if subset:

This provides a clear, user-friendly error message.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.claude/skills/content-create-hero-image/scripts/embed-fonts.py around lines
76 - 89, Add a file existence check immediately after the font_path assignment
in the font loading loop to verify that the font file exists before attempting
to process it. If the font file does not exist at the resolved font_path, raise
an error with a clear message that identifies the specific missing font filename
(fname) and its expected location (fonts directory), so users understand exactly
which bundled font file is missing and where it should be located.

The skill was moved from prisma/ignite, where the web repo is cloned into
spaces/web. In this repo the blog assets live at apps/blog/public/<slug>/imgs/
and the brand fonts are bundled in the skill's assets/fonts. Remove the dead
spaces/web font fallback and fix the stale example paths and font comments so
the skill is accurate for prisma/web.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add the docs-writer skill (.claude/skills/docs-writer) for writing and
reviewing developer-facing docs, with a README and per-page-type examples,
and link it from CONTRIBUTING so external contributors can find it.

Remove .claude/skills/content-write-blog/assets/positioning.md and gitignore
it: it is Prisma's internal positioning doc and is not meant to be user-facing
in this public repo. content-write-blog now treats it as a locally-placed
internal asset and asks for it when absent.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant