[ COPY & CONTENT ]
/campaign-deck
Write a complete Meta ad campaign deck in ACME Agency's high-energy in-house deck voice.
ACME Agency, <id> and you@example.com mark values that are per-agency — your install fills them with YOUR clients and accounts. If a section references a helper script you don't have yet, it ships with that workflow's install./campaign-deck
Generates a ACME Agency Meta campaign deck in the agency's high-energy in-house deck voice — the deck structure, the voice, the emoji/arrow system, the problem→solution arc — for any vertical and in HR, BS, EN, or DE. The deck lands as a native Google Slides file in the client's Drive folder and is directly ready for /meta-lead-ads once a designer drops in the visuals.
This is NOT /copywrite. /copywrite returns 3 ad-copy variants in a Doc. /campaign-deck returns a complete campaign deck (ads + lead form + thank-you + email) in the deck voice, at max fidelity (emojis and fragments kept, unlike the house copywriter).
When to trigger
- "write the campaign deck for <client>" / "deck of Meta ads for <client>"
- "napravi deck oglasa za <klijent>" / "napiši kampanju u našem deck stilu"
- "/campaign-deck <Client>"
- Any request for a full Meta lead-ads deck/brief (not just a couple of copy lines) for a ACME Agency client, where the ask is the full high-energy deck style.
- NOT for: a single headline or one-off copy line (use
/copywrite); building the campaign IN Meta from
an existing deck (that's /meta-lead-ads); visuals/images (that's /reference-ads etc.).
Phase 0 — Parse inputs
Extract: client (required), --lang (one or more of hr|bs|en|de; default = client's primary language), --audience (optional extra audience blocks, e.g. "turisti, partneri"), --type (lead-gen | giveaway | recruitment; default lead-gen), --folder (Drive folder override).
If client is missing, ask once. Don't guess.
Phase 1 — Mirror the deck process: client → competition → questionnaire
The deck voice is written after looking at the client, the competition, and the questionnaire. Gather all three:
1.1 Client (3-step cascade — see ACME Agency/CLAUDE.md)
ACME Agency/clients/clients.json→slack_channel,drive_folder_id,website,vertical,
page_id, languages.
ACME Agency/clients/<Client>/CLIENT.md→ business, offer, audience, USPs, proof points,
competitors, pricing, tone, conversion goal.
ACME Agency/clients/<Client>/brand-dna.mdif present → voice adjectives, language, tone.- If
clients.jsonlacks the client, fall back to the Sheet registry (readClientRegistry) then API
discovery, and backfill clients.json.
1.2 Competition
- Read competitors from CLIENT.md. If the client has a
/spyhistory
(ACME Agency/clients/<Client>/ spy docs) read the latest for current hook/offer/format patterns.
- Optional deeper pass: if the user asks for a fresh competitive read, run
/spyfor the client (or
/spy --keywords "<vertical terms>") first and feed its hook/offer findings into the brief. Don't block on this — the deck's edge is voice, not a competitor audit.
1.3 Questionnaire (upitnik)
- Look for an onboarding questionnaire in the client's Drive folder or local folder
(ACME Agency/clients/<Client>/ — files named upitnik, questionnaire, brief, intake). If a Drive questionnaire exists, read it for offer details, audience pains, proof, and the client's own phrasing. If none exists, note the gap and proceed from CLIENT.md + website.
- If key facts (price, guarantee, certifications, exact offer) are missing, list them — the agent will
placeholder them as [POTVRDITI — …] rather than inventing.
1.4 Decide blocks
- One block per language in
--lang, plus one block per--audienceentry. Decide, per extra block,
PORT (same offer, other language) vs REWRITE (same language, other audience) — see STYLE_GUIDE §2.
Phase 2 — Delegate to the campaign-copywriter agent
Invoke the campaign-copywriter subagent (Task tool, subagent_type: "campaign-copywriter"). Pass:
client: <name>
business: ACME Agency
vertical: <from clients.json / CLIENT.md>
campaign_type: lead-gen | giveaway | recruitment
language_blocks: [<hr>, <de>, ...] # + audience blocks (turisti / partneri / dijaspora)
brief: <assembled from Phase 1 — offer, audience pains, USPs, proof points, price anchor, mechanism,
competitor hooks to differ from, the client's own phrasing from the questionnaire,
per-block PORT vs REWRITE decision>
constraints: <must-include claims, banned angles, char sensitivities, known proof points; any [POTVRDITI] gaps>
reference_files:
- <abs path>/.claude/skills/campaign-deck/STYLE_GUIDE.md
- <abs path>/.claude/skills/campaign-deck/campaign-deck.tests.md
- <abs path>/ACME Agency/clients/<Client>/CLIENT.md (if exists)
- <abs path>/ACME Agency/clients/<Client>/brand-dna.md (if exists)
The agent reads the style guide + tests, writes the full deck per block, runs the deck-voice self-test loop (structure complete + markers present + no em-dashes + English error guards + HR/BS register consistency + "is this on-voice?" ≥ 8/10), and returns the deck as text with === SLIDE === delimiters plus angle notes, iteration counts, and per-block scores.
Do NOT write or hand-edit the copy yourself. If a block is off, re-invoke the agent with specific feedback.
Phase 3 — Build the Slides deck + deliver
3.1 Save the agent's deck text locally
Write the agent's DECK: payload (everything from the first === SLIDE === onward) to ACME Agency/clients/<Client>/campaign_deck_<YYYY-MM-DD>.txt.
3.2 Build the native Slides deck
node ACME Agency/scripts/build_campaign_deck.mjs \
--client "<Client>" \
--title "<Client> — Deck oglasa — <YYYY-MM-DD>" \
--in "ACME Agency/clients/<Client>/campaign_deck_<YYYY-MM-DD>.txt"
This splits on === SLIDE ===, creates one left-column text box per slide, and files the deck in the client's Drive Oglasi subfolder (or --folder/My Drive root if no client folder). It prints { presentationId, url, slideCount }. The left-column placement is what makes the deck /meta-lead-ads -readable — designers add visuals on the right of each slide afterward.
Also save the full agent payload (angle notes + scores) to ACME Agency/clients/<Client>/campaign_deck_<YYYY-MM-DD>.md for reference.
3.3 Deliver via slack-reporter
Invoke the slack-reporter subagent. Pass: the client's slack_channel (from clients.json), a headline *Deck oglasa — <Client> — <YYYY-MM-DD>*, one section per language block listing the ad concepts + hook archetypes, an info line (campaign type, languages, iterations, voice-scores), and the Slides URL as the primary link. Language = the channel's language.
3.4 Next steps line
Tell the user: the deck is in Drive (link), it's in the house deck voice, and the next step is to add visuals to each slide's right side, then run /meta-lead-ads "<Client>" "<slides URL>" to build the campaign (PAUSED).
Verification (run AFTER 3.3)
- [ ] Agent returned a deck for every requested language/audience block
- [ ] Each lead-gen block has 4–5 ad concepts incl. ≥1 CAROUSEL and ≥1 VIDEO (giveaway/recruitment per type)
- [ ] Every ad slide carries a standalone format marker (
SINGLE IMAGE/CAROUSEL/VIDEO); the tail has
META LEAD FORM + THANK YOU EMAIL markers
- [ ] Carousels have a stacked
Headline:set (card 1 + card names); singles/videos haveHeadline:+Description: - [ ] Lead form has ≥1 qualifying question (not just contact fields)
- [ ] No em-dashes anywhere; HR/BS register is consistent within each block (no Croatian↔Serbian drift)
- [ ] English blocks pass M-EN* (possessive apostrophes, period decimals, no typos, agreement) — the weakest language
- [ ] Diacritics (š ć č ž đ) and emojis preserved verbatim
- [ ] Each block's "is this on-voice?" score ≥ 8 (or the gap is flagged loudly — never silently shipped)
- [ ] Slides deck built (
urlnon-null) and filed in the client's DriveOglasifolder - [ ] Local copy saved at
ACME Agency/clients/<Client>/campaign_deck_<YYYY-MM-DD>.{txt,md} - [ ] Slack post via slack-reporter returned
tsnon-null with the Slides URL
If any check fails, name the gap. The most common acceptable reduction is a block scoring < 8 after 5 iterations — flag it, never silently ship off-voice.
Key files
| File | Purpose |
|---|---|
.claude/skills/campaign-deck/STYLE_GUIDE.md | The deck voice's structure, voice, hooks, emoji system, per-vertical + per-language guards |
.claude/skills/campaign-deck/campaign-deck.tests.md | The deck-voice self-test suite (keeps emojis/fragments; guards the real error types) |
.claude/agents/campaign-copywriter.md | The agent that writes the deck |
ACME Agency/scripts/build_campaign_deck.mjs | Builds the native Slides deck from === SLIDE === text |
ACME Agency/scripts/lib/google_slides.mjs | createCopyDeck() (deck builder) + the /meta-lead-ads reader |
.claude/skills/meta-lead-ads/SKILL.md | The downstream skill that ingests this deck |
ACME Agency/clients/clients.json | Client lookup: Slack channel, Drive folder, website, vertical |
Notes
- Max deck-voice fidelity is the point. This skill deliberately keeps emojis,
→arrows, and English
power-fragments — it does NOT apply the house no-emoji rule. Do not "clean up" the deck style.
- Never fabricate proof (prices, guarantees, certifications). Missing facts become
[POTVRDITI — …]. - The deck is copy-only. Visuals are added by designers afterward; the
[Link oglasa]convention and
left-column text-box layout keep it /meta-lead-ads-ready.
- Diacritics + emojis are sacred — see
ACME Agency/CLAUDE.md→ "Meta Ad Creation Rules" #2.