winback-engine · v1.1.2 · 2026-10-12 · sha256 558c00d40559e406

winback-engine v1.1.2A

Immutable. This exact content never changes and is served at /api/v1/blob/558c00d40559e406.

---
name: winback-engine
description: Find dormant subscribers, segment by historical value, draft personalized winback emails per tier, and identify suppression candidates
version: "1.1.2"
author: Cogny AI
requires: cogny-mcp
platforms: [klaviyo, mailchimp, rule, get-a-newsletter, brevo, mailerlite, drip, salesforce-marketing-cloud, braze, shopify, woocommerce, stripe]
user-invocable: true
argument-hint: "[aggressive|standard|conservative]"
allowed-tools:
  # Cogny Cloud (aggregated) namespace
  - mcp__cogny__refresh_mcp_discovery
  - mcp__cogny__mcp__Klaviyo__list_profiles
  - mcp__cogny__mcp__Klaviyo__get_profile
  - mcp__cogny__mcp__Klaviyo__list_lists
  - mcp__cogny__mcp__Klaviyo__get_list
  - mcp__cogny__mcp__Klaviyo__get_list_profiles
  - mcp__cogny__mcp__Klaviyo__list_segments
  - mcp__cogny__mcp__Klaviyo__get_segment
  - mcp__cogny__mcp__Klaviyo__list_campaigns
  - mcp__cogny__mcp__Klaviyo__get_campaign
  - mcp__cogny__mcp__Klaviyo__get_campaign_message
  - mcp__cogny__mcp__Klaviyo__get_campaign_values_report
  - mcp__cogny__mcp__Klaviyo__list_flows
  - mcp__cogny__mcp__Klaviyo__get_flow
  - mcp__cogny__mcp__Klaviyo__list_metrics
  - mcp__cogny__mcp__Klaviyo__get_metric
  - mcp__cogny__mcp__Klaviyo__list_events
  - mcp__cogny__mcp__Klaviyo__list_templates
  - mcp__cogny__mcp__Klaviyo__get_account
  - mcp__cogny__mcp__Mailchimp__tool_get_account_info
  - mcp__cogny__mcp__Mailchimp__tool_list_campaigns
  - mcp__cogny__mcp__Mailchimp__tool_get_campaign
  - mcp__cogny__mcp__Mailchimp__tool_get_campaign_content
  - mcp__cogny__mcp__Mailchimp__tool_list_audiences
  - mcp__cogny__mcp__Mailchimp__tool_get_audience
  - mcp__cogny__mcp__Mailchimp__tool_list_members
  - mcp__cogny__mcp__Mailchimp__tool_get_member
  - mcp__cogny__mcp__Mailchimp__tool_get_member_tags
  - mcp__cogny__mcp__Mailchimp__tool_list_segments
  - mcp__cogny__mcp__Mailchimp__tool_get_segment
  - mcp__cogny__mcp__Mailchimp__tool_list_templates
  - mcp__cogny__mcp__Mailchimp__tool_get_template
  - mcp__cogny__mcp__Mailchimp__tool_list_reports
  - mcp__cogny__mcp__Mailchimp__tool_get_report
  - mcp__cogny__mcp__Mailchimp__tool_get_report_click_details
  - mcp__cogny__mcp__Mailchimp__tool_get_report_open_details
  - mcp__cogny__mcp__Mailchimp__tool_get_report_unsubscribed
  - mcp__cogny__mcp__Mailchimp__tool_list_automations
  - mcp__cogny__mcp__Mailchimp__tool_get_automation
  - mcp__cogny__mcp__Rule__tool_list_subscribers
  - mcp__cogny__mcp__Rule__tool_get_subscriber
  - mcp__cogny__mcp__Rule__tool_get_subscriber_fields
  - mcp__cogny__mcp__Rule__tool_list_subscriber_tags
  - mcp__cogny__mcp__Rule__tool_list_tags
  - mcp__cogny__mcp__Rule__tool_get_tag
  - mcp__cogny__mcp__Rule__tool_list_campaigns
  - mcp__cogny__mcp__Rule__tool_get_campaign
  - mcp__cogny__mcp__Rule__tool_get_campaign_statistics
  - mcp__cogny__mcp__Rule__tool_list_templates
  - mcp__cogny__mcp__Rule__tool_get_template
  - mcp__cogny__mcp__Rule__tool_list_segments
  - mcp__cogny__mcp__Rule__tool_list_customizations
  - mcp__cogny__mcp__Rule__tool_get_customization
  - mcp__cogny__mcp__Rule__tool_list_suppressions
  - mcp__cogny__mcp__Rule__tool_list_preference_groups
  - mcp__cogny__mcp__Rule__tool_get_subscriber_preferences
  - mcp__cogny__mcp__Rule__tool_list_journeys
  - mcp__cogny__mcp__Get_a_Newsletter__tool_list_contacts
  - mcp__cogny__mcp__Get_a_Newsletter__tool_get_contact
  - mcp__cogny__mcp__Get_a_Newsletter__tool_list_lists
  - mcp__cogny__mcp__Get_a_Newsletter__tool_get_list
  - mcp__cogny__mcp__Get_a_Newsletter__tool_list_drafts
  - mcp__cogny__mcp__Get_a_Newsletter__tool_get_draft
  - mcp__cogny__mcp__Get_a_Newsletter__tool_list_sent
  - mcp__cogny__mcp__Get_a_Newsletter__tool_get_sent
  - mcp__cogny__mcp__Get_a_Newsletter__tool_list_scheduled
  - mcp__cogny__mcp__Get_a_Newsletter__tool_list_reports
  - mcp__cogny__mcp__Get_a_Newsletter__tool_get_report
  - mcp__cogny__mcp__Get_a_Newsletter__tool_get_report_bounces
  - mcp__cogny__mcp__Get_a_Newsletter__tool_get_report_opens
  - mcp__cogny__mcp__Get_a_Newsletter__tool_get_report_opens_aggregated
  - mcp__cogny__mcp__Get_a_Newsletter__tool_get_report_have_not_opened
  - mcp__cogny__mcp__Get_a_Newsletter__tool_get_report_clicks
  - mcp__cogny__mcp__Get_a_Newsletter__tool_get_report_link_clicks
  - mcp__cogny__mcp__Get_a_Newsletter__tool_get_report_unsubscriptions
  - mcp__cogny__mcp__Get_a_Newsletter__tool_list_attributes
  - mcp__cogny__mcp__Get_a_Newsletter__tool_list_subscriptions
  - mcp__cogny__mcp__Get_a_Newsletter__tool_list_senders
  - mcp__cogny__mcp__Get_a_Newsletter__tool_get_sender
  # Newer ESPs and stores: read tools only (writes ask first)
  - mcp__cogny__mcp__Brevo__list_contacts
  - mcp__cogny__mcp__Brevo__get_contact
  - mcp__cogny__mcp__Brevo__list_contact_lists
  - mcp__cogny__mcp__MailerLite__list_subscribers
  - mcp__cogny__mcp__MailerLite__get_subscriber
  - mcp__cogny__mcp__MailerLite__list_groups
  - mcp__cogny__mcp__MailerLite__list_segments
  - mcp__cogny__mcp__Drip__list_subscribers
  - mcp__cogny__mcp__Drip__get_subscriber
  - mcp__cogny__mcp__Drip__list_tags
  - mcp__cogny__mcp__Salesforce_Marketing_Cloud__list_data_extensions
  - mcp__cogny__mcp__Salesforce_Marketing_Cloud__get_data_extension_fields
  - mcp__cogny__mcp__Salesforce_Marketing_Cloud__get_data_extension_rows
  - mcp__cogny__mcp__Braze__braze_list_segments
  - mcp__cogny__mcp__Braze__braze_get_segment_details
  - mcp__cogny__mcp__Braze__braze_get_segment_analytics
  - mcp__cogny__mcp__Shopify__tool_list_customers
  - mcp__cogny__mcp__Shopify__tool_list_orders
  - mcp__cogny__mcp__WooCommerce__list_orders
  - mcp__cogny__mcp__Stripe__stripe_api_read
  - mcp__cogny__list_integrations
  - mcp__cogny__create_finding
  - mcp__cogny__create_ticket
  - mcp__cogny__write_context_node
  # Cogny Solo / Lite (per-ESP direct) namespace
  - mcp__klaviyo__*
  - mcp__mailchimp__*
  - mcp__rule__*
  - mcp__get_a_newsletter__*
  - Bash
  - Read
  - Write
