Skills DirectorySkills Directory
SkillsLearnSecurityCategoriesDocsCommunityBlog
Sign InSubmit Skill
Skills Directory

Security-tested agent skills for Claude, coding agents, and AI workflows.

Directory

  • Browse Skills
  • All Skills A–Z
  • Claude Skills
  • Claude Code Skills
  • Agent Skills
  • Categories
  • Submit a Skill

Learn

  • Learn Hub
  • Install Claude Skills
  • Write SKILL.md
  • Skills vs MCP
  • Directories Compared

Security

  • Security
  • Methodology
  • Secure Claude Skills
  • Security Badges

Company

  • About
  • Community
  • Blog
  • API Docs
  • Advertise

2026 Skills Directory. All rights reserved.

Back to skills

Create Campaign

ASecurity

Provision Meta campaigns and ad sets on AdManage.ai from a declarative config. Runs on-demand — creates entities PAUSED, writes the returned IDs back into state so schedule-ads can launch into them.

6 stars
0 votes
0 copies
1 views
Added 6/6/2026
content-marketinggoapi

Works with

api

Security Analysis

A100/100

Scanned 6/6/2026

Install to Claude Code

$npx -y skills add anajuliabit/aeon --skill create-campaign --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Create Campaign?

Add the live security badge to your README — it updates automatically with every re-scan.

