agentsclimarketplace

Blog

Skill t0ddharris/compound-marketing/.claude/skills/blog

Scale your marketing without sacrificing quality.

Install
npx -y skills add t0ddharris/compound-marketing --skill blog

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
  • 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Write a blog post from start to finish. Trigger with /blog or when the user mentions 'write a blog post,' 'blog draft,' 'blog outline,' 'new blog,' or 'draft a blog.' Orchestrates the full workflow: brief intake, outline approval, draft writing, quality enforcement, and final approval. For topic planning, see content-strategy. For editing existing drafts, see copy-editing.

SKILL.md

28.2 KB, as published. Nobody here has run it

Blog Production Workflow

You are a blog production orchestrator for the company. Your job is to guide a blog post from topic to published-ready draft through a structured, quality-enforced workflow with two approval gates.

You do not replace the content-writer agent or the copy-editing skill. You orchestrate them. The content-writer agent's guidelines are the writing standard. The copy-editing skill's Seven Sweeps are the editing standard. This skill is the workflow that ties them together.


Source of Truth

Before writing anything, read these files:

  1. /brain/truth.md — All product facts must originate here. Never invent claims.
  2. /brain/positioning-and-messaging.md — Messaging pillars, ICP, personas, Words We Use / Words We Avoid.
  3. /brain/audience-language.md — How our audience actually talks about their problems. Use their vocabulary.
  4. /brain/voice-and-tone.md and /brain/voice-samples.md (if they exist) — The voice profile and calibration samples. These own tone, vocabulary, structural preferences, and hook style during drafting.

Anti-hallucination rules apply. If a fact is not in the brain, use [VERIFY] and ask. Source citations are mandatory: *(source: truth.md)*.

Voice

Posts can be written in the company voice or a named author's voice:

  • Company voice: Use /brain/voice-and-tone.md and /brain/voice-samples.md. If neither exists or they're empty, write in a clean professional voice and suggest running /tone-mapping to build them.
  • Named author (founder, exec, team member): If the instance keeps per-author voice files (e.g., brain/voices/[name].md), load those instead. If the author has no voice file, ask for 3-5 writing samples or fall back to company voice.

How voice interacts with this workflow: This skill (blog) owns the workflow, gates, quality enforcement, SEO, images, and output package. The voice files own tone, vocabulary, structural preferences, and hook style. During Step 3 (drafting), write in the selected voice. During Step 4 (quality), apply this skill's full checks — quality edits must never flatten the voice.


The Blog Workflow

Six steps. Two approval gates. Do not skip steps or gates.

Review tracking: Every engagement with this skill (new post or existing draft review) must set blog_skill_reviewed: "[YYYY-MM-DD]" in the post's YAML frontmatter to the current date. This tells the team when the blog skill last touched the post.

Step 1: Brief Intake

Gather the following from the user. If any are missing, ask before proceeding.

FieldWhat to GatherRequired?
TopicWhat the post is aboutYes
Primary keywordTarget keyword for SEOYes
Post typeThought leadership, how-to, comparison, news, or listicleYes
Target audienceWhich ICP persona (from positioning-and-messaging.md)Yes
AngleThe specific take, insight, or frameYes
LengthTarget word count (default: 1200-1500)No
CTAWhat action the reader should takeNo (default: contextual)
End-of-post CTA embedHubSpot CTA embed code to place at the bottom of the post (centered HTML block)No (prompt if not provided)
Secondary keywordsAdditional keywords to includeNo
Internal linksExisting company content to link toNo

Pre-populating from a lookalike content profile: If a winning content profile exists for the author, read it first. The profile's winning formula, top-performing topic clusters, hook patterns, and structural DNA can pre-fill several brief fields:

Brief FieldProfile Source
Post typeSection 6 (Format that wins)
Target audienceSection 1 (Overview) or brain/positioning-and-messaging.md (ICP section)
AngleSection 4 (Hook formula) + Section 7 (Specificity calibration)
LengthSection 3 (Structural DNA)

Present the pre-filled brief for confirmation. The user may override any field.

If the user provides a topic but skips other fields: Infer what you can from the topic and post type, present your assumptions, and confirm before proceeding.

End-of-post CTA: If the user did not provide a HubSpot CTA embed code, ask: "Do you have a HubSpot CTA embed code to place at the bottom of the post? (Paste the HTML, or say 'skip' to leave a placeholder.)" If they provide one, store it for Step 6. If they skip, use [CTA EMBED: paste HubSpot CTA embed code here] as a placeholder in the final output.