---

# Winback Engine

Turn dormant subscribers back into customers. This skill scans your connected ESP for inactive subscribers, segments them by historical value, drafts a personalized winback series per tier, and flags who you should suppress before they tank your deliverability.

**Requires:** Cogny MCP + a connected ESP. [Sign up](https://cogny.com)

The output is a complete, ready-to-run winback campaign — not a report.

## Usage

`/winback-engine` — standard mode (60-day dormancy threshold)
`/winback-engine aggressive` — 30-day threshold (acts earlier, bigger list)
`/winback-engine conservative` — 90-day threshold (only chronic dormants)

## Step 0: Is Cogny connected?

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

```
Winback Engine needs your marketing data through Cogny's MCP gateway.

1. Sign up at https://cogny.com and connect your ESP (Klaviyo, Mailchimp, Rule, Get a Newsletter, Brevo, MailerLite, Drip, Salesforce Marketing Cloud or Braze); Shopify, WooCommerce or Stripe adds purchase value.
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.
```

## Prerequisites Check

Detect connected ESP (same pattern as subject-line-lab; on Cloud, `mcp__cogny__list_integrations`). If Cogny is connected but no ESP is, say "connect your ESP in Cogny" and stop. Also note whether a store (Shopify, WooCommerce) or, for SaaS, Stripe is connected — it supplies purchase data for ESPs that have none.

**Health check:** `health_status` misses revoked tokens, so make one cheap read per integration before relying on it (e.g. Mailchimp `tool_get_account_info`, Get a Newsletter `tool_list_senders`, Klaviyo `get_account`, Shopify `tool_list_customers` with a small page, Stripe `stripe_api_read` `GetSubscriptions` with `limit: 1`). A 401, Forbidden or scope error means 🔴 "reconnect <integration> in Cogny": name it, don't retry, and continue with what remains.

**Missing tool:** if a tool named here isn't exposed by the workspace, call `mcp__cogny__refresh_mcp_discovery` once, use the fallback named next to the tool for this run, mark that source ⚠ "needs reconnect", and tell the user to reconnect the Cogny MCP. Never loop on refresh. Get a Newsletter fallbacks: `tool_get_report_have_not_opened` → that report's list contacts minus the openers from `tool_get_report_opens`; `tool_get_report_link_clicks` → `tool_get_report_opens` (per-contact click counts) or `tool_get_report_clicks` (per-link totals); `tool_get_report_opens_aggregated` → the totals in `tool_get_report`. Mailchimp `tool_get_campaign_content` → `tool_get_campaign` for the headers, and ask the user for the body.

**ESP connected but 0 sends in the window:** skip it with a one-line note ("Rule: connected, 0 sends in the last <threshold> days — no engagement to tier; see step 2 for never-mailed contacts").

## Works with

| ESP (Prefix) | Subscribers + engagement | Purchase / LTV | Suppression write (asks first) | Coverage |
|--------------|--------------------------|----------------|--------------------------------|----------|
| Klaviyo (`Klaviyo`) | `list_profiles`, `get_profile` | `list_events` (Placed Order metric) | `unsubscribe_profiles` | Full |
| Mailchimp (`Mailchimp`) | `tool_list_members` | store join | `tool_update_member` | Full, engagement-tiered |
| Rule (`Rule`) | `tool_list_subscribers`, `tool_list_suppressions` | store join | `tool_update_subscriber` | Full, engagement-tiered |
| Get a Newsletter (`Get_a_Newsletter`) | `tool_list_contacts` (**no engagement fields**) + `tool_get_report_opens` (paged, per report) to rebuild engagement | store join | `tool_update_contact` / `tool_delete_contact` | Partial: last-engaged is rebuilt from recent reports only, so it can't see engagement older than the reports you page through |
| Brevo (`Brevo`) | `list_contacts` (`modified_since`), `get_contact` (per-contact `statistics` with open/click events) | store join | `update_contact` (`email_blacklisted: true`) | Full, but last-engaged needs one `get_contact` per contact — sample if the list is large |
| MailerLite (`MailerLite`) | `list_subscribers` (`filter_status: "active"`): lifetime `opens_count`, `clicks_count`, `open_rate`, `subscribed_at` | store join | `upsert_subscriber` (`status: "unsubscribed"`) | No last-open date: tier on lifetime rates + tenure, and say so |
| Drip (`Drip`) | `list_subscribers` (`status: "active"`, `tags`) | subscriber `lifetime_value` (when a store integration feeds Drip) | `unsubscribe_from_all` | No per-subscriber last-open date; use `lifetime_value` + tags |
| Salesforce Marketing Cloud (`Salesforce_Marketing_Cloud`) | `list_data_extensions` → `get_data_extension_fields` → `get_data_extension_rows` (`row_filter`) on an engagement or customer data extension | same, if the data extension holds orders | none in the MCP; hand over the list | Only if such a data extension exists; rows are PII, fetch only what's needed |
| Braze (`Braze`) | `braze_list_segments` → `braze_get_segment_details` / `braze_get_segment_analytics` (sizes only) | — | none in the MCP | **Partial:** sizes existing lapsed segments; can't list users, so tiers and the suppression list are recommendations to build in Braze |
| Symplify, Drip broadcasts | — | — | — | Symplify has no bulk contact read (only `get_contact` by id), so winback isn't possible there |

**Store join (any ESP):** `mcp__cogny__mcp__Shopify__tool_list_customers` returns `numberOfOrders` and `amount_spent` per customer email; WooCommerce `list_orders` (`after`, `status: "completed"`) gives order history. For SaaS, Stripe `stripe_api_read` `GetSubscriptions` (`status: "all"`) gives active vs cancelled customers and `GetInvoices` (`status: "paid"`) the billed total per customer (LTV); treat cancelled subscribers as past purchasers. Join on lowercased email to turn engagement-only tiers into value tiers. If Stripe's `email`/`customer_email` comes back `[REDACTED]` (a restricted key), skip the Stripe join and say so ("Stripe emails redacted by the restricted key: tiers stay engagement-only"). Page Stripe with `limit` 20–25 and `starting_after` (a 100-row page is ~370KB). Name the source ("LTV from Shopify"), use the store currency, and never mix ESP-attributed revenue with store revenue.

## Steps

### 1. Define dormancy thresholds

| Mode | Dormant | Deep dormant | Suppress candidate |
|------|---------|--------------|-------------------|
| aggressive | 30+ days no open | 90+ days no open | 180+ days no open/click, no purchase |
| standard | 60+ days | 180+ days | 365+ days no engagement |
| conservative | 90+ days | 270+ days | 540+ days |

### 2. Pull subscriber data

From the connected ESP, pull every active subscriber with:
- Subscribe date
- Last open date + last click date (take max as last_engaged)
- Total historical opens / clicks
- Signup source / list
- Tags / segments
- Email domain (gmail, yahoo, hotmail, corporate)

**Purchase / LTV data — Klaviyo, Drip (`lifetime_value`), or a connected store.** The cogny-mcp-proxy exposes purchase data in Klaviyo (via `list_events` filtered to the "Placed Order" metric, summing the `value` field per profile) and Drip. With Shopify or WooCommerce connected, use the store join above for any ESP. Otherwise Mailchimp, Rule, Get a Newsletter, Brevo and MailerLite are **engagement-only** — they do not expose:
- Total spend / LTV
- Order count
- AOV
- Last order date

**Get a Newsletter engagement rebuild:** `tool_list_contacts` returns no open or click fields. Rebuild them per contact: list the sends in the window with `tool_list_sent` (each row has subject, send time and `report_id`), skip test sends (under 10 recipients or "test" in the subject), then page through `tool_get_report_opens` for each `report_id` (each row: email, opens, clicks). A contact's last_engaged is the send time of the latest report they appear in; lifetime opens/clicks are the sums. `tool_get_report_opens` returns **only openers**, so "mailed but never opened" has to be derived: use `tool_get_report_have_not_opened` if the workspace exposes it; otherwise take the contacts on the lists that send targeted (`tool_get_sent`, matched against each contact's `lists`) whose `created` is before the send time, minus that report's openers. Cover at least the deep-dormant threshold (e.g. 180 days in standard mode) and state the date range, because engagement older than the oldest report read is invisible.

