---
name: create-ab-test
description: Create a Sellable campaign A/B test by duplicating a full Campaign A.
visibility: public
allowed-tools:
  - mcp__sellable__get_auth_status
  - mcp__sellable__start_cli_login
  - mcp__sellable__wait_for_cli_login
  - mcp__sellable__bootstrap_create_campaign
  - mcp__sellable__get_subskill_prompt
  - mcp__sellable__get_subskill_asset
  - mcp__sellable__search_subskill_prompts
  - mcp__sellable__get_provider_prompt
  - mcp__sellable__get_source_scout_registry
  - mcp__sellable__get_post_find_leads_scout_registry
  - mcp__sellable__get_active_workspace
  - mcp__sellable__list_workspaces
  - mcp__sellable__set_active_workspace
  - mcp__sellable__list_senders
  - mcp__sellable__get_sender
  - mcp__sellable__fetch_linkedin_profile
  - mcp__sellable__fetch_linkedin_posts
  - mcp__sellable__get_linkedin_profile
  - mcp__sellable__fetch_company
  - mcp__sellable__fetch_company_posts
  - mcp__sellable__complete_sender_research
  - mcp__sellable__lookup_sales_nav_filter
  - mcp__sellable__search_sales_nav
  - mcp__sellable__search_prospeo
  - mcp__sellable__search_prospeo_companies
  - mcp__sellable__confirm_prospeo_company_accounts
  - mcp__sellable__search_harvest_jobs
  - mcp__sellable__confirm_harvest_job_companies
  - mcp__sellable__search_signals
  - mcp__sellable__fetch_post_engagers
  - mcp__sellable__enrich_with_prospeo
  - mcp__sellable__bulk_enrich_with_prospeo
  - mcp__sellable__save_domain_filters
  - mcp__sellable__add_rubric_item
  - mcp__sellable__upsert_rubric
  - mcp__sellable__set_headline_icp_criteria
  - mcp__sellable__check_rubric
  - mcp__sellable__create_campaign
  - mcp__sellable__update_campaign_brief
  - mcp__sellable__update_campaign
  - mcp__sellable__save_rubrics
  - mcp__sellable__get_campaign
  - mcp__sellable__get_campaign_context
  - mcp__sellable__get_campaign_framework
  - mcp__sellable__get_campaign_navigation_state
  - mcp__sellable__get_campaign_messages_preview
  - mcp__sellable__get_campaign_table_schema
  - mcp__sellable__select_campaign_cells
  - mcp__sellable__queue_campaign_cells
  - mcp__sellable__wait_for_campaign_processing
  - mcp__sellable__revise_message_template_and_rerun
  - mcp__sellable__confirm_lead_list
  - mcp__sellable__import_leads
  - mcp__sellable__duplicate_campaign
  - mcp__sellable__prepare_campaign_ab_test
  - mcp__sellable__list_dnc_entries
  - mcp__sellable__load_csv_dnc_entries
  - mcp__sellable__load_csv_linkedin_leads
  - mcp__sellable__load_csv_domains
  - mcp__sellable__wait_for_lead_list_ready
  - mcp__sellable__wait_for_campaign_table_ready
  - mcp__sellable__get_rows
  - mcp__sellable__get_table_rows
  - mcp__sellable__get_rows_minimal
  - mcp__sellable__attach_sequence
  - mcp__sellable__attach_recommended_sequence
---

# Sellable Create A/B Test

Use this workflow when the user asks to create an A/B campaign test, split a
campaign into variants, duplicate a campaign for copy testing, or compare two
campaign-message approaches from the same source list.

## Opening Contract

Start by identifying the campaign idea and the one variable being tested.
Campaign A must be a real, fully prepared Sellable campaign before this A/B
helper runs. If the user only supplied an idea, this skill must first execute
the normal `$sellable:create-campaign` workflow for Campaign A in the same run:
bootstrap create-campaign, load `create-campaign-v2` and
`core/flow.v2.json`, research the sender/company, create the campaign shell,
build and approve the campaign brief, source or attach leads when appropriate,
save any approved ICP filters, and get the message/template state into the
campaign brief. Do not call
`prepare_campaign_ab_test` with only `campaignName`/`campaignBrief`.