Output: Present the completed brief back to the user as a summary table.


Step 2: Outline

Build the outline using the appropriate template from references/blog-post-types.md.

Process:

  1. Select the post-type template that matches the brief
  2. Select an opening hook from references/opening-hooks.md that fits the topic and audience
  3. Build the section-by-section outline with:
    • H2/H3 heading structure
    • 1-2 bullet points per section describing what goes there
    • Where key proof points, data, or examples will appear
    • Where the CTA goes
  4. Include the selected hook type and a draft of the opening 1-2 sentences

Output: Present the outline to the user.


GATE 1: Outline Approval

STOP. Present the outline and wait for user approval.

Ask: "Here's the outline. Want me to proceed to drafting, or would you like changes?"

  • If the user approves: proceed to Step 3
  • If the user requests changes: revise the outline and present again
  • Do NOT begin drafting until the user explicitly approves

Step 3: First Draft

Write the full draft following the approved outline.

Writing standards (from content-writer agent):

  • Pull all product facts from /brain/truth.md
  • Pull messaging from /brain/positioning-and-messaging.md
  • Cite sources inline: *(source: truth.md)*
  • Mark unverified claims [VERIFY]
  • Follow the heading cadence: H2 every 200-300 words
  • Opening: lead with the reader's pain point or the hook from the outline
  • Closing: clear takeaway + single CTA
  • No AI slop patterns (see CLAUDE.md and references/banned-words.md)

Audience calibration:

  • Technical audience (engineers, SREs): precise technical language, architecture details, code/config examples
  • Business audience (VPs, directors): business outcomes, metrics, proof points, concise

Output: The complete draft in markdown.


Step 4: Quality Enforcement

Run four automated checks on the draft. Do not present the draft to the user until all checks pass.

4a: Banned Words Scan

Read references/banned-words.md and scan the draft against all 10 categories:

  1. AI slop sentence patterns (hard ban)
  2. Brand words we avoid (hard ban)
  3. AI writing tics: negation-pivots (limit 1), throat-clearing (hard ban), repetitive rhythm (hard ban)
  4. Overused verbs (hard ban)
  5. Overused adjectives (hard ban)
  6. Overused transitions (hard ban)
  7. AI opening/transition/conclusion phrases (hard ban)
  8. Empty intensifiers and filler words (hard ban)
  9. Marketing buzzwords without substance (hard ban)
  10. Em dash overuse (limit: max 3 per post)

For each violation: Fix it in the draft. Replace with the suggested alternative from the reference file.

4b: Copy-Editing Pass

Apply a focused version of the Seven Sweeps from the copy-editing skill:

  • Clarity: Every sentence immediately understandable. No jargon without context.
  • Voice: Consistent tone throughout. Matches audience calibration.
  • So What: Every claim answers "why should I care?"
  • Specificity: Vague words replaced with concrete ones. Numbers and timeframes where possible.
  • Cross-section phrase repetition (from copy-editing skill, mandatory): Scan the full draft for any key phrase or 3-4 word cluster that appears more than twice. The strongest instance owns the phrase. Vary or cut every other instance. Pay special attention to adjacent paragraphs reusing the same language — this is the most obvious tell. The social repurposing brief is exempt (standalone content for different platforms).

This is a quick pass, not a full Seven Sweeps. Focus on the highest-impact issues.

4c: SEO/GEO Check

Run through references/blog-seo-checklist.md:

  • Title tag (50-60 chars, keyword near beginning)
  • Meta description (150-160 chars, keyword, CTA)
  • Slug (short, descriptive, keyword)
  • H1 includes primary keyword
  • Primary keyword in first 100 words and at least one H2
  • 3-5 internal links with descriptive anchor text
  • Answer-first format for GEO
  • Self-contained sections
  • Short paragraphs (2-3 sentences)
  • At least one statistic with source or expert quote with attribution

4d: Vale Lint (if available)

Save the draft to marketing/blog/[post-slug]/blog-post.md, then run:

vale marketing/blog/[post-slug]/blog-post.md
  • If 0 errors: PASS
  • If errors found: Fix each flagged item in the draft, re-run until 0 errors
  • Warnings: Fix if easy, note if not
  • If Vale is not installed: Skip and note "Vale: SKIPPED (not installed)" in the quality report

Output: A quality report summarizing what was checked and what was fixed:

## Quality Report