**Last send older than the dormancy threshold:** if the ESP's most recent send is older than the dormant threshold, every contact is dormant by default. That says nothing about the people; it means the program stopped sending. Say so up front, tier only contacts who were actually mailed, and treat the cadence gap as the main finding.

**Never-mailed contacts:** contacts created after the last send (Get a Newsletter: `tool_list_contacts` with `created_gt` = last send time), or on lists no send has targeted, have never received an email. They aren't dormant, so keep them out of the tiers and the suppression list: count them separately and route them to `/welcome-series`.

**Per-ESP tool adapter:**

| ESP | Subscriber list | Purchase history | Suppression write |
|-----|-----------------|------------------|-------------------|
| Klaviyo | `list_profiles` (+ `get_profile` for detail) | `list_events` with `metric="Placed Order"` — use `value` field per profile for LTV | `unsubscribe_profiles` |
| Mailchimp | `tool_list_members` (filter `status=subscribed`) | **Not available** | `tool_update_member` (status=unsubscribed) |
| Rule | `tool_list_subscribers` | **Not available** | `tool_update_subscriber` / `tool_list_suppressions` |
| Get a Newsletter | `tool_list_contacts` + `tool_get_report_opens` (engagement rebuild above) | **Not available** | `tool_delete_contact` or `tool_update_contact` |
| Brevo | `list_contacts` + `get_contact` | **Not available** (store join) | `update_contact` (`email_blacklisted`) |
| MailerLite | `list_subscribers` | **Not available** (store join) | `upsert_subscriber` (`status`) |
| Drip | `list_subscribers` | `lifetime_value` on the subscriber | `unsubscribe_from_all` |
| SFMC | `get_data_extension_rows` | only if a data extension holds it | not exposed |
| Braze | segment sizes only | not exposed per user | not exposed |

