Add content-create-hero-image and content-write-blog local skills#7975
Add content-create-hero-image and content-write-blog local skills#7975ankur-arch wants to merge 3 commits into
Conversation
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>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
🚧 Files skipped from review as they are similar to previous changes (3)
WalkthroughTwo new Claude skill definitions are added under Changescontent-create-hero-image skill
content-write-blog skill
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
|
The latest updates on your projects. Learn more about Argos notifications ↗︎ Awaiting the start of a new Argos build… |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (4)
.claude/skills/content-write-blog/SKILL.md (2)
94-114: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winClarify 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 winStep 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 valueSimplify the redundant import logic.
The script imports
fontToolsandbrotliin the try block (line 59), then re-importsfontToolsagain 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 = FalseThen use
if can_subset:instead ofif 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 valueStrengthen the
@font-facecheck before Chrome render.Line 84 checks for embedded fonts with
grep -q "@font-face", but this is too broad — it could match@font-faceinside comments or SVG metadata, giving a false positive. A more precise check would look for@font-facewithin 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)." >&2Alternatively, 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
⛔ Files ignored due to path filters (30)
.claude/skills/content-create-hero-image/assets/examples/building-open-chat/hero.svgis excluded by!**/*.svg.claude/skills/content-create-hero-image/assets/examples/building-open-chat/meta.pngis excluded by!**/*.png.claude/skills/content-create-hero-image/assets/examples/create-prisma-deploy-prisma-compute/hero.svgis excluded by!**/*.svg.claude/skills/content-create-hero-image/assets/examples/create-prisma-deploy-prisma-compute/meta.pngis excluded by!**/*.png.claude/skills/content-create-hero-image/assets/examples/image-transformations-with-bun-on-prisma-compute/hero.svgis excluded by!**/*.svg.claude/skills/content-create-hero-image/assets/examples/image-transformations-with-bun-on-prisma-compute/meta.pngis excluded by!**/*.png.claude/skills/content-create-hero-image/assets/examples/prisma-compute-config-file/hero.svgis excluded by!**/*.svg.claude/skills/content-create-hero-image/assets/examples/prisma-compute-config-file/meta.pngis excluded by!**/*.png.claude/skills/content-create-hero-image/assets/examples/prisma-next-benchmark/hero.svgis excluded by!**/*.svg.claude/skills/content-create-hero-image/assets/examples/prisma-next-benchmark/meta.pngis excluded by!**/*.png.claude/skills/content-create-hero-image/assets/figma/board-thumbnail.pngis excluded by!**/*.png.claude/skills/content-create-hero-image/assets/figma/examples/prisma-next-announcement.svgis excluded by!**/*.svg.claude/skills/content-create-hero-image/assets/fonts/GeistMono.woff2is excluded by!**/*.woff2.claude/skills/content-create-hero-image/assets/fonts/Inter-Regular.woff2is excluded by!**/*.woff2.claude/skills/content-create-hero-image/assets/fonts/MonaSans.woff2is excluded by!**/*.woff2.claude/skills/content-create-hero-image/assets/hero1.svgis excluded by!**/*.svg.claude/skills/content-create-hero-image/assets/hero2.svgis excluded by!**/*.svg.claude/skills/content-create-hero-image/assets/hero3.svgis excluded by!**/*.svg.claude/skills/content-create-hero-image/assets/hero4.svgis excluded by!**/*.svg.claude/skills/content-create-hero-image/assets/logos/prisma-compute-icon.svgis excluded by!**/*.svg.claude/skills/content-create-hero-image/assets/logos/prisma-logo-dark.svgis excluded by!**/*.svg.claude/skills/content-create-hero-image/assets/logos/prisma-logo-indigo.svgis excluded by!**/*.svg.claude/skills/content-create-hero-image/assets/logos/prisma-logo-white.svgis excluded by!**/*.svg.claude/skills/content-create-hero-image/assets/logos/prisma-next-logo.svgis excluded by!**/*.svg.claude/skills/content-create-hero-image/assets/logos/prisma-next-mark-dark.svgis excluded by!**/*.svg.claude/skills/content-create-hero-image/assets/logos/prisma-next-mark-white.svgis excluded by!**/*.svg.claude/skills/content-create-hero-image/assets/logos/prisma-postgres-icon.svgis excluded by!**/*.svg.claude/skills/content-create-hero-image/assets/logos/prisma-symbol-indigo.svgis excluded by!**/*.svg.claude/skills/content-create-hero-image/assets/logos/prisma-symbol-white.svgis excluded by!**/*.svg.claude/skills/content-create-hero-image/assets/templates/cover.svgis 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
| 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() |
There was a problem hiding this comment.
🩺 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>
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 ahero(SVG) +meta(Open Graph PNG) image for a blog post in the Eclipse house style. Bundles:tokens.jsonand a content-module catalog (comparison card, code card, pipeline/flow, terminal, data/log panel);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.mdis now a bundled file (in ignite it was a symlink intodocs/prisma/, which doesn't resolve here).Notes
.claude/skills/.content-write-tweetintentionally 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