Lametapel blog — authoring guide

How to add a new blog post with consistent design, cover art, schema, and tone.

TL;DR — add a new post in 7 steps

  1. Pick a slug (English, kebab-case): <topic> → file landing/src/pages/blog/<slug>.astro
  2. Generate the cover image via Creative Claw (see Cover images) → save to landing/public/blog/<slug>-cover.png (1920×1088 PNG)
  3. Copy the post template and fill in
  4. Add a 3-question FAQ (see FAQ conventions)
  5. Add the post to landing/src/pages/blog/index.astro (newest first)
  6. Add a related-reading callout linking to the most-relevant existing post; add one back in that post pointing to the new one
  7. Verify locally (pnpm dev in landing/), then commit + deploy via cd landing && npm run deploy

File structure

landing/
├── 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.

Anatomy of a post

Every post follows the same sections in this order:

  1. Frontmatter constantsPOST_URL, COVER, PUBLISHED, faqs array
  2. Layout + schema slots<Layout> with BlogPosting and FAQPage JSON-LD in the head slot
  3. <Nav />
  4. Header section (bg-cream-300) — cover image, breadcrumb to /blog, category chip, date, reading time, H1, lead paragraph
  5. Article body (bg-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)
  6. Related-reading callout (bg-brand-50/40) — links to one other post
  7. FAQ section (bg-white card) — three Q&A entries that match the faqs array used in the JSON-LD
  8. CTA card (bg-brand-900 dark) — links to / (the landing page), not direct app sign-in
  9. “Back to blog” link
  10. <Footer />
  11. <style> block with .prose-policy rules (copy verbatim from an existing post)

Post template

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.

Cover images

All blog covers share the same visual language so the index reads as a cohesive set.

Style spec (locked in)

Recipe (use this every time)

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:

Prompt pattern (proven)

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

After generation

  1. check_job until status: "completed"
  2. load_image if you want to preview before saving (only when needed — costs context)
  3. curl -sL <image_url> -o landing/public/blog/<slug>-cover.png
  4. Verify with file <path> — should be PNG image data, 1920 x 1088, 8-bit/color RGB
  5. Reference as /blog/<slug>-cover.png in the post’s COVER constant

If the carrot looks off-model or text leaked in, re-generate (don’t accept and ship). Tighten the prompt around the failure mode.

FAQ conventions

After the article body, before the FAQ, every post links to one most-relevant existing post. The callout block:

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

CTA card

The CTA at the bottom of every post is the same dark-green card with:

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.

Tone and voice

Schema markup checklist

For every post, both schemas must be present and accurate:

After deploying, validate with Google’s Rich Results Test — both BlogPosting and FAQPage should be eligible.

Index page

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.

Renaming or moving a post

If you change a slug after deploy:

  1. Add a 301 to landing/public/_redirects:
    /blog/<old-slug>  /blog/<new-slug>  301
    /blog/<old-slug>/  /blog/<new-slug>  301
  2. Update the index.
  3. Update any related-reading callouts in other posts that pointed to the old slug.
  4. Search for hardcoded references in the source: grep -rn "/blog/<old-slug>" landing/src/

Deploy

cd landing && npm run deploy

Builds via Astro static, uploads via Wrangler to Cloudflare Pages. Production CDN propagates within a couple of minutes.

Quick-reference: existing posts

SlugCoverTopicAudience
amendment-13regulation-cover.pngIsraeli Privacy Law Amendment 13 (Aug 2025)Every therapist with a clinic
ipa-ai-guidelinesipa-cover.pngIPA ethics committee AI guidelines (Mar 2026)Psychologists using AI

Both cross-link via related-reading.