### 3. Segment into tiers

**If Klaviyo, Drip with `lifetime_value`, or any ESP + store join (has purchase data):** cross-cut by **engagement recency** × **historical value**:

| Tier | Criteria | Tone | Offer |
|------|----------|------|-------|
| **A — High value dormant** | Dormant + LTV ≥ top quartile OR past purchaser | Personal, apologetic, premium | Strong (20% off, free shipping, exclusive access). This is real money. |
| **B — Medium value dormant** | Dormant + some past engagement or 1 purchase | Warm, value-forward | Moderate (10–15% off, bundle, content) |
| **C — Low engagement dormant** | Dormant + never purchased + low engagement history | Direct, honest | Last-chance offer or content-only |
| **D — Suppression candidates** | Deep dormant + no purchase + no recent engagement | Final email only | "We're removing you unless..." |

**If engagement-only (Mailchimp / Rule / Get a Newsletter / Brevo / MailerLite with no store connected):** tier by **engagement depth** instead. LTV-based tiering falls back to:

| Tier | Criteria | Tone | Offer |
|------|----------|------|-------|
| **A — Deep engaged dormant** | Dormant now, but historically high open+click rate (top quartile of clicks) | Personal, "we miss you" | Strong offer or exclusive content |
| **B — Casual dormant** | Dormant, moderate historical engagement | Warm, value-forward | Modest offer |
| **C — Low engagement dormant** | Dormant, few lifetime opens/clicks | Direct, honest | Content-only or re-opt-in ask |
| **D — Suppression candidates** | Deep dormant, minimal lifetime engagement | Final email only | Goodbye |

