campaign-sequencer

Multi-channel drip sequence orchestrator that builds and executes outbound campaigns across email, Slack, and direct messages. Triggers when the user asks to set up an outbound campaign, drip sequence, multi-channel outreach, or creator outreach program. Coordinates Clay enrichment, Gmail drafts, Slack DMs, and scheduled follow-ups with full state tracking in Supabase. Enforces send limits, opt-out compliance, and batch confirmation before any messages go out.

Campaign Sequencer

Multi-channel drip sequence orchestrator for outbound campaigns.

When to Trigger

Activate this skill when the user:

  • Asks to set up an outbound campaign or drip sequence
  • Wants to run multi-channel outreach (email + Slack + DM)
  • Requests creator outreach, partnership outreach, or cold outreach programs
  • Needs to schedule follow-up messages across multiple touchpoints
  • Says "campaign", "drip", "sequence", "outreach", "nurture", or "cadence"

MCP Tool Mappings

This skill orchestrates across five MCP servers. Always verify each server is connected before starting.

MCP ServerTools UsedPurpose
Clayfind-and-enrich-company, find-and-enrich-contacts-at-company, add-contact-data-pointsLead enrichment and data append
Gmailgmail_create_draft, gmail_search_messagesEmail composition and reply detection
Slackslack_send_message, slack_search_usersSlack DM outreach
Scheduled Taskscreate_scheduled_taskDelayed follow-up scheduling
Supabaseexecute_sqlState tracking and analytics

Stage Template System

Define each stage of the sequence with these fields:

stages:
  - id: 1
    name: "Initial Outreach"
    channel: email          # email | slack | dm
    timing: "Day 0"         # Relative to sequence start
    template: "intro_email"
    fallback_channel: slack  # If primary channel unavailable

  - id: 2
    name: "Follow-up Nudge"
    channel: email
    timing: "Day 3"
    template: "follow_up_1"
    skip_if: replied         # Skip if contact already replied

  - id: 3
    name: "Slack Touch"
    channel: slack
    timing: "Day 5"
    template: "slack_casual"
    skip_if: replied

  - id: 4
    name: "Final Follow-up"
    channel: email
    timing: "Day 7"
    template: "break_up_email"
    skip_if: replied

Channel Definitions

  • email: Uses Gmail MCP to create drafts. User reviews and sends, or auto-send if explicitly approved.
  • slack: Uses Slack MCP to send DMs. Requires the contact's Slack workspace membership.
  • dm: Platform-specific DM (Twitter, Discord). Manual send -- skill generates the message text only.

Sequence Workflow

Execute these steps in order. Report progress after each step.

Step 1: Define Target List

Pull contacts from Supabase or accept manual input.

-- Example: pull from an existing prospects table
SELECT id, first_name, last_name, email, company, linkedin_url
FROM prospects
WHERE campaign_id IS NULL
  AND unsubscribed = false
ORDER BY created_at DESC
LIMIT 50;

If no Supabase table exists, accept a list of names/emails/companies from the user and create the tracking table (see State Machine below).

Step 2: Enrich Each Contact via Clay

For each contact in the target list:

  1. Call find-and-enrich-company with the company name or domain
  2. Call find-and-enrich-contacts-at-company to get role, seniority, tech stack
  3. Call add-contact-data-points to append social profiles, recent funding, headcount

Store enrichment results back to Supabase for use in personalization.

Step 3: Score Leads

Invoke the lead-scorer skill if available. Pass enriched contact data and receive a score + tier.

For each contact:
  score = lead-scorer(contact_data)
  UPDATE prospects SET score = {score}, tier = {tier} WHERE id = {contact_id};

Filter out contacts with tier = "Skip" (score < 20). Flag "Hot" leads (80+) for priority sequencing.

Step 4: Generate Personalized Messages

Invoke the template-personalizer skill for each stage and each contact.

Pass:

  • Template ID from the stage definition
  • Contact enrichment data from Clay
  • Tone setting from user preference
  • Personalization depth level (L1/L2/L3 based on tier)

Hot leads get L3 (hyper-personalized). Warm get L2. Cold get L1.

Step 5: Queue Day 0 Actions

For all contacts, execute the first stage immediately:

  • Email: Call gmail_create_draft with personalized subject and body
  • Slack: Call slack_search_users to find the user, then slack_send_message
  • DM: Output the message text for manual sending

Update state to contacted in Supabase after each send.

Step 6: Schedule Follow-ups

For stages with timing beyond Day 0, use Scheduled Tasks MCP:

For each future stage:
  create_scheduled_task({
    name: "campaign_{campaign_id}_contact_{contact_id}_stage_{stage_id}",
    scheduled_time: now() + stage.timing,
    task: {
      action: "send_message",
      channel: stage.channel,
      contact_id: contact_id,
      template: stage.template
    }
  })

Before scheduling, check if the contact has already replied (query Gmail or Slack). If replied, skip remaining stages.

Step 7: Track Opens and Replies

Set up monitoring queries:

