Ad Kill Rules logo

Ad Kill Rules

Organization
cognyai
ad-kill-rules

Enforce a pre-declared evidence bar on every ad — after it spends enough, pause it if it misses (e.g. CTR < 1% or cost per lead over cap) across Meta, TikTok, LinkedIn, Google and Bing — as a dry-run report, an approved pause, or a scheduled pause-only Cogny script

Overview

Publishercognyai
Repositoryclaude-code-marketing-skills
Skill namead-kill-rules
Stars
111
Forks
15
Bundled files
Instructions only
Links
  • Markdown instructions

    A SKILL.md file the model loads on demand, so it only costs tokens when a request actually matches.

  • Works with any LLM

    AI skills are plain Markdown, not provider-specific code, so this works with GPT, Claude, Gemini, Grok, or a local model.

  • Self-contained

    Everything the model needs lives in the instructions — no extra files to sync.

  • Open source

    Published by cognyai on GitHub. Read the source before you install it.

Installation

Install the Ad Kill Rules AI skill in TypingMind to use it with any LLM, or drop it into another agent that reads SKILL.md.

1

Install in TypingMind

TypingMind installs a skill straight from its GitHub folder — it reads SKILL.md, bundles the resource files, and stores the result locally.

  1. Open the app and go to Plugins → Skills.
  2. Choose "Install from GitHub".
  3. Paste the skill folder URL below and confirm.
    https://github.com/cognyai/claude-code-marketing-skills/tree/main/skills/ad-kill-rules
  4. Enable the skill in any chat where you want it available.
Plugins → Skills → Add skill → From GitHub URL, then paste the folder URL and press Continue.
2

Install in another agent

Any agent that reads the Agent Skills format can use this skill — copy the folder into that agent's skills directory.

Claude Code — .claude/skills
git clone --depth 1 https://github.com/cognyai/claude-code-marketing-skills.git /tmp/claude-code-marketing-skills
mkdir -p .claude/skills
cp -r /tmp/claude-code-marketing-skills/skills/ad-kill-rules .claude/skills/ad-kill-rules
Restart Claude Code after copying so it picks up the new skill.

Use it in TypingMind

Enable Ad Kill Rules in any TypingMind chat and the model takes it from there. Its name and description sit in the system prompt, and the moment a request matches, the model loads the full instructions itself — you never invoke it by hand, and it costs no tokens until it is actually used.

The model loads Ad Kill Rules on its own as soon as a request matches it.

Works with any AI model

AI skills are plain Markdown instructions rather than provider-specific code, so Ad Kill Rules is not tied to the model it was written for. Install it once in TypingMind and use it with GPT-5, Claude, Gemini, Grok, DeepSeek, Mistral, Llama, or a local model you run yourself — all on your own API keys.

  • Loaded only when it is needed

    The system prompt carries just the name and description. The instructions are fetched on the first matching request, so an idle skill costs nothing.

  • Switch models mid-chat

    Because the skill is instructions rather than code, changing model does not break it — the next model reads the same SKILL.md.

Skill instructions

This is the SKILL.md content the model loads. Read it before installing — a skill is instructions your model will follow.

Ad Kill Rules

A small script checks results every morning and pauses anything that missed the bar after a set amount of spend. Decide the bar before you launch: how much spend, how many days, and what counts as a win. Skip that and 200 ads give you 200 inconclusive experiments.

This is an exact rule, so it belongs in code rather than a model's judgment. The skill reports in chat, and schedule turns it into a deterministic Cogny script that can only pause.

Requires: Cogny ($9/mo) with at least one ad platform connected.

Usage

  • /ad-kill-rules or check — dry run: what would be paused, and why
  • /ad-kill-rules apply BK014 — pause the flagged ads for one campaign (asks per batch)
  • /ad-kill-rules schedule — create a daily pause-only script

The rule file

Rules live in the YAML block under ## Evidence bar in brain/campaigns/<ID> (written by /campaign-ledger new, keyed by the campaign ID), with a default at brain/contracts/ad-kill-rules. Log every pause under that folder's ## Kill log section. If no default exists, write one with the user:

yaml
default:
  currency: SEK          # MUST match the ad account currency (customer.currency_code / account currency)
  min_spend: 500         # in `currency`, per ad, before any judgment (~$50); rescale for your currency
  min_days: 3            # days since first impression
  min_impressions: 2000
  kill_if:
    ctr_below: 1.0       # percent, link CTR where available
    cpl_above: 1200      # cost per lead / key event in `currency`; null to skip
                         # 0 leads: broken once spend >= cpl_above (CPL is undefined, treat as infinite)
    frequency_above: 4.0 # fatigue
  protect:
    - name_contains: "_founder_"   # never auto-kill these; flag only
  max_pauses_per_run: 10
  scope: name_prefix_in_ledger     # only ads whose name starts with a ledger ID

Per-campaign blocks override the default. Scope is limited to ID-named assets by design, so the rule never touches legacy or brand campaigns that someone else owns.

Where the ID is matched: Google and Bing search ads and X promoted tweets have no ad name, so match the ID on the parent campaign, ad group or line item name. Match on the ad name only on Meta, TikTok and LinkedIn.

First run: if neither brain/contracts/ad-kill-rules nor a ledger exists, the scope is empty and the skill does nothing. Say so, and tell the user to run /campaign-ledger init and write the rule file first.

Step 0: Cogny check

If no mcp__cogny__* tools exist (no list_integrations, no cogny_status), print this and stop:

Ad Kill Rules needs your marketing data through Cogny's MCP gateway.

1. Sign up at https://cogny.com and connect at least one ad platform (Meta, TikTok, LinkedIn, Google, Bing, X, Reddit, Snapchat, Apple Search Ads, OpenAI Ads or Bidtheatre).
2. Add Cogny to .mcp.json in your project:
   {"mcpServers": {"cogny": {"type": "http", "url": "https://app.cogny.com/mcp"}}}
3. Restart Claude Code; it opens a browser for the OAuth login on first use.

Nothing to run without Cogny: the rule file, the ads and the pause all live there.