Revenue estimates in the output should be omitted for engagement-only ESPs, or marked `estimated_impact_usd: null` on findings with a note that the user can pair with their own LTV data to size the opportunity.

Output the tier sizes before drafting:

```
Winback candidates: <total>
├─ Tier A (high-value dormant):   <count> subscribers (est. revenue: $<X>)
├─ Tier B (medium):               <count>
├─ Tier C (low engagement):       <count>
└─ Tier D (suppression):          <count>  ← do not keep sending to these

Never mailed (not tiered):        <count>  → run /welcome-series
```

**Revenue estimate for Tier A/B:** `count × historical AOV × expected reactivation rate` (use 3-5% for Tier A, 1-2% for Tier B).

### 4. Draft a 3-email winback series per tier

For each tier (A, B, C), generate 3 emails with cadence:
- **Email 1** — day 0, soft reopener ("we noticed")
- **Email 2** — day 4, value + offer
- **Email 3** — day 8, last-chance / decision

Tone by tier:

**Tier A (high-value):**
- E1: Personal note, reference last purchase by name if available. No offer yet.
- E2: Show what they're missing — new products in their category, or customer stories
- E3: Strongest offer, explicit decision framing ("if we're not a fit anymore, we'll respect that")

**Tier B (medium):**
- E1: "We miss you" + social proof
- E2: Content-led (best of what they missed) + modest offer
- E3: Offer + deadline