-- Check for replies (run daily or before each scheduled send)
SELECT p.id, p.email, p.state
FROM prospects p
WHERE p.campaign_id = {campaign_id}
  AND p.state = 'contacted'
  AND p.last_stage_sent_at < NOW() - INTERVAL '1 day';

Use gmail_search_messages to check for replies from each contact's email. Update state to replied when found.

State Machine

Each contact progresses through these states:

new --> enriched --> contacted --> replied --> converted
                        |                        |
                        +----> churned <---------+
StateMeaningTransition Trigger
newAdded to campaign, not yet enrichedContact added to target list
enrichedClay enrichment completeEnrichment data returned
contactedAt least one message sentFirst stage executed
repliedContact responded on any channelReply detected via Gmail/Slack search
convertedContact completed desired action (meeting, signup)Manual update by user
churnedAll stages exhausted with no reply, or opted outFinal stage sent with no response

Supabase Schema

CREATE TABLE IF NOT EXISTS campaign_contacts (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  campaign_id TEXT NOT NULL,
  contact_email TEXT NOT NULL,
  first_name TEXT,
  last_name TEXT,
  company TEXT,
  role TEXT,
  state TEXT DEFAULT 'new' CHECK (state IN ('new','enriched','contacted','replied','converted','churned')),
  score INTEGER,
  tier TEXT,
  enrichment_data JSONB,
  current_stage INTEGER DEFAULT 0,
  last_stage_sent_at TIMESTAMPTZ,
  created_at TIMESTAMPTZ DEFAULT NOW(),
  updated_at TIMESTAMPTZ DEFAULT NOW(),
  unsubscribed BOOLEAN DEFAULT FALSE
);

CREATE INDEX idx_campaign_state ON campaign_contacts(campaign_id, state);

Safety Rules

These are non-negotiable. The skill must enforce all of them.

  1. Never send to unsubscribed contacts. Check unsubscribed = false before every send.
  2. Always include opt-out. Every email must end with: "Reply STOP to opt out of future messages."
  3. Max 50 contacts per batch. If the target list exceeds 50, split into batches and confirm each.
  4. Require confirmation before sending. Present a summary table (contact, channel, message preview) and wait for explicit user approval before executing sends.
  5. No duplicate sends. Check state before each send -- never re-send a stage that was already delivered.
  6. Rate limiting. Space emails at least 30 seconds apart to avoid spam flags.
  7. Reply detection before follow-ups. Always check for replies before sending any follow-up stage. If the contact replied, skip all remaining stages and update state.
  8. No weekends or late nights. Schedule sends for business hours (9 AM - 6 PM in the contact's timezone) on weekdays only.

Example Sequence: Creator Program Outreach

Target: Web3 developers and content creators for a developer ambassador program.

campaign:
  name: "Creator Program Q2 2026"
  goal: "Recruit 20 developer ambassadors"
  total_targets: 40
  tone: "CT-style"
  personalization_depth: "L3 for Hot, L2 for Warm"

stages:
  - id: 1
    name: "Warm Intro"
    channel: email
    timing: "Day 0"
    template: |
      Subject: Your {{recent_achievement}} caught my eye

      Hey {{first_name}},

      Saw your {{recent_achievement}} -- legit impressive work.
      We're building a creator program for devs who ship,
      and your background in {{tech_stack}} is exactly what
      we're looking for.

      Quick 15-min call this week? No pitch deck, just vibes.

      Reply STOP to opt out of future messages.

  - id: 2
    name: "Value Add"
    channel: slack
    timing: "Day 3"
    template: |
      hey {{first_name}} -- dropped you an email earlier this week
      about our creator program. thought you might also find this
      useful: [relevant resource link]. no pressure, just sharing.

  - id: 3
    name: "Social Proof"
    channel: email
    timing: "Day 5"
    template: |
      Subject: {{mutual_connection}} just joined -- thought of you

      {{first_name}},

      {{mutual_connection}} from {{mutual_company}} just came on
      board as a creator. Given your overlap in {{tech_stack}},
      figured you'd want to know.

      Interested? Just reply and I'll send details.

      Reply STOP to opt out of future messages.

  - id: 4
    name: "Last Call"
    channel: email
    timing: "Day 7"
    template: |
      Subject: closing the loop

      {{first_name}} -- wanted to follow up one last time.
      If the timing isn't right, totally get it. If you want
      in on the creator program, just reply and we'll make it
      happen.

      Either way, keep shipping.

      Reply STOP to opt out of future messages.

Reporting

After campaign execution, generate a summary:

Campaign: Creator Program Q2 2026
Total Contacts: 40
Enriched: 38 (2 failed enrichment)
Contacted: 36 (2 scored as Skip)
Replied: 12 (33% reply rate)
Converted: 8 (22% conversion rate)
Churned: 24

Top performing stage: Stage 1 (8 replies)
Best channel: Email (10 replies vs 2 Slack)
Average score of converted leads: 84

Store the report in Supabase and present it as a formatted table.