Once Campaign A exists, the A/B step duplicates Campaign A through Sellable's
product duplicate path and applies only the B variant delta. This preserves the
approved brief, ICP filters, message setup, rubrics, and campaign-table
structure so the test differs only by the chosen variable and, if approved, the
split lead list.

## Required Flow

1. Decide the source mode:
   - Existing Campaign A: confirm the source campaign ID or resolve it with
     `get_campaign`.
   - Idea-only request: run the full create-campaign workflow inline first,
     through `bootstrap_create_campaign`, `get_subskill_prompt({
     subskillName: "create-campaign-v2" })`, and `get_subskill_asset({
     subskillName: "create-campaign-v2", assetPath: "core/flow.v2.json" })`.
     Use the created campaign ID as `sourceCampaignId`.
2. Confirm the A/B variable in plain language. Keep variant B as the explicit
   change and leave variant A as the control unless the user names an A change.
3. Inspect Campaign A with `get_campaign` and `get_campaign_context`. Confirm
   the brief exists and includes the approved messaging/template state when the
   campaign has reached message review.
4. If Campaign A has a clean `selectedLeadListId`, ask the user whether to split
   Campaign A's lead list for this A/B test:
   - Split the lead list: pass that clean list as `sourceLeadListId`.
   - Do not split yet: omit `sourceLeadListId`; Campaign B is a duplicate for
     review and no rows are imported.
   Never silently split a list just because Campaign A has one.
5. If a source lead list is supplied, verify it is clean. A clean source list is
   a lead-list or signal-lead-list table, not the generated campaign workflow
   table.
6. Call `prepare_campaign_ab_test` with `dryRun: true` first.
7. Review split counts when applicable, campaign names, and variant brief deltas
   with the user.
8. Only after review, call `prepare_campaign_ab_test` without `dryRun` using the
   same `idempotencyKey` if one was returned or supplied.
9. Return Campaign A, duplicated Campaign B, split lead-list IDs when supplied,
   counts, and the explicit note that both campaigns are `not_started`.

## Tool Inputs

Use one of these shapes:

- No split: pass `sourceCampaignId`, `variantName`, `variantBriefDelta`, and
  any optional A-variant fields. The helper treats the source campaign as A and
  duplicates it for B.
- Approved split: pass `sourceCampaignId`, the approved clean
  `sourceLeadListId`, `variantName`, `variantBriefDelta`, and any optional split
  or A-variant fields. The helper creates deterministic A/B split lead lists and
  review-copy campaigns from Campaign A.

Do not pass `campaignName`, `campaignBrief`, `offerPositioning`,
`clientProspectId`, or `senderLinkedinUrl` to `prepare_campaign_ab_test`.
Those belong to the full create-campaign workflow that creates Campaign A.

## Anti-Patterns

- Do not call `export_table_csv` from an enriched/generated campaign workflow
  table as the lead source for A/B splitting.
- Do not reimport workflow output columns such as `ICP Score`, `Passes Rubric`,
  `Generate Message`, `Message`, `Approved`, scheduling, status, result, or
  error columns.
- Do not use broad workflow-table selectors to split decorated campaign rows.
- Do not call `start_campaign`, approve launch, attach senders for launch, or
  trigger live sends in this workflow.

## Clean Source Fallback

If the source campaign has no clean source lead list, or the source list is
polluted with workflow/output columns, ask for the original CSV or clean source
list. Use `load_csv_linkedin_leads`; it strips Sellable workflow columns if a
contaminated CSV is supplied, then creates a clean lead list. If no clean source
is available, omit `sourceLeadListId` and create only the B duplicate for review.

## Output Contract

Report:

- source Campaign A ID
- source lead-list ID when supplied
- split strategy and counts when a source lead list was supplied
- duplicate/skipped lead counts when a source lead list was supplied
- Campaign A ID, or A review-copy campaign ID when a split was approved
- duplicated Campaign B ID
- split lead-list IDs when supplied
- variant difference
- `launchState: not_started` for both campaigns
