📦 deps(thirdparty): update snapshots
This commit is contained in:
+127
@@ -0,0 +1,127 @@
|
||||
# Battle Card subagent prompt
|
||||
|
||||
## Contents
|
||||
- [Placeholders to substitute](#placeholders-to-substitute) — `{OUTPUT_DIR}`, `{COMPETITOR_SLUG}`, etc.
|
||||
- [Prompt](#prompt) — full subagent instruction template (paste with placeholders filled in)
|
||||
- [Wave management](#wave-management) — launch policy: one Agent message per run, all competitors in parallel
|
||||
|
||||
Main agent substitutes placeholders per competitor. Launch AFTER Step 5c fact-check completes — this lane depends on `matrix.json` cells having `sources` URLs.
|
||||
|
||||
## Placeholders to substitute
|
||||
|
||||
- `{OUTPUT_DIR}` → the absolute path to the output directory (the per-run directory from Step 0; no `~` or `$HOME`)
|
||||
- `{COMPETITOR_SLUG}` → e.g. `rival-co`
|
||||
- `{COMPETITOR_NAME}` → e.g. `Rival Co`
|
||||
- `{USER_SLUG}` → e.g. `exa`
|
||||
- `{USER_COMPANY_NAME}` → e.g. `Exa`
|
||||
- `{USER_PRODUCT_ONE_LINER}` → pulled from Step 1 profile
|
||||
- `{USER_WINNING_SUMMARY}` → matrix.json `userCompany.winningSummary`
|
||||
- `{USER_LOSING_SUMMARY}` → matrix.json `userCompany.losingSummary`
|
||||
|
||||
## Prompt
|
||||
|
||||
```
|
||||
You are the Battle Card synthesis subagent. Produce an evidence-grounded
|
||||
battle card a real AE would use on a call.
|
||||
|
||||
TOOL RULES — CRITICAL, FOLLOW EXACTLY:
|
||||
1. You may ONLY use the Bash tool. No exceptions.
|
||||
2. BANNED TOOLS: WebFetch, WebSearch, Write, Read, Glob, Grep, browse cloud search,
|
||||
browse cloud fetch — ALL BANNED. This is a SYNTHESIS lane, not a research lane.
|
||||
You read files that already exist; you do not make new network calls.
|
||||
3. Read ALL inputs in ONE Bash call via `cat`. Write output in ONE heredoc.
|
||||
4. NEVER use ~ or $HOME — full literal paths only.
|
||||
|
||||
INPUTS (all already exist on disk — read in one Bash call):
|
||||
- {OUTPUT_DIR}/partials/{COMPETITOR_SLUG}.marketing.md
|
||||
- {OUTPUT_DIR}/partials/{COMPETITOR_SLUG}.discussion.md
|
||||
- {OUTPUT_DIR}/partials/{COMPETITOR_SLUG}.social.md
|
||||
- {OUTPUT_DIR}/partials/{COMPETITOR_SLUG}.news.md
|
||||
- {OUTPUT_DIR}/partials/{COMPETITOR_SLUG}.technical.md
|
||||
- {OUTPUT_DIR}/{USER_SLUG}.md # user's own merged file
|
||||
- {OUTPUT_DIR}/matrix.json # fact-checked matrix — cells
|
||||
# must have a `sources` URL to
|
||||
# be trustworthy; reject any
|
||||
# cell without one
|
||||
|
||||
CONTEXT:
|
||||
- User's company: {USER_COMPANY_NAME}
|
||||
- User's product: {USER_PRODUCT_ONE_LINER}
|
||||
- User's verified moats (from matrix.json userCompany.winningSummary):
|
||||
{USER_WINNING_SUMMARY}
|
||||
- User's verified gaps (from matrix.json userCompany.losingSummary):
|
||||
{USER_LOSING_SUMMARY}
|
||||
- Competitor: {COMPETITOR_NAME}
|
||||
- Competitor slug: {COMPETITOR_SLUG}
|
||||
|
||||
TASK — produce three sections, every claim traceable to an input bullet
|
||||
or matrix.sources URL:
|
||||
|
||||
1. LANDMINES (3-5 items) — concrete verifiable facts that HURT
|
||||
{COMPETITOR_NAME} in a deal. Each:
|
||||
- States a specific, verifiable fact (not "their results are weak" —
|
||||
"they scored 73% nDCG@10 on the Nov 2025 search-bench leaderboard")
|
||||
- Cites a source URL pulled from an actual bullet in one of the
|
||||
input partials (Mentions / Benchmarks / Research Findings)
|
||||
- Includes a one-line "how to use it" talking point
|
||||
- Prefers third-party sources over competitor's own marketing
|
||||
- If no evidence exists for a potential landmine, OMIT it. 3 cited
|
||||
landmines > 5 half-invented ones.
|
||||
|
||||
2. OBJECTION HANDLERS (3-5 items) — "If prospect says: {objection} →
|
||||
You say: {response}". Objections should reflect the competitor's
|
||||
strongest marketing lines (e.g. if their homepage says "99.99%
|
||||
uptime", the objection is "we hear {user} has no uptime guarantee").
|
||||
Responses must reference a real user moat from winningSummary —
|
||||
never a hallucinated feature.
|
||||
|
||||
3. TALK TRACKS (2-3 items) — 1-2 sentence opening pitches. Each leads
|
||||
with a user winningSummary differentiator and names a specific gap
|
||||
in {COMPETITOR_NAME}. Confident, factual, no hyperbole.
|
||||
|
||||
ADVERSARIAL SELF-CHECK before writing:
|
||||
- [ ] Every landmine cites a URL that appears in one of the input
|
||||
partials. No invented URLs.
|
||||
- [ ] No claim contradicts a fact-checked cell in matrix.json.
|
||||
- [ ] No talk track claims a user feature where matrix.json shows
|
||||
userCompany.features[X] = false.
|
||||
- [ ] Objections are realistic (what a prospect would actually raise),
|
||||
not strawmen.
|
||||
|
||||
OUTPUT — write via a single heredoc to
|
||||
{OUTPUT_DIR}/partials/{COMPETITOR_SLUG}.battle.md
|
||||
|
||||
cat << 'BATTLE_MD' > {OUTPUT_DIR}/partials/{COMPETITOR_SLUG}.battle.md
|
||||
---
|
||||
competitor_name: {COMPETITOR_NAME}
|
||||
lane: battle
|
||||
generated_at: {YYYY-MM-DD}
|
||||
---
|
||||
|
||||
## Battle Card
|
||||
|
||||
### Landmines
|
||||
|
||||
- **{one-line fact}** — {how to use it in the call}. (source: {url})
|
||||
|
||||
### Objection Handlers
|
||||
|
||||
- If they say: "{objection verbatim}"
|
||||
You say: {response citing user's moat} (evidence: {url})
|
||||
|
||||
### Talk Tracks
|
||||
|
||||
1. {1-2 sentence pitch}
|
||||
BATTLE_MD
|
||||
|
||||
REPORT BACK only one line:
|
||||
"{COMPETITOR_SLUG} battle: {N} landmines, {M} objections, {K} tracks, all cited."
|
||||
|
||||
Do NOT return the card content.
|
||||
```
|
||||
|
||||
## Wave management
|
||||
|
||||
- Launch 1 battle-card subagent per competitor. All can run in parallel (synthesis is fast and uses no shared state beyond already-written partials).
|
||||
- Depth: only run in `deep` or `deeper` modes. `quick` mode does not have the research depth to ground battle cards credibly.
|
||||
- Budget: ~3-5 Bash calls per subagent (1 big cat, 1 big heredoc, maybe 1-2 sanity checks).
|
||||
@@ -0,0 +1,91 @@
|
||||
# Battle Card — format spec
|
||||
|
||||
The Battle lane is the **6th** subagent lane in deep/deeper mode. It runs AFTER Step 5c fact-check completes — it reads only existing partials + the fact-checked `matrix.json`, **never makes new `browse cloud` calls**. This is a pure synthesis lane.
|
||||
|
||||
Output file: `{OUTPUT_DIR}/partials/{slug}.battle.md`. `merge_partials.mjs` unions its `## Battle Card` section into the consolidated `{slug}.md`. `compile_report.mjs` renders it as a brand-accented card on the per-competitor HTML page.
|
||||
|
||||
## The three sections
|
||||
|
||||
### Landmines (3-5 items)
|
||||
|
||||
Concrete, verifiable facts about the competitor that **hurt them in a deal**. Every item must cite a URL from an existing partial (Mentions, Benchmarks, or Research Findings). Prefer third-party evidence (benchmarks, reviews, news) over the competitor's own marketing — marketing claims are weak ammunition.
|
||||
|
||||
Format:
|
||||
```
|
||||
### Landmines
|
||||
|
||||
- **{one-line factual claim}** — {how an AE uses it in the call}. (source: {url})
|
||||
```
|
||||
|
||||
Example:
|
||||
```
|
||||
- **Rival Co placed 4th of 7 on the Nov 2025 search-bench retrieval leaderboard (73% nDCG@10)** — use if prospect cares about relevance, but only after confirming their volume tier; Rival Co's reranking add-on is paywalled behind Scale ($499/mo). (source: https://github.com/example-org/search-bench)
|
||||
```
|
||||
|
||||
### Objection Handlers (3-5 items)
|
||||
|
||||
Format: "if prospect says X → you say Y, citing a real user moat from `userCompany.winningSummary`." Every response must reference a feature/integration the fact-checked matrix confirms the user has. Never respond with a claim that contradicts a fact-checked matrix cell.
|
||||
|
||||
Format:
|
||||
```
|
||||
### Objection Handlers
|
||||
|
||||
- If they say: "{objection verbatim}"
|
||||
You say: {response citing user's moat} (evidence: {url})
|
||||
```
|
||||
|
||||
Example:
|
||||
```
|
||||
- If they say: "Rival Co is $99/mo cheaper than your Scale tier"
|
||||
You say: "Rival Co's reranking is a paid add-on you'll need for production relevance — once you add it the price gap closes. Our Scale tier includes neural reranking and a research endpoint; matrix.json confirms Rival Co's feature set doesn't cover the research API." (evidence: https://docs.rivalco.com/changelog)
|
||||
```
|
||||
|
||||
### Talk Tracks (2-3 items)
|
||||
|
||||
One-to-two sentence opening pitches an AE can memorize. Lead with a user winningSummary differentiator; name the specific gap in the competitor. No hyperbole, no claims not grounded in fact-checked matrix cells.
|
||||
|
||||
Format:
|
||||
```
|
||||
### Talk Tracks
|
||||
|
||||
1. {1-2 sentence pitch}
|
||||
```
|
||||
|
||||
Example:
|
||||
```
|
||||
1. For production RAG, Exa is the only provider in the category with BOTH a first-party neural index AND a dedicated research/answer endpoint — Rival Co shipped neither, Serper shipped neither, and one competitor replaced its answer endpoint with a thin LLM wrapper last quarter.
|
||||
```
|
||||
|
||||
## Markdown file shape
|
||||
|
||||
```markdown
|
||||
---
|
||||
competitor_name: Rival Co
|
||||
lane: battle
|
||||
generated_at: 2026-04-24
|
||||
---
|
||||
|
||||
## Battle Card
|
||||
|
||||
### Landmines
|
||||
- **Fact 1** — usage. (source: url)
|
||||
- **Fact 2** — usage. (source: url)
|
||||
|
||||
### Objection Handlers
|
||||
- If they say: "..."
|
||||
You say: ... (evidence: url)
|
||||
|
||||
### Talk Tracks
|
||||
1. Pitch 1
|
||||
2. Pitch 2
|
||||
```
|
||||
|
||||
## Quality gates — Adversarial self-check (subagent MUST run before writing)
|
||||
|
||||
- [ ] Every landmine cites a URL that appears in one of the input partials (Mentions / Benchmarks / Research Findings). No invented URLs.
|
||||
- [ ] No claim contradicts a fact-checked cell in `matrix.json` (cells must have a `sources` URL to be trustworthy).
|
||||
- [ ] No talk track claims a user feature where `matrix.json` shows `userCompany.features[X] = false`.
|
||||
- [ ] Objections are realistic — they're what a prospect would actually raise based on the competitor's strongest marketing lines, not strawmen.
|
||||
- [ ] Third-party evidence preferred over competitor's own marketing (benchmarks, reviews, news > their docs/pricing).
|
||||
|
||||
If a potential landmine has no evidence in the partials, OMIT it. It is better to ship 3 cited landmines than 5 half-invented ones.
|
||||
@@ -0,0 +1,130 @@
|
||||
# Example Competitor Research File
|
||||
|
||||
## Contents
|
||||
- [Template](#template) — full worked example for a fictional "Rival Co"
|
||||
- [Field Rules](#field-rules) — frontmatter fields, body section order, mention/findings format
|
||||
- [Writing via Bash Heredoc](#writing-via-bash-heredoc) — required pattern for subagents to avoid permission prompts
|
||||
|
||||
Each enrichment subagent writes one markdown file per competitor to `{OUTPUT_DIR}/{competitor-slug}.md`, where `{OUTPUT_DIR}` is the per-run Desktop directory set up by the main agent in Step 0 (e.g., `~/Desktop/acme_competitors_2026-04-23/`). The YAML frontmatter contains structured fields for report/matrix compilation. The body contains per-section research plus aggregated mentions and benchmarks.
|
||||
|
||||
## Template
|
||||
|
||||
```markdown
|
||||
---
|
||||
competitor_name: Rival Co
|
||||
website: https://rivalco.com
|
||||
tagline: The fastest way to give your agents the web
|
||||
positioning: Developer-first web search API
|
||||
product_description: Web search & retrieval API for AI agents and RAG pipelines
|
||||
target_customer: AI engineers, RAG/agent teams, SaaS companies
|
||||
pricing_model: Usage-based + seat tiers
|
||||
pricing_tiers: Free (1K searches) | Pro $99/mo | Scale $499/mo | Enterprise Contact
|
||||
key_features: web search API | neural/semantic search | site crawler | reranking | live crawl
|
||||
integrations: LangChain | LlamaIndex | Python SDK | TypeScript SDK
|
||||
headquarters: San Francisco, CA
|
||||
founded: 2023
|
||||
employee_estimate: 11-50
|
||||
funding_info: Seed, $5M (2024)
|
||||
strategic_diff: Similar retrieval API; weaker neural relevance, but cheaper entry tier
|
||||
---
|
||||
|
||||
## Product
|
||||
Web search and retrieval API for AI agents. Exposes a REST search endpoint with both
|
||||
keyword and semantic/neural modes, plus a site crawler and live-crawl fallback.
|
||||
Positioned at AI engineers building RAG and agent pipelines.
|
||||
|
||||
## Pricing
|
||||
- Free: 1K searches/month, 1 API key
|
||||
- Pro ($99/mo): 100K searches, reranking, basic support
|
||||
- Scale ($499/mo): 1M searches, neural search, live crawl, higher rate limits
|
||||
- Enterprise: custom pricing, SSO, dedicated support
|
||||
|
||||
## Features
|
||||
- Keyword + neural/semantic search modes
|
||||
- Site crawler with scheduled recrawls
|
||||
- Result reranking and content highlights
|
||||
- Live-crawl fallback for fresh pages
|
||||
- REST API with JSON responses
|
||||
- Python and TypeScript SDKs
|
||||
|
||||
## Positioning
|
||||
Marketing emphasizes "AI-native" and developer-first DX. Landing page hero:
|
||||
"Give your agents the web." Targets solo devs through mid-market AI teams.
|
||||
|
||||
## Comparison vs {user_company}
|
||||
- **Overlaps**: Web search API, neural search mode, crawler, LangChain integration
|
||||
- **Gaps**: No dedicated research/answer endpoint, weaker neural relevance benchmarks, no news endpoint
|
||||
- **Where they win**: Lower entry price ($99 vs $199), simpler pricing tiers
|
||||
- **Where you win**: Stronger neural relevance (per public benchmarks), research API, larger integration ecosystem
|
||||
|
||||
## Mentions
|
||||
- **[Benchmark]** retrieval-quality leaderboard — Rival Co 73% nDCG@10, 4th of 7 tested (source: https://github.com/example-org/search-bench/pull/92, 2026-03-14)
|
||||
- **[Comparison]** Exa vs Rival Co — side-by-side review (source: https://example.com/exa-vs-rivalco, 2026-02-01)
|
||||
- **[Reddit]** r/LangChain thread: "Moved from Rival Co to X after relevance issues" — 24 upvotes (source: https://reddit.com/r/LangChain/comments/abc123)
|
||||
- **[HN]** "Show HN: Rival Co raises seed to build..." — 112 points, 48 comments (source: https://news.ycombinator.com/item?id=12345)
|
||||
- **[LinkedIn]** CEO post on product launch — 412 reactions (source: https://linkedin.com/posts/rivalco-launch)
|
||||
- **[YouTube]** "Rival Co vs Exa" review by Dev YouTuber — 8.2K views (source: https://youtube.com/watch?v=xyz)
|
||||
- **[News]** TechCrunch coverage of seed round (source: https://techcrunch.com/2024/11/rival-co-seed)
|
||||
- **[Review]** G2 4.3/5 (31 reviews), main complaint: stale results (source: https://g2.com/products/rival-co)
|
||||
|
||||
## Benchmarks
|
||||
- **search-bench PR #92** — Rival Co 73% nDCG@10 on retrieval quality, 4th of 7 tested (https://github.com/example-org/search-bench/pull/92)
|
||||
- **retrieval-latency blog** — Rival Co 480ms p50, 2nd fastest (https://example.com/search-latency-2026)
|
||||
|
||||
## Research Findings
|
||||
- **[high]** Usage-based pricing starts at $99/mo for 100K searches (source: rivalco.com/pricing)
|
||||
- **[high]** Series seed, $5M raised Nov 2024 (source: TechCrunch)
|
||||
- **[medium]** CEO LinkedIn emphasizes AI-agent use cases (source: linkedin.com/in/rivalco-ceo)
|
||||
- **[low]** Possibly a team under 20 based on careers page (source: rivalco.com/careers)
|
||||
|
||||
## Battle Card
|
||||
|
||||
### Landmines
|
||||
- **Rival Co scores 73% nDCG@10 on the search-bench leaderboard (4th of 7 tested)** — use against relevance-sensitive prospects; they rank below Exa on the same test. (source: https://github.com/example-org/search-bench/pull/92)
|
||||
- **G2 average 4.3/5 with "stale results" as top complaint across 31 reviews** — cite when prospect raises freshness concerns. (source: https://g2.com/products/rival-co)
|
||||
|
||||
### Objection Handlers
|
||||
- If they say: "Rival Co is $99/mo — cheaper than your Pro tier"
|
||||
You say: "Cheaper upfront, but compare total cost of poor relevance — their 73% nDCG@10 means more irrelevant results your agent has to filter or re-query, and re-queries aren't free." (evidence: https://github.com/example-org/search-bench/pull/92)
|
||||
|
||||
### Talk Tracks
|
||||
1. For RAG pipelines where relevance drives answer quality, Exa ships a neural index and a dedicated research/answer endpoint as table stakes; Rival Co has neither in their 2024 product set.
|
||||
```
|
||||
|
||||
## Field Rules
|
||||
|
||||
- **YAML frontmatter**: All structured fields go here. Extracted for matrix + CSV compilation.
|
||||
- **`pricing_tiers`**: Pipe-separated (`|`) with tier name + short price. `compile_report.mjs` parses on `|` for the matrix view.
|
||||
- **`key_features`**, **`integrations`**: Pipe-separated lists.
|
||||
- **`strategic_diff`**: One-line summary (shown in overview table).
|
||||
- **Body sections**: `## Product`, `## Pricing`, `## Features`, `## Positioning`, `## Comparison vs {user_company}`, `## Mentions`, `## Benchmarks`, `## Research Findings`, `## Battle Card` (deep/deeper modes only; synthesized by the Battle lane after fact-check).
|
||||
- **Mentions format**: `- **[SourceType]** title | snippet (source: url, date)` — `SourceType` is one of `Benchmark`, `Comparison`, `News`, `Reddit`, `HN`, `LinkedIn`, `YouTube`, `Review`, `Podcast`, `X`.
|
||||
- **Findings format**: `- **[confidence]** fact (source: url)` — `confidence` is `high`, `medium`, or `low`.
|
||||
- **Filename**: `{OUTPUT_DIR}/{competitor-slug}.md` where slug is lowercase, hyphenated.
|
||||
|
||||
## Writing via Bash Heredoc
|
||||
|
||||
Subagents write these files using bash heredoc to avoid security prompts. Use the full literal `{OUTPUT_DIR}` path — no `~` or `$HOME`:
|
||||
|
||||
```bash
|
||||
cat << 'COMPETITOR_MD' > {OUTPUT_DIR}/rival-co.md
|
||||
---
|
||||
competitor_name: Rival Co
|
||||
website: https://rivalco.com
|
||||
...
|
||||
---
|
||||
|
||||
## Product
|
||||
...
|
||||
|
||||
## Pricing
|
||||
...
|
||||
|
||||
## Mentions
|
||||
- **[Benchmark]** ...
|
||||
COMPETITOR_MD
|
||||
```
|
||||
|
||||
Use `'COMPETITOR_MD'` (quoted) as the delimiter to prevent shell variable expansion.
|
||||
|
||||
**IMPORTANT**: Write ALL competitor files in a SINGLE Bash call using chained heredocs to minimize permission prompts.
|
||||
+127
@@ -0,0 +1,127 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Competitor Analysis — {{TITLE}}</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
:root {
|
||||
--brand: #F03603;
|
||||
--blue: #4DA9E4;
|
||||
--green: #90C94D;
|
||||
--amber: #F4BA41;
|
||||
--black: #100D0D;
|
||||
--gray: #514F4F;
|
||||
--border: #edebeb;
|
||||
--bg: #F9F6F4;
|
||||
--card: #ffffff;
|
||||
--text: #100D0D;
|
||||
--muted: #514F4F;
|
||||
--high: #5a8a1a;
|
||||
--low: #F03603;
|
||||
}
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body { font-family: Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif; background: var(--bg); color: var(--text); line-height: 1.6; font-size: 16px; }
|
||||
.container { max-width: 1200px; margin: 0 auto; padding: 2rem 1.5rem; }
|
||||
|
||||
header { margin-bottom: 2rem; display: flex; align-items: center; justify-content: space-between; }
|
||||
.header-left h1 { font-size: 1.5rem; font-weight: 600; margin-bottom: 0.25rem; color: var(--black); }
|
||||
.header-left .meta { color: var(--muted); font-size: 0.875rem; }
|
||||
|
||||
nav.views { display: flex; gap: 0.5rem; margin-bottom: 2rem; }
|
||||
nav.views a { background: var(--card); border: 1px solid var(--border); border-radius: 4px; padding: 0.5rem 0.875rem; font-size: 0.8125rem; color: var(--muted); text-decoration: none; font-weight: 500; }
|
||||
nav.views a:hover { border-color: var(--brand); color: var(--brand); }
|
||||
nav.views a.active { background: var(--brand); color: #fff; border-color: var(--brand); }
|
||||
|
||||
.summary { display: flex; gap: 0.75rem; margin-bottom: 2rem; flex-wrap: wrap; }
|
||||
.stat { background: var(--card); border: 1px solid var(--border); border-radius: 4px; padding: 1rem 1.25rem; flex: 1; min-width: 140px; }
|
||||
.stat .label { font-size: 0.6875rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--muted); font-weight: 600; margin-bottom: 0.25rem; }
|
||||
.stat .value { font-size: 1.5rem; font-weight: 700; color: var(--black); }
|
||||
|
||||
/* Strategic win/loss cards */
|
||||
.strategic { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; margin-bottom: 2rem; }
|
||||
@media (max-width: 720px) { .strategic { grid-template-columns: 1fr; } }
|
||||
.strategic .card { background: var(--card); border: 1px solid var(--border); border-radius: 4px; padding: 1.25rem; }
|
||||
.strategic .card.win { border-left: 3px solid var(--high); }
|
||||
.strategic .card.loss { border-left: 3px solid var(--low); }
|
||||
.strategic h3 { font-size: 0.9375rem; font-weight: 600; margin-bottom: 0.125rem; color: var(--black); display: flex; align-items: center; gap: 0.5rem; }
|
||||
.strategic h3 .badge { font-size: 0.6875rem; font-weight: 700; padding: 2px 8px; border-radius: 999px; }
|
||||
.strategic h3 .badge.win { background: rgba(144,201,77,0.12); color: #5a8a1a; border: 1px solid rgba(144,201,77,0.3); }
|
||||
.strategic h3 .badge.loss { background: rgba(240,54,3,0.08); color: var(--low); border: 1px solid rgba(240,54,3,0.2); }
|
||||
.strategic .sub { font-size: 0.8125rem; color: var(--muted); margin-bottom: 0.75rem; }
|
||||
.strategic .prose { font-size: 0.9375rem; line-height: 1.6; color: var(--text); margin: 0.5rem 0 0; }
|
||||
.strategic ul { list-style: none; }
|
||||
.strategic li { padding: 0.375rem 0; font-size: 0.875rem; border-top: 1px solid var(--border); display: flex; justify-content: space-between; align-items: baseline; gap: 0.75rem; }
|
||||
.strategic li:first-child { border-top: 0; }
|
||||
.strategic li .who { color: var(--muted); font-size: 0.75rem; white-space: nowrap; }
|
||||
.strategic .empty { color: var(--muted); font-size: 0.8125rem; padding: 0.5rem 0; }
|
||||
|
||||
.results-table { width: 100%; border-collapse: collapse; background: var(--card); border: 1px solid var(--border); border-radius: 4px; overflow: hidden; margin-bottom: 2rem; }
|
||||
.results-table th { text-align: left; font-size: 0.6875rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--muted); font-weight: 600; padding: 0.75rem 1rem; border-bottom: 1px solid var(--border); background: #fafafa; }
|
||||
.results-table td { padding: 0.75rem 1rem; border-bottom: 1px solid var(--border); font-size: 0.875rem; vertical-align: top; }
|
||||
.results-table tr:last-child td { border-bottom: none; }
|
||||
.results-table tr:hover { background: #fdfcfb; }
|
||||
.results-table a { color: var(--brand); text-decoration: none; font-weight: 500; }
|
||||
.results-table a:hover { text-decoration: underline; }
|
||||
.muted-line { color: var(--muted); font-size: 0.75rem; display: block; margin-top: 2px; }
|
||||
|
||||
.pill { display: inline-block; font-size: 0.6875rem; font-weight: 600; padding: 2px 8px; border-radius: 999px; margin-right: 4px; margin-bottom: 3px; }
|
||||
.pill-feature { background: rgba(77,169,228,0.12); color: #2172a3; border: 1px solid rgba(77,169,228,0.3); }
|
||||
|
||||
footer { margin-top: 3rem; padding-top: 1.5rem; border-top: 1px solid var(--border); display: flex; align-items: center; justify-content: center; gap: 0.5rem; font-size: 0.75rem; color: var(--muted); }
|
||||
footer a { color: var(--brand); text-decoration: none; font-weight: 500; }
|
||||
footer a:hover { text-decoration: underline; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<header>
|
||||
<div class="header-left">
|
||||
<h1>{{TITLE}}</h1>
|
||||
<div class="meta">{{META}}</div>
|
||||
</div>
|
||||
<a href="https://browserbase.com" target="_blank" rel="noopener" style="display:flex;align-items:center;gap:0.5rem;text-decoration:none;color:var(--muted);font-size:0.8125rem;font-weight:500;">
|
||||
<span>Powered by Browserbase</span>
|
||||
<svg width="32" height="32" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg"><rect width="100" height="100" rx="8" fill="#F03603"/><path d="M36 72.2222V27.7778H51.2381C57.5873 27.7778 62.6667 32.8571 62.6667 39.2063V41.746C62.6667 44.6667 61.5873 47.3968 59.7461 49.3651C62.2858 51.4603 63.9366 54.6349 63.9366 58.254V60.7936C63.9366 67.1428 58.8572 72.2222 52.508 72.2222H36ZM42.3493 65.873H52.508C55.3651 65.873 57.5873 63.6508 57.5873 60.7936V58.254C57.5873 55.3968 55.3651 53.1746 52.508 53.1746H42.3493V65.873ZM42.3493 46.8254H51.2381C54.0953 46.8254 56.3175 44.6032 56.3175 41.746V39.2063C56.3175 36.3492 54.0953 34.127 51.2381 34.127H42.3493V46.8254Z" fill="white"/></svg>
|
||||
</a>
|
||||
</header>
|
||||
|
||||
<nav class="views">
|
||||
<a href="index.html" class="active">Overview</a>
|
||||
<a href="matrix.html">Matrix</a>
|
||||
<a href="mentions.html">Mentions</a>
|
||||
</nav>
|
||||
|
||||
<div class="summary">
|
||||
<div class="stat"><div class="label">Competitors</div><div class="value">{{TOTAL}}</div></div>
|
||||
<div class="stat"><div class="label">Mentions</div><div class="value">{{MENTION_COUNT}}</div></div>
|
||||
<div class="stat"><div class="label">Benchmarks</div><div class="value">{{BENCHMARK_COUNT}}</div></div>
|
||||
<div class="stat"><div class="label">With Pricing</div><div class="value">{{WITH_PRICING}}</div></div>
|
||||
</div>
|
||||
|
||||
{{STRATEGIC_SUMMARY}}
|
||||
|
||||
<table class="results-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Competitor</th>
|
||||
<th>Positioning</th>
|
||||
<th>Pricing</th>
|
||||
<th>Key Features</th>
|
||||
<th>Strategic Diff</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{TABLE_ROWS}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<svg width="16" height="16" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg"><rect width="100" height="100" rx="8" fill="#F03603"/><path d="M36 72.2222V27.7778H51.2381C57.5873 27.7778 62.6667 32.8571 62.6667 39.2063V41.746C62.6667 44.6667 61.5873 47.3968 59.7461 49.3651C62.2858 51.4603 63.9366 54.6349 63.9366 58.254V60.7936C63.9366 67.1428 58.8572 72.2222 52.508 72.2222H36ZM42.3493 65.873H52.508C55.3651 65.873 57.5873 63.6508 57.5873 60.7936V58.254C57.5873 55.3968 55.3651 53.1746 52.508 53.1746H42.3493V65.873ZM42.3493 46.8254H51.2381C54.0953 46.8254 56.3175 44.6032 56.3175 41.746V39.2063C56.3175 36.3492 54.0953 34.127 51.2381 34.127H42.3493V46.8254Z" fill="white"/></svg>
|
||||
Generated by <a href="https://github.com/anthropics/skills">competitor-analysis</a> · Powered by <a href="https://browserbase.com">Browserbase</a>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
+217
@@ -0,0 +1,217 @@
|
||||
# Competitor Analysis — Research Patterns
|
||||
|
||||
## Contents
|
||||
- [Overview](#overview) — two research contexts (self vs target)
|
||||
- [Self-Research (User's Company)](#self-research-users-company) — sub-questions, page discovery, synthesis output (precise_category, include keywords, exclusion list)
|
||||
- [Competitor Research — 4 Research Lanes](#competitor-research--4-research-lanes) — Marketing / External / Benchmarks / Strategic Diff
|
||||
- [Depth Mode Behavior](#depth-mode-behavior) — quick / deep / deeper budgets and scope
|
||||
- [Finding Format (per lane)](#finding-format-per-lane) — JSON shape, confidence levels
|
||||
- [Research Loop Rules](#research-loop-rules) — 7 meta-rules for the research phase
|
||||
- [Synthesis Instructions](#synthesis-instructions) — turn findings into matrix cells
|
||||
|
||||
## Overview
|
||||
|
||||
Two research contexts:
|
||||
1. **Self-Research** (Step 1) — Deep research on the user's company so we know what "competitor" means for this run.
|
||||
2. **Competitor Research** (Step 4) — For each discovered/seeded competitor, run the 4-lane enrichment below.
|
||||
|
||||
Both use the Plan → Research → Synthesize pattern. Self-research is identical in shape to the one in `company-research`, so profiles can be reused across skills.
|
||||
|
||||
## Self-Research (User's Company)
|
||||
|
||||
### Sub-Questions
|
||||
- "What does {company} sell and what specific problem does it solve?"
|
||||
- "Who are {company}'s existing customers? What industries, company sizes, use cases?"
|
||||
- "Who are {company}'s known competitors? What category do they compete in?"
|
||||
- "What pricing model does {company} use?"
|
||||
- "What features, integrations, and differentiators does {company}'s marketing emphasize?"
|
||||
|
||||
### Page Discovery
|
||||
Dynamic via sitemap — do NOT hardcode `/about` or `/pricing`:
|
||||
1. `browse cloud fetch --allow-redirects "{company website}/sitemap.xml"` — primary source
|
||||
2. Scan for URLs with keywords: `pricing`, `customer`, `compare`, `vs`, `about`, `features`, `integrations`
|
||||
3. Optionally fetch `/llms.txt` for page descriptions
|
||||
4. Pick 3-5 most relevant URLs
|
||||
|
||||
### External Research
|
||||
- `browse cloud search "{company} alternatives competitors vs"`
|
||||
- `browse cloud search "{company} review comparison"`
|
||||
- Fetch 1-2 most informative third-party pages
|
||||
|
||||
### Synthesis Output
|
||||
Produce a profile with:
|
||||
- **Company**, **Product**, **Existing Customers**, **Competitors** (seed list), **Use Cases**
|
||||
- **precise_category** — one clear sentence that describes what category this product competes in. Avoid fuzzy words like "tools" or "platform". Good: "AI web search API for agents with neural + keyword retrieval". Bad: "search tools". This becomes the anchor for discovery queries and the gate.
|
||||
- **category_include_keywords** — 8-15 phrases that a *direct competitor's* marketing would very likely contain (title or hero). Include semantic variants. e.g. for Exa: `web search api`, `search api`, `neural search`, `semantic search`, `retrieval api`, `search for ai agents`, `search for llms`, `serp api`, `embeddings search`, `live crawling`, `answer api`, `research api`.
|
||||
- **exclusion_list** — phrases that indicate a *different* category, used by the gate to reject false positives. e.g. `vector database`, `enterprise search appliance`, `site search widget`, `observability`, `analytics platform`, `data warehouse`, `scraping platform` (full ETL/scraping suites, not retrieval APIs), `internal knowledge base`.
|
||||
|
||||
The same `profiles/{company-slug}.json` shape used by `company-research`, extended with the three new fields. The `competitors` array becomes the seed list and the first inputs to the comparison-graph expansion in Step 3.
|
||||
|
||||
---
|
||||
|
||||
## Competitor Research — 4 Research Lanes
|
||||
|
||||
For each competitor, run these four lanes (depth-gated):
|
||||
|
||||
### Lane 1 — Marketing Surface (ALL depth modes)
|
||||
Goal: extract what the competitor says about themselves from their own site.
|
||||
|
||||
**Sub-questions**:
|
||||
- "What does {competitor} sell, who is it for, and how is it positioned?"
|
||||
- "What are {competitor}'s pricing tiers and pricing model?"
|
||||
- "What key features, integrations, and platforms does {competitor} list?"
|
||||
|
||||
**Pages to fetch** (via sitemap discovery — do NOT hardcode):
|
||||
1. Homepage
|
||||
2. `/pricing` (or equivalent from sitemap)
|
||||
3. `/features`, `/product`, `/platform`, `/solutions`
|
||||
4. `/integrations`, `/customers`, `/case-studies`
|
||||
|
||||
**Extract into frontmatter fields**: `tagline`, `positioning`, `product_description`, `target_customer`, `pricing_model`, `pricing_tiers`, `key_features`, `integrations`.
|
||||
|
||||
### Lane 2 — External Signal (deep + deeper)
|
||||
Goal: what the rest of the internet says about them.
|
||||
|
||||
**Sub-questions**:
|
||||
- "What third-party comparison pages mention {competitor}?"
|
||||
- "What do users say on Reddit, HN, G2, Capterra?"
|
||||
- "What recent news, launches, or announcements?"
|
||||
- "Who is talking about them on LinkedIn or YouTube?"
|
||||
|
||||
**Search queries**:
|
||||
```
|
||||
"{competitor} vs"
|
||||
"{competitor} alternatives"
|
||||
"{competitor} review"
|
||||
"{competitor} G2" / "{competitor} Capterra"
|
||||
"site:reddit.com {competitor}"
|
||||
"site:news.ycombinator.com {competitor}"
|
||||
"site:linkedin.com/posts {competitor}"
|
||||
"site:youtube.com {competitor}"
|
||||
"{competitor} launch 2025 OR 2026"
|
||||
"{competitor} funding announcement"
|
||||
```
|
||||
|
||||
**Extraction rule**: From search results, harvest each hit as a `Mentions` entry. Classify source type from the URL:
|
||||
- `reddit.com` → `Reddit`
|
||||
- `news.ycombinator.com` → `HN`
|
||||
- `linkedin.com` → `LinkedIn`
|
||||
- `youtube.com` / `youtu.be` → `YouTube`
|
||||
- `g2.com` / `capterra.com` / `trustradius.com` → `Review`
|
||||
- `*vs*` in path or title → `Comparison`
|
||||
- news domains (techcrunch, theverge, venturebeat, forbes, businesswire, globenewswire) → `News`
|
||||
- `twitter.com` / `x.com` → `X`
|
||||
- `spotify.com/episode` / transistor/simplecast → `Podcast`
|
||||
|
||||
For LinkedIn and YouTube, the snippet + URL from `browse cloud search` is enough. Do NOT try to deep-fetch individual LinkedIn posts (auth walls) — list them with title/snippet.
|
||||
|
||||
### Lane 3 — Public Benchmarks (deeper only)
|
||||
Goal: find third-party benchmarks that measured this competitor's product.
|
||||
|
||||
**Sub-questions**:
|
||||
- "Has {competitor} been included in any public benchmark?"
|
||||
- "Are there GitHub repos, PRs, or blog posts comparing {competitor} head-to-head on a measured axis (speed, accuracy, cost, pass rate)?"
|
||||
|
||||
**Search queries**:
|
||||
```
|
||||
"{competitor} benchmark"
|
||||
"{competitor} performance test"
|
||||
"site:github.com {competitor} benchmark"
|
||||
"site:github.com {competitor} vs"
|
||||
"{competitor} vs {seed_competitor} benchmark" # pairwise, use another known competitor as the seed
|
||||
"{category} benchmark {competitor}" # e.g. "web search api benchmark {competitor}"
|
||||
```
|
||||
|
||||
**Extraction**: Add each hit to `Benchmarks` section with: title, source, URL, key finding (one line). Also mirror into `Mentions` with type `Benchmark`.
|
||||
|
||||
**Known benchmark repos to check directly** (if domain is on-topic):
|
||||
- Public retrieval-quality leaderboards (e.g. BEIR / MTEB-style repos) when a vendor publishes scores
|
||||
- Category-specific benchmark repos discovered via the first search wave
|
||||
|
||||
### Lane 4 — Strategic Diff vs User's Company (deeper only)
|
||||
Goal: explicitly compare this competitor to the user's company.
|
||||
|
||||
**Inputs**: `{user_company_profile}` (from Step 1) — specifically `product`, `use_cases`, `key_features` if available.
|
||||
|
||||
**Sub-questions**:
|
||||
- "What features does {competitor} have that {user_company} does not?"
|
||||
- "What features does {user_company} have that {competitor} does not?"
|
||||
- "Who does {competitor} serve that {user_company} does not (and vice versa)?"
|
||||
- "Where does each one win on the marketing surface (price, feature depth, DX, ecosystem)?"
|
||||
|
||||
**No new fetches required** for this lane — it's a synthesis step over Lane 1 + 2 + 3 findings plus the user's profile. Write as:
|
||||
|
||||
```markdown
|
||||
## Comparison vs {user_company}
|
||||
- **Overlaps**: ...
|
||||
- **Gaps**: ...
|
||||
- **Where they win**: ...
|
||||
- **Where you win**: ...
|
||||
```
|
||||
|
||||
Also populate the `strategic_diff` frontmatter field with a one-line summary for the overview table.
|
||||
|
||||
---
|
||||
|
||||
## Depth Mode Behavior
|
||||
|
||||
### Quick Mode (~lots of competitors, cheap)
|
||||
- **Lanes**: 1 only
|
||||
- **Budget**: 2-3 tool calls per competitor (homepage + pricing page)
|
||||
- **Fields populated**: tagline, product_description, pricing_tiers, key_features
|
||||
- **Mentions / Benchmarks / Comparison**: skipped
|
||||
|
||||
### Deep Mode (balanced, default)
|
||||
- **Lanes**: 1 + 2
|
||||
- **Budget**: 5-8 tool calls per competitor
|
||||
- **Everything in quick** + 5-10 mentions across source types
|
||||
|
||||
### Deeper Mode (full intel)
|
||||
- **Lanes**: 1 + 2 + 3 + 4
|
||||
- **Budget**: 10-15 tool calls per competitor
|
||||
- **Everything in deep** + benchmarks section + strategic diff section
|
||||
|
||||
---
|
||||
|
||||
## Finding Format (per lane)
|
||||
|
||||
Every finding is a factual statement tied to a source:
|
||||
|
||||
```json
|
||||
{
|
||||
"lane": "marketing | external | benchmark | strategic",
|
||||
"fact": "Rival Co charges $99/mo for 10K search requests",
|
||||
"sourceUrl": "https://rivalco.com/pricing",
|
||||
"confidence": "high"
|
||||
}
|
||||
```
|
||||
|
||||
**Confidence**:
|
||||
- `high`: Directly stated on the competitor's own website or official press
|
||||
- `medium`: Inferred from third-party articles, reviews, or job posts
|
||||
- `low`: Speculative / outdated sources
|
||||
|
||||
## Research Loop Rules
|
||||
|
||||
1. **Lane 1 first** — always start with the competitor's own site
|
||||
2. **Use sitemap, not hardcoded paths** — `/pricing` might be `/plans` or `/pricing-plans`
|
||||
3. **Rephrase, don't retry** — if a search returns generic junk, switch keywords
|
||||
4. **Fetch selectively** — pick the 1-2 most promising URLs per query
|
||||
5. **For LinkedIn/YouTube: search only, don't fetch** — snippet is enough, avoid auth walls
|
||||
6. **Respect step budget** per depth mode
|
||||
7. **Deduplicate mentions** — same URL should only appear once in `## Mentions`
|
||||
|
||||
## Synthesis Instructions
|
||||
|
||||
After the research loop completes for a competitor:
|
||||
|
||||
1. Fill frontmatter fields from Lane 1 findings
|
||||
2. Write body sections: Product, Pricing, Features, Positioning (all from Lane 1)
|
||||
3. Append `## Mentions` from Lane 2 classified hits
|
||||
4. Append `## Benchmarks` from Lane 3 (deeper only)
|
||||
5. Append `## Comparison vs {user_company}` from Lane 4 synthesis (deeper only)
|
||||
6. Append `## Research Findings` as a raw-findings appendix with confidence tags
|
||||
|
||||
No ICP score. No threat score. Pure intel.
|
||||
|
||||
If a field has no supporting findings, leave it empty rather than guessing.
|
||||
@@ -0,0 +1,434 @@
|
||||
# Competitor Analysis — Workflow Reference
|
||||
|
||||
## Contents
|
||||
- [Discovery Batch JSON Schema](#discovery-batch-json-schema) — browse cloud search output format
|
||||
- [Competitor Research Markdown Format](#competitor-research-markdown-format) — frontmatter + body section spec
|
||||
- [Extracting Page Text](#extracting-page-text) — browse cloud fetch (markdown default; --format raw for HTML)
|
||||
- [Discovery — parallel Bash, not subagents](#discovery--parallel-bash-not-subagents) — Wave A/B/C recipes
|
||||
- [Enrichment fan-out — 5 subagents PER competitor](#enrichment-fan-out--5-subagents-per-competitor-deepdeeper-modes)
|
||||
- [Legacy: Single-subagent template](#legacy-single-subagent-template-quick-mode-only) — quick mode only
|
||||
- [Wave Management](#wave-management) — parallelism rule, gate phase, sizing formula
|
||||
- [Report Compilation](#report-compilation) — compile_report.mjs invocation
|
||||
|
||||
## Discovery Batch JSON Schema
|
||||
|
||||
File: `/tmp/competitor_discovery_batch_{N}.json`
|
||||
|
||||
`browse cloud search --output` writes a JSON object:
|
||||
|
||||
```json
|
||||
{
|
||||
"requestId": "abc123",
|
||||
"query": "alternatives to acme",
|
||||
"results": [
|
||||
{ "id": "...", "url": "https://example.com", "title": "Example Corp", "image": null, "favicon": null }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
The `list_urls.mjs` script (run with `--prefix competitor`) deduplicates across batches.
|
||||
|
||||
## Competitor Research Markdown Format
|
||||
|
||||
File: `{OUTPUT_DIR}/{competitor-slug}.md` — see `references/example-research.md` for the full template.
|
||||
|
||||
**YAML frontmatter fields** (used by `compile_report.mjs`):
|
||||
- `competitor_name` (required)
|
||||
- `website` (required)
|
||||
- `tagline`
|
||||
- `positioning`
|
||||
- `product_description`
|
||||
- `target_customer`
|
||||
- `pricing_model`
|
||||
- `pricing_tiers` (pipe-separated: `Free | Pro $99 | Enterprise Contact`)
|
||||
- `key_features` (pipe-separated)
|
||||
- `integrations` (pipe-separated)
|
||||
- `headquarters`
|
||||
- `founded`
|
||||
- `employee_estimate`
|
||||
- `funding_info`
|
||||
- `strategic_diff` (one-line for overview table; deeper mode only)
|
||||
|
||||
**Body sections** (in this order — `compile_report.mjs` parses by heading):
|
||||
- `## Product`
|
||||
- `## Pricing`
|
||||
- `## Features`
|
||||
- `## Positioning`
|
||||
- `## Comparison vs {user_company}` (deeper only)
|
||||
- `## Mentions`
|
||||
- `## Benchmarks` (deeper only)
|
||||
- `## Research Findings`
|
||||
|
||||
**Mentions line format** (parsed into the mentions feed):
|
||||
```
|
||||
- **[SourceType]** Title | Snippet (source: URL, YYYY-MM-DD)
|
||||
```
|
||||
`SourceType` ∈ `Benchmark | Comparison | News | Reddit | HN | LinkedIn | YouTube | Review | Podcast | X`. Date is optional but preferred.
|
||||
|
||||
## Extracting Page Text
|
||||
|
||||
`browse cloud fetch --allow-redirects` returns clean **markdown by default** — no HTML stripping needed. Just cap the length:
|
||||
|
||||
```bash
|
||||
browse cloud fetch --allow-redirects "https://rivalco.com/pricing" | head -c 3000
|
||||
```
|
||||
|
||||
If you need the original HTML (e.g. to read the `<title>` tag or parse markup), add `--format raw` and strip tags:
|
||||
|
||||
```bash
|
||||
browse cloud fetch --allow-redirects --format raw "https://rivalco.com/pricing" | sed 's/<script[^>]*>.*<\/script>//g; s/<style[^>]*>.*<\/style>//g; s/<[^>]*>//g; s/&/\&/g; s/</</g; s/>/>/g; s/ / /g; s/&#[0-9]*;//g' | tr -s ' \n' | head -c 3000
|
||||
```
|
||||
|
||||
Limit to ~3000 chars per page to keep subagent context manageable. For JS-heavy pages (client-rendered pricing tables) where the Fetch API returns thin content, open the page in a browser session and read it: `browse open "{url}" --remote` then `browse get markdown`.
|
||||
|
||||
## Discovery — parallel Bash, not subagents
|
||||
|
||||
The main agent runs discovery as **3 parallel `browse cloud search` Bash calls** (one per wave) in a SINGLE message. No subagent layer. Each wave chains its 2-4 queries with `&&` and writes results to `/tmp/competitor_discovery_batch_{wave}{N}.json`.
|
||||
|
||||
Example — main agent issues these three Bash tool calls in parallel in one message:
|
||||
|
||||
```bash
|
||||
# Wave A — alternatives
|
||||
browse cloud search "alternatives to {user_company}" --num-results 12 --output /tmp/competitor_discovery_batch_A1.json && \
|
||||
browse cloud search "{user_company} competitors" --num-results 12 --output /tmp/competitor_discovery_batch_A2.json && \
|
||||
echo "A done"
|
||||
```
|
||||
|
||||
```bash
|
||||
# Wave B — precise category
|
||||
browse cloud search "{precise_category}" --num-results 12 --output /tmp/competitor_discovery_batch_B1.json && \
|
||||
browse cloud search "{compose 3 distinctive tokens}" --num-results 12 --output /tmp/competitor_discovery_batch_B2.json && \
|
||||
browse cloud search "{primary_noun} for ai agents" --num-results 12 --output /tmp/competitor_discovery_batch_B3.json && \
|
||||
echo "B done"
|
||||
```
|
||||
|
||||
```bash
|
||||
# Wave C — comparison-page graph
|
||||
browse cloud search "{user_company} vs" --num-results 12 --output /tmp/competitor_discovery_batch_C1.json && \
|
||||
browse cloud search "{seed1} vs" --num-results 12 --output /tmp/competitor_discovery_batch_C2.json && \
|
||||
browse cloud search "{seed2} vs" --num-results 12 --output /tmp/competitor_discovery_batch_C3.json && \
|
||||
echo "C done"
|
||||
```
|
||||
|
||||
Why direct Bash and not subagents: each wave is 2-4 `browse cloud search` calls — agent cold-start + tool-reasoning overhead is bigger than the actual work. Using parallel Bash saves ~1-2 min per run with no quality loss.
|
||||
|
||||
### Discovery query patterns
|
||||
|
||||
Discovery uses **three parallel waves** (evaluated — all three are additive):
|
||||
|
||||
**Wave A — Generic alternatives** (broad net, lots of noise):
|
||||
- `"alternatives to {user_company}"`
|
||||
- `"{user_company} competitors"`
|
||||
|
||||
**Wave B — Precise category queries** (uses `precise_category` from self-research):
|
||||
- `"{precise_category}"` verbatim
|
||||
- `"{precise_category_2_3_keywords}"` — pick the 3 most distinctive tokens
|
||||
- Compose with "API", "cloud", "for agents": `"cloud {primary_noun} for ai agents"`, `"{primary_noun} infrastructure API"`
|
||||
|
||||
**Wave C — Comparison-page graph** (highest-precision single wave):
|
||||
- `"{user_company} vs"`
|
||||
- For each seed competitor from the user's profile, also run `"{seed} vs"`
|
||||
- After the searches, `scripts/extract_vs_names.mjs` parses `"X vs Y"` titles across all Wave C results to surface candidate names that don't appear as URLs.
|
||||
|
||||
**Evaluation result** (tested on a search-API run): Wave A returns ~10% real competitors (mostly AI-tool-listicle aggregators). Wave B returns ~35%. Wave C uniquely surfaces named brands via title parsing that neither A nor B finds. Use all three.
|
||||
|
||||
## Enrichment fan-out — 5 subagents PER competitor (deep/deeper modes)
|
||||
|
||||
For each gated-PASS competitor, launch **five parallel subagents**, one per lane. Each subagent writes a *partial* to `{OUTPUT_DIR}/partials/{slug}.{lane}.md`. After all subagents complete, `scripts/merge_partials.mjs` unions the partials into one canonical `{OUTPUT_DIR}/{slug}.md` per competitor (dedup mentions by URL, sort by date desc).
|
||||
|
||||
The 5 lanes:
|
||||
|
||||
| Lane | Slug | Scope |
|
||||
|------|------|-------|
|
||||
| **A. Marketing** | `marketing` | Owns canonical frontmatter. Pricing, features, positioning, integrations, customers, target, team, funding, HQ. Homepage + sitemap-driven page discovery. |
|
||||
| **B. Discussion** | `discussion` | Reddit, HN, forums, dev.to, hashnode. Broader queries beyond `site:` restrictions — also `"{competitor}" discussion`, `"{competitor}" review 2026`, `"{competitor}" issues OR problems`. Writes Mentions bullets with dates. |
|
||||
| **C. Social** | `social` | LinkedIn posts, YouTube videos, Twitter/X threads. Search snippets only — do NOT fetch (auth walls). |
|
||||
| **D. News & Comparisons** | `news` | Comparison pages ("X vs Y"), TechCrunch / Verge / Forbes / VentureBeat / Businesswire, independent blog reviews, Substack. Every mention MUST include a date. |
|
||||
| **E. Technical & Benchmarks** | `technical` | GitHub benchmark repos/PRs, performance blog posts, independent tests. Writes Benchmarks bullets AND Findings on technical specifics (retrieval modes, latency, rate limits, SDKs). |
|
||||
|
||||
**Wave management — launch ALL subagents in ONE message**: for N competitors × 5 lanes = 5N subagents, fit them all in a single Agent-tool message. Wall clock then equals the slowest single subagent (~3-5 min) instead of `batches × slowest_per_batch`. On a real 10-competitor run we measured 25 minutes wasted by self-throttling to 10-per-message — the Agent tool happily runs 50+ in parallel; do not split into batches for "politeness". The only cap is that each subagent still batches its own Bash operations into a single call.
|
||||
|
||||
**Merge step** (once all partials exist):
|
||||
```bash
|
||||
node {SKILL_DIR}/scripts/merge_partials.mjs {OUTPUT_DIR}
|
||||
```
|
||||
Produces one `{OUTPUT_DIR}/{slug}.md` per competitor with dedup'd Mentions (sorted date desc), Benchmarks, and Findings.
|
||||
|
||||
## Legacy: Single-subagent template (quick mode only)
|
||||
|
||||
In `quick` mode, keep a single subagent per batch of competitors (no fan-out — Lane 1 only, budget 2-3 calls each).
|
||||
|
||||
```
|
||||
You are a competitor enrichment subagent. For each competitor URL, run the 4-lane research
|
||||
pattern and write a single markdown file per competitor.
|
||||
|
||||
CONTEXT:
|
||||
- User's company: {user_company}
|
||||
- User's product: {user_product}
|
||||
- User's key features: {user_key_features}
|
||||
- Depth mode: {depth_mode} (quick | deep | deeper)
|
||||
- Output directory: {OUTPUT_DIR} ← write files HERE, as a full literal path
|
||||
|
||||
COMPETITOR URLS TO PROCESS:
|
||||
{url_list}
|
||||
|
||||
TOOL RULES — CRITICAL, FOLLOW EXACTLY:
|
||||
1. You may ONLY use the Bash tool. No exceptions.
|
||||
2. All searches: Bash → browse cloud search "..." --num-results 10
|
||||
3. All page fetches: Bash → browse cloud fetch --allow-redirects "..."
|
||||
browse cloud fetch returns clean markdown by default — just `| head -c 3000`, no HTML stripping.
|
||||
If you need the raw HTML, add --format raw and pipe through:
|
||||
sed 's/<script[^>]*>.*<\/script>//g; s/<style[^>]*>.*<\/style>//g; s/<[^>]*>//g' | tr -s ' \n' | head -c 3000
|
||||
If a page returns thin content or "enable JavaScript", use `browse open "{url}" --remote` then `browse get markdown`.
|
||||
4. BATCH all file writes: Write ALL markdown files in a SINGLE Bash call using chained heredocs.
|
||||
5. BANNED TOOLS: WebFetch, WebSearch, Write, Read, Glob, Grep — ALL BANNED.
|
||||
6. NEVER use ~ or $HOME in paths — use full literal paths.
|
||||
|
||||
RESEARCH PATTERN (per competitor — lanes are depth-gated):
|
||||
|
||||
LANE 1 — Marketing Surface (always run):
|
||||
a. Fetch competitor homepage
|
||||
b. Discover via sitemap: /sitemap.xml — find /pricing, /features, /integrations, /customers
|
||||
c. Fetch 2-4 most relevant pages
|
||||
d. Extract: tagline, positioning, product_description, target_customer,
|
||||
pricing_model, pricing_tiers, key_features, integrations
|
||||
|
||||
LANE 2 — External Signal (deep + deeper):
|
||||
Run these searches:
|
||||
browse cloud search "{competitor} vs"
|
||||
browse cloud search "{competitor} alternatives review"
|
||||
browse cloud search "site:reddit.com {competitor}"
|
||||
browse cloud search "site:news.ycombinator.com {competitor}"
|
||||
browse cloud search "site:linkedin.com/posts {competitor}"
|
||||
browse cloud search "site:youtube.com {competitor}"
|
||||
browse cloud search "{competitor} G2 OR Capterra"
|
||||
browse cloud search "{competitor} launch OR funding 2025 OR 2026"
|
||||
|
||||
For each search result, classify source type from URL:
|
||||
reddit.com → Reddit
|
||||
news.ycombinator.com → HN
|
||||
linkedin.com → LinkedIn
|
||||
youtube.com/youtu.be → YouTube
|
||||
twitter.com/x.com → X (or Twitter — either works)
|
||||
dev.to → DevTo
|
||||
hashnode.dev, hashnode.com → Hashnode
|
||||
*.substack.com → Substack
|
||||
spotify.com/episode, transistor.fm, simplecast.com → Podcast
|
||||
g2.com/capterra.com/trustradius.com → Review
|
||||
url or title contains "vs" → Comparison
|
||||
techcrunch/theverge/venturebeat/forbes/businesswire/wired/fortune → News
|
||||
other blog domain → Blog
|
||||
|
||||
Record each as a Mentions line with title + one-line snippet + URL + **date**. Always include
|
||||
the date when available. If a `browse cloud search` result carries a date field, prefer it.
|
||||
If absent, parse the year from title/URL (e.g. "2026" or `/2025/11/` in a news URL).
|
||||
For LinkedIn and YouTube — use search snippet only, do NOT fetch the page.
|
||||
|
||||
LANE 3 — Public Benchmarks (deeper only):
|
||||
Run these searches:
|
||||
browse cloud search "{competitor} benchmark"
|
||||
browse cloud search "site:github.com {competitor} benchmark"
|
||||
browse cloud search "{category} benchmark {competitor}"
|
||||
|
||||
Record each hit in ## Benchmarks with: title, source, URL, one-line key finding.
|
||||
Also append to ## Mentions with type Benchmark.
|
||||
|
||||
LANE 4 — Strategic Diff vs {user_company} (deeper only):
|
||||
Using Lane 1-3 findings + the user's company profile, write:
|
||||
## Comparison vs {user_company}
|
||||
- Overlaps: ...
|
||||
- Gaps: ...
|
||||
- Where they win: ...
|
||||
- Where you win: ...
|
||||
Also fill the `strategic_diff` frontmatter field with a one-line summary.
|
||||
|
||||
HARD TOOL-CALL CAP — count your browse cloud calls and STOP at the cap. Partial output beats blocking the pipeline.
|
||||
quick mode: 3 browse cloud calls max per competitor
|
||||
deep mode: 8 browse cloud calls max per competitor
|
||||
deeper mode: 12 browse cloud calls max per competitor
|
||||
|
||||
ENFORCEMENT — at the start of every Bash call, prepend a comment like
|
||||
# browse call N/8 (deep mode)
|
||||
After hitting the cap, write the output file with WHAT YOU HAVE — even if a section is thin.
|
||||
NEVER do a 9th call in deep mode "to be thorough". The pipeline budgets time on this assumption.
|
||||
|
||||
Observed cost of overshoot (Apr 25 search-API run): two lanes hit 29-30 calls each, drove
|
||||
wall-clock for the whole 30-agent fan-out from 5 min → 12 min. Don't do this.
|
||||
|
||||
OUTPUT — write ALL competitor files in a SINGLE Bash call using chained heredocs directly to {OUTPUT_DIR}:
|
||||
|
||||
cat << 'COMPETITOR_MD' > {OUTPUT_DIR}/{slug1}.md
|
||||
---
|
||||
competitor_name: {name}
|
||||
website: {url}
|
||||
tagline: {tagline}
|
||||
positioning: {positioning}
|
||||
product_description: {description}
|
||||
target_customer: {audience}
|
||||
pricing_model: {model}
|
||||
pricing_tiers: {tier1} | {tier2} | {tier3}
|
||||
key_features: {f1} | {f2} | {f3}
|
||||
integrations: {i1} | {i2}
|
||||
headquarters: {hq}
|
||||
founded: {year}
|
||||
employee_estimate: {estimate}
|
||||
funding_info: {funding}
|
||||
strategic_diff: {one line — deeper only}
|
||||
---
|
||||
|
||||
## Product
|
||||
{paragraph}
|
||||
|
||||
## Pricing
|
||||
{bullets per tier}
|
||||
|
||||
## Features
|
||||
{bullets}
|
||||
|
||||
## Positioning
|
||||
{paragraph}
|
||||
|
||||
## Comparison vs {user_company} ← deeper only
|
||||
- Overlaps: ...
|
||||
- Gaps: ...
|
||||
- Where they win: ...
|
||||
- Where you win: ...
|
||||
|
||||
## Mentions
|
||||
- **[SourceType]** Title | Snippet (source: URL, YYYY-MM-DD)
|
||||
|
||||
## Benchmarks ← deeper only
|
||||
- Title | Source | URL | Key finding
|
||||
|
||||
## Research Findings
|
||||
- **[confidence]** Fact (source: URL)
|
||||
COMPETITOR_MD
|
||||
cat << 'COMPETITOR_MD' > {OUTPUT_DIR}/{slug2}.md
|
||||
...
|
||||
COMPETITOR_MD
|
||||
|
||||
Use 'COMPETITOR_MD' (quoted) as the heredoc delimiter to prevent shell variable expansion.
|
||||
|
||||
Report back ONLY: "Batch {batch_id}: {succeeded}/{total} competitors researched, {mentions_count} mentions, {benchmarks_count} benchmarks."
|
||||
Do NOT return raw data to the main conversation.
|
||||
```
|
||||
|
||||
## Wave Management
|
||||
|
||||
### Key Principle: Maximize Parallelism, Minimize Prompts
|
||||
**Launch ALL subagents needed for a phase in ONE message.** No "up to 6 per message" cap — the Agent tool runs them in parallel, so wall clock = slowest single agent regardless of count. On a 10-competitor × 5-lane = 50-subagent enrichment, splitting into 5 batches of 10 cost an extra 20 minutes of wall clock vs one batch of 50 (measured Apr 2026). Each subagent still MUST batch its own Bash operations into a single call.
|
||||
|
||||
### Discovery Phase
|
||||
- **Run discovery as parallel `browse cloud search` Bash calls, not subagents.** Subagent overhead (cold start + tool reasoning) is bigger than the work. Three Bash tool calls in one message — one per wave (A/B/C) — chain each wave's searches with `&&`.
|
||||
- Each wave's bash call writes its outputs as `/tmp/competitor_discovery_batch_{wave}{N}.json`
|
||||
- After all waves complete, run the following in sequence:
|
||||
```bash
|
||||
# 1. Dedup URLs from all batches
|
||||
node {SKILL_DIR}/scripts/list_urls.mjs /tmp --prefix competitor > /tmp/competitor_urls.txt
|
||||
|
||||
# 2. Extract candidate names from "X vs Y" titles (Wave C output)
|
||||
node {SKILL_DIR}/scripts/extract_vs_names.mjs /tmp --prefix competitor \
|
||||
--seed "{user_company},{seed1},{seed2},{seed3}" \
|
||||
> /tmp/competitor_vs_names.jsonl
|
||||
```
|
||||
- **Filter URLs**: Remove blog posts, news articles, AI-tool directories (seektool.ai, respan.ai, agentsindex.ai, toolradar.com, aitoolsatlas.ai, aidirectory.com, vibecodedthis.com, aichief.com, openalternative.co, cbinsights.com, saasworthy.com, softwareworld.com), review aggregators (g2.com, capterra.com, trustradius.com), databases (crunchbase.com, tracxn.com), and the user's own domain. Keep only candidate company homepages.
|
||||
- For names from `extract_vs_names.mjs` that didn't resolve to a domain, optionally run `browse cloud search "{name}" --num-results 3` to resolve the top domain; skip if ambiguous.
|
||||
- **Merge**: filtered-URL list ∪ resolved `vs_names` domains ∪ user-provided seed URLs. Dedup by hostname into `/tmp/competitor_candidates.txt`.
|
||||
|
||||
### User-confirm phase (between gate and enrichment — mandatory)
|
||||
|
||||
After the gate writes `/tmp/competitor_gated.jsonl`, the main agent MUST ask the user to confirm the enrichment set before launching subagents. Enrichment is 25 subagents × depth budget per competitor — too expensive to run on guesses.
|
||||
|
||||
Present three buckets to the user:
|
||||
1. **PASS** — status=PASS rows with title
|
||||
2. **UNKNOWN** — status=UNKNOWN (fetch failed; always a silent miss risk — JS-heavy homepages, Cloudflare challenges)
|
||||
3. **Rejected-brand matches** — top ~10 REJECT rows whose title contains a seed token or that showed up repeatedly in the Wave C "X vs Y" graph
|
||||
|
||||
Then `AskUserQuestion` with a checkbox list + free-text "add more". Write the confirmed set to `/tmp/competitor_enrichment_set.txt` (one URL per line). That file — not `/tmp/competitor_passed.txt` — is the input to the enrichment subagents.
|
||||
|
||||
Known gate blind spots to surface aggressively:
|
||||
- JS-heavy landing pages return near-empty hero text → gate's keyword matcher has nothing to bite on
|
||||
- Cloudflare challenge titles ("Just a moment...") → obvious false negative
|
||||
- "Search foundation" / "retrieval backbone" / "agent runtime" — semantic variants of the category don't lexically match
|
||||
- Apex domain vs product subdomain (e.g. `brave.com` the browser vs `api-dashboard.search.brave.com` the actual API product)
|
||||
|
||||
### Gate Phase (between discovery and enrichment)
|
||||
|
||||
Drop wrong-category candidates BEFORE enrichment burns tool calls on them.
|
||||
|
||||
```bash
|
||||
cat /tmp/competitor_candidates.txt \
|
||||
| node {SKILL_DIR}/scripts/gate_candidates.mjs \
|
||||
--include "{category_include_keywords_csv}" \
|
||||
--exclude "{exclusion_list_csv}" \
|
||||
--concurrency 6 \
|
||||
> /tmp/competitor_gated.jsonl
|
||||
|
||||
# Extract PASS-only URLs for enrichment
|
||||
grep '"status":"PASS"' /tmp/competitor_gated.jsonl \
|
||||
| node -e 'require("fs").readFileSync(0,"utf-8").split("\n").filter(Boolean).forEach(l => { try { console.log(JSON.parse(l).url); } catch {} })' \
|
||||
> /tmp/competitor_passed.txt
|
||||
```
|
||||
|
||||
**Keyword sources**:
|
||||
- `--include` ← profile's `category_include_keywords` (comma-joined).
|
||||
- `--exclude` ← profile's `exclusion_list`.
|
||||
|
||||
**Gate logic** (position-aware): REJECT if exclude term in `<title>`; PASS if include term in `<title>`; for hybrid titles with both (e.g. "Browser Automation & Web Scraping API"), tiebreak by first 200 chars of hero text; otherwise fall through to hero-wide check. Conservative by default.
|
||||
|
||||
**Review the output** — the main agent SHOULD spot-check both lists and MAY manually re-include a REJECT if it recognizes a known direct competitor whose own marketing is category-ambiguous.
|
||||
|
||||
**Evaluation on a search-API run** (12 candidates): 7/7 real competitors PASSED; 4/4 wrong-category (vector database, scraping/ETL platform, analytics tool, internal-KB search) REJECTED. One split-identity edge (a search vendor that also sells a scraping suite) rejected — acceptable.
|
||||
|
||||
### Enrichment Phase
|
||||
Two modes:
|
||||
|
||||
- **`quick` mode** — single subagent per batch of competitors. Lane A (marketing) only. ~8 competitors per subagent, 2-3 tool calls each. Writes directly to `{OUTPUT_DIR}/{slug}.md`.
|
||||
- **`deep` / `deeper` modes** — 5-subagent fan-out PER competitor. Each subagent owns ONE lane (marketing / discussion / social / news / technical). Writes to `{OUTPUT_DIR}/partials/{slug}.{lane}.md`. Budget: 5-8 calls per subagent (deep), 10-15 (deeper). After all lanes complete, run `scripts/merge_partials.mjs` to consolidate.
|
||||
- **Launch ALL competitor × lane subagents in a SINGLE Agent tool message.** For 10 competitors × 5 lanes = 50 parallel agents in one message. Do NOT split into batches — wall clock becomes the slowest single agent (~3-5 min) instead of batches-times-batch-max (~25 min on 10 competitors split into 5 rounds of 10).
|
||||
|
||||
### Screenshots Phase (after merge, before compile)
|
||||
|
||||
Capture homepage hero screenshot for each competitor:
|
||||
```bash
|
||||
node {SKILL_DIR}/scripts/capture_screenshots.mjs {OUTPUT_DIR} --mode remote --concurrency 1
|
||||
```
|
||||
Requires the `browse` CLI (`npm install -g browse`). `--mode remote` drives a Browserbase session (the script passes `--remote` on each `browse` command); use `--mode local` for local Chrome. Writes one PNG per competitor to `{OUTPUT_DIR}/screenshots/{slug}-hero.png`. `compile_report.mjs` auto-embeds the hero in the per-competitor HTML page when present.
|
||||
|
||||
Cost: ~10-20s per competitor (serial). Total for 5 competitors ≈ 60s.
|
||||
|
||||
### Sizing Formula
|
||||
```
|
||||
search_queries = ceil(requested_competitors / 20) # discovery is narrower than lead gen
|
||||
discovery_subagents = ceil(search_queries / 3)
|
||||
expected_urls = search_queries * 15
|
||||
|
||||
quick: research_subagents = ceil(expected_urls / 8)
|
||||
deep: research_subagents = ceil(expected_urls / 4)
|
||||
deeper: research_subagents = ceil(expected_urls / 2)
|
||||
```
|
||||
|
||||
### Error Handling
|
||||
- If a subagent fails, log and continue with remaining batches
|
||||
- If >50% of subagents fail in a wave, pause and inform the user
|
||||
- If `browse cloud fetch --allow-redirects` fails, try `browse open "{url}" --remote` + `browse get markdown` as fallback, or skip that page
|
||||
|
||||
## Report Compilation
|
||||
|
||||
After all enrichment subagents complete, compile all HTML views in one command:
|
||||
|
||||
```bash
|
||||
node {SKILL_DIR}/scripts/compile_report.mjs {OUTPUT_DIR} --user-company "{user_company}" --open
|
||||
```
|
||||
|
||||
The script:
|
||||
- Reads all `.md` files in `{OUTPUT_DIR}`
|
||||
- Parses YAML frontmatter + body sections
|
||||
- Deduplicates by normalized competitor name
|
||||
- Generates `{OUTPUT_DIR}/index.html` — overview table (name, tagline, pricing, key features, strategic diff)
|
||||
- Generates `{OUTPUT_DIR}/competitors/{slug}.html` — per-competitor deep dive
|
||||
- Generates `{OUTPUT_DIR}/matrix.html` — side-by-side feature/pricing grid across competitors
|
||||
- Generates `{OUTPUT_DIR}/mentions.html` — chronological feed with source-type pills + client-side filter
|
||||
- Generates `{OUTPUT_DIR}/results.csv` — flat spreadsheet
|
||||
- Opens `index.html` in the default browser (`--open` flag)
|
||||
- Prints a JSON summary to stderr
|
||||
Reference in New Issue
Block a user