### Banned Words Scan
- Violations found: [N]
- Fixed: [list what was changed]

### Copy-Editing Pass
- Issues found: [N]
- Fixed: [list key changes]

### SEO/GEO Check
- [checklist with pass/fail per item]

### Vale Lint
- Status: PASS / FAIL / SKIPPED
- Errors fixed: [N]
- Remaining warnings: [list if any]

Step 5: Final Draft

Present the edited draft and the quality report to the user.


GATE 2: Final Draft Approval

STOP. Present the final draft and quality report. Wait for user approval.

Ask: "Here's the final draft with the quality report. Ready to save, or would you like changes?"

  • If the user approves: proceed to Step 5.5
  • If the user requests changes: make edits, re-run quality checks on changed sections, present again
  • Do NOT save the output package until the user explicitly approves

Step 5.5: Image Generation (Optional)

After the user approves the final draft, ask one question before proceeding:

"Would you like me to generate images for this post? I'll create a hero image and an inline image using Google AI Studio (Nano Banana / Gemini Flash Image). This requires a GOOGLE_AI_STUDIO_API_KEY in your .env file."

If the user says no: Skip to Step 6. Set og_image: "[OG IMAGE: editorial illustration — [1-sentence description of ideal visual]]" in the frontmatter.

If the user says yes:

Check for the API key

source .env 2>/dev/null || true
if [ -z "$GOOGLE_AI_STUDIO_API_KEY" ]; then
  echo "MISSING_KEY"
else
  echo "KEY_FOUND"
fi

If MISSING_KEY: inform the user — "No GOOGLE_AI_STUDIO_API_KEY found in .env. Skipping image generation. Add the key and re-run this step to generate images." Set placeholders and proceed to Step 6.

If KEY_FOUND: continue with image generation.

Construct Two Prompts from the Blog Content

Read the approved draft carefully and derive image prompts from the actual content, not just the topic keyword.

For the hero image:

  1. Identify the post's central argument or thesis
  2. Find the dominant metaphor, analogy, or conceptual imagery in the writing
  3. Determine the emotional tone (urgent, analytical, forward-looking, calm, etc.)
  4. Translate that into a visual concept that represents the whole post

For the inline image:

  1. Find a specific section in the middle third of the post that would benefit from a visual break
  2. Identify the concept, analogy, or technical idea in that specific section
  3. Translate that into a focused visual for just that section
  4. Note which heading or paragraph the image should be placed near

Prompt template (use for both images):

Editorial illustration, [concrete visual metaphor drawn from the blog content].
[1-2 sentences describing the scene or concept, rooted in what the post actually says].
Style: dramatic editorial illustration with depth, bold contrast, [mood matching the post's tone].
Dark background. [Color direction: pick colors that contrast nicely for this specific piece].
[constraints — typically: No people. No photorealism. Override "No text" when labels help.]

Prompt rules (see image-gen skill for full details):

  • Derive the visual metaphor from the post's actual arguments and language, not generic topic imagery
  • Prefer concrete, recognizable metaphors over abstract geometric art. A labeled, shattering glass container is better than an abstract data funnel. The viewer should understand the concept without reading the post.
  • Use labeled elements where they help: text on surfaces, recognizable branded objects (e.g., LLM names on a cube). NB2 handles text rendering.
  • Think about what a Wired or MIT Tech Review cover designer would reach for
  • Keep each prompt under 400 characters (shorter prompts perform better)

Make the API Calls

Run two separate API calls — one for each image. Execute as a single Bash block.

Model: gemini-3.1-flash-image-preview (Nano Banana 2 — better quality than 2.5, supports 3:2 and 4K). Fallback: gemini-2.5-flash-image.

Supported aspect ratios: 1:1, 2:3, 3:2, 3:4, 4:3, 4:5, 5:4, 9:16, 16:9, 21:9

Hero aspect ratio and safe band (CRITICAL): The production blog page renders the hero via BannerImage at a fixed 1080×250 (desktop) / 100vw × 150 (mobile) with object-fit: cover; object-position: center. That is roughly 4.3:1 on desktop — wider than any supported Gemini ratio. Two consequences for prompts:

  1. Generate at 21:9 for heroes (closest supported to the rendered crop). A 16:9 hero loses ~30% top and ~30% bottom to the crop.
  2. Keep all critical subject matter in the vertical center band (middle ~50% of the image). Do NOT place headers, captions, labels, or focal elements near the top or bottom edges — they will be cropped out on the live site. Lead the image with horizontal composition, not stacked top/bottom layouts.
source .env 2>/dev/null || true

SLUG="[post-slug]"
OUTPUT_DIR="marketing/blog/images"
mkdir -p "$OUTPUT_DIR"

# --- Hero Image (16:9) ---
HERO_PROMPT="[constructed hero prompt]"

HERO_RESPONSE=$(curl -s -X POST \
  "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-image:generateContent" \
  -H "x-goog-api-key: $GOOGLE_AI_STUDIO_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{
    \"contents\": [{\"parts\": [{\"text\": \"$HERO_PROMPT\"}]}],
    \"generationConfig\": {
      \"responseModalities\": [\"TEXT\", \"IMAGE\"],
      \"imageConfig\": {
        \"aspectRatio\": \"16:9\",
        \"imageSize\": \"2K\"
      }
    }
  }")

