name: trueadvertize-seo-geo description: "Produce a 3500–4200 word blog article optimized for both Google SEO AND AI search citation (ChatGPT, Perplexity, Google AI Overviews). Uses Serper API for keyword research, loads TA's ICP + brand-voice at runtime, outputs MDX for the /blog route. Use when: writing a TA blog article, producing GEO content, drafting for trueadvertize.com/blog. Trigger phrases: write SEO article, create blog post, GEO content for TA, write a TA article." allowed-tools: Read Write Edit Bash WebSearch WebFetch AskUserQuestion Grep Glob
trueadvertize-seo-geo
Article production engine for trueadvertize.com/blog. One skill, 10-step workflow, hard quality gates. Loads icp.json + brand-voice.json at runtime — never embed those files; they evolve.
The whole point: from approved topic → published-ready MDX in ~2.5 hours, optimized for both Google ranking AND AI citation. Final draft is reviewer-ready, not first-pass.
When to use
- "Write a TA blog article on
" - "Produce GEO content for the slug
" - "Adapt the calendar's Week N topic into a draft"
- Any new piece of trueadvertize.com/blog content
When NOT to use
- LinkedIn personal posts — use
SAM Team Engine(different voice cadence) - Cold outbound emails — use
clay-alt-generate-copy - TA ad / landing / sales / webinar copy — use
trueadvertize-master-copy - Client-facing copy for a TA client (Atlas, Global Hydro, etc.) — TA voice ≠ client voice
- Reddit posts — use
trueadvertize-reddit-post(different platform conventions)
Required inputs
Before invoking, you should have:
- A topic confirmed against the calendar in
CONTENT_SYSTEM.mdSection 8 - A slug (kebab-case, includes primary keyword)
- A primary keyword (the term you want to rank for)
- Optional: an angle or audience qualifier if the topic is broad
If any are missing, use AskUserQuestion to collect them in a single batch.
How
Step 1 — Load context (ALWAYS first, no skipping)
Read in parallel:
C:/Users/Juanc/Nick Saraev/trueadvertize-context/icp.json— 41-Q ICP profile (audience psychology, pain language)C:/Users/Juanc/Nick Saraev/trueadvertize-context/brand-voice.json— voice spec (do_say / dont_say / tone / 5-step method)Landing Page/CONTENT_SYSTEM.md— Sections 2 (voice profile), 6 (quality checklist), 8 (calendar context)
Gate: if either JSON has version != "v1.0" or status != "AUTHORITATIVE", STOP and surface — stale context produces subtly off-brand articles.
Step 2 — Load the Serper API key
export SERPER_API_KEY=$(grep SERPER_API_KEY "Landing Page/.env.local" | cut -d= -f2)
If .env.local is missing or the key is unset, STOP and ask the user.
Step 3 — Keyword research via Serper (curl)
Run these calls in parallel; capture output to content/research/<slug>.md:
Primary keyword SERP:
curl -sS -X POST "https://google.serper.dev/search" \
-H "X-API-KEY: $SERPER_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"q\":\"<primary keyword>\",\"num\":10}"
Capture: top 10 organic results (title + URL + snippet), "People Also Ask" questions, related searches, knowledge graph entry if any.
Autocomplete expansion:
curl -sS -X POST "https://google.serper.dev/autocomplete" \
-H "X-API-KEY: $SERPER_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"q\":\"<primary keyword>\"}"
Capture: 5–10 long-tail variations.
Recent news (trending angles):
curl -sS -X POST "https://google.serper.dev/news" \
-H "X-API-KEY: $SERPER_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"q\":\"<primary keyword>\",\"num\":5}"
Capture: last-30-days news headlines + dates.
Top 3 competitor scrape:
curl -sS -X POST "https://google.serper.dev/scrape" \
-H "X-API-KEY: $SERPER_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"url\":\"<top result URL>\"}"
Run once per top-3 URL. Capture: full article text, headers, key claims.
Step 4 — Synthesize the research
Write content/research/<slug>.md with:
# Research — <slug>
## Primary keyword
<keyword>
## Top 10 SERP (current)
1. [Title](url) — snippet
2. [Title](url) — snippet
[...]
## People Also Ask
1. <question>
2. <question>
[...]
## Related searches
- <variation>
[...]
## Autocomplete expansions
- <long-tail>
[...]
## Recent news (last 30 days)
- <date>: <headline> (<source>)
## Top 3 competitor analysis
### #1 — <URL>
- Word count: ~X
- Structure: <H2 list>
- Key claims: <bullet list>
- Gaps: <what they miss that TA can answer>
[repeat for #2 and #3]
## Unique TA angle
<1-paragraph synthesis: where do TA's expertise + the SERP gap intersect?>
## 3–5 citable stats
- <stat with source URL>
[...]
Step 5 — Outline
Produce content/outlines/<slug>.md:
# Outline — <slug>
## Title (≤60 chars)
<title with primary keyword, benefit-focused>
## Meta description (150–160 chars)
<single sentence, includes primary keyword, ends with hook or CTA>
## TL;DR (2–3 sentences, front-loaded)
<the synthesized answer — this is what AI tools will extract>
## H2 section plan (8–12 sections)
1. **<H2 title>** — <one-sentence summary>
2. **<H2 title>** — <one-sentence summary>
[...]
## Comparison table planned
| <Dimension> | <Option A> | <Option B> | <Option C> |
[outline only — fill in draft]
## FAQ (5–8 questions sourced from PAA + autocomplete)
1. **Q:** <PAA question> — **A:** <2–3 sentence answer>
[...]
## Key Takeaways (3–5 bullets)
- <bullet>
[...]
## Internal links planned
- → /blog/<other-slug-1>
- → /<existing-page>
[...]
## External authority links planned
- → <source 1>
- → <source 2>
Gate: before writing the draft, eyeball the outline. Does it pass the topic score from CONTENT_SYSTEM.md Section 3? If not, stop and revise.
Step 6 — Draft
Write content/drafts/<slug>.md following the locked structure from CONTENT_SYSTEM.md Section 4 Step 4. Word count target: 3,500–4,200.
Writing rules (apply as you write, not at the end):
Sentence-level:
- Mix short punchy lines with longer explanatory sentences. Open most sections with a 5–10 word punchy line.
- First person where appropriate ("here's what we've seen", "in our last 5 builds"). Treat the reader as a peer founder, not a search engine.
- Specific numbers over vague claims. NEVER write "many", "most", "significantly" without a number.
- Bold the key insight in each section (≤1 bold per paragraph).
Voice-level:
- Use at least 5 phrases from
do_saynaturally — system / engineering rigor / allbound / partnership not outsourcing / 8–12% reply rates / etc. - Mirror back 2–3 pain phrases from
icp.jsonQ22 ("our pipeline is cooked", "stuck scaling", "tired of dragging this thing uphill") - Wedge at least once against the
primary_enemy_belief("great product = growth") - Zero em dashes (—). Use commas, periods, colons, or middle dots.
- Strip every
dont_sayphrase. This includes consultant filler (leverage / synergy / world-class), AI tells ("here's the thing", "it's not X, it's Y"), and salesy filler (deep dive, value prop, low-hanging fruit).
Structure-level:
- TL;DR box appears BEFORE the Table of Contents.
- First 100 words contain: primary keyword, key insight, author credibility marker (Samuel — former data scientist, 3 yrs building B2B SaaS GTM).
- Each H2 section is self-contained (extractable by AI without needing context from above).
- At least 1 comparison table OR structured list.
- FAQ section uses real PAA questions verbatim where possible.
Honesty gates:
- ONLY real testimonials: Dave Menjura (Clay) + Collin Stewart (Predictable Revenue). No invented client names.
- All methodology numbers (8–12% reply rate, 100+ deals/6mo, 70% lower CPM, 300+ meetings) framed as targets/benchmarks: "This approach typically yields 8–12% reply rates against a real list." — NOT "Our client X got 12% reply rates." (unless cleared by Sam with attribution).
- No invented case studies. If you can't cite a real source, frame as methodology.
Step 7 — Voice validation
Run two passes:
dont_sayscan: grep the draft against thebrand-voice.jsondont_saylist + thede-ai-contentblacklist. Any hits → rewrite the sentence. Re-scan. Loop until clean.fresh-reviewerpass (optional but recommended for cornerstone articles): invoke thefresh-reviewerskill on the draft. Treat its feedback as a second opinion.
Step 8 — Quality checklist
Walk the full checklist from CONTENT_SYSTEM.md Section 6. Every box must tick. Document failures in the draft's header comment and fix before continuing.
Step 9 — Convert to MDX
Move from content/drafts/<slug>.md to content/blog/<slug>.mdx. Apply the conversion rules below.
MDX frontmatter (at top of file, between --- fences):
---
title: "<title>"
slug: "<slug>"
description: "<meta description 150–160 chars>"
date: "YYYY-MM-DD"
author: "Samuel Roa"
authorBio: "Founder of TrueAdvertize. Former data scientist, 3 years building custom GTM systems for B2B SaaS founders with 50–300 customers."
authorImage: "/samuel.jpg"
primaryKeyword: "<primary keyword>"
secondaryKeywords: ["<kw1>", "<kw2>", "<kw3>"]
readTime: "<X> min read"
ogImage: "/blog/og/<slug>.png"
---
JSON-LD schema (inject via the Article page component, not in the MDX itself — see lib/schema.ts).
Body conversion:
- Keep markdown headers (
##,###) — MDX renders them - Convert tables to markdown tables — MDX renders them
- Use
<Callout>component for TL;DR box and Key Takeaways (component to be defined inlib/blog-components.tsx) - Use
<FAQ>component for the FAQ section so it can be auto-extracted into FAQPage schema - Internal links →
<Link href="/blog/<slug>">or<Link href="/<page>">
Step 10 — Open the PR
git checkout -b post/<slug>
git add content/blog/<slug>.mdx content/research/<slug>.md
git commit -m "post: <title>"
git push -u origin post/<slug>
gh pr create --title "post: <title>" --body "$(cat <<EOF
## Summary
New blog article: <title> (~<word count> words)
## Preview URL
Vercel will post it below.
## Calendar position
Week N — see CONTENT_SYSTEM.md Section 8
## Quality checklist
- [ ] Structure passes (Section 6 — Structure)
- [ ] SEO passes (Section 6 — SEO)
- [ ] GEO passes (Section 6 — GEO)
- [ ] Voice passes (Section 6 — Voice)
- [ ] Honesty passes (Section 6 — Honesty / brand)
- [ ] Technical passes (Section 6 — Technical)
## Sam's review
Open the preview, read on desktop + mobile, leave PR comments. Approve to ship.
🤖 Generated with Claude Code via trueadvertize-seo-geo skill
EOF
)"
Sam reviews on the preview URL. Approve → merge → live at trueadvertize.com/blog/
Step 11 — Submit to indexers (manual, ~5 min)
After merge:
- Google Search Console → URL inspection → Request indexing
- Optionally: tweet from Sam's X (@SaamCrdens) with the article link
Output structure summary
content/
├── research/<slug>.md ← Step 4 (Serper data + competitor analysis)
├── outlines/<slug>.md ← Step 5
├── drafts/<slug>.md ← Step 6 (markdown working file)
└── blog/<slug>.mdx ← Step 9 (published source — committed)
Composition
- Pre-req:
trueadvertize-context/icp.jsonv1.0 +brand-voice.jsonv1.0; Serper API key in.env.local;/blogroute + MDX rendering live in the Next.js app - Sibling skills:
trueadvertize-master-copy(other copy types),trueadvertize-reddit-post(Reddit distribution),de-ai-content(AI pattern stripping — apply automatically),fresh-reviewer(final draft review for cornerstone articles) - Validators: quality checklist from
CONTENT_SYSTEM.mdSection 6;screenshot-verifyon the preview URL
Anti-patterns
- Don't skip Step 1. Stale icp.json or brand-voice.json produces subtly off-brand articles. If they're not at v1.0 AUTHORITATIVE, STOP.
- Don't invent client names or fake case studies. Only Dave Menjura + Collin Stewart are real, attributable testimonials.
- Don't claim methodology numbers as past client results. Frame as targets / benchmarks unless Sam confirms attribution.
- Don't write under 3,500 words. AI tools deprioritize thin content. Below 3,500 reads as low-effort to both Google and LLM crawlers.
- Don't skip TL;DR box. This is the single highest-leverage GEO element. Front-loaded answer = AI extraction target.
- Don't write em dashes (—). Use commas, periods, colons, middle dots (·).
- Don't write Hormozi patterns. "It's not X, it's Y" and "Not A. Not B. Not C. But D." flag as AI-generated.
- Don't accept a draft that fails the
dont_sayscan. Loop the scan until clean. Don't ship with consultant-speak. - Don't auto-publish without Sam's review. Per CONTENT_SYSTEM.md, every article opens as a PR. Sam approves before merge.
- Don't write for keywords TA can't authentically defend. If Sam couldn't take a 30-min call with a founder on this exact topic, drop it.
Source
CONTENT_SYSTEM.mdSection 4 (Content Production Workflow), Section 6 (Quality Checklist)- OneAway SEO/GEO skill methodology (oneaway.io/skills/seo-geo) — extracted 2026-05-13
trueadvertize-context/icp.json+brand-voice.jsonv1.0 — Samuel interview merged 2026-05-11- Serper API docs — serper.dev