Agency Skills
SkillsCollectionsContributorsContribute
Install every skill
Agency Skills

Skills written by the people who run agencies, consultancies and coaching firms. Free and open source, MIT.

LibraryAll skillsCollectionsContributorsInstall every skillFor AI agents (llms.txt)
ContributeHow to contributeContributor guideGitHubReport a problem
GiaCompany BrainBook a build session
Built by the community. Published by Gia.PrivacyTerms
Skills/Win the work/Cold email sequence that gets positive replies
Sales

Cold email sequence that gets positive replies

Use this skill when an agency is writing, rewriting or reviewing cold email for a client: a full sequence, a subject line, first line, P.S., CTA, offer, follow-up step, spintax, a signal or trigger campaign, conference outreach, a segment and offer map, or an A/B test. Walks the decisions in order (value lever, list and signal, offer, subject, first line, body framework, CTA, follow-ups), lints the copy and sizes or reads tests. Also use for "build a sequence", "why isn't this campaign getting replies", "did variant B win".

Garrett WolfeFounder, OneGTM
Say something like
“build a sequence”“why isn't this campaign getting replies”“did variant B win”
instantlycold-emailoutboundcopywritingsignalsab-testingsequences
SKILL.mdView on GitHub

Cold Email Sequence

How we write cold email, every time. This skill owns the copy craft: what to say, in what order, and how to check it. The campaign shape, naming and API push belong to your sending setup, and the voice belongs to the client.

Read before writing:

  • references/playbook.md is the full canonical doc: every rule with its source, the disagreements between experts and the call we made on each, and the benchmarks.
  • references/frameworks.md holds body templates per situation (signal, no signal, creative ideas, lookalike, new leader, referral) and the follow-up templates.
  • references/offers.md covers picking an offer or lead magnet and scoring it.
  • references/ai-lines-and-spintax.md covers AI-written slots, blank-variable safety and Instantly spintax.
  • references/ps-and-first-lines.md: first-line types, the bridge test, AI first-line prompting, P.S. types and rules .
  • references/signals.md: every buying signal (website visitors, new hires, promotions, exec changes, job posts, hiring surges, funding, M&A, launches, competitor post engagement, our-post engagement, content downloads, webinars, champion moves, closed-lost, PQL, third-party intent, tech changes, reviews, layoffs, earnings and more): strength, window, whether to name it, angle, example line, pitfalls, stacking and who gets the email.
  • references/conferences.md: pre / during / post conference outreach, roster gates, event-anchored copy and templates.
  • references/triggers.md: time-based triggers (company events, sports, weather, the B2B calendar) with recency windows, data sources and the never-send list.
  • references/segments-and-offers.md: the messaging map (segment → pain, lever, offer, proof, CTA), deterministic routing, and offer waterfalls.
  • references/testing.md: test order, sample sizes, design, tags, the test log and the decision rubric. references/ab_test.py does the math.
  • references/voices-and-styles.md: more practitioners (Crawford PQS/PVP, 30MPC, McKenna, Coleman, Abraham), the best 2025-26 episodes, and a verdict on each trending style.
  • references/evidence.md has the benchmark numbers.

Precedence: the client's brief and voice guide > this skill > the experts. If a client rule contradicts a default here, the client wins. Say so in the spec.


The one idea

A positive reply needs three things to be true at once: the right person, a reason now, and an outcome they want, easy to say yes to. Copy amplifies a good list and offer; it can't rescue a bad one. Experts agree on the priority order for effort and testing: list > offer > subject > opener > CTA > timing > length.

The value lever (mandatory)

Every email names exactly one lever, in the prospect's nouns:

LeverThe prospect hearsSounds like
Make moneymore revenue, pipeline, deals, customers"every pool contractor in Texas with the owner's cell"
Save time or moneyfewer hours, people, tools, dollars"without adding a second SDR"
Reduce riskfewer misses, mistakes, fines, churn, surprises"before the audit, not after"
  • Pick E1's lever from the pain the best current customer had before buying. If the pain is unclear, that's the gap to fix, not something to paper over in copy.
  • Rotate levers across the sequence. If E1 was "save time" and got no reply, that lever didn't land, so E3 tries "make money" or "reduce risk".
  • State it as a problem or a concrete outcome, not an ROI promise. Gong found ROI claims in cold email cut success 15%. "know what each float costs before you price it" beats "boost margins 23%". Numbers belong in proof (what happened for someone), not in promises.

The workflow

Run these in order. Steps 1-4 are decisions. Write them at the top of the campaign spec before any copy exists. If a step can't be answered, stop and get the input; don't write around it.

1. Gather inputs (no copy yet)

From the client's graph or docs: what they sell (one sentence a buyer would recognise), the persona and their day, the #1 pain the best customer had before buying, cleared proof points (names and numbers you may use), what they don't do, banned claims, and the voice node. Research the client's site: every case-study customer, their industry, size, metric and problem. Challenge the ICP if the case studies show a broader buyer.

2. List and signal: why you, why now

  • Name the cohort and the trigger. Tighter beats bigger: campaigns under ~200 contacts reply at roughly 2x the rate of 500-1,000 (Saleshandy 2026).
  • Relevance beats personalization (Becc Holland). A line true of the whole cohort ("you run a title agency with no in-house marketing") beats a fake-personal token. Reply.io found generic personalized variables cut interested replies 26%.
  • Signal strength, strongest first: a stuck mandate they told the world about (job post, public ask) > a dated event (new role under 90 days, raise, launch, expansion) > a structural fact (team shape, stack, geo) > none (go Billboard or Search, see step 5).
  • Only cite signals you can verify. Never invert a tech-stack absence ("no enrichment tool detected" is wrong too often). Job titles and job posts are safe to invert.
  • Write to the signal with references/signals.md. The naming rule decides the opener: public, self-announced events (job change, funding, job post, talk) may be named, with an observation attached. Tracked behavior (site visits, intent, G2, likes) is never stated; write to the problem it implies. First-party relationships (past champion, closed-lost, our webinar) are named, because the relationship is the hook. Events and conferences: references/conferences.md.
  • Time-based triggers (company events, sports, weather, fiscal year, calendar) each have a send window and a never-send list. A freshness gate in code re-checks in-flight leads, and a stale or empty trigger drops the line, never the email (references/triggers.md).
  • More than one segment? Build the messaging map first (references/segments-and-offers.md). Each segment keeps the core value but switches pain language, lever, proof and offer. Code assigns the segment (first matching rule wins, ending in default), and one segment = one campaign. 3-6 live segments at most, each able to reach ~1,000-2,500 leads in a test window.

3. Offer: what they get for replying

Lead with what the prospect gets. A meeting is an ask, not an offer. Run references/offers.md: generate 5-10 candidates, score each on four criteria (1-5 each: cheap to deliver, valuable enough to pay for, shows competence, unique vs competitors), and keep only those scoring 15/20 or more. Never gate it behind a form. The most you ask of them is a one-line reply.

4. Subject line

  • 2-4 words, specific, reads like an internal email. Sentence or lowercase per client voice. Belkins measured 2-4 words best.
  • Pick one of three types: a signal or name ("title agency marketing", "the vp sales req"), the whole offer (the subject plus preview text self-select the reader), or a problem indicator ("looked you up on chatgpt").
  • Test: could a colleague or customer have sent this? Never "quick question", "curious", "following up", "partnership opportunity", fake "re:", or clickbait.
  • Threaded follow-ups (E2, E4) have a blank subject.

5. Email 1

Pick a framework from references/frameworks.md by situation:

SituationFramework
Real signal, want a conversationSignal 4-move (Kellen): signal → three pains → insight → binary CTA
Real signal, clear offerObservation → lever → proof → soft CTA
No signal, homogeneous niche listBillboard: the whole offer up top; the reader self-selects
No signal, unknown painSearch: "trying to find the [team] that [has X figured out]"
Broad list, varied businessesCreative ideas: 3 slot-defined bullets from their site
Have a lookalike customerLookalike: "[similar company] had [problem]; [what changed]"
New in seat (< 90 days)New leader: the window insight plus a state CTA
Unsure who owns itReferral (Ross): find the right person
We hold data they can't easily getPVP (Crawford): the finding is email 1
Persona relevance, no signal4-sentence (30MPC): reason → problem → solution → interest CTA
Exec / tier-1, strong signalPOV (Coleman): interpret what the signal means for them

Rules for every E1:

  • First line is about them, specific and observable, and puts the strongest phrase where the preview shows it. It must bridge: if deleting line 1 doesn't change line 2, it's decoration. Execs get company relevance; ICs can get personal (references/ps-and-first-lines.md). No "hope this finds you", "I wanted to reach out", "I came across", "my name is", or prefacing ("quick one", "I'll keep this short").
  • One email, one job, one lever, one CTA. Aim for 50-90 words; 125 only when an AI slot earns it. Keep the reading grade at 7 or under, and keep sentences about them at 3:1 to sentences about you. It should read aloud in under 20 seconds.
  • Exactly one question, and it's the CTA, answerable in five words or fewer. Default to the interest or state form: "worth a look?", "is that on your radar?", "already solved, or still manual?". Never a calendar ask in E1. Gong: specific-time asks book 15% cold vs 37% in active deals.
  • Proof only if it matches the prospect's problem shape: one named customer and one number, stated as what happened, never a logo list. Otherwise hold it for E3.
  • No links in E1, no images, no tracking, no attachments, no exclamation marks, no em dashes.

5b. P.S. (optional, E1)

One P.S., one sentence, ≤20 words, new information only, never a second pitch or a repeat of the CTA. Its job is the human detail (fact + casual reaction) that would clutter a relevance-led body, or a soft offer when the body has no question. The fact must be public and explainable. Abstain to no P.S. rather than a filler one. Types and prompts: references/ps-and-first-lines.md.

6. The sequence (default 4 emails, 2 threads)

StepThreadJobWordsLever
E1A, new subjectbest signal, clearest offer50-90lever 1
E2A, blank subjectone new fact or angle; reads like a reply25-50lever 1 or 2
E3B, new subjectnew angle; proof or a lower-commitment offer (audit, list, video)40-80a different lever
E4B, blank subjectexit: a redirect ("who owns X?") or a useful resource; no guilt20-40none
  • Each email stands alone. Never reference the last one ("following up", "bumping", "circling back", "did you see", "one more thought", "last note from me"). Gong: "I never heard back" raises replies but cuts meetings 14%; "Thoughts?" cuts meetings 20%.
  • Follow-ups matter: 42-57% of replies (and 57% of positive replies) come after E1. But each step past the 4th roughly triples spam complaints. Four steps is the default; never more than five.
  • Timing, delays and threading use delays of 2/2/3/2 days, and step 1's delay is never 0 (in Instantly, a step's delay is the wait after it).

7. AI lines and variables

AI fills slots, never whole emails. Keep the template, pitch and CTA human-written. Each slot gets a fixed frame in the copy, a word cap and an abstain rule (empty string). Hand-write the first three examples before any model runs, and review a batch of 10, never single rows. Then preflight: every variable must be non-empty on every enrolled lead, including in-flight leads. Instantly sends a blank variable silently, and spintax can't hide a blank. Full method: references/ai-lines-and-spintax.md.

8. Spintax (Instantly)

{{RANDOM|a|b}}, never Smartlead's {a|b}. Use 3-5 blocks per cold open, 2-3 options each, on the greeting, connectors, a mid-body verb and the CTA. Never spin variables, numbers, names, proof, prices or technical terms. Every combination must read as a grammatical sentence, so spin whole clauses rather than fragments that collide.

9. Check, then ship

  1. python3 references/lint_copy.py <spec.json|draft.txt> must report 0 errors. It checks length, question count, subject words, banned phrases, spam words, links, dashes, spintax syntax and collisions across every rendered combination, reading grade, you:I ratio, variables used and step-1 delay.
  2. Score it on the rubric in references/playbook.md §9. Ship at 85 or above; 70-84 needs one more pass; below 70, start over at step 2 or 3, not at the wording.
  3. Edit every variant for AI writing patterns. Re-lint afterwards.
  4. Render five real leads end to end and read them aloud. Ask: would I reply to this? AI judges reward cleverness humans don't, so show a person real renders early.
  5. Hand off for campaign setup, preflight and push. Record the copy tags (lever, hook, CTA, offer, proof) with the campaign spec so you can attribute the result.

Testing (how we learn what works)

  • Test one variable per campaign or arm, in priority order: list > offer > subject > opener > CTA. An A/B variant that changes three things teaches nothing.
  • Sample size: at a 1% baseline you need ~2,300 sends per arm to see a 2x lift and ~7,750 to see 1.5x (python3 references/ab_test.py n 0.01 2). Vendor floors of 100-500 only detect 3x+. So at our volumes, test list, offer, angle and segment; pool small copy tweaks through tags.
  • Whole-sequence tests run as separate campaigns split at random before upload. Step-1 tests (subject, first line, CTA) run as in-step variants. Turn Instantly auto-optimize off on a declared test, since it optimizes raw replies. Close only after every lead finishes the sequence plus 7 days. Log every test with the template and rubric in references/testing.md.
  • Grade on positive replies and meetings, never raw replies or opens. Opens are inflated by Apple MPP. Bumps like "Thoughts?" buy replies and lose meetings.
  • Read results with python3 references/ab_test.py analyze <sendsA> <posA> <sendsB> <posB>: promote at P(B>A) ≥ 0.90 with ≥10 positives on the winner and meetings not moving the other way.
  • Bars: a positive reply rate of 1% or more is good and 2% or more is great. Message-market fit is at least 1 reply per 320 sends for a templated campaign. Below that after ~1,000 contacts, change the list or the offer, not the words. Pause any campaign at more than 0.3% hostile replies or more than 2% unsubscribes.
  • Read your own results by copy tag before writing a new campaign. Your live read beats any rule here once n is large enough.

What good looks like

  • The lever, list, signal and offer are written at the top of the spec before any copy exists. If one can't be answered, stop and get the input.
  • The copy lints at 0 errors, scores 85 or above on the playbook rubric, and five real lead renders read well aloud.
  • Results are graded on positive replies and meetings, never opens or raw replies.
  • Red flag: rewording a campaign that is under 1 reply per 320 sends after about 1,000 contacts. That is a list or offer problem, not a words problem.

Hard rules (lint enforces most)

  1. One lever, one job, one question-CTA per email. No calendar ask in E1.
  2. First line about them. No pleasantries, no prefacing, no "following up".
  3. Subject 2-4 words, specific, not clickbait. Threaded follow-ups have a blank subject.
  4. 50-90 words for E1/E3 (hard max 125); follow-ups under 50.
  5. No em dashes, exclamation marks, links in E1, images, tracking or attachments.
  6. No hard spam phrases (references/spam_words.json); no agency vocabulary.
  7. Never fabricate a fact, a mutual connection, a customer or a number. Claims come from the client's cleared proof.
  8. Instantly spintax only. Every rendered combination is grammatical. Never spin variables, names or numbers.
  9. Every variable is non-empty on every lead or the row is excluded. AI slots abstain to empty.
  10. At most one P.S.: one sentence, new information, never a second pitch.
  11. Trigger facts come from stored fields within their send window; a stale or empty trigger drops the line, never the email. Never send into disasters or tragedies.
  12. Never imply silence ends it ("I'll take silence as a no"); give an easy out instead ("a quick 'not for us' is enough and I'll stop").
15 reference files
references/ab_test.py

#!/usr/bin/env python3 """Sample size, minimum detectable effect and Bayesian readout for cold email A/B tests.

python3 ab_test.py n 0.01 2            # sends per arm to detect 2x lift at a 1% baseline
python3 ab_test.py n 0.01 1.5 --alpha 0.10
python3 ab_test.py mde 0.01 3000       # smallest lift detectable with 3,000 sends per arm
python3 ab_test.py analyze 2400 21 2400 38          # champion sends, positives, challenger sends, positives
python3 ab_test.py analyze 2400 21 2400 38 --prior 1 99

