
Marketing Ops
- 83 installs
- 451 repo stars
- Updated July 21, 2026
- borghei/claude-skills
marketing-ops is a skill that routes marketing questions to the right specialist skill and orchestrates multi-skill marketing campaigns, MarTech, and attribution.
About
This skill is a central marketing operations hub that routes marketing questions to the correct specialist skill and orchestrates multi-skill campaigns in sequence. It also covers MarTech stack management, marketing automation, data management, and attribution modeling. Marketing teams use it to coordinate execution across content, SEO, conversion, and channel skills.
- Central hub that routes marketing questions to the correct skill via a routing matrix
- Orchestrates multi-skill campaigns with sequenced execution plans
- Covers MarTech stack management, marketing automation, data management, and attribution
Marketing Ops by the numbers
- 83 all-time installs (skills.sh)
- Ranked #462 of 853 Sales & Marketing skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
marketing-ops capabilities & compatibility
- Capabilities
- campaign orchestration · skill routing · martech management · attribution
- Use cases
- marketing · orchestration · planning
- Pricing
- Free
What marketing-ops says it does
Central command for marketing operations — routing questions, orchestrating campaigns, managing MarTech, and coordinating across all marketing functions.
If multiple skills are needed, create an orchestration plan
Match to the routing matrix below
npx skills add https://github.com/borghei/claude-skills --skill marketing-opsAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 83 |
|---|---|
| repo stars | ★ 451 |
| Last updated | July 21, 2026 |
| Repository | borghei/claude-skills ↗ |
What it does
Route marketing questions and orchestrate multi-skill campaigns across content, SEO, conversion, and channel work.
Who is it for?
Marketing teams coordinating campaigns and routing work across multiple marketing skills.
Skip if: Executing a single specific deliverable like page copy, which a specialist skill handles directly.
When should I use this skill?
You are routing marketing questions, orchestrating multi-skill campaigns, or managing the MarTech stack.
What you get
Produces a routing decision or a sequenced multi-skill campaign orchestration plan.
- Skill routing decisions
- Campaign orchestration plan
- MarTech and attribution guidance
By the numbers
- Routing matrix spans content, SEO, conversion, channel, and strategy skills
- Defines campaign sequences for launch and content-marketing sprints
Files
Marketing Ops
Central command for marketing operations — routing questions, orchestrating campaigns, managing MarTech, and coordinating across all marketing functions.
---
Table of Contents
- Keywords
- Quick Start
- Skill Routing Matrix
- Campaign Orchestration
- MarTech Stack Management
- Marketing Automation Framework
- Data Management
- Attribution Framework
- Marketing Audit
- Best Practices
- Integration Points
---
Keywords
marketing ops, marketing operations, MarTech stack, marketing automation, campaign orchestration, skill routing, marketing coordination, data management, attribution, marketing technology, campaign management, workflow automation, lead management, marketing analytics, marketing infrastructure, CRM integration, email automation, lead scoring
---
Quick Start
Route a Marketing Question
1. Identify what the user is trying to accomplish 2. Match to the routing matrix below 3. Route to the correct skill with context 4. If multiple skills are needed, create an orchestration plan
Orchestrate a Campaign
1. Check that marketing context exists (if not, create it first) 2. Identify all skills needed for the campaign 3. Sequence skills in the correct order 4. Execute each phase, passing outputs to the next 5. Measure results using campaign analytics
---
Skill Routing Matrix
Content Skills
| User Says | Route To | Not This |
|---|---|---|
| "Write a blog post," "content ideas," "what should I write" | Content Strategy | Not Copywriting (that is for page copy) |
| "Write copy for my homepage," "landing page copy," "headline" | Copywriting | Not Content Strategy (that is for planning) |
| "Edit this copy," "proofread," "polish this" | Copy Editing | Not Copywriting (that is for writing new) |
| "Social media post," "LinkedIn post," "tweet" | Social Content | Not Content Strategy (that is for planning) |
| "Write an article end-to-end," "content production" | Content Production | Not Content Strategy (production has the full pipeline) |
| "Sounds too robotic," "make it human," "AI watermarks" | Content Humanizer | Not Copy Editing (that is for editorial quality) |
| "Marketing ideas," "brainstorm," "what else can I try" | Marketing Ideas | Not Content Strategy (that is for content specifically) |
SEO Skills
| User Says | Route To | Not This |
|---|---|---|
| "SEO audit," "technical SEO," "on-page SEO" | SEO Specialist | Not AI SEO (that is for AI search engines) |
| "AI search," "ChatGPT visibility," "Perplexity," "GEO" | AI SEO | Not SEO Specialist (that is traditional SEO) |
Conversion Skills
| User Says | Route To | Not This |
|---|---|---|
| "Landing page," "campaign page," "lead capture page" | Landing Page Generator | Not Copywriting (generator includes structure + copy) |
| "Brand guidelines," "style guide," "brand voice" | Brand Guidelines | Not Marketing Context (guidelines are implementation) |
Channel Skills
| User Says | Route To | Not This |
|---|---|---|
| "Paid ads," "Google Ads," "Meta ads," "ad campaign" | Paid Ads | Not Ad Creative (that is for copy, not strategy) |
| "Ad copy," "ad headlines," "ad variations," "RSA" | Ad Creative | Not Paid Ads (that is for campaign strategy) |
| "Cold email," "outreach," "prospecting email" | Cold Email | Not Content Production (cold email has different rules) |
Strategy Skills
| User Says | Route To | Not This |
|---|---|---|
| "Marketing context," "who is my customer," "ICP" | Marketing Context | Set up before other skills |
| "Marketing strategy," "how to market" | Marketing Ideas | Not Marketing Ops (ops is for execution routing) |
| "Psychology," "persuasion," "why people buy" | Marketing Psychology | Not Copywriting (psychology is the theory layer) |
---
Campaign Orchestration
Campaign Type: Product/Feature Launch
Sequence:
1. Marketing Context (verify foundation exists)
2. Content Strategy (plan launch content)
3. Copywriting (write landing page and email copy)
4. Landing Page Generator (build the conversion page)
5. Ad Creative (create ad copy for paid promotion)
6. Paid Ads (set up campaign targeting and budget)
7. Social Content (create organic social posts)
8. Cold Email (targeted outreach to prospects)
9. Campaign Analytics (measure results)Campaign Type: Content Marketing Sprint
Sequence:
1. Content Strategy (plan topics and calendar)
2. Content Production (research, write, optimize each piece)
3. Content Humanizer (polish for natural voice)
4. AI SEO (optimize for AI search citation)
5. Social Content (distribute across platforms)
6. Campaign Analytics (track performance)Campaign Type: Lead Generation Blitz
Sequence:
1. Marketing Context (verify ICP and messaging)
2. Landing Page Generator (build conversion pages)
3. Ad Creative (generate ad variations)
4. Paid Ads (launch campaigns)
5. Cold Email (parallel outbound effort)
6. Campaign Analytics (measure and optimize)Campaign Type: Brand Awareness
Sequence:
1. Marketing Context (define brand foundation)
2. Brand Guidelines (establish visual and verbal standards)
3. Content Strategy (plan thought leadership content)
4. Social Content (build social presence)
5. Content Production (create pillar content)
6. Campaign Analytics (measure reach and engagement)Campaign Type: Conversion Optimization
Sequence:
1. Marketing Psychology (identify behavioral levers)
2. Copy Editing (audit existing page copy)
3. Copywriting (rewrite underperforming sections)
4. Landing Page Generator (redesign conversion pages)
5. Campaign Analytics (set up A/B tests and track results)---
MarTech Stack Management
Core Stack Components
| Category | Purpose | Common Tools | Integration Priority |
|---|---|---|---|
| CRM | Customer data management | Salesforce, HubSpot, Pipedrive | Critical |
| Marketing Automation | Email, workflows, scoring | HubSpot, Marketo, ActiveCampaign | Critical |
| Analytics | Traffic and behavior tracking | GA4, Mixpanel, Amplitude | Critical |
| Email Platform | Email sending and deliverability | SendGrid, Mailchimp, Customer.io | Critical |
| Ad Platforms | Paid advertising | Google Ads, Meta Ads, LinkedIn Ads | High |
| SEO Tools | Keyword research and tracking | Ahrefs, SEMrush, Moz | High |
| Social Management | Publishing and scheduling | Buffer, Hootsuite, Sprout Social | Medium |
| Content Management | Content creation and hosting | WordPress, Webflow, Ghost | High |
| Attribution | Multi-touch attribution | Attribution App, Dreamdata | Medium |
| ABM | Account-based marketing | Demandbase, 6sense, Terminus | Medium (B2B) |
Stack Evaluation Framework
When evaluating new tools:
| Criterion | Weight | Scoring |
|---|---|---|
| Does it solve a validated problem? | 30% | Clear need (3), Nice to have (2), Speculative (1) |
| Does it integrate with existing stack? | 25% | Native integration (3), API available (2), Manual export (1) |
| Total cost of ownership | 20% | Under budget (3), At budget (2), Over budget (1) |
| Time to value | 15% | Under 1 week (3), 1-4 weeks (2), 4+ weeks (1) |
| Team capability to use it | 10% | Self-serve (3), Training needed (2), Expert required (1) |
Rule: Never add a tool that does not integrate with your CRM. Disconnected data is worse than no data.
Stack Audit Checklist
- [ ] Every tool has a clear owner responsible for it
- [ ] Every tool connects to CRM or central data warehouse
- [ ] No overlapping tools doing the same job
- [ ] All contracts reviewed annually for cost optimization
- [ ] Data flows documented between tools
- [ ] Integration health monitored (failures flagged within 24 hours)
- [ ] Tool adoption measured (tools nobody uses should be cut)
---
Marketing Automation Framework
Automation Priority by Impact
| Automation | Impact | Complexity | Build First |
|---|---|---|---|
| Welcome/onboarding email sequence | High | Low | Yes |
| Lead scoring | High | Medium | Yes |
| Abandoned cart/trial follow-up | High | Low | Yes |
| Event-triggered emails (usage milestones) | High | Medium | Second priority |
| Lead routing to sales | High | Low | Yes |
| Social media scheduling | Medium | Low | Second priority |
| Reporting dashboards | Medium | Medium | Second priority |
| Content personalization | Medium | High | Third priority |
| Predictive lead scoring | Medium | High | Third priority |
| Dynamic content insertion | Low-Medium | High | Later |
Lead Scoring Model
| Signal Type | Examples | Score |
|---|---|---|
| Demographic fit | Matches ICP (title, company size, industry) | +10 to +25 |
| Behavioral - high intent | Visited pricing page, requested demo, viewed case study | +15 to +25 |
| Behavioral - engagement | Opened 3+ emails, downloaded content, attended webinar | +5 to +15 |
| Behavioral - product | Used free trial, reached activation milestone | +20 to +30 |
| Negative signals | Competitor employee, student email, unsubscribed | -10 to -50 |
Lead score thresholds:
- 0-25: Nurture (automated email sequences)
- 26-50: Marketing Qualified Lead (MQL) — deeper engagement
- 51-75: Sales Qualified Lead (SQL) — route to sales
- 76+: Hot lead — immediate sales outreach
Email Automation Sequences
| Sequence | Trigger | Emails | Duration |
|---|---|---|---|
| Welcome | New signup | 5-7 | 14 days |
| Onboarding | Started trial | 4-6 | 14 days |
| Re-engagement | Inactive 30 days | 3-4 | 21 days |
| Win-back | Churned | 3-5 | 30 days |
| Nurture | Downloaded content | 5-7 | 45 days |
| Upsell | Reached plan limit | 2-3 | 7 days |
| Referral | 90 days active + high NPS | 2 | 7 days |
---
Data Management
Data Quality Framework
| Dimension | Definition | How to Measure |
|---|---|---|
| Completeness | Required fields are filled | % of records with complete required fields |
| Accuracy | Data matches reality | Sample audit against source of truth |
| Consistency | Same data, same format everywhere | Cross-system comparison |
| Timeliness | Data is current | % of records updated within defined freshness window |
| Uniqueness | No duplicate records | Duplicate rate in CRM |
Data Hygiene Schedule
| Task | Frequency | Owner |
|---|---|---|
| Deduplicate CRM records | Monthly | Marketing Ops |
| Verify email addresses | Before every campaign | Marketing Ops |
| Update firmographic data | Quarterly | Marketing Ops |
| Clean inactive contacts | Quarterly | Marketing Ops |
| Audit UTM parameter consistency | Monthly | Marketing Ops |
| Review lead scoring accuracy | Quarterly | Marketing + Sales |
| Sync CRM with marketing automation | Continuous (automated) | System |
UTM Parameter Standards
Consistent UTM tagging is foundational for attribution:
utm_source: [platform] — google, linkedin, facebook, email, partner-name
utm_medium: [channel type] — cpc, organic, email, social, referral
utm_campaign: [campaign name] — product-launch-q1, blog-promo-march
utm_content: [variant] — headline-a, cta-blue, audience-cmo
utm_term: [keyword] — for paid search onlyRules:
- Always lowercase
- Use hyphens, not spaces or underscores
- Document all campaign names in a shared registry
- Validate UTMs before launching any campaign
---
Attribution Framework
Attribution Models
| Model | How It Works | Best For | Limitation |
|---|---|---|---|
| First-touch | 100% credit to first interaction | Understanding acquisition channels | Ignores nurture touchpoints |
| Last-touch | 100% credit to final interaction | Understanding conversion triggers | Ignores awareness touchpoints |
| Linear | Equal credit to all touchpoints | Simple multi-touch understanding | Treats all touches equally |
| Time-decay | More credit to recent touchpoints | Long sales cycles | May undervalue awareness |
| Position-based (U-shaped) | 40% first, 40% last, 20% middle | Balanced view | Arbitrary weighting |
| Data-driven | ML-based weighting | Sophisticated programs | Requires large data volume |
Attribution Implementation Checklist
- [ ] UTM parameters standardized and enforced
- [ ] All marketing channels tagged consistently
- [ ] CRM captures source/medium/campaign for every lead
- [ ] Conversion events defined and tracked
- [ ] Attribution model selected and documented
- [ ] Reporting cadence established (weekly + monthly)
- [ ] Channel ROI calculated and compared monthly
---
Marketing Audit
Full Marketing Audit Structure
| Area | What to Assess | Key Questions |
|---|---|---|
| Strategy | Positioning, ICP, messaging | Is our positioning differentiated? Do we know our ICP? |
| Content | Quality, quantity, performance | Is content driving traffic and conversions? |
| SEO | Rankings, technical health, content gaps | Are we visible for target keywords? |
| Paid | ROAS, CPA, channel mix | Are paid campaigns profitable? |
| List health, engagement, automation | Are sequences driving conversions? | |
| Social | Reach, engagement, brand consistency | Are we building audience and trust? |
| MarTech | Stack utilization, integration health | Are our tools connected and used? |
| Data | Quality, attribution, reporting | Can we trust our data and attribution? |
Audit Scoring
For each area, score 1-5:
| Score | Status | Action |
|---|---|---|
| 1 | Not present | Build from scratch |
| 2 | Basic but underperforming | Significant improvement needed |
| 3 | Functional | Optimize and iterate |
| 4 | Strong | Maintain and scale |
| 5 | Best-in-class | Protect and document |
---
Best Practices
1. Context first, always — Check that marketing context exists before any marketing work. Everything works better with context.
2. Route precisely — A question routed to the wrong skill produces wrong-shaped output. Use the routing matrix.
3. Orchestrate, do not fragment — Multi-skill campaigns need a sequence plan. Ad hoc execution produces inconsistent results.
4. Own the data — Marketing ops is responsible for data quality. Bad data produces bad decisions.
5. Standardize UTMs — Inconsistent UTM parameters make attribution impossible. Enforce standards before launching campaigns.
6. Audit tools annually — Every tool should justify its cost and usage. Cut tools nobody uses.
7. Automate the repeatable — If you do it every week, automate it. Manual processes do not scale.
8. Document everything — Campaign playbooks, automation logic, data flows, tool configurations. Tribal knowledge is fragile.
9. Align with sales — Marketing ops and sales ops must share data definitions, lead scoring criteria, and attribution models.
10. Measure what matters — Track leading indicators (MQLs, pipeline velocity) alongside lagging indicators (revenue, ROI).
---
Integration Points
- Marketing Context — Foundation for all marketing operations. Create this first.
- Campaign Analytics — Use for measuring outcomes of orchestrated campaigns.
- All Marketing Skills — Marketing Ops routes questions and orchestrates workflows across the full skill ecosystem.
- Content Strategy — Coordinate content calendar with campaign schedule.
- Paid Ads — Coordinate paid campaigns with organic efforts and landing pages.
- Cold Email — Coordinate outbound with inbound campaigns to avoid audience overlap.
---
Troubleshooting
| Symptom | Likely Cause | Resolution |
|---|---|---|
| Marketing and sales disagree on lead quality | Lead scoring thresholds not aligned or model not validated against outcomes | Run lead_scoring_simulator.py with historical data; validate that high-scored leads convert at 2x+ the rate of low-scored |
| MarTech stack costs growing 20%+ YoY without proportional ROI | Tool proliferation without consolidation; unused tools not audited | Run martech_stack_auditor.py quarterly; cut tools with <30% utilization; consolidate overlapping categories |
| Campaign data siloed across platforms, attribution impossible | No unified UTM standard; tools not integrated through CRM | Standardize UTM parameters (lowercase, hyphens, documented registry); require CRM integration for every tool |
| Lead routing to sales takes >24 hours | Manual handoff process; no automation between marketing automation and CRM | Implement automated lead routing rules; route hot leads (76+ score) within 15 minutes |
| Email deliverability dropping below 90% | List hygiene not maintained; bounced/inactive contacts not cleaned | Deduplicate monthly; verify addresses before campaigns; clean inactive contacts quarterly |
| Budget spent evenly across channels regardless of performance | No performance-based allocation framework in place | Use campaign_budget_allocator.py with historical ROAS data; shift budget quarterly toward highest performers |
| Multi-skill campaigns produce inconsistent messaging | No orchestration sequence defined; skills executed ad hoc | Follow campaign orchestration templates; always start with marketing context verification |
---
Success Criteria
- All MarTech tools connected to CRM with verified data flow
- MarTech stack audit score above 70/100 with zero critical gaps
- Lead scoring model validated: high-scored leads convert at 2x+ rate of low-scored
- UTM parameters 100% standardized and validated before every campaign launch
- Campaign orchestration follows documented sequences with context verified first
- Budget allocation reviewed and adjusted quarterly based on channel ROI data
- Data quality: <5% duplicate rate in CRM, <2% email bounce rate, >95% required fields complete
---
Scope & Limitations
In Scope: Skill routing and orchestration, campaign sequencing, MarTech stack management and auditing, marketing automation (email sequences, lead scoring, lead routing), data quality management, UTM standardization, attribution framework setup, marketing audit methodology, budget allocation.
Out of Scope: Individual channel execution (see channel-specific skills), analytics implementation (see analytics-tracking skill), content creation (see content-creator skill), sales operations and CRM administration (sales ops function).
Limitations: Marketing ops is the coordination layer, not the execution layer. Tool auditing uses self-reported utilization data; actual usage may differ. Lead scoring models require minimum 50+ historical conversions for meaningful validation. Budget allocation assumes linear channel scaling; real channels have diminishing returns.
---
Scripts
| Script | Purpose | Usage |
|---|---|---|
scripts/martech_stack_auditor.py | Audit MarTech stack for gaps, redundancies, and optimization opportunities | python scripts/martech_stack_auditor.py stack.json --demo |
scripts/campaign_budget_allocator.py | Allocate marketing budget across campaigns by priority and performance | python scripts/campaign_budget_allocator.py campaigns.json --budget 100000 --strategy balanced |
scripts/lead_scoring_simulator.py | Simulate and validate lead scoring models against actual outcomes | python scripts/lead_scoring_simulator.py leads.json --demo |
#!/usr/bin/env python3
"""Campaign Budget Allocator - Allocate marketing budget across campaigns and channels.
Distributes a total budget across campaigns based on priority, historical
performance, and strategic objectives.
Usage:
python campaign_budget_allocator.py campaigns.json --budget 100000
python campaign_budget_allocator.py campaigns.json --budget 100000 --json
python campaign_budget_allocator.py --demo
"""
import argparse
import json
import sys
PRIORITY_WEIGHTS = {"critical": 4, "high": 3, "medium": 2, "low": 1}
OBJECTIVE_WEIGHTS = {"revenue": 3, "pipeline": 2.5, "leads": 2, "awareness": 1.5, "retention": 1.5}
def allocate_budget(campaigns, total_budget, strategy="balanced"):
"""Allocate budget across campaigns."""
if not campaigns:
return {"error": "No campaigns provided"}
# Calculate priority scores
for camp in campaigns:
priority = camp.get("priority", "medium")
historical_roas = camp.get("historical_roas", 1.0)
objective = camp.get("objective", "leads")
strategic_importance = camp.get("strategic_importance", 5)
# Composite score
priority_score = PRIORITY_WEIGHTS.get(priority, 2)
objective_score = OBJECTIVE_WEIGHTS.get(objective, 2)
performance_score = min(5, historical_roas) # Cap at 5
if strategy == "performance":
# Weight heavily toward historical performance
camp["_score"] = performance_score * 3 + priority_score + objective_score
elif strategy == "strategic":
# Weight toward strategic importance
camp["_score"] = strategic_importance * 2 + priority_score * 2 + objective_score
else: # balanced
camp["_score"] = priority_score * 2 + performance_score * 1.5 + objective_score + strategic_importance * 0.5
# Normalize scores to get allocation percentages
total_score = sum(c["_score"] for c in campaigns)
allocations = []
remaining = total_budget
for camp in sorted(campaigns, key=lambda x: x["_score"], reverse=True):
share = camp["_score"] / max(total_score, 1)
# Apply min/max constraints
min_budget = camp.get("min_budget", 0)
max_budget = camp.get("max_budget", total_budget)
allocated = max(min_budget, min(max_budget, int(total_budget * share)))
allocations.append({
"campaign": camp.get("name", "Unnamed"),
"objective": camp.get("objective", "leads"),
"priority": camp.get("priority", "medium"),
"historical_roas": camp.get("historical_roas"),
"score": round(camp["_score"], 2),
"allocated_budget": allocated,
"budget_share": round(share * 100, 1),
})
# Normalize to fit exact budget
total_allocated = sum(a["allocated_budget"] for a in allocations)
if total_allocated > 0:
scale = total_budget / total_allocated
for a in allocations:
a["allocated_budget"] = int(a["allocated_budget"] * scale)
# Projected outcomes
for a in allocations:
camp_data = next((c for c in campaigns if c.get("name") == a["campaign"]), {})
roas = camp_data.get("historical_roas", 1.0)
cpl = camp_data.get("historical_cpl", 100)
a["projected_revenue"] = round(a["allocated_budget"] * roas, 2)
a["projected_leads"] = int(a["allocated_budget"] / max(cpl, 1))
total_projected_revenue = sum(a["projected_revenue"] for a in allocations)
total_projected_leads = sum(a["projected_leads"] for a in allocations)
return {
"strategy": strategy,
"total_budget": total_budget,
"total_allocated": sum(a["allocated_budget"] for a in allocations),
"projected_revenue": round(total_projected_revenue, 2),
"projected_roas": round(total_projected_revenue / max(total_budget, 1), 2),
"projected_leads": total_projected_leads,
"projected_cpl": round(total_budget / max(total_projected_leads, 1), 2),
"allocations": allocations,
}
def get_demo_data():
return {
"campaigns": [
{"name": "Paid Search - Brand", "priority": "critical", "objective": "revenue", "historical_roas": 4.2, "historical_cpl": 45, "strategic_importance": 8},
{"name": "LinkedIn ABM Campaign", "priority": "high", "objective": "pipeline", "historical_roas": 2.8, "historical_cpl": 120, "strategic_importance": 9},
{"name": "Content Marketing", "priority": "high", "objective": "leads", "historical_roas": 3.5, "historical_cpl": 35, "strategic_importance": 7},
{"name": "Email Nurture", "priority": "medium", "objective": "revenue", "historical_roas": 8.5, "historical_cpl": 12, "strategic_importance": 6},
{"name": "Display Retargeting", "priority": "medium", "objective": "leads", "historical_roas": 1.8, "historical_cpl": 85, "strategic_importance": 4},
{"name": "Brand Awareness", "priority": "low", "objective": "awareness", "historical_roas": 0.5, "historical_cpl": 200, "strategic_importance": 5},
],
"budget": 100000,
}
def format_report(analysis):
"""Format human-readable allocation report."""
lines = []
lines.append("=" * 75)
lines.append(f"BUDGET ALLOCATION ({analysis['strategy'].upper()} STRATEGY)")
lines.append("=" * 75)
lines.append(f"Total Budget: ${analysis['total_budget']:,.0f}")
lines.append(f"Projected Revenue: ${analysis['projected_revenue']:,.0f}")
lines.append(f"Projected ROAS: {analysis['projected_roas']:.1f}x")
lines.append(f"Projected Leads: {analysis['projected_leads']:,}")
lines.append(f"Projected CPL: ${analysis['projected_cpl']:.0f}")
lines.append("")
lines.append("--- ALLOCATIONS ---")
lines.append(f"{'Campaign':<25} {'Budget':>10} {'Share':>6} {'ROAS':>6} {'Proj Rev':>12} {'Leads':>7}")
lines.append("-" * 70)
for a in sorted(analysis["allocations"], key=lambda x: x["allocated_budget"], reverse=True):
roas = a.get("historical_roas", "N/A")
roas_str = f"{roas:.1f}x" if isinstance(roas, (int, float)) else roas
lines.append(
f"{a['campaign']:<25} ${a['allocated_budget']:>9,} {a['budget_share']:>5.0f}% "
f"{roas_str:>6} ${a['projected_revenue']:>11,.0f} {a['projected_leads']:>7,}"
)
return "\n".join(lines)
def main():
parser = argparse.ArgumentParser(description="Allocate marketing budget across campaigns")
parser.add_argument("input", nargs="?", help="JSON file with campaign data")
parser.add_argument("--budget", type=float, help="Total budget to allocate")
parser.add_argument("--strategy", choices=["balanced", "performance", "strategic"], default="balanced")
parser.add_argument("--json", action="store_true", dest="json_output", help="Output JSON")
parser.add_argument("--demo", action="store_true", help="Run with demo data")
args = parser.parse_args()
if args.demo:
data = get_demo_data()
campaigns = data["campaigns"]
budget = data["budget"]
elif args.input:
try:
with open(args.input, "r", encoding="utf-8") as f:
data = json.load(f)
campaigns = data if isinstance(data, list) else data.get("campaigns", [])
budget = args.budget or data.get("budget", 100000)
except FileNotFoundError:
print(f"Error: File not found: {args.input}", file=sys.stderr)
sys.exit(1)
else:
parser.print_help()
sys.exit(1)
if args.budget:
budget = args.budget
analysis = allocate_budget(campaigns, budget, args.strategy)
if args.json_output:
print(json.dumps(analysis, indent=2))
else:
print(format_report(analysis))
if __name__ == "__main__":
main()
#!/usr/bin/env python3
"""Lead Scoring Simulator - Simulate and validate lead scoring models.
Scores leads based on demographic fit and behavioral signals, validates
model effectiveness against actual outcomes, and tunes thresholds.
Usage:
python lead_scoring_simulator.py leads.json
python lead_scoring_simulator.py leads.json --model scoring_model.json --json
python lead_scoring_simulator.py --demo
"""
import argparse
import json
import sys
DEFAULT_MODEL = {
"demographic": {
"title_match": {"values": ["vp", "director", "head", "manager", "lead", "chief"], "score": 20},
"company_size_fit": {"min": 50, "max": 5000, "score": 15},
"industry_fit": {"values": ["saas", "technology", "fintech", "software"], "score": 15},
},
"behavioral": {
"pricing_page_visit": {"score": 25},
"demo_requested": {"score": 30},
"case_study_viewed": {"score": 15},
"emails_opened_3plus": {"score": 10},
"content_downloaded": {"score": 10},
"webinar_attended": {"score": 15},
"trial_started": {"score": 30},
"feature_used": {"score": 20},
},
"negative": {
"competitor_employee": {"score": -50},
"student_email": {"score": -40},
"unsubscribed": {"score": -30},
"bounced_email": {"score": -20},
},
"thresholds": {
"hot": 76,
"sql": 51,
"mql": 26,
"nurture": 0,
},
}
def score_lead(lead, model=None):
"""Score a single lead against the scoring model."""
if model is None:
model = DEFAULT_MODEL
total_score = 0
scoring_details = []
# Demographic scoring
for signal, config in model.get("demographic", {}).items():
lead_value = lead.get(signal)
if lead_value is None:
continue
matched = False
if "values" in config:
if isinstance(lead_value, str):
matched = any(v.lower() in lead_value.lower() for v in config["values"])
elif isinstance(lead_value, bool):
matched = lead_value
elif "min" in config and "max" in config:
try:
val = float(lead_value)
matched = config["min"] <= val <= config["max"]
except (ValueError, TypeError):
pass
if matched:
total_score += config["score"]
scoring_details.append({
"signal": signal,
"type": "demographic",
"score": config["score"],
"value": lead_value,
})
# Behavioral scoring
for signal, config in model.get("behavioral", {}).items():
lead_value = lead.get(signal, False)
if lead_value:
total_score += config["score"]
scoring_details.append({
"signal": signal,
"type": "behavioral",
"score": config["score"],
})
# Negative signals
for signal, config in model.get("negative", {}).items():
lead_value = lead.get(signal, False)
if lead_value:
total_score += config["score"]
scoring_details.append({
"signal": signal,
"type": "negative",
"score": config["score"],
})
# Determine segment
thresholds = model.get("thresholds", DEFAULT_MODEL["thresholds"])
if total_score >= thresholds.get("hot", 76):
segment = "hot"
elif total_score >= thresholds.get("sql", 51):
segment = "sql"
elif total_score >= thresholds.get("mql", 26):
segment = "mql"
else:
segment = "nurture"
return {
"lead": lead.get("name", lead.get("email", "Unknown")),
"total_score": total_score,
"segment": segment,
"details": scoring_details,
"demographic_score": sum(d["score"] for d in scoring_details if d["type"] == "demographic"),
"behavioral_score": sum(d["score"] for d in scoring_details if d["type"] == "behavioral"),
"negative_score": sum(d["score"] for d in scoring_details if d["type"] == "negative"),
}
def simulate_scoring(leads, model=None):
"""Score all leads and generate distribution analysis."""
results = [score_lead(lead, model) for lead in leads]
# Segment distribution
segments = {"hot": 0, "sql": 0, "mql": 0, "nurture": 0}
for r in results:
segments[r["segment"]] = segments.get(r["segment"], 0) + 1
# Score distribution
scores = [r["total_score"] for r in results]
avg_score = sum(scores) / max(len(scores), 1)
min_score = min(scores) if scores else 0
max_score = max(scores) if scores else 0
# Validation against outcomes (if available)
validation = None
leads_with_outcome = [l for l in leads if "converted" in l]
if leads_with_outcome:
scored_with_outcome = []
for lead in leads_with_outcome:
result = score_lead(lead, model)
result["actual_converted"] = lead["converted"]
scored_with_outcome.append(result)
# Check if high scores correlate with conversions
high_scored = [s for s in scored_with_outcome if s["segment"] in ("hot", "sql")]
low_scored = [s for s in scored_with_outcome if s["segment"] in ("mql", "nurture")]
high_conversion = (
sum(1 for s in high_scored if s["actual_converted"]) / max(len(high_scored), 1) * 100
)
low_conversion = (
sum(1 for s in low_scored if s["actual_converted"]) / max(len(low_scored), 1) * 100
)
validation = {
"leads_with_outcome": len(leads_with_outcome),
"high_score_conversion_rate": round(high_conversion, 1),
"low_score_conversion_rate": round(low_conversion, 1),
"model_effective": high_conversion > low_conversion,
"lift": round(high_conversion / max(low_conversion, 0.1), 1),
}
results.sort(key=lambda x: x["total_score"], reverse=True)
return {
"total_leads": len(leads),
"segments": segments,
"score_stats": {
"average": round(avg_score, 1),
"min": min_score,
"max": max_score,
},
"leads": results,
"validation": validation,
"segment_percentages": {
seg: round(count / max(len(leads), 1) * 100, 1)
for seg, count in segments.items()
},
}
def get_demo_data():
return [
{"name": "Alice VP", "title_match": "VP of Marketing", "company_size_fit": 200, "industry_fit": "saas", "pricing_page_visit": True, "demo_requested": True, "emails_opened_3plus": True, "converted": True},
{"name": "Bob Manager", "title_match": "Product Manager", "company_size_fit": 500, "industry_fit": "technology", "case_study_viewed": True, "content_downloaded": True, "converted": True},
{"name": "Carol Dev", "title_match": "Developer", "company_size_fit": 100, "industry_fit": "saas", "trial_started": True, "feature_used": True, "converted": False},
{"name": "Dan Student", "title_match": "Student", "company_size_fit": 5, "student_email": True, "content_downloaded": True, "converted": False},
{"name": "Eve Director", "title_match": "Director of Ops", "company_size_fit": 1000, "industry_fit": "fintech", "pricing_page_visit": True, "webinar_attended": True, "demo_requested": True, "converted": True},
{"name": "Frank Lead", "title_match": "Team Lead", "company_size_fit": 80, "industry_fit": "retail", "emails_opened_3plus": True, "converted": False},
]
def format_report(analysis):
"""Format human-readable report."""
lines = []
lines.append("=" * 65)
lines.append("LEAD SCORING SIMULATION")
lines.append("=" * 65)
lines.append(f"Total Leads: {analysis['total_leads']}")
lines.append(f"Avg Score: {analysis['score_stats']['average']}")
lines.append(f"Range: {analysis['score_stats']['min']} to {analysis['score_stats']['max']}")
lines.append("")
# Segment distribution
lines.append("--- SEGMENT DISTRIBUTION ---")
for seg in ["hot", "sql", "mql", "nurture"]:
count = analysis["segments"].get(seg, 0)
pct = analysis["segment_percentages"].get(seg, 0)
bar = "#" * int(pct / 5) + "." * (20 - int(pct / 5))
lines.append(f" {seg.upper():<8} [{bar}] {count:>4} ({pct:.0f}%)")
lines.append("")
# Top leads
lines.append("--- LEAD SCORES ---")
lines.append(f"{'Lead':<20} {'Score':>6} {'Demo':>5} {'Behav':>5} {'Neg':>5} {'Segment':>8}")
lines.append("-" * 55)
for lead in analysis["leads"]:
lines.append(
f"{lead['lead']:<20} {lead['total_score']:>6} {lead['demographic_score']:>5} "
f"{lead['behavioral_score']:>5} {lead['negative_score']:>5} {lead['segment']:>8}"
)
lines.append("")
# Validation
if analysis["validation"]:
v = analysis["validation"]
lines.append("--- MODEL VALIDATION ---")
lines.append(f" High-score conversion: {v['high_score_conversion_rate']:.0f}%")
lines.append(f" Low-score conversion: {v['low_score_conversion_rate']:.0f}%")
lines.append(f" Lift: {v['lift']:.1f}x")
lines.append(f" Model effective: {'Yes' if v['model_effective'] else 'No'}")
return "\n".join(lines)
def main():
parser = argparse.ArgumentParser(description="Simulate and validate lead scoring models")
parser.add_argument("input", nargs="?", help="JSON file with lead data")
parser.add_argument("--model", help="Custom scoring model JSON")
parser.add_argument("--json", action="store_true", dest="json_output", help="Output JSON")
parser.add_argument("--demo", action="store_true", help="Run with demo data")
args = parser.parse_args()
model = None
if args.model:
with open(args.model, "r") as f:
model = json.load(f)
if args.demo:
leads = get_demo_data()
elif args.input:
try:
with open(args.input, "r", encoding="utf-8") as f:
data = json.load(f)
leads = data if isinstance(data, list) else data.get("leads", [])
except FileNotFoundError:
print(f"Error: File not found: {args.input}", file=sys.stderr)
sys.exit(1)
else:
parser.print_help()
sys.exit(1)
analysis = simulate_scoring(leads, model)
if args.json_output:
print(json.dumps(analysis, indent=2))
else:
print(format_report(analysis))
if __name__ == "__main__":
main()
#!/usr/bin/env python3
"""MarTech Stack Auditor - Audit marketing technology stack for gaps and redundancies.
Evaluates each tool on integration health, utilization, cost efficiency,
and identifies overlaps, gaps, and optimization opportunities.
Usage:
python martech_stack_auditor.py stack.json
python martech_stack_auditor.py stack.json --json
python martech_stack_auditor.py --demo
"""
import argparse
import json
import sys
REQUIRED_CATEGORIES = {
"crm": {"priority": "critical", "description": "Customer relationship management"},
"marketing_automation": {"priority": "critical", "description": "Email workflows, lead scoring"},
"analytics": {"priority": "critical", "description": "Traffic and behavior tracking"},
"email": {"priority": "critical", "description": "Email sending and deliverability"},
"ad_platforms": {"priority": "high", "description": "Paid advertising management"},
"seo": {"priority": "high", "description": "Keyword research and tracking"},
"social_management": {"priority": "medium", "description": "Social publishing and scheduling"},
"content_management": {"priority": "high", "description": "Content creation and hosting"},
"attribution": {"priority": "medium", "description": "Multi-touch attribution"},
"abm": {"priority": "medium", "description": "Account-based marketing"},
}
def audit_stack(tools):
"""Audit a MarTech stack for gaps, redundancies, and optimization."""
categories_covered = {}
total_annual_cost = 0
tool_results = []
for tool in tools:
name = tool.get("name", "Unknown")
category = tool.get("category", "other")
annual_cost = tool.get("annual_cost", 0)
utilization = tool.get("utilization_pct", 50) # 0-100
integrations = tool.get("integrations", [])
has_crm_integration = tool.get("crm_connected", False)
owner = tool.get("owner", "unassigned")
users = tool.get("active_users", 0)
total_annual_cost += annual_cost
# Score the tool
scores = {}
# Integration score
integration_score = min(100, len(integrations) * 15)
if has_crm_integration:
integration_score = min(100, integration_score + 30)
scores["integration"] = integration_score
# Utilization score
scores["utilization"] = utilization
# Cost efficiency (cost per user per month)
if users > 0 and annual_cost > 0:
cost_per_user_month = annual_cost / 12 / users
scores["cost_efficiency"] = max(0, 100 - cost_per_user_month) # Lower cost = higher score
else:
scores["cost_efficiency"] = 50
# Ownership
scores["governance"] = 100 if owner != "unassigned" else 0
overall = sum(scores.values()) / len(scores)
# Issues
issues = []
if not has_crm_integration:
issues.append({"severity": "high", "issue": "Not connected to CRM"})
if utilization < 30:
issues.append({"severity": "high", "issue": f"Low utilization ({utilization}%)"})
elif utilization < 60:
issues.append({"severity": "medium", "issue": f"Moderate utilization ({utilization}%)"})
if owner == "unassigned":
issues.append({"severity": "medium", "issue": "No assigned owner"})
# Track categories
if category not in categories_covered:
categories_covered[category] = []
categories_covered[category].append(name)
tool_results.append({
"name": name,
"category": category,
"annual_cost": annual_cost,
"utilization": utilization,
"crm_connected": has_crm_integration,
"active_users": users,
"owner": owner,
"scores": scores,
"overall_score": round(overall, 1),
"issues": issues,
"recommendation": _recommend(overall, utilization, annual_cost),
})
# Identify redundancies (multiple tools in same category)
redundancies = {cat: tools_list for cat, tools_list in categories_covered.items() if len(tools_list) > 1}
# Identify gaps (required categories not covered)
gaps = []
for cat, config in REQUIRED_CATEGORIES.items():
if cat not in categories_covered:
gaps.append({
"category": cat,
"priority": config["priority"],
"description": config["description"],
})
# Cost optimization
low_util_cost = sum(t["annual_cost"] for t in tool_results if t["utilization"] < 30)
potential_savings = low_util_cost * 0.5 # Assume 50% could be saved
# Stack health score
coverage_score = (len(categories_covered) / len(REQUIRED_CATEGORIES)) * 100
avg_tool_score = sum(t["overall_score"] for t in tool_results) / max(len(tool_results), 1)
redundancy_penalty = len(redundancies) * 5
stack_health = max(0, min(100, (coverage_score + avg_tool_score) / 2 - redundancy_penalty))
return {
"stack_health": round(stack_health, 1),
"total_tools": len(tools),
"total_annual_cost": total_annual_cost,
"potential_savings": round(potential_savings, 2),
"categories_covered": len(categories_covered),
"categories_required": len(REQUIRED_CATEGORIES),
"tools": sorted(tool_results, key=lambda x: x["overall_score"]),
"redundancies": redundancies,
"gaps": sorted(gaps, key=lambda x: {"critical": 0, "high": 1, "medium": 2}[x["priority"]]),
"recommendations": _stack_recommendations(tool_results, redundancies, gaps),
}
def _recommend(score, utilization, cost):
if score < 40 and utilization < 30:
return "REMOVE - Low score and utilization"
elif score < 50:
return "REVIEW - Consider replacement or better integration"
elif utilization < 40:
return "TRAIN - Increase adoption through team training"
elif score >= 75:
return "KEEP - Well-utilized and integrated"
return "OPTIMIZE - Good tool, improve integration or usage"
def _stack_recommendations(tools, redundancies, gaps):
recs = []
if gaps:
critical_gaps = [g for g in gaps if g["priority"] == "critical"]
if critical_gaps:
recs.append(f"CRITICAL: Missing {len(critical_gaps)} essential categories: {', '.join(g['category'] for g in critical_gaps)}")
if redundancies:
recs.append(f"REDUNDANCY: {len(redundancies)} categories have overlapping tools. Consolidate to reduce cost.")
low_util = [t for t in tools if t["utilization"] < 30]
if low_util:
recs.append(f"WASTE: {len(low_util)} tools have <30% utilization. Review for removal or training.")
disconnected = [t for t in tools if not t["crm_connected"]]
if disconnected:
recs.append(f"INTEGRATION: {len(disconnected)} tools not connected to CRM. Data silos likely.")
return recs
def get_demo_data():
return [
{"name": "HubSpot", "category": "marketing_automation", "annual_cost": 14400, "utilization_pct": 85, "crm_connected": True, "integrations": ["salesforce", "slack", "ga4"], "owner": "Marketing Ops", "active_users": 12},
{"name": "Google Analytics 4", "category": "analytics", "annual_cost": 0, "utilization_pct": 70, "crm_connected": False, "integrations": ["google_ads", "gtm"], "owner": "Marketing Ops", "active_users": 20},
{"name": "Ahrefs", "category": "seo", "annual_cost": 2388, "utilization_pct": 45, "crm_connected": False, "integrations": [], "owner": "Content Lead", "active_users": 3},
{"name": "SEMrush", "category": "seo", "annual_cost": 2400, "utilization_pct": 20, "crm_connected": False, "integrations": [], "owner": "unassigned", "active_users": 1},
{"name": "Buffer", "category": "social_management", "annual_cost": 600, "utilization_pct": 60, "crm_connected": False, "integrations": ["twitter", "linkedin"], "owner": "Social Lead", "active_users": 3},
{"name": "Salesforce", "category": "crm", "annual_cost": 36000, "utilization_pct": 80, "crm_connected": True, "integrations": ["hubspot", "slack", "zoom"], "owner": "Sales Ops", "active_users": 25},
]
def format_report(analysis):
"""Format human-readable audit report."""
lines = []
lines.append("=" * 70)
lines.append("MARTECH STACK AUDIT REPORT")
lines.append("=" * 70)
lines.append(f"Stack Health: {analysis['stack_health']:.0f}/100")
lines.append(f"Total Tools: {analysis['total_tools']}")
lines.append(f"Annual Cost: ${analysis['total_annual_cost']:,.0f}")
lines.append(f"Potential Savings: ${analysis['potential_savings']:,.0f}")
lines.append(f"Coverage: {analysis['categories_covered']}/{analysis['categories_required']} required categories")
lines.append("")
# Tool breakdown
lines.append("--- TOOL SCORES ---")
lines.append(f"{'Tool':<20} {'Category':<22} {'Cost':>8} {'Util':>5} {'Score':>6} {'Action':>8}")
lines.append("-" * 75)
for t in sorted(analysis["tools"], key=lambda x: x["overall_score"]):
lines.append(
f"{t['name']:<20} {t['category']:<22} ${t['annual_cost']:>7,} {t['utilization']:>4}% {t['overall_score']:>5.0f} {t['recommendation'].split(' - ')[0]:>8}"
)
lines.append("")
# Gaps
if analysis["gaps"]:
lines.append("--- GAPS ---")
for g in analysis["gaps"]:
lines.append(f" [{g['priority'].upper()}] Missing: {g['category']} - {g['description']}")
lines.append("")
# Redundancies
if analysis["redundancies"]:
lines.append("--- REDUNDANCIES ---")
for cat, tool_names in analysis["redundancies"].items():
lines.append(f" {cat}: {', '.join(tool_names)} (consolidate to save cost)")
lines.append("")
# Recommendations
if analysis["recommendations"]:
lines.append("--- RECOMMENDATIONS ---")
for rec in analysis["recommendations"]:
lines.append(f" * {rec}")
return "\n".join(lines)
def main():
parser = argparse.ArgumentParser(description="Audit MarTech stack for gaps and redundancies")
parser.add_argument("input", nargs="?", help="JSON file with tool data")
parser.add_argument("--json", action="store_true", dest="json_output", help="Output JSON")
parser.add_argument("--demo", action="store_true", help="Run with demo data")
args = parser.parse_args()
if args.demo:
tools = get_demo_data()
elif args.input:
try:
with open(args.input, "r", encoding="utf-8") as f:
data = json.load(f)
tools = data if isinstance(data, list) else data.get("tools", data.get("stack", []))
except FileNotFoundError:
print(f"Error: File not found: {args.input}", file=sys.stderr)
sys.exit(1)
else:
parser.print_help()
sys.exit(1)
analysis = audit_stack(tools)
if args.json_output:
print(json.dumps(analysis, indent=2))
else:
print(format_report(analysis))
if __name__ == "__main__":
main()
Related skills
FAQ
What does the routing matrix do?
It matches what the user says to the correct marketing skill, for example landing-page requests to the Landing Page Generator.
Can it run a full campaign?
Yes, it sequences skills into an orchestration plan, such as a product/feature launch or a content marketing sprint.