Campaign Types & Schema
Purpose: TypeScript schemas and types for all campaign playbooks
Use: Import these schemas in your message sequence agent
Status: Reference Implementation
Last Updated: 2026-01-26
Core Types
Campaign Type Enum
export type CampaignType =
| 'event-follow-up'
| 'mutual-intro'
| 'partnership-outreach'
| 'product-launch'
| 'content-syndication'
| 're-engagement'
| 'cold-outbound'
| 'referral-request';Campaign-Specific Segments
Event Follow-Up Segments
export type EventFollowUpSegment =
| 'booth-visitor'
| 'panelist-speaker'
| 'vip-dinner'
| 'meeting-log'
| 'general-attendee';
export interface EventFollowUpContext {
eventName: string;
eventDate: Date;
eventType: 'conference' | 'dinner' | 'meetup' | 'demo-day' | 'panel';
interactionType: EventFollowUpSegment;
conversationTopics?: string[];
boothNumber?: string;
panelTopic?: string;
meetingNotes?: string;
}Mutual Introduction Segments
export type MutualIntroSegment =
| 'warm-intro-executive'
| 'warm-intro-peer'
| 'cold-intro-context'
| 'multi-hop-intro';
export interface MutualIntroContext {
introducerName: string;
introducerRelationship: 'investor' | 'customer' | 'partner' | 'advisor' | 'peer';
introducerContext: string;
sharedConnections?: string[];
introMessage?: string;
urgency: 'high' | 'medium' | 'low';
}Partnership Outreach Segments
export type PartnershipSegment =
| 'cold-partner-rep'
| 'engaged-partner-rep'
| 'active-deal-support'
| 'partner-leadership'
| 'ecosystem-intro';
export interface PartnershipContext {
partnerName: string;
partnerType: 'technology' | 'referral' | 'reseller' | 'services';
repName?: string;
repTitle?: string;
accountsShared?: string[];
activationGoal?: string;
slackChannelActive?: boolean;
}Product Launch Segments
export type ProductLaunchSegment =
| 'active-user'
| 'churned-user'
| 'prospect-good-fit'
| 'prospect-early-stage'
| 'waitlist-member';
export interface ProductLaunchContext {
productName: string;
releaseDate: Date;
featureType: 'major' | 'minor' | 'integration' | 'improvement';
relevanceToProspect: string;
usageHistory?: {
lastActive?: Date;
featureUsage?: string[];
churnReason?: string;
};
}Content Syndication Segments
export type ContentSegment =
| 'by-persona'
| 'by-industry'
| 'by-engagement-history'
| 'by-funnel-stage';
export interface ContentContext {
contentType: 'blog' | 'case-study' | 'whitepaper' | 'webinar' | 'guide';
contentTitle: string;
contentUrl: string;
publishDate: Date;
targetPersona: PersonaType;
targetIndustry?: string;
relevanceReason: string;
}Re-engagement Segments
export type ReEngagementSegment =
| 'inactive-prospect'
| 'stalled-deal'
| 'churned-customer'
| 'ghosted-conversation';
export interface ReEngagementContext {
lastInteraction: Date;
lastInteractionType: 'email' | 'call' | 'demo' | 'proposal' | 'usage';
stallReason?: string;
churnReason?: string;
objections?: string[];
newValue?: string; // What's changed since last interaction
}Persona Types
export type PersonaType =
| 'executive'
| 'practitioner'
| 'champion'
| 'blocker';
export interface PersonaProfile {
type: PersonaType;
title: string;
seniority: 'ic' | 'manager' | 'director' | 'vp' | 'c-level';
department: string;
decisionAuthority: 'decision-maker' | 'influencer' | 'user' | 'gatekeeper';
}
export const PersonaTone = {
executive: {
style: 'concise and ROI-driven',
focus: ['outcomes', 'strategic value', 'business impact'],
avoid: ['technical jargon', 'long emails', 'process details'],
emailLength: 'short (3-4 paragraphs max)',
},
practitioner: {
style: 'tactical and use-case focused',
focus: ['technical depth', 'specific examples', 'how it works'],
avoid: ['buzzwords', 'vague benefits', 'sales speak'],
emailLength: 'medium (4-6 paragraphs)',
},
champion: {
style: 'collaborative and enablement-focused',
focus: ['internal selling', 'success stories', 'team impact'],
avoid: ['pressure', 'external focus only', 'ignoring their needs'],
emailLength: 'medium (4-6 paragraphs)',
},
blocker: {
style: 'risk-aware and proof-driven',
focus: ['risk mitigation', 'proof points', 'alternatives considered'],
avoid: ['overpromising', 'dismissing concerns', 'rushing'],
emailLength: 'medium-long (5-7 paragraphs with proof)',
},
} as const;Sequence Schemas
Sequence Step
import { z } from 'zod';
export const sequenceStepSchema = z.object({
step: z.number().int().positive(),
channel: z.enum(['email', 'linkedin', 'slack', 'phone', 'video']),
timing: z.string().describe('When to send: immediate, day-2, day-7, day-14, etc.'),
subject: z.string().optional().describe('Email subject line (if email)'),
body: z.string().describe('Full message body with personalization'),
cta: z.string().describe('Clear call-to-action'),
attachments: z.array(z.string()).optional().describe('URLs to attachments'),
personalizationNotes: z.array(z.string()).describe('Notes on personalization for human reviewer'),
fallbackTrigger: z.string().optional().describe('What triggers fallback sequence'),
});
export type SequenceStep = z.infer<typeof sequenceStepSchema>;Full Sequence
export const sequenceSchema = z.object({
campaignType: z.enum([
'event-follow-up',
'mutual-intro',
'partnership-outreach',
'product-launch',
'content-syndication',
're-engagement',
'cold-outbound',
'referral-request',
]),
segment: z.string().describe('Campaign-specific segment'),
persona: z.enum(['executive', 'practitioner', 'champion', 'blocker']),
sequenceLength: z.number().int().min(2).max(6),
priority: z.enum(['high', 'medium', 'low']),
reasoning: z.string().describe('Why this classification and sequence'),
primarySequence: z.array(sequenceStepSchema),
fallbackSequence: z.array(sequenceStepSchema).optional(),
metadata: z.object({
generatedAt: z.date(),
model: z.string(),
confidence: z.number().min(0).max(1),
playbookVersion: z.string(),
}),
});
export type Sequence = z.infer<typeof sequenceSchema>;Research Report Schema
export const researchReportSchema = z.object({
prospect: z.object({
name: z.string(),
email: z.string().email(),
title: z.string(),
company: z.string(),
linkedin: z.string().url().optional(),
location: z.string().optional(),
}),
intelligence: z.object({
companyInfo: z.object({
stage: z.string(),
funding: z.string().optional(),
size: z.string(),
industry: z.string(),
techStack: z.array(z.string()).optional(),
}),
recentNews: z.array(z.object({
title: z.string(),
url: z.string().url(),
date: z.date(),
relevance: z.string(),
})),
painPoints: z.array(z.string()),
competitors: z.array(z.string()),
}),
personalization: z.object({
signals: z.array(z.string()).describe('Specific personalization opportunities'),
context: z.string().describe('Overall context for outreach'),
relevance: z.string().describe('Why Brainforge is relevant'),
mutualConnections: z.array(z.string()).optional(),
sharedInterests: z.array(z.string()).optional(),
}),
engagementHistory: z.object({
lastContact: z.date().optional(),
interactions: z.number().int(),
stage: z.string(),
previousCampaigns: z.array(z.string()).optional(),
responseRate: z.number().min(0).max(1).optional(),
}),
});
export type ResearchReport = z.infer<typeof researchReportSchema>;Campaign Classification Schema
export const campaignClassificationSchema = z.object({
campaignType: z.enum([
'event-follow-up',
'mutual-intro',
'partnership-outreach',
'product-launch',
'content-syndication',
're-engagement',
'cold-outbound',
'referral-request',
]),
segment: z.string().describe('Campaign-specific segment (e.g., booth-visitor, warm-intro-executive)'),
persona: z.enum(['executive', 'practitioner', 'champion', 'blocker']),
sequenceLength: z.number().int().min(2).max(6),
priority: z.enum(['high', 'medium', 'low']),
reasoning: z.string().describe('Explanation of classification decisions'),
confidence: z.number().min(0).max(1),
});
export type CampaignClassification = z.infer<typeof campaignClassificationSchema>;Slack Approval Schema
export interface SlackApprovalRequest {
workflowId: string;
prospectName: string;
prospectCompany: string;
campaignType: CampaignType;
segment: string;
persona: PersonaType;
sequence: Sequence;
researchReport: ResearchReport;
approvalDeadline: Date;
}
export type ApprovalAction = 'approve' | 'edit' | 'reject';
export interface SlackApprovalResponse {
workflowId: string;
action: ApprovalAction;
editedSequence?: Sequence;
rejectionReason?: string;
approvedBy: string;
approvedAt: Date;
}CRM Integration Schema
export interface CRMContact {
id: string;
email: string;
firstName: string;
lastName: string;
company: string;
title: string;
hubspotContactId?: string;
customProperties?: Record<string, any>;
}
export interface CRMSequenceTracking {
sequenceId: string;
contactId: string;
campaignType: CampaignType;
currentStep: number;
totalSteps: number;
status: 'active' | 'paused' | 'completed' | 'opted-out';
performance: {
sent: number;
opened: number;
clicked: number;
replied: number;
meetingBooked: boolean;
};
nextActionDate: Date;
}Trigger Event Schema
export type TriggerSource =
| 'form-submission'
| 'crm-webhook'
| 'manual-trigger'
| 'event-integration'
| 'api-request';
export interface CampaignTrigger {
source: TriggerSource;
triggeredAt: Date;
triggeredBy?: string;
prospect: {
email: string;
name?: string;
company?: string;
title?: string;
};
context:
| EventFollowUpContext
| MutualIntroContext
| PartnershipContext
| ProductLaunchContext
| ContentContext
| ReEngagementContext
| Record<string, any>;
metadata?: Record<string, any>;
}Playbook Structure (Markdown)
Each campaign playbook should follow this structure:
# [Campaign Name] Playbook
> **Purpose**: [One-line description]
> **Use Case**: [When to use this campaign]
> **Last Updated**: [Date]
---
## Overview
**Use Case:** [Description]
**Goal:** [Specific outcome]
**Key Principle:** [Core messaging principle]
---
## Segmentation Strategy
### Segment 1: [Name]
- **Context**: [When this segment applies]
- **Engagement Level**: [Light/Moderate/High]
- **Personalization Angle**: [What to personalize on]
- **Example Context**: [Sample opening line]
### Segment 2: [Name]
...
---
## Persona-Based Messaging
### Persona 1: [Executive/Practitioner/Champion/Blocker]
**Tone & Style:**
- [Style description]
**Key Messages:**
- [Message 1]
- [Message 2]
**What to Avoid:**
- [Anti-pattern 1]
- [Anti-pattern 2]
**Example Opening:**[Sample opening line]
**Example Value Prop:**
[Sample value prop]
**Example CTA:**
[Sample call-to-action]
---
## Multi-Step Sequences
### Sequence Template 1: [Segment + Persona]
**Length**: [N] touchpoints over [X] days
#### Step 1 (Immediate)
- **Channel**: Email
- **Goal**: [Goal of this step]
- **Template**:
Subject: [Subject template]
[Body template with [PERSONALIZATION] markers]
[CTA]
#### Step 2 (Day [N])
...
---
## Examples
### Example 1: [Real example name]
[Full example with context]
### Example 2: [Real example name]
[Full example with context]
---
## Success Metrics
- **Open Rate**: [Target]%
- **Response Rate**: [Target]%
- **Meeting Booked**: [Target]%
Usage in Agent
Import Playbook
// lib/playbooks/event-follow-up.ts
import playbookMd from '@/memory/event-follow-up-playbook.md';
export const eventFollowUpPlaybook = {
type: 'event-follow-up' as const,
content: playbookMd,
version: '1.0.0',
lastUpdated: new Date('2026-01-26'),
};Load Playbook in Generator
// lib/services/generator.ts
import { eventFollowUpPlaybook } from '@/lib/playbooks/event-follow-up';
export async function generateSequence(
classification: CampaignClassification,
research: ResearchReport
): Promise<Sequence> {
// Load appropriate playbook
const playbook = getPlaybook(classification.campaignType);
// Generate sequence with AI SDK
const { object: sequence } = await generateObject({
model: openai('gpt-4-turbo'),
schema: sequenceSchema,
messages: [
{
role: 'system',
content: GENERATOR_PROMPT,
},
{
role: 'user',
content: `
Campaign Playbook:
${playbook.content}
Research Report:
${JSON.stringify(research, null, 2)}
Classification:
${JSON.stringify(classification, null, 2)}
Generate a personalized sequence following the playbook guidelines.
`,
},
],
});
return sequence;
}Adding New Campaign Types
- Define segment type in this file
- Define context interface in this file
- Add to CampaignType enum
- Create playbook markdown following structure above
- Import playbook in
lib/playbooks/ - Update classifier to recognize new type
- Test with sample triggers
Validation
Use Zod schemas for runtime validation:
import { sequenceSchema, researchReportSchema } from './schema';
// Validate research report
const validatedReport = researchReportSchema.parse(rawReport);
// Validate generated sequence
const validatedSequence = sequenceSchema.parse(generatedSequence);