Metric is positive reply rate per unique lead. Two-sided test, 80% power by default. No dependencies (stdlib only). """ import argparse import math import random from statistics import NormalDist

Z = NormalDist().inv_cdf

def n_per_arm(p1, lift, alpha=0.05, power=0.8): p2 = p1 * lift pbar = (p1 + p2) / 2 num = Z(1 - alpha / 2) * math.sqrt(2 * pbar * (1 - pbar)) + Z(power) * math.sqrt(p1 * (1 - p1) + p2 * (1 - p2)) return math.ceil(num ** 2 / (p2 - p1) ** 2)

def mde(p1, n, alpha=0.05, power=0.8): lo, hi = 1.0001, 50.0 for _ in range(60): mid = (lo + hi) / 2 if n_per_arm(p1, mid, alpha, power) > n: lo = mid else: hi = mid return hi

def analyze(na, xa, nb, xb, a0, b0, draws=200_000, seed=7): rng = random.Random(seed) wins, loss_b, loss_a = 0, 0.0, 0.0 for _ in range(draws): pa = rng.betavariate(a0 + xa, b0 + na - xa) pb = rng.betavariate(a0 + xb, b0 + nb - xb) wins += pb > pa loss_b += max(pa - pb, 0) loss_a += max(pb - pa, 0) return wins / draws, loss_b / draws, loss_a / draws

def wilson(x, n, z=1.96): if n == 0: return 0.0, 0.0 p = x / n d = 1 + z * z / n c = (p + z * z / (2 * n)) / d h = z * math.sqrt(p * (1 - p) / n + z * z / (4 * n * n)) / d return max(0, c - h), c + h

def main(): ap = argparse.ArgumentParser(description=doc, formatter_class=argparse.RawDescriptionHelpFormatter) sub = ap.add_subparsers(dest="cmd", required=True) s = sub.add_parser("n", help="sends per arm") s.add_argument("baseline", type=float) s.add_argument("lift", type=float, help="relative, e.g. 1.5 or 2") s.add_argument("--alpha", type=float, default=0.05) s.add_argument("--power", type=float, default=0.8) s = sub.add_parser("mde", help="minimum detectable lift for a given n per arm") s.add_argument("baseline", type=float) s.add_argument("n", type=int) s.add_argument("--alpha", type=float, default=0.05) s.add_argument("--power", type=float, default=0.8) s = sub.add_parser("analyze", help="Bayesian readout: champion (A) vs challenger (B)") for k in ("sends_a", "pos_a", "sends_b", "pos_b"): s.add_argument(k, type=int) s.add_argument("--prior", type=float, nargs=2, metavar=("A0", "B0"), help="Beta prior; default Beta(1, 1/baseline - 1) from the pooled rate") s.add_argument("--tolerance", type=float, default=0.001, help="expected-loss stop threshold (0.001 = 0.1 point)") a = ap.parse_args()

if a.cmd == "n":
    n = n_per_arm(a.baseline, a.lift, a.alpha, a.power)
    exp = n * a.baseline
    print(f"{n:,} sends per arm ({2 * n:,} total) to detect {a.lift}x on a {a.baseline:.2%} baseline "
          f"(alpha {a.alpha}, power {a.power}). Expect ~{exp:.0f} positives in the champion arm.")
elif a.cmd == "mde":
    m = mde(a.baseline, a.n, a.alpha, a.power)
    print(f"With {a.n:,} sends per arm at {a.baseline:.2%}, the smallest detectable lift is {m:.2f}x "
          f"({a.baseline * m:.2%}).")
    if m > 2:
        print("MDE > 2x: only test list, offer, angle or segment changes at this volume.")
else:
    pooled = (a.pos_a + a.pos_b) / max(1, a.sends_a + a.sends_b)
    priors = [tuple(a.prior)] if a.prior else [(1, max(1, round(1 / max(pooled, 1e-4)) - 1)), (1, 1)]
    for lbl, n, x in (("A champion", a.sends_a, a.pos_a), ("B challenger", a.sends_b, a.pos_b)):
        lo, hi = wilson(x, n)
        print(f"{lbl:13} {x:4} / {n:6,}  PRR {x / max(n, 1):.2%}  95% CI {lo:.2%}-{hi:.2%}")
    if min(a.pos_a, a.pos_b) < 10:
        print("note: an arm has under 10 positives; read this as a hypothesis, not a result.")
    for a0, b0 in priors:
        p, lb, la = analyze(a.sends_a, a.pos_a, a.sends_b, a.pos_b, a0, b0)
        if p >= 0.9 and lb < a.tolerance:
            verdict = "PROMOTE challenger (if the validity gate passed)"
        elif p <= 0.1:
            verdict = "KEEP champion"
        else:
            verdict = "INCONCLUSIVE: extend once to 1.5x n, or keep the simpler variant"
        print(f"prior Beta({a0:g},{b0:g}): P(B>A) = {p:.3f}, expected loss choosing B = {lb * 100:.3f} pts, "
              f"choosing A = {la * 100:.3f} pts -> {verdict}")

if name == "main": main()

references/ai-lines-and-spintax.md

AI Lines, Variables and Spintax

Part 1: AI-written lines

When to use AI at all

Use AI context only when the prospect's business changes how the product helps them (Eric).

  • Yes: broad targeting (a facilities manager at a hospital vs a hotel vs a school), variable use cases, creative-ideas campaigns.
  • No: commodity use cases, narrow homogeneous lists, or anything that feels forced. Static copy wins there.
  • Checklist: the targeting is broad enough that the context varies; the value changes with what they do; the line adds relevance; removing it would make the email generic. Fail any one, and keep it static.

Slot discipline

AI fills slots inside a human template, never whole emails (in our testing, whole emails from top models scored well with AI judges and a human rejected them as clever but unclear).

For each slot, define:

  1. The frame lives in the copy, not the variable. "I think we can help you {{specificity_line}}." The variable holds only the tail, so the model can't drift the sentence.
  2. What it's about, fixed for every lead (slot-defined bullets: 21/23 usable vs 2/5 free-form).
  3. Caps: words (≤20 for a line, 8-22 per bullet, 6-14 for a tail) and characters (≤90).
  4. The offer block: 5-7 lines of what the client actually does, plus a "What they do NOT do" line. The model may only promise what's in that block.
  5. Banned words: vague outcomes ("grow sales", "boost margins", "improve efficiency", "your business", "platform", "solutions", "leverage", "ecosystem"). If a line needs one, the anchor is too vague.
  6. Abstain rule: if the input is thin (a description under ~20 characters or no evidence), the model returns an empty string. Never "N/A", "there", "your company" or "cannot be generated".
  7. Evidence quote: each line quotes the source substring it's based on (evidence_N). Code checks the substring exists and blanks the line if not. That's a free hallucination check.
  8. Reading grade ≤ 7 on the generated part.

Process (Eric's approval loop)

  1. Hand-write 3 complete examples for 3 real companies before any model call. The AI never drafts the exemplars it is graded against.
  2. Few-shot with 8-10 pairs, including at least 2 abstains.
  3. Run 1 lead, then batches of 10, shown as a table. Each edit updates the prompt.
  4. Lock the prompt after 2 consecutive rounds with zero edits. Judge a batch, never a row.
  5. Run 5 rows before 5,000. Expect 10-20% blanks. More than 30% blank means the list is wrong. Under 5% blank means the prompt got loose.
  6. Use a cheap model for slots (nano / mini class).

Facts are computed, not generated

Dates, counts, tenure, funding amounts and enums come from code. The model only phrases them. For signal lines:

  • "started a new role", never "hired" (28% are internal moves).
  • Funding: the round and amount, never the valuation or investors; indexes lag 3-4 months.
  • Job posts: blank if older than 30 days.
  • Never name the recipient to themselves as "another prospect"; never claim a mutual connection; never name a client's customer without approval.
  • Skip personal, political, bereavement or charged social posts (fail closed).

Part 2: Variables and blanks

Instantly sends a blank variable as an empty string, silently. No bounce, no error. "Hey ," goes out.

  • Every variable in a subject or body must be non-empty on every enrolled lead, including in-flight leads, or have a fallback. Run a required-variable check before activating.
  • Word-level slots get a fallback: {{firstName | there}}, {{companyName | your team}}. Instantly renders the fallback when the field is empty, so a blank becomes impossible. Pick a fallback that reads naturally in the sentence; lint renders the fallback to check.
  • Spintax can't gate an empty variable. {{RANDOM|Saw {{funding_line}}.|}} renders "Saw ." about half the time. Use a self-erasing whole-sentence variable (the variable holds the full sentence, or is empty and the template still reads), or split the list: leads with the slot go to the AI campaign, leads without go to the static one.
  • An empty creative-ideas bullet excludes the row.
  • Namespace custom fields per campaign (creative_idea_1_<campaign>) so a re-run can't overwrite a live one.

Part 3: Spintax (Instantly)

Syntax: {{RANDOM|option a|option b|option c}}. No spaces around the pipes (house convention). Smartlead's single-brace {a|b} renders literally in Instantly, and lint flags it.

Where: 3-5 blocks per cold open, 2-3 options each, on:

  • greetings {{RANDOM|Hey|Hi}}
  • connectors {{RANDOM|saw|noticed}}
  • a mid-body verb {{RANDOM|help|work with}}
  • the CTA, whole sentence: {{RANDOM|Worth a look?|Is that on your radar?|Useful?}}
  • an opt-out line, whole sentence

Subjects get at least 1 block; follow-ups get at least 2.

Never spin: variables, {{accountSignature}}, numbers and stats, customer or brand names, proof, prices, technical terms. Spinning a case-study name is a fabrication.

The golden rule: every combination is a grammatical sentence. Adjacent blocks multiply, so:

  • BAD: {{RANDOM|let me know if|would}} {{name}} {{RANDOM|would be better to ask|be a better person}} produces "would Sam would be better to ask".
  • GOOD: spin the whole clause: {{RANDOM|let me know if {{name}} would be better to ask.|would {{name}} be the better person to ask?|should I ask {{name}} instead?}}
  • Spun options must match the register. Don't pair "Worth a shot?" with "Would you be amenable to a trial?"
  • Each option must keep the email's single question. Don't spin a statement against a question.

lint_copy.py renders combinations and flags doubled words, double spaces, " ." / " ?", mismatched question counts across combinations, and stray {/}.

references/conferences.md

Conference Outreach

Conferences are the warmest cold lane we run. The message is "we'll both be there", which is true and checkable, not a pitch. They matter most for vertical buyers who don't live on LinkedIn or answer cold email (surgeons, field ops, clinic and job-site leaders), who all show up to their industry's annual meeting.


1. The flywheel: pre, during, post

PhaseChannelsTiming
Preemail → LinkedIn request → call or textemail 2-3 weeks out; LinkedIn 1-2 weeks out; text or call the week of
Duringbooth, floor walk on a hit list, booked coffees, side events10am-3pm floor: one meeting every 15-20 min = 12-20 a day
Postemail + LinkedIn follow-up referencing what you talked about, then BDR calls on non-repliesthe Monday after; done within the week

The metric is cost per qualified meeting. $20K all-in for 40 real conversations = $500 per meeting, which beats most channels when CAC runs $5-10K+. Conferences fail when teams skip the pre-work, walk without a hit list, and don't follow up. A booth helps but isn't required: a general admission pass plus a hit list plus booked coffees works.

2. Building the list

  1. Scrape the event's own site first: exhibitors, speakers, sponsors. It's free, and it's the highest-precision source because it isn't an inference. Buy the attendee list if one is sold ($500-2K is almost always worth it).
  2. Search LinkedIn posts mentioning the event. People announce they're going. Treat these as an inference, not a fact: on one Texas home-care event, 597 posts → 190 kept → 25 accounts matched, and most top matches rested on one common word in a generic agency name.
  3. Enrich and score accounts exactly as you would any account. Sort the hit list by score, with the reason visible ("25+ field reps, 15 managers, PE-acquired last year").
  4. Find 2-3 buyers per top account. For registrants, the roster is the person.
  5. Exhibitors cut both ways. A vendor exhibitor is a competitor to position against and is never emailed as a prospect. A provider exhibitor is an account with budget.

The three questions that decide a run

  1. Did attendees consent to sharing their details? If the roster has a consent column, it is the only thing deciding who can be emailed, and a blank means no. The one consented roster (6 human replies from 67 people reached) far out-replied the others (0-2 replies each).
  2. Does the roster carry email addresses? If not, run every free gate before paying to find an address, so you never buy an address for a vendor, a clinician or an existing customer.
  3. Who is a buyer at this kind of organization? Personas invert by vertical: a nurse doesn't pick the billing system at an IDD provider, but the Administrator and Director of Nursing are the licensed leadership at a Texas home-health agency. Personas are event-scoped.

Gates (all fail closed)

  • Customers come from the live CRM, never a cached column. One gate read an all-false column and reported "no customers on this roster".
  • Suppression is alias-expanded (acmeclinic.org and acme-clinic.org are the same customer).
  • Reply gate: anyone who replied to any campaign is out. Do-not-contact list, cooldowns.
  • Check whether you're on your own roster (one roster listed the client itself and three competitors).
  • The usual per-account cap is normally off for a one-week event (everyone at the account knows they're going). Address-level dedup still applies.

3. Copy rules for this lane

  • Anchor steps to the event dates, not a cadence. Three emails: about a week out, the first morning of the event, and the Monday after. A normal 3-day follow-up lands mid-conference, when nobody reads email.
  • Instantly delays count from each lead's start, not the calendar. A late-enrolled lead gets "see you there" after the event. Enroll everyone on the same day, or schedule the steps, and verify the dates before launch.
  • Never claim a detail you can't verify per recipient. No booth number you don't have (keep it a token: {{boothLine}} with a safe fallback), no "I saw your post", no "great meeting you" unless you met. A conference list is where an unverifiable detail gets read by the person standing next to the one it was true of.
  • Company voice vs person voice. "We're exhibiting at booth 1412" is a fact about the company and stays true whoever travels. "I'll be there" is only safe if that person is going. A LinkedIn DM is always signed by a person.
  • Attending vs exhibiting changes every ask. With no booth there's no "come by", and no booth token at all. The ask becomes a hallway conversation or a call.
  • Say where the address came from when it's a shared roster: "your name is on the registrant list the association circulates, which is where this address came from." Transparency is the whole asset of this lane.
  • Every merge token carries a fallback ({{firstName | there}}, {{companyName | your agency}}) so a blank is structurally impossible.
  • The ask must not grow between steps (15 minutes in step 1 can't become 30 in step 3).
  • Single variant. 60 people across three steps can't resolve a copy test.
  • Post-event copy references something tangible from the conversation (from the Granola notes), never generic "great to connect".
  • Both campaigns are created switched off. A person reads the event-specific copy last and launches it.

Templates

Pre-event (about a week out). Subject: {{RANDOM|[event] next week|see you at [event]}}

{{RANDOM|Hey|Hi}} {{firstName}}, {{RANDOM|looks like|saw}} {{companyName}} is headed to [event] next week. We'll be there too {{boothLine}}.

[One line: the problem we help [persona]s with, in their words.]

{{RANDOM|Worth grabbing 15 minutes on the floor?|Open to a quick coffee while we're both there?}}

First morning (same thread, blank subject):

{{firstName}}, we're {{RANDOM|set up|here}} {{boothLine}} through [day]. If a coffee works better than the floor, {{RANDOM|just reply with a time|send me a time}}.

The Monday after (new subject: after [event]). Met them:

{{firstName}}, {{RANDOM|good|great}} talking about [specific thing from notes] at [event]. [The next step we agreed, in one line.]

{{RANDOM|Still good for [day]?|Does [day] still work?}}

Didn't meet:

{{firstName}}, sorry we missed each other at [event]. [One line of what people kept asking us about there.]

{{RANDOM|Worth 15 minutes this week instead?|Want the short version over email?}}

Week-of text (needs a mobile number and a reason to expect it to be welcome; this has booked well at trade shows when the list was tight):

hey [name], <your name> here, just got into [city] for [event]. would love to grab a coffee if you're around.

4. During the event

  • Work the hit list in score order, and read the buyer's LinkedIn and firmographics before walking up.
  • Record or take notes (Granola), get contact details, and land a concrete next step.
  • Be memorable: post-event outreach only works if they remember you.
  • Each night, have Claude ingest the notes: update the CRM and draft the follow-ups.

5. After the event: retire the campaign

Retire the conference campaign once its last email sends, and release its leads. The copy is false after the event, and in Instantly a lead held by any campaign is blocked from every other one, so a drained conference campaign silently becomes a tombstone for everyone in it. Clear its id from the campaign map.

6. Tags

trigger_type: event, segment: <event-slug>, and the persona. Track meetings per event separately from cold lanes, or the conference's cost per meeting can never be computed.

references/evidence.md

Evidence: Benchmarks

Vendor benchmarks define "reply rate" differently (per contact vs per email, all steps vs step 1), so compare within a source, not across sources. Open rates are inflated by Apple MPP; prefer reply- and meeting-measured findings. Pulled 2026-10-26.

1. Industry benchmarks

Reply rates

MetricValueSource (data period)
Avg reply rate3.43%; top 25% 5.5%; top 10% 10.7%+Instantly 2026 report (2025)
Reply per contactmedian 0.74% (1 in 135); top 25% 1.43%; top 10% 2.63%Smartlead State of Cold Email 2026 (Jan-Jun 2026, 850M+)
Avg reply rate4.5%; top campaigns 2-3 meetings per 100 emailsSaleshandy 2026 (30M)
Positive share of replies~14% (≈0.5% positive reply rate)Something Inc. compilation, 2026
Eric's barspositive reply ≥1% good, ≥2% great; MMF ≥1 reply per 320 templated sendsGEX skills repo; Clay blog

Length

FindingSource
First emails under 50 words: 1.47% reply; 100-149 words need 97 contacts per reply vs 68Smartlead 2026
0-50 words +23% replies; grade 3-7 reading level 1.66x; mobile-optimized +24%Lavender (vendor page)
20-39 words best at 4.5%; gaps between buckets smallHunter (2022-24, 34M)
Elite first touches average under 80 wordsInstantly 2026
70-90 words bestEric, internal review 2025
30-150 words beat ≤30 for meetingsGong

Subject lines

FindingSource
2-4 words: 46% open vs 34-39% at 7-10 wordsBelkins (2024, 5.5M)
Personalized subject: 7% vs 3% replyBelkins (2024)
5-7 words recommendedSaleshandy 2026 (disagrees)

CTAs

FindingSource
Interest CTA ("interested in learning more about X?") ~2x the next best coldGong Labs (2020, 304K)
Specific-time CTA books 15% cold vs 37% in active dealsGong Labs
"Thoughts?" raises replies, cuts meetings 20%; "I never heard back" cuts meetings 14%Gong
ROI claims −15% successGong
A single soft CTA: +78% positive replies vs hard CTAsSaleshandy 2026

Follow-ups

FindingSource
Per-step reply: E1 1.18%, E2 0.73%, E3 0.56%, E4 0.49%, E5 0.37%Smartlead 2026
Replies per 1,000 contacts: 12 (1 step), 25 (3), 33 (5), 40 (7)Smartlead 2026
42% of replies from follow-ups; reply-style E2 +30%Instantly 2026
57% of positive replies from follow-upsSaleshandy 2026
Step 3 = 35.6% of email-sourced meetingsBelkins (2025, 7.5M)
4+ steps triple unsubscribe and spam; complaints 0.5% at E1 → 1.6% at E4Belkins (2024, 16.5M)
Reply share by step in Eric's sequences: ~35 / 30 / 20 / 15%GEX skills repo

Segments and personalization

FindingSource
Campaigns under 200 prospects: 15-20% reply vs 8% at 500-1,000Saleshandy 2026
Generic personalized variables: −6% reply, −26% interestedReply.io
Creative-ideas campaign: 85 contacts per opportunity vs 176 for new-hire triggerEric (Instantly test, secondary)
Slot-defined AI ideas 21/23 usable vs free-form 2/5GEX playbook-creative-ideas

Timing

Instantly: Tue-Wed peak. Smartlead: 7am local peaks; 64% of replies land within 1 hour. Saleshandy: Tue 9-10am local.

references/frameworks.md

Frameworks and Templates

Body templates by situation, in Instantly syntax ({{firstName}}, {{companyName}}, custom {{var}}, spintax {{RANDOM|a|b}}). Templates are shapes, not scripts: rewrite them in the client's voice and run the lint. [brackets] are things you write per campaign. {{vars}} are per-lead.

The skeleton under all of them: their situation → one lever in their words → (proof or mechanism) → one low-effort question.


E1 frameworks

1. Signal 4-move (Kellen Casebeer). Real signal, want a conversation

Hey {{firstName}}, [signal ack: one observable fact, single hedge at most].

Figured you might be [verb] [pain 1], [pain 2], or [pain 3].

[Insight: one active, hedge-free sentence about their world.]

[Binary CTA: two states they might be in?]
  • Name pains in Move 2, not features. Keep the three items about the same length.
  • The insight earns a "yes, exactly". Patterns: "[Transition moments] are when [problem] is easiest to see." "After a [event], the question shifts from [old] to [new]." "[Tool] covers [X]; the hard part is [Y when Z]."
  • The CTA offers two states: "Do you already have a system you love, or are you open to changes as you settle in?"
  • Don't name the product until E3.

Example (Kellen, new hire):

Hey {{firstName}}, congrats on joining {{companyName}}.
Figured you might be getting a read on the field team, CRM habits, or what reps are actually doing day to day.
That first window is when it's easiest to spot what's working and what's already messy.
Do you already have a system you love, or are you open to making changes as you settle in?

2. Observation → lever → proof → ask. Real signal, clear offer

{{firstName}}, [observation about them].

[One sentence: the outcome, in their nouns, with one lever.] [Optional: how, in 6-12 words.]

[Proof: similar company went from X to Y.]   ← only if it matches their problem shape

[Soft question CTA?]

Example (Eric's "after" cut, 52 words):

Sarah, saw you sell to sales leaders.
Noticed John is a BDR on the team. Have you figured out how he could use better data and GPT-4 for prospecting, or still manual?
Most teams save 10 min per prospect and 3x volume without adding headcount.
Worth a look?

3. "So you can focus on" (Eric). Save-time lever, AI context varies by company

{{firstName}}, noticed {{companyName}} [situation].

[What we do, one line.]

So you can focus on {{ai_company_mission}} instead of [the chore].

Worth a look?

4. Billboard. No signal, homogeneous niche list

The whole offer goes in the subject and first line, and the right readers self-select.

Subject: [the offer or the pain, plainly]

{{firstName}}, [the question that names the pain, or the offer, in one line]?

[One line: what we do and the lever.] [One line: proof or mechanism.]

[Soft CTA?]

Example (Eric): subject "Tax bill" → "How do you know your current accountant is getting you as much back as legally possible?"

5. Search frame (Kellen). No signal, finding the people with the pain

Hey {{firstName}}, I'm trying to find the [team type] that [has X figured out / is dealing with X].

Figured {{companyName}} might be [pain 1], [pain 2], or [pain 3].

[Insight.]

[Binary CTA?]

6. Creative ideas (Eric). Broad list, varied businesses, AI from their site

{{firstName}}, I was on your site and had a few ideas for {{companyName}}.

• {{idea_1}}
• {{idea_2}}
• {{idea_3}}

Of course, I wrote this without knowing your current bottlenecks.

[Soft CTA, e.g. "want me to show how we'd run the first one?"]
  • Slot discipline: you define what bullet 1, 2 and 3 are about, fixed for every lead. Each idea must use a capability the client actually has (list 3-5 in the prompt). The model only fills in the company detail.
  • Each bullet is 8-22 words, lowercase start, no trailing period, no competitor, $, headcount or named customer. Any empty bullet excludes the row.
  • Hand-write 3 complete bullet sets for 3 real companies before any model call.
  • Measured: 85 contacts per opportunity vs 176 for a new-hire trigger (Eric, Instantly test).

7. Lookalike. You have a customer that looks like them

{{firstName}}, [similar company / "a [type] firm like yours"] had [problem in their words].

[What changed, with the number and timeframe.]

Given what {{companyName}} does, figured it might be relevant. [Soft CTA?]

8. New leader (< 90 days in seat)

{{firstName}}, congrats on the [role] seat at {{companyName}}.

Most new [role]s I talk to are looking at [priority 1] or [priority 2] in the first quarter.

[Insight about the window.]

Is [specific thing] on your list, or already handled?

9. Referral (Aaron Ross, Cold Calling 2.0). Unsure who owns it

Subject: right person?

{{firstName}}, I'm trying to find whoever owns [function] at {{companyName}}.

[One line: what we do, the lever.]

Is that you, or is there someone better to ask?

10. Poke the bear (Josh Braun, 4T)

{{firstName}}, [Truth: a relevant fact about them].

[Think: a neutral question exposing a gap they may not have considered]?

[Third-party: teams like X handle it by ...].

[Talk: "worth a look?" / "feel free to say no".]

11. Hook → Relate → Bridge → Ask (Jeb Blount)

A hook that grabs attention, a line that relates (I get your world), a bridge (what's in it for them), and an ask. Use a targeted bridge (common to the cohort) for scale and a strategic bridge (built for one account) for tier 1.

12. Permissionless value / PVP (Jordan Crawford). We hold data they can't easily get

Email 1 is the deliverable: no offer to produce it, no call needed to get it.

Subject: [the finding, 2-4 words]

{{firstName}}, [what we looked at, for them specifically].

[The finding: 1-2 sentences, concrete, from data only we combined.] [Why it matters, in their lever.]

[Optional: "the full list / photo / breakdown is below" or attached-as-text.]

[Soft question: "want the rest?" / "useful, or already on it?"]
  • Gate test: could you write the value sentence without reading their file? Then it fails.
  • Customer test: a real customer would call it "really valuable to me".
  • If the number is too small to matter to this person, send it up the chain (portfolio-level to the PE firm).
  • Every fact comes from a stored source with a URL; nothing is model-asserted.
  • PVPs can raise replies more than meetings (Abraham), so grade them on meetings.

13. 4-sentence (30 Minutes to President's Club). Clean default for persona-relevance lists

{{firstName}}, [reason: what people in your seat are dealing with right now].
[Problem: because of that, X is top of mind / getting harder.]
[Solution: we help [similar teams] do Y, which means Z.]
[Interest CTA: is this on your radar at all?]

14. POV (Kyle Coleman). Exec and tier-1 accounts with a strong signal

{{firstName}}, [signal].
[Interpretation: what that signal means for them, an operational or strategic consequence.]
[Implication: the thing that gets hard next, said plainly.]
[Low-pressure invite: happy to share what's working for teams making that shift, if useful.]

One strong POV can drive a 5-touch cascade: the insight → a second implication → proof plus a story → a low-pressure invite → a graceful exit.


Follow-ups

E2: same thread, blank subject, 25-50 words. One new fact or a disarm

{{firstName}}, [one new fact about them or their market, or a second lever in one line].

[Question?]
  • Disarming (Kellen): "Was this a misfire on the [thing] we're [doing]?"
  • New context (Eric): "from my experience, most [role]s are focused on [quick-win category]. [Problem in one sentence.] Is [specific problem] on your radar?"
  • Findings (Eric):
    {{firstName}}, here's what stood out about {{companyName}}:
    • [fact 1]  • [fact 2]  • [fact 3]
    [What we do, one line.] Worth exploring?
    

E3: new thread, new subject, 40-80 words. New lever, proof, lower-commitment offer

Subject: [customer type] [result]  /  [pain, plainly]

{{firstName}}, [similar company] was [bad state]. We [what we did], and [metric in timeframe].

[Product in one plain sentence, if not yet named.]

[Lower-commitment offer as a question: "want the 2-minute video?", "should I send the list?"]

Or the inherited-problem version (Eric): "when you took over at {{companyName}}, did you inherit [specific problem]? If so, we've been [doing X] since [year]. Worth exploring?"

E4: same thread, 20-40 words. Exit with a redirect or a resource

  • Redirect: "{{firstName}}, if [area] isn't yours, who owns it at {{companyName}}? Happy to reach out to them instead."
  • Resource: "{{firstName}}, if the timing's off, I have a short [guide/list] on [topic] that might still help with [benefit]. Want it?"
  • Value bomb (Eric, when the offer can be shown): pull 3 real examples of the output for them and put them in the email. "Want to see how I did this?"

Example: a full 4-step sequence

The client is fictional: a tool that logs field reps' visits from a voice note. The lever rotates from save time (E1) to reduce risk (E3).

E1  subject: {{RANDOM|field visits|field rep visits}}
{{RANDOM|Hey|Hi}} {{firstName}}, {{RANDOM|saw|noticed}} {{companyName}} is hiring 4 field reps in Texas.

Figured you might be chasing visit notes, CRM updates, or what reps actually said on site.

Reps always have the activity. The logging is what slips once the team grows.

{{RANDOM|Already solved, or still a Friday cleanup?|Is that handled, or still manual?}}

E2  (blank subject)
{{firstName}}, {{RANDOM|most teams we see|the teams we work with}} lose about a third of visit notes in the first month a new rep is on the road.

{{RANDOM|Does that match what you see?|Sound familiar?}}

E3  subject: {{RANDOM|missed visits|2,000 visits}}
{{firstName}}, Acme {{RANDOM|was missing|used to lose}} 2,000 logged visits a year. Reps now {{RANDOM|leave|record}} a 20-second voice note and the CRM fills itself.

{{RANDOM|Want the 2-minute video?|Should I send a quick video?}}

E4  (blank subject)
{{firstName}}, if field reporting isn't yours, {{RANDOM|who owns it|who should I ask}} at {{companyName}}? {{RANDOM|Happy to reach out to them instead.|I'll take it to them instead.}}
references/lint_copy.py

#!/usr/bin/env python3 """Lint a cold email sequence against the cold-email-sequence skill's rules.

