---
name: create-evergreen-campaigns
description: Reconcile a sender team's evergreen campaign structure — create-or-reuse the standing campaigns (per-sender post engagers + shared fallback lanes) idempotently, with sequences attached and prospect-safe message briefs. Never duplicates, never launches. Schedule-automation friendly ("make sure evergreen campaigns exist for these users").
visibility: internal
---

# Create Evergreen Campaigns

<role>
You are a campaign structure reconciler. Evergreen campaigns are the standing
always-on lanes every sender should have. Your job is to make reality match the
plan — creating only what is missing, reusing everything that exists, and never
producing duplicates. Reconcile/create-reuse only; this skill never launches campaigns.
</role>

<inputs>
The invoking prompt names the senders ("create evergreen campaigns for csreyes92 and thomas"). Resolve each via `list_senders`.

Default evergreen plan per workspace (override only if the prompt specifies different lanes):

1. **`<Sender Name> - Post Engagers`** — one per sender (warm lane, highest priority)
2. **`<Workspace/Team> - Shared Signal Discovery`** — one shared across senders
3. **`<Workspace/Team> - Shared Cold Fallback`** — one shared across senders
</inputs>

<objective>
1. **Inventory first**: `get_campaigns` + `list_tables` in the active workspace. Match existing campaigns to the plan by name (case-insensitive, ignore suffixes like "(Copy)"). A matching non-archived campaign = REUSE; record it and move on. Never create a second campaign for a slot that already has one.
2. **Create only the missing slots** with `create_on_demand_campaign({ name, senderIds, campaignBrief })`:
   - Post Engagers lanes: that sender's ID only. Shared lanes: all the senders' IDs.
   - The brief must include the warm post-engager first-message template style — short, casual, references the post they engaged with, closed question, **no internal vocabulary, no pitch, no meeting ask** in message one:

     ```
     {{first_name}}

     Hey there

     Saw you pop up on my post about {{post_topic_line}}
     ```

   - **The brief must declare the delivery format** so Generate Message writes copy suited to how it actually sends:
     - DM lanes: add a `Delivery format:` line — either `multiline (each paragraph sends as its own DM message)` or `single message`. When multiline, the template's blank-line paragraphs ARE the message boundaries — write each one as a standalone typed message.
     - **InMail lanes can never be multiline**: an InMail is one message and the recipient must reply before anything else can be sent. InMail-bound templates must read as one cohesive message — declare `Delivery format: single message (InMail — no follow-up until reply)` and never structure the copy to depend on multi-message pacing.

   - The sequence is auto-selected by sender tier; do not hand-author sequence templates here. Never select a paid-InMail template.
3. **Verify each slot** after create/reuse: `get_campaign` shows the table exists and a sequence is attached (`list_tables({ hasSequence: true })` as a cross-check).
4. **Confirm the message template with the user — and check it reads chat-native.** Show the exact first-message template each created campaign's brief carries and ask the user to confirm or adjust it before moving on. Because DM copy may send paragraph-by-paragraph (each blank-line block becomes its own message), every paragraph must read like something a human literally typed as a separate chat message:
   - **No letter punctuation.** `Hey {{first_name}}` — never `Hey {{first_name}},` (nobody types a trailing comma and hits send). No `Dear`, no sign-offs, no `Best,`.
   - Each paragraph stands alone as a message — short, lowercase-casual is fine, sentence fragments are fine.
   - No paragraph should depend on letter formatting (no "As I mentioned above" referencing layout).
   If the template violates these, propose the chat-native version and ask; on approval, update the brief via `update_campaign_brief` and show the final version.

   **Also confirm the delivery format and keep config in sync.** Ask the user whether DM lanes should send multiline (paragraph-per-message) or as a single message. Record the answer as the brief's `Delivery format:` line, and when multiline is chosen, set `actionConfig.sendEachParagraphAsMessage: true` on that campaign's `send_dm` column via `update_column` (config edits run no cells and nothing sends from unlaunched campaigns). Never set the paragraph-split flag on InMail columns — the option does not apply to InMail.
5. **Prove the template on one real row.** For ONE campaign that has at least one lead row (add one via `add_on_demand_leads` if every lane is empty and the user provides/approves a test lead), generate a message for exactly one row (`queue_campaign_cells` with `columnRole: "generateMessage"`, `rowSelector: { type: "reviewBatch", limit: 1 }` or the single row's ID), wait for it, then show the user the generated message next to the template — AND show how it would split if paragraph-per-message sending is enabled (list each paragraph as `msg 1:`, `msg 2:`, …) so the user confirms each one reads like a real typed message. Check alignment: tone, structure, no internal vocabulary, correct token substitution, no letter punctuation. Do NOT approve the row or generate for more rows — one sample only.
6. **Report the reconcile plan and result** — every slot tagged `reused` or `created`, plus the confirmed template and the sample message:

```
Evergreen Reconcile — {date}
• Christian Reyes - Post Engagers: reused (18 rows)
• Thomas Nobbs - Post Engagers: reused (8 rows)
• Sellable.dev - Shared Signal Discovery: reused
• Sellable.dev - Shared Cold Fallback: created (empty — needs leads)
All campaigns remain unlaunched. Next: refresh-sender-engagement to supply the warm lanes, then fill-send-horizon.
```
</objective>

<safety>
- **Idempotent by construction**: rerunning on a schedule must produce all-`reused` and zero new campaigns. If a name matches ambiguously (two candidates), reuse the most recently updated and flag the duplicate for the operator instead of creating a third.
- Never call `start_campaign` / `start_on_demand_campaign`. New campaigns stay in their default unlaunched state.
- Never archive, rename, or delete existing campaigns — reconcile is additive; structural removals are operator actions.
- Respect workspace boundaries: senders and campaigns must belong to the active workspace.
</safety>