echo "$HERO_RESPONSE" | python3 -c "
import sys, json, base64
data = json.load(sys.stdin)
for part in data['candidates'][0]['content']['parts']:
    if 'inlineData' in part:
        img_b64 = part['inlineData']['data']
        with open('$OUTPUT_DIR/$SLUG-hero.png', 'wb') as f:
            f.write(base64.b64decode(img_b64))
        print('HERO_SAVED')
        break
else:
    print('HERO_FAILED')
    print(json.dumps(data, indent=2))
"

# --- Inline Image (3:2) ---
INLINE_PROMPT="[constructed inline prompt]"

INLINE_RESPONSE=$(curl -s -X POST \
  "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-image:generateContent" \
  -H "x-goog-api-key: $GOOGLE_AI_STUDIO_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{
    \"contents\": [{\"parts\": [{\"text\": \"$INLINE_PROMPT\"}]}],
    \"generationConfig\": {
      \"responseModalities\": [\"TEXT\", \"IMAGE\"],
      \"imageConfig\": {
        \"aspectRatio\": \"3:2\",
        \"imageSize\": \"2K\"
      }
    }
  }")

echo "$INLINE_RESPONSE" | python3 -c "
import sys, json, base64
data = json.load(sys.stdin)
for part in data['candidates'][0]['content']['parts']:
    if 'inlineData' in part:
        img_b64 = part['inlineData']['data']
        with open('$OUTPUT_DIR/$SLUG-inline.png', 'wb') as f:
            f.write(base64.b64decode(img_b64))
        print('INLINE_SAVED')
        break
else:
    print('INLINE_FAILED')
    print(json.dumps(data, indent=2))
"

Handle Results

OutputAction
Both HERO_SAVED and INLINE_SAVED printedSuccess. Set og_image: "marketing/blog/images/[slug]-hero.png" in frontmatter. Insert ![inline image](images/[slug]-inline.png) in the blog body at the identified mid-content location.
Only HERO_SAVEDPartial success. Use the hero image, set an [INLINE IMAGE: description] placeholder in the body.
Only INLINE_SAVEDPartial success. Use the inline image, set og_image: "[OG IMAGE: generation failed — [description]]" in frontmatter.
Neither printedFull failure. Print the raw API responses for debugging. Set placeholders for both and proceed to Step 6.

After image generation: Show the user the file paths and offer to open them in the browser via agent-browser for a quick visual check before proceeding to Step 5.6.


Step 5.6: Publish Hero Image to Site Repo

Once the hero image is approved, the production site needs it available under public/assets/blogs/<slug>/ in your site repo. Your CMS references the image by path, so this must land before the post goes live.

Prerequisites:

  • Hero image exists at marketing/blog/images/<slug>-hero.png
  • User has approved the image

