
Competitive Teardown
- 99 installs
- 451 repo stars
- Updated July 21, 2026
- borghei/claude-skills
Competitive Teardown is a Claude skill for systematic competitor analysis using a 12-dimension scoring rubric, feature matrices, SWOT, pricing deconstruction, and battle cards.
About
Competitive Teardown is a competitor-analysis framework that collects intelligence across six sources, scores competitors on a 12-dimension rubric, and builds feature-comparison matrices, SWOT analyses, pricing deconstructions, UX audits, and action plans. A team uses it before a roadmap session, after a competitor launch, for quarterly reviews, or to prep a sales battle card. It outputs battle-card-ready results and stakeholder presentation templates.
- 12-dimension competitor scoring rubric with feature matrices, SWOT, and pricing deconstruction
- Collects intelligence from 6 sources (website, reviews, job postings, SEO, and more)
- Produces battle cards and stakeholder presentation templates
Competitive Teardown by the numbers
- 99 all-time installs (skills.sh)
- Ranked #445 of 853 Sales & Marketing skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
competitive-teardown capabilities & compatibility
- Capabilities
- competitor analysis · swot analysis · battle cards · pricing analysis
- Works with
- Use cases
- research · marketing
- Pricing
- Free
What competitive-teardown says it does
a 12-dimension scoring rubric, feature comparison matrices, SWOT analysis, pricing model deconstruction, UX audit methodology, and strategic action plans
Produces battle-card-ready output and stakeholder presentation templates.
npx skills add https://github.com/borghei/claude-skills --skill competitive-teardownAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 99 |
|---|---|
| repo stars | ★ 451 |
| Last updated | July 21, 2026 |
| Repository | borghei/claude-skills ↗ |
What it does
Run a systematic competitor teardown with a 12-dimension scorecard, SWOT, and battle cards.
Who is it for?
Product and marketing teams analyzing competitors before a roadmap session or sales pitch
Skip if: Writing code or non-competitive market sizing
When should I use this skill?
Before a product strategy session, when a competitor launches a major feature, or when a sales battle card is needed
What you get
Produces a numeric competitor scorecard, comparison matrices, SWOT, and battle-card-ready output.
- 12-dimension scorecard
- feature comparison matrix
- SWOT analysis
By the numbers
- 12-dimension scoring rubric
- Collects data from 6 intelligence sources
- Recommends 50+ reviews per competitor
Files
Competitive Teardown
Production-grade competitor analysis framework covering systematic data collection across 6 intelligence sources, a 12-dimension scoring rubric, feature comparison matrices, SWOT analysis, pricing model deconstruction, UX audit methodology, and strategic action plans. Produces battle-card-ready output and stakeholder presentation templates.
---
Table of Contents
- When to Use
- Teardown Workflow
- Data Collection Framework
- 12-Dimension Scoring Rubric
- Feature Comparison Matrix
- Pricing Analysis Framework
- SWOT Analysis Template
- UX Audit Methodology
- Positioning Map
- Action Plan Framework
- Battle Card Template
- Stakeholder Presentation
- Output Artifacts
- Related Skills
---
When to Use
| Trigger | Teardown Scope |
|---|---|
| Before product strategy or roadmap session | Full teardown (2-4 competitors) |
| Competitor launches major feature or pricing change | Focused teardown (1 competitor, updated dimensions only) |
| Quarterly competitive review | Update existing teardowns + trend analysis |
| Before a sales pitch (battle card needed) | Single-competitor battle card |
| Entering a new market segment | Full teardown of segment incumbents |
---
Clarify First
Before running the teardown, confirm these inputs. If any is unknown or vague, ASK — do not assume:
- [ ] Competitors + primary focus — the 2-4 names and which is the main threat (sets scorecard columns and depth)
- [ ] Your own product baseline — so the 12-dimension scorecard and feature matrix have a "you" column to compare against
- [ ] Decision this feeds — roadmap session, sales battle card, or new-market entry (determines full teardown vs single battle card vs segment incumbents)
- [ ] Available data sources — pricing pages, 50+ reviews, product access (the rubric needs evidence; thin data caps which dimensions are scorable)
Stop rule: ask only the 2-3 that most change the output. If the user says "just draft it," proceed and list your assumptions at the top of the teardown.
Teardown Workflow
Step-by-Step Process
1. Define competitors -- List 2-4 competitors. Confirm which is the primary focus. 2. Collect data -- Gather intelligence from at least 3 of the 6 sources per competitor. 3. Score using rubric -- Apply the 12-dimension rubric to produce a numeric scorecard. 4. Generate comparison outputs -- Feature matrix, pricing analysis, SWOT, positioning map. 5. Build action plan -- Translate findings into quick wins, medium-term, and strategic priorities. 6. Package for stakeholders -- Assemble the presentation or battle card.
Validation Checkpoints
- Before scoring: Confirm you have pricing data, 20+ user reviews, and recent product data
- Before action plan: Every dimension should have a score and supporting evidence
- Before presentation: Every recommendation should tie back to a data point
---
Data Collection Framework
Source 1: Website and Product Analysis
| Data Point | Where to Find | What It Signals |
|---|---|---|
| Pricing tiers and price points | Pricing page | Market positioning, target segment |
| Feature lists per tier | Pricing + feature pages | Packaging strategy |
| Primary CTA and messaging | Homepage hero | Positioning and ICP |
| Case studies and customer logos | Case study page, homepage | Target segments, social proof |
| Integration partnerships | Integrations page | Ecosystem strategy |
| Trust signals | Footer, security page | Enterprise readiness |
| Job postings | Careers page, LinkedIn | Growth direction, tech stack |
Source 2: User Reviews
Platforms: G2, Capterra, TrustRadius, App Store, Product Hunt
| Category | What to Track | Strategic Value |
|---|---|---|
| Praise themes | What users love (top 5 themes) | Their defensible strengths |
| Complaint themes | What users hate (top 5 themes) | Your opportunities |
| Feature requests | What users want but do not have | Product roadmap gaps |
| Switching mentions | Why users left competitors | Competitive migration paths |
| Rating trends | Quarter-over-quarter rating change | Improving or declining |
Sample size target: 50+ reviews per competitor for reliable themes.
Source 3: Job Postings
| Signal | What It Means |
|---|---|
| High engineering hiring | Product investment, scaling |
| AI/ML roles | AI features coming |
| Sales team expansion | Moving upmarket or expanding geographically |
| Customer success roles | Retention focus, enterprise motion |
| Compliance/legal roles | Regulatory expansion |
| Reduced postings | Cost cutting, potential contraction |
Source 4: SEO and Content Analysis
| Metric | Tool | Strategic Value |
|---|---|---|
| Top 20 organic keywords | Ahrefs, SEMrush, GSC | Content strategy and targeting |
| Domain authority | Ahrefs, Moz | Brand strength |
| Blog publishing cadence | Manual check | Content investment level |
| Ranking pages (product vs blog vs docs) | Ahrefs | Traffic composition |
Source 5: Social Media and Community
| Platform | What to Track |
|---|---|
| Twitter/X | Product announcements, customer praise, complaints |
| Honest reviews, comparison threads | |
| Thought leadership, hiring signals, employee count | |
| Community forums | Feature requests, workarounds, power user patterns |
| Discord/Slack | Community size, engagement level |
Source 6: Financial and Market Data
| Source | Data Available |
|---|---|
| Crunchbase | Funding, valuation, investors, employee count |
| Employee count trend (growth proxy) | |
| Public filings (if public) | Revenue, growth rate, churn |
| Industry reports | Market share estimates |
---
12-Dimension Scoring Rubric
Score each competitor (and your own product) on a 1-5 scale with evidence notes.
| # | Dimension | 1 (Weak) | 3 (Average) | 5 (Best-in-class) |
|---|---|---|---|---|
| 1 | Features | Core only, many gaps | Solid coverage | Comprehensive + unique capabilities |
| 2 | Pricing | Confusing or overpriced | Market-rate, clear | Transparent, flexible, fair |
| 3 | UX / Design | Confusing, high friction | Functional, adequate | Delightful, minimal friction |
| 4 | Performance | Slow, unreliable | Acceptable | Fast, high uptime, responsive |
| 5 | Documentation | Sparse, outdated | Decent coverage | Comprehensive, searchable, with examples |
| 6 | Support | Email only, slow response | Chat + email, reasonable SLA | 24/7, multiple channels, fast |
| 7 | Integrations | 0-5 native integrations | 6-25 integrations | 26+ or deep ecosystem (API + marketplace) |
| 8 | Security | No mentions | SOC2 claimed | SOC2 Type II + ISO 27001 + GDPR |
| 9 | Scalability | No enterprise tier | Mid-market ready | Enterprise-grade (SSO, SCIM, SLA) |
| 10 | Brand | Generic, unmemorable | Decent positioning | Strong, differentiated, recognized |
| 11 | Community | None | Forum or Slack exists | Active, vibrant, user-generated content |
| 12 | Innovation | No releases in 6+ months | Quarterly releases | Frequent, meaningful, well-communicated |
Scoring Output Format
| Dimension | Your Product | Competitor A | Competitor B | Competitor C |
|---|---|---|---|---|
| Features | 4 | 3 | 5 | 3 |
| Pricing | 3 | 4 | 3 | 4 |
| ... | ... | ... | ... | ... |
| Total (/60) | 38 | 35 | 42 | 33 |
---
Feature Comparison Matrix
Matrix Structure
| Feature Category | Your Product | Competitor A | Competitor B | Notes |
|---|---|---|---|---|
| Core Features | ||||
| Feature 1 | Full | Full | Partial | Comp B lacks [specific capability] |
| Feature 2 | Full | Missing | Full | Our differentiator |
| Feature 3 | Partial | Full | Full | Gap to close |
| Platform | ||||
| Web app | Yes | Yes | Yes | |
| iOS app | Yes | No | Yes | Comp A gap |
| API access | Full | Limited | Full | |
| Enterprise | ||||
| SSO | Yes | No | Yes | |
| Audit logs | Yes | Yes | No | |
| Custom SLA | Yes | Yes | Yes |
Score per cell: Full = 5, Partial = 3, Basic = 2, Missing = 0
---
Pricing Analysis Framework
Pricing Model Comparison
| Attribute | Your Product | Competitor A | Competitor B |
|---|---|---|---|
| Model type | Per seat | Usage-based | Flat rate |
| Free tier | Yes (3 users) | Yes (limited) | No |
| Entry price | $15/user/mo | $29/mo (up to 1K events) | $49/mo |
| Mid-tier price | $35/user/mo | $99/mo | $99/mo |
| Enterprise | Custom | Custom | $249/mo |
| Annual discount | 20% | 15% | 2 months free |
| Trial | 14-day free | 7-day free | 30-day money-back |
Pricing Position Map
| Position | Characteristic | Your Strategy |
|---|---|---|
| Price leader | Lowest price, may signal lower quality | Win on value, not features |
| Value leader | Best features-per-dollar ratio | Win on differentiation |
| Premium | Highest price, justified by brand/features | Win on exclusivity and support |
| Disruptor | Radically different model (free, usage-based) | Win on accessibility |
---
SWOT Analysis Template
For each competitor, produce:
Competitor SWOT
| Quadrant | Points |
|---|---|
| Strengths (Their advantages) | 3-5 bullets, each anchored to a data signal |
| Weaknesses (Their vulnerabilities) | 3-5 bullets, each tied to reviews, missing features, or complaints |
| Opportunities for Us | What their weaknesses create for us |
| Threats to Us | What their strengths mean for our position |
Evidence rule: Every bullet must cite the data source (review quote, pricing page, job posting count, feature comparison, etc.).
---
UX Audit Methodology
First-Run Experience Audit
| Dimension | What to Measure | How to Score |
|---|---|---|
| Time to first value (TTFV) | Minutes from signup to first meaningful output | < 5 min = 5, 5-15 min = 3, > 15 min = 1 |
| Steps to activation | Number of screens/actions before core value | < 3 = 5, 3-7 = 3, > 7 = 1 |
| Credit card required | Required at signup? | No = 5, Optional = 3, Required = 1 |
| Onboarding quality | Wizard, tooltips, empty states | Comprehensive = 5, Basic = 3, None = 1 |
| SSO available | Google, Microsoft, etc. | Yes = 5, No = 1 |
Core Workflow Audit
For the 3 most common workflows, compare:
| Workflow | Steps (Yours) | Steps (Competitor) | Friction Points |
|---|---|---|---|
| [Primary workflow] | N | N | Specific UX issues |
| [Secondary workflow] | N | N | Specific UX issues |
| [Tertiary workflow] | N | N | Specific UX issues |
---
Positioning Map
2x2 Positioning Map
Choose the two axes most relevant to your market:
| Common Axis Pairs | When to Use |
|---|---|
| Simple / Complex x Low Price / High Price | General product comparison |
| SMB / Enterprise x Narrow / Broad Features | Market segment analysis |
| Self-Serve / Sales-Led x Point Solution / Platform | Go-to-market comparison |
| Technical / Non-Technical x Niche / Horizontal | Audience analysis |
Map Template
High Price / Enterprise
│
│
[Competitor B] │ [Competitor C]
│
Simple ─────────────────┼─────────────────── Complex
│
[YOUR PRODUCT] │ [Competitor A]
│
│
Low Price / SMB---
Action Plan Framework
Three Horizons
| Horizon | Timeframe | Effort | Examples |
|---|---|---|---|
| Quick wins | 0-4 weeks | Low | Publish comparison pages, update pricing page, add missing trust badges |
| Medium-term | 1-3 months | Moderate | Build top-requested integration, improve onboarding TTFV, launch free tier |
| Strategic | 3-12 months | High | Enter new market segment, build API v2, achieve SOC2 Type II |
Priority Scoring
For each action item, score:
| Factor | Weight | Scale |
|---|---|---|
| Competitive impact | 40% | How much does this close or widen a gap? |
| Customer demand | 30% | How many customers/prospects request this? |
| Implementation effort | 20% | How hard is this to build/execute? |
| Revenue impact | 10% | Direct revenue contribution? |
---
Battle Card Template
One-Page Battle Card
COMPETITOR: [Name]
LAST UPDATED: [Date]
THREAT LEVEL: [LOW / MEDIUM / HIGH / CRITICAL]
THEIR POSITIONING: [1 sentence]
OUR POSITIONING AGAINST THEM: [1 sentence]
WHERE THEY WIN:
- [Strength 1 with evidence]
- [Strength 2 with evidence]
- [Strength 3 with evidence]
WHERE WE WIN:
- [Advantage 1 with evidence]
- [Advantage 2 with evidence]
- [Advantage 3 with evidence]
LANDMINES (questions that expose their weaknesses):
- "How does [competitor] handle [weakness area]?"
- "Can you show me [feature they lack]?"
- "What do their customers say about [common complaint]?"
OBJECTION HANDLING:
- "They're cheaper" → [Response with value framing]
- "They have [feature]" → [Response with alternative/roadmap]
- "Everyone uses them" → [Response with differentiation]
PRICING COMPARISON:
[Quick comparison table]
CUSTOMER QUOTE:
"[Quote from a customer who switched from this competitor to you]"---
Stakeholder Presentation
7-Slide Structure
| Slide | Content |
|---|---|
| 1. Executive Summary | Threat level, top strength, top opportunity, recommended action |
| 2. Market Position | 2x2 positioning map with all players |
| 3. Feature Scorecard | 12-dimension scores, total comparison |
| 4. Pricing Analysis | Pricing comparison table + key pricing insight |
| 5. UX Comparison | Where they win (3 bullets) vs where we win (3 bullets) |
| 6. Voice of Customer | Top 3 competitor complaints from reviews (quoted) |
| 7. Action Plan | Quick wins, medium-term, strategic priorities |
---
Output Artifacts
| Artifact | Format | Description |
|---|---|---|
| Data Collection Report | Structured notes per source | Raw intelligence organized by source type |
| 12-Dimension Scorecard | Scored table with evidence | Numeric comparison across all dimensions |
| Feature Comparison Matrix | Grid table | Feature-by-feature comparison with scoring |
| Pricing Analysis | Comparison table + position map | Model comparison, tier mapping, positioning |
| SWOT Analysis | Per-competitor 4-quadrant | Anchored to data signals |
| UX Audit | Scored checklist | TTFV, steps, friction analysis |
| Positioning Map | 2x2 diagram | Visual market position |
| Action Plan | Three-horizon table | Prioritized competitive responses |
| Battle Card | One-page template | Sales-ready competitive reference |
| Stakeholder Presentation | 7-slide outline | Executive-ready competitive briefing |
---
Related Skills
- competitor-alternatives -- Use for creating comparison and alternative pages for SEO/marketing. Competitive-teardown provides the intelligence; competitor-alternatives produces the marketing content.
- pricing-strategy -- Use when competitive analysis reveals pricing misalignment. Feed teardown pricing data into pricing-strategy.
- page-cro -- Use for optimizing your comparison or competitor landing pages for conversion.
- content-creator -- Use for writing competitive content (blog posts, comparison guides) based on teardown findings.
---
Tool Reference
1. competitor_scorer.py
Purpose: Score competitors across the 12-dimension rubric and generate a numeric comparison scorecard.
python scripts/competitor_scorer.py competitor_data.json
python scripts/competitor_scorer.py competitor_data.json --json| Flag | Required | Description |
|---|---|---|
competitor_data.json | Yes | JSON file with competitor dimension scores and evidence |
--json | No | Output results as JSON |
--weights | No | Custom dimension weights as JSON string (default: equal weights) |
2. feature_matrix_builder.py
Purpose: Build a feature comparison matrix from structured feature data and calculate coverage scores.
python scripts/feature_matrix_builder.py features.json
python scripts/feature_matrix_builder.py features.json --json| Flag | Required | Description |
|---|---|---|
features.json | Yes | JSON file with feature comparison data |
--json | No | Output results as JSON |
3. battle_card_generator.py
Purpose: Generate a one-page battle card from competitor data for sales team use.
python scripts/battle_card_generator.py competitor_profile.json
python scripts/battle_card_generator.py competitor_profile.json --json| Flag | Required | Description |
|---|---|---|
competitor_profile.json | Yes | JSON file with competitor profile data |
--json | No | Output results as JSON |
--format | No | Output format: text (default) or markdown |
---
Troubleshooting
| Problem | Likely Cause | Solution |
|---|---|---|
| Scoring feels subjective across analysts | No shared rubric calibration | Use the 12-dimension rubric with explicit 1/3/5 definitions; have two analysts score independently and reconcile |
| Data is stale within weeks of teardown | Fast-moving competitors | Set calendar reminders for monthly pricing checks and quarterly full refreshes; use competitor_scorer.py to track score changes over time |
| Feature matrix has too many rows to be useful | Trying to capture every micro-feature | Group features into 8-12 categories; detail only the top differentiators |
| Battle cards are not used by sales | Too long, too academic, or not actionable | Keep to one page; lead with "Where We Win" and "Landmines"; validate with 3 sales reps before distributing |
| Review data is contradictory | Small sample size or selection bias | Target 50+ reviews per competitor across G2, Capterra, and TrustRadius; weight recent reviews more heavily |
| Cannot get pricing data for enterprise tiers | Custom pricing not published | Use sales intel (request a demo), G2 pricing data, or customer interviews for directional estimates |
| SWOT analysis has no actionable output | Analysis lacks connection to action plan | Every SWOT bullet must map to a specific quick-win, medium-term, or strategic action |
---
Success Criteria
- 12-dimension scorecard completed with evidence notes for every score
- Feature matrix covers at least 80% of features that prospects evaluate
- Battle cards reviewed and approved by 3+ sales representatives
- Pricing data verified within the last 30 days
- Teardown produces at least 3 actionable quick wins and 2 strategic priorities
- Stakeholder presentation reviewed and feedback incorporated within 1 week
- Teardown data refreshed quarterly with score trend tracking
---
Scope & Limitations
- In scope: Product analysis, feature comparison, pricing deconstruction, UX audit, SWOT analysis, battle card creation, action plan generation
- Out of scope: Primary market research (customer interviews, surveys), financial modeling, legal competitive analysis, intellectual property assessment
- Data dependency: Quality depends on publicly available data, user reviews, and product access; some competitors may have limited public information
- Bias risk: Teardowns conducted by internal teams may have confirmation bias; consider external validation for high-stakes decisions
- Point-in-time: Teardowns are snapshots; competitors evolve continuously -- schedule regular refreshes
---
Integration Points
- competitor-alternatives -- Teardown provides the data; competitor-alternatives produces the marketing content (comparison and alternative pages)
- pricing-strategy -- When teardown reveals pricing misalignment, feed pricing data into pricing-strategy for repositioning analysis
- page-cro -- Use for optimizing your comparison or competitor landing pages for conversion after teardown produces the content
- sales-engineer -- Battle cards feed directly into sales engineering competitive positioning and RFP responses
- customer-success-manager -- When exit surveys reveal COMPETITOR as a top churn reason, use teardown data to understand what competitors offer that you do not
#!/usr/bin/env python3
"""
Battle Card Generator
Generate a one-page battle card from competitor profile data for sales
team use. Includes positioning, strengths/weaknesses, landmine questions,
objection handling, and pricing comparison.
Usage:
python battle_card_generator.py competitor_profile.json
python battle_card_generator.py competitor_profile.json --json
python battle_card_generator.py competitor_profile.json --format markdown
"""
import argparse
import json
import sys
from datetime import date
def generate_battle_card(data: dict, output_format: str = "text") -> dict:
"""Generate battle card from competitor profile."""
competitor = data.get("competitor", {})
your_product = data.get("your_product", {})
comp_name = competitor.get("name", "Competitor")
your_name = your_product.get("name", "Your Product")
# Threat assessment
threat_score = 0
if competitor.get("market_share_growing", False):
threat_score += 2
if competitor.get("recent_funding", False):
threat_score += 1
if competitor.get("targeting_your_icp", False):
threat_score += 2
if competitor.get("price_advantage", False):
threat_score += 1
if competitor.get("feature_parity", False):
threat_score += 2
if threat_score >= 6:
threat_level = "CRITICAL"
elif threat_score >= 4:
threat_level = "HIGH"
elif threat_score >= 2:
threat_level = "MEDIUM"
else:
threat_level = "LOW"
# Build battle card
card = {
"competitor_name": comp_name,
"your_product_name": your_name,
"last_updated": date.today().isoformat(),
"threat_level": threat_level,
"threat_score": threat_score,
"positioning": {
"their_positioning": competitor.get("positioning", "Not specified"),
"your_positioning_against_them": your_product.get("positioning_vs", "Not specified"),
},
"where_they_win": competitor.get("strengths", [])[:5],
"where_we_win": your_product.get("advantages", [])[:5],
"landmine_questions": _generate_landmines(competitor),
"objection_handling": _build_objection_handling(competitor, your_product),
"pricing_comparison": {
"their_pricing": competitor.get("pricing", {}),
"your_pricing": your_product.get("pricing", {}),
},
"customer_quotes": your_product.get("switcher_quotes", [])[:2],
"key_differentiators": your_product.get("differentiators", [])[:3],
}
return card
def _generate_landmines(competitor: dict) -> list:
"""Generate landmine questions that expose competitor weaknesses."""
landmines = []
weaknesses = competitor.get("weaknesses", [])
for w in weaknesses[:5]:
area = w.get("area", "this area")
detail = w.get("detail", "")
landmines.append({
"question": f"How does {competitor.get('name', 'the competitor')} handle {area}?",
"why_it_works": detail or f"They are weak in {area}.",
})
if not landmines:
landmines.append({
"question": "Can you show me customer case studies in my industry?",
"why_it_works": "Tests whether they have relevant customer proof.",
})
return landmines
def _build_objection_handling(competitor: dict, your_product: dict) -> list:
"""Build objection handling responses."""
objections = []
comp_name = competitor.get("name", "They")
if competitor.get("price_advantage", False):
objections.append({
"objection": f"{comp_name} is cheaper",
"response": your_product.get("price_response",
"Compare total cost of ownership including implementation, training, and ongoing support. Our customers see ROI within [X] months."),
})
for feat in competitor.get("unique_features", [])[:3]:
objections.append({
"objection": f"{comp_name} has {feat.get('name', 'this feature')}",
"response": feat.get("counter", f"We address this through {feat.get('alternative', 'our approach')}."),
})
if competitor.get("market_leader", False):
objections.append({
"objection": f"Everyone uses {comp_name}",
"response": your_product.get("market_response",
"Market share does not mean best fit. Here is what makes us different for your specific use case."),
})
return objections
def format_text(card: dict) -> str:
"""Format battle card as text."""
lines = []
lines.append("=" * 60)
lines.append(f"BATTLE CARD: {card['competitor_name']}")
lines.append(f"Last Updated: {card['last_updated']}")
lines.append(f"Threat Level: {card['threat_level']}")
lines.append("=" * 60)
pos = card["positioning"]
lines.append(f"\nTHEIR POSITIONING: {pos['their_positioning']}")
lines.append(f"OUR POSITIONING: {pos['your_positioning_against_them']}")
lines.append(f"\nWHERE THEY WIN:")
for s in card["where_they_win"]:
if isinstance(s, dict):
lines.append(f" - {s.get('point', s)}")
else:
lines.append(f" - {s}")
lines.append(f"\nWHERE WE WIN:")
for a in card["where_we_win"]:
if isinstance(a, dict):
lines.append(f" + {a.get('point', a)}")
else:
lines.append(f" + {a}")
lines.append(f"\nLANDMINE QUESTIONS:")
for lm in card["landmine_questions"]:
lines.append(f" Q: \"{lm['question']}\"")
lines.append(f" Why: {lm['why_it_works']}")
lines.append(f"\nOBJECTION HANDLING:")
for obj in card["objection_handling"]:
lines.append(f" \"{obj['objection']}\"")
lines.append(f" -> {obj['response']}")
if card["customer_quotes"]:
lines.append(f"\nCUSTOMER QUOTES:")
for q in card["customer_quotes"]:
if isinstance(q, dict):
lines.append(f" \"{q.get('quote', '')}\" -- {q.get('attribution', '')}")
else:
lines.append(f" \"{q}\"")
lines.append("")
return "\n".join(lines)
def format_markdown(card: dict) -> str:
"""Format battle card as markdown."""
lines = []
lines.append(f"# Battle Card: {card['competitor_name']}")
lines.append(f"\n**Last Updated:** {card['last_updated']} ")
lines.append(f"**Threat Level:** {card['threat_level']}")
pos = card["positioning"]
lines.append(f"\n## Positioning")
lines.append(f"**Their positioning:** {pos['their_positioning']} ")
lines.append(f"**Our positioning:** {pos['your_positioning_against_them']}")
lines.append(f"\n## Where They Win")
for s in card["where_they_win"]:
text = s.get("point", s) if isinstance(s, dict) else s
lines.append(f"- {text}")
lines.append(f"\n## Where We Win")
for a in card["where_we_win"]:
text = a.get("point", a) if isinstance(a, dict) else a
lines.append(f"- {text}")
lines.append(f"\n## Landmine Questions")
for lm in card["landmine_questions"]:
lines.append(f"- **\"{lm['question']}\"** -- {lm['why_it_works']}")
lines.append(f"\n## Objection Handling")
for obj in card["objection_handling"]:
lines.append(f"- **\"{obj['objection']}\"** -> {obj['response']}")
if card["customer_quotes"]:
lines.append(f"\n## Customer Quotes")
for q in card["customer_quotes"]:
if isinstance(q, dict):
lines.append(f"> \"{q.get('quote', '')}\" -- {q.get('attribution', '')}")
else:
lines.append(f"> \"{q}\"")
lines.append("")
return "\n".join(lines)
def main():
parser = argparse.ArgumentParser(
description="Generate a one-page battle card from competitor profile data."
)
parser.add_argument("input_file", help="JSON file with competitor profile data")
parser.add_argument("--json", action="store_true", help="Output results as JSON")
parser.add_argument("--format", choices=["text", "markdown"], default="text",
help="Output format (default: text)")
args = parser.parse_args()
try:
with open(args.input_file, "r") as f:
data = json.load(f)
except FileNotFoundError:
print(f"Error: File not found: {args.input_file}", file=sys.stderr)
sys.exit(1)
except json.JSONDecodeError as e:
print(f"Error: Invalid JSON in {args.input_file}: {e}", file=sys.stderr)
sys.exit(1)
card = generate_battle_card(data, args.format)
if args.json:
print(json.dumps(card, indent=2))
elif args.format == "markdown":
print(format_markdown(card))
else:
print(format_text(card))
if __name__ == "__main__":
main()
#!/usr/bin/env python3
"""
Competitor Scorer
Score competitors across a 12-dimension rubric and generate a numeric
comparison scorecard with gap analysis and strategic recommendations.
Usage:
python competitor_scorer.py competitor_data.json
python competitor_scorer.py competitor_data.json --json
"""
import argparse
import json
import sys
DIMENSIONS = [
"features", "pricing", "ux_design", "performance", "documentation",
"support", "integrations", "security", "scalability", "brand",
"community", "innovation",
]
DIMENSION_LABELS = {
"features": "Features",
"pricing": "Pricing",
"ux_design": "UX / Design",
"performance": "Performance",
"documentation": "Documentation",
"support": "Support",
"integrations": "Integrations",
"security": "Security",
"scalability": "Scalability",
"brand": "Brand",
"community": "Community",
"innovation": "Innovation",
}
def score_competitors(data: dict, custom_weights: dict = None) -> dict:
"""Score competitors across 12 dimensions."""
competitors = data.get("competitors", [])
if not competitors:
return {"error": "No competitor data provided."}
weights = custom_weights or {d: 1.0 / len(DIMENSIONS) for d in DIMENSIONS}
total_weight = sum(weights.values())
weights = {k: v / total_weight for k, v in weights.items()}
scorecards = []
for comp in competitors:
name = comp.get("name", "Unknown")
scores = comp.get("scores", {})
evidence = comp.get("evidence", {})
dimension_scores = []
raw_total = 0
weighted_total = 0.0
for dim in DIMENSIONS:
score = scores.get(dim, 0)
score = max(0, min(5, score))
weight = weights.get(dim, 1.0 / len(DIMENSIONS))
weighted = score * weight * len(DIMENSIONS)
dimension_scores.append({
"dimension": dim,
"label": DIMENSION_LABELS.get(dim, dim),
"score": score,
"weight": round(weight, 4),
"weighted_score": round(weighted, 2),
"evidence": evidence.get(dim, ""),
})
raw_total += score
weighted_total += weighted
scorecards.append({
"name": name,
"raw_total": raw_total,
"max_possible": len(DIMENSIONS) * 5,
"weighted_total": round(weighted_total, 2),
"percentage": round((raw_total / (len(DIMENSIONS) * 5)) * 100, 1),
"dimensions": dimension_scores,
})
scorecards.sort(key=lambda x: x["weighted_total"], reverse=True)
# Gap analysis (compare first two)
gaps = []
if len(scorecards) >= 2:
leader = scorecards[0]
for other in scorecards[1:]:
comp_gaps = []
for i, dim in enumerate(DIMENSIONS):
leader_score = leader["dimensions"][i]["score"]
other_score = other["dimensions"][i]["score"]
diff = leader_score - other_score
if abs(diff) >= 1:
comp_gaps.append({
"dimension": DIMENSION_LABELS.get(dim, dim),
"leader_score": leader_score,
"other_score": other_score,
"gap": diff,
"direction": "leader ahead" if diff > 0 else "other ahead",
})
gaps.append({
"comparison": f"{leader['name']} vs {other['name']}",
"gaps": sorted(comp_gaps, key=lambda x: abs(x["gap"]), reverse=True),
})
# Strategic recommendations
recommendations = _generate_recommendations(scorecards)
return {
"scorecards": scorecards,
"ranking": [{"rank": i + 1, "name": s["name"], "score": s["raw_total"],
"percentage": s["percentage"]} for i, s in enumerate(scorecards)],
"gap_analysis": gaps,
"recommendations": recommendations,
}
def _generate_recommendations(scorecards: list) -> list:
"""Generate strategic recommendations from scorecard analysis."""
recs = []
if not scorecards:
return recs
# Find dimensions where your product (first entry typically) scores lowest
if scorecards:
first = scorecards[0]
weak_dims = sorted(first["dimensions"], key=lambda x: x["score"])[:3]
for dim in weak_dims:
if dim["score"] <= 2:
recs.append({
"priority": "HIGH",
"dimension": dim["label"],
"recommendation": f"{first['name']} scores {dim['score']}/5 on {dim['label']}. This is a significant gap that competitors can exploit.",
})
strong_dims = sorted(first["dimensions"], key=lambda x: x["score"], reverse=True)[:3]
for dim in strong_dims:
if dim["score"] >= 4:
recs.append({
"priority": "LEVERAGE",
"dimension": dim["label"],
"recommendation": f"{first['name']} leads on {dim['label']} ({dim['score']}/5). Feature this in positioning and battle cards.",
})
return recs
def format_text(result: dict) -> str:
"""Format results as human-readable text."""
lines = []
lines.append("=" * 70)
lines.append("COMPETITOR SCORECARD -- 12-Dimension Analysis")
lines.append("=" * 70)
lines.append(f"\n--- Ranking ---")
for r in result["ranking"]:
bar = "#" * int(r["percentage"] / 5)
lines.append(f" {r['rank']}. {r['name']:<25} {r['score']:>3}/60 ({r['percentage']:>5.1f}%) {bar}")
for sc in result["scorecards"]:
lines.append(f"\n--- {sc['name']} ---")
lines.append(f"{'Dimension':<16} {'Score':>6} {'Evidence'}")
for d in sc["dimensions"]:
ev = d["evidence"][:50] + "..." if len(d["evidence"]) > 50 else d["evidence"]
lines.append(f"{d['label']:<16} {d['score']:>4}/5 {ev}")
lines.append(f"{'TOTAL':<16} {sc['raw_total']:>4}/60 ({sc['percentage']:.1f}%)")
if result["gap_analysis"]:
lines.append(f"\n--- Gap Analysis ---")
for ga in result["gap_analysis"]:
lines.append(f"\n {ga['comparison']}:")
for g in ga["gaps"][:5]:
lines.append(f" {g['dimension']:<16} {g['leader_score']} vs {g['other_score']} (gap: {g['gap']:+d})")
if result["recommendations"]:
lines.append(f"\n--- Recommendations ---")
for r in result["recommendations"]:
lines.append(f"[{r['priority']}] {r['dimension']}: {r['recommendation']}")
lines.append("")
return "\n".join(lines)
def main():
parser = argparse.ArgumentParser(
description="Score competitors across a 12-dimension rubric and generate comparison scorecard."
)
parser.add_argument("input_file", help="JSON file with competitor dimension scores")
parser.add_argument("--json", action="store_true", help="Output results as JSON")
parser.add_argument("--weights", type=str, default=None,
help="Custom dimension weights as JSON string")
args = parser.parse_args()
try:
with open(args.input_file, "r") as f:
data = json.load(f)
except FileNotFoundError:
print(f"Error: File not found: {args.input_file}", file=sys.stderr)
sys.exit(1)
except json.JSONDecodeError as e:
print(f"Error: Invalid JSON in {args.input_file}: {e}", file=sys.stderr)
sys.exit(1)
custom_weights = None
if args.weights:
try:
custom_weights = json.loads(args.weights)
except json.JSONDecodeError:
print("Error: Invalid JSON in --weights argument.", file=sys.stderr)
sys.exit(1)
result = score_competitors(data, custom_weights)
if args.json:
print(json.dumps(result, indent=2))
else:
print(format_text(result))
if __name__ == "__main__":
main()
#!/usr/bin/env python3
"""
Feature Matrix Builder
Build a feature comparison matrix from structured feature data. Calculates
per-category and overall coverage scores for each competitor.
Usage:
python feature_matrix_builder.py features.json
python feature_matrix_builder.py features.json --json
"""
import argparse
import json
import sys
COVERAGE_SCORES = {
"full": 5,
"partial": 3,
"basic": 2,
"planned": 1,
"missing": 0,
}
def build_matrix(data: dict) -> dict:
"""Build feature comparison matrix."""
products = data.get("products", [])
categories = data.get("categories", [])
if not products or not categories:
return {"error": "Products and categories are required."}
product_names = [p.get("name", f"Product {i+1}") for i, p in enumerate(products)]
# Build matrix
matrix_rows = []
category_scores = {name: {} for name in product_names}
overall_scores = {name: {"total": 0, "max": 0} for name in product_names}
for cat in categories:
cat_name = cat.get("name", "Unknown")
features = cat.get("features", [])
cat_rows = []
for feat in features:
feat_name = feat.get("name", "Unknown")
row = {"feature": feat_name, "category": cat_name, "scores": {}, "notes": feat.get("notes", "")}
for i, product in enumerate(products):
name = product_names[i]
product_features = product.get("features", {})
cat_features = product_features.get(cat_name, {})
coverage = cat_features.get(feat_name, "missing").lower()
score = COVERAGE_SCORES.get(coverage, 0)
row["scores"][name] = {
"coverage": coverage,
"score": score,
}
overall_scores[name]["total"] += score
overall_scores[name]["max"] += 5
cat_rows.append(row)
matrix_rows.append({"category": cat_name, "features": cat_rows})
# Calculate category scores
for name in product_names:
cat_total = sum(r["scores"][name]["score"] for r in cat_rows)
cat_max = len(cat_rows) * 5
pct = (cat_total / cat_max * 100) if cat_max > 0 else 0
category_scores[name][cat_name] = {
"score": cat_total,
"max": cat_max,
"percentage": round(pct, 1),
}
# Overall coverage
overall_coverage = {}
for name in product_names:
total = overall_scores[name]["total"]
max_score = overall_scores[name]["max"]
pct = (total / max_score * 100) if max_score > 0 else 0
overall_coverage[name] = {
"total_score": total,
"max_score": max_score,
"coverage_pct": round(pct, 1),
}
# Differentiators (features where only one product has "full")
differentiators = {name: [] for name in product_names}
gaps = {name: [] for name in product_names}
for cat_data in matrix_rows:
for feat in cat_data["features"]:
full_products = [n for n in product_names if feat["scores"][n]["coverage"] == "full"]
missing_products = [n for n in product_names if feat["scores"][n]["coverage"] == "missing"]
if len(full_products) == 1:
differentiators[full_products[0]].append(
f"{feat['category']}: {feat['feature']}"
)
for name in missing_products:
if any(feat["scores"][n]["coverage"] in ("full", "partial") for n in product_names if n != name):
gaps[name].append(f"{feat['category']}: {feat['feature']}")
return {
"products": product_names,
"matrix": matrix_rows,
"category_scores": category_scores,
"overall_coverage": overall_coverage,
"differentiators": differentiators,
"gaps": {k: v[:10] for k, v in gaps.items()},
}
def format_text(result: dict) -> str:
"""Format results as human-readable text."""
lines = []
lines.append("=" * 70)
lines.append("FEATURE COMPARISON MATRIX")
lines.append("=" * 70)
names = result["products"]
# Overall coverage
lines.append(f"\n--- Overall Coverage ---")
for name in names:
ov = result["overall_coverage"][name]
bar = "#" * int(ov["coverage_pct"] / 5)
lines.append(f" {name:<25} {ov['total_score']:>3}/{ov['max_score']} ({ov['coverage_pct']:>5.1f}%) {bar}")
# Category scores
lines.append(f"\n--- Category Scores ---")
header = f"{'Category':<20}"
for name in names:
header += f" {name[:15]:>15}"
lines.append(header)
if result["matrix"]:
for cat_data in result["matrix"]:
cat = cat_data["category"]
row = f"{cat:<20}"
for name in names:
cs = result["category_scores"][name].get(cat, {})
row += f" {cs.get('percentage', 0):>13.1f}%"
lines.append(row)
# Feature matrix
for cat_data in result["matrix"]:
lines.append(f"\n--- {cat_data['category']} ---")
header = f" {'Feature':<25}"
for name in names:
header += f" {name[:12]:>12}"
lines.append(header)
for feat in cat_data["features"]:
row = f" {feat['feature']:<25}"
for name in names:
coverage = feat["scores"][name]["coverage"]
row += f" {coverage:>12}"
lines.append(row)
# Differentiators
lines.append(f"\n--- Unique Differentiators ---")
for name in names:
diffs = result["differentiators"][name]
if diffs:
lines.append(f" {name}:")
for d in diffs[:5]:
lines.append(f" + {d}")
# Gaps
lines.append(f"\n--- Key Gaps ---")
for name in names:
g = result["gaps"][name]
if g:
lines.append(f" {name}:")
for gap in g[:5]:
lines.append(f" - {gap}")
lines.append("")
return "\n".join(lines)
def main():
parser = argparse.ArgumentParser(
description="Build a feature comparison matrix from structured feature data."
)
parser.add_argument("input_file", help="JSON file with feature comparison data")
parser.add_argument("--json", action="store_true", help="Output results as JSON")
args = parser.parse_args()
try:
with open(args.input_file, "r") as f:
data = json.load(f)
except FileNotFoundError:
print(f"Error: File not found: {args.input_file}", file=sys.stderr)
sys.exit(1)
except json.JSONDecodeError as e:
print(f"Error: Invalid JSON in {args.input_file}: {e}", file=sys.stderr)
sys.exit(1)
result = build_matrix(data)
if args.json:
print(json.dumps(result, indent=2))
else:
print(format_text(result))
if __name__ == "__main__":
main()
Related skills
FAQ
How many dimensions does the scoring rubric use?
A 12-dimension scoring rubric.
How many review data points are recommended?
50 or more reviews per competitor for reliable themes.