mcpField
H
hypothesis-scoring

hypothesis-scoring

github.com/victor-shulgaMarketing & growth141 installsUpdated 3w ago
Repository

About hypothesis-scoring

hypothesis-scoring is a skill for growth teams that turns outbound campaign ideas into a ranked pre-launch queue. It filters ideas for feasibility before weighted scoring, then specifies launch capacity, stop dates, and a test journal.

Key features

  1. 01Four execution-readiness gates
  2. 02Numeric hypothesis rewrite format
  3. 03Six-factor weighted scoring
  4. 04Capacity-based launch queue
  5. 05Test plans and journal template
  6. 06Failure diagnosis by campaign stage

Use cases

  1. 01Choosing outbound hypotheses to test next
  2. 02Checking whether a campaign list and channel are viable
  3. 03Planning parallel tests around sender capacity
  4. 04Diagnosing weak campaign results

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/victor-shulga/gtm-skills --skill hypothesis-scoring

After installing, type/hypothesis-scoringin Claude Code to confirm it loaded.

Bundled filesexamples/hypotheses.example.jsonscripts/score.py

Details

From the project README

Hypothesis Scoring — the pre-launch queue

Takes a pile of hypothesis ideas and returns a launch queue: which three go into work now, which wait, which are disqualified and why.

The point of this skill is to end the argument that usually follows a batch of outbound tests — "did it work or not" — with a number agreed on before the send.

Output language: the team's working language (Ukrainian by default for Ukrainian-speaking teams; English if the input is English). Plain words, no jargon.


What you need

  • A list of hypothesis ideas — a matrix from hypo-generator, a workshop output, the team's own list, or raw text.
  • Per idea, ideally: ICP · trigger (or static data point) · offer · channel · proof (a case with a number) · where the list comes from.

Missing fields are not a blocker — they are a finding. An idea with no proof or no list source fails the gate at Step 1. Never invent either one.

Ask for, if not given: which channels are live and how many senders (LinkedIn accounts / mailboxes), and whether the team has its own campaign history (own numbers always beat market benchmarks).


Workflow

Step 1 — Stop-filter (the gate before any scoring)

Four yes/no gates. One "no" means the hypothesis is not scored at all. Scoring something you can't execute only pollutes the queue.

#GatePASS means
G1The list can be builta named source + filter that yields ≥300 companies carrying this trigger. "Somewhere on LinkedIn" = FAIL
G2The trigger is verifiablefor one specific company you can confirm the event happened and name the date
G3Proof existsa case, a number, or an adjacent project the decision maker will accept as relevant to THIS segment
G4The decision maker is reachable in the channelthey read LinkedIn, or have a work mailbox that passes the gateway

Technical stop-filter (email only — checked once per company, not per hypothesis): SPF/DKIM/DMARC set on every domain · inbox-placement tested (not "well, the emails are going out") · mailboxes warmed ≥3 weeks · bounce rate under 3% in previous campaigns.

A failure here blocks every email hypothesis at once — report it as one blocker with an owner, not as N separate findings. These checks cost a day; skipped, they poison every conclusion that follows, because a hypothesis looks dead when the emails simply never arrived.

Output a gate table: hypothesis | G1 | G2 | G3 | G4 | verdict. For each FAIL, write the single action that fixes it and who owns it.

Step 2 — Rewrite into the canonical format

A hypothesis that cannot be refuted by a number stays an opinion. Rewrite every survivor into one sentence:

For [ICP] with trigger [T], offer [O] in channel [C] will produce at least [N] replies per 300 contacts in 3 weeks. Below half of N: close it. Between half and N: change one variable and repeat. N or above: scale the volume to 1000.

Calculating N — use the team's own history when it exists; market baselines only when it doesn't:

ChannelMath on 300 contactsDefault N
Email300 × 1.5% (2026 average reply rate)4–5
LinkedIn300 × 30% accepted × 20% replied15–20

N is a floor, not a forecast. If someone wants N set below the market baseline, the hypothesis isn't worth a slot.

Step 3 — Channel physics (how many tests actually fit)

Capacity decides how many hypotheses run in parallel. Ambition doesn't.

  • LinkedIn: ~20 invites/day per account → 300 contacts = 15 working days = 3 weeks for ONE account on ONE hypothesis. Three parallel tests need three accounts. There is no third option.
  • Email: 3 mailboxes × 30 emails/day = 90 sends/day. A 3-step sequence over 300 contacts ≈ 900 sends ≈ 10 working days.

Output: available capacity → how many hypotheses physically fit this cycle → a stop date for each test, in the calendar. If the queue is longer than the capacity, say so plainly — that, and not the score, is why the rest are waiting. A plan for five parallel hypotheses on one LinkedIn account is really a five-month plan.

Step 4 — Score (6 factors, scale 0 / 1 / 3 / 5)

The zero is mandatory. Without it every option clusters around 3 and the score stops separating anything.

