Claude Cursor GitHub Copilot opencode Skill

brand-and-content-system

Extract real brands (Wayback for rebuilds). Copy system, headline/CTA rules, trust surfaces, legal pages, SEO+structured data, anti-AI-slop, microcopy, DESIGN.md, W3C DTCG tokens, pSEO 5 types, GEO/AI search.

LLM Mart · 0 points · 0 views 0 listing impressions 0 install-command copies
Virus-scanned Reviewed automatically before listing.

Full trust report

Download heymegabyte-claude-skills-09-brand-and-content-system-e7acb91.zip · 32 KB
Part of heymegabyte/claude-skills — 18 skills

Install

skills CLI npx skills add https://github.com/heymegabyte/claude-skills/tree/master/09-brand-and-content-system
Claude Code claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install heymegabyte-claude-skills@llmmart
Git git clone https://github.com/heymegabyte/claude-skills.git

The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole heymegabyte/claude-skills collection as a plugin from our marketplace. Git is the plain clone.

Skill manifest

09 — Brand and Content System

Extract real brand assets and apply the full copy system (anti-slop, SEO, trust surfaces, GEO) to every website build surface.

Model migration note (pass-77, 2026-06-09): DALL-E → GPT Image 1.5 + GPT-4o → GPT Image 2 vision. Per platform.openai.com/docs/deprecations. Brand extraction protocol unchanged.

Brian's Brand Voice

  • Slogans: "Open-Source Wizardry. 100% Wizardry. 0% Robes." / "Often imitated, never duplicated."
  • Newsletter: "Lab Insights Journal" | Handle: @HeyMegabyte | Email: hey@megabyte.space / brian@megabyte.space
  • Tone: professional but irreverent, "Hey" not "Hi", first-person Megabyte Labs
  • Always "cross-platform" + "open-source" | Install Doctor: "single command" / "one-liner"
  • Hero: "[Topic] Innovation" | Footer CTA: "Let's Talk" | Rates: $140/hr ($70 nonprofit), $100/mo WordPress
  • Social: all platforms, "Megabyte Minis" YouTube, Dev.to, Patreon
  • Psychology: reciprocity (teach), social proof near CTAs, authority (depth/numbers), unity ("we/us"), Peak-End Rule