**Tier C (low engagement):**
- E1: Direct — "is this still useful?"
- E2: One-click re-subscribe or one-click unsubscribe (reduce friction)
- E3: Final send before suppression

For every email produce: subject, preheader, body, CTA. Same format as `/welcome-series`.

### 5. Suppression list (Tier D)

Output a block the user can act on:

```
Suppression recommendation: <count> subscribers

These haven't opened, clicked, or purchased in <threshold> days. Keeping
them on the list:
  • Hurts deliverability (low engagement = more spam placement for everyone)
  • Inflates list size → higher ESP costs
  • Distorts reporting baselines

Recommended action:
  1. Send ONE final "goodbye" email offering resubscribe
  2. After 7 days, suppress non-responders

Sample suppression email is included below.
```

Then include the goodbye email draft.

### 6. Write-mode: offer to execute

After presenting the plan, ask:

```
I can push this into your ESP as:
  [A] Drafts only (you review + launch)
  [B] Full flow installed but paused (you activate when ready)
  [C] Just give me the copy, I'll handle it

Which?
```

If the user picks A or B and the ESP MCP has write tools available, follow the **Write Action Protocol** (same as the `/cogny` skill — present the action plan, wait for approval, then execute one step at a time).

Draft-capable writes for the newer ESPs (each asks first): Brevo `create_email_campaign` (omit `scheduled_at` to keep it a draft), MailerLite `create_campaign` (then `schedule_campaign` only on approval), Drip `apply_tag` to enter an existing winback workflow. SFMC and Braze have no write tools in the MCP: deliver copy + segment definitions only (option C).

### 7. Record findings

For each significant tier (A, B with >100 subscribers), and for a never-mailed group or a stopped send cadence, record a finding. On Cloud call `create_ticket` first (fields mapped per section 2 of the routing guide); on Solo call `create_finding`:

```json
{
  "title": "Tier A winback: <N> high-value dormant subscribers, est. $<X> recoverable",
  "body": "Identified <N> past purchasers with LTV in top quartile who haven't engaged in <days> days. Avg historical AOV: $<Y>. At 4% reactivation, estimated winback revenue = $<X>. 3-email series drafted and ready to install.",
  "action_type": "winback_campaign",
  "expected_outcome": "Reactivate 3-5% of Tier A dormant, generate $<X> over 30 days",
  "estimated_impact_usd": <X>,
  "priority": "high"
}
```

And one for suppression:

```json
{
  "title": "<N> subscribers recommended for suppression",
  "body": "Deep dormant (<threshold>+ days) with no purchases. Keeping them hurts deliverability and inflates ESP cost. Recommend goodbye email + suppression after 7 days.",
  "action_type": "list_hygiene",
  "expected_outcome": "Improve overall open rate by 1-3 pp, lower ESP tier cost",
  "estimated_impact_usd": <monthly_esp_savings>,
  "priority": "medium"
}
```

## Notes

- **Never suppress before a winback attempt.** Give Tier D subscribers one last chance to re-engage.
- Apple MPP means "last open" is noisy for iPhone users. Weight **clicks** and **purchases** higher than opens when assigning tiers.
- **Purchase/LTV data** comes from Klaviyo events, Drip `lifetime_value`, a connected Shopify/WooCommerce store, or Stripe for SaaS. Without one of those, Mailchimp, Rule, Get a Newsletter, Brevo and MailerLite fall back to the engagement-only tiering scheme above.
- **Several ESPs connected:** tier each list separately and show them side by side. A person on two lists counts once per ESP; don't add tier sizes or revenue estimates across ESPs.
- **Get a Newsletter has no flow/automation object.** "Install as a flow" isn't available — winback is delivered as scheduled individual sends via `tool_send_draft` with `time_to_send`. For Klaviyo, flows install via the Klaviyo UI (the MCP exposes `list_flows`/`get_flow` for reads only, not create). For Mailchimp/Rule, automations/journeys are read-only too — so "install" means drafting campaigns and scheduling them, not creating a native automation.

## 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`.