beat-my-competitors
Context load
Run rainmaker context --check first. It prints what exists, what is stale, and exits 1 if anything this skill requires is missing.
Then read, in this order:
context/business.mdin full. If absent, stop: "No business context. Runrainmaker audit, then theknow-my-buyerskill."context/voice.mdif this skill writes prose. If absent, stop and say so.context/glossary.mdif this skill names products, features or competitors.data/strategy.jsonif this skill reads or writes strategy.- Only the
data/files listed in this skill's Consumes table. Never crawl or call an API the core already covers.
If strategy.json.context_hash does not match the current hash of context/business.md, say exactly:
"Business context was edited after the strategy was written. Re-run know-my-buyer, or run rainmaker context --sync to accept the prose as authoritative."
Then stop.
If context/business.md carries confidence: stub, continue, and stamp every output with: "Built on a stub context. Nothing in it came from a buyer. Run know-my-buyer to replace it."
Consumes
| File | Why | If missing |
|---|---|---|
config.competitors or strategy.json.competitors |
who to tear down | ask the user for 3 to 5 domains and stop |
data/state.json |
our own tier distribution, for a like-for-like comparison | run rainmaker audit |
data/citation-graph.json |
which competitor pages answer engines cite | say the comparison omits AI citation |
Produces
data/competitors.json. Appends benchmark proof points to strategy.json (owner: beat-my-competitors) and the competitor table in context/business.md.
Refuses when
No competitors are named anywhere. Ask for 3 to 5 domains and stop; do not guess competitors from search results.
Concurrency
One agent per competitor, maximum 5. This is one of the three permitted fan-out points in the system.
Procedure
- Per competitor: fetch their sitemap, classify every URL into our own tier rules from
src/analyze/tiering.ts, so the comparison is like for like rather than borrowing their own labels. - Count pages per tier. A competitor with 40 tier 1 pages against our 3 is the finding; their domain rating is not, and is never used.
- Pull their tier 0 and tier 1 pages. Extract positioning language, pricing presence, proof types and named integrations, in their own words.
- Diff
strategy.json.clustersagainst their coverage. A cluster we have not built that they cover becomes a candidate withgap: 'missing'. - Where GSC data exists, mark which of our queries they also rank for.
- Where the citation graph exists, mark which of their pages answer engines cite. A competitor page that owns the answers matters more than one that merely exists.
Decision rules
- Never report a third-party domain authority score. The core spec forbids vendor authority metrics anywhere in scoring or reporting.
- A gap counts only when the competitor's page is tier 0, 1 or 2. Tier 3 blog volume is one summary count, never a page-by-page list.
- Every competitor claim in
context/business.mdcarries the domain and the page it came from.
Output
Per competitor: a tier distribution table, a positioning summary in their own words, and a joint gap table ranked by the tier weight of the missing cluster.
Done when
competitors.json validates against its schema, every gap row has a target tier and a pain point id or an explicit unmapped marker, and no domain authority score appears anywhere in the output.