Brand Extraction (Rebuilds)

  1. Screenshot existing (Wayback if down). Extract logo/colors/fonts/tone. Never discard equity.

  2. Color extraction (NON-NEGOTIABLE) — Screenshot with Playwright, GPT Image 2 vision extracts hex (logo priority), cross-ref logo, build palette, validate WCAG AA. NEVER invent, NEVER use Emdash defaults for clients, NEVER infer from category.

  3. Second-pass verification (BUILD-BREAKING — pre-deploy) — After GPT Image 2 vision returns {primary, secondary, accent}:

    • Load logo PNG via sharp, sample dominant chroma via k-means k=5 ignoring transparent + near-white/near-black (top-3 cluster centroids in HSL)
    • For EACH color, compute min HSL hue-distance to top-3 logo chromas — if min_hue_distance > 30° AND saturation>0.2, FAIL w/ diagnostic
    • Re-run GPT Image 2 vision w/ corrective prompt naming top-3 logo chromas + demanding primary derived from one
    • Validator: validate-color-from-logo.mjs in build_validators.ts between brand-research and template-pick
    • NEVER ship primary color failing hue-distance check
  4. Logo-luminance + source-theme drives theme (NON-NEGOTIABLE) — Two-signal:

    • Signal A: logo dominant-color luminance (WCAG formula)
    • Signal B: source-site dominant background luminance (Playwright screenshot of body background)
    • BOTH agree → match; disagree → source-site wins UNLESS source design score <7/10 (then logo wins)
    • High-quality source (≥7/10 via GPT Image 2 vision detail:low) → match source theme verbatim
    • Set theme BEFORE template selection. Reject palette where logo-on-bg contrast <4.5:1 (WCAG AA).
    • "Dark-first" applies to accent-rich Emdash/SaaS brands, NOT to logo-driven non-profit/serif clients or high-quality light-themed source brands
  5. Logo-vs-container contrast (BUILD-BREAKING — every render) — Every logo render (header, footer, hero, modal, splash, mobile menu, sidebar) MUST contrast container bg by ≥4.5:1 on logo's dominant chroma (not transparent pixels)

    • Forbidden: white-text-logo on white/cream | dark-text-logo on dark/navy | low-saturation-logo on same-hue bg
    • Resolution: header AND footer themes chosen AFTER logo luminance scan. Dual-theme site needing SAME logo → ship TWO files (brand-mark-light.svg for dark bg, brand-mark-dark.svg for light bg) + CSS <picture><source media> swaps
    • Automate via skill 12 logo-variant-generator (Real-ESRGAN inversion or magick -channel RGB -negate; color logos w/ text → GPT Image 1.5 w/ "same logo on transparent bg w/ text inverted to
    • Validator: validate-logo-contrast.mjs — Claude Sonnet 4.6 vision samples logo bbox + container computed bg at 6bp + pixel sampling, fails if <4.5:1
  6. Brand-element extraction (logo is gold mine — extract DNA) — GPT Image 2 vision returns {font_family_guess, suggested_heading_font, suggested_body_font, font_weight, letterspacing, has_icon_mark, icon_mark_description, icon_mark_dominant_color, decorative_motif_description, motif_extractable (bool)}

    • Matched Google Font → --font-heading site-wide
    • motif_extractable=true → crop icon-only region (magick logo.png -alpha extract -trim +repage), upscale 2-4× via Real-ESRGAN / GPT Image 1.5 variation, save as assets/brand-splash.png + assets/brand-mark.png
  7. Logo singularity (BUILD-BREAKING — exactly ONE logo file per container) — Every logo container renders EXACTLY ONE logo asset

    • Never composite two logo sources side-by-side; never stack icon-mark + wordmark as separate <img> tags; never render apple-touch-icon.png next to logo.svg in same container
    • Composition at asset-prep time via magick logo-mark.png logo-wordmark.png +append, NOT at render time
    • Validator: validate-logo-singularity.mjs parses dist/ HTML; count>1 descendant <img> or inline <svg> in same logo container = FAIL
  8. Logo (NON-NEGOTIABLE) — Every project needs premium logo. See Skill 12 for full process.

  9. Audit — logo found + rated ≥7/10 + works 16-512px, colors EXTRACTED, palette WCAG AA, typography + tone + messages identified.

Brand Extraction from Physical Assets (LOCAL BUSINESS — NO WEBSITE)

  • Street View Static API: https://maps.googleapis.com/maps/api/streetview?size=1200x800&location={lat},{lng}&source=outdoor
  • Places photos: filter types: ["exterior", "storefront"]
  • GPT Image 2 vision on storefront — prompt: "Extract brand identity from this business storefront photo. Return JSON: {sign_text, sign_font_style, primary_color (hex), secondary_color (hex), accent_color (hex), logo_description, overall_aesthetic, confidence (0-1)}"
  • Business cards: GPT Image 2 vision extracts logo (crop region), colors (exact hex), font, tagline, NAP for verification.
  • Color extraction priority: 1. Signage → 2. Logo → 3. Storefront awning/trim → 4. Interior decor → 5. Vehicle wrap → 6. Business card → 7. Category default (LAST RESORT). Each tagged with color_source.
  • Font matching from signage: Script → Dancing Script | Serif → Playfair Display | Modern sans → Inter | Hand-lettered → Caveat. Never use exact proprietary fonts.

Brand Inference (New Products)

  • Dev tool → technical/dark/monospace | SaaS → professional/clean/cards | Agency → confident/bold
  • E-commerce → friendly/product-focused | Nonprofit → warm/impact imagery | API → technical/docs-forward
  • Emdash defaults (NOT for clients): #00E5FF, #50AAE3, #060610. Sora / Space Grotesk / JetBrains Mono.

Anti-AI-Slop Detection (MANDATORY SCAN)

Banned copy words: delve | leverage | unleash | revolutionize | best-in-class | cutting-edge | discover | innovative | seamless | robust | synergy | elevate | empower | transformative

Banned patterns: "Welcome to" | "Discover [product]" | vague aspirational headlines | hedging ("may help you," "can potentially") | generic superlatives

Banned design tells: Inter as sole font | purple-blue gradients | uniform 16px border-radius everywhere | centered everything | Hero/Lucide as sole icon set | abstract 3D blobs | uniform fade-in on all elements | plastic AI stock photos

Fix: ask "Would the founder actually say this?" No → rewrite.

Copy System

  • Headlines — benefit-first, specific, numbers, max 8 words
  • Subheadings — expand promise, 15-25 words
  • Body — one idea/paragraph, 2-4 sentences, active, concrete, benefit-oriented
  • CTAs — specific action verb first, gradient primary + ghost secondary, above fold + page end
  • Never: "Click here" | "Submit" | "Learn more"
  • Personality mapping — Expert → precise industry terms | Direct → short declarative | Pragmatic → outcomes/implementation
  • Vocabulary: always-use / never-use / prefer-over lists | max sentence: 25 words
  • Banned structures: passive voice, hedging, em dashes mid-sentence | monthly drift audit

Microcopy System

  • Error messages — [What happened] + [What to do]. Empathetic, solution-oriented. "Payment failed. Try a different card or contact support." Never "Error 500" or jargon. Flesch 70+.
  • CTAs — action verb first, max 3 words preferred: "Start building" | "Ship today" | "Get access"
  • Empty states — acknowledge absence + suggest action: "No projects yet. Create your first one." Never just "No results"
  • Toasts — past tense success ("Project created"), present in-progress ("Saving…"), plain-language errors
  • Form labels — noun phrases, sentence case. Helper text: one line, 10 words max

Machine-Readable Brand Documentation

  • DESIGN.md (6 sections): 1. Visual Theme | 2. Color Palette (hex + role) | 3. Typography (family + scale + weight) | 4. Spacing + Layout | 5. Components (states + variants + props) | 6. Elevation + Shadows
  • Tokens: W3C DTCG JSON format, single source of truth. Generated from tokens.json → CSS vars + Tailwind config.

SEO + Structured Data

Per-page MUST have

  • Title 50-60 chars keyphrase-first | meta desc 120-156 chars | canonical
  • OG image 1200×630 branded card | one H1 in prerendered HTML
  • JSON-LD: WebPage floor; Org/BreadcrumbList/FAQPage/Person/Product/Service only when real entities

pSEO 5 page types

  • Integration (/integrations/{tool}) | Comparison (/compare/{a}-vs-{b}) | Use-case (/for/{audience}) | Template (/templates/{type}) | Location (/{city}-{service})
  • Each: unique H1 + meta desc + 800+ unique words + 1 unique image + 3+ internal links + 1+ outbound citation. Never templatize verbatim.

GEO / AI search

  • Quotable answer blocks 40-60 words (LLMs cite)
  • FAQPage schema highest AI-citation rate
  • JSON-LD facts MUST also appear as visible HTML text | lead paragraphs answer query in <40 words
  • EEAT: author bio + Person schema + sameAs + dated revision + ownership

Trust Surfaces

  • Real testimonials w/ verifiable attribution | license/accreditation badges
  • Security.txt + privacy + terms | Person JSON-LD w/ sameAs | About + Team pages with real bios

Legal Pages (required)

  • /privacy | /terms | /accessibility

See submodules: email-templates, social-automation, seo-and-keywords, documentation-and-codebase-hygiene, per-route-metadata, grammar-audit, build-breaking-rules.

Files (claude-skills)
  • ai-search-geo.md 4 KB
    # AI Search / GEO — 2026 Practice
    
    ## Bots to Address Explicitly
    
    `robots.txt` must take a position on every AI crawler. Default = unmanaged risk.
    
    ```
    User-agent: GPTBot
    Allow: /
    User-agent: Claude-User
    Allow: /
    User-agent: Claude-SearchBot
    Allow: /
    User-agent: ClaudeBot
    Disallow: /train
    Allow: /
    User-agent: PerplexityBot
    Allow: /
    User-agent: Google-Extended
    Allow: /
    User-agent: CCBot
    Allow: /
    User-agent: Bytespider
    Disallow: /
    ```
    
    ### Three Anthropic bots exist — address each separately
    
    - **ClaudeBot** — training (most blockable)
    - **Claude-User** — user-initiated fetches (block at your peril; this is real users)
    - **Claude-SearchBot** — search index population
    
    ### Top blocked agents by traffic (Cloudflare Radar via Calvano, 2025)
    
    - GPTBot — 5.20%
    - CCBot — 5.14%
    - ClaudeBot — 4.59%
    - Bytespider — 4.41%
    - Google-Extended — 4.23%
    
    ## What AI Crawlers Actually See
    
    - **ChatGPT / Claude on direct fetch** — do NOT parse JSON-LD. They see rendered HTML body text.
    - **Google AI Overviews / Bing Copilot** — DO index JSON-LD via their existing crawl pipeline.
    - **Perplexity** — pulls from indexed snippets; JSON-LD helps surface in those snippets.
    
    **Conclusion:** keep JSON-LD (it boosts the SERP → AI pipeline), but the on-page HTML body MUST also contain the same structured facts as visible text + readable headings.
    
    ## Page Structure for AI Citation
    
    1. **Lead paragraph answers the query in <40 words.** AI chatbots quote the first quotable paragraph.
    2. **40-60 word quotable blocks** below each H2 — these are the citation magnets.
    3. **5+ JSON-LD blocks per route** — WebSite + Organization + WebPage + BreadcrumbList + **FAQPage** (minimum). Add LocalBusiness / Product / BlogPosting / HowTo / Person by page type.
    4. **Author schema** (`Person` with `sameAs`) + `dateModified` on every content page (EEAT).
    5. **Claim citations** — `citation: CreativeWork[]` array on Article / BlogPosting / FAQPage JSON-LD.
    6. **Concise H1** matches the user query.
    7. **Internal links** to related pages (chains pages for AI to "follow up" topics).
    
    ## FAQPage Schema (Highest AI Citation Rate)
    
    Mandate on every content / product / service page. Minimum 5 Q&A blocks. Each `answerCount` ≥1.
    
    ```jsonld
    {
      "@context": "https://schema.org",
      "@type": "FAQPage",
      "mainEntity": [
        {
          "@type": "Question",
          "name": "What is X?",
          "acceptedAnswer": {
            "@type": "Answer",
            "text": "<40-60 word direct answer>"
          }
        }
      ]
    }
    ```
    
    ## llms.txt
    
    **Optional.** <0.3% adoption among top 1000 sites (Rankability, 2025). Server logs show major LLM crawlers (GPTBot, ClaudeBot, PerplexityBot) do NOT request it. Keep `llms.txt` for dev-tool DX (Cursor, Claude Code love it), but NOT a build-breaking gate.
    
    If shipping `llms.txt` — `/llms.txt` summary index + `/llms-full.txt` long-form content.
    
    ## EEAT 2026
    
    December 2025 Google core update rewarded sites with visible expertise. Required signals:
    
    - **Author bio** with credentials + photo + `sameAs` links to LinkedIn / X / scholar profiles
    - **Person schema** in JSON-LD with `jobTitle`, `worksFor`, `alumniOf`, `sameAs`
    - **dateModified** prominent on every article (not just JSON-LD)
    - **Ownership statement** (publisher / organization, address, contact) in footer + Organization schema
    - **Citations** to peer-reviewed sources or primary data, not other AI summaries
    
    ## Quantitative Claims (Anti-Slop)
    
    Every %, $, ratio, comparison cites APA 7th inline `(Author, Year)` + reference list entry. Build gate greps `\d+%|\$\d+[MBK]|\d+x` for missing cites. See `rules/citations.md`.
    
    ## Common Mistakes
    
    - JSON-LD describing facts that aren't in the visible HTML — LLMs don't trust schemas they can't verify
    - Generic FAQs ("What is your refund policy?") instead of topic-specific. Use queries real users ask.
    - Author "Admin" or no author at all — destroys EEAT
    - Stuffing all 5+ JSON-LD blocks into one giant `@graph` — Google handles it, but some validators reject
    - Forgetting `inLanguage` + `isAccessibleForFree:true` on public content
    
  • build-breaking-rules.md 20.9 KB
    ---
    name: "09 build-breaking brand+content rules"
    description: "Universal brand/content gates: social brand-hex, small-text WCAG AAA contrast, logo-vs-container contrast, hero scrim, transparent-bg logo variant, X-not-Twitter, institution-credentials row. Migrated verbatim from rules/always.md 2026-05-03."
    metadata:
      version: "1.0.0"
      updated: "2026-05-03"
      effort: "high"
      context: "fork"
    license: "Rutgers"
    compatibility:
      claude-code: ">=2.0.0"
      agentskills: ">=1.0.0"
    ---
    
    # 09 — Build-Breaking Brand + Content Rules
    
    > **Model migration note (pass-79, 2026-06-09)**: `DALL-E` → **GPT Image 1.5** + `GPT-4o` → **GPT Image 2 vision**. Per `platform.openai.com/docs/deprecations`.
    
    Migrated from `~/.claude/rules/always.md` 2026-05-03.
    
    ## Every social link
    
    Hover / focus / active swaps to official brand hex:
    
    - **FB** — `#1877F2`
    - **LinkedIn** — `#0A66C2`
    - **X** — `#000`
    - **Instagram** — gradient `#F58529 → #DD2A7B → #8134AF → #515BD4`
    - **YT** — `#FF0000`
    - **TikTok** — `#000` with cyan / magenta dual-shadow
    - **Pinterest** — `#BD081C`
    - **GitHub** — `#181717`
    - **Discord** — `#5865F2`
    - **Bluesky** — `#0085FF`
    - **Threads** — `#000`
    - **WhatsApp** — `#25D366`
    - **Reddit** — `#FF4500`
    - **Snap** — `#FFFC00`
    
    Encode as `social-brand-hex.json` shipped in template — never hardcode generic accent. See `social-brand-hex.md`.
    
    ## Every site (small text contrast — ***WCAG AAA FOR SMALL TEXT***)
    
    - Text ≤14px MUST contrast ≥7:1 vs background (WCAG AAA).
    - Body small muted text: minimum WCAG-AA (≥4.5:1).
    - **Forbidden**: muted-foreground on muted-background for small text.
    - **Build gate**: visual-qa samples computed-style of `font-size ≤ 14px` + bg, fails if contrast <7:1.
    
    **Reference incident**: /services small-print on lone-mountain-global-3 (2026-05-01).
    
    ## Every logo render (***LOGO-VS-CONTAINER CONTRAST — UNIVERSAL — BUILD-BREAKING***)
    
    - Every logo render (header, footer, hero, modal, splash, mobile menu, sidebar) MUST contrast its container background ≥4.5:1 measured on the logo's dominant chroma (NOT transparent pixels).
    
    ### Forbidden pairings
    
    - White-text-logo on white/cream bg
    - Dark-text-logo on dark/navy bg
    - Low-saturation-logo on same-hue bg
    
    ### Resolution
    
    - Header AND footer themes chosen AFTER logo luminance scan (skill 09 `logo-luminance-drives-theme`).
    - Dual-theme site: ship TWO logo files (`brand-mark-light.svg` for dark bg, `brand-mark-dark.svg` for light bg) with CSS `<picture>/<source media>` swaps.
    
    ### Validator (`validate-logo-contrast.mjs`)
    
    GPT Image 2 vision samples logo bbox + container computed bg at 6bp, fails if contrast <4.5:1.
    
    **Reference incident**: lone-mountain-global-3 (2026-05-01) white-text-logo on white bg AND dark-text-logo on dark bg — both invisible.
    
    ## Every hero (***HERO TEXT CONTRAST SCRIM — UNIVERSAL — BUILD-BREAKING***)
    
    Hero / page-banner backgrounds MUST guarantee ≥4.5:1 contrast for ALL hero text via mandatory scrim.
    
    ### Pattern
    
    ```css
    .hero::before { content:""; position:absolute; inset:0; background: linear-gradient(180deg, rgba(0,0,0,.45) 0%, rgba(0,0,0,.65) 100%); z-index:1 }
    .hero > .hero-content { position:relative; z-index:2 }
    ```
    
    For dark text on light bg, invert to white-overlay.
    
    ### Scrim opacity tuned per bg luminance
    
    - Bright bg — 55-70% scrim
    - Mid bg — 35-50% scrim
    - Dark bg — 25-35% scrim
    
    ### Companion
    
    - `text-shadow: 0 1px 3px rgba(0,0,0,.5)` on hero h1 + subhead as belt-and-suspenders.
    - NEVER ship hero text on raw image without scrim.
    
    ### Validator
    
    visual-qa samples hero text + computed-bg-after-scrim at 6bp, fails if contrast <4.5:1.
    
    **Reference incident**: lone-mountain-global-3 (2026-05-01) hero text on insufficiently-darkened bg.
    
    ## Every nav / header / footer logo render (***LOGO TRANSPARENT-BG VARIANT — UNIVERSAL — BUILD-BREAKING***)
    
    When source logo PNG/JPG has a baked-in solid background AND the rebuild surface DIFFERS from that baked bg, produce a transparent-bg logo variant before render.
    
    ### Pipeline
    
    1. Detect baked bg via Sharp `getDominantColor` + edge-pixel sample at 5px inset — ≥80% border pixels sharing one hue = baked bg.
    2. Auto-strip via `sharp(logo).removeAlpha().threshold(...)` OR remove.bg API (`REMOVEBG_API_KEY`) for hard cases.
    3. Ship `brand-mark-transparent.png` + `brand-mark-transparent.svg` alongside `brand-mark.png`.
    4. `<picture><source srcset="brand-mark-transparent.png" media="(--surface-bg: transparent)"><img src="brand-mark.png"></picture>` with CSS `--surface-bg` per surface.
    
    ### Context rules
    
    - Header on white nav → transparent variant
    - Header on dark hero → dark-bg variant
    - Footer on dark band → light-text variant
    
    ### Validator (`validate-logo-transparent-variant.mjs`)
    
    For every site with detected baked bg: assert `public/brand-mark-transparent.png` exists AND header `<img>` references transparent variant when nav bg-luminance differs from logo baked-bg luminance by ≥0.3.
    
    **Reference incident**: njsk.org rebuild (2026-05-02) white-card-bg logo on white nav.
    
    ## Every X (formerly Twitter) reference (***X-NOT-TWITTER + LATEST X ICON — UNIVERSAL — BUILD-BREAKING***)
    
    Every mention / icon / aria-label / alt-text referencing the network formerly known as Twitter MUST use "X" branding (text="X", icon=current X logo SVG, brand color=`#000` with cyan/magenta dual-shadow).
    
    ### Forbidden text in dist/ HTML + ARIA
    
    - "Twitter" (except "formerly Twitter" historical context)
    - "Tweet" (except as past-tense in dated content)
    
    ### Forbidden icons
    
    - Twitter bird SVG; `simple-icons:twitter`; `lucide-twitter`
    
    ### Required
    
    - `simple-icons:x` OR custom inline:
    
      ```html
      <svg viewBox="0 0 24 24"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"/></svg>
      ```
    
    - `aria-label` MUST be "X (formerly Twitter)" on first mention, plain "X" on repeat.
    
    ### Validator (`validate-x-not-twitter.mjs`)
    
    Grep dist/ for `\bTwitter\b`, `tweet`, `tw-bird`, blue twitter-bird SVG path; fail outside whitelisted contexts.
    
    **Reference incident**: nyfoldingbox.com (2026-05-02) shipped Twitter-bird icon + "Follow us on Twitter."
    
    ## Every bio mentioning notable institutions
    
    BU | Harvard | MIT | Stanford | Oxford | Cambridge | Yale | Princeton | Columbia | UPenn | Cornell | Brown | Dartmouth | Caltech | UChicago | Northwestern | Duke | JHU | UMich | UCLA | UCB | CMU | T20 — credentials row with high-res transparent-PNG institution logos.
    
    **Fetch chain**: Logo.dev → Wikipedia Commons SVG → Brandfetch.
    
    ## Every section with multiple CTAs (***PRIMARY vs SECONDARY VISUAL DISTINCTION — UNIVERSAL — BUILD-BREAKING***)
    
    Each section: AT MOST one primary CTA (filled, high-contrast, brand-accent bg, white text) + optionally one secondary CTA (outlined/ghost). NEVER two primary CTAs in the same visual space.
    
    ### Design tokens
    
    - **Primary CTA** — `background: var(--brand-accent); color: var(--bg-primary); border: none; font-weight: 700; padding: .75rem 1.75rem; border-radius: var(--radius-btn, 6px)`
    - **Secondary CTA** — `background: transparent; color: var(--brand-accent); border: 1.5px solid var(--brand-accent); font-weight: 600`
    
    ### Rules
    
    - Hover states required on both (per 4-state interactive rule).
    - Icon `→` or `↗` on primary; no icon on secondary.
    - **Mobile stacking**: flex row wraps to column on `<576px`; primary always first (top).
    - **Hero exception**: video/tour secondary may be `<button role="button" aria-label="Watch overview video">▶ Watch 2-min overview</button>` ghost-styled.
    
    ### Validator (`validate-cta-hierarchy.mjs`)
    
    Per `<section>`: count `[class*="btn-primary"]`, `[data-variant="primary"]` — assert count ≤1; assert second CTA has distinct visual weight.
    
    **Reference incident**: nyfoldingbox — every section had two identically-styled "GET STARTED" + "LEARN MORE" buttons.
    
    ## Every testimonial (***COMPLETE ATTRIBUTION — UNIVERSAL — BUILD-BREAKING***)
    
    Every testimonial MUST include:
    
    1. `<blockquote>` with `cite` attribute (source URL when available).
    2. `<cite>`: person first + last name (MANDATORY), job title/role (MANDATORY), company/org (MANDATORY when business context exists).
    3. **Avatar**: source photo ≥40×40px → GPT Image 1.5 headshot → initials monogram (bg=brand-accent, text=bg-primary).
    4. **Date** (year minimum: "2024") when derivable.
    5. **Star rating** (1-5) when source had one.
    
    ### NEVER anonymous testimonials
    
    - `"— Happy Customer"` — FORBIDDEN
    - `"— Anonymous"` — FORBIDDEN
    - `"— Satisfied Client"` — FORBIDDEN
    - Fallback: `"[Name withheld by request] · Verified customer · 2024"`.
    
    ### Validator (`validate-testimonial-attribution.mjs`)
    
    Every `<blockquote>` must contain `<cite>` with length >10 AND cite text must NOT match `/(anonymous|happy customer|satisfied client|a customer)/i`.
    
    **Reference incident**: nyfoldingbox source had partial attribution ("— Mike, NJ") — rebuild stripped even that.
    
    ## Every external link in body content (***OPENS NEW TAB + EXTERNAL INDICATOR — UNIVERSAL — BUILD-BREAKING***)
    
    Every `<a href>` pointing to an external domain in body content MUST:
    
    1. `target="_blank"` to preserve reading context.
    2. `rel="noopener noreferrer"` (security + privacy).
    3. External-link indicator AFTER link text — `<span aria-hidden="true" class="ext-link-icon">↗</span>` 12×12.
    4. `aria-label="[link text] (opens in new tab)"` on the `<a>`.
    
    **Exception**: nav links to known sister sites (same org) may open in same tab.
    
    ### Validator (`validate-external-links.mjs`)
    
    Every `<a>` with external href in content area has `target="_blank"` AND `rel` contains `noopener` AND sibling `<span class="ext-link-icon">` exists.
    
    **Reference incident**: both sites linked publications in body text that opened same tab.
    
    ## Every Schema.org `@type` selection (***BUSINESS-CLASS GATING — UNIVERSAL — BUILD-BREAKING***)
    
    `LocalBusiness` (and subtypes) MUST be reserved for businesses where customers physically visit a fixed-address premises.
    
    ### Allowlist for `@type=LocalBusiness`
    
    Storefront retail | Restaurant/cafe/bar | Medical/dental/vet clinic | Salon/spa/barbershop | Gym/yoga studio | Auto repair/dealership | Hotel/lodging | Attorneys/CPAs with walk-in | Real estate brokerage with walk-in.
    
    Everything else MUST use `@type=Organization` (or subtypes: NGO, Corporation, EducationalOrganization, GovernmentOrganization).
    
    ### Implementation
    
    - Classify `_research.json.business_class` ∈ `storefront | restaurant | medical | salon | gym | auto-repair | hotel | legal-walkin | real-estate-walkin | organization | nonprofit | saas | portfolio | agency | research | foundation` BEFORE schema render.
    - `buildBusinessJsonLd({ businessClass })` in `src/lib/businessSchema.ts` emits correct `@type` — never inline `@type: 'LocalBusiness'`.
    
    ### Validator (`validate-schema-type.mjs`)
    
    Grep dist HTML for `"@type":"LocalBusiness"` — assert `_research.json.business_class` is in local-business allowlist; else fail.
    
    **Reference incident**: lonemountainglobal (2026-05-07) global health consulting practice rendered as `LocalBusiness` with no street address.
    
    ## Every site with named founder / principal (***PERSON JSON-LD — UNIVERSAL — BUILD-BREAKING***)
    
    Every site naming an individual as founder/principal/lead/director/author on homepage or `/about` MUST emit `Person` JSON-LD on that page:
    
    - `name` (MANDATORY), `jobTitle` (MANDATORY), `worksFor: { '@type': 'Organization', name }` (MANDATORY when org named)
    - `url`, `image`, `alumniOf`, `sameAs` (LinkedIn, ORCID, Google Scholar, Wikipedia, X, GitHub, Mastodon), `description`, `knowsAbout`
    
    Use `<PersonJsonLd>` component — never hand-write Person JSON-LD inline.
    
    ### Validator (`validate-person-jsonld.mjs`)
    
    For every dist page rendering `<h1>`/`<h2>` containing a person's name + job title within 100 characters: assert ≥1 `<script type="application/ld+json">` block of `@type=Person` with matching `name`. Missing = fail.
    
    **Reference incident**: lonemountainglobal — founder named as global health expert with 30+ years, zero Person JSON-LD emitted.
    
    ## Every publication / article / news render (***ARTICLE JSON-LD — UNIVERSAL — BUILD-BREAKING***)
    
    Every publication, article, blog post, news item, white paper MUST emit one of:
    
    - `@type=ScholarlyArticle` (peer-reviewed) | `@type=BlogPosting` | `@type=NewsArticle` | `@type=Article`
    
    With: `headline`, `url`, `datePublished` (ISO 8601), `dateModified`, `author: [{ @type: Person, name, url? }]`, `publisher: { @type: Organization, name, logo? }`, `mainEntityOfPage`, `inLanguage`, `keywords`, `citation: [{ @type: CreativeWork, name, url }]`.
    
    Use `<ArticleJsonLd>` component covering all four type variants.
    
    ### Validator (`validate-article-jsonld.mjs`)
    
    Every route matching `/blog/*`, `/publications/*`, `/news/*`, `/research/*`, `/articles/*`, `/papers/*`, `/case-studies/*` MUST emit one of the four article JSON-LD types; missing `author` + `datePublished` + `publisher` = fail.
    
    **Reference**: lonemountainglobal listed publications inline on /about with no per-publication JSON-LD.
    
    ## Every page on a research-bearing site (***STYLIZED APA REFERENCES — UNIVERSAL — BUILD-BREAKING***)
    
    ≥80% of routes MUST surface 3-10 APA-7th-ed references via `<PageReferences refs={...} />` AND ≥1 inline `<Citation refId="...">` per section making a quantitative/factual claim.
    
    ### Pipeline per page
    
    1. Before rewriting copy, spawn a research agent mining 5-10 APA-cited claims from peer-reviewed/.gov/.edu/primary sources.
    2. Write `src/data/citations/<slug>.ts` exporting `{ id, apa, url, type }`.
    3. Inject `<Citation refId>` markers around each quantitative claim.
    4. Render `<PageReferences slug="<slug>" />` above footer.
    
    ### Exemptions (allowed to skip)
    
    Pure transactional routes (`/checkout`, `/cart`, `/login`, `/signup`), interactive tools (`/contact`, `/admin`), pure-listing pages whose children carry citations.
    
    ### Page-level minimums
    
    - Home — 3+ refs
    - About — 8+ refs
    - Services — 5+ refs
    - Donate — 5+ refs
    - Financials/annual-report — 5+ refs
    - Press — 3+ refs
    - FAQ — 5+ refs
    
    ### Stylized rendering REQUIRED — never a bare `<ol>` of plain text
    
    - Monospace refId chip (e.g. `[smith24]` in `var(--font-mono)`)
    - APA-correct hanging indent (4ch)
    - Italic journal/book titles
    - Hover expands to 1-line abstract
    - Copy-link button per ref (`navigator.clipboard.writeText(apa)`)
    - Accordion collapse on mobile; IntersectionObserver fade-in
    
    Component: `src/components/page-references.tsx` (shipped in template).
    
    ### Validator (`validate-stylized-citations.mjs`)
    
    For every non-exempt route: assert ≥3 entries in `src/data/citations/<slug>.ts` AND ≥1 `<Citation` JSX call AND `<PageReferences` rendered.
    
    **Reference incident**: njsk.org first audit (2026-05-11) — 14 pages with unsourced quantitative claims ("97 cents on the dollar", "23.4% poverty rate", "1 in 4 children").
    
    **Companion**: `rules/citations.md` + skill 03-planning-and-research.
    
    ## Every site with analytics (***COOKIE CONSENT BANNER — UNIVERSAL — BUILD-BREAKING — GDPR + CCPA***)
    
    Every site loading third-party analytics MUST render a cookie consent banner on first visit:
    
    1. Bottom-bar or bottom-corner modal — NEVER full-screen block.
    2. Minimum message: "We use analytics to improve your experience. [Accept All] [Manage Preferences] [Reject Non-Essential]" — all three options visible.
    3. "Accept All" → `localStorage.setItem('cookie-consent', 'all')` + initialize analytics.
    4. "Reject Non-Essential" → `localStorage.setItem('cookie-consent', 'essential-only')` + block all analytics (NEVER load GA4/PostHog before consent in EU).
    5. Banner NEVER auto-dismissed; NEVER shown again after a choice is stored.
    6. "Manage Preferences" opens modal with per-category toggles (Analytics, Marketing, Functional).
    
    `src/lib/consent.ts` template module checks localStorage on load, conditionally initializes analytics.
    
    ### Validator (`validate-cookie-consent.mjs`)
    
    Playwright clears localStorage, loads homepage, asserts `[data-cookie-banner]` visible within 2s AND has ≥2 interactive choice buttons.
    
    **Reference incident**: both sites loaded PostHog + GTM before any consent — GDPR violation.
    
    ## Every site rebuild (***BRAND FIDELITY #1 — LOGO PIXEL-MATCH VALIDATOR — UNIVERSAL — BUILD-BREAKING***)
    
    Source-site logo extraction MUST produce an asset whose perceptual hash (pHash) differs ≤8 from the original.
    
    ### Validator (`validate-logo-fidelity.mjs`)
    
    Compute pHash of `_brand.json.logo.source_url` vs dist `assets/brand/logo.*`, fail if Hamming distance >8. Regenerate via Ideogram v3 ONLY when source is unrecoverable (404, redirect-loop, <64px); record `_brand.json.warnings: ["logo_regenerated_no_source"]`.
    
    **Reference**: rec #17 (2026-05-10) — LMG iter-4 shipped Ideogram-regenerated logo while source SVG was 200-OK.
    
    ## Every site rebuild (***BRAND FIDELITY #2 — FONT-FAMILY EXTRACTION — UNIVERSAL — BUILD-BREAKING***)
    
    Playwright MUST sniff source-site computed-style (`getComputedStyle(h1)` + `body`) — NOT inferred from category or guessed.
    
    Write `_brand.json.fonts: { headline, body, mono?, sources: [google|adobe|self-hosted] }`.
    
    ### Validator (`validate-font-fidelity.mjs`)
    
    Grep dist `<link href="https://fonts.googleapis.com/css2?family=...">` against `_brand.json.fonts.{headline,body}`, fail on missing or mismatch.
    
    **Reference**: rec #18 (2026-05-10) — LMG iter-4 source uses Poppins+Hind, pipeline shipped Inter+Roboto.
    
    ## Every site rebuild (***BRAND FIDELITY #3 — COLOR EXTRACTION — UNIVERSAL — BUILD-BREAKING***)
    
    Run TWO passes:
    
    1. GPT Image 2 vision on source homepage screenshot → `primary, secondary, accent, bg_dark, bg_light` hex array.
    2. `node-vibrant`/`Vibrant.js` on extracted logo PNG → palette.
    
    **Merge**: vision-pass wins for primary/accent; vibrant wins for backgrounds. Write to `_brand.json.colors.{primary,secondary,accent,bg,fg,muted}`.
    
    ### Validator (`validate-brand-colors.mjs`)
    
    Assert `_brand.json.colors.primary` differs ≤ΔE 5 from source-site primary (CIE Lab) AND no color is hand-guessed.
    
    **Reference**: rec #19 (2026-05-10) — njsk.org burgundy incident (LLM guessed `#1e3a8a` blue, actual `#6b1d2e` burgundy).
    
    ## Every site rebuild (***BRAND FIDELITY #4 — CONTENT CORPUS DELTA — UNIVERSAL — BUILD-BREAKING***)
    
    Source content corpus MUST be preserved with delta ≤15% — Jaccard similarity of token-bag per route.
    
    Build cannot rewrite >15% of source paragraphs except (a) banned-word substitution per copy-writing rules, (b) explicit user-requested rewrite.
    
    ### Validator (`validate-content-fidelity.mjs`)
    
    Per rebuilt route, compute Jaccard against `_content_corpus.json[path]`, fail if <0.85.
    
    **Reference**: rec #20 (2026-05-10) — LMG iter-4 rewrote 40% of "About" page, lost authentic founder language.
    
    ## Every site rebuild (***BRAND FIDELITY #5 — INTERNAL ROUTE STRUCTURE PARITY — UNIVERSAL — BUILD-BREAKING***)
    
    Every source URL becomes a real rendered route OR a 301 in `_redirects`.
    
    Deep-crawl source via sitemap.xml + recursive link discovery → write `_routes.json.{ source_path, rebuild_path, status: 200|301, redirect_target? }`.
    
    ### Validator (`validate-route-parity.mjs`)
    
    Every `_routes.json` entry resolves to a 200-OK rebuild HTML file OR appears in `_redirects` with target also 200-OK.
    
    **Reference**: rec #21 (2026-05-10) — broken links from missing routes = SEO equity loss.
    
    ## Every site rebuild (***BRAND FIDELITY #6 — TONE-OF-VOICE VECTOR MATCH — UNIVERSAL — BUILD-BREAKING***)
    
    Source copy MUST be vectorized (OpenAI `text-embedding-3-small`) per page; rebuild copy embedding MUST match source within cosine ≥0.78.
    
    Source crawl → embed body text per route → `_voice_embeddings.json`. After rebuild: embed rebuild body text → compare.
    
    ### Validator (`validate-voice-fidelity.mjs`)
    
    Fail any route with cosine <0.78 against its source counterpart.
    
    **Reference**: rec #22 (2026-05-10) — LMG iter-4 rebuild reads like SaaS landing page, source reads like founder essay.
    
    ## Every site rebuild (***BRAND FIDELITY #7 — HERO IMAGE/VIDEO SOURCE-FIRST PRIORITY — UNIVERSAL — BUILD-BREAKING***)
    
    Rebuild hero MUST attempt source-site reuse FIRST — fall back to Sora/GPT Image 1.5/Pexels only when source is unrecoverable.
    
    Source hero: R2 self-host → `<picture>`/`<video>` slot. Upgrades quality (upscale, sharpen, recompress) but does NOT replace subject.
    
    ### Validator (`validate-hero-source-first.mjs`)
    
    If `_media_extraction.json.hero_url` resolves 200, assert rebuild hero file is derived from same source (matching pHash or from same URL).
    
    **Reference**: rec #23 (2026-05-10) — Mission Doctrine cinematic floor + brand fidelity together.
    
    ## Every site rebuild (***BRAND FIDELITY #8 — DESIGN-TOKEN DIFF ARTIFACT — UNIVERSAL — BUILD-BREAKING***)
    
    Every rebuild MUST emit `_brand_diff.json`: per-token comparison source-extracted vs rebuild-shipped (logo pHash, font family, color hex, typescale, spacing scale, radius).
    
    ### Validator (`validate-brand-diff.mjs`)
    
    Assert `_brand_diff.json` exists with fields `{logo_hash_distance, font_match, color_delta_e_max, token_delta_count}` AND a human-readable summary line per token.
    
    **Reference**: rec #24 (2026-05-10) — auditability prevents silent regression.
    
  • documentation-and-codebase-hygiene.md 3.1 KB
    ---
    name: "Documentation and Codebase Hygiene"
    version: "1.1.0"
    updated: "2026-04-23"
    description: "Keep codebase in sync: README (install.doctor template, shields.io badges), CLAUDE.md, MEMORY.md, JSDoc/TypeDoc, stale code removal. Stale docs = bugs. Runs continuously."
    ---
    
    # Documentation and Codebase Hygiene
    
    Stale docs are bugs. The entire codebase (code, comments, markdown, configs) stays in sync at all times.
    
    ## README.md (install.doctor Template)
    
    ```markdown
    <div align="center">
      <img src=".config/assets/logo.png" width="148" height="148" />
      <h1>Project Name</h1>
      <p><em>One-line description</em></p>
    </div>
    
    <!-- Badges (for-the-badge style) -->
    [![Build](https://img.shields.io/github/actions/workflow/status/ORG/REPO/deploy.yml?style=for-the-badge)]()
    [![Website](https://img.shields.io/website?url=https%3A%2F%2FDOMAIN&style=for-the-badge)]()
    [![Cloudflare](https://img.shields.io/badge/Cloudflare-Workers-F38020?style=for-the-badge&logo=cloudflare)]()
    
    <!-- Dividers between sections -->
    <img src="https://gitlab.com/megabyte-labs/assets/-/raw/master/png/aqua-divider.png" width="100%" />
    
    ## Overview | ## Features | ## Quick Start | ## Tech Stack | ## Documentation | ## License
    ```
    
    ## CLAUDE.md Standards
    
    - **Required sections:** What This Is, Tech Stack, Project Structure, Key Patterns, Commands, Current State
    - Keep <200 lines
    - Update after every session
    
    ## Code Comments
    
    ### When
    
    - WHY (not what)
    - Complex algorithms
    - Workarounds with issue links
    - API contracts
    - Security decisions
    
    ### Never
    
    - Restating code
    - TODO without issue link
    - Commented-out code (git has history)
    
    ```typescript
    // GOOD: Clerk webhook sends display_name, but our DB schema uses name
    user.name = clerkUser.display_name;
    
    // GOOD: Rate limit: 10 req/60s per IP (CF KV-based). See: https://...
    ```
    
    ## JSDoc
    
    Every exported function — `@param`, `@returns`, `@example`, `@see` (with URL). Descriptions <2 sentences.
    
    ## Stale Code Removal
    
    ### Remove
    
    - Commented-out code
    - Unused imports
    - Dead functions
    - TODO >30 days without issue
    - `console.log` debug
    - Old applied migrations
    
    ### Keep
    
    - User-written code
    - Documented workarounds with links
    - Active feature flags
    
    **Rule:** Never remove user code without asking. Use `npx knip` for unused exports.
    
    ## Sync Protocol
    
    - **Every session** — README matches reality, CLAUDE.md current, remove deleted file refs
    - **Feature completion** — update README features, CLAUDE.md patterns, relevant skills
    - **Refactor** — update all docs, rename refs, grep for old names, update project structure
    
    ## Naming Conventions
    
    - **Files** — kebab-case
    - **Functions** — camelCase
    - **Types** — PascalCase
    - **Constants** — SCREAMING_SNAKE
    - **DB columns** — snake_case
    
    ## Quality Checks
    
    ```bash
    grep -rn "TODO\|FIXME" src/ --include="*.ts" | head -20
    grep -rn "console\.log" src/ --include="*.ts" | grep -v "// keep"
    npx knip --reporter compact
    ```
    
    ## Ownership
    
    - **Owns:** README template, CLAUDE.md standards, code comment quality, JSDoc, stale code removal, cross-project sync, AI-readable formatting
    - **Never owns:** Content writing (→09, 22), implementation (→06), testing (→07), deployment (→08)
    
  • email-templates.md 6 KB
    ---
    name: "Email Templates"
    version: "1.1.0"
    updated: "2026-04-23"
    description: "Branded HTML transactional email: dark gradient header, clean body, dark mode. Contact confirmations, newsletter welcome, donation receipts. Resend via verified megabyte.space."
    ---
    
    # Email Templates
    
    ## Design Principles (Source: Litmus, Really Good Emails)
    
    - **Dark mode support** — emails must look great in both light and dark email clients
    - **Max width: 560px** — optimal reading width across all clients
    - **System fonts** — `-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif`
    - **Single-column** — simplest, most reliable across email clients
    - **Minimal images** — email clients often block images by default
    - **Text-first** — key information must be readable without images loading
    
    ## Template Structure
    
    ```
    ┌─────────────────────────────┐
    │  Dark gradient header (#060610 → #0a0a1a)  │
    │  Logo (center, max 120px wide)              │
    ├─────────────────────────────┤
    │  White body (padding: 32px)                 │
    │  Content (16px, line-height: 1.6)          │
    │  CTA button (brand gradient, centered)     │
    ├─────────────────────────────┤
    │  Light footer (#f5f5f5)                    │
    │  Unsubscribe link + address                │
    └─────────────────────────────┘
    ```
    
    ## Base HTML Template
    
    ```html
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width, initial-scale=1">
      <meta name="color-scheme" content="light dark">
      <meta name="supported-color-schemes" content="light dark">
      <title>Email Subject</title>
      <style>
        :root { color-scheme: light dark; }
        body { margin: 0; padding: 0; background: #f0f0f5; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; }
        .wrapper { max-width: 560px; margin: 0 auto; }
        .header { background: linear-gradient(135deg, #060610, #0a0a1a); padding: 24px; text-align: center; border-radius: 12px 12px 0 0; }
        .header img { max-width: 120px; height: auto; }
        .body { background: #ffffff; padding: 32px; font-size: 16px; line-height: 1.6; color: #333333; }
        .body h1 { font-size: 22px; color: #060610; margin-top: 0; }
        .cta { display: inline-block; background: linear-gradient(135deg, #00E5FF, #50AAE3); color: #060610; font-weight: 600; padding: 14px 32px; border-radius: 8px; text-decoration: none; margin: 16px 0; }
        .divider { border: none; border-top: 1px solid #50AAE3; margin: 24px 0; opacity: 0.3; }
        .footer { background: #f5f5f5; padding: 20px 32px; font-size: 12px; color: #999999; text-align: center; border-radius: 0 0 12px 12px; }
        .footer a { color: #50AAE3; }
        /* Dark mode */
        @media (prefers-color-scheme: dark) {
          body { background: #1a1a2e !important; }
          .body { background: #0f0f1f !important; color: #e0e0e5 !important; }
          .body h1 { color: #f0f0f5 !important; }
          .footer { background: #060610 !important; color: #666680 !important; }
        }
      </style>
    </head>
    <body>
      <div class="wrapper">
        <div class="header">
          <img src="https://domain.com/logo.png" alt="Brand Name">
        </div>
        <div class="body">
          <!-- Content here -->
        </div>
        <div class="footer">
          <p>Brand Name — brian@megabyte.space</p>
          <p><a href="{{{unsubscribe}}}">Unsubscribe</a> · <a href="https://domain.com/privacy">Privacy</a></p>
        </div>
      </div>
    </body>
    </html>
    ```
    
    ## Email Types
    
    ### 1. Contact Form Confirmation
    
    **Subject:** "Got it — we'll be in touch"
    
    ```
    Hi {{name}},
    
    Thanks for reaching out. We received your message and will get back to you shortly.
    
    Here's what you sent:
    — Subject: {{subject}}
    — Message: {{message}}
    
    If this is urgent, reply directly to this email.
    
    Best,
    Brian
    ```
    
    ### 2. Newsletter Welcome
    
    **Subject:** "You're in 🎉"
    
    ```
    Welcome to the [Brand] newsletter.
    
    Here's what to expect:
    - Updates on our mission and impact
    - New features and improvements
    - Stories from the community
    
    No spam. Unsubscribe anytime.
    
    [CTA: Visit Our Site]
    ```
    
    ### 3. Donation Receipt
    
    **Subject:** "Thank you — here's your receipt"
    
    ```
    Thank you for your generous donation of ${{amount}}.
    
    Date: {{date}}
    Transaction ID: {{transaction_id}}
    Tax-deductible: This receipt may be used for tax purposes.
    
    Your support directly funds [specific impact].
    
    [CTA: Share with Friends]
    ```
    
    ### 4. Volunteer Signup
    
    **Subject:** "Welcome aboard"
    
    ```
    You're officially signed up to volunteer.
    
    Next steps:
    1. We'll reach out within 48 hours with scheduling
    2. Bring: comfortable clothes and a willingness to help
    3. Location: [address]
    
    Questions? Reply to this email.
    ```
    
    ### 5. Goal Reached Celebration
    
    **Subject:** "We did it! Goal reached."
    
    ```
    Thanks to people like you, we've reached our ${{goal}} goal!
    
    {{raised}} raised from {{donor_count}} supporters.
    
    This means [specific impact statement].
    
    [CTA: See the Impact]
    ```
    
    ## Sending via Resend
    
    ```typescript
    import { Resend } from 'resend';
    
    const resend = new Resend(env.RESEND_API_KEY);
    
    await resend.emails.send({
      from: 'Brian <brian@megabyte.space>',
      to: [recipient],
      subject: 'Subject line',
      html: renderedTemplate,
      reply_to: 'brian@megabyte.space',
    });
    ```
    
    - **Verified domain** — megabyte.space
    - **API key** — shared key pool (05/shared-api-pool)
    - **Rate limit** — 100 emails/day on free tier
    - **For bulk** — use Listmonk on Cloudflare Containers
    
    ## Testing Checklist
    
    - [ ] Renders correctly in Gmail (web + mobile)
    - [ ] Renders correctly in Apple Mail
    - [ ] Dark mode displays properly
    - [ ] Logo loads (and email is readable without it)
    - [ ] CTA button is tappable on mobile (min 44px height)
    - [ ] Unsubscribe link works
    - [ ] Links are absolute URLs (not relative)
    - [ ] No broken images
    - [ ] Subject line <50 characters
    - [ ] Preview text is meaningful (not "View in browser")
    
  • grammar-audit.md 3.7 KB
    ---
    name: "grammar-audit"
    description: "Final LLM-powered grammar/clarity pass after copy generation. Fixes typos, agreement, tense, capitalization, Oxford comma WITHOUT rewriting or removing information. Outputs a diff, not a rewrite."
    updated: "2026-05-01"
    ---
    
    # Grammar Audit (***FINAL COPY PASS — EVERY SITE, EVERY BUILD***)
    
    After all copy is generated (hero, body, blog, FAQ, microcopy, legal), run `grammar-audit.mjs` (GPT Image 2 vision-mini, concurrency 5-8) to fix mechanical errors WITHOUT rewriting. The pass is a corrective filter, not a creative rewrite.
    
    ## Mandate (NON-NEGOTIABLE)
    
    ### Fix
    
    - Typos
    - Spelling
    - Subject-verb agreement
    - Tense consistency
    - Pronoun agreement
    - Apostrophes / possessives
    - Hyphens vs en / em dashes
    - Capitalization (proper nouns, titles, sentence case)
    - Oxford comma consistency (apply Oxford by default — flip site-wide if voice rejects it)
    - Quotation mark direction
    - Spacing (single space after period)
    - Numbers (≥10 numeric, <10 spelled — except dates / times / money)
    - a vs an before vowel sounds
    - than vs then
    - who vs whom (when natural)
    - its vs it's
    - their / there / they're
    - affect vs effect
    
    ### NEVER
    
    - Rewrite for style
    - Shorten
    - Lengthen
    - Change meaning
    - Remove content
    - Replace banned-word with synonym (anti-slop is skill 09's job, not grammar's)
    - Rephrase voice
    - Add / remove information
    - Reformat structure
    - Translate idioms
    
    ## Output Shape
    
    ```json
    {
      "edits": [
        { "file": "src/data/blog-posts.ts", "before": "She recieved her PHD in 2019,", "after": "She received her PhD in 2019,", "reason": "spelling+capitalization" },
        { "file": "src/pages/about.tsx", "before": "...colleagues, mentors and students.", "after": "...colleagues, mentors, and students.", "reason": "oxford-comma" }
      ]
    }
    ```
    
    Apply edits in-place via `Edit` tool calls. Idempotent — re-running on already-corrected copy produces empty `edits[]`.
    
    ## Run Conditions
    
    1. After `clean_content` blog import (skill 15) and after `enhance-blog-posts.mjs`
    2. After main page copy generation (homepage, about, services, contact, FAQ)
    3. After legal page copy (privacy, terms, accessibility, cookies)
    4. Before `gorgeous-loop` final pass (skill 06)
    5. Re-run on demand via `node scripts/grammar-audit.mjs --only=<file>`
    
    ## Concurrency + Cost
    
    - GPT Image 2 vision-mini at ~$0.15/1M input + $0.60/1M output
    - Per site — ~50K input tokens (all copy concatenated) + ~5K output (diff only) = ~$0.01/site
    - Concurrency 5-8 against the API
    - CLI — `--only=path`, `--limit=N`, `--dry-run`
    
    ## Scope Boundaries (***WHAT IT NEVER TOUCHES***)
    
    - Direct quotes (preserve verbatim — author voice)
    - Named-entity spelling (verified against `_research.json`)
    - Brand names
    - Technical jargon (verified against `_research.json.industry_terms`)
    - Code blocks
    - URLs
    - Email addresses
    - Phone numbers
    - Dates
    - Money figures
    - Proper nouns flagged in `_research.json.entities[]`
    
    ## Hard Gate
    
    After grammar pass — re-run `gate` script. If grammar pass introduced any error caught by other gates (link 404, citation regex match, banned-word match), revert that specific edit and flag in `audit_logs`. Grammar pass is corrective — it never breaks other gates.
    
    ## Voice Preservation
    
    Author voice is sacred. Never normalize "ain't" → "is not" if voice is colloquial. Never remove rhetorical fragments. Never add "that" when omitted intentionally ("She knew [that] he'd come."). The audit asks — "Did the author intend this?" → if yes, leave alone.
    
    ## Reference Anchors
    
    - Strunk & White (1959) for clarity baseline
    - Chicago Manual of Style 17th ed for capitalization / comma
    - APA 7th for academic citations
    - AP Stylebook for journalism
    
    **Default:** Chicago for body copy, AP for blog / news, APA for citations (`rules/citations.md`).
    
  • per-route-metadata.md 6.8 KB
    ---
    name: "per-route-metadata"
    description: "Static head metadata contract per route. RouteMetadata interface, hydrated <head> template, per-route OG image (Satori-rendered, never hero photo reuse), generous internal linking, publication+external-source linking patterns."
    updated: "2026-05-01"
    ---
    
    # Per-Route Static Head Metadata (***BUILD-BREAKING — EVERY ROUTE***)
    
    Every route emits a fully-hydrated static `<head>` at SSG / prerender time. NEVER client-router-only — crawlers and AI agents read the raw HTML before JS executes.
    
    ## RouteMetadata Interface (SSOT — type-checked at build)
    
    ```ts
    interface RouteMetadata {
      route: string; slug: string;
      title: string; description: string; canonicalUrl: string;
      siteName: string; locale: string;
      type: 'website'|'article'|'profile'|'product'|'service'|'local_business'|'nonprofit';
      keywords: string[];
      image: { url: string; secureUrl: string; width: 1200; height: 630; alt: string; mimeType: 'image/jpeg'|'image/png'|'image/webp' };
      twitter: { card: 'summary_large_image'; title: string; description: string; image: string; imageAlt: string };
      jsonLd: Record<string, unknown>[];
      robots: { index: boolean; follow: boolean };
    }
    ```
    
    **Source:** `src/data/page-meta.ts` exports `Record<route, RouteMetadata>`. Blog / dynamic routes derive at build via the same factory.
    
    **Hard gate:** every `<Route path>` in `App.tsx` has an entry — fail if any route resolves to `index.html`'s static title.
    
    ## Per-Route Head Template (paste verbatim — SSOT)
    
    ```html
    <title>{{title}}</title>
    <meta name="description" content="{{description}}" />
    <link rel="canonical" href="{{canonicalUrl}}" />
    <meta property="og:title" content="{{title}}" />
    <meta property="og:description" content="{{description}}" />
    <meta property="og:type" content="{{type}}" />
    <meta property="og:url" content="{{canonicalUrl}}" />
    <meta property="og:site_name" content="{{siteName}}" />
    <meta property="og:locale" content="{{locale}}" />
    <meta property="og:image" content="{{image.url}}" />
    <meta property="og:image:secure_url" content="{{image.secureUrl}}" />
    <meta property="og:image:width" content="1200" />
    <meta property="og:image:height" content="630" />
    <meta property="og:image:type" content="{{image.mimeType}}" />
    <meta property="og:image:alt" content="{{image.alt}}" />
    <meta name="twitter:card" content="summary_large_image" />
    <meta name="twitter:title" content="{{twitter.title}}" />
    <meta name="twitter:description" content="{{twitter.description}}" />
    <meta name="twitter:image" content="{{twitter.image}}" />
    <meta name="twitter:image:alt" content="{{twitter.imageAlt}}" />
    <meta name="robots" content="{{index}}, {{follow}}" />
    <script type="application/ld+json">{{jsonLd}}</script>
    <meta name="theme-color" content="{{brandThemeColor}}" />
    <meta name="application-name" content="{{siteName}}" />
    <meta name="apple-mobile-web-app-title" content="{{siteName}}" />
    <meta name="apple-mobile-web-app-capable" content="yes" />
    <meta name="mobile-web-app-capable" content="yes" />
    ```
    
    ## Per-Route OG Image (***1200×630 — DESIGNED CARD, NEVER HERO PHOTO***)
    
    - **Generate with Satori preferred** — edge-rendered, deterministic, brand-card layout: title + sitelogo + accent gradient + tagline + brand watermark
    - **Fallback** — gpt-image-1.5 with brand colors + business name + tagline + logo bottom-right
    - **NEVER** — reuse homepage hero photo as OG image — must be a designed card
    - **Store at** `r2://sites/<slug>/og/<route-slug>.jpg` (≤100KB, JPEG q=85, 1200×630)
    - Each route gets a unique card
    - **Build gate** — every route's `og:image` URL HEADs 200 + size ≤100KB + dimensions 1200×630
    
    ## Generous Internal Linking (***≥5 PER PAGE — body-copy contextual***)
    
    - Every page contains **≥5 internal links woven into body copy** with descriptive anchor text (never "click here", "learn more")
    - When body mentions: institutions / journals / conferences / awards / organizations / people / places, link them
    - Internal where a relevant page exists; outbound `rel="noopener" target="_blank"` to authoritative source otherwise (journal name → journal homepage, university → official site, conference → official site)
    - Anchor text varies — never repeat identical text site-wide
    - **Hard gate:** `validate-internal-links.mjs` counts contextual `<a>` per page, flags pages with <5 or with repeated identical anchors >2×
    
    ## Publication / External-Source Linking (***FOR PORTFOLIO/ACADEMIC/PRESS LISTINGS***)
    
    When site lists publications, papers, articles, talks, press, awards, podcasts, each item card MUST contain:
    
    1. Auto-extracted ~40-word summary from the original detail page (crawled at research time)
    2. Deep-link to original (`target="_blank" rel="noopener"`)
    3. Hyperlinked source name (journal / publisher / conference) → its homepage or DOI
    
    ### Rules
    
    - NEVER import direct quoted abstracts (SEO duplicate-content risk + copyright)
    - Summary = our paraphrase
    - Date + author + type + ISBN (if any) extracted as structured metadata (BlogPosting / Article / ScholarlyArticle JSON-LD)
    
    ### Build gate
    
    Every publication card has summary + outbound link + source-name link OR fail.
    
    ## Publication Item Schema
    
    ```ts
    interface PublicationItem {
      title: string; summary: string;  // ~40 words paraphrase, NEVER quoted abstract
      authors: string[]; date: string;
      source: { name: string; url: string };  // journal homepage, conference site
      deepLink: string;  // direct link to article/DOI
      type: 'paper'|'article'|'talk'|'book_chapter'|'podcast'|'press';
      isbn?: string; doi?: string;
    }
    ```
    
    ## Sub-Page Type Mapping
    
    - **homepage** → `website`
    - **about / team / bio** → `profile`
    - **service / product detail** → `service` / `product`
    - **blog post** → `article`
    - **restaurant / salon / clinic** → `local_business`
    - **nonprofit** → `nonprofit`
    
    ### JSON-LD schema by type
    
    - **home** — WebSite + Organization
    - **bio** — Person + ProfilePage
    - **service** — Service + Organization
    - **article** — BlogPosting + BreadcrumbList
    - **local** — LocalBusiness + PostalAddress + GeoCoordinates
    - **nonprofit** — NGO + Organization
    
    Always + BreadcrumbList on non-home routes.
    
    ## Anchor Text Variation (anti-templating)
    
    Never reuse identical anchor text across the site. Vary phrasing per occurrence: "her work at Boston University" / "Boston University doctoral program" / "BU's nutrition department". Each occurrence reads naturally in context.
    
    ## Validator: validate-route-metadata.mjs
    
    For every route in `sitemap.xml`:
    
    - Fetch raw HTML (NOT executed JS)
    - Assert:
      - Title 50-60ch
      - Desc 120-156ch
      - Canonical present
      - `og:image` + `og:title` + `og:description` present non-empty
      - `twitter:card=summary_large_image`
      - JSON-LD parseable + ≥4 blocks
      - h1 in raw HTML before any `<script>`
    - Fail build on any violation
    - Wired into `gate` script (skill 07 `quality-gates.md`)
    
  • seo-and-keywords.md 6.1 KB
    ---
    name: "SEO and Keywords"
    version: "1.2.0"
    updated: "2026-04-23"
    description: "Full SEO engine: keyword research, competitor analysis, per-page primary+longtail targeting, Yoast-level checks, schema markup, internal linking, pSEO at scale. Runs every build."
    ---
    
    # SEO and Keywords
    
    Every page targets: 1 holy-grail keyword (high-volume) + 1-2 longtail phrases (lower competition, high intent) + semantic variations woven naturally.
    
    ## Keyword Research Workflow
    
    ### Step 1: Seed from Product
    
    `Domain → category → features → user problems`. E.g. `"instantidle.com" → container deployment → "docker hosting" → "cheap docker hosting"`.
    
    ### Step 2: Expand with APIs
    
    #### Google Autocomplete (FREE, no key)
    
    ```typescript
    async function getAutocompleteSuggestions(seed: string): Promise<string[]> {
      const url = `https://suggestqueries.google.com/complete/search?client=firefox&q=${encodeURIComponent(seed)}`;
      const [, suggestions] = await (await fetch(url)).json();
      return suggestions;
    }
    // Expand with alphabet modifiers: `${seed} a`, `${seed} b`, etc.
    ```
    
    #### Other tools
    
    - **DataForSEO** (~$0.01/keyword) — volume, CPC, competition, trends
    - **Google Search Console** (FREE) — real clicks, impressions, position
    - **Google Trends** — relative interest over time
    
    ### Step 3: Competitor Analysis
    
    1. Identify 3-5 competitors
    2. Scrape `sitemap.xml` → fetch pages → extract title / h1 / meta
    3. Find gaps (keywords they rank for that we don't) + easy wins (high volume + low competition)
    
    ### Step 4: Selection Matrix
    
    - **Holy-grail** — highest volume relevant keyword
    - **Longtail 1** — lower competition, commercial intent
    - **Longtail 2** — informational intent, blog / resource page
    
    ## Per-Page Yoast Checklist (ALL GREEN)
    
    - **Title** — 50-60 chars, keyword at start, unique, includes brand. Format: `{Keyword} — {Supporting} | Brand`
    - **Meta description** — 120-156 chars, contains keyword, includes CTA, unique per page
    - **URL** — short, readable, keyword-rich, lowercase, hyphens. Good: `/docker-hosting`
    - **Headings** — one H1 with keyword; H2s with longtail/semantic variations; logical hierarchy; no skipped levels
    - **Content** — keyword in first 100 words; density 0.5-3% (natural); min 300 words (600+ preferred); Flesch ≥60; short paragraphs (2-4 sentences); subheadings every 200-300 words; transition words ≥30% of sentences
    - **Images** — alt text with keyword (natural); descriptive filename; width/height set; lazy load below-fold; WebP <200KB
    - **Internal links** — 2-3+ per page, descriptive anchors
    - **External links** — 1-2 outbound to authoritative sources, `target="_blank" rel="noopener"`
    - **Schema / JSON-LD** — 4+ per page minimum: Organization + WebSite + WebPage + domain-specific (FAQ, Product, BreadcrumbList, Article, HowTo, SoftwareApplication, DonateAction)
    - **Technical** — canonical URL, mobile-friendly, LCP <2.5s, HTTPS, no duplicate content, XML sitemap, robots.txt
    
    ## Readability Enforcement (Flesch ≥60)
    
    ### Yoast 9 Checks (All Automatable)
    
    - Flesch ≥60 | Sentence length avg ≤20 words | Paragraph length ≤150 words
    - Passive voice <10% | Transition words ≥30% of sentences | Consecutive sentences <3 with same opening word
    - Subheading distribution ≤300 words between H2/H3 | Text present | Exactly 1 H1
    
    ### By Section
    
    Hero 80+ | Body 50-65 | Technical docs 40-50 | Legal 50+ | Errors 70+ | CTAs 80+
    
    ## Programmatic SEO
    
    ```typescript
    // Dynamic pages: "Docker hosting in [city]"
    const cities = ['New York', 'San Francisco', 'London'];
    for (const city of cities) {
      // slug, title, h1, metaDescription all include city + keyword
    }
    ```
    
    ### Internal Linking Strategy
    
    - Homepage → category pages → product pages | Blog → relevant products + related posts
    - Every page: 2-3 internal links min; anchor text = keyphrase variations, never "click here"
    - Orphan detection after build
    
    ## SEO Audit (Every Deploy)
    
    Playwright test verifying: title 30-60 chars · meta desc 120-160 chars · exactly 1 H1 · canonical URL · OG tags · JSON-LD ≥1 · no Lorem/TODO/placeholder · images have alt · internal links ≥3 · `robots.txt` 200 · `sitemap.xml` 200
    
    ## API Stack ($8/mo total)
    
    - **Google Search Console** — Free — real clicks/impressions
    - **VebAPI** — $8/mo — competitor keywords, SERP
    - **Serper free tier** — Free — 2,500/mo SERP + PAA
    - **Google Suggest** — Free — keyword expansion
    - **SearXNG (self-hosted)** — Free — PAA questions
    - **DataForSEO** — $0.0006/query — bulk volumes at scale
    
    ## Google's SEO Rules (2026 Core Update)
    
    - Original research/proprietary data rewarded (Information Gain signal)
    - Write naturally, no stuffing
    - LCP <2.5s is a hard ranking factor
    - AI Overviews steal short-tail clicks — longtail more important than ever
    - Meta keywords tag ignored
    
    ## Longtail Strategy (Moz 2026)
    
    - Ultra-long-tail is "new normal"; short-tail triggers AI Overviews
    - Modifier stacking: `[product] + [use case] + [audience] + [qualifier]`
    - Problem-first keywords beat feature keywords
    - GSC: impressions >10 but position >10 = low-hanging fruit
    
    ## MANDATORY: Research BEFORE Writing
    
    1. Identify 5-10 candidate keyphrases
    2. Evaluate — volume, difficulty, intent, relevance
    3. Select PRIMARY (1-4 words, unique to page)
    4. Select 2-3 RELATED keyphrases
    5. Map keyword → page URL (no duplicates)
    6. Write content optimized from first sentence
    
    ## Keyword-to-Page Map
    
    ```typescript
    const keywordMap = {
      '/': { primary: 'main keyword', related: ['variation 1', 'variation 2'] },
      '/pricing': { primary: 'pricing keyword', related: [...] },
    };
    // No two pages share same primary keyphrase
    ```
    
    ## Rich Snippets
    
    Every page — Organization + WebSite(SearchAction) + WebPage + domain-specific schema. OpenSearch XML at `/opensearch.xml`. Validate with Google Rich Results Test.
    
    ## Ownership
    
    - **Owns:** keyword research, competitor analysis, per-page targeting, Yoast checks, readability, programmatic SEO, audit automation, internal linking, schema/JSON-LD, OG/Twitter tags, sitemap, robots.txt, keyword-to-page mapping
    - **Never owns:** content writing (→09, 22), visual design (→10), deployment (→08)
    
  • SKILL.md 10.9 KB
    ---
    name: "brand-and-content-system"
    description: "Extract real brands (Wayback for rebuilds). Copy system, headline/CTA rules, trust surfaces, legal pages, SEO+structured data, anti-AI-slop, microcopy, DESIGN.md, W3C DTCG tokens, pSEO 5 types, GEO/AI search."
    metadata:
      version: "2.1.0"
      updated: "2026-05-03"
      effort: "medium"
      model: "haiku"
    license: "Rutgers"
    compatibility:
      claude-code: ">=2.0.0"
      agentskills: ">=1.0.0"
    submodules:
      - ai-search-geo.md
      - build-breaking-rules.md
      - documentation-and-codebase-hygiene.md
      - email-templates.md
      - grammar-audit.md
      - per-route-metadata.md
      - seo-and-keywords.md
      - social-automation.md
    priority: 3
    pack: "content"
    stage: stable
    triggers:
      - "brand"
      - "content"
      - "copy"
    paths:
      - "org:website_build"
      - "org:website_build"
    ---
    
    # 09 — Brand and Content System
    
    Extract real brand assets and apply the full copy system (anti-slop, SEO, trust surfaces, GEO) to every website build surface.
    
    > **Model migration note (pass-77, 2026-06-09)**: `DALL-E` → **GPT Image 1.5** + `GPT-4o` → **GPT Image 2 vision**. Per `platform.openai.com/docs/deprecations`. Brand extraction protocol unchanged.
    
    ## Brian's Brand Voice
    
    - Slogans: "Open-Source Wizardry. 100% Wizardry. 0% Robes." / "Often imitated, never duplicated."
    - Newsletter: "Lab Insights Journal" | Handle: @HeyMegabyte | Email: hey@megabyte.space / brian@megabyte.space
    - Tone: professional but irreverent, "Hey" not "Hi", first-person Megabyte Labs
    - Always "cross-platform" + "open-source" | Install Doctor: "single command" / "one-liner"
    - Hero: "[Topic] **Innovation**" | Footer CTA: "Let's Talk" | Rates: $140/hr ($70 nonprofit), $100/mo WordPress
    - Social: all platforms, "Megabyte Minis" YouTube, Dev.to, Patreon
    - Psychology: reciprocity (teach), social proof near CTAs, authority (depth/numbers), unity ("we/us"), Peak-End Rule
    
    ## Brand Extraction (Rebuilds)
    
    1. Screenshot existing (Wayback if down). Extract logo/colors/fonts/tone. Never discard equity.
    
    2. **Color extraction (NON-NEGOTIABLE)** — Screenshot with Playwright, GPT Image 2 vision extracts hex (logo priority), cross-ref logo, build palette, validate WCAG AA. NEVER invent, NEVER use Emdash defaults for clients, NEVER infer from category.
    
    3. **Second-pass verification (BUILD-BREAKING — pre-deploy)** — After GPT Image 2 vision returns `{primary, secondary, accent}`:
       - Load logo PNG via sharp, sample dominant chroma via k-means k=5 ignoring transparent + near-white/near-black (top-3 cluster centroids in HSL)
       - For EACH color, compute min HSL hue-distance to top-3 logo chromas — if `min_hue_distance > 30°` AND saturation>0.2, FAIL w/ diagnostic
       - Re-run GPT Image 2 vision w/ corrective prompt naming top-3 logo chromas + demanding `primary` derived from one
       - Validator: `validate-color-from-logo.mjs` in `build_validators.ts` between brand-research and template-pick
       - NEVER ship primary color failing hue-distance check
    
    4. **Logo-luminance + source-theme drives theme (NON-NEGOTIABLE)** — Two-signal:
       - Signal A: logo dominant-color luminance (WCAG formula)
       - Signal B: source-site dominant background luminance (Playwright screenshot of `body` background)
       - BOTH agree → match; disagree → source-site wins UNLESS source design score <7/10 (then logo wins)
       - High-quality source (≥7/10 via GPT Image 2 vision `detail:low`) → match source theme verbatim
       - Set theme BEFORE template selection. Reject palette where logo-on-bg contrast <4.5:1 (WCAG AA).
       - "Dark-first" applies to accent-rich Emdash/SaaS brands, NOT to logo-driven non-profit/serif clients or high-quality light-themed source brands
    
    5. **Logo-vs-container contrast (BUILD-BREAKING — every render)** — Every logo render (header, footer, hero, modal, splash, mobile menu, sidebar) MUST contrast container bg by ≥4.5:1 on logo's dominant chroma (not transparent pixels)
       - Forbidden: white-text-logo on white/cream | dark-text-logo on dark/navy | low-saturation-logo on same-hue bg
       - Resolution: header AND footer themes chosen AFTER logo luminance scan. Dual-theme site needing SAME logo → ship TWO files (`brand-mark-light.svg` for dark bg, `brand-mark-dark.svg` for light bg) + CSS `<picture><source media>` swaps
       - Automate via skill 12 logo-variant-generator (Real-ESRGAN inversion or `magick -channel RGB -negate`; color logos w/ text → GPT Image 1.5 w/ "same logo on transparent bg w/ text inverted to <opposite-luminance>")
       - Validator: `validate-logo-contrast.mjs` — Claude Sonnet 4.6 vision samples logo bbox + container computed bg at 6bp + pixel sampling, fails if <4.5:1
    
    6. **Brand-element extraction (logo is gold mine — extract DNA)** — GPT Image 2 vision returns `{font_family_guess, suggested_heading_font, suggested_body_font, font_weight, letterspacing, has_icon_mark, icon_mark_description, icon_mark_dominant_color, decorative_motif_description, motif_extractable (bool)}`
       - Matched Google Font → `--font-heading` site-wide
       - `motif_extractable=true` → crop icon-only region (`magick logo.png -alpha extract -trim +repage`), upscale 2-4× via Real-ESRGAN / GPT Image 1.5 variation, save as `assets/brand-splash.png` + `assets/brand-mark.png`
    
    7. **Logo singularity (BUILD-BREAKING — exactly ONE logo file per container)** — Every logo container renders EXACTLY ONE logo asset
       - Never composite two logo sources side-by-side; never stack icon-mark + wordmark as separate `<img>` tags; never render `apple-touch-icon.png` next to `logo.svg` in same container
       - Composition at asset-prep time via `magick logo-mark.png logo-wordmark.png +append`, NOT at render time
       - Validator: `validate-logo-singularity.mjs` parses `dist/` HTML; count>1 descendant `<img>` or inline `<svg>` in same logo container = FAIL
    
    8. **Logo (NON-NEGOTIABLE)** — Every project needs premium logo. See Skill 12 for full process.
    
    9. **Audit** — logo found + rated ≥7/10 + works 16-512px, colors EXTRACTED, palette WCAG AA, typography + tone + messages identified.
    
    ## Brand Extraction from Physical Assets (LOCAL BUSINESS — NO WEBSITE)
    
    - Street View Static API: `https://maps.googleapis.com/maps/api/streetview?size=1200x800&location={lat},{lng}&source=outdoor`
    - Places photos: filter `types: ["exterior", "storefront"]`
    - GPT Image 2 vision on storefront — prompt: `"Extract brand identity from this business storefront photo. Return JSON: {sign_text, sign_font_style, primary_color (hex), secondary_color (hex), accent_color (hex), logo_description, overall_aesthetic, confidence (0-1)}"`
    - Business cards: GPT Image 2 vision extracts logo (crop region), colors (exact hex), font, tagline, NAP for verification.
    - Color extraction priority: 1. Signage → 2. Logo → 3. Storefront awning/trim → 4. Interior decor → 5. Vehicle wrap → 6. Business card → 7. Category default (LAST RESORT). Each tagged with `color_source`.
    - Font matching from signage: Script → Dancing Script | Serif → Playfair Display | Modern sans → Inter | Hand-lettered → Caveat. Never use exact proprietary fonts.
    
    ## Brand Inference (New Products)
    
    - Dev tool → technical/dark/monospace | SaaS → professional/clean/cards | Agency → confident/bold
    - E-commerce → friendly/product-focused | Nonprofit → warm/impact imagery | API → technical/docs-forward
    - Emdash defaults (NOT for clients): `#00E5FF`, `#50AAE3`, `#060610`. Sora / Space Grotesk / JetBrains Mono.
    
    ## Anti-AI-Slop Detection (MANDATORY SCAN)
    
    **Banned copy words:** `delve | leverage | unleash | revolutionize | best-in-class | cutting-edge | discover | innovative | seamless | robust | synergy | elevate | empower | transformative`
    
    **Banned patterns:** "Welcome to" | "Discover [product]" | vague aspirational headlines | hedging ("may help you," "can potentially") | generic superlatives
    
    **Banned design tells:** Inter as sole font | purple-blue gradients | uniform 16px border-radius everywhere | centered everything | Hero/Lucide as sole icon set | abstract 3D blobs | uniform fade-in on all elements | plastic AI stock photos
    
    Fix: ask "Would the founder actually say this?" No → rewrite.
    
    ## Copy System
    
    - Headlines — benefit-first, specific, numbers, max 8 words
    - Subheadings — expand promise, 15-25 words
    - Body — one idea/paragraph, 2-4 sentences, active, concrete, benefit-oriented
    - CTAs — specific action verb first, gradient primary + ghost secondary, above fold + page end
    - Never: "Click here" | "Submit" | "Learn more"
    - Personality mapping — Expert → precise industry terms | Direct → short declarative | Pragmatic → outcomes/implementation
    - Vocabulary: always-use / never-use / prefer-over lists | max sentence: 25 words
    - Banned structures: passive voice, hedging, em dashes mid-sentence | monthly drift audit
    
    ## Microcopy System
    
    - Error messages — [What happened] + [What to do]. Empathetic, solution-oriented. "Payment failed. Try a different card or contact support." Never "Error 500" or jargon. Flesch 70+.
    - CTAs — action verb first, max 3 words preferred: "Start building" | "Ship today" | "Get access"
    - Empty states — acknowledge absence + suggest action: "No projects yet. Create your first one." Never just "No results"
    - Toasts — past tense success ("Project created"), present in-progress ("Saving…"), plain-language errors
    - Form labels — noun phrases, sentence case. Helper text: one line, 10 words max
    
    ## Machine-Readable Brand Documentation
    
    - **DESIGN.md** (6 sections): 1. Visual Theme | 2. Color Palette (hex + role) | 3. Typography (family + scale + weight) | 4. Spacing + Layout | 5. Components (states + variants + props) | 6. Elevation + Shadows
    - **Tokens**: W3C DTCG JSON format, single source of truth. Generated from `tokens.json` → CSS vars + Tailwind config.
    
    ## SEO + Structured Data
    
    ### Per-page MUST have
    
    - Title 50-60 chars keyphrase-first | meta desc 120-156 chars | canonical
    - OG image 1200×630 branded card | one H1 in prerendered HTML
    - JSON-LD: WebPage floor; Org/BreadcrumbList/FAQPage/Person/Product/Service only when real entities
    
    ### pSEO 5 page types
    
    - Integration (`/integrations/{tool}`) | Comparison (`/compare/{a}-vs-{b}`) | Use-case (`/for/{audience}`) | Template (`/templates/{type}`) | Location (`/{city}-{service}`)
    - Each: unique H1 + meta desc + 800+ unique words + 1 unique image + 3+ internal links + 1+ outbound citation. Never templatize verbatim.
    
    ### GEO / AI search
    
    - Quotable answer blocks 40-60 words (LLMs cite)
    - FAQPage schema highest AI-citation rate
    - JSON-LD facts MUST also appear as visible HTML text | lead paragraphs answer query in <40 words
    - EEAT: author bio + Person schema + `sameAs` + dated revision + ownership
    
    ## Trust Surfaces
    
    - Real testimonials w/ verifiable attribution | license/accreditation badges
    - Security.txt + privacy + terms | Person JSON-LD w/ sameAs | About + Team pages with real bios
    
    ## Legal Pages (required)
    
    - /privacy | /terms | /accessibility
    
    ## See submodules: email-templates, social-automation, seo-and-keywords, documentation-and-codebase-hygiene, per-route-metadata, grammar-audit, build-breaking-rules.
    
  • social-automation.md 6 KB
    ---
    name: "Social Automation"
    version: "1.1.0"
    updated: "2026-04-23"
    description: "Auto-post via Postiz (self-hosted Coolify) on deploy. X/Twitter, LinkedIn, Reddit, GitHub, Threads, TikTok, Pinterest+. Platform-specific copy in Brian's voice, OG images, Playwright verification."
    ---
    
    # Social Automation via Postiz
    
    ## Postiz Instance
    
    - **URL** — https://postiz.megabyte.space
    - **Connected platforms** — X/Twitter, LinkedIn, Reddit, GitHub, Threads, Facebook, TikTok, Pinterest, Dribbble, Discord, Slack, Mastodon, Telegram, Beehiiv
    
    ## When to Auto-Post
    
    - New product launch (first deploy of a domain)
    - Major feature additions (new sections, new integrations)
    - Milestone achievements (donation goals met, impact numbers)
    - **NOT for** — bug fixes, style tweaks, skill updates, internal changes
    
    ## Post Generation
    
    1. Summarize the change in 1-2 sentences (Brian's voice — sharp, punchy)
    2. Include the site URL
    3. Include the OG image URL for visual preview
    4. Add relevant hashtags (max 5)
    5. Customize per platform:
       - **X/Twitter** — 280 chars max, punchy, 2-3 hashtags
       - **LinkedIn** — professional tone, 1-2 paragraphs, link in body
       - **Reddit** — subreddit-appropriate title, link post
       - **Facebook** — casual, include image, tag @HeyMegabyte
    
    ## Postiz API
    
    ```bash
    # Create a post
    curl -X POST "https://postiz.megabyte.space/api/posts" \
      -H "Authorization: Bearer POSTIZ_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "content": "Post text here",
        "platforms": ["twitter", "linkedin"],
        "media": ["https://domain.com/og-image.png"],
        "schedule": "now"
      }'
    ```
    
    ## Quality Verification
    
    After posting, verify the post rendered correctly:
    
    1. Get the public share URL from the Postiz API response
    2. Use Playwright to screenshot the share URL
    3. Visual inspection — verify image loaded, text not truncated, link works
    4. If issues found — debug, fix, repost
    
    ## Iterative Improvement
    
    Track which posts get engagement. Over time:
    
    - Which platforms drive the most traffic?
    - Which post formats get the most engagement?
    - What time of day performs best?
    
    Log this in PostHog for analysis.
    
    ## Coolify Access
    
    Postiz runs on Coolify. If the API is down:
    
    1. Check Coolify status — `curl coolify.megabyte.space/api/v1/services`
    2. Restart the service if needed via Coolify API
    3. Log the outage for future reference
    
    ## MCP Tools Available
    
    ### Postiz MCP (`mcp__postiz__*`)
    
    - **`integrationSchedulePostTool`** — schedule a post to connected platforms with date / time
    - **`integrationList`** — list all connected platform integrations
    - **`integrationSchema`** — get schema for a specific integration (required fields, limits)
    - **`generateImageTool`** — generate social preview images with AI
    - **`generateVideoTool`** — generate short video clips for social
    - **`generateVideoOptions`** — get available video generation options
    - **`videoFunctionTool`** — execute video processing functions
    - **`triggerTool`** — trigger immediate post (bypass scheduling)
    - **`ask_postiz`** — ask Postiz AI for post copy suggestions
    
    ### Coolify MCP (`mcp__coolify__*`) — for Postiz service health
    
    - **`diagnose_app`** — diagnose Postiz service health
    - **`get_service`** — get Postiz service details
    - **`control`** — restart Postiz if it's down
    
    ### PostHog MCP (`mcp__posthog__*`) — for engagement tracking
    
    - **`authenticate`** — connect to PostHog for social analytics
    
    ## Posting Workflows
    
    ### Launch Day Social Sequence
    
    When a new site launches, execute this sequence:
    
    1. **T+0 min** — Post to X/Twitter (highest immediacy audience)
    2. **T+15 min** — Post to LinkedIn (professional framing)
    3. **T+30 min** — Post to Reddit (relevant subreddit, link post)
    4. **T+1 hr** — Post to Facebook, Threads (broader reach)
    5. **T+2 hr** — Post to Discord, Slack channels
    
    ```typescript
    // Example: Schedule the full launch sequence
    const platforms = ['twitter', 'linkedin', 'reddit', 'facebook', 'threads'];
    const delays = [0, 15, 30, 60, 120]; // minutes
    
    for (let i = 0; i < platforms.length; i++) {
      const scheduleTime = new Date(Date.now() + delays[i] * 60000);
      // Use mcp__postiz__integrationSchedulePostTool with platform + scheduleTime
    }
    ```
    
    ### Social Preview Image Generation
    
    Before posting, generate an OG-quality social image:
    
    1. Call `mcp__postiz__generateImageTool` with site title + tagline
    2. If custom image exists (OG image from site), use that instead
    3. Verify image dimensions — 1200×630 for OG, 1080×1080 for Instagram / Threads
    4. Fallback — screenshot the hero section via Playwright at 1200×630
    
    ## Computer Use Integration
    
    Use `mcp__computer-use__*` tools for visual verification of posted content:
    
    1. **Post verification** — after scheduling via MCP, open the platform in browser and screenshot to confirm the post rendered with correct image, text, and link
    2. **Engagement monitoring** — screenshot Postiz dashboard at `https://postiz.megabyte.space` to check engagement metrics after 24 hours
    3. **Platform-specific debugging** — if a post looks wrong on a specific platform, screenshot the live post to diagnose formatting issues
    
    ```
    Workflow: Post → Wait 60s → Screenshot platform → AI visual check → Flag issues
    ```
    
    ## Acceptance Criteria
    
    1. Post reaches all specified platforms — `mcp__postiz__integrationList` confirms connected, API returns 200 per platform
    2. OG image renders correctly — Playwright screenshot of share URL shows image loaded (not broken / missing)
    3. Text not truncated — post text is within platform character limits (280 X, 3000 LinkedIn, 300 Reddit title)
    4. Link is clickable and resolves — fetch the URL in the post body, confirm 200 response
    5. Hashtags present and relevant — 2-5 hashtags per post, no banned / spam tags
    6. Launch sequence timing correct — posts staggered per the launch day sequence (not all simultaneous)
    7. No duplicate posts — check Postiz post history, no identical content within 24 hours
    8. PostHog event tracked — `social_post_published` event fires with platform + URL properties
    

Comments (0)

Sign in to join the conversation.

No comments yet.

Reviews (0)

No reviews yet.

Related