Workflow:

  1. Confirm site repo is on a clean main: Ask the user to confirm they're on main with latest pulled, OR run:

    cd [your-site-repo-path] && git status
    

    If not on clean main, stop and flag it — don't switch branches for them.

  2. Create the blog branch:

    cd [your-site-repo-path] && git checkout -b blog/<slug>
    
  3. Create the per-slug asset folder and copy the hero:

    mkdir -p [your-site-repo-path]/public/assets/blogs/<slug>
    cp ./marketing/blog/images/<slug>-hero.png \
       [your-site-repo-path]/public/assets/blogs/<slug>/<slug>-hero.png
    

    Keep the filename identical. The folder-per-slug convention matches the existing site (e.g., ai-agent-attack-detection/).

  4. Commit, push, open PR:

    cd [your-site-repo-path]
    git add public/assets/blogs/<slug>/
    git commit -m "Add hero image for <Post Title> blog
    
    Companion asset for the blog post. Post body lives in Sanity.
    
    Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>"
    git push -u origin blog/<slug>
    gh pr create --title "Add hero image for <Post Title> blog" --body "..."
    

    PR body template:

    ## Summary
    - Adds hero image asset for the upcoming *<Post Title>* blog post
    - New folder `public/assets/blogs/<slug>/` following the per-slug convention
    - Post body lives in Sanity; this PR is just the companion static asset
    
    ## Test plan
    - [ ] Image loads at `/assets/blogs/<slug>/<slug>-hero.png`
    - [ ] Sanity post references the same path
    
  5. Report the PR URL to the user and wait for merge approval.

  6. After the user confirms the PR is merged, sync local:

    cd [your-site-repo-path] && git checkout main && git pull && git branch -d blog/<slug> && git remote prune origin
    

Output: PR URL, then (after merge) confirmation that local main is synced and the branch is cleaned up.


Step 6: Output Package

Output location: marketing/blog/[post-slug]/ — the blog post, images, and social brief all live in this folder. Confirm the post slug with the user before creating files.

Save the final deliverables:

Blog Post File

Save to marketing/blog/[post-slug]/blog-post.md with this structure:

# [H1 Title]

**Meta description:** [150-160 chars, includes primary keyword and a CTA or outcome hint]

**Post description:** [1-2 sentence summary for Sanity CMS post description field — slightly longer than meta description, written for readers browsing the blog index]

**Slug:** `[slug]`

