# /campaign-deck

> Write a complete Meta ad campaign deck in ACME Agency's high-energy in-house deck voice.


# /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`)
1. `ACME Agency/clients/clients.json` → `slack_channel`, `drive_folder_id`, `website`, `vertical`,
   `page_id`, languages.
2. `ACME Agency/clients/<Client>/CLIENT.md` → business, offer, audience, USPs, proof points,
   competitors, pricing, tone, conversion goal.
3. `ACME Agency/clients/<Client>/brand-dna.md` if present → voice adjectives, language, tone.
4. If `clients.json` lacks 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 `/spy` history
  (`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 `/spy` for 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 `--audience` entry. 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
```bash
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 have `Headline:` + `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 (`url` non-null) and filed in the client's Drive `Oglasi` folder
- [ ] Local copy saved at `ACME Agency/clients/<Client>/campaign_deck_<YYYY-MM-DD>.{txt,md}`
- [ ] Slack post via slack-reporter returned `ts` non-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.
