Skill v1.0.1
currentAutomated scan100/100+3 new
version: "1.0.1" name: kai-ad-campaign description: Plan, evaluate, and produce paid ad campaigns across platforms (Meta, Google, LinkedIn, TikTok, Microsoft, Pinterest, Snapchat, Amazon, X). Evaluate existing ads, map funnel stages (TOF/MOF/BOF), produce ad variants per platform with policy compliance, output ready-to-upload copy. Use when "ad campaign", "create ads", "run ads for", "paid campaign", "media plan", "launch ads", "Meta campaign", "Google Ads campaign", "multi-platform ads", "evaluate my ads", "how are my ads doing", "audit my ads", "ad performance", "analyze ads", or any request to evaluate existing or create new advertising.
Plan, evaluate, and batch-produce ad campaigns across platforms and funnel stages. Every ad passes platform policy compliance + quality gates.
Mode Detection
Before loading product context, determine the mode:
- Evaluation mode — user says "evaluate", "analyze", "audit", "how are my ads doing", "ad performance", "review my ads"
- Creation mode — user says "create", "launch", "build", "new campaign", "run ads"
- Evaluate + Create — user wants both (evaluation first, then create/fix based on findings)
Evaluation mode does NOT require MARKETING.md. Creation mode does.
Phase E: Ad Evaluation (Evaluation Mode Only)
Skip this phase entirely if the user only wants to create new ads.
Evaluation mode is read-only. Do not create, pause, activate, change bids, change budgets, upload assets, add keywords, or mutate targeting while evaluating performance.
E.1 Pull Active Campaigns
Load the Meta API reference: harness/references/meta-ads-api-reference.md
- Extract credentials from
.env.localusing grep (neversource):
``bash META_TOKEN=$(grep '^META_ACCESS_TOKEN=' .env.local | cut -d= -f2-) AD_ACCOUNT_ID=$(grep '^META_AD_ACCOUNT_ID=' .env.local | cut -d= -f2-) ``
- List all active campaigns with insights:
``bash curl "https://graph.facebook.com/v21.0/act_${AD_ACCOUNT_ID}/campaigns?fields=id,name,objective,status,daily_budget,insights.date_preset(last_30d){impressions,clicks,spend,ctr,cpc,actions,cost_per_action_type}&filtering=[{\"field\":\"effective_status\",\"operator\":\"IN\",\"value\":[\"ACTIVE\"]}]&limit=50&access_token=${META_TOKEN}" ``
- For each campaign, pull ad-level insights:
``bash curl "https://graph.facebook.com/v21.0/act_${AD_ACCOUNT_ID}/ads?fields=id,name,status,effective_status,campaign_id,creative{id,object_story_spec},insights.date_preset(last_30d){impressions,clicks,spend,ctr,cpc,actions,cost_per_action_type,video_p25_watched_actions,video_p50_watched_actions,video_p75_watched_actions,video_p100_watched_actions}&filtering=[{\"field\":\"effective_status\",\"operator\":\"IN\",\"value\":[\"ACTIVE\"]}]&limit=100&access_token=${META_TOKEN}" ``
E.2 Cross-Reference with PostHog
Load: harness/references/posthog-marketing-queries.md
Pull landing page data to cross-reference ad traffic with on-site behavior:
- Pageviews with UTM breakdown (query #2)
- Ad visitor journeys (query #5)
- Campaign attribution / conversions (query #8)
E.3 Score Each Ad
| Metric | Poor | OK | Good | Great | |
|---|---|---|---|---|---|
| CTR | < 0.5% | 0.5–1% | 1–2% | > 2% | |
| CPC | > $5 | $3–5 | $1.50–3 | < $1.50 | |
| CPL | > $50 | $30–50 | $15–30 | < $15 | |
| Video 25% retained | < 30% | 30–50% | 50–70% | > 70% | |
| Video 75% retained | < 5% | 5–10% | 10–20% | > 20% | |
| Landing page bounce | > 80% | 60–80% | 40–60% | < 40% |
Adjust benchmarks to the vertical (B2B SaaS, local service, ecommerce, etc.).
E.4 Generate Evaluation Report
Output to workspace/ads/_evaluation-report.md:
# Ad Evaluation Report — [Date]## Summary-Active campaigns: [N]-Active ads: [N]-Total 30-day spend: $[X]-Avg CTR: [X]% | Avg CPC: $[X] | Avg CPL: $[X]## Campaign Performance| Campaign | Objective | Spend | Impressions | Clicks | CTR | CPC | Leads | CPL ||----------|-----------|-------|-------------|--------|-----|-----|-------|-----|## Ad-Level Performance| Ad | Campaign | CTR | CPC | Spend | Leads | CPL | Verdict ||----|----------|-----|-----|-------|-------|-----|---------|## Recommendations### Keep (performing well)[List ads to keep running]### Optimize (underperforming but fixable)[List ads with specific fix recommendations — copy, creative, targeting]### Pause (not working)[List ads to turn off]### Create New[Gaps identified — missing funnel stages, untested hooks, audience segments]
E.5 Transition to Creation
If evaluation reveals gaps or the user wants new ads, transition to Phase 0 → Phase 1 below with the evaluation findings as context.
Phase 0: Load Product Context
Check if MARKETING.md exists in the project root (same directory as CLAUDE.md, README.md, package.json).
If it exists: Read it — skip product discovery questions. It has the product name, ICP, value prop, monetization, brand voice, current channels, and competitive landscape.
If it does NOT exist: Auto-explore the codebase to create it in the project root (next to CLAUDE.md). Do NOT ask the user what the product is. Read CLAUDE.md, README.md, PROJECT.md, package.json, landing pages, and any project files. Search for email/ad/analytics config. Then create MARKETING.md using the template from /kai-email-system. Present draft to user for confirmation.
Phase 1: Campaign Discovery
Read from MARKETING.md. Only ask about things not covered there:
- Platforms — which platforms? (Meta, Google, LinkedIn, TikTok, etc.)
- Budget range — affects platform mix and bid strategy recommendations
- Goal — leads, conversions, traffic, awareness, app installs?
- Landing page — where do ads send traffic?
- Existing assets — any images/video already available?
New Launch Add-On
If the campaign is for a new brand, new product, first paid test, or "launch ads" request, load:
knowledge/playbooks/paid-media-launch-playbook.md
Apply these launch defaults before writing ads:
- Use
Target CPA x 50as the minimum test budget. - Build the measurement checklist before campaign copy.
- Start Meta with one campaign per product plus simple retargeting.
- Start Google with branded search, non-branded search per product/problem, and shopping only when feed quality is ready.
- Avoid Performance Max until the account has baseline data.
- Produce
workspace/ads/_launch-brief.mdandworkspace/ads/_measurement-checklist.md.
Meta Creative Testing Add-On
If the platform is Meta and the request includes 10+ creatives, API creation, video batches, existing winners, low budgets, or a "best solution" question, load:
knowledge/playbooks/meta-creative-testing-decision-framework.md
Before recommending activation or creating live ads:
- Separate "create paused for review" from "activate for spend."
- Compare daily budget against target CPA and recent CPA.
- Protect existing winning ad sets unless the user explicitly wants a refresh test.
- Recommend a staged active subset when budget cannot fairly test the full batch.
- Produce
workspace/ads/_meta-creative-testing-decision.mdwhen writing workspace artifacts.
Creative Format Library Add-On
For paid-social, short-form video, or any request for ad concepts, creative formats, or variant tests, load:
kai/paid_media/creative_formats.py
Use select_creative_formats(...) to choose formats by:
- platform
- funnel stage
- available assets
- regulated-industry risk
Each variant must now choose both:
- a
hook_type - a concrete
creative_format
Example pairings:
problem_agitation+foundersocial_proof+testimonial_mashuppattern_interrupt+ugly_ad
If the selector returns NEEDS_ASSET or REVIEW, keep the format in the plan only when the missing asset or review step is stated explicitly.
Phase 2: Campaign Architecture
Generate workspace/ads/_campaign-map.md with:
Funnel Structure
| Stage | Objective | Audience | Platforms | Ad Count | |
|---|---|---|---|---|---|
| TOF (Awareness) | Reach/awareness | Cold — lookalikes, interest-based | Meta, TikTok, Google Display | 3 variants each | |
| MOF (Consideration) | Traffic/engagement | Warm — site visitors, engagers | Meta, Google Search, LinkedIn | 3 variants each | |
| BOF (Conversion) | Leads/sales | Hot — cart abandoners, demo requesters | Meta retarget, Google Search (brand), Email | 3 variants each |
Adapt to the actual product and platforms. Not every product needs every stage.
Per-Platform Ad Specs
Before writing any ad, load the platform's policy reference and skill contract. For Meta, also load the API reference for execution:
| Platform | Policy Reference | API/Execution Reference | Contract | Key Constraints | |
|---|---|---|---|---|---|
| Meta | harness/references/meta-ads-rules.md | harness/references/meta-ads-api-reference.md | harness/skill-contracts/meta-ads.yaml | Headline 27 chars, primary text 125 chars visible | |
harness/references/google-ads-policy-reference.md | — | harness/skill-contracts/google-ads.yaml | 15 headlines (30 chars), 4 descriptions (90 chars) | ||
harness/references/linkedin-ads-rules.md | — | — | Professional context, B2B claim substantiation | ||
| TikTok | harness/references/tiktok-ads-policy-reference.md | — | — | No political ads, AI disclosure required | |
| Microsoft | harness/references/microsoft-ads-rules.md | — | — | Similar to Google RSA format | |
harness/references/pinterest-ads-rules.md | — | — | All weight loss banned, strict body image | ||
| Snapchat | harness/references/snapchat-ads-policy-reference.md | — | — | Young audience protections | |
| Amazon | harness/references/amazon-ads-policy-reference.md | — | — | 18-month claim evidence rule | |
| X/Twitter | harness/references/x-ads-policy-reference.md | — | — | Verification tier affects access |
All paths relative to the project root.
Also load: harness/references/advertising-compliance.md for FTC/GDPR/CAN-SPAM requirements that apply to ALL platforms.
Also load: harness/references/ad-write-guardrails.md for any workflow that may upload assets, create ads, create campaigns/ad sets/ad groups, activate/pause entities, or change bids/budgets.
Approval Gate
Present the campaign map to the user before producing ads. Confirm:
- Platform selection
- Funnel stages
- Number of variants per stage
- Any compliance concerns (regulated industry?)
Phase 3: Batch Production
Produce ads by platform and funnel stage. For each ad:
Output Format
# [Platform] — [Funnel Stage] — Variant [A/B/C]**Platform:** Meta / Google / LinkedIn / etc.**Funnel stage:** TOF / MOF / BOF**Objective:** [campaign objective]**Audience:** [target description]## Ad Copy### Headlines[Per platform specs — e.g., 15 headlines for Google RSA, 1 for Meta]### Primary Text / Description[Per platform specs]### CTA[Button text or action]### Display URL / Path[If applicable]## Hook Type[pattern_interrupt | social_proof | pain_agitate | direct_offer | story]## Creative Format-Selected format: [format id + name]-Platform fit: PASS/FAIL-Funnel fit: PASS/FAIL-Asset feasibility: PASS/FAIL/NEEDS_ASSET-Compliance status: PASS/REVIEW-Missing assets: [list or none]-Compliance flags: [list or none]## Quality Gate Results-Four U's: [X]/16 (min 10)-Banned words: PASS/FAIL-Platform char limits: PASS/FAIL-Has number/stat: PASS/FAIL-Policy compliance: PASS/FAIL
Quality Gates (per ad)
- Four U's >= 10/16
- Zero banned words and zero AI slop
- Platform character limits respected (headlines, descriptions, primary text)
- Has specific number or stat anchoring the claim
- Platform policy compliance — no violations from the loaded policy reference
- No superlatives without proof (Google requirement, good practice everywhere)
- Single clear CTA per ad
Hook Variety
Across the 3 variants per stage, use different hook types:
- Variant A: Pain/agitate
- Variant B: Social proof or stat-led
- Variant C: Pattern interrupt or story
Across those variants, also rotate the concrete creative format. Do not count three ads with the same production format and different opening lines as full creative diversity.
Batch Output
workspace/ads/├── _campaign-map.md├── meta/│ ├── tof-variant-a.md│ ├── tof-variant-b.md│ ├── tof-variant-c.md│ ├── mof-variant-a.md│ └── bof-variant-a.md├── google/│ ├── search-rsa-branded.md│ ├── search-rsa-nonbranded.md│ └── pmax-assets.md├── linkedin/│ └── ...└── _quality-report.md
Phase 4: Quality Report
Generate workspace/ads/_quality-report.md:
# Ad Campaign Quality Report## Summary-Total ads: [N]-Platforms: [list]-Passed all gates: [N]-Policy flags: [N]## Per-Ad Results| Ad | Platform | Stage | Four U's | Char Limits | Policy | Status ||----|----------|-------|----------|-------------|--------|--------|## Policy Flags[Any ads that need legal review or have borderline claims]## A/B Test Recommendations[Which variants to test first based on hook type diversity]
Phase 5: API Execution (Optional — Meta)
If the user wants to create ads via API (not just produce copy), load harness/references/meta-ads-api-reference.md and follow this sequence:
Load harness/references/ad-write-guardrails.md before API execution. Default to read-only reports, dry-run previews, upload validation, and recommendations. Live write access is approval-gated and never auto-approved.
Launch Decision Gate
Before creating or activating Meta ads by API, load knowledge/playbooks/meta-creative-testing-decision-framework.md when any of these are true:
- 10 or more ads/creatives will be created.
- The ad set daily budget is below the recent or target CPA.
- Existing winners are already producing leads, purchases, or qualified calls.
- The user asks whether to push all, push a subset, pause all, or find the best launch structure.
For those cases, write or present a decision memo before execution. Default behavior for large batches is:
- Create all requested ads as
PAUSEDwhen staging is useful. - Activate only the recommended subset when budget is tight.
- Keep proven winner ad sets separate from exploratory batches.
- Strip organic-only captions, hashtags, and comment-keyword CTAs from paid copy.
Pre-Flight Checks
- Verify credentials: Extract all required env vars via
grepfrom.env.local - Verify video IDs: Before creating any video ad, query the video library first:
``bash curl "https://graph.facebook.com/v21.0/act_${AD_ACCOUNT_ID}/advideos?fields=id,title,created_time&limit=20&access_token=${META_TOKEN}" `` Never trust video IDs from logs or docs without verification — a single digit difference means a different (or nonexistent) video.
- Verify Instagram account ID: Pull from Page settings if not in
.env.local - Set all ads to PAUSED initially — review before activating
- Build the write guardrail packet: include account allowlist, target campaign/ad set IDs, dry-run payload, before/after diff, evidence source, platform policy result, rollback reference, and human approval note.
- Block bid/budget writes unless capped: include current value, proposed value, percent change, daily cap, per-change cap, and rollback path. Never auto-approve bid or budget changes.
Execution Order
1. Create campaign (PAUSED)2. Create ad set(s) with targeting + budget3. For each ad:a. If video ad → verify video_id exists in libraryb. Create ad with inline creative (object_story_spec)c. Use instagram_user_id (NOT instagram_actor_id)4. Review all created ads in Ads Manager5. Activate
Activation is a separate high-risk action. Do not activate in the same action that creates or uploads assets.
Cross-Reference with PostHog
After ads are live, use harness/references/posthog-marketing-queries.md to track:
- Landing page traffic from UTM parameters (query #2)
- Visitor journeys from ad click to conversion (query #5)
- Campaign attribution and conversion rates (query #8)
Phase 6: Platform Setup Notes
Generate workspace/ads/_platform-setup.md with:
- Campaign structure per platform (campaigns, ad sets, ad groups)
- Audience targeting recommendations
- Budget allocation across platforms and stages
- Bid strategy recommendations
- Tracking/UTM parameter conventions