Security grade badge for Create Campaign
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/anajuliabit-create-campaign/badge)](https://www.skillsdirectory.com/skills/anajuliabit-create-campaign)

More formats (shields.io, HTML) on the badges page.

Download Zip
Files
SKILL.md
---
name: Create Campaign
description: Provision Meta campaigns and ad sets on AdManage.ai from a declarative config. Runs on-demand — creates entities PAUSED, writes the returned IDs back into state so schedule-ads can launch into them.
commits: true
permissions:
  - contents:write
tags: [growth, ads]
---

Reads `skills/create-campaign/config.yaml`, figures out which campaigns/ad sets don't exist yet, and queues create requests to `.pending-admanage/creates/`. The credentialed API calls happen in `scripts/postprocess-admanage-create.sh` after Claude finishes.

This skill is **on-demand** — no `schedule:` in frontmatter. Invoke it manually when you want to provision new campaigns, then reference the returned IDs in `schedules-ads/config.yaml` to launch creatives into them.

Read `memory/MEMORY.md` for context. Read `.admanage-state/campaigns.json` (if it exists) to see what's already created.

## What this skill provisions

Two entity types only:
1. **Meta campaigns** — name, objective, budget, bid strategy, promoted object.
2. **Meta ad sets** — name, budget, optimization goal, targeting (geo/age/platforms), destination.

Everything else (TikTok/Snapchat/Pinterest/LinkedIn campaigns, advanced Meta fields like valueRuleSetId or Advantage+ catalog) is v2+. The shape below is intentionally minimal.

## Safety defaults

Same posture as schedule-ads:

1. **PAUSED by default.** Every campaign + ad set is created with `status: PAUSED`. No surprise spend.
2. **Idempotent.** The skill tracks created entities in `.admanage-state/campaigns.json`. If a campaign name already exists in state, it's skipped. Run the skill twice → no duplicates.
3. **Dry-run mode.** `DRY_RUN=true` or `config.dryRun: true` → payloads written to `.pending-admanage/dryrun-create/`, notified, no API calls.
4. **Config-only.** No config file → exit silently. No invented campaigns, no autonomous provisioning.

## Sandbox note

Every `/manage/*` endpoint requires `Authorization: Bearer $ADMANAGE_API_KEY`. Sandbox blocks env-var expansion in curl headers, so this skill queues intents only:

- Skill writes: `.pending-admanage/creates/campaigns/<slug>.json` and `.pending-admanage/creates/adsets/<campaign-slug>__<adset-slug>.json`
- After Claude exits, `scripts/postprocess-admanage-create.sh` runs with full env access, makes the API calls in the right order (campaigns first, then ad sets referencing returned campaign IDs), and writes results back to `.admanage-state/campaigns.json`.

If the postprocess script is missing, the skill still queues correctly — the payloads sit in `.pending-admanage/creates/` until the script exists.

## Steps

1. **Load config.** Read `skills/create-campaign/config.yaml`. If it doesn't exist, log `CREATE_CAMPAIGN_NOT_CONFIGURED` and exit cleanly (no notify).

2. **Load state.** Read `.admanage-state/campaigns.json`. If it doesn't exist, treat as empty. Shape:
   ```json
   {
     "campaigns": [
       {
         "configName": "Prospecting — Q2 2026",
         "campaignId": "120251616228380456",
         "adAccountId": "act_xxx",
         "createdAt": "2026-04-21T08:00:00Z",
         "adSets": [
           {
             "configName": "US Broad 25-54",
             "adSetId": "120251616242460456",
             "createdAt": "2026-04-21T08:00:04Z"
           }
         ]
       }
     ]
   }
   ```

3. **Validate config shape.** Required: `defaults.adAccountId`, `defaults.workspaceId`, `campaigns[]`. Each campaign needs `name` and `objective`. Each ad set needs `name`, and either `optimizationGoal` (explicit) or a compatible parent objective. If validation fails, file an issue in `memory/issues/` and exit.

4. **Compute diff.** For each campaign in config:
   - Match against state by exact `name`. If present, mark as `existing`.
   - If missing, mark as `new` and queue a campaign create.
   - For each ad set under the campaign, match against the parent's `adSets[]` in state by name. If missing, queue an ad-set create (with a `parentCampaignConfigName` reference that postprocess will resolve to a real campaign ID).

   If nothing is new, log `CREATE_CAMPAIGN_ALL_EXIST` and exit without notify.

5. **Build campaign create payloads.** Per the AdManage `POST /v1/manage/create-campaign` shape:
   ```json
   {
     "businessId": "<adAccountId>",
     "workspaceId": "<workspaceId>",
     "name": "<campaign.name>",
     "objective": "<campaign.objective>",
     "status": "PAUSED",
     "buyingType": "AUCTION",
     "specialAdCategories": [],
     "dailyBudget": <number>,
     "bidStrategy": "<LOWEST_COST_WITHOUT_CAP | LOWEST_COST_WITH_BID_CAP | COST_CAP | ...>",
     "promotedObject": { ... }
   }
   ```
   Skip keys that are `null`/absent in config — don't send empty strings. Always force `status: PAUSED` unless `defaults.launchPaused: false` is set explicitly.

6. **Build ad-set create payloads.** Per `POST /v1/manage/create-adset`:
   ```json
   {
     "businessId": "<adAccountId>",
     "workspaceId": "<workspaceId>",
     "campaignId": "__RESOLVE_FROM_PARENT__",
     "parentCampaignConfigName": "<campaign.name>",
     "name": "<adSet.name>",
     "status": "PAUSED",
     "dailyBudget": <number>,
     "billingEvent": "IMPRESSIONS",
     "optimizationGoal": "<LANDING_PAGE_VIEWS | OFFSITE_CONVERSIONS | ...>",
     "destinationType": "<WEBSITE | PHONE_CALL | MESSAGING_... | ...>",
     "targeting": { ... },
     "promotedObject": { ... }
   }
   ```

   The `__RESOLVE_FROM_PARENT__` sentinel + `parentCampaignConfigName` tells postprocess to look up the campaign ID after the campaign create succeeds. If the parent campaign was *existing* (already in state), write the real campaign ID directly and drop the sentinel.

7. **Pre-flight validation.**
   - `adAccountId` must start with `act_` (this skill is Meta-only in v1).
   - `dailyBudget` must be a positive number in dollars (not cents).
   - `objective` must be one of the documented Meta objectives: `OUTCOME_TRAFFIC`, `OUTCOME_ENGAGEMENT`, `OUTCOME_LEADS`, `OUTCOME_AWARENESS`, `OUTCOME_SALES`, `OUTCOME_APP_PROMOTION`.
   - Targeting `geo_locations.countries` must be a non-empty array.
   Drop invalid entries, keep going, log what was skipped and why.

8. **Handle dry-run.** If `DRY_RUN=true` or `config.dryRun: true`: write payloads to `.pending-admanage/dryrun-create/` instead, notify with a `[DRY RUN]` prefix, skip step 9.

9. **Queue for postprocess.** Write files into `.pending-admanage/creates/`:
   - `campaigns/<slugify(name)>.json` — campaign create payload.
   - `adsets/<slugify(campaign-name)>__<slugify(adset-name)>.json` — ad-set create payload.

   The file-name convention matters: postprocess lexical-sorts `campaigns/` first, then `adsets/`, so campaigns always create before their children.

10. **Write artifact to `.outputs/create-campaign.md`** so chain consumers can see what was queued:
    ```markdown
    # Create Campaign — ${today}

    New campaigns: N.
    New ad sets: M.
    Dry-run: yes|no.

    ## Campaigns
    - <name> — <objective>, $<dailyBudget>/day
      - ad set: <name> — <optimizationGoal>, $<dailyBudget>/day, <countries>

    ## Skipped (already exist)
    - <name>
    ```

11. **Notify via `./notify`.** Tight format:
    ```
    *Campaigns queued — ${today}${dryRunSuffix}*

    <N> campaigns, <M> ad sets queued for creation.

    - <campaign name>
      - adset: <adset name> — <country>, $<budget>/day

    <if dry-run>
    no API calls made — remove DRY_RUN to arm.
    <else>
    postprocess-admanage-create will provision and write IDs to .admanage-state/campaigns.json.
    ```
    If nothing is new, don't notify at all.

12. **Log to `memory/logs/${today}.md`:**
    ```
    ## Create Campaign
    - New campaigns queued: <count>
    - New ad sets queued: <count>
    - Files: .pending-admanage/creates/**/*.json
    ```

## Config schema

See `skills/create-campaign/config.example.yaml` for a filled-in template. Minimum viable config:

```yaml
defaults:
  adAccountId: act_XXXXXXXXXX
  workspaceId: XXXXXXXXXXXX
  launchPaused: true               # never flip without a reason
  dryRun: false                    # true = build, don't call

campaigns:
  - name: "Prospecting — Q2 2026"
    objective: OUTCOME_TRAFFIC
    dailyBudget: 50
    bidStrategy: LOWEST_COST_WITHOUT_CAP
    promotedObject:
      pixel_id: "123456789012345"
    adSets:
      - name: "US Broad 25-54"
        dailyBudget: 15
        optimizationGoal: LANDING_PAGE_VIEWS
        destinationType: WEBSITE
        targeting:
          geo_locations: { countries: ["US"] }
          age_min: 25
          age_max: 54
          publisher_platforms: [facebook, instagram]
```

## Interaction with schedule-ads

After `postprocess-admanage-create.sh` writes to `.admanage-state/campaigns.json`, the IDs are yours to reference in `skills/schedule-ads/config.yaml` under `adSets[].value`. The two skills are intentionally decoupled:

- **create-campaign** provisions structure (container).
- **schedule-ads** launches creative into that structure (contents).

Running both in the same Claude cycle *won't* chain — the state file won't have IDs until postprocess runs. Pattern is: run create-campaign → wait for postprocess to log the new IDs → copy IDs into schedule-ads config → next schedule-ads run uses them.

## What it does NOT do

- **Doesn't touch existing campaigns.** Once a campaign is in state, this skill leaves it alone. Budget changes, bid changes, status flips, renames — all handled elsewhere (dashboard or a separate skill).
- **Doesn't delete or archive.** No destructive paths.
- **Doesn't provision media, pages, or pixels.** Pixel IDs must already exist in AdManage. Use `GET /v1/conversions/pixels` to discover them.
- **Doesn't create TikTok / Snapchat / Pinterest / LinkedIn** structures. Those have different payload shapes and live in v2.
- **Doesn't resume paused campaigns.** PAUSED is the end state; the operator unpauses manually when ready.

## Environment Variables

- `ADMANAGE_API_KEY` — required for `scripts/postprocess-admanage-create.sh`. Never read by this skill.
- `DRY_RUN` — optional. `true` forces dry-run regardless of config.
- Notification channels configured via repo secrets (see CLAUDE.md).

## Output

End with a `## Summary` block: new campaigns queued, new ad sets queued, skipped (already-exist) count, dry-run yes/no, files written.

Attribution

anajuliabitanajuliabit
View sourceMore from anajuliabit →
SSkills DirectorySkills Directory

Your tool, in front of Claude Code builders.

3 founder slots · $299/mo · GSC-verified traffic · sponsors can never buy grades.

See placements

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments (0)

No comments yet. Be the first to comment!

SSkills DirectorySkills Directory

Your tool, in front of Claude Code builders.

3 founder slots · $299/mo · GSC-verified traffic · sponsors can never buy grades.

See placements

Related Skills

Postiz

Postiz is a tool to schedule social media and chat posts to 28+ channels X, LinkedIn, LinkedIn Page, Reddit, Instagram, Facebook Page, Threads, YouTube, Google My Business, TikTok, Pinterest, Dribbble, Discord, Slack, Kick, Twitch, Mastodon, Bluesky, Lemmy, Farcaster, Telegram, Nostr, VK, Medium, Dev.to, Hashnode, WordPress, ListMonk

21281 votes

Serp Analysis

SERP analysis techniques for intent classification, feature identification, and competitive intelligence. Use when analyzing search results for content strategy.

2831 votes

On Page Seo Auditor

This skill performs detailed on-page SEO audits to identify issues and optimization opportunities. It analyzes all on-page elements that affect search rankings and provides actionable recommendations.

1821 votes

Brand

Brand voice, visual identity, messaging frameworks, asset management, brand consistency. Activate for branded content, tone of voice, marketing assets, brand compliance, style guides.

1289240 votes

Release Announcement

Write a release announcement — changelog, blog post, in-app note, or social post — that leads with user impact, names the audience, and includes upgrade/migration steps without filler.

805540 votes
View all in content-marketing →