FactorWeight5 =0 =
Proof strength for this segment0.25a case with a real number in exactly this nicheno proof at all
Pain sharpness0.25hurts right now, budget already allocateda pain we invented; the market never named it
Trigger non-obviousness0.20competitors don't use this signaleveryone uses it — noise
Segment volume0.10over 1,000 companiescan't even be assembled up to 300
Data-collection cost0.10the list is built in an hourmanual research per account
Speed of verification0.10first replies within a weekthe cycle runs longer than a month

Intermediate values: 1 = weak but present · 3 = normal, works but unremarkable.

Total = Σ(score × weight), range 0.0–5.0.

Two hard rules:

  1. A zero on Proof or on Pain removes the hypothesis from the queue — regardless of the total. Report it as dropped, and name the missing piece. A high total built on no proof is the most expensive kind of false confidence.
  2. The three highest totals go into work, however many crossed 3.2. The threshold is secondary; the queue is the mechanism. A fourth hypothesis splits attention and splits the list.

Every score carries a one-line reason. A bare number can't be argued with later, and in a quarter nobody remembers what it meant.

The scoring is subjective, and that's fine: it decides launch ORDER only. The facts will come from replies either way.

Step 5 — The queue
#Hypothesis (one line)ProofPainTriggerVolumeDataSpeedTotalStatus

Statuses: launch (top 3) · queue (waits for the next cycle or free capacity) · dropped (zero on Proof or Pain) · failed the gate (Step 1 FAIL + what to fix).

Step 6 — Launch plan + journal

For the three launched:

  • ICP · trigger · offer · channel · N · first batch size (300) · start date · stop date · who decides to close it.
  • Order of variables. Round 1 "where": offer and copy frozen, 2–3 segments run in parallel (a segment = ICP + trigger, they move together). Round 2 "what": winning segment, two offer variants. Round 3 "how": same segment and offer, the angle changes — first line, proof, call. One change per round; two changes at once turn the result into a guess.
  • Write to 2–3 people per company, not one. With a single contact you can't tell "wrong persona" from "wrong company", and you'll close a live segment by accident.
  • Triggers expire. A job posting stops being a signal after ~30 days, a funding round after ~90. A list assembled three months ago is not a trigger list, and the campaign on it will fail regardless of copy quality.

Then emit the journal skeleton with the fact columns empty: number · ICP · trigger · offer · channel · start date · stop date · contacts · companies · sends · delivered · opens · replies · positives · meetings · three verbatim objection quotes · verdict · next step.

The verdict has exactly three values: scale · change one variable · close. If you're tempted to write "not clear yet", the volume was too small — that is also a journal entry.

Keep three verbatim objection quotes from every test. After five campaigns you have a dictionary in which the market itself explains why it doesn't buy.

Step 7 — Portfolio 80/20 (once two hypotheses have confirmed meetings)

80% of the channel's daily quota goes to the proven ones. 20% stays for ONE active test — not two, not five, but one, carried all the way to 300 contacts. When a test wins, it moves into the working 80% and the weakest working hypothesis is switched off; the queue from Step 5 supplies the next one.


Reading a failure (when the test comes back)

Scoring happens before launch, but the queue only stays honest if failures are diagnosed instead of mourned. Four axes, checked in this order:

  1. Technical — opens under 30%, bounces over 3%, mail in spam. The hypothesis had nothing to do with it: fix delivery and rerun the same test.
  2. Targeting — replies exist and they say "we don't do that", "you want a different person", "we're not in that region". The segment or the persona is wrong.
  3. Offer — "got it, but we don't need it", "we handle this in-house", "we already have a contractor". Right segment, weak proposition.
  4. Message — delivery fine, segment confirmed, silence in return. The copy and the angle are the problem.

Hard rules

  • Never invent proof or a list source. Missing = a gate FAIL, not "a 3".
  • A hypothesis without the number N is not scored — rewrite it into the canonical format first.
  • 300 contacts is the minimum test. Positives are not readable at 300 at all: the difference between one and three is randomness. Talk about positives and cost-per-meeting from 1000 up.
  • The base metric of a test is the reply rate; the hypothesis wins on meetings. 4% replies and zero meetings is not a working hypothesis, whatever the table says.
  • Exactly three hypotheses launch. The fourth divides attention and the list.
  • Own campaign numbers beat market benchmarks whenever they exist.
  • Agree in advance who decides to close a test. Without that, a test runs until somebody gets bored.

Helper script

scripts/score.py does the arithmetic and sorts the queue, so nobody adds weights in their head:

python3 scripts/score.py hypotheses.json

Input format, the hard-zero rule and gate handling are documented in the script header. It prints a ranked markdown table you can paste straight into the report.


Pairs with

  • hypo-generator — builds the hypothesis matrix from an agency URL; this skill scores its output before launch.
  • agency-signal-sourcer — detection tooling, cost and decay window per trigger; feeds the "Data-collection cost" and "Trigger non-obviousness" factors.
  • anticopywriting-ai — run the finished report through it before sending it to anyone.

Comments

Markdown supported