How to add a new blog post with consistent design, cover art, schema, and tone.
<topic> → file landing/src/pages/blog/<slug>.astrolanding/public/blog/<slug>-cover.png (1920×1088 PNG)landing/src/pages/blog/index.astro (newest first)pnpm dev in landing/), then commit + deploy via cd landing && npm run deploylanding/
├── public/
│ └── blog/
│ ├── ipa-cover.png (1920×1088)
│ ├── regulation-cover.png
│ └── <new-slug>-cover.png
├── src/pages/blog/
│ ├── CLAUDE.md (this file)
│ ├── index.astro (the listing page)
│ ├── ipa-ai-guidelines.astro (a post)
│ ├── amendment-13.astro (a post)
│ └── <new-slug>.astro (a new post)
└── public/_redirects (Cloudflare Pages 301s — add here if you rename a slug)
Posts are individual .astro files. We do not use Astro content collections — overkill for ~5 posts, harder to customize per-post layout.
Every post follows the same sections in this order:
POST_URL, COVER, PUBLISHED, faqs array<Layout> with BlogPosting and FAQPage JSON-LD in the head slot<Nav />bg-cream-300) — cover image, breadcrumb to /blog, category chip, date, reading time, H1, lead paragraphbg-cream-100) inside <div class="prose-policy text-ink-700"> — long-form content using the prose-policy styles (defined at the bottom of each post)bg-brand-50/40) — links to one other postbg-white card) — three Q&A entries that match the faqs array used in the JSON-LDbg-brand-900 dark) — links to / (the landing page), not direct app sign-in<Footer /><style> block with .prose-policy rules (copy verbatim from an existing post)Copy this verbatim. Fill in the marked spots.
---
import Layout from '../../layouts/Layout.astro';
import Nav from '../../components/Nav.astro';
import Footer from '../../components/Footer.astro';
const POST_URL = 'https://lametapel.com/blog/<SLUG>/';
const COVER = '/blog/<SLUG>-cover.png';
const PUBLISHED = '<YYYY-MM-DD>';
const faqs = [
{ q: '<question 1>', a: '<answer 1 — 2-4 sentences>' },
{ q: '<question 2>', a: '<answer 2>' },
{ q: '<question 3>', a: '<answer 3>' },
];
---
<Layout
title="<seo title — max ~60 chars>"
description="<seo description — max ~155 chars>"
ogImage={COVER}
>
<link slot="head" rel="alternate" hreflang="he" href={POST_URL} />
<script type="application/ld+json" slot="head" set:html={JSON.stringify({
"@context": "https://schema.org",
"@type": "BlogPosting",
"headline": "<post H1>",
"description": "<short description>",
"image": `https://lametapel.com${COVER}`,
"datePublished": PUBLISHED,
"dateModified": PUBLISHED,
"url": POST_URL,
"mainEntityOfPage": { "@type": "WebPage", "@id": POST_URL },
"inLanguage": "he",
"author": { "@type": "Organization", "name": "למטפל", "url": "https://lametapel.com" },
"publisher": {
"@type": "Organization",
"name": "למטפל",
"logo": { "@type": "ImageObject", "url": "https://lametapel.com/carrot.png" }
},
"about": [
{ "@type": "Thing", "name": "<topic 1 in English>" },
{ "@type": "Thing", "name": "<topic 2>" }
]
})} />
<script type="application/ld+json" slot="head" set:html={JSON.stringify({
"@context": "https://schema.org",
"@type": "FAQPage",
"mainEntity": faqs.map((f) => ({
"@type": "Question",
"name": f.q,
"acceptedAnswer": { "@type": "Answer", "text": f.a }
}))
})} />
<Nav />
<main>
<!-- Use an existing post as the structural source-of-truth.
Copy header + article wrapper + related-reading + FAQ + CTA + back-link
from amendment-13.astro or ipa-ai-guidelines.astro. -->
</main>
<Footer />
</Layout>
<!-- Copy the <style> block from an existing post verbatim. -->
The fastest way to start a new post: copy amendment-13.astro wholesale, then change the frontmatter constants, the H1, the body, the FAQ, and the related-reading target.
All blog covers share the same visual language so the index reads as a cohesive set.
Model: image/gpt-image via the Creative Claw MCP (generate_image tool)
Style reference: pass the wave.png mascot URL as image_url for image-to-image:
landing/public/carrots/wave.pnghttps://cdn.creativeclaw.co/u/32787cd1/images/40df68d5-a875-40ab-bc59-73140d1a6626.png
(If this expires, re-upload wave.png via upload_asset and use the new URL.)size: "16:9", output_format: "png"Cover illustration for a <TOPIC> blog post. <Same visual style as the companion image —
soft watercolor blended with flat 2D illustration, hand-painted feel, gentle texture,
no harsh lines.> The exact same kawaii cartoon carrot character from the reference image
(preserve its design — soft orange gradient body, two green leaves on top, friendly
closed-eye smile, simple cartoon style). Place the carrot in <SCENE — a concrete,
believable physical place — describe lighting, key props, background depth>. Same color
palette: deep forest green for foliage, warm cream and beige for environment, soft muted
orange for the carrot, subtle warm light. Mood: <one or two adjectives>. ABSOLUTELY NO
TEXT — no signs, no labels, no letters, no words on any document or surface, anywhere.
Just the character and the scene. Composition: carrot is the focal point, plenty of
breathable negative space around. Wide landscape composition suitable for a blog cover.
Reference the established covers when describing a new one — e.g. “matching the watercolor style of the existing IPA and Amendment 13 covers, but set in a different scene.”
check_job until status: "completed"load_image if you want to preview before saving (only when needed — costs context)curl -sL <image_url> -o landing/public/blog/<slug>-cover.pngfile <path> — should be PNG image data, 1920 x 1088, 8-bit/color RGB/blog/<slug>-cover.png in the post’s COVER constantIf the carrot looks off-model or text leaked in, re-generate (don’t accept and ship). Tighten the prompt around the failure mode.
faqs array is consumed both by the FAQPage JSON-LD and by the visible FAQ section in the body. Don’t duplicate the data — drive both from the array.divide-y between questions. Copy structure from ipa-ai-guidelines.astro.After the article body, before the FAQ, every post links to one most-relevant existing post. The callout block:
bg-brand-50/40 with border-brand-200When you add a new post, also edit the post you linked to, so the back-pointer exists. Without that, the two posts are unbalanced and the user can only travel one way through the cluster.
The CTA at the bottom of every post is the same dark-green card with:
/ — the landing page homepage. NOT /sign-in and NOT a direct app URL.Rationale: blog readers are top-of-funnel. Send them to the landing page where the comparison table, sources, and security claims do the conversion work — not straight to a sign-up form they’re not ready for.
<bdi> to avoid bidi punctuation glitches: <bdi>ChatGPT</bdi>.אתם, שלכם, תוכלו). The audience is therapists, broadly — not specifically psychologists. Use מטפלים by default; פסיכולוגים only when the topic is specifically the IPA or another psychologist-specific authority.style="font-family: var(--font-display);" — keeps headlines consistent with the rest of the site.For every post, both schemas must be present and accurate:
BlogPosting with headline, description, image (absolute URL), datePublished, dateModified, url, mainEntityOfPage, inLanguage: "he", author, publisher, about[]FAQPage with mainEntity[] of Question/Answer pairs derived from the faqs array<link slot="head" rel="alternate" hreflang="he" href={POST_URL} />ogImage prop on <Layout> (the cover) — drives Open Graph and Twitter previewsAfter deploying, validate with Google’s Rich Results Test — both BlogPosting and FAQPage should be eligible.
Add the new post to landing/src/pages/blog/index.astro at the top of the posts array. Required fields:
{
slug: '<slug>',
title: '<post H1>',
excerpt: '<2-3 sentence summary, used on the index card>',
cover: '/blog/<slug>-cover.png',
date: '<YYYY-MM-DD>',
readingTime: '<N> דקות קריאה',
category: '<one or two Hebrew words — אתיקה, רגולציה, מקצוע…>',
}
The card layout is auto-handled by the index template — no markup edits needed.
If you change a slug after deploy:
landing/public/_redirects:
/blog/<old-slug> /blog/<new-slug> 301
/blog/<old-slug>/ /blog/<new-slug> 301
grep -rn "/blog/<old-slug>" landing/src/cd landing && npm run deploy
Builds via Astro static, uploads via Wrangler to Cloudflare Pages. Production CDN propagates within a couple of minutes.
| Slug | Cover | Topic | Audience |
|---|---|---|---|
amendment-13 | regulation-cover.png | Israeli Privacy Law Amendment 13 (Aug 2025) | Every therapist with a clinic |
ipa-ai-guidelines | ipa-cover.png | IPA ethics committee AI guidelines (Mar 2026) | Psychologists using AI |
Both cross-link via related-reading.