AI Agent Auto-Blog

Let Claude Code or any compatible AI agent research, write, and publish SEO-optimised blog posts to your CMS — fully automatically, no browser required.

Quick Start

The skill file lives at skills/seo-expert.md in this repository. Load it in Claude Code with:

/seo-expert keyword="best headless CMS 2025" siteSlug=my-site

Required Variables

Set these in your agent environment before invoking the skill.

Variable
Description
Example
CMS_BASE_URLYour deployed CMS domainhttps://cms.example.com
SUPABASE_URLSupabase project URLhttps://xxx.supabase.co
API_KEYCMS API key (sk_xxx)sk_abc123xyz
PEXELS_API_KEYFree Pexels image keyyour_pexels_key
siteSlugTarget site slug in CMSmy-blog

Get a free Pexels API key at pexels.com/api. Generate a CMS API key in Settings → API Keys.

4-Phase Workflow

1

Keyword Research

The agent web-searches the target keyword, extracts titles and H2/H3 headings from the top 3 organic results, and scrapes People Also Ask questions for the FAQ section.

2

Media (Pexels)

Fetches a royalty-free landscape photo from Pexels using a 2-4 word query derived from the keyword. Extracts imageUrl and an imageAlt credit string.

3

Outline → Draft

Presents the outline for your approval before writing. After approval, writes 1 500 words in Markdown with internal links and a PAA-based FAQ. No content is generated without your sign-off.

4

Publish

POSTs the article to the agent-publish Edge Function as a draft (published: false). Returns an editUrl so you can review and publish from the CMS dashboard.

Deploy the Edge Functions

The skill relies on three Supabase Edge Functions. Deploy them once with the Supabase CLI:

# Publish endpoint — custom sk_ auth, skip JWT verification
supabase functions deploy agent-publish --no-verify-jwt

# Read endpoints
supabase functions deploy posts-api --no-verify-jwt
supabase functions deploy categories-api --no-verify-jwt

# Inject the CMS URL (used to build editUrl / upgradeUrl)
supabase secrets set NEXT_PUBLIC_SITE_URL=https://cms.example.com

API Reference

GET/api/agent/posts?siteSlug={siteSlug}

Lists up to 50 posts for a given site. Used by the agent to pick internal link candidates. Auth: Authorization: Bearer sk_xxx

curl -H "Authorization: Bearer sk_xxx" \
  "https://cms.example.com/api/agent/posts?siteSlug=my-site"

# Response
{ "posts": [ { "id": "...", "title": "...", "slug": "..." } ] }
GET/functions/v1/categories-api?site={siteSlug}

Returns all categories for a site including post count. Auth: apikey: sk_xxx

curl -H "apikey: sk_xxx" \
  "https://PROJECT.supabase.co/functions/v1/categories-api?site=my-site"

# Response
{ "data": [ { "id": "...", "name": "Tech", "slug": "tech", ... } ] }
POST/functions/v1/agent-publish

Creates a post (draft by default). Automatically resolves category and slug conflicts. Auth: Authorization: Bearer sk_xxx

curl -X POST "https://PROJECT.supabase.co/functions/v1/agent-publish" \
  -H "Authorization: Bearer sk_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "siteSlug": "my-site",
    "title": "Best Headless CMS 2025",
    "slug": "best-headless-cms-2025",
    "content": "# Best Headless CMS 2025\n\nYour markdown body...",
    "categoryName": "Technology",
    "metaTitle": "Best Headless CMS 2025 – Top Picks",
    "metaDesc": "Compare the top headless CMS platforms of 2025.",
    "imageUrl": "https://images.pexels.com/photos/...",
    "imageAlt": "Photo by Jane Doe on Pexels",
    "published": false
  }'

# 201 Response
{
  "id": "...",
  "slug": "best-headless-cms-2025",
  "editUrl": "https://cms.example.com/cms/posts/...",
  "message": "Post created successfully"
}
HTTP
Meaning
Action
201Post saved as draftOpen editUrl to review & publish
400Missing required fieldsCheck title, slug, content
401Invalid API keyRegenerate key in Settings
403No site access or FREE plan limitCheck membership or upgrade plan
404Site not foundVerify siteSlug is correct

FREE Plan Limit

FREE plan accounts are capped at 10 posts per author. When the limit is reached, the publish endpoint returns 403 with an upgradeUrl field. Upgrade your plan to remove this restriction.

Slug conflicts are resolved automatically by the server — if my-post already exists, the post is saved as my-post-2. The final slug is returned in the 201 response.

Ready to automate your content pipeline?

Generate an API key, deploy the Edge Functions, and let your AI agent handle the rest.

AI Agent Auto-Blog Skill — Automated SEO Publishing | Supabase CMS | Supabase CMS