Your AI B2B SaaS marketing team: 90 specialist agents in 19 skills across content and editorial operations, SEO/AEO, paid media, social, email, design, sales…

An open-source AI marketing team for B2B SaaS — 90 AI marketing agents for Claude Code, one orchestrator, real playbooks.
Install a full B2B SaaS marketing org into Claude Code: 90 role-based agent personas, packaged as 19 skills, coordinated by the CATALYST multi-agent orchestrator — with worked ABM, launch & demand-gen workflows and an actively-maintained AEO/GEO playbook for the AI-search era.
Quick start · The 90 agents · Skills · CATALYST · Loops · AEO/GEO · Contributing
<img src="assets/catalyst-demo.svg" alt="The CATALYST orchestrator takes one product-launch brief, loads brand-context.md, selects CATALYST-Sprint mode, and routes the work to named specialist agents across product marketing, content, SEO/AEO, design, paid media, social, email, sales enablement, and analytics." width="880">
<sub>Illustration of the routing flow — every agent shown is a real agent in this repo.</sub>
Most "marketing prompt" collections are a flat grab-bag: you get 50 clever prompts, but you're still the manager — deciding which to run, in what order, and how the outputs fit together.
This is the opposite. It's a marketing team shaped like a real B2B SaaS marketing org — 90 specialist agents with defined roles and hand-offs, plus an orchestrator that turns one brief into assigned sub-tasks. You brief the team; it routes the work.
/plugin marketplace add shalintripathi/saas-marketing-agents
/plugin install saas-marketing@saas-marketing-agents
That's it — the 19 skills load as /saas-marketing:<skill> (e.g. /saas-marketing:seo-growth, /saas-marketing:catalyst-orchestrator). Then just describe what you need:
"Plan a product-launch campaign for [feature] targeting [ICP]."
The orchestrator routes positioning to product marketing, assets to content & design, distribution to social/email/paid, and measurement to analytics.
The plugin ships a live pane for Claude Code: type /campaign-board (or just run any skill) and it shows the specialists CATALYST routed, each deliverable as it lands, and every [NEEDS INPUT] marker collected into a checklist — the facts your agents refused to invent, waiting for you to supply them. It also tells you whether brand-context.md was found. (The mod hooks command.run only to answer its own /campaign-board command; it never alters other commands.)
Copy templates/brand-context.md to brand-context.md in your project root and fill it in — ICP, positioning, messaging pillars, voice, banned words, and the proof you can actually cite.
CATALYST reads it before routing anything and passes it to every specialist, so output sounds like your company rather than generic B2B SaaS. It also bounds what the agents may assert: customer names, metrics, and certifications not recorded there are surfaced as [NEEDS INPUT: …] instead of being invented.
npx skills add shalintripathi/saas-marketing-agents
The skills CLI installs the same 19 skills into any agent that supports the open SKILL.md format.
Every agent is plain Markdown, so it works in any AI tool:
git clone https://github.com/shalintripathi/saas-marketing-agents.git
cd saas-marketing-agents
# Claude Code / Cursor / Copilot / Aider / Windsurf — reference an agent file:
# content/content-blog-strategist.md
# seo/seo-ai-search-optimizer.md
# Or install the skills locally without the marketplace:
./scripts/install.sh --tool cowork
See the Integrations Guide for tool-by-tool setup.
Every agent is a named role with its own remit, critical rules, and deliverables — click any one to read it.
_These 17 disciplines hold all 90 specialist agents. On top sits the CATALYST orchestrator, which coordinates them._
→ Full Agent Index — every agent with a one-line description of what it does and when to reach for it.
The agents are grouped into 19 installable skills, each triggered by natural language:
| Skill | Agents | Triggers on |
|---|---|---|
| CATALYST Orchestrator | all 90 | "GTM launch", "campaign plan", "marketing strategy" |
| SaaS Marketing Suite (router) | — | "help with marketing", "what can you do" |
| Content Marketing | 9 | "blog", "case study", "whitepaper", "newsletter", "content brief", "editorial calendar", "content ops", "who reviews this", "our content pipeline is stuck", "content audit", "style guide", "AI content policy", "customer academy", "online course", "certification program", "our tutorial shows the old UI", "should the academy be gated" |
| SEO Growth | 7 | "SEO audit", "keyword research", "what is Googlebot crawling in our logs", "AEO", "link building", "programmatic SEO", "hreflang", "our translated pages get no traffic", "do we need a Google Business Profile in Germany", "G2 / Capterra listing", "get into a 'best software' roundup", "directory submissions" |
| Paid Media Ops | 8 | "Google Ads", "LinkedIn Ads", "Thought Leader Ads", "boost our CEO's post", "partnership ads", "creator usage rights", "ROAS", "attribution", "our paid leads are junk", "offline conversion import", "send CRM stages back to Google Ads", "LinkedIn Conversions API", "newsletter sponsorship", "content syndication", "budget pacing", "we underspent our budget", "are our campaigns competing with each other", "audience overlap", "self-competition", "suppression list", "ad frequency across channels", "ads in AI Overviews", "should we advertise on ChatGPT", "ChatGPT Ads", "AI Mode ads", "can we buy our way into the AI answer", "our ad landing page fails review" |
| Social Media Ops | 8 | "social listening", "what are people saying about us", "share of voice", "brand monitoring", "LinkedIn strategy", "LinkedIn newsletter", "should we start a LinkedIn newsletter", "LinkedIn Events", "LinkedIn Live", "event registration form", "YouTube", "community", "podcast", "show notes", "podcast guesting", "how do I know if this podcast has real listeners", "the host says they get 50k downloads", "is this podcast worth going on", "IAB podcast measurement certification", "Listen Score", "vet this influencer", "is this creator's engagement real", "sponsored post disclosure", "who has admin on our social accounts", "our social media manager left", "social post approval workflow" |
| Email Marketing Ops | 5 | "email sequence", "nurture", "deliverability", "SPF/DKIM/DMARC", "our emails go to spam", "cold email sending domains", "domain warmup", "set up sending infrastructure", "frequency cap", "customers get too many emails from different teams" |
| Design Ops | 5 | "landing page", "brand identity", "ad creative" |
| Sales Enablement | 8 | "website chatbot", "AI SDR", "what should our chat agent be allowed to say", "our chatbot quoted a price", "do we have to disclose it's AI", "chat handoff to sales", "outbound", "out-of-office replies inflate our reply rate", "battle card", "proposal", "MEDDPICC", "demo plan", "proof of concept", "security questionnaire", "AI security questionnaire", "the buyer is asking if we train on their data", "which model do we use", "AI-CAIQ", "ISO 42001", "are we a provider or a deployer", "mutual action plan", "close plan", "the deal is stalled" |
| Product Marketing Ops | 13 | "positioning", "what's our real ICP", "founder-led sales", "design partners", "do we have product-market fit", "when to hire our first AE", "moving upmarket", "enterprise readiness", "product launch", "beta / early access program", "when can we call it GA", "competitive intel", "win/loss interviews", "why we lose deals", "customer referral program", "refer a friend reward", "displace an incumbent", "win deals from a competitor", "switching costs", "their contract renews when?", "pricing", "packaging", "agent readiness", "is our site agent-ready", "Lighthouse Agentic Browsing", "WebMCP", "expand into Europe", "market entry", "which country next", "localization", "brand awareness", "brand vs performance", "how do we measure brand", "share of search", "category entry points", "demand creation", "sell to government", "public sector marketing", "FedRAMP marketing claims", "gift rules for government officials", "how can agencies buy from us", "we just acquired a company", "post-acquisition marketing", "tell the acquired customers", "keep or retire the acquired brand", "merge the two databases", "plan a demand gen campaign", "integrated campaign", "channel plan for next year", "which channels should we stop", "always-on vs tentpole campaigns", "campaign brief" |
| Marketing Analytics | 9 | "CRO", "A/B testing", "sample size", "not enough traffic to test", "dashboards", "attribution", "tracking plan", "GA4 audit", "martech stack audit", "too many tools", "build vs buy", "ESP/CRM migration", "switching cost", "customer interviews", "survey design", "how many people should I interview", "voice of customer", "jobs-to-be-done", "is this finding real", "data enrichment", "which enrichment provider", "waterfall enrichment", "bad list data", "email verification", "data decay", "where did this list come from", "demand planning", "how many leads do we need to hit the target", "build the marketing plan", "top-down vs bottom-up plan", "plan of record", "our leads can't close this quarter", "sales-cycle lag", "scenario band", "stretch target", "reforecast triggers", "we missed plan and nobody knows why", "AI policy for the marketing team", "which AI tools are we allowed to use", "can I paste customer data into ChatGPT", "shadow AI", "our AI vendor changed the model", "turn off Google Ads auto-generated assets", "EU AI Act AI literacy" |
| Marketing Project Mgmt | 4 | "sprint planning", "resource allocation", "QBR" |
| Client Operations | 4 | "client reporting", "QA", "compliance", "budget", "someone asked us to delete their data", "right to erasure", "GDPR deletion request", "do we delete or suppress", "they unsubscribed and we emailed them again", "do we have to disclose AI voice", "AI presenter disclosure", "EU AI Act", "C2PA" |
| Growth Ops | 3 | "PLG", "activation", "PQL", "free trial", "expansion", "churn", "cancel flow", "dunning", "NRR", "champion tracking", "our champion changed jobs", "interactive demo", "product tour", "self-guided demo", "should our demo be gated?" |
| ABM Ops | 1 | "ABM", "target account list", "account tiering", "named accounts", "intent data", "account coverage" |
| Comms Ops | 2 | "PR", "press release", "analyst relations", "Gartner", "Forrester" |
| Partnerships Ops | 2 | "co-marketing", "channel", "integration launch", "AWS Marketplace", "channel conflict", "deal registration", "should we build a partner program", "partner economics" |
| Events Ops | 1 | "conference", "booth", "field marketing", "webinar", "roadshow" |
| Developer Marketing Ops | 1 | "developer marketing", "DevRel", "docs", "SDK", "quickstart" |
Skill sources live in plugins/saas-marketing/skills/.
CATALYST is the coordination layer that runs a multi-agent campaign end to end:
Coordination · Analysis · Targeting · Adaptation · Leveraging · Yield · Strategy · Teamwork
Instead of prompting each specialist by hand, you give CATALYST a brief and it decomposes the work, assigns specialists, and manages the hand-offs. See the Workflow Guide and the phased playbooks.
Workflows are one-shot; loops repeat. The loops/ library holds recurring, agent-run workflows on a cadence:
Full worked campaigns live in examples/:
Buyers increasingly ask an AI engine instead of clicking ten links — so the vendors an engine cites shape the shortlist. The AEO/GEO Playbook is a sourced, practitioner-grade guide to getting cited by ChatGPT, Perplexity, Google AI Overviews, and Copilot: what measurably works (quotations, statistics, cited sources), how each engine differs, and what not to do. It's a living document we intend to keep current as the answer engines change.
Contributions are welcome — new agents, better agents, new loops, and freshness fixes. See CONTRIBUTING.md, the ROADMAP, and the CODE_OF_CONDUCT. Good first contributions are listed in the maintenance backlog.
If this saves you time, a star genuinely helps other marketers find it — and it's the signal that tells us which parts to invest in next. Thank you.
MIT — free to use, modify, and distribute.
Built by Shivaa Tripathi · Report an issue · Changelog
hooks/register.tsx 146 lines1import { atom, read, update } from 'claude-code'
2import type { EngineInterface, Register } from 'claude-code'
3
4import type { BrandState, Deliverable, NeedsInput, SkillRun } from '../types'
5
6const PANE = 'campaign-board'
7const PLUGIN_PREFIX = 'saas-marketing'
8const MARKER = /\[NEEDS INPUT[^\]]*\]/g
9
10const skills = atom({ plugin: 'saas-marketing', key: 'skills' } as const, [] as SkillRun[])
11const deliverables = atom({ plugin: 'saas-marketing', key: 'deliverables' } as const, [] as Deliverable[])
12const needs = atom({ plugin: 'saas-marketing', key: 'needs' } as const, [] as NeedsInput[])
13const brand = atom({ plugin: 'saas-marketing', key: 'brand' } as const, 'unknown' as BrandState)
14
15const base = (path: string) => path.split('/').pop() ?? path
16
17const harvest = async ($: EngineInterface, file: string, content: string) => {
18 const found = content.match(MARKER) ?? []
19 if (found.length === 0) return
20 const short = base(file)
21 await update($, needs, list => {
22 const next = [...list]
23 for (const raw of found) {
24 const text = raw.slice(0, 120)
25 if (!next.some(one => one.file === short && one.text === text)) next.push({ file: short, text })
26 }
27 return next.slice(-100)
28 })
29}
30
31export const register: Register = on => {
32 on('session.start', async ($, e, next) => {
33 await $.command.register({
34 name: 'campaign-board',
35 description: 'Open the saas-marketing campaign board pane',
36 })
37 const hasBrand = await $.fs.exists(`${e.cwd}/brand-context.md`)
38 await update($, brand, () => (hasBrand ? 'found' : 'missing'))
39
40 return next(e)
41 })
42
43 on('command.run', { command: 'campaign-board' }, async $ => {
44 await $.ui.open({ id: PANE, title: 'Campaign board' })
45
46 return { text: 'Campaign board opened.' }
47 })
48
49 on('tool.call', { tool: 'Skill' }, async ($, e, next) => {
50 if (!e.skill.startsWith(PLUGIN_PREFIX)) return next(e)
51
52 const run: SkillRun = { id: e.tool_use_id, name: e.skill, at: Date.now(), isDone: false }
53 await update($, skills, list => [...list, run].slice(-50))
54 void $.ui.open({ id: PANE, title: 'Campaign board' })
55 $.ui.status(`campaign: ${e.skill.split(':').pop()}`)
56
57 const ran = await next(e)
58 await update($, skills, list =>
59 list.map(one => (one.id === run.id ? { ...one, isDone: true } : one)),
60 )
61 $.ui.status(`campaign: ${e.skill.split(':').pop()} done`)
62
63 return ran
64 })
65
66 on('tool.call', { tool: 'Write' }, async ($, e, next) => {
67 const ran = await next(e)
68 if (ran.deny !== undefined || ran.isError === true) return ran
69
70 const active = (await read($, skills)).length > 0
71 if (active && e.file_path.endsWith('.md')) {
72 await update($, deliverables, list => {
73 if (list.some(one => one.path === e.file_path)) return list
74 return [...list, { path: e.file_path, at: Date.now() }].slice(-100)
75 })
76 $.ui.toast(`deliverable: ${base(e.file_path)}`)
77 await harvest($, e.file_path, e.content)
78 }
79
80 return ran
81 })
82
83 on('tool.call', { tool: 'Edit' }, async ($, e, next) => {
84 const ran = await next(e)
85 if (ran.deny === undefined && ran.isError !== true && (await read($, skills)).length > 0) {
86 await harvest($, e.file_path, e.new_string)
87 }
88
89 return ran
90 })
91
92 on('ui.render', { component: 'Pane', requestId: PANE }, async ($, e) => {
93 const { Box, Text } = $.ui.resolve(e)
94 const runList = await read($, skills)
95 const fileList = await read($, deliverables)
96 const needList = await read($, needs)
97 const brandNow = await read($, brand)
98 const rows = Math.max(6, (e.viewport?.rows ?? 30) - 6)
99 const roomEach = Math.max(2, Math.floor(rows / 3))
100
101 return (
102 <Box flexDirection="column" paddingX={1}>
103 <Text bold>
104 Campaign board{' '}
105 <Text color={brandNow === 'found' ? 'green' : 'yellow'}>
106 brand-context.md {brandNow === 'found' ? 'found' : brandNow === 'missing' ? 'missing' : '...'}
107 </Text>
108 </Text>
109 {brandNow === 'missing' && (
110 <Text dimColor>copy templates/brand-context.md into your project for grounded output</Text>
111 )}
112
113 <Box marginTop={1} flexDirection="column">
114 <Text bold underline>Skills routed</Text>
115 {runList.length === 0 && <Text dimColor>none yet — run any /saas-marketing skill</Text>}
116 {runList.slice(-roomEach).map(run => (
117 <Text dimColor={run.isDone}>
118 {run.isDone ? 'done ' : 'runs '}{run.name.split(':').pop()}
119 </Text>
120 ))}
121 </Box>
122
123 <Box marginTop={1} flexDirection="column">
124 <Text bold underline>Deliverables</Text>
125 {fileList.length === 0 && <Text dimColor>none yet</Text>}
126 {fileList.slice(-roomEach).map(one => (
127 <Text>{base(one.path)}</Text>
128 ))}
129 </Box>
130
131 <Box marginTop={1} flexDirection="column">
132 <Text bold underline>
133 Needs your input{needList.length > 0 ? ` (${needList.length})` : ''}
134 </Text>
135 {needList.length === 0 && <Text dimColor>nothing — agents invented no facts</Text>}
136 {needList.slice(-roomEach).map(one => (
137 <Text color="yellow" wrap="truncate-end">
138 {base(one.file)}: {one.text}
139 </Text>
140 ))}
141 </Box>
142 </Box>
143 )
144 })
145}
146types/index.d.ts 16 lines1export type SkillRun = { id: string; name: string; at: number; isDone: boolean }
2export type Deliverable = { path: string; at: number }
3export type NeedsInput = { file: string; text: string }
4export type BrandState = 'unknown' | 'found' | 'missing'
5
6declare module 'claude-code' {
7 interface PluginState {
8 'saas-marketing': {
9 skills: SkillRun[]
10 deliverables: Deliverable[]
11 needs: NeedsInput[]
12 brand: BrandState
13 }
14 }
15}
16