Usage: python3 lint_copy.py sequence.json # Instantly campaign / {"steps": [...]} / [steps] python3 lint_copy.py draft.txt # text blocks, see below python3 lint_copy.py draft.txt --renders 50

Text format: one block per variant, headed "=== E<step> [variant label]". An optional first line "subject: ..." sets the subject; blank or missing = threaded reply.

=== E1 A
subject: field visits
{{RANDOM|Hey|Hi}} {{firstName}}, ...
=== E2
{{firstName}}, ...

Every spintax combination is rendered (sampled above --renders) and checked, including P.S. lines (one at most, ≤20 words, no grading or job tie-ins). Exit code 1 if any ERROR. """ import argparse import html import itertools import json import random import re import sys from pathlib import Path

WORDS = json.loads((Path(file).resolve().parent.parent / "references" / "spam_words.json").read_text())

SAMPLE_VARS = {"firstname": "Alex", "first_name": "Alex", "companyname": "Acme", "company_name": "Acme", "company": "Acme"} SKIP_VARS = {"accountsignature", "sendingaccountfirstname", "signature"} YOU = re.compile(r"\b(you|your|you're|yours|you've|you'll)\b", re.I) ME = re.compile(r"\b(i|i'm|i've|i'll|we|we're|we've|our|us|my|me)\b", re.I) PS_LINE = re.compile(r"(?im)^\s*p.?\s?s.?[\s:,-]") GRADING = re.compile(r"\b(impressive|accomplished|talented|great background|bet that|shaped how|honed|instincts|so you know)\b", re.I) LINK = re.compile(r"(https?://|www.|\b[a-z0-9-]+.(com|io|ai|co|net|org)/)", re.I)

---------- parsing ----------

def html_to_text(s): s = re.sub(r"(?i)<br\s*/?>", "\n", s or "") s = re.sub(r"(?i)</(div|p)>", "\n", s) s = re.sub(r"<[^>]+>", "", s) s = html.unescape(s) return re.sub(r"\n{3,}", "\n\n", s).strip()

def load(path): p = Path(path) raw = p.read_text() if p.suffix == ".json": d = json.loads(raw) if isinstance(d, dict) and "sequences" in d: d = d["sequences"][0] steps = d["steps"] if isinstance(d, dict) else d out = [] for i, st in enumerate(steps): vs = st.get("variants") or [st] out.append({"n": i + 1, "delay": st.get("delay"), "variants": [{"label": chr(65 + j), "subject": v.get("subject") or "", "body": html_to_text(v.get("body", ""))} for j, v in enumerate(vs)]}) return out steps = {} for block in re.split(r"(?m)^===\s*", raw)[1:]: head, _, rest = block.partition("\n") m = re.match(r"E?(\d+)\s*(.*)", head.strip(), re.I) if not m: continue n, label = int(m.group(1)), (m.group(2).strip() or "A") subject = "" lines = rest.strip("\n").split("\n") if lines and lines[0].lower().startswith("subject:"): subject = lines[0].split(":", 1)[1].strip() lines = lines[1:] steps.setdefault(n, {"n": n, "delay": None, "variants": []})["variants"].append( {"label": label, "subject": subject, "body": "\n".join(lines).strip()}) return [steps[k] for k in sorted(steps)]

def parse_spintax(s): """Split into a list of literal strings and option-lists for each {{RANDOM|...}} block.""" parts, i, errs = [], 0, [] while True: j = s.find("{{RANDOM", i) if j < 0: parts.append(s[i:]) return parts, errs parts.append(s[i:j]) k, depth = j + 2, 1 while k < len(s) and depth: if s.startswith("{{", k): depth, k = depth + 1, k + 2 elif s.startswith("}}", k): depth, k = depth - 1, k + 2 else: k += 1 if depth: errs.append("unclosed {{RANDOM block") parts.append(s[j:]) return parts, errs inner = s[j + 2:k - 2] head, _, body = inner.partition("|") if head.strip() != "RANDOM": errs.append(f"malformed block: {{{{{inner[:40]}}}}}") if head != "RANDOM" or re.search(r"\s|||\s", inner): errs.append("spaces around | in {{RANDOM}} (house style: none)") opts, d, cur = [], 0, "" for ch_i, ch in enumerate(body): if body.startswith("{{", ch_i): d += 1 if body.startswith("}}", ch_i): d -= 1 if ch == "|" and d == 0: opts.append(cur) cur = "" else: cur += ch opts.append(cur) parts.append(opts) i = k

def renders(s, cap, rng): parts, _ = parse_spintax(s) blocks = [p for p in parts if isinstance(p, list)] total = 1 for b in blocks: total *= len(b) combos = (itertools.product(*blocks) if total <= cap else (tuple(rng.choice(b) for b in blocks) for _ in range(cap))) out = [] for combo in combos: it = iter(combo) out.append("".join(p if isinstance(p, str) else next(it) for p in parts)) return out or [s], len(blocks), total

VAR = re.compile(r"{{\s*([^{}|]+?)\s*(?:|\s*([^{}]?)\s)?}}")

def fill_vars(s): """Variables -> sample values; {{var | fallback}} renders its fallback (worst case: lead field empty).""" def rep(m): name, fb = m.group(1).strip(), m.group(2) if name.lower() in SKIP_VARS: return "" if fb is not None: return fb return SAMPLE_VARS.get(name.lower(), f"<{name}>") return VAR.sub(rep, s).strip()

---------- metrics ----------

def words(s): return re.findall(r"[A-Za-z0-9<>'$%.,/-]+", s)

def syllables(w): w = re.sub(r"[^a-z]", "", w.lower()) if not w: return 0 n = len(re.findall(r"[aeiouy]+", w)) if w.endswith("e") and not w.endswith("le") and n > 1: n -= 1 return max(1, n)

def fk_grade(s): ws = [w for w in re.findall(r"[A-Za-z']+", s)] sents = max(1, len(re.findall(r"[.?!]+|\n\n", s))) if not ws: return 0.0 syl = sum(syllables(w) for w in ws) return 0.39 * len(ws) / sents + 11.8 * syl / len(ws) - 15.59

def has_phrase(text, phrase): t = text.lower() if re.match(r"^[\w' -]+$", phrase): return re.search(r"(?<![\w'])" + re.escape(phrase) + r"(?![\w'])", t) is not None return phrase in t

---------- lint ----------

def lint(steps, cap): rng = random.Random(7) findings, variables = [], set()

def add(level, where, msg):
    findings.append((level, where, msg))

if steps and steps[0].get("delay") == 0:
    add("ERROR", "E1", "step 1 delay is 0: email 2 sends ~20 min after email 1 (delay is the wait AFTER the step)")

for st in steps:
    n = st["n"]
    cold = n == 1 or any(v["subject"].strip() for v in st["variants"])
    for v in st["variants"]:
        w = f"E{n}.{v['label']}"
        subj, body = v["subject"].strip(), v["body"]
        for m in VAR.finditer(subj + body):
            if m.group(1).strip() != "RANDOM":
                variables.add(m.group(1).strip() + (" (has fallback)" if m.group(2) is not None else ""))

        # raw-syntax checks
        for label, txt in (("subject", subj), ("body", body)):
            stripped = re.sub(r"\{\{.*?\}\}", "", txt, flags=re.S)
            if re.search(r"\{[^{}]*\|[^{}]*\}", stripped):
                add("ERROR", w, f"{label}: single-brace {{a|b}} spintax is Smartlead syntax; Instantly sends it literally")
            if txt.count("{{") != txt.count("}}"):
                add("ERROR", w, f"{label}: unbalanced {{{{ }}}}")
            for e in set(parse_spintax(txt)[1]):
                add("WARN" if "spaces" in e else "ERROR", w, f"{label}: {e}")
            if re.search(r"\[[^\]]{2,}\]", txt):
                add("ERROR", w, f"{label}: unfilled template bracket {re.search(r'\[[^\]]{2,}\]', txt).group(0)}")

        # subject
        if n == 1 and not subj:
            add("ERROR", w, "email 1 needs a subject")
        if subj:
            sub_rs, sub_blocks, _ = renders(subj, cap, rng)
            sub_msgs = set()
            for r in sub_rs:
                s = fill_vars(r)
                nw = len(s.split())
                if len(s) > 50:
                    sub_msgs.add(("ERROR", f"subject {len(s)} chars (>50): {s!r}"))
                elif nw > 4:
                    sub_msgs.add(("WARN", f"subject {nw} words (aim 2-4): {s!r}"))
                if "!" in s:
                    sub_msgs.add(("ERROR", f"exclamation in subject: {s!r}"))
                for b in WORDS["bad_subjects"]:
                    if has_phrase(s, b):
                        sub_msgs.add(("ERROR", f"subject uses banned {b!r}"))
            for lvl, msg in sorted(sub_msgs):
                add(lvl, w, msg)
            if sub_blocks == 0:
                add("WARN", w, "subject has no {{RANDOM}} block (minimum: 1)")

        # body renders
        rs, nblocks, total = renders(body, cap, rng)
        min_blocks = 3 if cold else 2
        if nblocks < min_blocks:
            add("WARN", w, f"{nblocks} spintax blocks (minimum {min_blocks} for {'a cold open' if cold else 'a follow-up'})")
        seen = set()

        def once(level, msg):
            if msg not in seen:
                seen.add(msg)
                add(level, w, msg)

        wcs, qcounts = [], set()
        for r in rs:
            t = fill_vars(r)
            low = t.lower()
            wc = len(words(t))
            wcs.append(wc)
            q = t.count("?")
            qcounts.add(q)
            if re.search(r"\b(\w+)\s+\1\b", t, re.I) and not re.search(r"\b(that that|had had)\b", low):
                once("ERROR", f"doubled word in a render: {re.search(r'\b(\w+)\s+\1\b', t, re.I).group(0)!r}")
            if re.search(r"\s[,.?]", t):
                once("ERROR", f"space before punctuation in a render (blank variable or bad spin): {t[max(0, re.search(r'\s[,.?]', t).start() - 25):re.search(r'\s[,.?]', t).end() + 5]!r}")
            if re.search(r"[^\n ]  +", t):
                once("WARN", "double space in a render")
            if re.search(r"[{}|]", t):
                once("ERROR", "stray { } or | after rendering")
            if q > 1:
                once("ERROR" if cold else "WARN", f"{q} questions in a render; exactly one question, the CTA")
            for ph in WORDS["hard"]:
                if has_phrase(low, ph):
                    once("ERROR", f"spam phrase: {ph!r}")
            for ph in WORDS["agency_vocab"]:
                if has_phrase(low, ph):
                    once("ERROR", f"agency vocabulary: {ph!r}")
            for ph in WORDS["openers_and_filler"]:
                if has_phrase(low, ph):
                    once("ERROR", f"filler / prefacing / follow-up reference: {ph!r}")
            for ph in WORDS["calendar_cta"]:
                if has_phrase(low, ph):
                    once("ERROR" if n == 1 else "WARN", f"calendar/time ask {ph!r}" + (" in email 1" if n == 1 else ""))
            ps_lines = [ln for ln in t.split("\n") if PS_LINE.match(ln)]
            if len(ps_lines) > 1:
                once("ERROR", "more than one P.S.")
            for ln in ps_lines:
                if len(ln.split()) > 21:
                    once("WARN", f"P.S. {len(ln.split()) - 1} words (aim ≤20)")
                if GRADING.search(ln):
                    once("WARN", f"P.S. grades the person or ties the fact to their job: {GRADING.search(ln).group(0)!r}")
            for ph in WORDS["soft"]:
                if has_phrase(low, ph):
                    once("WARN", f"soft spam word: {ph!r}")
        if 0 in qcounts:
            once("WARN", "a render has no question; is there a CTA?")
        if len(qcounts) > 1:
            once("WARN", f"question count differs across spins {sorted(qcounts)}")

        first = fill_vars(rs[0])
        if re.search(r"[ - -]", subj + body):
            add("ERROR", w, "em/en dash")
        if re.search(r"\s-\s", first):
            add("WARN", w, "' - ' used as a dash; use a period or comma")
        if "!" in body:
            add("ERROR", w, "exclamation mark")
        links = LINK.findall(first)
        if links and n == 1:
            add("ERROR", w, "link in email 1")
        elif len(links) > 1:
            add("ERROR", w, f"{len(links)} links; max one, own domain, from email 2")

        lo, hi = min(wcs), max(wcs)
        span = f"{lo}" if lo == hi else f"{lo}-{hi}"
        if cold:
            if hi > 125:
                add("ERROR", w, f"{span} words (>125)")
            elif hi > 90:
                add("WARN", w, f"{span} words (aim 50-90)")
            elif lo < 25:
                add("WARN", w, f"{span} words (thin for a cold open)")
        else:
            if hi > 80:
                add("ERROR", w, f"{span} words (follow-up >80)")
            elif hi > 50:
                add("WARN", w, f"{span} words (follow-ups aim under 50)")
        g = fk_grade(first)
        if g > 8:
            add("WARN", w, f"reading grade {g:.1f} (aim ≤7)")
        you, me = len(YOU.findall(first)), len(ME.findall(first))
        if me > you:
            add("WARN", w, f"more I/we ({me}) than you ({you}); write about them")
        add("INFO", w, f"{span} words, grade {g:.1f}, {nblocks} spin blocks ({total} combos), you:I {you}:{me}")
return findings, variables

def main(): ap = argparse.ArgumentParser(description=doc, formatter_class=argparse.RawDescriptionHelpFormatter) ap.add_argument("path") ap.add_argument("--renders", type=int, default=200, help="max combinations rendered per field") ap.add_argument("--quiet", action="store_true", help="hide INFO lines") a = ap.parse_args() steps = load(a.path) if not steps: sys.exit("no steps found (text files need '=== E1' headers)") findings, variables = lint(steps, a.renders) order = {"ERROR": 0, "WARN": 1, "INFO": 2} for lvl, where, msg in sorted(findings, key=lambda f: (f[1], order[f[0]])): if a.quiet and lvl == "INFO": continue print(f"{lvl:5} {where:7} {msg}") errs = sum(f[0] == "ERROR" for f in findings) warns = sum(f[0] == "WARN" for f in findings) print(f"\n{len(steps)} steps, {errs} errors, {warns} warnings") if variables: print("variables used (preflight every one non-empty on every lead):", ", ".join(sorted(v for v in variables if v.lower() not in SKIP_VARS))) sys.exit(1 if errs else 0)

if name == "main": main()

references/offers.md

Offers and Lead Magnets

What the prospect gets for replying. Adapted from Eric Nowoslawski's lead-magnet-brainstorm (MIT) plus Spychalski and Braun.

"A concrete free offer outperforms 'book a call' by 3-10x" (Eric). A meeting is what you want; the offer is what they get.

Intake (answer before brainstorming)

  1. What does the client sell, in one sentence a buyer would recognise?
  2. What was the #1 problem the best customer had before buying? This is the north star, and its lever (make money, save time or money, reduce risk) is E1's lever.
  3. What could we do for a prospect in under 30 minutes that they'd pay $100 for? Push back on "nothing". An SEO shop audits a page; a copywriter rewrites a subject line; a dev shop reviews one function; a data shop pulls 20 real leads.
  4. Any legal, regulatory or client limits on what we can promise?
  5. What would make them not reply? (Too busy, burned before, already have a vendor, sounds like a pitch.) The offer should answer the biggest one (Eric).

The 10 archetypes

ArchetypeExampleCTA
AFree audit / diagnostic"a 5-minute audit of your [thing]""want me to run it?"
BData / research"we looked at 500 [type] firms; here's what the top 10% do""want the summary?"
CCompetitive intel"I pulled who engaged with your 3 biggest competitors' last 10 posts""want the list?"
DTemplate / checklist"the 12-point checklist we run before every launch""want me to send it?"
EIntro / connection"I know 3 [role]s who solved exactly this" (never fake it)"want the intro?"
FQuick-win work"I'll write 3 subject lines for your ICP""reply with your ICP and I'll send them"
GSpecific-to-them analysis2-3 sentences of real observation (high-ACV)"happy to go deeper if useful"
HTool / free account"I can spin you up an account""want access?"
IWorking session"15 min where I walk your checkout and flag 3 friction points""worth 15 min?" (E3+, never E1)
JBenchmark"you rank #X for [term]; the median in your space is #Y""want the full comparison?"

Plus two that lower the risk of the first step:

  • Free test / pilot: the first small piece of work, free (GEX's own front-end offer is a free test campaign). Ask: "What can they accomplish in 14 days that would make them not want to stop?"
  • Pay on result: charge only after the outcome ("we remove the negative reviews; you pay only after removal" produced 1 positive reply per 70 emails).

Scoring

Rate each idea 1-5 on four criteria:

Criterion5 means
Cheap to deliver at scaleautomated, or 5 minutes of manual work
Genuinely valuablethey'd pay $100+ for it
Shows competencedelivering it proves we can do the paid work
Uniquecompetitors aren't all offering it

15/20 or more: propose it. Under 15: rework it or drop it. Recommend the top 2-3 by lowest delivery friction, fit with intake question 2, and novelty. If every competitor does free audits, pick something else.

Rules

  • Never gate it behind a form. Send it inline or as a direct link once they reply.
  • The prospect's maximum effort is a one-line reply or 1-2 data points ("reply with your ICP").
  • Don't promise what can't be delivered at the volume the campaign sends.
  • "Free consultation" isn't an offer. "15 min where I [specific action] for you" is.
  • The offer must use the client's real capabilities. Write the "what we do NOT do" line before brainstorming.
  • If a campaign underperforms, change what they get, not the wording (Eric).

Output format

For each idea: what it is / what it takes to deliver / example CTA / score (x/20).

references/playbook.md

The Cold Email Playbook

The canonical reference behind the cold-email-sequence skill. Each rule names its source, and where experts disagree, §14 records the call we made and why. Researched 2026-10-26.


1. Sources

WhoWhat to take from themWhere
Eric Nowoslawski (Growth Engine X; 1.5-8M emails a month)Offer before copy; lead-magnet rubric; campaign-idea generation (broad → niche); creative-ideas campaign; slot-defined AI lines; message-market-fit bars; test like adsgithub.com/growthenginenowoslawski/coldoutboundskills (MIT); Clay blog "validate cold outbound offers by finding message-market fit"; GTM Engineer podcast
Kellen Casebeer (The Deal Lab, Smartlead partner)4-move E1 (signal → three pains → insight → binary CTA); proof held to E3; disarming E2; segment by insight, trigger and signalSmartlead talks "Cold Email Like a Pro" (2025) and "Creative Segmentation" (2025); our synced kellen-copy-generator skill
Josh BraunPoke the Bear; detachment ("sort, don't sell"); 4T: Truth, Think, Third-party credibility, Talkjoshbraun.com
Will Allred / LavenderShort, mobile-first, grade 3-7 reading level, about them, context firstLavender Cold Email Benchmark Report (231,818 emails, to Feb 2026)
Gong LabsInterest CTA beats time ask cold; ROI claims −15%; "Thoughts?" −20% meetingsGong Labs CTA study (304,174 emails)
Becc Holland (Flip the Script)Relevance vs personalization; premise → hook → CTA; one premise reused across the cadence
Jason Bay (Outbound Squad)REPLY: Results, Empathy, Personalization, Laser-focus, You. "Reps have an opening problem, not a closing problem"
Justin Michael (Tech-Powered Sales)The JM "spear": 1-3 sentences, pain or fear, a hinted fix, a binary close
Aaron Ross (Predictable Revenue)Cold Calling 2.0 referral email: find the right person, plain text
Jeb Blount (Fanatical Prospecting)Hook → Relate → Bridge → Ask; targeted vs strategic bridges
Alex BermanNeutral subjects; open on something they already believe
Patrick Spychalski (The Kiln)Offer beats personalization; work backwards from the value prop to data that quantifies it
Jordan Crawford (Blueprint)PQS (pain-qualified segments from detectable signals); PVP (the email is the value)voices-and-styles.md
30MPC (Farrokh & Cegelski), Sam McKenna, Kyle Coleman, Nick Abraham, Jeremy & Jack4-sentence email; recipient-only subjects and objection pre-empts; POV-led emails; offer-first at 1.5M a monthvoices-and-styles.md
BenchmarksInstantly 2026 (2025 data), Smartlead State of Cold Email 2026 (850M+), Belkins 2025-26, Saleshandy 2026, Hunterevidence.md

2. The priority order

list > offer > subject > opener > CTA > timing > length (Eric; Spychalski; every benchmark that slices by segment). Effort and testing follow this order. When a campaign underperforms, go back up the list. Rewording an email aimed at the wrong list with a weak offer is wasted time.

Unit economics first (Eric): cold email pays when the TAM is more than ~100K contacts, LTV is more than ~$10K and the sales cycle is under 6 months. Below that, use smaller, curated lists and more manual research per lead. Judge campaigns by sends per meeting and email-to-deal, not reply rate.


3. The three value levers

Every product sells at least one of these, and every email leads with exactly one:

  1. Make money: revenue, pipeline, customers, deals, price, retention as revenue.
  2. Save time or money: hours, headcount, tools, cost per X, cycle time.
  3. Reduce risk: misses, errors, compliance, churn, bad hires, wasted spend, being caught out.

Eric's version splits "save time" and "save money" and adds "mitigate risk". His copywriting skill only uses the first three. We merge time and money because buyers hear them together, and we keep risk, which is often the strongest lever for regulated or high-stakes buyers.

How to pick:

  • Start from the #1 pain the best customer had before buying (Eric's north star). Its lever is E1's lever.
  • Break the product into component offers and tag each one with a lever (Eric, Clay article). That gives you the rotation for E2-E3.
  • Say it in the prospect's nouns, never the vendor's. "know what each pool noodle costs to make before you price the next run", not "improve margins". Banned as too vague: "grow faster", "increase sales", "boost margins", "improve efficiency", "drive results", "your business".
  • Problem framing over ROI promises. Gong: ROI claims cut success 15%. Put a number in proof ("Acme went from missing 2,000 visits a year to capturing all of them"), not in a promise.

Rotate. If E1's lever got no reply, it didn't resonate. E2 can deepen it with one new fact, but E3 switches lever (Eric).


4. List, signal and relevance

  • Segment by insight, trigger and signal, not demographics (Kellen). The tighter the list, the more the copy can name the filter itself ("you run a cost seg practice with 3-10 people").
  • Broad → focused → niche (Eric). A broad list (base filters only) needs strong AI relevance. A focused list adds one filter. A niche list stacks 3-4 filters and can run near-static copy. Generate 15-25 campaign ideas across all three levels before picking one.
  • Three campaigns worth always having (Eric): Creative Ideas (AI bullets from their site), New Leader (in seat under 90 days), Lookalike (modeled on the best case study). Plus one no-AI campaign: short, snappy, a strong offer and tight targeting.
  • The 10-minute test: what would a good rep look up in 10 minutes before writing? Automate that research, and that's the campaign.
  • Relevance vs personalization (Becc Holland). Personalization is 1:1 and couldn't be sent to anyone else. Relevance fits a cohort. With no real individual premise, be relevant, not fake-personal. Research once and reuse the premise across the whole sequence.
  • Signals: a public ask or job post > a dated event (new role under 90 days, raise, launch, hiring burst, expansion) > a structural fact > none. A funding index lags 3-4 months, so check the date. "Started a new role" includes internal moves (28%), so never write "you hired". Signals aren't a silver bullet (Eric). A signal with a weak offer still fails.
  • Never invert an undetectable signal. "Has a VP Sales but no GTM engineer" is fine (titles are detectable). "Doesn't use an enrichment tool" is not (stack detection misses).
  • Avoid: scraped review complaints from G2/Capterra, private revenue guesses, and existing freemium users (that's nurture, not cold).

5. Offers

Full method: offers.md. The essentials:

  • A concrete free offer beats "book a call" by 3-10x (Eric). A meeting is an ask, not an offer.
  • Ask: what could you do for this prospect in under 30 minutes that they'd pay $100 for?
  • Score 1-5 each on: cheap to deliver, valuable enough to pay for, shows competence, unique vs competitors. Propose at 15/20 or more.
  • Never gate it behind a form. The prospect's maximum effort is a one-line reply.
  • Lower the risk of the first step: a free test, a sample, an audit, or pay only on result.
  • Name why they wouldn't reply, and answer it in the offer (Eric).
  • If a campaign fails, change what they get, not the wording.

6. Subject lines

  • Length: 2-4 words (Belkins 5.5M: 46% opens at 2-4 words vs 34-39% at 7-10). Saleshandy argues for 5-7 words; §14 records our call.
  • Personalized subjects reply 7% vs 3% (Belkins). That's the only reply-measured subject finding, so use a name, company, role or signal when you have a real one.
  • Three types (Eric):
    • A, intrigue or signal (2-4 words): "question for {{firstName}}", "{{companyName}} field team", "the vp sales req", "title agency marketing".
    • B, whole offer (subject plus preview): "Ever chase renters to pay on time?" plus the first line, so the reader self-selects. Use it when data is thin.
    • C, problem indicator: "looked you up on chatgpt", "review from karen", "starter vs pro".
  • Kellen's house style: 2-3 words, lowercase, no punctuation, named after the signal ("new role", "growing the team").
  • Colleague test: could a coworker or customer have sent this? If not, rewrite it.
  • Banned: "quick question", "curious", "following up", "touching base", "partnership opportunity", a fake "re:"/"fwd:", ALL CAPS, emoji, urgency, and anything promotional.
  • The first 50-100 characters of the body show as preview text. Write the subject and first line as one unit.
  • Open rates are inflated by Apple Mail Privacy Protection, so treat open-rate studies as weak evidence and favor reply-measured findings.

7. Openers

The first line is about them, specific, observable and true. Patterns:

  • Signal ack (Kellen): "saw {{companyName}} is hiring for the field team." Name the real thing. No double hedge: "saw your team is looking at X", not "heard you may be looking at X".
  • Situation recognition (Eric): "noticed you sell to {{ai_customer_type}}." One sentence describing their world.
  • Truth (Braun): a relevant fact. "noticed you're hiring 3 SDRs."
  • Belief (Berman): something the reader already believes is true about their market.
  • Search frame (Kellen, with no signal): "I'm trying to find the [team] that [has X figured out]."
  • Poke the bear (Braun, Eric), as a neutral question that surfaces an unconsidered gap:
    • "Do you already have a reliable way to {{problem}}?"
    • "Have you figured out {{outcome}} without adding headcount, or still manual?"
    • "Totally possible you've solved this. How do you handle {{process}} today?"

Never: "hope this finds you well", "I wanted to reach out", "I came across your profile", "my name is", "I'm reaching out because", observer-fan voice ("I noticed your amazing…"), and prefacing ("quick one", "I'll keep this short", "one more thought"). Never start an AI line with "I noticed".

Gong found "Hope all is well" correlated with +24% meetings. It's correlation on 2020-era data, and every practitioner disagrees, so we ban it (§14).


8. Body, CTA and proof

Body

Pick a framework by situation (templates in frameworks.md). They all share one skeleton:

their situation → the pain or outcome in their words, with one lever → (optional) proof or the specific mechanism → one low-effort question

  • One email, one job. Aim for 50-90 words (Eric's best: 70-90; Smartlead: first emails under 50 words replied best at 1.47%; Lavender: 0-50 words +23%). Go to 125 only when an AI slot earns it. §14 records our call.
  • Reading grade 3-7: Lavender saw 1.66x replies. Short sentences, plain words, contractions everywhere (Kellen).
  • Keep sentences about them to sentences about you at 3:1 (Eric). "You" outnumbers "I/we".
  • Active voice, no hedges ("usually", "might possibly"), no adjectives without data. Keep numbers as digits ("3x", "30 days").
  • Light peer humor is fine ("equipment older than some employees").
  • The three-pass cut (Eric):
    1. Delete fluff: greetings, "I wanted to", hedges (about −20%).
    2. Compress: "We built a platform that can do X" becomes "We do X" (about −15%).
    3. Cut adjectives without data (about −10%).
  • Mobile-first: 2-4 short paragraphs, no paragraph longer than 2 lines on a phone (Lavender +24%).

CTA

  • Exactly one question, and it's the CTA. It must be answerable in 5 words or fewer.
  • Three good forms:
    1. Interest or state (default): "worth a look?", "is that on your radar?", "already solved, or still manual?", "do you have a system you love, or open to changes as you settle in?" (Gong interest CTA ~2x next best; Kellen binary; Braun.)
    2. Value exchange: "want me to send the 3 we'd flag for {{companyName}}?", "should I send the list?" (pairs with an offer).
    3. Confirmation: "is this still the case?", "did I get that right?"
  • Never in E1: a calendar link, a specific time, "15 minutes", "hop on a call", "let me know your thoughts", "thoughts?" (Gong −20% meetings), or two asks.

Proof

  • One customer, one number, framed as what happened: "[similar company] went from X to Y in Z." Third-party credibility over self-claims (Braun). Never a logo list, award or ranking (Holland).
  • Pick proof by problem shape, not industry label. Name 2-3 relevant customers at most, never the list.
  • Placement: in E1 only if it matches the prospect's problem shape exactly; otherwise E3 (Kellen). See §14.
  • Proof must be cleared by the client. Never generalise one client's result to "our clients".

9. Scoring rubric and QA

Rubric (0-100; adapted from Eric's positive-reply scorer)

DimensionPointsFull marks when
Situation recognition25The first line is specific, true and about them; a colleague would recognise their company in it
Value clarity25One lever, in their nouns, concrete; the reader knows what they'd get within 2 seconds
Relevance / personalization20The reason-now is real; AI lines add relevance and would make the email generic if removed
CTA effort15One question, answerable in ≤5 words, no calendar ask
Punchiness1050-90 words, grade ≤7, no hedges, reads aloud in under 20 seconds
Subject52-4 words, specific, passes the colleague test

85 or more: ship. 70-84: one more pass. Under 70: go back to the list or offer, not the words.

QA checklist

  • Inputs written at the top of the spec: cohort, signal, lever, offer, proof cleared.
  • lint_copy.py reports 0 errors; warnings each have a reason.
  • Every claim traces to a cleared source; nothing invented (customers, numbers, mutuals).
  • Every variable is non-empty on every lead (in-flight too), or the row is excluded.
  • Five real leads rendered end to end and read aloud.
  • Edited for AI writing patterns, then re-linted.
  • Would I reply to this? Yes.

10. Sequence and follow-ups

How much follow-ups add:

SourceShare of replies from follow-ups
Instantly42%
Smartlead52% with 3 steps; replies per 1,000 contacts go 12 → 25 → 33 → 40 for 1 / 3 / 5 / 7 steps
Saleshandy57% of positive replies
Belkinsstep 3 alone = 35.6% of email-sourced meetings

Against that, Belkins found 4+ steps more than triples unsubscribe and spam rates (complaints 0.5% at E1 → 1.6% at E4). Default: 4 steps; never more than 5.

What each step does:

  • E1: the strongest signal, the clearest offer, and the best-matched proof if any.
  • E2 (same thread, blank subject): one new fact or angle, written like a reply (Instantly: reply-style E2s +30%). Or Kellen's disarming bump ("was this a misfire on the tool we're using?"). No re-pitch.
  • E3 (new thread, new subject): a new lever and angle. Name the product plainly, give one proof point, and drop to a lower-commitment offer (audit, list, video, resource) (Eric, Kellen). Eric says to consider dropping all AI personalization here.
  • E4 (same thread): exit. Either a redirect ("if this isn't yours, who owns X at {{companyName}}?") or a useful resource. No guilt, no "last chance".

Rules:

  • Every email stands alone. Never reference the previous one: "following up", "bumping", "circling back", "just checking in", "did you see my last", "one more thought", "last note from me".
  • Never imply silence is consent or ends it. Give an explicit easy out: "a quick 'not for us' is enough and I'll stop."
  • Send on weekdays in business hours in the recipient's time zone. Tuesday-Wednesday and early morning lead in vendor data; check your own results.
  • Contact each person about once a quarter at most (Eric). Re-approach with a new angle, never the same sequence.
  • Gaps of 2-4 days between steps (2/2/3/2; step 1's delay is never 0).

11. Personalization and AI at scale

Full method: ai-lines-and-spintax.md; first lines and P.S. lines: ps-and-first-lines.md; triggers: triggers.md; segment routing: segments-and-offers.md. The rules that matter:

  • AI fills slots, never emails. The template, pitch and CTA stay human. In our testing, whole emails from top models scored well with AI judges and a human rejected them as clever but unclear.
  • Use AI context only when the prospect's business changes how the product helps them (Eric). A commodity use case ("vacuums clean floors the same everywhere") or a homogeneous niche list should stay static.
  • Slot discipline: the operator defines what each slot is about. Free-form "three ideas" was 2/5 usable; slot-defined was 21/23 (Eric).
  • Abstain = empty string. An empty slot excludes the row or routes it to a non-AI campaign, never to "there", "N/A" or "your company".
  • The model never establishes a fact. Dates, counts and enums are computed in code; the model only phrases them.
  • Generic merge-field personalization hurts: Reply.io measured −26% interested.

12. Deliverability rules for copy

Deliverability is about 80% infrastructure and 20% content (Eric). The 20%:

  • Plain text. No images, logos, HTML signatures, attachments, open or link tracking.
  • No links in E1. From E2 on, at most one link, to your own domain, written as text.
  • No hard spam phrases (spam_words.json, tier hard). Treat soft words as a judgment call.
  • No ALL CAPS, multiple "!", "$$$", or "free" offers phrased like ads ("100% free", "risk-free").
  • Spintax on every cold open (3-5 blocks) so no two sends are byte-identical. AI lines vary the text too.
  • Sender name is a real person. The signature carries the name, company and physical address where the client requires it; {{accountSignature}} in Instantly.
  • Company names containing spam tokens get shortened ("Calcon Mutual Mortgage" → "Calcon Mutual").
  • Bars: bounce under 2%, spam complaints under 0.3% (Google), and a reply rate of at least 1% per domain after 200 sends.

13. Testing

  • One hypothesis per test. Hypothesis tests run as two separate campaigns (Eric); in-sequence A/B is for polishing, with 2-3 variants at most.
  • Sample size per arm (Eric):
BaselineDetectSends per arm
1%2x~2,300
1%1.5x~7,750
2%2x~1,150
2%1.5x~3,800

Corrected 2026-10-26 from the standard two-proportion formula (α .05, power .8). Eric's repo table (500 / 2,000 / 250 / 1,000) is about 4x too small. Full table, test design, tags, log template and decision rubric: testing.md. Math: references/ab_test.py.

  • Close a test only after every lead finishes the sequence plus 7 days (typically 3-5 weeks). Promote at P(challenger > champion) ≥ 0.90 with ≥10 positives on the winner.
  • Message-market-fit bar (Eric): at least 1 reply per 320 sends for a templated campaign and ~1 per 65 for curated ones. If a campaign is still failing at ~1,000 contacts, change the list or offer. Below the bar, switch to an information-gathering angle (asking their view, sharing expertise) instead of pitching.
  • Positive reply rate = (interested + soft + referral) / sent, excluding OOO and bounces. 1% or more is good; 2% or more is great. A 1% reply rate at 70% positive (0.7%) beats 5% at 10% positive (0.5%).
  • Weekly: a winner at 2x baseline or more gets scaled; a loser under 0.5x baseline gets killed. Pause at more than 0.3% hostile or more than 2% unsubscribe.

14. Where experts disagree, and our call

QuestionPositionsOur call
LengthLavender/Smartlead: under 50 words. Eric: 70-90. Gong: 30-150 for meetings50-90, max 125 only for AI-slot campaigns.
Subject lengthBelkins: 2-4 words. Saleshandy: 5-72-4.
E1 CTAGong/Braun/Kellen: interest or state. Eric/Instantly: a meeting or soft time askInterest/state in E1. A soft-time ask is allowed from E3, never a fixed time.
Proof placementEric: E1. Kellen: E3E3 by default. E1 only when it matches the prospect's problem shape.
GreetingEric's spam checker: no "Hi". Spintax skill and our house style: {{RANDOM|Hey|Hi}}Keep the greeting (house style); spin it
PleasantriesGong: "hope all is well" +24% meetings. Everyone else: cutCut. Correlational, 2020-era, and it reads as filler
Sequence lengthBelkins 2024: 1-3. Smartlead: 3-4. Instantly: 4-74, max 5
Bump styleJMM: "Thoughts?". Gong: −20% meetingsNo bare bumps. E2 adds a fact or disarms
Blank variablesSome Eric playbooks drop the clause with spintax; his README bans thatBanned. Spintax can't gate a blank; exclude or split the row
P.S."Most-read part" folklore (no source); Nowoslawski: attention hacks, sparinglyOptional, one sentence, a human fact or a soft offer; never a second pitch
Lead magnets / PVPEric and Crawford: lead with value. Abraham: magnets raise replies, not always meetingsUse them; grade on meetings, not replies
Spam word listEric bans single words like "sales", "marketing", "new", "now", "problem"Phrases are hard bans; single words are warnings. You can't sell to sales leaders without saying "sales"

15. Handling replies (because the sequence is only half of it)

  • Answer positive replies fast: within 30 minutes during business hours. A 2-minute answer vs a 2-hour answer is a ~5x booking difference, and replies left 24h+ lose about half (Eric).
  • Keep the reply shorter than their message. Offer two specific times plus a link as fallback.
  • Negative: "Got it, appreciate the direct reply. I'll stop reaching out." No argument.
  • Wrong person: thank them and ask who owns it. A referral is a positive reply.
  • Classify only the first reply per lead (positive_interested / positive_soft / positive_referral / neutral_question / negative_notnow / negative_notfit / negative_hostile / unsubscribe / ooo).
references/ps-and-first-lines.md

First Lines and P.S. Lines

The two places personalization lives. Relevance goes in the first line; personal flavor goes in the P.S. Personalization without relevance is decoration. Researched 2026-10-26.

Evidence: two often-quoted numbers have no primary source, so never cite them: "the P.S. is the most-read part of an email" and "Lavender: a personalized P.S. lifts replies 35%". The most credible personalization data is Gong Labs (30K+ emails, observational). The only randomized head-to-head found is Saleshandy's 12K-send test (vendor-run). There is no clean public test of AI first line vs no first line on the same list, so run your own (§5).


Part 1: First lines

What the data says

  • Who you're writing to changes what works (Gong Labs). Individual personalization more than doubles replies from non-managers but adds only ~50% for directors and above. Company personalization triples replies from directors and above, with little effect below. For executives, write about the company and its situation; for ICs, write about the person.
  • AI research + human or rule-bound writing wins; free AI writing loses. Saleshandy (12K, VP and Head of Sales): AI-only 4.1% reply / 1.4% positive / 7.8% spam-flagged; human-only 10.4% / 4.2%; hybrid (AI research, human writes) 14.7% / 7.3%.
  • Hunter (31M emails, 2025): two custom attributes 5.6% vs 3.6% with none; hand-edited 5.2% vs fully automated 4.4%. 69% of surveyed buyers are bothered by AI-written email.
  • A wrong fact is worse than no line. One error destroys the "a human looked" signal.

The bridge principle

The first line must make sentence 2 inevitable. If you can delete line 1 without changing line 2, it's decoration.

  • Becc Holland: premise → bridge (premise to what you do) → CTA.
  • Lavender: observation → informed conclusion (the pain it implies).
  • Recipients care less about how much personal data you used than whether the email explains how the detail connects to the offer (White et al., 2008).
  • "I'm mentioning this because ___" test (Rework): if the blank is a problem their role owns, keep it. If it's "to show I did research", cut it.
  • Swap test: if a competitor's name fits the line, it fails.

Nowoslawski's four levels (higher earns more replies)

  1. Random (school, location). Belongs in the P.S.
  2. Company or lead specific.
  3. Recent, top of mind.
  4. Recent and product-related: infers a likely problem tied to how you solve it. Aim here.

Taxonomy

TypeExample (good)Notes
Trigger / signal"your team posted three SDR roles this month. new reps usually start by sorting leads by hand."Strongest when the next line names the problem it creates. Windows in triggers.md
Company observation"powder-coating turnaround in 5 days is a bold promise most fabricators won't put on their homepage."Specific, least-obvious fact; numbers and named things beat descriptions
Observation + implication"opening a third austin location while payroll still runs from one office puts a lot on one coordinator."Fact plus its consequence, no praise. The current best practice
Role / persona relevance"as the cro, I'd imagine forecast accuracy is the number you get asked about most."Scales 1:many (relevance)
Pain hypothesis"teams that sell through brokers usually hear about lost deals last."Works without per-person data
Content they made"your point on [podcast] that sdr ramp is a data problem, not a coaching problem, is exactly what we see."Only if engaged with; "I saw your post about leadership" is noise
Tech stack"saw you're on hubspot and outreach." + a yes/no on a known gapOnly detectable installs; never an absence
Mutual / affiliation"[mutual] said to say hi."Only if true. The one personal type that earns line 1
Timeline / tenure"90 days into the role is when the stack gets a hard look."New-leader windows good; tenure as praise weak
Search / billboard"trying to find the [team] that [has X figured out]."No-signal fallbacks (frameworks.md)
Creative idea"had an idea for {{companyName}}: [slot]."Slot-defined only

Bad patterns, always:

  • "Love what you're doing at {{companyName}}!", "impressive", "caught my eye": praise, and it fails the swap test.
  • "I see you went to [university]!" as an opener: vanity. Put it in the P.S. if anywhere.
  • "My name is… I work with…": about the sender.
  • "Hi {firstName}, I saw you work at {companyName}": merge tags pretending to be research.
  • "Congrats on the new role! Anyway, we sell…": no bridge.

Prompting AI first lines (when an AI slot is justified)

  • Inputs: structured upstream fields (site summary, news, job posts, LinkedIn summary), plus title and the segment's pain line, so the line can bridge. Never raw HTML.
  • A forced prefix written by a human carries the voice; the model fills only the slot.
    • "I saw you're hiring for '[title]'. usually that means you're trying to ___"
    • "as the [title], I'd imagine you focus on ___"
  • Caps: one sentence, 12-22 words (25 max).
  • Lead with the most specific, least obvious fact. No greeting or name inside the line.
  • Banned: impressive, love what you're doing, came across, I noticed, congrats, caught my eye, I was impressed, hope this finds you, and any construction that repeats across the review batch. LeadHaste added "while X, Y" after it took over a batch.
  • Never invent, and never merge facts across fields into a claim neither supports.
  • Abstain: return NOT_FOUND / empty. A formula routes the lead to the segment fallback line, so the sentinel is never sent.
  • Watch the abstain rate. 18-27% is healthy. Near 0% means the model is inventing; over 30% means the source or list is wrong.
  • Review 10-25 rows in sequence before scaling. Check each fact against its source, that it's current, the right person and the right company. Strip praise, and ban repeated constructions. Then audit a sample monthly.

Part 2: P.S. lines

What a P.S. is for

There's no proven lift, but it's a cheap slot whose most defensible job is to carry a human or attention detail without contaminating a relevance-led body (Reddit consensus via vendor roundups: semi-templated body plus one truly personal P.S.). Nowoslawski uses P.S. "attention hacks" (college plus current city; count of past roles plus a question) but warns that SaaS and e-commerce buyers spot automation, so use them sparingly.

Rules

  • One P.S., one idea, one sentence (two at most); ≤20 words. Never a P.P.S.
  • After the sign-off, on its own line.
  • New information only. Delete test: remove it and reread. If nothing's missing, cut it.
  • Never restate or compete with the main CTA, and never a second pitch. The P.S. adds no second question unless the P.S. is the CTA (soft-offer type), in which case the body has none.
  • The fact must be public and explainable: the prospect can guess its source in one second. Never family, health, age, religion or politics; never non-public data; never exact timestamps ("posted 6 hours ago"); never web-visit tracking.
  • No praise and no grading the person ("impressive background").
  • No fake urgency, no "I'm a real person, not a bot" (show it, don't assert it).
  • Vary the construction; the same P.S. across 1,000 sends becomes a detectable template.
  • Usually email 1 only. A follow-up can carry a different type (referral on E4).

Types

TypeJobUse whenExample
Human hook (fact + reaction)Shows a human looked; pattern breakTemplate or relevance-led body; a public fact exists"ps saw you were a ski instructor at whistler, that's so cool."
Former companyShared referenceLarge, long-established past employer"ps noticed you were at salesforce, were you there when they bought slack?"
LocationCheap local touchTight geo segments, real local knowledge (never a chain)"ps whenever I'm in sf I end up at the marin headlands for sunset."
Social proofCredibility without bloating the bodyPeer company in the same niche, cleared"ps [customer] was skeptical too. their note after month two: '[quote]'."
Soft offer (is the CTA)A lower-friction exit than a callSMB, high volume; the body has no question"ps if a call's too much, I can send a three-bullet teardown of your onboarding email instead."
Referral / routingFinds the ownerUnsure of persona; E3-E4"ps if [area] sits with someone else, point me to them and I'll leave you be."
Objection pre-emptRemoves the obvious noKnown incumbent"ps if you already have an agency, this runs alongside them, not instead."
SignalTimely aside not core to the pitchReal signal unrelated to the first line"ps congrats on the bills clinching, must be a good week in buffalo." (allegiance evidenced)
Opt-outReplies from not-now peopleLate steps"ps if now's not the time, a one-line 'not now' is more useful to me than silence."

Anti-examples: "P.S. let me know if you want to chat!" (repeats the CTA). "P.S. only 2 spots left!" (fake urgency). "P.S. saw you volunteer at a food bank, which is why pipeline matters to you" (a stretch tie-in). "P.S. impressive background" (grading).

Prompting AI P.S. lines

  • Input only the profile fields you'll allow (education, prior roles, volunteering, location, certifications, public talks). Never the whole scrape.
  • A forced prefix ("ps saw you ") plus the reaction list; 8-20 words.
  • Only a fact present in the input; never infer. Abstain → empty → no P.S. (not a fallback P.S. that says nothing).
  • A regex judge rejects grading and tie-ins (impressive|smart|accomplished|bet that|shaped|honed| instincts), then a cheap model judge checks the fact against the source.
  • Don't say "cold email" in the prompt (Clay community tip). Describe the reader instead.

Part 3: Testing them

Run a three-arm first-line test: AI line / segment line / none. Run P.S. on vs off separately. Measure positive replies, not replies. These are step-1 variant tests, so the volume math in testing.md §1 applies. At 1-2% PRR, only a ~2x difference will show up under ~2,000 sends per arm, so pool through hook_type and ps_type tags across campaigns rather than expecting one campaign to settle it.

references/segments-and-offers.md

Segments, Messaging Maps and Offer Switching

How to send different pains, proof and offers to different slices of the list without writing a new campaign from scratch each time. Researched 2026-10-26.

1. The principle: one positioning, many pitches

April Dunford: most segments don't need separate positioning. The product's differentiated value is usually the same, but the pitch changes (her IBM example: "keep the registers running" for retailers, "keep the lights on" for utilities).

So per segment, keep the core value and vary four things:

  1. Pain language, in that segment's own words.
  2. The lever (make money, save time or money, reduce risk), if the segment feels a different one most.
  3. Proof: same-segment first, then same problem shape.
  4. Offer: the lowest-commitment thing that shows the value to that segment.

The template, CTA style and voice stay the same. Segments switch slots, not emails.

2. The messaging map (one row per segment)

Keep it as a table in the campaign spec (or the client graph), not in prompts. Every campaign and AI slot reads from it.

# messaging_map: one entry per segment. First matching rule wins (top to bottom).
- segment_id: s1-vsaas-new-vp
  rule: vertical_saas AND employees 20-200 AND new_vp_sales_days <= 90   # signal segments first
  persona: VP Sales
  trigger: new VP Sales in seat ≤ 90 days
  pain: "inherits a thin pipeline and a quota due in two quarters"      # their words
  cost_of_pain: "a missed first two quarters"
  best_alternative: "AEs prospecting their own lists"
  lever: make_money
  angle: first-90-days pipeline
  offer: { primary: 50-hand-scored-accounts, fallback: peer-case-study }
  proof: { primary: <cleared same-segment result>, fallback: <same problem shape> }
  cta: value_exchange          # "want the list?"
  subject_pattern: signal      # "new role"
  avoid: ["congrats on the new role" as the whole email; naming their predecessor]
  campaign_id: <instantly id>
  status: testing              # testing | champion | retired
  min_volume_ok: true          # can reach ~1,000-2,500 leads in the test window
- segment_id: default
  rule: ICP fit, no segment or signal
  pain: <the shared best-alternative pain>
  lever: <the core lever>
  offer: { primary: soft-resource, fallback: none }
  proof: { primary: <broadest cleared proof> }
  cta: soft_question

Columns worth keeping even in a spreadsheet: segment_id | rule | est. monthly volume | trigger | persona | pain (their words) | cost of pain | best alternative | lever | angle | offer (primary → fallback) | proof | CTA | subject pattern | avoid | campaign_id | status | PRR | meetings/1k.

Build the pain column from the persona's world (Jason Bay's messaging matrix: priorities, current solution, problems, aspirations), sorted into the four pain kinds: financial, productivity, process, risk. For multi-persona accounts, add a buying-job column (economic approver, operational owner, technical evaluator, champion), each with what they need to validate and the proof they need (Unify). If one person holds two jobs, send one combined message. Route replies at the account level before emailing the next persona.

3. Routing leads (deterministic, in code)

  1. Compute segment with an ordered rule list, first match wins: signal segments first (most specific, most perishable) → vertical × size → persona-only → default. Never let a model pick the segment.
  2. Look up the map for that segment: offer, angle, proof, pain line, CTA, campaign_id.
  3. Fill slots inside the fixed template with those values. AI writes at most one or two short lines (ai-lines-and-spintax.md).
  4. One segment = one campaign. It keeps results attributable and stops variables leaking between segments.
  5. Offer waterfall within a segment: if the lead has what the primary offer needs (say, the data for a custom audit), use it; otherwise the fallback offer (a sample list, a case study); otherwise the default soft CTA. The waterfall result is a variable ({{offer_line}}), never a blank.
  6. Preflight every slot non-empty on every lead before push.

In Clay this is an IF / ELSE IF / ELSE formula column (segment) plus lookups. ELSE is the default. In code, a list of (predicate, segment_id) tuples.

4. Picking an offer per segment

Score candidates with offers.md, then choose the one with:

  1. the lowest commitment that still shows the core value;
  2. a direct tie to the segment's #1 pain or trigger;
  3. proof from the same segment (or the same problem shape);
  4. the lowest delivery cost at the positive-reply volume you expect. A 2% PRR on 2,000 sends is 40 audits.

Rules:

  • Lead with the segment where proof is deepest. Single-segment pitches outperform broad ones (Smartlead claims 6.8% vs 4.7%; directional only). Save the other services for the call.
  • One case study, many angles. Reframe one result per segment instead of hunting a new case study each time.
  • For retainer services, offer a smaller first step (an audit, sprint, sample or free test) that leads into the engagement. Never a price.

5. How many segments

A segment earns its own copy only if it can reach ~1,000-2,500 contacted leads in the test window, the volume needed to see a 2x difference at 1-2% PRR (testing.md §1). Otherwise merge it into its parent and vary only the pain or proof slot, or keep it as a tag inside a larger campaign.

Practical cap: 3-6 live segments × 1-2 offers each, plus the default.

6. The default campaign is your control

  • Write it around the shared best-alternative value, the broadest cleared proof and a soft interest CTA. Never a segment-specific offer it can't back.
  • Every segment is tested against the default. If a segment can't beat the default by ~1.5x on PRR after 2,000+ sends, merge it back: its custom copy isn't earning its maintenance.

7. Testing order for a map

  1. Segment × offer as separate campaigns vs the default. The coarse test, where 2x+ effects are plausible.
  2. Within winning segments: angle or lever, champion vs challenger.
  3. Then first line or CTA as step-1 variants.
  4. Subject, PS and length only once a segment sends 10k+ a month, or pooled across segments through tags.

8. Worked example (fictional outbound-services firm)

SegmentTriggerPersonaPainLeverOffer → fallbackCTA
S1 Vertical SaaS 20-200new VP Sales ≤ 90 daysVP Salesinherits thin pipeline, quota in 2 quartersmake money50 hand-scored ICP accounts → peer case study"want the list?"
S2 B2B services 50-500hiring BDRsManaging partnerpartners still prospect themselvessave timesample list of 25 targets → 2-min teardown video"worth a look?"
S3 PE-backed portfolio conew sponsor ≤ 12 monthsCEO / CRO100-day plan needs pipelinereduce riskoutbound audit readout → plan template"want the readout?"
S4 AE, no SDRAE hired, no SDR teamHead of SalesAEs prospecting instead of closingsave timeAE-ready account list → checklistinterest CTA
D Defaultnoneanyinconsistent pipelinecore lever"happy to send what's working in your space""worth a chat?"
references/signals.md

Signals: Writing Copy for Every Buying Signal

The catalog of buying signals we work with, and how to write for each: what it is, where it comes from, how strong it is, the send window, whether to name it, the angle, an example line, and the pitfalls. Researched 2026-10-26.

  • This file owns signal copy.
  • triggers.md owns real-world time triggers (sports, weather, the calendar) and the general freshness rules.
  • conferences.md owns events.

Evidence warning: nearly every per-signal reply number is published by the vendor that sells that signal (Unify, UserGems, RB2B, Valley, Trigify, ColdIQ). There's no independent, controlled dataset. Compare claims against the real baseline: the Smartlead 2026 median sender gets 1 reply per 135 contacts (0.74%). Expect a real signal to lift replies 2-5x, not 10x.


1. Four kinds of signal (and score ≠ signal)

AxisQuestionDecays?Examples
FitShould they ever buy?Noindustry, size, stack, growth, awards, lookalike of closed-won
IntentAre they looking? First-party (high) or third-party (medium)Fast (days)website visits, PQL, content, own-post engagement · Bombora, G2, competitor engagement
Timing / triggerWhy now?Weeksnew hire, promotion, exec change, funding, M&A, job post, deadline
Access / relationshipDo they know us?Slowlypast champion, closed-lost, followers, mutual connections, event co-attendance

Fit and signal are separate fields, never summed. Outreach needs both. Priority = fit × signal strength × freshness.

2. The naming rules (the most important part of this file)

  1. Public, self-announced events may be named: job change, promotion, funding, job post, talk, filing, award, launch. But naming must come with an observation or implication. "Congrats on the raise" alone is the most saturated opener in B2B.
  2. Tracked behavior is never stated: website visits, pricing-page views, third-party intent, G2, likes, stars, competitor reviews. Write to the problem it implies, at the persona level, as a question. Company-level signals (reverse IP, Bombora, G2) must never be written as if this person did the thing. "Saw you on our pricing page" reads as surveillance, and is often wrong about who looked.
  3. First-party relationships are named; the relationship is the hook: past champion, closed-lost, engagement with our posts, a webinar they attended, their own product usage.
  4. Every inference is a hypothesis: "usually", "my guess is", "am I off?". Assertive claims about their business cut replies 26% (Lavender via UserGems).
  5. Never say where or how you found them for tracked signals. If someone asks, have an honest one-line answer ready. For shared rosters, do say where the address came from (conferences.md).

House call on a known conflict: Kellen's Warm archetype opens with "saw {{companyName}} was on the [product] site". Our rule is never state the visit. Use the visit to time and aim, not as the subject. Our rule wins.

3. Archetypes (how the 4 moves adapt), after Kellen Casebeer

ArchetypeSignalsMove 1 (opener)Insight patternCTA shape
Transitionnew hire, promotion, exec change, champion movename the move ("congrats on joining")"the first window is when it's easiest to see what's working and what's messy""have a system you love, or open to changes as you settle in?"
Eventfunding, M&A, launch, job posts, expansion, earningsname the event plainly ("saw the deal")"after a [event], the question shifts from [old] to [new]""already planned for, or still being worked out?"
Competitivecompetitor engagement, tool evaluation, tech change, competitor reviewsthe topic, never the competitor; one hedge at most"[tool] covers X; the hard part is Y when Z""open to alternatives, or still mapping what you need?"
Warm (first-party)own-post engagement, content, webinar, champion, closed-lost, PQLname the relationshipcontinue the conversationa reply, not a meeting
Implied (tracked)website visits, third-party intent, G2no mention; open on the problem the page or topic implies"teams at your stage usually hit X when they start comparing""is that what's going on, or am I off?"
Searchnone"trying to find the [team] that [has X figured out]"binary

4. The catalog

S = strength (H/M/L). Window = when to send. Name = whether to state the signal.

First-party intent

Website visitor: company level (reverse IP: HubSpot Breeze/Clearbit, Dealfront, Snitcher, Koala, Warmly, Vector, Common Room)

  • S: M; H on pricing, demo, comparison, integration, security or docs pages, or a repeat visit within 7 days. Homepage visits barely count (docs and pricing page visits are the ones that matter).
  • Window: same day to 48h. Decay weights: 100% (0-7 days) / 50% (8-14) / 25% (15-30) / drop after 30.
  • Name: never. You don't know who looked.
  • Angle: the problem the page implies (pricing → ROI or time-to-value; integrations → stack fit), aimed at the persona who owns it.
  • Example: "teams at {{companyName}}'s stage usually hit [pain] right around when they start comparing options. worth a two-line note on how others handled it?"
  • Pitfalls: company ID accuracy is low across vendors, and claimed match rates range 15-60%. VPN, mobile and home IPs give false hits. Exclude customers, competitors, and careers-page visitors (job seekers).
  • Route to a human same day; automating it into a drip wastes it.

Website visitor: person level (RB2B, Warmly, Vector, Knock2)

  • S: H if the match is right.
  • Window: within hours; skip after 14 days.
  • Name: never (house rule). RB2B's own team names pages and claims 30% positive replies (self-reported); Knock2, Unify and ColdIQ say never.
  • Angle: as above, plus the persona's job.
  • Example: "{{firstName}}, most [role]s I talk to look at [category] when [trigger pain]. is that what's going on at {{companyName}}, or am I off?"
  • Pitfalls: US-only, needs LinkedIn coverage (weak in trades, healthcare, manufacturing). In the EU, person-level ID without consent is high-risk under GDPR plus ePrivacy, so get counsel or don't. Suppress EU person-level matches by default.

Content download / gated asset (HubSpot, Marketo forms)

  • S: M (often research or students).
  • Window: within 48h.
  • Name: yes; they gave their email knowingly.
  • Angle: the asset's topic → the next logical question.
  • Example: "you grabbed the [asset]. the part most people get stuck on is [X]. want the two-minute version of how [peer] handled it?"
  • Pitfalls: a download isn't an MQL. Gate on fit. Students and vendors.

Webinar registration / attendance (Zoom, Goldcast, ON24, Luma)

  • S: M (registered) / M-H (attended) / H (asked a question).
  • Window: 0-24h, then 2-4 touches over 5-7 days.
  • Name: yes.
  • Angle: attendees → the next step, or their question answered; no-shows → the replay plus a 3-line recap. Never scold a no-show.
  • Example (asked a question): "you asked about [X] in the session. the short answer is [Y]; the longer one depends on [Z]. worth 15 minutes to walk through yours?"

Engagement with our posts / new followers (Teamfluence, Trigify, Common Room, PhantomBuster)

  • S: M-H; they already know us.
  • Window: 48-72h.
  • Name: yes. It's public and with us.
  • Angle: continue the conversation; no pitch in message 1.
  • Example: "thanks for jumping on the [topic] post. curious what you're seeing at {{companyName}}: [question]?"
  • Pitfalls: peers, vendors and job seekers inflate the list. Comments ≫ likes. LinkedIn first, then email.

Product signup / PQL (product events via Segment, Pocus, Unify)

  • S: H.
  • Window: 1-4h after the action (limit hit, invites sent, setup done).
  • Name: yes, it's their own usage. Avoid creepy granularity ("you clicked X 7 times").
  • Angle: help with the specific action.
  • Example subject: "hit the [feature] limit?"
  • Pitfalls: Gmail signups, students, competitors. Gate on fit + usage + role.

Community / GitHub / Slack activity (Common Room, Reo.dev)

  • S: H in our own community or repo; M in a competitor's.
  • Window: days.
  • Name: our community yes; a star → imply only.
  • Angle: help with the problem they starred or asked about.
  • Pitfalls: hobbyists; GitHub handle → work email matching is error-prone.

Relationship

Past champion / user changes job (UserGems, Champify, Common Room, Deepline champion tracking)

  • S: highest of the cold signals (vendors: 3x conversion; one case reports 40-50% response).
  • Window: touch 1 fast with no ask; pitch at weeks 2-4; ~10 touches over ~45 days at a slower pace.
  • Name: yes; the history is the point.
  • Angle: shared history → bridge.
  • Example: "congrats on the move to {{companyName}}. at [OldCo] you [result]. curious if [NewCo] has the same [problem], or if it's a different animal."
  • Pitfalls: verify the employer (a mismatch is "a lead, not proof"). Route customers and open deals to their owners; manager review for churned or negative history. Also email the replacement at the old account within ~5 days.

Closed-lost / old opportunity (CRM + a new signal)

  • S: H (vendors claim 10-15% reply).
  • Window: when the loss reason changes (new budget, new leader, M&A, tech shift), not on a timer. 4-5 touches over 2-3 weeks.
  • Name: yes, both the old conversation and what changed.
  • Angle: touch 1 = old conversation + the change; 2 = proof; 3 = a resource on the objection; 4 = a 15-minute ask.
  • Example: "we spoke last [quarter] about [use case] and timing was [objection]. with [new signal], figured it might look different now."
  • Pitfalls: no "checking in", don't re-litigate the loss, check the original owner.

Event co-attendance: see conferences.md. A registration is a fact; a LinkedIn post about going is an inference.

Transition (people)

New hire in the target persona (UserGems, Champify, Sales Nav alerts, Coresignal, PDL, LeadMagic, Deepline job-change enrichment)

  • S: H for timing; a mandate and a 90-day clock.
  • Window: days 14-90 (sources disagree: LeadMagic says first touch days 14-21, never day 1; ColdIQ says peak 14-45; Apollo says evaluation at 31-60).
  • Name: yes, briefly, but "congrats" can't be the whole opener.
  • Angle: what people in this seat inherit in the first 90 days, as a hypothesis.
  • Example: "congrats on joining {{companyName}}. people stepping into [role] at a [stage] company usually inherit [pain] in the first quarter. have a system you love, or open to changes as you settle in?"
  • Pitfalls: stale profiles (verify the role is current); 28% of "new roles" are internal moves (say "started", never "hired"). Keep it under 50 words, 0-1 questions. Dual track: also email their boss or the CEO about the same mandate.

Promotion

  • S: M-H; new scope, but they inherit the existing stack.
  • Window: 2-6 weeks.
  • Name: yes, briefly.
  • Angle: the new scope: the function or team that now sits under them.
  • Example: "congrats on the promotion. now that [function] sits with you, [pain] becomes your call rather than someone else's."
  • Pitfalls: inflated LinkedIn title bumps. Little published evidence.

Leadership change (new CEO, CRO, CFO, VP)

  • S: H.
  • Window: days 14-60 (a new VP moves within ~30 days; 90+ may be too late).
  • Name: yes.
  • Angle: the new exec's likely first-quarter mandate; also email the team under them, who face it.
  • Example: "new [CRO]s usually re-baseline [metric] in quarter one. if [X] is on the list, happy to share what we've seen work."
  • Pitfalls: execs get flooded; this is where real research earns its keep (POV framework, frameworks.md #14).

Work anniversary (lifecycle)

  • S: L-M.
  • Window: the anniversary week.
  • Name: yes, with a business angle ("2 years running [function], what's changed since you took it over?").
  • Never birthdays.

Company events

Job postings (PredictLeads, TheirStack, Coresignal, LinkUp, Sumble, Apify scrapers)

  • S: M (a RevOps or ops req for a problem we solve is the strongest variant).
  • Window: weeks 1-2 → the hiring manager or CEO ("the gap before the hire lands"); weeks 3-8 → find who was hired and target them on days 1-30. Verify the post is still live.
  • Name: yes, by its content, not "I see you're hiring". Quote one requirement and tie it to an operational problem. Say you saw it, don't quote their headline back, and never say where you saw it.
  • Example subject: "{{RANDOM|the [role] req|[role] question}}". Line: "the [role] req mentions owning [X] from day one. most teams fill that seat and still [gap] for six months. how are you covering it in the meantime?"
  • Pitfalls: evergreen and repost roles, agency postings. Rank on distinct titles, not posting count (one company: 146 postings, 2 distinct titles). A post doesn't prove budget.

Hiring surge / headcount growth (Coresignal, PredictLeads, Sumble, Harmonic, Sales Nav)

  • S: M; a good fit or timing filter.
  • Window: weeks.
  • Name: yes, in aggregate ("you've roughly doubled the AE team").
  • Angle: what breaks at scale.
  • Gate: 2+ related roles in 30 days, or role starts ≥2 in a department of ≥4.
  • Pitfalls: LinkedIn headcount lags.

Fundraise (Crunchbase, Harmonic, PitchBook, Dealroom, SEC Form D, Fundable)

  • S: M-L alone. Consistently the lowest-replying signal in vendor data (Unify 3-6%).
  • Window: week 1 is noise (the inbox floods); weeks 2-8 are the window; drop the reference after ~3 months. Indexes lag 3-4 months, so check the date.
  • Name: weeks 0-2 only with a sharp observation; weeks 4-8, name what the money is for, not the round.
  • Angle: the execution plan the round funds (hiring, a new market), not "you have budget".
  • Example: "the plan after the series b looks like [new market / hiring 6 AEs]. the part that usually lags is [X]. is that on your radar yet?"
  • Pitfalls: never infer a project from round size; never the valuation or investors. Stack it with a matching job post (funding in 90 days + a related post in 60 days).

M&A / acquisition (Crunchbase, PitchBook, news APIs)

  • S: M-H; tool consolidation is coming.
  • Window: after close, months 1-2; integration is the real window (14-120 days).
  • Name: yes, neutrally ("saw the deal"), never "congrats".
  • Angle: acquirer → standardizing tools across the combined company; target → meeting the parent's requirements. Lead with empathy for full plates; offer a resource and defer the pitch.
  • Example: "guessing the next two quarters are mostly integration. when [tool area] comes up, happy to share the checklist we see teams use."
  • Pitfalls: don't pitch before close; job insecurity is real (tone).

Product launch (news, Product Hunt, changelog)

  • S: L-M; stack it.
  • Window: 1-3 weeks.
  • Name: yes, specifically ("saw [product] went live last week"), never "congrats on the launch!".
  • Angle: the GTM work after launch (pipeline, adoption, field readiness).

New office / geographic expansion (PredictLeads news, TheirStack geo jobs)

  • S: M.
  • Window: 0-8 weeks.
  • Name: yes.
  • Angle: building [X] from zero in the new market (hiring, compliance, local pipeline).
  • Pitfalls: "expansion" is sometimes one remote hire.

Earnings / 10-K / annual report (EDGAR, Quartr, AlphaSense)

  • S: M for enterprise.
  • Window: 1-3 weeks after.
  • Name: yes, and cite it.
  • Angle: quote the stated initiative (Item 1A risk factors, MD&A, the call) → where it lands on this persona's desk.
  • Example: "[CEO] called out [initiative] as the 2026 priority on the Q2 call. that usually lands on [persona]'s desk as [pain]."
  • Pitfalls: public companies only; never misquote.

Partnerships / integrations announced: S L-M, window 0-6 weeks, name it. Angle: what the partnership requires operationally, or that we integrate with the same partner. Weak alone.

Awards / rankings (Inc 5000, Deloitte Fast 500, G2 badges): S L as intent (it's a fit signal of growth). Window 0-4 weeks. A brief, verifiable nod, then "[X]% growth usually means [process] is about to break". Every Inc 5000 company gets hundreds of these emails, so stack it.

Layoffs / restructuring (WARN notices, layoffs.fyi, headcount drops)

  • S: M, and only for cost-down, efficiency or retention offers.
  • Window: wait 2-4 weeks.
  • Name: never.
  • Angle: covering the same ground with a leaner team ("a lot of [function] teams are being asked to cover more this year. here's how [peer] kept [metric] flat").
  • Pitfalls: never email the people laid off; no gloating, no "do more with less"; never pitch headcount-based seats; low touch count.

Regulatory / compliance deadline (regulator calendars, GovFiles): S M-H for in-scope firms. Window 3-9 months before. Name it (public). Angle: one specific friction point. Verify they're in scope, don't fearmonger with fines, and get the dates right.

Prospect's website or pricing change (Visualping, Firecrawl change tracking): S L-M, window 1-3 weeks, name it ("noticed you added an enterprise tier"). Angle: the new motion it implies. Ignore cosmetic changes.

Press / newsletter / exec quote: S L, window 1-2 weeks, name and cite it briefly and verifiably. "Saw your article" with no specifics reads as automated.

Permits / project announcements (local permit portals, project databases): S M-H for construction-adjacent sellers, window 0-21 days. See triggers.md.

Competitive and third-party

Competitor LinkedIn post engagement (Trigify, Valley, Common Room, PhantomBuster, Apify, Clay post audience, Teamfluence)

  • S: M; a comment ≫ a like; repeat engagement > one-off.
  • Window: within 48h.
  • Name: the topic, never the competitor ("I saw you follow [competitor]" spends the goodwill). "saw your take on [topic]" only for comments.
  • Example: "saw your comment on [topic]. we've found [specific, slightly contrarian point]. how are you handling it at {{companyName}}?"
  • Pitfalls: engagers include competitor employees, vendors, job seekers and the poster's friends, so filter to ICP. Scraping and automation risk LinkedIn bans. Vendor claims of 25-54% replies are unverified.

Third-party intent (Bombora topic surges, G2 Buyer Intent, TrustRadius, 6sense, Demandbase)

  • S: M (category research, not interest in us). G2 compare and alternatives pages are the strongest.
  • Window: the week of the surge (data already lags a week).
  • Name: never (G2: a contact on the list "does not mean a specific contact generated" it).
  • Angle: the category and the buyer's evaluation criteria.
  • Example: "teams comparing [category] tools usually get stuck on [criterion]. worth one paragraph on how we'd answer it?"
  • Pitfalls: accuracy claims range from ~15% to ~81%. Always overlay fit. Backtest before buying: if more than 60% of the last 50 closed-won deals showed prior intent, it's real; under 40% is noise. $20-100K+ a year.

Tech install / removal / competitor renewal (BuiltWith, Wappalyzer, HG Insights, Sumble, TheirStack via job descriptions)

  • S: M; a removal or replacement is H.
  • Window: install or removal 1-2 weeks; renewal ~90+ days before the estimated date (adoption date
    • a 12/24-month term).
  • Name: the public tool, yes ("you're on [tool]"); never claim to know their contract date.
  • Angle: install → the adjacent problem it creates; competitor user → the known gap. Never trash the competitor.
  • Example: "most [tool] teams we talk to love [strength] but end up exporting to sheets for [gap]. same at {{companyName}}?"
  • Pitfalls: client-side tech only; a detection date isn't a purchase date; never infer an absence.

Negative reviews of a competitor (G2, Capterra, Reddit)

  • S: H if the reviewer is identifiable and ICP.
  • Window: days.
  • Name: no; lead with the pain they described.
  • Example: "teams on [competitor] keep telling us [gap] is what breaks at [scale]. true for you?"
  • Pitfalls: most reviewers are anonymous; terms of service; it can feel predatory.

Social posts expressing pain (Trigify, Common Room, Octolens, Syften, F5Bot)

  • S: H for a first-person complaint.
  • Window: 24-72h.
  • Name: the public post's topic, yes; how you tracked it, no.
  • Angle: reply to the idea with one useful point. Don't assume a buying motive.

Podcast appearance (Podscan, Listen Notes): S L as intent, high personalization value. Window 1-4 weeks after release. Quote one specific idea they said → the problem it implies. Never fake having listened.

Fit-only (good for lists, not reasons)

Lookalikes of recent closed-won · accounts a competitor just won (wait 6-12 months) · Glassdoor or Indeed reviews naming process pain · tech-stack fit · growth rankings · mutual connections and warm paths (these earn line 1 only if real). Customer expansion and customers on the pricing page → route to the account owner, never outbound.


5. Stacking, routing and priority

  • Composite priority = fit × signal × freshness. Score a surge against the account's own baseline, not raw volume. Run 5-7 signal types at most.
  • Stacks that work: new VP + pricing-page visit · past champion + intent · funding + a related job post or sales hiring surge · website visit + a growing buying committee · job post + a new leader in that function.
  • 1 signal = normal priority; 2 = high; 3+ = same-day human outreach (ColdIQ heuristic; its reply claims look inflated).
  • One account gets one message combining its signals, not one sequence per trigger. Idempotency is per signal, not per company: the same signal never fires twice, and the highest-intent unacted signal goes first.
  • Routing: high fit + high intent → a human today. Mixed → automated sequence. Low fit → monitor.
  • Suppress always: customers, open opportunities, competitors, job seekers, non-ICP, EU person-level visitor matches, anyone who replied anywhere, the do-not-contact list.

6. Who gets the email (signal holder ≠ buyer)

The person who generated the signal isn't always the buyer :

  • A recruiter posts the job → email the hiring leader, and never mention the post or who wrote it.
  • A new IC joins → email their boss about the mandate, and optionally the new person separately.
  • An exec changes → email the exec and the team under them.
  • Competitor engagement by a junior → email the function lead about the topic, not the engagement.

Write one version per who-slot (founder / function lead / IC) in the messaging map (segments-and-offers.md).

7. Channel and pace per signal

SignalFirst channelPace
Pricing or demo visitor (person level)email within 1h, or a call if you have the number4 steps over 7 days, permission CTA
PQLin-app or email within 2h4 steps over 5 days
Champion movepersonal email, no ask → LinkedIn day 3 → value email day 7~10 touches over 45 days
New hire / new execLinkedIn connect first, email ~day 14plus a parallel track to their boss
Post engagement (ours or a competitor's)LinkedIn within 48h, then emailcomments before likes
Third-party intentemail + multithread 2-4 personasprioritize, don't fire instantly
Eventsconferences.mdanchored to the event dates
Closed-lostemail from the original rep4-5 touches over 2-3 weeks
Funding / M&A / layoffsemail, low touch count, empatheticresource first, pitch later

8. Vendor claims

Vendor reply claims, for calibration only (all self-interested): champion move 12-20% (Unify) to 40-50% (one case); closed-lost 10-15%; new hire 8-12%; G2 intent 4-8%; tech change 6-10%; funding 3-6%; post engagement 13-28%; website visit 5-10% (Unify) to 30% positive (RB2B's own). The consistent ordering is the useful part: relationship and first-party > new hire > third-party intent, tech, funding.

9. Tags

Every signal campaign declares trigger_type (vocabulary in testing.md §5) and records trigger_age_days at enrollment, so your reporting can tell you which signals and windows actually work for your buyers. The windows above are starting values, not truths.

references/spam_words.json

{ "_about": "Tiers used by references/lint_copy.py. hard = error, soft = warning (judgment call: B2B copy to sales leaders can't avoid 'sales'). Phrase lists adapted from growthenginenowoslawski/coldoutboundskills spam-word-checker (MIT, (c) 2026 GrowthEngineX). Edit here, not in the script.", "hard": [ "$$$", "50% off", "100% guaranteed", "100% free", "100% off", "100% satisfied", "access now", "act fast", "act immediately", "act now", "action required", "affordable deal", "amazing deal", "amazing offer", "apply here", "apply now", "avoid bankruptcy", "bargain", "best bargain", "best deal", "best offer", "best price", "best rates", "big profit", "buy now", "buy today", "call now", "can't live without", "cash bonus", "cash out", "claim now", "claim your discount", "click below", "click here", "click this link", "contact us immediately", "deal ending soon", "don't delete", "double your money", "double your wealth", "drastically reduced", "earn cash", "earn extra income", "earn money", "easy income", "exclusive deal", "expires today", "extra cash", "extra income", "fantastic offer", "fast cash", "final call", "free access", "free consultation", "free gift", "free membership", "free money", "free quote", "free trial", "full refund", "get it now", "get out of debt", "get started now", "giveaway", "great news", "guaranteed deposit", "guaranteed results", "hurry up", "important information", "incredible deal", "instant earnings", "instant income", "instant savings", "investment advice", "join millions", "limited time", "lowest price", "make money fast", "million dollars", "money-back guarantee", "must read", "no catch", "no cost", "no obligation", "no strings attached", "once in a lifetime", "only available here", "order now", "order today", "please read", "price protection", "pure profit", "risk-free", "satisfaction guaranteed", "save big money", "save up to", "sign up free", "special invitation", "special offer", "special promotion", "supplies are limited", "take action now", "this won't last", "time limited", "top urgent", "unbeatable offer", "unbelievable", "what are you waiting for", "while supplies last", "why pay more", "will not believe", "winner announced", "you are a winner", "access your account", "account update", "activate now", "change password", "click to verify", "confirm your details", "data breach", "download now", "final notice", "important update", "immediate action required", "install now", "last warning", "log in now", "password reset", "payment details needed", "security update", "update account", "verify identity", "warning message" ], "soft": [ "free", "guarantee", "guaranteed", "winner", "urgent", "discount", "bonus", "cash", "earn", "profits", "promise", "unlimited", "amazing", "fantastic", "wonderful", "incredible", "trial", "quote", "investment", "credit", "mortgage", "billing", "invoice", "deal", "great fit", "compare notes", "off chance", "keep this open", "appreciate the reply", "increase revenue", "increase sales", "the best" ], "agency_vocab": [ "leverage", "leveraging", "synergy", "synergies", "solutions", "best-in-class", "world-class", "cutting-edge", "game-changing", "game changer", "innovative", "revolutionary", "state-of-the-art", "next-gen", "disruptive", "transformative", "seamless", "seamlessly", "robust", "empower", "unlock", "supercharge", "drive results", "partner with you", "touch base", "circle back", "move the needle", "low-hanging fruit", "value-add", "ecosystem" ], "openers_and_filler": [ "hope this finds you", "hope you're doing well", "hope you are doing well", "hope all is well", "hope you're well", "i wanted to reach out", "i'm reaching out", "i am reaching out", "just reaching out", "i came across your", "my name is", "i wanted to introduce", "allow me to introduce", "just wanted to touch base", "i noticed your amazing", "quick question", "quick one", "i'll keep this short", "i will keep this short", "one more thought", "last note from me", "just checking in", "following up", "follow up on my", "bumping this", "circling back", "did you see my", "in case you missed", "per my last", "i never heard back", "take silence as", "if i don't hear back" ], "calendar_cta": [ "calendly", "my calendar", "your calendar", "15 minutes", "15 min", "30 minutes", "book a time", "book a call", "grab time", "hop on a call", "schedule a call", "schedule a meeting", "set up a call", "tuesday at", "wednesday at", "thursday at", "monday at", "friday at" ], "bad_subjects": [ "quick question", "curious", "following up", "follow up", "touching base", "partnership opportunity", "re:", "fwd:", "checking in", "important", "urgent" ] }

references/testing.md

A/B Testing Cold Email Copy

How to run a test that teaches you something. references/ab_test.py does the math: sample size, minimum detectable effect, and the Bayesian readout. Researched 2026-10-26. The sample sizes here come from the standard two-proportion formula, not vendor blog figures, which are mostly too small.


1. The hard truth: you can only detect big effects

Positive reply rates are 0.5-3%, so a test needs thousands of sends per arm to see anything short of a doubling.

Sends per arm (two-sided α = 0.05, 80% power; metric = positive reply rate per unique lead):

Baseline PRR+25%+50%2x3x
0.5%56,19315,5994,6731,553
1.0%27,9377,7502,319769
1.5%18,5195,1341,534507
2.0%13,8093,8261,141376
3.0%9,1002,518749245
5.0%5,3331,471435141

A directional bar (α = 0.10) needs ~20% fewer sends. Quick approximation: n ≈ 16·p̄(1−p̄)/(p2−p1)².

What follows:

  • Vendor floors of 100-500 per variant only detect a 3x+ effect. Eric's repo table (500 per arm for 2x at 1%) is about 4-5x too small. Use the table above.
  • Count events, not sends. Read nothing until each arm has ~10 positives; trust it at ~30.
  • Size the test from your volume. Fix the sends you can actually afford in the window, then solve for the minimum detectable effect (ab_test.py mde). If the MDE is above 2x, only list, offer, angle or segment changes are worth testing. Subject, PS and length tests have to wait for 10k+ sends a month or pooled tagging (§5).

2. What to test, in order

**list/segment > offer > angle (lever / problem) > first line > CTA > subject > length/format > PS

send time / sender.** Leverage shrinks down the list, and so does the effect you can expect, so the order is forced by the math as much as by the experts.

At Eric's volume (~1.5M a month) Growth Engine X tests segment × offer × angle as separate campaigns and "front-loads" testing: 11 segmented campaigns cracked one offer in ~48 hours. He builds messages from swappable parts (value prop, problem statement, case study) and tracks each trigger by its positive-reply ratio.

3. Test design

  • Whole-sequence tests (offer, angle, segment) run as separate campaigns. Split the leads at random before upload, stratified by list batch and segment.
  • Step-1 tests (subject, first line, CTA) run as in-step variants. Instantly assigns a variant at random at each step, with no matching across steps (a lead can get 1A then 2B), so in-sequence variants can't compare whole sequences. A new subject on a step 2+ variant breaks the thread.
  • One variable per test. Multivariate needs n × cells, which is impossible here. The exception is factorial tagging: vary factors deliberately across many campaigns, tag every factor, and read main effects by pooling (§5).
  • Champion / challenger. Keep a standing champion and run one challenger at a time, 50/50 (a 70/30 split needs ~25-40% more total sends for the same power). Promote by the rubric (§7), then write the next challenger.
  • Holdout for signal plays. To learn whether a trigger or the sequence adds anything at all, keep 5-10% of eligible leads unsent and compare meetings from any source over 60-90 days.
  • Turn Instantly auto-optimize off for real tests. It optimizes raw reply, click or open rate, never positive replies, and has no documented threshold. Replies arrive late, so it commits to early leaders, and a variant can "win" because it landed on healthier mailboxes. Use it only to prune obvious duds (0 positives vs 6+ after ~1,000 sends each). Switch it off on any campaign that is a declared test.
  • Commit to n before launch. Peeking and stopping on a lead is the top cause of false wins. If you must look early, plan 2-3 looks in advance.
  • Close a test only after every lead finishes the sequence plus 7 days. That's typically 3-5 weeks. Instantly's "5-7 days" is too short for multi-step sequences.

4. Metrics and confounders

Metrics, in order: positive reply rate per unique lead contacted (define "positive" before launch) → meetings per 1,000 leads → qualified pipeline per 1,000 → closed-won per 1,000 (lagging; use for offer decisions). Diagnostics only: bounce, unsubscribe and negative-reply rate, raw reply rate, opens. A variant with more opens but fewer replies is clickbait, so kill it.

Confounders to balance:

  • Inbox placement: variants with links, images or spammier words land differently. Run a placement seed test per arm, and compare bounce and negative replies.
  • Mailbox and domain: every arm rotates across the same mailbox pool. Never give a variant its own domain. Log the mailbox on every send.
  • Day and time: randomize within day.
  • List batch and enrichment vintage: split every batch across all arms.
  • Segment mix: stratify, or analyse within segment.
  • LinkedIn touches on the same leads: balance them across arms or exclude.
  • Mid-test edits void the test.
  • Novelty decay: a winning opener wears out at volume ("never send the identical opener at volume", Eric).

5. Tag everything (so small tests pool)

Every campaign spec declares its copy choices from a fixed vocabulary, never free text. A campaign that changes nothing from the champion says so.

TagValues
levermake_money, save_time_money, reduce_risk
segmentthe segment_id from the messaging map (segments-and-offers.md)
trigger_typenone, funding, new_exec, new_hire, promotion, job_post, launch, m_and_a, earnings, fye, permit, website_visit, competitor_engagement, content_download, event, champion_move, intent, tech_change, sports, weather, calendar, other
offerthe offer_id from the messaging map, or none
hook_type (first line)signal, observation, question, peer_proof, pain, search, billboard
cta_typesoft_question, interest_check, value_exchange, confirmation, referral, calendar, none
proofnamed_client, metric, none (or the client-specific proof id)
ps_typenone, fact_reaction, social_proof, soft_offer, signal, referral
subject_typesignal, name, offer, problem, question
length_band≤50, 51-75, 76-100, 101-125

Record test_id and arm (champion / challenger / holdout) on every lead in a test, plus trigger_age_days for trigger plays.

6. Test log (one per test, saved with the campaign spec)

Test ID:            T-YYYY-MM-DD-<short-name>         Owner:        Opened / closed:
Hypothesis:         For <segment>, <challenger> beats <champion> on PRR because <reason>.
Variable changed:   (exactly one)
Held constant:      list source, segment, mailboxes, schedule, steps, delays, everything else
Champion:           copy link + tags                  Challenger:   copy link + tags
Primary metric:     PRR per unique lead; "positive" = interested + soft + referral
Secondary:          meetings / 1k, bounce, negative-reply rate
Baseline PRR:       x% (source)   MDE: x   α / power: .05 / .8 (or Bayes thresholds)   n per arm: x
Allocation:         50/50, lead-level, stratified by batch + segment + day   Planned looks: x
Preflight:          variables non-empty, step-1 delay > 0, auto-optimize OFF, placement seed per arm
Results:            n, positives, PRR, 95% CI per arm | meetings/1k | P(B>A) | expected loss
Validity:           bounce per arm, open parity, placement per arm, mailbox/day balance
Decision:           PROMOTE / KEEP CHAMPION / EXTEND / ABANDON / KILL (harm)
Learning:           one generalizable sentence          Next test:

7. Decision rubric

  1. Validity gate (fail any one = void): planned n reached; every lead finished the sequence plus 7 days; bounce under 2% and within 0.5 points between arms; open or placement parity within ~20%; no mid-test edits; mailboxes and days balanced.
  2. Promote the challenger when P(challenger > champion) ≥ 0.90 on PRR (p < 0.05 for permanent house-rule changes), expected loss < 0.1 point, the winner has ≥10 positives, and meetings per 1k don't move the other way.
  3. Keep the champion when P ≤ 0.10, or when the challenger raises raw replies but lowers PRR or meetings.
  4. Inconclusive (0.10 < P < 0.90): extend once to 1.5x n if the upside is worth it. Otherwise keep the simpler or cheaper variant and log "no detectable difference at MDE x".
  5. Stop for harm at any time: bounce over 3%, a spike in complaints or unsubscribes, or a placement drop.
  6. A win in one segment is a hypothesis for the next, not a rule.

8. Bayesian readout (what ab_test.py analyze does)

Each arm's PRR posterior is Beta(a0 + positives, b0 + sends − positives), with a weak prior centered on the historical rate (Beta(1, 99) for ~1%). Report:

  • P(B > A), by Monte Carlo draws from both posteriors;
  • Expected loss of choosing B: E[max(pA − pB, 0)]. Stop when it's below tolerance (0.1 point);
  • the result under a second prior. If the decision flips, it isn't a decision yet.

Bayes doesn't create information. It makes acting under uncertainty explicit, which is what a low-volume operator needs.

references/triggers.md

Time-Based Triggers: Sports, Weather, Calendar and Company Events

Company and behavioral buying signals (visitors, hires, funding, job posts, intent and the rest) are cataloged with their copy rules in signals.md, and events in conferences.md. This file covers real-world time triggers (sports, weather, the calendar) and the freshness rules every trigger shares.

A trigger is the why now. It earns one line, and the next line ties it to the buyer's problem. The event is the reason for writing today, never the pitch. Researched 2026-10-26.

Evidence quality: data sources (NWS, SPC, ESPN, SEC) are solid. Decay windows and "3-5x lift" claims come from vendors who sell signal data (Autobound, Landbase, FirstSales, Salesforge) and are unverified. Treat every window as a starting value: tag trigger_type and trigger_age_days, and let your own results calibrate them.


1. Rules for every trigger

  1. One line, then value. Situational relevance (why this person, why now) beats name-drop personalization (Apollo).
  2. Facts come from a stored field, never from the model. Store event_date, event_source_url and the raw values (score, hail size, county). The AI may phrase them; it never supplies them. A judge checks the line's facts appear in the source row before push.
  3. A freshness gate in code. Block the send if the event is past its window, and re-check in-flight leads too: follow-up 3 must not mention a 5-week-old win. Aim to send within ~72 hours of detection; a reference after 3 weeks reads as a stale scrape.
  4. Fallback = drop the line. Use a two-version template: the base email must stand on its own when the trigger is empty or stale. Never let a model fill the gap with a plausible score or storm. Spintax can't hide a blank (ai-lines-and-spintax.md).
  5. Tone: congratulate wins, stay neutral on weather, and never joke about or reference losses, layoffs, lawsuits, bankruptcies or disasters.
  6. Never send:
    • into a county with an active Hurricane Warning, Tornado Emergency or Flash Flood Emergency, or a FEMA declaration in the last 14 days;
    • after the recipient's team was knocked out;
    • in the 24-72 hours after a national tragedy (pause all sequences);
    • on major holidays (Thanksgiving week, Dec 24 - Jan 1, July 4, regional holidays);
    • on a birthday (creepy in cold email; no data says otherwise).
  7. Stack signals where you can: a raise in the last 6 months plus a VP Revenue hired in the last 30 days beats either alone.

2. Company and person triggers: recency windows

Sources disagree by up to 5x, so these are our defaults.

TriggerSend windowNotesExample line
Funding round7-45 daysInbox floods in week 1; spend runs ~6 months; indexes lag 3-4 months, so check the date"congrats on the series b. the next step is usually hiring AEs before there's pipeline for them."
New exec (VP+, CRO, head of)14-90 daysFirst 90 days is when the stack gets reviewed"saw you joined as vp sales last month."
Champion job change7-45 daysCongratulate fast, sell slower"congrats on the move to {{companyName}}."
Job posts in your domainwhile open, ≤60 days6+ related roles in a short window = a surge"you've got 6 sdr roles open."
Product launch3-21 daysFast decay"saw the launch of [product] last week."
M&A14-120 daysIntegration pain lasts months"saw the [target] deal close."
Earnings / 10-K / 10-Q0-30 daysQuote their risk factors (Item 1A) or MD&A in their own words, not the call recap"in the 10-K you flagged [risk, quoted]."
Fiscal year end4-8 weeks beforePull FYE from the 10-K cover or EDGAR; private = assume December"your fiscal year closes june 30."
Permits (building, construction)0-21 daysBidding happens before work"saw the permit for the 120k sqft build on elm st."
Tech install / uninstall30-90 daysOnly detectable installs; never infer an absence
Website change (pricing, new page)7-14 days
Reviews (G2, Google)0-30 daysAvoid quoting a complaint about them
Lawsuit / regulatory action / WARN layoffsdon't name itAt most an industry framing

3. Sports

Two uses, very different strength:

  • The event is the business (strong). Coaches and athletic directors after a game; sports bars, hospitality and ticketing around playoffs; venues, staffing, security and logistics in host cities. Eric Nowoslawski: "We've gone as deep as finding high school football scores on Friday to email coaches about on Monday."
  • Rapport (weak, PS-level). A nod to a team the prospect publicly follows. This belongs in the PS (ps-and-first-lines.md), not the opener.

Rules:

  • Allegiance must be evidenced (their LinkedIn, bio, a sponsorship). HQ city does not tell you who someone roots for, since transplants are common. Without evidence, talk about the city ("must be a loud week in philly"), not "your eagles".
  • Wins and milestones only, within 4 days of the game. A loss, blowout or elimination drops the line. Never trash-talk.
  • Send Monday or Tuesday after the game.

Data:

  • ESPN's unofficial API (free, unkeyed, no SLA): site.api.espn.com/apis/site/v2/sports/football/nfl/scoreboard (same pattern for college football, NBA, MLB, NHL, soccer); /teams gives venue cities for a metro → team table.
  • TheSportsDB (free shared key, low limits), API-Sports (100 requests a day free), SportsDataIO (~$99/mo+).
  • High school: no official MaxPreps API (community tools read its undocumented JSON routes; check the terms first). State associations and local outlets publish weekly score roundups.
  • Pipeline: geocode HQ → metro → teams; pull results daily; write team, opponent, score, result, round, game_date onto the lead; gate the line on a win within 4 days.
  • 2026 World Cup (Jun 11 - Jul 19, 11 US host metros plus Toronto, Vancouver and 3 Mexican cities) is past. Use it only as a lookback ("running ops in kc during the quarterfinal weekend can't have been quiet").

Examples:

  • Coach: "saw westlake took down lake travis 28-21 friday. congrats to you and the staff."
  • Evidenced fan (PS): "ps congrats on the bills clinching, must be a good week in buffalo."

4. Weather

EventWho buysStrength
Hail ≥1"roofing, restoration, auto glass, PDR, adjusters, property managersstrong
Heat waveHVAC, refrigeration, cold chain, utilities, construction safety, staffingstrong
Hard freezeplumbing, pipe-burst restoration, ag, irrigation, propanestrong
Hurricane / tropical stormrestoration, generators, tree service, insurance, logistics (after only)strong, very sensitive
Wildfire smokeair purification, HVAC filtration, outdoor events, constructionmedium
Snow and icesnow removal, facilities, retail, logisticsmedium

Windows: hail 2-14 days after (claims and inspections run for weeks). Heat or freeze during the warning, up to 7 days after. Hurricane: never during, only 2-6+ weeks into recovery, for recovery and preparedness services. The plan-ahead angle is always safe: HVAC capacity in April and May, freeze prep in October.

Sensitivity: never opportunistic. No discounts tied to a disaster, no humor, no silver lining, never casualties (American Apparel's 2012 "Sandy Sale" drew boycott calls). Auto-suppress declared disaster counties; a human approves every first send into a hit area.

Data (free):

  • NWS Alerts API: api.weather.gov/alerts/active?area=TX. No key, but needs a User-Agent. Filter by event, severity, zone or county; 7 days of history.
  • SPC Storm Reports: daily hail, wind and tornado CSVs. Size is in hundredths of an inch (175 = 1.75"); days run 1200-1159 UTC; preliminary, so dedupe.
  • OpenWeather One Call (1,000 calls a day free, includes alerts), Tomorrow.io (500 a day free). Paid hail swaths (HailTrace) map points to addresses.
  • Pipeline: store company sites as county FIPS or NWS zone → poll daily → join with threshold rules (hail ≥1", Excessive Heat Warning, Hard Freeze Warning) → write wx_event, wx_date, wx_county.

Examples:

  • "noaa logged 1.75 inch hail across collin county tuesday. if any of your properties need roof inspections before claims windows close, we can be on site this week."
  • "first hard freeze usually hits dfw mid-november. are your sites winterized yet?"

5. The B2B calendar

Shift by the account's fiscal year (Microsoft and many states start July 1; the US federal year starts October 1). Procurement takes 2-4 weeks, so reach out 4-8 weeks before a deadline.

MonthTrigger momentsWho
Janbudgets released, SKOs, planning, CESall B2B; CROs and sales leaders; consumer tech
FebQ4 earnings, tax-prep peak, HIMSSpublic-company execs; CPAs; healthcare IT
MarQ1 close push, March Madness, northern construction startssales leaders; hospitality; GCs and subs
Aprtax deadline (Apr 15), Q1 earnings, hail season starts, UK, India and Japan FY startaccounting; roofing and restoration; APAC and UK accounts
Mayhail and tornado peak, HVAC pre-season, graduation hiring, mid-year reviewroofing, insurance, HVAC; recruiting and HR
JunQ2 close, hurricane season opens (prep only), H2 planning, retail Q4 planningsales and finance; restoration; retail
JulFY start (Microsoft, universities, many states), Q2 earnings, Prime Dayedu, state and local government; e-commerce
Augback-to-school, heat peak, next-year budget kickoff, harvest startsedtech; HVAC and cold chain; CFOs and FP&A; ag
Sepfederal FY end (Sep 30), Dreamforce and conference season, Q3 closefederal contractors; SaaS and revops; sales leaders
Octopen enrollment, Q4 budget-flush outreach starts, Q3 earnings, retail peak prepHR and benefits brokers; all B2B; retail, 3PL, seasonal staffing
NovMedicare and ACA enrollment, BFCM, next-year budgets lock, freeze seasoninsurance and health plans; e-commerce; finance; plumbing
Decyear-end close; book January meetings; sends slow Dec 20 - Jan 2finance and accounting; everyone ("for january")

Also: regulatory dates (state privacy laws on Jan 1, 1099s on Jan 31, SOC 2 renewals); trade shows (scrape the public exhibitor list, email 2-3 weeks before to book floor meetings, follow up within 24 hours after); industry seasons (northern construction runs Mar-Nov, harvest Aug-Nov, retail peak Oct-Dec).

Budget flush: don't lead with "use it or lose it" discounts (and never quote a price). The angle is timing: "if [problem] is on next year's plan, now is when it gets budgeted." Frame it as a start date, not a deal.

Holidays: pause on major holidays. "Hope you had a good thanksgiving" adds nothing. For global lists, suppress or soften around Ramadan, Diwali and Lunar New Year by region.

Anniversaries: company founding anniversaries are fine. Work anniversaries are borderline: use one only with a business angle ("2 years running revops at X, what's changed since you took it over?"), and better on LinkedIn. Never birthdays.


6. Building a trigger campaign

  1. Pick a trigger where the event changes what the buyer needs this month. If the honest answer to "why does this matter to them?" is "it's a fun fact", it's a PS, not a trigger.
  2. Write the source → field → gate pipeline first: trigger_type, event_date, event_source_url, raw values, plus the window and suppression rules above.
  3. Write the base email (no trigger) first, so it works when the line drops.
  4. Write the trigger line as a frame in the copy with the facts in variables ("saw {{team}} took down {{opponent}} {{score}} friday."). Never ask an AI to write a whole sentence about a score.
  5. Tag the campaign trigger_type and record trigger_age_days at enrollment so you can tell whether fresher is actually better.
references/voices-and-styles.md

More Voices, Episodes and 2025-26 Styles

Practitioners and styles beyond the core sources in playbook.md §1. Researched 2026-10-26. Many of these people publish their real frameworks behind paywalls (Jed Mahrle, Florin Tatulea, Caliber courses) or only in audio, so the public material is thinner than their reputations. Numbers are self-reported unless noted.


1. Voices worth stealing from

Jordan Crawford (Blueprint GTM): PQS and PVP

The strongest new idea in the space. "Target pain, not persona."

  • PQS, Pain-Qualified Segment: find the situation that made past customers buy, then a public, detectable signal that a prospect is in that situation now (hiring, tool changes, DNS records, filings, competitor footprint, support-doc changes). Build the list from the signal, not from firmographics. The email names the situation back to them. "If the pain doesn't produce a detectable signal, it isn't a PQS, it's a hypothesis."
  • PVP, Permissionless Value Proposition: "a message that's worth something to the person who gets it", with no demo, signup or even a reply needed. Built by combining 2-5 data sources only you have.
    • Work backwards: who receives it → what data only we have → what work we can do for them.
    • If the number is too small to matter, send it further up the chain (to the PE firm, not a single portco).
    • Customer test: show it to a real customer. It passes only if they say "that would be really valuable to me."
    • Gate test: for each value sentence, could I say this without reading their file? If yes, it fails.
  • His example: "We flew a drone over your San Jose location last week. We found unattended propane tanks in the back. That's an OSHA violation. Photo attached." To a PE firm: "Your 12 portcos' top 3 ingredients are cinnamon, cane sugar and oat flour."
  • Sources: edge.blueprintgtm.com; SaaS Unbound podcast "Ship an A+ campaign in 1 hour" (Sep 2025).

Armand Farrokh & Nick Cegelski (30 Minutes to President's Club, Cold Calling Sucks)

The 4-sentence email: reason you're reaching out → the problem → the solution → a low-friction interest CTA. Plain text, a trigger-based subject, a short same-thread bump, then vary each later follow-up. Template from their toolkit (Anthony Natoli, Lattice):

Hey {{first_name}}, people leaders like you are moving to a more continuous performance and feedback culture. Because of this, employee growth and retention are top of mind. We help our customers build flexible performance management programs, which enables ongoing feedback from managers and employees. Is this on your radar at all?

E3 is a reply in the thread: problem → why it hurts → customer quote → "Open to learning more?"

Sam McKenna (#samsales, "Show Me You Know Me")

  • A subject only the recipient would understand: details joined with "+" ("switzerland + liip cheeseburger + [company]").
  • Lead with a specific problem and pre-empt the most likely objection in the body.
  • No calendar links: "do you have time over the next week or two to learn more?"
  • About 20 emails a week. Her 20% reply rate comes from a low-volume, heavy-research motion and doesn't transfer to scaled sends. Use the subject and objection moves for tier-1 accounts.

Kyle Coleman (Clari, Copy.ai, ClickUp): POV-led outbound

"Personalization that only shows research, without showing understanding, doesn't work." The email interprets the signal ("here's what that hire means for you") instead of citing it.

  • Construction: trigger → interpretation → copy.
  • The 5-touch cascade from one strong POV:
    1. the strongest insight;
    2. a second painful implication;
    3. social proof plus a short story;
    4. a low-pressure invite;
    5. a graceful exit.
  • Research with 5×5×5: 5 minutes, 5 insights, 5 minutes writing.
  • Rank signals: strong signals create operational or strategic pressure; hires and awards are only background.

Nick Abraham (Leadbird, 1.5M+ emails a month)

  • "The number one thing that correlates to the result of your campaign is just the offer."
  • Under 100 words; copy "gets fatigued way quicker" above 120.
  • Strip legal suffixes ("LLC") from company names, since they signal automation.
  • Personalize one variable, not the whole email: "I wasn't sure if I should reach out to you or Liam."
  • "Is that something you'd be interested in?" is his best CTA, and now overused, so vary it.
  • Lead magnets and free mockups raise replies but convert to meetings less reliably. That's the counterweight to PVP: grade on meetings.
  • His bars: 2-4% reply, 20-40% of replies positive, one qualified lead per 350-500 contacts. Under 1% reply usually means a deliverability problem, not a copy problem.

Jack Reamer & Jeremy Chatelaine ("Cold Email Outreach with Jeremy & Jack", weekly teardowns)

  • Say why you're writing in line 1, with an explicit "because".
  • Frame the offer as a gift or sample rather than an ask.
  • Back pay-on-results claims with specific proof.
  • Test a stripped version with only the pain and the CTA.
  • Test asking for feedback instead of pitching.
  • "Gun to your head" offer exercise: write the offer the prospect can't refuse.
  • "Quick question, [name]" plus flattery reads as fake.

Others in brief

  • Jed Mahrle (Practical Prospecting): subject → line 1 context → line 2 value prop → line 3 CTA → optional P.S. "for 90% of cold emails".
  • Steli Efti (Close): answer who you are, what you want and why them, in that order; one ask per email.
  • Michael Seibel (YC): 3 sentences, Situation → Reason to care → Ask. A good founder-to-founder register.
  • Bryan Kreuzberger (Breakthrough Email): the "appropriate person" email to 3-4 people at one company, naming the others you've emailed. Still a valid multi-thread routing move.
  • Florin Tatulea / Chris Orlob: the "4-sentence cold email" (paywalled). Expect it to look like the 30MPC template above.

2. Episodes and videos (2025-26)

EpisodeTakeaways
30MPC × Gong × Outbound Squad, "We Analyzed 85 Million Cold Emails" (Jason Bay, Jul 2025); article: gong.io/blog/does-cold-email-even-work-any-more344 cold emails per meeting for the average rep; top reps get 8.1x the meetings; 3-4 sentences under 100 words reply best; pitching cuts replies up to 57%; buzzwords and numbers in subjects cut opens up to 18%; social proof works in the body, not the subject
30MPC #596, Sam McKenna, "This Cold Email Formula Gets +20% Replies" (Aug 2026)Recipient-only subjects; pre-empt the objection; no calendar links; educational touches in the sequence
30MPC Sell #324 "8 Brutal Cold Email Truths" and #322 "Writing Better Cold Emails in Half the Time with AI" (Jul 2025)AI drafts from rich context, a human edits for voice; AI for research and writer's block, not the final draft
Discovered Labs, Nick Abraham, "He sends 1.5M cold emails per month" (May 2025)Offer > everything; under 100 words; a yes/no interest CTA; magnets raise replies, not always meetings
SaaS Unbound, Jordan Crawford, "Ship an A+ campaign in 1 hour using ChatGPT 5" (Sep 2025)PQS from why past customers bought; "switchers" from legacy-competitor pain; check every AI claim against a URL
The GTM Engineer podcast, Eric Nowoslawski, "The Winning Cold Outbound Formula" (Jul 2025)Offers beat personalization; make the call worth paying for; answer "why wouldn't they reply"; the pay-after-removal review offer: 1 positive per 70
AI x GTM Summit #4, live AI-copy teardowns (recap: thesignal.club, Feb 2026)Timing and signal beat copy; assume it will be read as AI; kill em dashes and over-structured sentences; ~3-word subjects; text-only signatures
Jeremy & Jack #417 "How to Spot Cold Email Lies" and #418 "10 LinkedIn A/B Tests" (Mar 2026)A "because" reason; free sample work; pain-plus-CTA-only tests

The email the summit audience rated best (Cursor), subject "Saw your AI tooling req":

Noticed {{company}} is hiring devs with AI coding tool experience. Sounds like you're serious about building this into how the team works, not just letting people experiment. That's the hard part. Most eng orgs I talk to are stuck between "everyone uses whatever" and "we should probably have a strategy here." Happy to share what's working for teams making that shift if useful.

The email it called slop listed the prospect's tech stack, then made a generic "cut prototyping from weeks to hours" claim.


3. 2025-26 styles: what they are and whether to use them

StyleWhat it isEvidenceOur call
Permissionless value (PVP) / show, don't tellEmail 1 contains the deliverable: the finding, list, photo or audit resultStrong anecdotes (Crawford; Eric 1 positive per 70); Abraham: more replies, not always more meetingsUse it when we hold data they can't easily get. Grade on meetings. Framework in frameworks.md
Signal-based / PQSThe list is built from an observed trigger; line 1 names itNo controlled study; summit consensus "timing beats copy"Default for every list we can build this way
POV-ledInterpret the signal: what it means for themClari before-and-after claim onlyUse it for exec and tier-1 accounts; it's the insight line in Kellen's 4-move
Relevance over flatteryNo "loved your podcast"; a sharp problem statement or one variableGong: hours of personalization return little; Belkins personalized subjects 7% vs 3%House rule. Read "personalization" in studies as relevance
Ultra-short / text-like3-4 sentences, under 80 wordsModerately strong and consistent across Smartlead, Gong and InstantlyDefault 50-90 words; our niche winners run ~100
Lowercase subjects"new role", "field visits"Open-rate data only (MPP-inflated); no reply evidenceA voice choice, not a lever
5th-grade reading levelShort words, short sentencesTraces to Boomerang 2016 (warm email); not replicated coldGrade ≤7 is a style norm, not a promise of lift
Loom / personal videoVideo in E1 or E2Vendor claims; adds a link; ~1 hour a day per repTier-1 only, and from E2 (no links in E1)
AI microsites / custom pagesA generated page per prospectNo reply data; vendors say it works best in email 2Test from E2, never E1
"Assume it's AI" plain textNo em dashes, no over-structure, text-only, no links in E169% of buyers dislike AI-sounding email (Hunter 2025)House rule (lint plus humanizer)

Patterns that recur across all the new sources:

  1. Lead with a signal or a pain the reader recognizes.
  2. One problem sentence, one proof point, and a yes/no interest CTA.
  3. Under ~80-100 words, no pitch.
  4. Where you hold unique data, give the finding, not an offer to make one.
  5. Social proof in the body, never the subject.

Install this skill

Pick the app you use. We remember it for next time.

  1. Download the skill as a ZIP.
  2. In Claude, open Customize, then Skills, then Your skills.
  3. Choose Upload skill and pick the ZIP. Leave it switched on.
Download ZIPOpen Claude skills

Then ask: “build a sequence”

Want the whole library, kept up to date? .

Run it on your own playbookBook 30 minutes. We build it onto a Company Brain live.
Win the workcollection
Salescategory
MITlicense

Install this skill

Pick the app you use. We remember it for next time.

  1. Download the skill as a ZIP.
  2. In Claude, open Customize, then Skills, then Your skills.
  3. Choose Upload skill and pick the ZIP. Leave it switched on.
Download ZIPOpen Claude skills

Then ask: “build a sequence”

Want the whole library, kept up to date? .

Want this sounding like you?

Out of the box it runs on general knowledge. On a Company Brain it runs on your framework, your pricing and the proposals you’ve already won with, so the output comes back in your voice.

Book 30 minutes

More from Garrett

Customer Success

Client performance review doc

Use this skill when an agency owes a client its periodic outbound performance review (QBR, 30-60-90, "three months in") and wants a commentable doc the client reads before the call. Pulls the numbers by channel and campaign, writes the summary, levers, what has not worked, new plays and the client's asks, adds a data appendix (TAM, who replies, objections), renders clean tables and charts, and runs the comment-and-call loop. Also use for "performance review", "QBR", "results doc", "write up how outbound is going".

Garrett WolfeFounder, OneGTM
Sales

Sent cold email content review

Use this skill when an agency needs to QA every cold email a client campaign has actually sent: names and company names rendering correctly, variables filled, message coherence, pitch accuracy, ICP fit, signal-to-message alignment, sender and signature consistency, CTA calibration and cross-campaign duplication. Produces findings tagged by severity and fix location with a prioritized action list. Also use for "review our emails", "QA our outbound", "are our emails going out correctly".

Garrett WolfeFounder, OneGTM
RevOps

TAM scoring audit and distribution fix

Use this skill when a client's account scoring model piles everyone at the same score and the agency needs to audit it against the data, simulate revised rubrics and recommend bands, weights and multipliers that make accounts stack-rank, with a DQ cutoff that means something. Works on a Clay or spreadsheet TAM export plus its rubric. Also use for "rescore this list", "fix the scoring", "why is everyone scoring the same", "distribution is compressed", "twin-firm test".

Garrett WolfeFounder, OneGTM

More in Win the work

Sales Coaching

Activity incentive sprint

Use this skill when a sales team's pattern needs interrupting for a few days: Call 1 bookings have dried up, presentations have stalled, a dormant list needs clearing, or the quarter needs a jolt. Produces an Executive Sprint Brief for a 1-day blitz, 3-day push or 2-week sprint, with targets worked from the team's real baseline, qualifying criteria, a scoreboard, a reward and three daily huddle prompts. Also use for "sales blitz", "sprint incentive", "spiff", "activity competition", "get the team booking meetings this week".

Tony DowlingTony DowlingDirector, CONVRG
Marketing

Buyer read

Use this skill when a finished page, deck, or piece of client copy is about to go to the client or be published, and a real ICP or buyer research document exists. Produces a ranked list of what would make the target buyer stop trusting it, read in character, with every finding citing a line in a real source, plus what to cut and a score. Catches what craft reviews miss: scenarios that can't happen in the buyer's week, an offer never plainly stated, missing price, unused proof, seller vocabulary. Also use for "/buyer-read", "review this as the buyer", "have the ICP look at this", "what would a CFO think of this page", "be hypercritical about this copy". Not for grammar or voice checks, and never for rewriting.

Chris DuBoisChris DuBoisFounder and Coach, Dynamic Agency OS
Sales

Client proposal

Use this skill when a proposal is due and it is about to be the last one with the name changed. Produces a proposal built from what the prospect actually said: their situation in their own words, the firm's named approach, scope with explicit exclusions, the objection they already raised answered directly, pricing options, and the proof the firm can stand behind. Also use for "I need a proposal out tonight", "respond to this RFP", "write the SOW", "pitch document".

Tapajyoti (Tukan) DasTapajyoti (Tukan) DasCEO, Gia