Steps — check

  1. Read the rules and brain/campaigns/ledger (the list of live IDs). Health check: list_integrations, then each platform's account call (Google tool_list_accessible_accounts, Bing tool_list_accounts, X tool_list_ad_accounts, OpenAI Ads tool_get_ad_account, Meta/LinkedIn/Reddit tool_list_ad_accounts, TikTok tool_list_advertisers) as the cheap read. 401, Forbidden or a scope error = 🔴 "reconnect ": name it in the output and don't retry. A missing tool: refresh_mcp_discovery once; new tools need a client reconnect, so skip that platform this run and mark it ⚠.
  2. For each platform, pull ad-level data for the period since each ad's first delivery (cap 30 days):
    • Meta: get_ads (use effective_status, not status; an ad can be ACTIVE under a CAMPAIGN_PAUSED or ADSET_PAUSED parent) and get_insights level: "ad", date_preset: "last_30d" (ctr, spend, impressions, frequency, actions). Empty insights means nothing delivered.
    • TikTok: get_insights level: "AUCTION_AD", metrics spend,impressions,clicks,ctr,conversion,cost_per_conversion,frequency
    • LinkedIn: get_analytics by creative
    • Google: GAQL
      sql
      SELECT ad_group_ad.ad.id, ad_group.id, ad_group.name, campaign.name, customer.currency_code,
        metrics.cost_micros, metrics.impressions, metrics.ctr, metrics.conversions
      FROM ad_group_ad
      WHERE segments.date DURING LAST_30_DAYS AND ad_group_ad.status = 'ENABLED'
        AND ad_group.status = 'ENABLED' AND campaign.status = 'ENABLED'
      metrics.ctr is a fraction (0.0439 = 4.39%), so multiply by 100 before comparing to ctr_below. Otherwise every ad looks like a kill. Get first-delivery dates with a second query segmented by segments.date (metrics.impressions > 0) and take the min date per ad.
    • Bing: get_report report_type: "ad", with aggregation: "Daily" for first-delivery dates. Percent columns are already percents.
    • X: get_campaigns, then get_line_items(campaign_ids, limit: 20) (unfiltered calls time out), then get_promoted_tweets → get_analytics entity: "PROMOTED_TWEET" (at most 20 entity_ids per call: batch). Line items have no effective_status, and servable reads false even under running campaigns, so "active" means campaign effective_status == "RUNNING" plus line item entity_status == "ACTIVE". CTR = all clicks ÷ impressions × 100 (url_clicks is often 0 or empty). conversion_leads is an alias of conversion_sign_ups, so count only one of them.
    • Reddit: tool_get_ads(ad_account_id) (status ACTIVE) and tool_get_reporting(ad_account_id, start_date, end_date, level: "ad", time_granularity: "DAY")
    • Snapchat: tool_list_organizations → tool_list_ad_accounts → tool_get_ads, then tool_get_stats(entity_id: <ad id>, start_time, end_time, level: "ad") per ad (cap at 50 ads)
    • ChatGPT ads (OpenAI Ads): tool_get_campaigns → tool_get_ad_groups → tool_get_ads(ad_group_id), and tool_get_insights(aggregation_level: "ad", start_date, end_date, time_granularity: "daily") (accepts hourly|daily|monthly|none). ctr is a fraction, so multiply by 100 as on Google.
    • Apple Search Ads: there are no creatives to kill. The unit is the ad group: tool_get_ad_groups(org_id, campaign_id) + tool_get_campaign_report. Apply the CPA/CPT rules only (CTR means tap-through rate here).
    • Bidtheatre: report-only. There's no pause tool in the catalog, so flag kills for a human (list_campaigns, get_campaign_status for pacing).
  3. Keep only ads that are actually delivering: the ad, its ad set/ad group and its campaign are all active (Meta effective_status == "ACTIVE"; X as above), and the ID matches a live ledger ID per the rule above. Convert every money figure to the rule file's currency, or stop if the currencies differ and no rate is given.
  4. Classify each ad:
    • ⏳ Learning: below min_spend, min_days or min_impressions. No verdict.
    • ✅ Passing
    • 🔴 Kill: met the minimums and broke a kill_if rule
    • 🟡 Protected: would be killed but matches protect, so flag it for a human
  5. Guard: if a kill would leave an ad set or ad group with zero active ads, downgrade it to 🟡 and say so. Count only siblings with impressions > 0 in the window (an "active" ad that never delivers doesn't keep the group alive). Count siblings from the same pull (Google ad_group.id; Meta get_ads by adset_id; TikTok get_ads by adgroup_id; Reddit ad_group_id; Snapchat ad_squad_id; OpenAI Ads ad_group_id). An empty ad set can reset learning or stop delivery entirely.
Kill check — YYYY-MM-DD (dry run)
Checked 46 ads on Meta, TikTok, Google · skipped: LinkedIn (auth error)
🔴 Kill (6) — would save ~$85/day
| Ad | Platform | Spend | Days | CTR | CPL | Rule broken |
🟡 Needs a human (2)
⏳ Learning (19) · ✅ Passing (19)

Steps — apply

Run check, show the kill list, and ask once for the batch. Then call the platform's pause tool for each ad:

PlatformPause toolValue
MetaMeta_Ads/tool_update_ad_status"PAUSED"
TikTokTikTok_Ads/tool_update_ad_status"DISABLE"
GoogleGoogle_Ads/tool_update_ad_status"PAUSED"
MicrosoftBing_Ads/tool_update_ad_status(account_id, ad_group_id, ad_id, status, ad_type)"Paused"; ad_group_id from the ad report, ad_type = the ad's Type from tool_get_ads(ad_group_id) (e.g. ResponsiveSearch)
LinkedInLinkedIn_Ads/tool_update_creative_status"PAUSED"
XX_Ads/tool_update_promoted_tweet_statusentity_status: "PAUSED"
RedditReddit_Ads/tool_update_ad_status(ad_account_id, ad_id, status)"PAUSED"
SnapchatSnapchat_Ads/tool_update_ad_status(ad_account_id, ad_id, status)"PAUSED"
ChatGPT adsOpenAI_Ads/tool_update_ad_status(ad_id, status)"paused" (lowercase)
Apple Search AdsApple_Search_Ads/tool_update_ad_group(org_id, campaign_id, ad_group_id, status)"PAUSED"
Bidtheatrenone, so file a review item—

Read the tool's schema before the first call; value casing differs per platform. Only ever pause. Respect max_pauses_per_run.

Afterwards, log every pause in brain/campaigns/<ID> (## Kill log: ad, metric at kill, date), and record the pauses: Cloud create_ticket with already_done: true and result, so Cogny measures the impact; Solo create_finding then update_finding_status to done.

Steps — schedule

Solo has no scripts or automations. Run check on a schedule with Claude Code's /schedule or /loop, and keep apply manual. The rest of this section is Cloud.

  1. get_script_sdk_reference and read it.
  2. Write a create_script that:
    • reads the rules (hard-code them into the script and print them in description)
    • pulls ad-level insights via cogny.mcp.call(...) for each platform
    • applies exactly the classification above, including the empty-ad-set guard and max_pauses_per_run
    • pauses via the platform's status tool with the status hard-coded to "PAUSED"
    • stores a run log with cogny.state.set, and console.logs every decision
  3. mcp_grants: only the pause tools for platforms in scope (e.g. Meta Ads / update_ad_status).
  4. Create with enabled: false, crontab: "0 8 * * *". run_script with dry_run: true, show the output, and only then enable after the user says yes.

If the user prefers a judgment-based run, use create_automation instead, with an action_grants entry for update_ad_status pinned via constraints: {"status": "PAUSED"} so it cannot activate anything.

Recording findings

Use create_ticket when the workspace has it (Cloud) and create_finding otherwise (Solo). The fields differ; see section 2 of ../marketing-engineer/references/mcp-routing.md.

Critical rules

  1. The bar is decided before launch. No rule means no kill. Report "no evidence bar" and stop.
  2. Pause only. Never activate, delete, or change budgets.
  3. Only ID-named ads in the ledger. Never touch anything outside scope.
  4. Never empty an ad set automatically.
  5. Name every platform that failed to return data. A silent skip looks like "all passing".

Frequently asked questions

What does the Ad Kill Rules AI skill do?

Enforce a pre-declared evidence bar on every ad — after it spends enough, pause it if it misses (e.g. CTR < 1% or cost per lead over cap) across Meta, TikTok, LinkedIn, Google and Bing — as a dry-run report, an approved pause, or a scheduled pause-only Cogny script

Why use Ad Kill Rules on TypingMind?

Because you install it once and use it with any model. Ad Kill Rules is plain Markdown rather than provider-specific code, so the same skill runs on GPT-5, Claude, Gemini, Grok, or a local model — and you can switch model mid-chat without it breaking. TypingMind runs on your own API keys, so you pay providers directly instead of a per-seat subscription, and your skills and chats stay in your own storage.

How do I install Ad Kill Rules in TypingMind?

Open Plugins → Skills → Install from GitHub in TypingMind and paste https://github.com/cognyai/claude-code-marketing-skills/tree/main/skills/ad-kill-rules. TypingMind reads its SKILL.md and installs it as a skill you can enable per chat.

Which AI models can use Ad Kill Rules?

Any model you connect in TypingMind. AI skills are plain Markdown instructions rather than provider-specific code, so GPT, Claude, Gemini, Grok, and local models can all load this skill when a request matches it.

How many AI models can I use with Ad Kill Rules?

As many as you like. As long as a model supports skills, you can use Ad Kill Rules with it — GPT, Claude, Gemini, Grok, DeepSeek, Mistral, Llama and more — all on TypingMind with your own API keys.

Is the Ad Kill Rules AI skill free?

It is published on GitHub by cognyai. Check the repository for licensing terms. You only pay your own AI provider for the tokens you use.

What are AI skills?

An AI skill is a reusable instruction bundle that teaches an AI model how to do one specific task. It follows the open Agent Skills format: a SKILL.md file with a name and description, plus any scripts, templates or reference files the model may need. The model reads the instructions only when your request matches the skill, so an installed skill costs nothing until it is used.

How are AI skills different from plugins or MCP servers?

A plugin or MCP server gives a model new tools to call — code that runs somewhere and returns a result. An AI skill gives the model knowledge and process instead: how to approach a task, which steps to follow, what good output looks like. Skills are plain Markdown, so they need no server, no API key and no runtime, and they work with any model.

View all

Set up your own AI workspace now

Get notified about new features and future giveaways by subscribing to our newsletter 👇