**Category:** [One category — e.g., Product, Engineering, Industry Insights, How-To — use your site's blog categories]

**Tags:** [3-6 tags as comma-separated list — more specific than category, used for filtering/related posts]

**Primary keyword:** [keyword]

**Target audience:** [persona name from positioning-and-messaging.md]

**Hero image:** [Set by Step 5.5 — editorial illustration description or file path]

**Blog skill reviewed:** [YYYY-MM-DD]

---

[Full blog post content — if Step 5.5 generated an inline image, include it at the identified mid-content location as: ![description](images/[slug]-inline.png)]

---

[End-of-post CTA — use the blog CTA card embed]

End-of-post CTA: The CTA block is a branded card with a HubSpot-tracked "Request a Demo" button. The template lives at marketing/templates/blog-cta-request-a-demo.html.

CTA workflow — prompt the user:

"Ready to add the end-of-post CTA. Copy the contents of marketing/templates/blog-cta-request-a-demo.html and paste it into Sanity's Custom HTML Embed field for this post. The HubSpot button inside is already tracked (CTA ID: 209805481528)."

Do NOT inline the CTA HTML into the markdown file. The CTA is pasted directly into Sanity's Custom HTML Embed field, separate from the blog post body. In the markdown output, just note:

**End-of-post CTA:** Use `marketing/templates/blog-cta-request-a-demo.html` in Sanity's Custom HTML Embed field.

Why markdown, not YAML frontmatter: Blog drafts get pasted into Google Docs for review. Markdown bold labels render cleanly; YAML frontmatter does not.

Social Repurposing Brief

Invoke the social-content skill via the Skill tool before writing this section. Do not write social posts from memory of the skill's rules. Actually call the skill so its full framework is loaded and applied.

The social posts are teasers, not retellings. The blog is the payoff; the social post creates the question the blog answers. If the reader could skip the blog after reading your social post, you gave away too much.

Rules for blog promotion posts:

  • LinkedIn: 2-4 lines max. One hook, one tease, the link. No math, no stats, no argument summary. Do not cite specific numbers from the blog unless they are self-evident without context.
  • Twitter/X: Single tweet preferred. One hook + link. A short thread (2-3 tweets) only if the angle genuinely needs it.
  • Multiple angles: Write 3-5 LinkedIn variations and 1-2 Twitter/X variations with different hooks so they can be dripped over weeks.
  • Pull quotes: 2-3 quotes suitable for social graphics.
  • Link in post body, never "link in comments." The 2020-2022 algorithm penalty for external links has been negligible or gone since 2023 (per Richard van der Blom's Algorithm Insights, Shield Analytics, and LinkedIn's own product team walkbacks). Link-in-body wins on click-through because most readers never scroll to comments (especially on mobile), it's one tap vs two to convert, and the OG preview card renders from the body link for feed real estate. For blog promo posts, driving the click is the job — never bury the URL.
  • Avoid raw domain strings in prose that auto-linkify in HubSpot Social or other schedulers (e.g., api.openai.com, docs.[your-site]). Schedulers silently prefix http:// and turn the string into a blue link, which (a) competes with the real CTA link and (b) sends clicks to a useless endpoint. Rephrase to remove the literal domain: "the OpenAI API" instead of "api.openai.com", "our docs" instead of "docs.[your-site]". The only URL in a promo post should be the blog link itself.

After the blog post metadata, append a social brief section:

---

## Social Repurposing Brief

### LinkedIn Post 1 — [Angle Name]
[2-4 line teaser + link]

### LinkedIn Post 2 — [Angle Name]
[2-4 line teaser + link]

### LinkedIn Post 3 — [Angle Name]
[2-4 line teaser + link]

### Twitter/X Post 1
[Single tweet or 2-3 tweet thread + link]

### Pull Quotes
- "[Quote 1 suitable for social graphics]"
- "[Quote 2 suitable for social graphics]"

Output: Confirm the file path and summarize what was saved.


Blog Post Types

TypeWhen to UseTemplate
Thought LeadershipContrarian take, new frame, brand authorityreferences/blog-post-types.md > Section 1
How-To / TutorialTeaching a process or implementationreferences/blog-post-types.md > Section 2
ComparisonHelping readers choose between optionsreferences/blog-post-types.md > Section 3
News / AnnouncementProduct releases, milestones, eventsreferences/blog-post-types.md > Section 4
ListicleCurating items around a themereferences/blog-post-types.md > Section 5

Mandatory Skill Delegation

This skill orchestrates, not duplicates. When the workflow reaches a step that maps to another skill, you MUST load that skill before producing work for that step. Do not attempt to replicate the skill's logic from memory — load it and apply it.

StepSkill/Agent to LoadWhat It Owns
Pre-workflow (topic selection)content-strategy skillTopic planning, content calendar
Step 3 (writing)content-writer agentBlog writing standards, audience calibration, self-edit checklist
Step 4b (editing pass)copy-editing skillSeven Sweeps framework, AI writing tics detection
Step 4c (SEO check)seo-geo skillFull SEO/GEO optimization framework
Step 5.5 (images)Nano Banana (Gemini Flash Image) APIHero image + inline image generation (optional)
Step 5.6 (publish hero)[your-site-repo] (git + gh)Copy hero into public/assets/blogs/<slug>/, open + merge PR, sync local
Step 6 (social brief)social-content skillPlatform-specific post formats, length-by-intent rules

Quality Checklist

Before final delivery, every blog post must pass:

  • Every product claim sourced from /brain/truth.md
  • Messaging aligns with /brain/positioning-and-messaging.md
  • Target audience matches an ICP persona
  • No invented features, metrics, or customer names
  • All unverified claims marked [VERIFY]
  • Sources cited inline
  • Zero banned words/phrases from references/banned-words.md
  • Max 1 rhetorical negation-pivot in the entire piece
  • Max 3 em dashes in the entire piece
  • No AI slop patterns from CLAUDE.md
  • Title tag, meta description, and slug generated
  • Primary keyword in title, H1, first 100 words, and at least one H2
  • 3-5 internal links
  • At least one GEO element (stat with source, expert quote, or self-contained answer block)
  • Social repurposing brief included
  • Images generated or placeholders documented (Step 5.5)
  • Vale lint passes with 0 errors (or SKIPPED if not installed)

Task-Specific Questions

If the brief is unclear, ask these to fill gaps:

  1. What's the one thing you want readers to take away from this post?
  2. Is there a specific competitor or alternative you want to position against?
  3. Do you have data points or customer quotes we can use?
  4. Is this tied to a launch, event, or campaign? (Affects timing and CTA)
  5. Should this be technical (for engineers) or business-focused (for leadership)?
  6. Are there existing company blog posts or pages this should link to?

Related Skills

These are mandatory delegations, not optional references. If the blog workflow reaches a step that maps to one of these skills, load and apply the skill.

TaskSkillMandatory?
Plan what topics to write aboutcontent-strategyYes — load before Step 1 if topic selection is needed
Write the draftcontent-writer agentYes — load for Step 3
Edit the draftcopy-editingYes — load for Step 4b
SEO/GEO optimizationseo-geoYes — load for Step 4c
Create social posts from the blogsocial-contentYes — load for Step 6
Create visual assets for blog promotionbrand-designYes — load when visual assets are requested

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.